Repository: hybridgroup/gobot Branch: release Commit: 798be8ce070d Files: 973 Total size: 7.1 MB Directory structure: gitextract_4majm_s_/ ├── .chglog/ │ ├── CHANGELOG.gobot.md │ ├── README.md │ └── config_gobot.yml ├── .circleci/ │ └── config.yml ├── .github/ │ ├── FUNDING.yml │ ├── dependabot.yml │ ├── pull_request_template.md │ └── workflows/ │ └── golangci-lint.yml ├── .gitignore ├── .golangci.yml ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE.txt ├── MIGRATION.md ├── Makefile ├── README.md ├── adaptor.go ├── api/ │ ├── api.go │ ├── api_test.go │ ├── basic_auth.go │ ├── basic_auth_test.go │ ├── cors.go │ ├── cors_test.go │ ├── doc.go │ ├── helpers_test.go │ └── robeaux/ │ └── robeaux.go ├── appveyor.yml ├── commander.go ├── commander_test.go ├── connection.go ├── debug.go ├── device.go ├── doc.go ├── driver.go ├── drivers/ │ ├── aio/ │ │ ├── LICENSE │ │ ├── README.md │ │ ├── aio_driver.go │ │ ├── aio_driver_test.go │ │ ├── analog_actuator_driver.go │ │ ├── analog_actuator_driver_test.go │ │ ├── analog_sensor_driver.go │ │ ├── analog_sensor_driver_test.go │ │ ├── doc.go │ │ ├── grove_drivers.go │ │ ├── grove_drivers_test.go │ │ ├── grove_temperature_sensor_driver.go │ │ ├── grove_temperature_sensor_driver_test.go │ │ ├── helpers_test.go │ │ ├── temperature_sensor_driver.go │ │ ├── temperature_sensor_driver_test.go │ │ ├── thermalzone_driver.go │ │ └── thermalzone_driver_test.go │ ├── ble/ │ │ ├── LICENSE │ │ ├── README.md │ │ ├── battery_driver.go │ │ ├── battery_driver_test.go │ │ ├── ble_driver.go │ │ ├── ble_driver_test.go │ │ ├── device_information_driver.go │ │ ├── device_information_driver_test.go │ │ ├── doc.go │ │ ├── generic_access_driver.go │ │ ├── generic_access_driver_test.go │ │ ├── microbit/ │ │ │ ├── LICENSE │ │ │ ├── accelerometer_driver.go │ │ │ ├── accelerometer_driver_test.go │ │ │ ├── button_driver.go │ │ │ ├── button_driver_test.go │ │ │ ├── doc.go │ │ │ ├── io_pin_driver.go │ │ │ ├── io_pin_driver_test.go │ │ │ ├── led_driver.go │ │ │ ├── led_driver_test.go │ │ │ ├── magnetometer_driver.go │ │ │ ├── magnetometer_driver_test.go │ │ │ ├── temperature_driver.go │ │ │ └── temperature_driver_test.go │ │ ├── parrot/ │ │ │ ├── LICENSE │ │ │ ├── doc.go │ │ │ ├── minidrone_driver.go │ │ │ └── minidrone_driver_test.go │ │ ├── serial_port.go │ │ ├── serial_port_test.go │ │ ├── sphero/ │ │ │ ├── LICENSE │ │ │ ├── doc.go │ │ │ ├── sphero_bb8_driver.go │ │ │ ├── sphero_bb8_driver_test.go │ │ │ ├── sphero_ollie_driver.go │ │ │ ├── sphero_ollie_driver_test.go │ │ │ ├── sphero_sprkplus_driver.go │ │ │ └── sphero_sprkplus_driver_test.go │ │ └── testutil/ │ │ └── testutil.go │ ├── common/ │ │ ├── bit/ │ │ │ ├── bit.go │ │ │ └── bit_test.go │ │ ├── mfrc522/ │ │ │ ├── mfrc522_connectionwrapper.go │ │ │ ├── mfrc522_pcd.go │ │ │ ├── mfrc522_pcd_register.go │ │ │ ├── mfrc522_pcd_test.go │ │ │ └── mfrc522_picc.go │ │ └── spherocommon/ │ │ ├── spherocommon.go │ │ ├── spherocommon_packets.go │ │ └── spherocommon_test.go │ ├── gpio/ │ │ ├── LICENSE │ │ ├── README.md │ │ ├── aip1640_driver.go │ │ ├── aip1640_driver_test.go │ │ ├── button_driver.go │ │ ├── button_driver_test.go │ │ ├── buzzer_driver.go │ │ ├── buzzer_driver_test.go │ │ ├── direct_pin_driver.go │ │ ├── direct_pin_driver_test.go │ │ ├── doc.go │ │ ├── easy_driver.go │ │ ├── easy_driver_test.go │ │ ├── gpio_driver.go │ │ ├── gpio_driver_test.go │ │ ├── grove_drivers.go │ │ ├── grove_drivers_test.go │ │ ├── hcsr04_driver.go │ │ ├── hcsr04_driver_test.go │ │ ├── hd44780_driver.go │ │ ├── hd44780_driver_test.go │ │ ├── helpers_test.go │ │ ├── led_driver.go │ │ ├── led_driver_test.go │ │ ├── max7219_driver.go │ │ ├── max7219_driver_test.go │ │ ├── motor_driver.go │ │ ├── motor_driver_test.go │ │ ├── pir_motion_driver.go │ │ ├── pir_motion_driver_test.go │ │ ├── relay_driver.go │ │ ├── relay_driver_test.go │ │ ├── rgb_led_driver.go │ │ ├── rgb_led_driver_test.go │ │ ├── servo_driver.go │ │ ├── servo_driver_test.go │ │ ├── stepper_driver.go │ │ ├── stepper_driver_test.go │ │ ├── tm1638_driver.go │ │ └── tm1638_driver_test.go │ ├── i2c/ │ │ ├── LICENSE │ │ ├── README.md │ │ ├── adafruit1109_driver.go │ │ ├── adafruit1109_driver_test.go │ │ ├── adafruit2327_driver.go │ │ ├── adafruit2327_driver_test.go │ │ ├── adafruit2348_driver.go │ │ ├── adafruit2348_driver_test.go │ │ ├── ads1x15_driver.go │ │ ├── ads1x15_driver_1015_test.go │ │ ├── ads1x15_driver_1115_test.go │ │ ├── ads1x15_driver_test.go │ │ ├── adxl345_driver.go │ │ ├── adxl345_driver_test.go │ │ ├── bh1750_driver.go │ │ ├── bh1750_driver_test.go │ │ ├── blinkm_driver.go │ │ ├── blinkm_driver_test.go │ │ ├── bme280_driver.go │ │ ├── bme280_driver_test.go │ │ ├── bmp180_driver.go │ │ ├── bmp180_driver_test.go │ │ ├── bmp280_driver.go │ │ ├── bmp280_driver_test.go │ │ ├── bmp388_driver.go │ │ ├── bmp388_driver_test.go │ │ ├── ccs811_driver.go │ │ ├── ccs811_driver_test.go │ │ ├── doc.go │ │ ├── drv2605l_driver.go │ │ ├── drv2605l_driver_test.go │ │ ├── generic_driver.go │ │ ├── generic_driver_test.go │ │ ├── grove_drivers.go │ │ ├── grove_drivers_test.go │ │ ├── grovepi_driver.go │ │ ├── grovepi_driver_test.go │ │ ├── helpers_test.go │ │ ├── hmc5883l_driver.go │ │ ├── hmc5883l_driver_test.go │ │ ├── hmc6352_driver.go │ │ ├── hmc6352_driver_test.go │ │ ├── i2c_config.go │ │ ├── i2c_config_test.go │ │ ├── i2c_connection.go │ │ ├── i2c_connection_test.go │ │ ├── i2c_driver.go │ │ ├── i2c_driver_test.go │ │ ├── ina3221_driver.go │ │ ├── ina3221_driver_test.go │ │ ├── jhd1313m1_driver.go │ │ ├── jhd1313m1_driver_test.go │ │ ├── l3gd20h_driver.go │ │ ├── l3gd20h_driver_test.go │ │ ├── lidarlite_driver.go │ │ ├── lidarlite_driver_test.go │ │ ├── mcp23017_driver.go │ │ ├── mcp23017_driver_test.go │ │ ├── mfrc522_driver.go │ │ ├── mma7660_driver.go │ │ ├── mma7660_driver_test.go │ │ ├── mpl115a2_driver.go │ │ ├── mpl115a2_driver_test.go │ │ ├── mpu6050_driver.go │ │ ├── mpu6050_driver_test.go │ │ ├── pca9501_driver.go │ │ ├── pca9501_driver_test.go │ │ ├── pca953x_driver.go │ │ ├── pca953x_driver_test.go │ │ ├── pca9685_driver.go │ │ ├── pca9685_driver_test.go │ │ ├── pcf8583_driver.go │ │ ├── pcf8583_driver_test.go │ │ ├── pcf8591_driver.go │ │ ├── pcf8591_driver_test.go │ │ ├── sht2x_driver.go │ │ ├── sht2x_driver_test.go │ │ ├── sht3x_driver.go │ │ ├── sht3x_driver_test.go │ │ ├── ssd1306_driver.go │ │ ├── ssd1306_driver_test.go │ │ ├── th02_driver.go │ │ ├── th02_driver_test.go │ │ ├── tsl2561_driver.go │ │ ├── tsl2561_driver_test.go │ │ ├── wiichuck_driver.go │ │ ├── wiichuck_driver_test.go │ │ ├── yl40_driver.go │ │ └── yl40_driver_test.go │ ├── onewire/ │ │ ├── README.md │ │ ├── ds18b20_driver.go │ │ ├── ds18b20_driver_test.go │ │ ├── helpers_test.go │ │ ├── onewire_connection.go │ │ ├── onewire_connection_test.go │ │ ├── onewire_driver.go │ │ └── onewire_driver_test.go │ ├── serial/ │ │ ├── LICENSE │ │ ├── README.md │ │ ├── doc.go │ │ ├── megapi/ │ │ │ └── motor_driver.go │ │ ├── neurosky/ │ │ │ ├── LICENSE │ │ │ ├── mindwave_driver.go │ │ │ └── mindwave_driver_test.go │ │ ├── serial_driver.go │ │ ├── serial_driver_test.go │ │ ├── sphero/ │ │ │ ├── LICENSE │ │ │ ├── sphero_driver.go │ │ │ └── sphero_driver_test.go │ │ └── testutil/ │ │ └── testutil.go │ └── spi/ │ ├── README.md │ ├── apa102.go │ ├── apa102_test.go │ ├── doc.go │ ├── helpers_test.go │ ├── mcp3002.go │ ├── mcp3002_test.go │ ├── mcp3004.go │ ├── mcp3004_test.go │ ├── mcp3008.go │ ├── mcp3008_test.go │ ├── mcp3202.go │ ├── mcp3202_test.go │ ├── mcp3204.go │ ├── mcp3204_test.go │ ├── mcp3208.go │ ├── mcp3208_test.go │ ├── mcp3304.go │ ├── mcp3304_test.go │ ├── mfrc522_driver.go │ ├── mfrc522_driver_test.go │ ├── spi_config.go │ ├── spi_connection.go │ ├── spi_connection_test.go │ ├── spi_driver.go │ ├── spi_driver_test.go │ ├── ssd1306_driver.go │ └── ssd1306_driver_test.go ├── event.go ├── eventer.go ├── eventer_test.go ├── examples/ │ ├── ardrone.go │ ├── ardrone_face_tracking.go │ ├── ardrone_ps3.go │ ├── audio.go │ ├── batty.go │ ├── beaglebone_basic_direct_pin.go │ ├── beaglebone_blink.go │ ├── beaglebone_blink_usr_led.go │ ├── beaglebone_blinkm.go │ ├── beaglebone_button.go │ ├── beaglebone_grove_accelerometer.go │ ├── beaglebone_led_brightness.go │ ├── beaglebone_led_brightness_with_analog_input.go │ ├── beaglepocket_direct_pin.go │ ├── bebop.go │ ├── bebop.sdp │ ├── bebop_ps3.go │ ├── bebop_ps3_video.go │ ├── bebop_rtp_video.go │ ├── bleclient_battery.go │ ├── bleclient_bb8-collision.go │ ├── bleclient_bb8.go │ ├── bleclient_device_info.go │ ├── bleclient_firmata_blink.go │ ├── bleclient_firmata_curie_imu.go │ ├── bleclient_generic_access.go │ ├── bleclient_microbit_accelerometer.go │ ├── bleclient_microbit_blink.go │ ├── bleclient_microbit_buttons.go │ ├── bleclient_microbit_buttons_leds.go │ ├── bleclient_microbit_io_button.go │ ├── bleclient_microbit_led.go │ ├── bleclient_microbit_magnetometer.go │ ├── bleclient_microbit_temperature.go │ ├── bleclient_minidrone.go │ ├── bleclient_minidrone_events.go │ ├── bleclient_minidrone_mambo_ps3.go │ ├── bleclient_minidrone_ps3.go │ ├── bleclient_multiple_generic.go │ ├── bleclient_multiple_info.go │ ├── bleclient_ollie.go │ ├── bleclient_ollie_boost.go │ ├── bleclient_ollie_crazy.go │ ├── bleclient_ollie_mqtt.go │ ├── bleclient_ollie_multiple.go │ ├── bleclient_ollie_roll.go │ ├── bleclient_ollie_spin.go │ ├── bleclient_sprkplus.go │ ├── bleclient_sprkplus_collision.go │ ├── chip_blink.go │ ├── chip_blinkm.go │ ├── chip_button.go │ ├── chip_button_led.go │ ├── chip_drv2605l.go │ ├── chip_grove_accelerometer.go │ ├── chip_grove_lcd.go │ ├── chip_mpu6050.go │ ├── chip_tsl2561.go │ ├── chip_wiichuck.go │ ├── digispark_api.go │ ├── digispark_blink.go │ ├── digispark_blinkm.go │ ├── digispark_driver.go │ ├── digispark_led_brightness.go │ ├── digispark_mpl115a2.go │ ├── digispark_pca9501.go │ ├── digispark_servo.go │ ├── dragonboard_button.go │ ├── edison_blink.go │ ├── edison_blink_without_all_gobot_framework.go │ ├── edison_blinkm.go │ ├── edison_bme280.go │ ├── edison_button.go │ ├── edison_button_led.go │ ├── edison_button_led_api.go │ ├── edison_grove_accelerometer.go │ ├── edison_grove_buzzer.go │ ├── edison_grove_lcd.go │ ├── edison_grove_light_sensor.go │ ├── edison_grove_piezo_vibration.go │ ├── edison_grove_rotary_sensor.go │ ├── edison_grove_sound_sensor.go │ ├── edison_grove_temperature_sensor.go │ ├── edison_led_brightness.go │ ├── edison_led_brightness_with_analog_input.go │ ├── edison_miniboard_grove_accelerometer.go │ ├── every_done.go │ ├── firmata_adxl345.go │ ├── firmata_aip1640.go │ ├── firmata_blink.go │ ├── firmata_blink_api.go │ ├── firmata_blink_metal.go │ ├── firmata_blink_robot.go │ ├── firmata_blinkm.go │ ├── firmata_bme280.go │ ├── firmata_bmp180.go │ ├── firmata_bmp280.go │ ├── firmata_button.go │ ├── firmata_buzzer.go │ ├── firmata_cat_toy.go │ ├── firmata_curie_imu.go │ ├── firmata_curie_imu_shock_detect.go │ ├── firmata_curie_imu_step_counter.go │ ├── firmata_curie_imu_tap_detect.go │ ├── firmata_direct_pin.go │ ├── firmata_gpio_max7219.go │ ├── firmata_grove_lcd.go │ ├── firmata_grove_sound_sensor.go │ ├── firmata_hmc6352.go │ ├── firmata_integration.go │ ├── firmata_led_brightness.go │ ├── firmata_led_brightness_with_analog_input.go │ ├── firmata_lidarlite.go │ ├── firmata_metal_button.go │ ├── firmata_mma7660.go │ ├── firmata_motor.go │ ├── firmata_mpl115a2.go │ ├── firmata_mpu6050.go │ ├── firmata_pca9685.go │ ├── firmata_pir_motion.go │ ├── firmata_rgb_led.go │ ├── firmata_servo.go │ ├── firmata_ssd1306.go │ ├── firmata_temp36.go │ ├── firmata_tm1638.go │ ├── firmata_travis.go │ ├── firmata_wiichuck.go │ ├── gopigo3.go │ ├── gopigo3_grove_button.go │ ├── gopigo3_grove_lcd.go │ ├── gopigo3_grove_light_sensor.go │ ├── gopigo3_led_brightness.go │ ├── gopigo3_servo.go │ ├── haarcascade_frontalface_alt.xml │ ├── hello.go │ ├── hello_api.go │ ├── hello_api_auth.go │ ├── hello_api_custom.go │ ├── hello_api_video.go │ ├── holystone_hs200.go │ ├── jetson-nano_blink.go │ ├── jetson-nano_servo.go │ ├── joule_blink.go │ ├── joule_blinkm.go │ ├── joule_grove_lcd.go │ ├── joule_grove_rotary_sensor.go │ ├── joule_led_brightness.go │ ├── joule_led_brightness_with_analog_input.go │ ├── joule_leds.go │ ├── joystick_ps3.go │ ├── joystick_ps4.go │ ├── joystick_ps5.go │ ├── joystick_xbox360.go │ ├── joystick_xbox360_rock_band_drums.go │ ├── joystick_xboxone.go │ ├── keyboard.go │ ├── keyboard_mqtt.go │ ├── leap_motion.go │ ├── leap_motion_gestures.go │ ├── leap_motion_hands.go │ ├── leap_servos.go │ ├── leap_sphero.go │ ├── mavlink.go │ ├── metal_button.go │ ├── mqtt_driver_ping.go │ ├── mqtt_firmata_blink.go │ ├── mqtt_ping.go │ ├── nanopct6_direct_pin.go │ ├── nanopct6_ds18b20.go │ ├── nanopct6_servo.go │ ├── nanopct6_thermalzone.go │ ├── nanopct6_yl40.go │ ├── nanopi_button.go │ ├── nanopi_direct_pin.go │ ├── nanopi_direct_pin_event.go │ ├── nanopi_led_brightness.go │ ├── nanopi_pca9533.go │ ├── nats.go │ ├── nats_driver_ping.go │ ├── opencv_face_detect.go │ ├── opencv_window.go │ ├── orangepi5pro_direct_pin.go │ ├── orangepi5pro_servo.go │ ├── orangepi5pro_thermalzone.go │ ├── particle_api.go │ ├── particle_blink.go │ ├── particle_button.go │ ├── particle_events.go │ ├── particle_function.go │ ├── particle_led_brightness.go │ ├── particle_variable.go │ ├── pebble.go │ ├── pebble_accelerometer.go │ ├── raspi_adafruit2327_servo.go │ ├── raspi_adafruit2348_dcmotor.go │ ├── raspi_adafruit2348_stepper.go │ ├── raspi_ads1015.go │ ├── raspi_blink.go │ ├── raspi_blinkm.go │ ├── raspi_button.go │ ├── raspi_ccs811.go │ ├── raspi_direct_pin.go │ ├── raspi_direct_pin_event.go │ ├── raspi_generic.go │ ├── raspi_grove_pi_blink.go │ ├── raspi_grove_pi_button.go │ ├── raspi_grove_pi_dht.go │ ├── raspi_grove_pi_rotary.go │ ├── raspi_grove_pi_ultrasonic.go │ ├── raspi_grove_rotary_sensor.go │ ├── raspi_hcsr04.go │ ├── raspi_hmc5883l.go │ ├── raspi_ina3221.go │ ├── raspi_led_brightness.go │ ├── raspi_mcp3008.go │ ├── raspi_pca9533.go │ ├── raspi_servo.go │ ├── raspi_sht2x.go │ ├── raspi_sht3x.go │ ├── raspi_ssd1306.go │ ├── raspi_ssd1306spi.go │ ├── raspi_stepper_move.go │ ├── raspi_thermalzone.go │ ├── rock64_direct_pin.go │ ├── rock64_yl40.go │ ├── serialport_megapi_motor.go │ ├── serialport_mindwave.go │ ├── serialport_sphero.go │ ├── serialport_sphero_api.go │ ├── serialport_sphero_calibration.go │ ├── serialport_sphero_conways.go │ ├── serialport_sphero_dpad.go │ ├── serialport_sphero_master.go │ ├── serialport_sphero_multiple.go │ ├── square.go │ ├── square_fire.go │ ├── tello.go │ ├── tello_facetracker.go │ ├── tello_keyboard.go │ ├── tello_opencv.go │ ├── tello_ps3.go │ ├── tello_video.go │ ├── tinkerboard2_direct_pin_bin_counter.go │ ├── tinkerboard2_yl40.go │ ├── tinkerboard_adafruit1109_lcd_keys.go │ ├── tinkerboard_ads1115.go │ ├── tinkerboard_adxl345.go │ ├── tinkerboard_blink.go │ ├── tinkerboard_bme280.go │ ├── tinkerboard_bmp280.go │ ├── tinkerboard_button.go │ ├── tinkerboard_direct_pin.go │ ├── tinkerboard_ds18b20.go │ ├── tinkerboard_generic.go │ ├── tinkerboard_grove_lcd.go │ ├── tinkerboard_hcsr04.go │ ├── tinkerboard_hmc5883l.go │ ├── tinkerboard_mfcrc522gpio.go │ ├── tinkerboard_mfcrc522spi.go │ ├── tinkerboard_motor.go │ ├── tinkerboard_mpl115a2.go │ ├── tinkerboard_mpu6050.go │ ├── tinkerboard_pca9533.go │ ├── tinkerboard_pcf8583_clock.go │ ├── tinkerboard_pcf8583_counter.go │ ├── tinkerboard_pcf8591.go │ ├── tinkerboard_thermalzone.go │ ├── up2_lcd.go │ ├── up2_leds.go │ ├── wifi_firmata_analog_input.go │ ├── wifi_firmata_blink.go │ ├── zero_analog.go │ ├── zero_direct_pin.go │ ├── zero_servo.go │ └── zero_yl40.go ├── go.mod ├── go.sum ├── helpers_test.go ├── manager.go ├── manager_test.go ├── platforms/ │ ├── adaptors/ │ │ ├── analogpinsadaptor.go │ │ ├── analogpinsadaptor_test.go │ │ ├── analogpinsadaptoroptions.go │ │ ├── analogpinsadaptoroptions_test.go │ │ ├── analogpintranslator.go │ │ ├── analogpintranslator_test.go │ │ ├── busnumbervalidator.go │ │ ├── busnumbervalidator_test.go │ │ ├── digitalpinsadaptor.go │ │ ├── digitalpinsadaptor_test.go │ │ ├── digitalpinsadaptoroptions.go │ │ ├── digitalpinsadaptoroptions_test.go │ │ ├── digitalpintranslator.go │ │ ├── digitalpintranslator_test.go │ │ ├── i2cbusadaptor.go │ │ ├── i2cbusadaptor_test.go │ │ ├── i2cbusadaptoroptions.go │ │ ├── i2cbusadaptoroptions_test.go │ │ ├── onewirebusadaptor.go │ │ ├── onewirebusadaptor_test.go │ │ ├── onewirebusadaptoroptions.go │ │ ├── onewirebusadaptoroptions_test.go │ │ ├── piblasterpwm_pin.go │ │ ├── piblasterpwm_pin_test.go │ │ ├── pwmpinsadaptor.go │ │ ├── pwmpinsadaptor_test.go │ │ ├── pwmpinsadaptoroptions.go │ │ ├── pwmpinsadaptoroptions_test.go │ │ ├── pwmpintranslator.go │ │ ├── pwmpintranslator_test.go │ │ ├── spibusadaptor.go │ │ ├── spibusadaptor_test.go │ │ ├── spibusadaptoroptions.go │ │ └── spibusadaptoroptions_test.go │ ├── asus/ │ │ ├── tinkerboard/ │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── adaptor.go │ │ │ ├── adaptor_test.go │ │ │ ├── doc.go │ │ │ └── pinmap.go │ │ └── tinkerboard2/ │ │ ├── README.md │ │ ├── adaptor.go │ │ ├── adaptor_test.go │ │ └── pinmap.go │ ├── audio/ │ │ ├── LICENSE │ │ ├── audio_adaptor.go │ │ ├── audio_adaptor_test.go │ │ ├── audio_driver.go │ │ ├── audio_driver_test.go │ │ └── doc.go │ ├── beagleboard/ │ │ ├── LICENSE │ │ ├── README.md │ │ ├── beaglebone/ │ │ │ ├── adaptor.go │ │ │ ├── adaptor_test.go │ │ │ └── pinmap.go │ │ ├── doc.go │ │ └── pocketbeagle/ │ │ ├── adaptor.go │ │ ├── adaptor_test.go │ │ └── pinmap.go │ ├── bleclient/ │ │ ├── LICENSE │ │ ├── README.md │ │ ├── ble_client_adaptor.go │ │ ├── ble_client_adaptor_options.go │ │ ├── ble_client_adaptor_options_test.go │ │ ├── ble_client_adaptor_test.go │ │ ├── btwrapper.go │ │ ├── doc.go │ │ ├── helpers_test.go │ │ ├── uuid.go │ │ └── uuid_test.go │ ├── chip/ │ │ ├── LICENSE │ │ ├── README.md │ │ ├── chip_adaptor.go │ │ ├── chip_adaptor_test.go │ │ ├── chip_pinmap.go │ │ ├── chippro_adaptor.go │ │ ├── chippro_adaptor_test.go │ │ ├── chippro_pinmap.go │ │ └── doc.go │ ├── dexter/ │ │ ├── README.md │ │ ├── dexter.go │ │ └── gopigo3/ │ │ ├── README.md │ │ ├── driver.go │ │ └── driver_test.go │ ├── digispark/ │ │ ├── LICENSE │ │ ├── README.md │ │ ├── digispark_adaptor.go │ │ ├── digispark_adaptor_test.go │ │ ├── digispark_i2c.go │ │ ├── digispark_i2c_test.go │ │ ├── doc.go │ │ ├── littleWire.c │ │ ├── littleWire.go │ │ ├── littleWire.h │ │ ├── littleWire_servo.c │ │ ├── littleWire_servo.h │ │ ├── littleWire_util.c │ │ ├── littleWire_util.h │ │ ├── opendevice.c │ │ └── opendevice.h │ ├── dji/ │ │ ├── README.md │ │ ├── dji.go │ │ └── tello/ │ │ ├── README.md │ │ ├── crc.go │ │ ├── driver.go │ │ ├── driver_test.go │ │ ├── pitch.go │ │ └── pitch_test.go │ ├── dragonboard/ │ │ ├── LICENSE │ │ ├── README.md │ │ ├── doc.go │ │ ├── dragonboard_adaptor.go │ │ └── dragonboard_adaptor_test.go │ ├── firmata/ │ │ ├── LICENSE │ │ ├── README.md │ │ ├── ble_firmata_adaptor.go │ │ ├── ble_firmata_adaptor_test.go │ │ ├── client/ │ │ │ ├── client.go │ │ │ ├── client_test.go │ │ │ └── examples/ │ │ │ └── blink.go │ │ ├── doc.go │ │ ├── firmata_adaptor.go │ │ ├── firmata_adaptor_test.go │ │ ├── firmata_i2c.go │ │ ├── firmata_i2c_test.go │ │ ├── tcp_firmata_adaptor.go │ │ └── tcp_firmata_adaptor_test.go │ ├── friendlyelec/ │ │ ├── nanopct6/ │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── adaptor.go │ │ │ ├── adaptor_test.go │ │ │ ├── doc.go │ │ │ └── pinmap.go │ │ └── nanopi/ │ │ ├── LICENSE │ │ ├── README.md │ │ ├── adaptor.go │ │ ├── adaptor_test.go │ │ ├── doc.go │ │ └── neo_pinmap.go │ ├── holystone/ │ │ ├── README.md │ │ ├── holystone.go │ │ └── hs200/ │ │ ├── README.md │ │ ├── doc.go │ │ ├── hs200_driver.go │ │ └── hs200_driver_test.go │ ├── intel-iot/ │ │ ├── LICENSE │ │ ├── README.md │ │ ├── curie/ │ │ │ ├── README.md │ │ │ ├── doc.go │ │ │ ├── imu_driver.go │ │ │ └── imu_driver_test.go │ │ ├── edison/ │ │ │ ├── README.md │ │ │ ├── arduino_pinmap.go │ │ │ ├── doc.go │ │ │ ├── edison_adaptor.go │ │ │ ├── edison_adaptor_test.go │ │ │ ├── miniboard_pinmap.go │ │ │ └── sparkfun_pinmap.go │ │ ├── intel-iot.go │ │ └── joule/ │ │ ├── README.md │ │ ├── doc.go │ │ ├── joule_adaptor.go │ │ ├── joule_adaptor_test.go │ │ └── tuchuck_pinmap.go │ ├── jetson/ │ │ ├── README.md │ │ ├── adaptor.go │ │ ├── adaptor_test.go │ │ ├── doc.go │ │ └── pinmap.go │ ├── joystick/ │ │ ├── LICENSE │ │ ├── README.md │ │ ├── bin/ │ │ │ └── scanner.go │ │ ├── configs/ │ │ │ ├── dualsense.json │ │ │ ├── dualshock3.json │ │ │ ├── dualshock4.json │ │ │ ├── magicseer1.json │ │ │ ├── shield.json │ │ │ └── xbox360_power_a_mini_proex.json │ │ ├── doc.go │ │ ├── events.go │ │ ├── joystick_adaptor.go │ │ ├── joystick_adaptor_test.go │ │ ├── joystick_driver.go │ │ ├── joystick_driver_test.go │ │ ├── joystick_dualsense.go │ │ ├── joystick_dualshock3_darwin.go │ │ ├── joystick_dualshock3_linux.go │ │ ├── joystick_dualshock3_windows.go │ │ ├── joystick_dualshock4_darwin.go │ │ ├── joystick_dualshock4_linux.go │ │ ├── joystick_dualshock4_windows.go │ │ ├── joystick_nintendo_joycon.go │ │ ├── joystick_shield.go │ │ ├── joystick_tflight_hotas_x.go │ │ ├── joystick_xbox360.go │ │ ├── joystick_xbox360_rock_band_drums.go │ │ ├── joystick_xboxone.go │ │ └── test_helper.go │ ├── keyboard/ │ │ ├── LICENSE │ │ ├── README.md │ │ ├── doc.go │ │ ├── keyboard.go │ │ ├── keyboard_driver.go │ │ ├── keyboard_driver_test.go │ │ └── keyboard_test.go │ ├── leap/ │ │ ├── LICENSE │ │ ├── README.md │ │ ├── doc.go │ │ ├── leap_motion_adaptor.go │ │ ├── leap_motion_adaptor_test.go │ │ ├── leap_motion_driver.go │ │ ├── leap_motion_driver_test.go │ │ ├── parser.go │ │ └── test/ │ │ └── support/ │ │ └── example_frame.json │ ├── mavlink/ │ │ ├── LICENSE │ │ ├── README.md │ │ ├── common/ │ │ │ ├── common.go │ │ │ ├── mavlink.go │ │ │ └── version.go │ │ ├── doc.go │ │ ├── mavlink_adaptor.go │ │ ├── mavlink_adaptor_test.go │ │ ├── mavlink_driver.go │ │ ├── mavlink_driver_test.go │ │ ├── mavlink_udp_adaptor.go │ │ └── mavlink_udp_adaptor_test.go │ ├── megapi/ │ │ ├── README.md │ │ └── doc.go │ ├── microbit/ │ │ ├── LICENSE │ │ ├── README.md │ │ └── doc.go │ ├── mqtt/ │ │ ├── LICENSE │ │ ├── README.md │ │ ├── doc.go │ │ ├── mqtt_adaptor.go │ │ ├── mqtt_adaptor_test.go │ │ ├── mqtt_driver.go │ │ └── mqtt_driver_test.go │ ├── nats/ │ │ ├── README.md │ │ ├── doc.go │ │ ├── nats_adaptor.go │ │ ├── nats_adaptor_test.go │ │ ├── nats_driver.go │ │ ├── nats_driver_test.go │ │ └── test_certs/ │ │ ├── catest-key.pem │ │ ├── catest.pem │ │ ├── client-cert.pem │ │ ├── client-key.pem │ │ ├── server-cert.pem │ │ └── server-key.pem │ ├── neurosky/ │ │ ├── LICENSE │ │ └── README.md │ ├── opencv/ │ │ ├── LICENSE │ │ ├── README.md │ │ ├── camera_driver.go │ │ ├── camera_driver_test.go │ │ ├── doc.go │ │ ├── haarcascade_frontalface_alt.xml │ │ ├── helpers_test.go │ │ ├── utils.go │ │ ├── utils_test.go │ │ ├── window_driver.go │ │ └── window_driver_test.go │ ├── orangepi/ │ │ └── orangepi5pro/ │ │ ├── LICENSE │ │ ├── README.md │ │ ├── adaptor.go │ │ ├── adaptor_test.go │ │ ├── doc.go │ │ └── pinmap.go │ ├── parrot/ │ │ ├── LICENSE │ │ ├── README.md │ │ ├── ardrone/ │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── ardrone_adaptor.go │ │ │ ├── ardrone_adaptor_test.go │ │ │ ├── ardrone_driver.go │ │ │ ├── ardrone_driver_test.go │ │ │ ├── doc.go │ │ │ ├── pitch.go │ │ │ ├── pitch_test.go │ │ │ └── test_helper.go │ │ ├── bebop/ │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── bebop_adaptor.go │ │ │ ├── bebop_adaptor_test.go │ │ │ ├── bebop_driver.go │ │ │ ├── bebop_driver_test.go │ │ │ ├── client/ │ │ │ │ ├── client.go │ │ │ │ ├── constants.go │ │ │ │ ├── examples/ │ │ │ │ │ ├── ff.conf │ │ │ │ │ ├── takeoff.go │ │ │ │ │ └── video.go │ │ │ │ └── networkframegenerator.go │ │ │ ├── doc.go │ │ │ ├── pitch.go │ │ │ ├── pitch_test.go │ │ │ └── test_helper.go │ │ ├── minidrone/ │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ └── doc.go │ │ └── parrot.go │ ├── particle/ │ │ ├── LICENSE │ │ ├── README.md │ │ ├── adaptor.go │ │ ├── adaptor_test.go │ │ └── doc.go │ ├── pebble/ │ │ ├── README.md │ │ ├── doc.go │ │ ├── pebble_adaptor.go │ │ ├── pebble_adaptor_test.go │ │ ├── pebble_driver.go │ │ └── pebble_driver_test.go │ ├── pine64/ │ │ └── rock64/ │ │ ├── LICENSE │ │ ├── README.md │ │ ├── adaptor.go │ │ ├── adaptor_test.go │ │ ├── doc.go │ │ └── pinmap.go │ ├── radxa/ │ │ ├── rockpi/ │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── adaptor.go │ │ │ ├── adaptor_test.go │ │ │ ├── doc.go │ │ │ └── pinmap.go │ │ └── zero/ │ │ ├── LICENSE │ │ ├── README.md │ │ ├── adaptor.go │ │ ├── adaptor_test.go │ │ ├── doc.go │ │ └── pinmap.go │ ├── raspi/ │ │ ├── LICENSE │ │ ├── README.md │ │ ├── adaptor.go │ │ ├── adaptor_test.go │ │ ├── doc.go │ │ └── pinmap.go │ ├── serialport/ │ │ ├── LICENSE │ │ ├── README.md │ │ ├── adaptor.go │ │ ├── adaptor_options.go │ │ ├── adaptor_options_test.go │ │ ├── adaptor_test.go │ │ ├── doc.go │ │ └── helpers_test.go │ ├── sphero/ │ │ ├── bb8/ │ │ │ ├── LICENSE │ │ │ └── README.md │ │ ├── ollie/ │ │ │ ├── LICENSE │ │ │ └── README.md │ │ ├── sphero/ │ │ │ ├── LICENSE │ │ │ └── README.md │ │ └── sprkplus/ │ │ ├── LICENSE │ │ └── README.md │ └── upboard/ │ ├── README.md │ ├── up2/ │ │ ├── LICENSE │ │ ├── README.md │ │ ├── adaptor.go │ │ ├── adaptor_test.go │ │ ├── doc.go │ │ └── pinmap.go │ └── upboard.go ├── robot.go ├── robot_test.go ├── robot_work.go ├── robot_work_test.go ├── system/ │ ├── GPIO.md │ ├── I2C.md │ ├── ONEWIRE.md │ ├── PWM.md │ ├── README.md │ ├── analogpin_sysfs.go │ ├── analogpin_sysfs_test.go │ ├── digitalpin_bench_test.go │ ├── digitalpin_cdev.go │ ├── digitalpin_cdev_test.go │ ├── digitalpin_mock.go │ ├── digitalpin_poll.go │ ├── digitalpin_poll_test.go │ ├── digitalpin_sysfs.go │ ├── digitalpin_sysfs_test.go │ ├── digitalpinaccess.go │ ├── digitalpinaccess_test.go │ ├── digitalpinoptions.go │ ├── digitalpinoptions_test.go │ ├── doc.go │ ├── fs.go │ ├── fs_mock.go │ ├── fs_mock_test.go │ ├── fs_test.go │ ├── i2c_device.go │ ├── i2c_device_test.go │ ├── onewiredevice_sysfs.go │ ├── onewiredevice_sysfs_test.go │ ├── pwmpin_sysfs.go │ ├── pwmpin_sysfs_test.go │ ├── spi_gpio.go │ ├── spi_gpio_test.go │ ├── spi_mock.go │ ├── spi_periphio.go │ ├── spiaccess.go │ ├── spiaccess_test.go │ ├── syscall.go │ ├── syscall_mock.go │ ├── sysfsfileaccess.go │ ├── system.go │ ├── system_test.go │ ├── systemoptions.go │ └── systemoptions_test.go ├── utils.go └── utils_test.go ================================================ FILE CONTENTS ================================================ ================================================ FILE: .chglog/CHANGELOG.gobot.md ================================================ # {{ .Info.Title }} Please adjust manually before add content to CHANGELOG.md. {{ if .Versions -}} ## [Unreleased]({{ .Info.RepositoryURL }}/compare/{{ $latest := index .Versions 0 }}{{ $latest.Tag.Name }}...HEAD) {{ if .Unreleased.CommitGroups -}} {{ range .Unreleased.CommitGroups -}} ### {{ .Title }} {{ range .Commits -}} * {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }} {{ end }} {{ end -}} {{ end -}} {{ end -}} {{ range .Versions }}## {{ if .Tag.Previous }}[{{ .Tag.Name }}]({{ $.Info.RepositoryURL }}/compare/{{ .Tag.Previous.Name }}...{{ .Tag.Name }}){{ else }}{{ .Tag.Name }}{{ end }} ({{ datetime "2006-01-02" .Tag.Date }}) {{ range .CommitGroups -}} ### {{ .Title }} {{ range .Commits -}} * {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }} {{ end }} {{ end -}} {{- if .NoteGroups -}} {{ range .NoteGroups -}} ### {{ .Title }} {{ range .Notes }} {{ .Body }} {{ end }} {{ end -}} {{ end -}} {{ end -}} ================================================ FILE: .chglog/README.md ================================================ # Creating a changelog automatically ## Install and configure tool We using , so refer to this side for installation instructions. It is possible to test the tool by `git-chglog --init` without overriding anything. ## Usage Example for a new release "v2.6.0": ```sh # optional update tool by: go install github.com/git-chglog/git-chglog/cmd/git-chglog@latest git checkout release git pull git fetch --tags git checkout dev git pull upstream dev git checkout -b rel/prepare_for_release_v260 git-chglog --config .chglog/config_gobot.yml --no-case --next-tag v2.6.0 v2.5.0.. > .chglog/chglog_tmp.md ``` ## Compare If unsure about any result of running git-chglog, just use: `git log --since=2025-02-16 --pretty="- %s"` ## Manual adjustment Most likely some manual work is needed to bring the items in the correct position. We use the style from ["keep a changelog"](https://keepachangelog.com/en/1.1.0/), together with the [standard template](https://github.com/git-chglog/example-type-scope-subject/blob/master/CHANGELOG.standard.md). The changelog will be generated based on the commit messages, so please follow the [Convention for Pull Request Descriptions](../CONTRIBUTING.md). An example for the following commits: * type(scope): description * i2c(PCF8583): added * gpio(HD44780): fix wrong constants * raspi(PWM): refactor usage * docs(core): usage of Kernel driver * or alternative: core(docs): usage of Kernel driver * build(style): adjust rule for golangci-lint ```md ### Build * **style**: adjust rule for golangci-lint ### Docs * **core**: usage of Kernel driver ### I2c * **PCF8583**: added ### Gpio * **HD44780**: fix wrong constants ### Raspi * **PWM**: refactor usage ### Type * **scope:** description ``` If in doubt, please refer to the current CHANGELOG.md to find the correct way. ## Finalization After all work is done in the temporary changelog file, the content can be moved to the real one and the "chglog_tmp.md" file can be removed. ================================================ FILE: .chglog/config_gobot.yml ================================================ style: github template: CHANGELOG.gobot.md info: title: Auto-Generated Changelog repository_url: https://github.com/hybridgroup/gobot options: header: pattern: "^(\\w*|1-wire)(?:\\(([\\w\\$\\.\\,\\-\\*\\s]*)\\))?\\:?\\s(.*)$" pattern_maps: - Type - Scope - Subject notes: keywords: - BREAKING CHANGE ================================================ FILE: .circleci/config.yml ================================================ # Since switch to cimg, the GOPATH has been changed from /go to $HOME/go. # The latter will expand to the full path of /home/circleci/go. # On first run, this change may affect caching and some other commands if # you don’t correct the page in your config. # # Specify service dependencies here if necessary # CircleCI maintains a library of pre-built images # documented at https://circleci.com/docs/circleci-images # - image: cimg/postgres:14.5.0 # # For more information, please read https://github.com/CircleCI-Public/cimg-go/blob/main/README.md version: 2 jobs: "test_core_and_drivers_with_coverage": docker: - image: cimg/go:1.24 steps: - checkout - run: name: Debug version command: go version - run: name: Core and drivers tests command: | go test -race -v -coverprofile=coverage.txt -covermode=atomic . ./drivers/... - run: name: Code coverage command: | bash <(curl -s https://codecov.io/bash) "test_platforms": docker: - image: cimg/go:1.24 steps: - checkout - run: name: Debug version command: go version - run: # digispark needs libusb, opencv needs opencv name: Platform tests (except digispark and opencv) command: | go test -race -v $(go list ./platforms/... | grep -v platforms/digispark | grep -v platforms/opencv) "check_examples": docker: - image: cimg/go:1.24 steps: - checkout - run: name: Debug version command: go version - run: # digispark needs libusb, opencv needs opencv name: Check examples (except digispark, opencv) command: | ALL=$(grep -l -r --include "*.go" 'build example' ./) SOME=$(grep -L 'digispark' $(grep -L 'gocv' ${ALL})) for e in ${SOME} ; do go vet "${e}" ; done "fmt_check_examples": docker: - image: golangci/golangci-lint:v2.4.0 steps: - checkout - run: name: Debug linter version command: golangci-lint --version - run: # digispark needs libusb, opencv needs opencv name: Check examples for linter issues (except digispark, opencv) command: | ALL=$(grep -l -r --include "*.go" 'build example' ./) SOME=$(grep -L 'digispark' $(grep -L 'gocv' ${ALL})) for e in ${SOME} ; do golangci-lint run "${e}" --build-tags example --disable forcetypeassert --disable noctx ; done workflows: version: 2 build: jobs: - "test_core_and_drivers_with_coverage" - "test_platforms" - "check_examples" - "fmt_check_examples" ================================================ FILE: .github/FUNDING.yml ================================================ # These are supported funding model platforms # github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] patreon: deadprogram # open_collective: # Replace with a single Open Collective username # ko_fi: # Replace with a single Ko-fi username # tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel # custom: # Replace with a single custom sponsorship URL ================================================ FILE: .github/dependabot.yml ================================================ # package-ecosystem, directory and schedule is mandatory version: 2 updates: - package-ecosystem: "gomod" directory: "/" schedule: interval: "weekly" # Raise pull requests for version updates # for go modules against the `dev` branch target-branch: "dev" ================================================ FILE: .github/pull_request_template.md ================================================ ## Solved issues and/or description of the change ... ## Manual test - OS and Version (Win/Mac/Linux): - Adaptor(s) and/or driver(s): ... ## Checklist - [ ] The PR's target branch is 'hybridgroup:dev' - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] New and existing unit tests pass locally with my changes (e.g. by run `make test_race`) - [ ] No linter errors exist locally (e.g. by run `make fmt_check`) - [ ] I have performed a self-review of my own code If this is a new driver or adaptor: - [ ] I have added the name to the corresponding README.md - [ ] I have added an example to see how to setup and use it - [ ] I have checked or build at least my new example (e.g. by run `make examples_check`) If this is a Go version or module update: - [ ] go.mod to new version updated - [ ] modules updated (go get -u -t ./...) - [ ] CI files updated - [ ] linter setting and linter version (if a newer one exist) updated - [ ] linter issues fixed or suppressed by config If this is a PR for release: - [ ] The PR's target branch is 'hybridgroup:release' - [ ] I have adjusted the CHANGELOG.md (or already prepared and will be merged as soon as possible) ================================================ FILE: .github/workflows/golangci-lint.yml ================================================ name: golangci-lint on: push: tags: - v* branches: - dev pull_request: permissions: contents: read # Optional: allow read access to pull request. Use with `only-new-issues` option. # pull-requests: read jobs: golangci: name: lint runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 - uses: actions/setup-go@v5 with: go-version: '1.24' cache: false - name: golangci-lint uses: golangci/golangci-lint-action@v7 with: # Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version version: v2.4.0 # Optional: working directory, useful for monorepos # working-directory: v2 # Optional: golangci-lint command line arguments. # Note: exclude arguments, e.g. --exclude-files="my_file", will not affect the "typecheck" linter, # at least since v1.61.0 - use build tags instead. #args: --exclude-files="platforms/digispark/digispark_adaptor.go" # Optional: show only new issues if it's a pull request. The default value is `false`. # only-new-issues: true # Optional: if set to true then the all caching functionality will be complete disabled, # takes precedence over all other caching options. # skip-cache: true ================================================ FILE: .gitignore ================================================ .sass-cache *.test *.swp *.snap profile.cov count.out /parts /prime /stage vendor/ output/ .idea/ coverage.txt .chglog/chglog_tmp*.md .chglog/CHANGELOG.tpl*.md .chglog/config.yml ================================================ FILE: .golangci.yml ================================================ # note: GolangCI-Lint also searches for config files in all directories from the directory of the first analyzed path up to the root. version: "2" run: build-tags: - utils # Timeout for analysis, e.g. 30s, 5m. # gobot is very expensive, on a machine with heavy load it takes some minutes # for first run or after empty the cache by 'golangci-lint cache clean' # Default: 1m timeout: 5m # If set we pass it to "go list -mod={option}". From "go help modules": # If invoked with -mod=readonly, the go command is disallowed from the implicit # automatic updating of go.mod described above. Instead, it fails when any changes # to go.mod are needed. This setting is most useful to check that go.mod does # not need updates, such as in a continuous integration and testing system. # If invoked with -mod=vendor, the go command assumes that the vendor # directory holds the correct copies of dependencies and ignores # the dependency descriptions in go.mod. # # Allowed values: readonly|vendor|mod # By default, it isn't set. modules-download-mode: readonly # https://golangci-lint.run/usage/linters/#enabled-by-default # note: typecheck can not be disabled, it is used to check code compilation linters: default: all disable: # deprecated: none # not used for this go version: none # not used for any reason - err113 # not used (we allow error creation at return statement) - exhaustive # not used (we allow incomplete usage of enum switch, e.g. with default case) - forbidigo # not used (we allow print statements) - ginkgolinter # not needed (enforces standards of using ginkgo and gomega) - gochecknoglobals # not used (we allow definition of unexposed variables at top level) - godot # not used (seems to be counting peas) - godox # not used (we have many TODOs, so not useful) - gosmopolitan # not needed (report i18n/l10n anti-patterns) - importas # not needed (there is no alias rule at the moment) - ireturn # not used (we allow return interfaces) - loggercheck # not needed (relates to kitlog, klog, logr, zap) - noinlineerr # this violates best practices in other style guides - paralleltest # not used - promlinter # not needed (prometheus metrics naming) - rowserrcheck # not needed (sql related) - sqlclosecheck # not needed (sql related) - testpackage # not needed, we use the same name for test package to have access to unexposed items - wrapcheck # not needed (we allow errors from interface methods) - zerologlint # not needed (related to zerolog package) # useful for the future - cyclop # useful with some tweeks (better understandable code), see also gocyclo - dupl # useful with some tweeks (reduce bugs and lines of code) - errname # useful for common style - exhaustruct # useful with some exclusions for existing code (e.g. mavlink/common/common.go) - funcorder # common style, but too many findings - funlen # useful with some tweeks (reduce bugs, simplify code, better understandable code) - gocognit # useful with some tweeks (better understandable code) - goconst # useful (reduce bugs) - gocyclo # useful with some tweeks (better understandable code) - goheader # useful, if we introduce a common header (e.g. for copyright) - interfacebloat # useful with some exclusions at usage of external packages - intrange # introduced with go 1.22, will simplify the range syntax - maintidx # useful with some tweeks (better understandable code), maybe use instead "gocyclo", "gocognit" , "cyclop" - mnd # useful with some exclusions for existing code (e.g. mavlink.go) - nestif # useful (reduce bugs, simplify code, better understandable code) - nlreturn # more common style, but could become annoying - tagliatelle # maybe useful with some tweaking or excluding - varnamelen # maybe useful with some tweaking, but many findings - whitespace # more common style, but could become annoying - wsl # more common style, but could become annoying - wsl_v5 # same as above exclusions: generated: lax presets: - comments - common-false-positives - legacy - std-error-handling settings: depguard: # Rules to apply. # # Variables: # - File Variables # you can still use and exclamation mark ! in front of a variable to say not to use it. # Example !$test will match any file that is not a go test file. # # `$all` - matches all go files # `$test` - matches all go test files # # - Package Variables # # `$gostd` - matches all of go's standard library (Pulled from `GOROOT`) # # Default: Only allow $gostd in all files. rules: main: # Packages that are not allowed where the value is a suggestion. deny: - pkg: github.com/pkg/errors desc: Should be replaced by standard lib errors package dupword: # Keywords for detecting duplicate words. # If this list is not empty, only the words defined in this list will be detected. # Default: [] keywords: - the - and - a errorlint: # Default: true # %v should be used by default over %w, see https://github.com/uber-go/guide/blob/master/style.md#error-wrapping errorf: false # Permit more than 1 %w verb, valid per Go 1.20 (Requires errorf:true) # Default: true errorf-multi: false gocritic: disabled-checks: - assignOp # very opinionated - appendAssign # mostly used by intention nolintlint: # Enable to require an explanation of nonzero length after each nolint directive. # Default: false require-explanation: true # Enable to require nolint directives to mention the specific linter being suppressed. # Default: false require-specific: true perfsprint: # Optimizes `fmt.Errorf`. # Default: true errorf: false # Optimizes `fmt.Sprintf` with only one argument # Default: true sprintf1: false revive: rules: # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unexported-return # disable this rule, because sometimes it has its justification - name: unexported-return severity: warning disabled: true formatters: enable: - gci - gofmt - gofumpt - goimports exclusions: generated: lax settings: gci: # Section configuration to compare against. # Section names are case-insensitive and may contain parameters in (). # The default order of sections is `standard > default > custom > blank > dot`, # If `custom-order` is `true`, it follows the order of `sections` option. # Default: ["standard", "default"] sections: - standard # Standard section: captures all standard packages. - default # Default section: contains all imports that could not be matched to another section type. - prefix(gobot.io/x/gobot/) # Custom section: groups all imports with the specified Prefix. #- blank # Blank section: contains all blank imports. This section is not present unless explicitly enabled. #- dot # Dot section: contains all dot imports. This section is not present unless explicitly enabled. # Enable custom order of sections. # If `true`, make the section order the same as the order of `sections`. # Default: false custom-order: true ================================================ FILE: CHANGELOG.md ================================================ # CHANGELOG ## [Unreleased](https://github.com/hybridgroup/gobot/compare/v2.6.0...HEAD) ## [v2.6.0](https://github.com/hybridgroup/gobot/compare/v2.5.0...v2.6.0) (2025-10-18) ### Adaptors * **all:** add debug option ([#1181](https://github.com/hybridgroup/gobot/issues/1181)) ### Ble * fix some issues in connect and disconnect ([#1161](https://github.com/hybridgroup/gobot/issues/1161)) ### Build * **deps:** update modules ([#1186](https://github.com/hybridgroup/gobot/issues/1186)) * **go, deps:** switch to Go 1.24 linter 2.4.0 and update modules ([#1162](https://github.com/hybridgroup/gobot/issues/1162)) ### Common * improve robot level errors ([#1180](https://github.com/hybridgroup/gobot/issues/1180)) ### Doc * **core:** prepare for release v2.6.0 ### Drivers * fix nil connector check ([#1178](https://github.com/hybridgroup/gobot/issues/1178)) ### I2c * **adafruit1109:** rework debug messages ([#1182](https://github.com/hybridgroup/gobot/issues/1182)) * **all:** ensure halt is idempotent ([#1171](https://github.com/hybridgroup/gobot/issues/1171)) * **bme280:** fix default name ([#1177](https://github.com/hybridgroup/gobot/issues/1177)) * **mcp23017:** fix missing code for halt is idempotent ([#1175](https://github.com/hybridgroup/gobot/issues/1175)) ### Onewire * **all:** ensure halt is idempotent ([#1174](https://github.com/hybridgroup/gobot/issues/1174)) ### Platforms * **bleclient:** improve errors and add sleep option ([#1179](https://github.com/hybridgroup/gobot/issues/1179)) ### Spi * **all:** ensure halt is idempotent ([#1173](https://github.com/hybridgroup/gobot/issues/1173)) ### Wiichuck * fix go routine leaking and concurrency problem ([#1172](https://github.com/hybridgroup/gobot/issues/1172)) ## [v2.5.0](https://github.com/hybridgroup/gobot/compare/v2.4.0...v2.5.0) (2025-02-16) ### Build * **deps:** update modules ([#1131](https://github.com/hybridgroup/gobot/issues/1131)) * **linter:** update linter to v1.64.5 and fix issues ([#1130](https://github.com/hybridgroup/gobot/issues/1130)) ### Core * **system:** split system accesser features ([#1121](https://github.com/hybridgroup/gobot/issues/1121)) ### Doc * **core:** prepare for release v2.5.0 ### Drivers * fix some function names in comment ([#1103](https://github.com/hybridgroup/gobot/issues/1103)) ### Examples * correct all usage of ps3 joystick reads, which are now int instead of int16 ([#1085](https://github.com/hybridgroup/gobot/issues/1085)) ### Gpio * rename gpiod to gpiocdev ([#1116](https://github.com/hybridgroup/gobot/issues/1116)) * **adaptors:** fix so now gpiodev is used as default ([#1112](https://github.com/hybridgroup/gobot/issues/1112)) * **core:** fix sporadic hang on finish for discrete edge polling ([#1107](https://github.com/hybridgroup/gobot/issues/1107)) ### Nanopct6 * introduce adaptor for FriendlyELEC NanoPC-T6 ([#1126](https://github.com/hybridgroup/gobot/issues/1126)) ### Onewire * **ds18b20:** introduce 1-wire device access by sysfs and temp driver ([#1091](https://github.com/hybridgroup/gobot/issues/1091)) ### Orangepi5pro * introduce adaptor for OrangePi 5 Pro ([#1129](https://github.com/hybridgroup/gobot/issues/1129)) ### Platforms * file name and folder unification ([#1127](https://github.com/hybridgroup/gobot/issues/1127)) ### Pocketbeagle * introduce and use cdev by default ([#1118](https://github.com/hybridgroup/gobot/issues/1118)) ### Rock64 * introduce adaptor for PINE64-ROCK64 ([#1122](https://github.com/hybridgroup/gobot/issues/1122)) ### Sphero * fix panic by removing unnecessary go routine ([#1117](https://github.com/hybridgroup/gobot/issues/1117)) ### Tests * fix for arm64 environment and stabilize ([#1115](https://github.com/hybridgroup/gobot/issues/1115)) ### Tinkerboard2 * introduce adapter for Asus Tinker Board 2 ([#1108](https://github.com/hybridgroup/gobot/issues/1108)) ### Zero * introduce adaptor for Radxa Zero ([#1128](https://github.com/hybridgroup/gobot/issues/1128)) ## [v2.4.0](https://github.com/hybridgroup/gobot/compare/v2.3.0...v2.4.0) (2024-11-05) ### Bebop * fix concurrent map writes ([#1063](https://github.com/hybridgroup/gobot/issues/1063)) ### Ble * add support for functional options, add tests ([#1059](https://github.com/hybridgroup/gobot/issues/1059)) * introduce in drivers folder ([#1057](https://github.com/hybridgroup/gobot/issues/1057)) * **client:** add scan timout ([#1051](https://github.com/hybridgroup/gobot/issues/1051)) * **module:** update tinygo.org/x/bluetooth to v0.10 and adapt code ([#1084](https://github.com/hybridgroup/gobot/issues/1084)) ### Build * **go, deps:** switch to Go 1.22 and update modules, linter v1.61.0 and adapt code ([#1093](https://github.com/hybridgroup/gobot/issues/1093),[#1092](https://github.com/hybridgroup/gobot/issues/1092)) * **go, deps:** switch to Go 1.20 and update modules ([#1067](https://github.com/hybridgroup/gobot/issues/1067)) * **linter:** update linter to v1.56.1 and fix issues ([#1068](https://github.com/hybridgroup/gobot/issues/1068)) ### Doc * update links to release or tagged branch ([#1069](https://github.com/hybridgroup/gobot/issues/1069)) * **core:** prepare for release v2.4.0 ### Examples * fix missing checks of return values ([#1060](https://github.com/hybridgroup/gobot/issues/1060)) ### Gobot * rename Master to Manager ([#1070](https://github.com/hybridgroup/gobot/issues/1070)) ### Megapi * use serialport adaptor and move driver to drivers/serial ([#1062](https://github.com/hybridgroup/gobot/issues/1062)) ### Neurosky * use serialport adaptor and move driver to drivers/serial ([#1061](https://github.com/hybridgroup/gobot/issues/1061)) ### Test * try to stabilize eventer tests ([#1066](https://github.com/hybridgroup/gobot/issues/1066)) * try to stabilize firmata tests ([#1097](https://github.com/hybridgroup/gobot/issues/1097)) ## [v2.3.0](https://github.com/hybridgroup/gobot/compare/v2.2.0...v2.3.0) (2024-01-06) ### Adaptors * **pwm:** introduce scale option for servo ([#1046](https://github.com/hybridgroup/gobot/issues/1046)) * **analogpins:** add a generic analog pin adaptor ([#1041](https://github.com/hybridgroup/gobot/issues/1041)) ### Aio * fix data race in AnalogSensorDriver ([#1024](https://github.com/hybridgroup/gobot/issues/1024)) * **all:** introduce functional options ([#1039](https://github.com/hybridgroup/gobot/issues/1039)) * **analog sensor:** fix deadlock in cyclic reading ([#1042](https://github.com/hybridgroup/gobot/issues/1042)) * **thermalzone:** add driver for read a thermalzone from system ([#1040](https://github.com/hybridgroup/gobot/issues/1040)) ### Build * **go, deps:** update modules ([#1047](https://github.com/hybridgroup/gobot/issues/1047), [#1052](https://github.com/hybridgroup/gobot/issues/1052)) ### Doc * **test:** use -race for tests by default ([#1035](https://github.com/hybridgroup/gobot/issues/1035)) ### Gpio * fix data race in StepperDriver ([#1029](https://github.com/hybridgroup/gobot/issues/1029)) * fix data race in PIRMotionDriver ([#1028](https://github.com/hybridgroup/gobot/issues/1028)) * fix data race in ButtonDriver ([#1027](https://github.com/hybridgroup/gobot/issues/1027)) * fix data race in EasyDriver ([#1025](https://github.com/hybridgroup/gobot/issues/1025)) * **all:** introduce functional options ([#1045](https://github.com/hybridgroup/gobot/issues/1045)) ### I2c * **core:** fix problems with usage of uintptr ([#1033](https://github.com/hybridgroup/gobot/issues/1033)) ### Lint * **all:** fix issues of errorlint etc ([#1037](https://github.com/hybridgroup/gobot/issues/1037)) * **all:** switch to 1.55.2 and adjust linter issues ([#1036](https://github.com/hybridgroup/gobot/issues/1036)) ### Ollie * **test:** fix data race in test ([#1034](https://github.com/hybridgroup/gobot/issues/1034)) ### Raspi * **pwm:** add support for sysfs and fix pi-blaster ([#1048](https://github.com/hybridgroup/gobot/issues/1048)) ## [v2.2.0](https://github.com/hybridgroup/gobot/compare/v2.1.1...v2.2.0) (2023-10-29) ### Adaptors * **PWM:** fix wrong duty cycle after kill program ([#994](https://github.com/hybridgroup/gobot/issues/994)) ### Beaglebone * **doc:** fix preceding typo ([#985](https://github.com/hybridgroup/gobot/issues/985)) ### Build * **deps:** module update ([#992](https://github.com/hybridgroup/gobot/issues/992)) * **go, deps:** switch to Go 1.19 and update modules ([#1008](https://github.com/hybridgroup/gobot/issues/1008)) * **style:** switch to gofumpt and add linters ([#1009](https://github.com/hybridgroup/gobot/issues/1009)) ### Doc * **roadmap:** remove file ROADMAP.md after creating issues ([#1005](https://github.com/hybridgroup/gobot/issues/1005)) ### Dragonboard * fix example and documentation ([#977](https://github.com/hybridgroup/gobot/issues/977)) ### Gpio * **hcsr04:** add driver for ultrasonic ranging module ([#1012](https://github.com/hybridgroup/gobot/issues/1012)) ### I2c * **PCA9685, adafruit, adafruit2327, adafruit2348:** clean up architecture and fix init ([#1021](https://github.com/hybridgroup/gobot/issues/1021)) ### Jetson * **PWM:** fix set period ([#1019](https://github.com/hybridgroup/gobot/issues/1019)) ### Joystick * **core:** replace sdl with 0xcafed00d/joystick package ([#988](https://github.com/hybridgroup/gobot/issues/988)) ### Sphero * Add support for calibration ### System * **gpio:** add edge polling function ([#1015](https://github.com/hybridgroup/gobot/issues/1015)) ### Test * **all:** substitude assert.Nil by assert.NoError if useful ([#1016](https://github.com/hybridgroup/gobot/issues/1016)) * **all:** substitude assert.Error by assert.ErrorContains ([#1014](https://github.com/hybridgroup/gobot/issues/1014), [#1011](https://github.com/hybridgroup/gobot/issues/1011)) * **all:** switch to test package stretchr testify ([#1006](https://github.com/hybridgroup/gobot/issues/1006)) * **gpio, aio:** cleanup helper_test ([#1018](https://github.com/hybridgroup/gobot/issues/1018)) ## [v2.1.1](https://github.com/hybridgroup/gobot/compare/v2.1.0...v2.1.1) (2023-07-07) ### All * upgrade modules * substitute deprecated ioutil methods ([#923](https://github.com/hybridgroup/gobot/issues/923)) * **linter:** activate linters "errcheck", "ineffassign", "unused" and fix issues ([#950](https://github.com/hybridgroup/gobot/issues/950)) * **linter, format:** format code and list of linter todo's ([#962](https://github.com/hybridgroup/gobot/issues/962)) * **linter:** activate linter "makezero" and fix issue ([#965](https://github.com/hybridgroup/gobot/issues/965)) ### Ble * simplify and substitute errors.Wrap() ([#958](https://github.com/hybridgroup/gobot/issues/958)) ### Build * **go:** switch to Go 1.18 ([#940](https://github.com/hybridgroup/gobot/issues/940)) ### Core * CLI removed ([#946](https://github.com/hybridgroup/gobot/issues/946)) ### Doc * fix and improve documentation regarding to installation ([#946](https://github.com/hybridgroup/gobot/issues/946), [#970](https://github.com/hybridgroup/gobot/issues/970)) ### Mavlink * fix linter issues of errcheck ([#959](https://github.com/hybridgroup/gobot/issues/959)) ### System * **syscall:** switch to x/sys ([#963](https://github.com/hybridgroup/gobot/issues/963)) ### Tello * fix wifiMessage and lightMessage ([#957](https://github.com/hybridgroup/gobot/issues/957)) * fix partially [#793](https://github.com/hybridgroup/gobot/issues/793) by initialize doneCh in NewDriverWithIP ([#931](https://github.com/hybridgroup/gobot/issues/931)) ## [v2.1.0](https://github.com/hybridgroup/gobot/compare/v2.0.3...v2.1.0) (2023-05-29) ### Build * **v2:** revert of [#927](https://github.com/hybridgroup/gobot/pull/927), no usage of a v2 subfolder anymore (issue [#920](https://github.com/hybridgroup/gobot/issues/920)) ## [v2.0.3](https://github.com/hybridgroup/gobot/compare/v2.0.2...v2.0.3) (2023-05-24) * accidentally created release without any changes ## [v2.0.2](https://github.com/hybridgroup/gobot/compare/v2.0.1...v2.0.2) (2023-05-22) ### Build * **v2:** fix usage by moving code to a v2 subfolder ([#927](https://github.com/hybridgroup/gobot/pull/927)) ## [v2.0.1](https://github.com/hybridgroup/gobot/compare/v2.0.0...v2.0.1) (2023-05-21) ### Build * **style:** add golangci-lint workflow configuration ([#916](https://github.com/hybridgroup/gobot/issues/916)) * **style:** fix linter findings of "gosimple", "govet" and "staticcheck" ([#917](https://github.com/hybridgroup/gobot/issues/917)) ### Bump * periph.io/x/conn/v3 from 3.6.10 to 3.7.0 ([#913](https://github.com/hybridgroup/gobot/issues/913)) * github.com/gofrs/uuid from 4.3.0+incompatible to 4.4.0+incompatible ([#914](https://github.com/hybridgroup/gobot/issues/914)) * golang.org/x/net from 0.1.0 to 0.10.0 ([#915](https://github.com/hybridgroup/gobot/issues/915)) * github.com/nats-io/nats-server/v2 from 2.1.0 to 2.7.4 ([#906](https://github.com/hybridgroup/gobot/issues/906)) ### Core * fix Semantic Import Versioning for v2 ([#921](https://github.com/hybridgroup/gobot/issues/921)) ### Docs * **core:** adjust changelog generation ([#924](https://github.com/hybridgroup/gobot/issues/924)) ## [v2.0.0](https://github.com/hybridgroup/gobot/compare/v1.16.0...v2.0.0) (2023-05-15) ### ble * update to TinyGo Bluetooth package v0.6.0 release ### build * update appveyor for go 1.19 * switch to new cimg with golang 1.17 * new home path for cimg * check examples in CI ([#884](https://github.com/hybridgroup/gobot/issues/884)) * add tests of more platforms to CI * add configuration file for dependabot ([#907](https://github.com/hybridgroup/gobot/issues/907)) * add PR template ### core * use base driver for all I2C devices * rename package "sysfs" to "system" * go.mod to 1.17 and all modules incl. code upgrades ## digispark * add example for generic i2c.Driver * fix i2c.ReadBlockData(), Read_Data() and some small other fixes ### dji tello * Halt does not terminate all the related goroutines and may wait forever when it is called multiple times ### docs * README for gpio, pwm, i2c and add example * document fields for flight data ### aio * analog sensor driver to prevent ReadValue() to get float64 ### gopigo3 * fix examples and driver ### gpio * add advanced digital pin options (pull, bias, drive, debounce, event) * add support for new character device Kernel ABI for GPIO * add read firmware version and DHT sensors for grovepi ### i2c * add generic i2c driver * fix I2C connection-bus caching and multiple device usage * introduce I2cBusAdaptor for composition in platforms * **Adafruit1109:** fix driver shows bad characters after Halt() * **ads1x15:** fix driver not working stable when reading multiple inputs * **ADXL345:** use ReadBlockData() * **bmxy8z:** use ReadBlockData * **BMP180, BMP280 BMP388 BME280:** use ReadBlockData() * **CCS811:** use ReadBlockData() * **HMC5883L:** fix I2C driver typo: change from HMC8553L * **HMC5883L:** fix driver returns wrong values * **L3GD20H:** fix full scale range usage * **MPL115A2:** use ReadBlockData(), WriteByteData() * **MPU6050:** fix wrong initialize and reduced temperature resolution * **PCA9501:** add driver * **PCA953x:** add driver * **PCF8583:** add driver * **TH02:** fix wrong register usage for read heater ### jetson nano * add Jetson Nano adpator * fix pwm feature ### joystick * add Xbox-One controller * add configuration for Nintendo Switch controllers ([#903](https://github.com/hybridgroup/gobot/issues/903)) * add Dualsense joystick (PlayStation 5) ([#880](https://github.com/hybridgroup/gobot/issues/880)) ### nanopi neo * add platform ### piblaster * add unused but missing interface implementation ### radxa rock pi 4(c+) * add platform ([#902](https://github.com/hybridgroup/gobot/issues/902)) ### raspi * fix pwm cache * fix Stopping and Starting Robot and LED Driver/LED does not toggle on restart ### spi * fix spi.SpiConnection is not gobot.Connection: missing method Connect * using GPIO's is now possible * **MFRC522:** add driver ### test * increase some timings to make tests a little less fragile * skip test TestNatsAdaptorFailedConnect when flaky * stabilize "every"-test * stabilize flaky utils_test * stabilize firmata tests * fix tests with sysfs mocks, ReadBlockData, WriteBlockData * fix keyboard tests and exclude opencv * fix PWM related read/write tests * add check for examples in Makefile ### tinkerboard * fix new pwm behaviour ### BREAKING CANGES * some interfaces moved, see folder system and adaptor.go ## [v1.16.0](https://github.com/hybridgroup/gobot/compare/v1.15.0...v1.16.0) (2022-05-02) ### bugfix * failing leftovers after usage of PR #569 * Fix servo and DC motors presence * FIX the bug #568 without further impact, heavy improvements of tests * fixed PinMode, SetPullUp and SetPolarity, unit tests activated * ReadGPIO fixed with #576, failing leftovers for PinMode, SetPullUp and SetPolarity * helper_test ReadByteData, ReadWordData to use reg ### core * update uuid package and directly access it; remove archived uuid package ### digispark * fix ReadByte & WriteByte, rework and add i2c tests * remove useless code in i2c test ### drivers * add AnalogActuatorDriver, analog temperature sensor, driver for PCF8591 (with 400kbit stabilization), driver for YL-40 * Adding support for hmc5883l compass * bmp388 fix missing address write byte in test of Measurements * drv2605l fix missing address write byte in test of Halt() * introduce adafruit1109 2x16 LCD with 5 keys * mcp23017: add mutex for write, hd44780: fix mutexes * MCP3004: correct number of channels ### raspi * fix raspi PWMPin.SetDutyCycle (#800) ### tello * Guards Dji Tello Halt against nil dereference ### test * don't panic on 'With*' allow simpler wrapping of drivers ### tinkerboard * fix tinkerboard i2c0 to i2c4, improve comments in pin map, improve README ## [v1.15.0](https://github.com/hybridgroup/gobot/compare/v1.14.0...v1.15.0) (2020-11-30) ### build * Switch to CircleCI ### ble * replace go-ble with tinygo bluetooth package, restore macOS functionality ### gpio * Update RelayDriver to invert value written on Inverted * Add tests for DigitalWrite value * Add support for HD44780 LCD controller * Add delay for Run function of StepperDriver ### spi * fixes #700 * Avoid to close the connection. ### i2c * add SHT2x device * add BMP388 Barometric Pressure/Temperature/Altitude Sensor ### pwm * Resolve issue with PWM for PWMWrite ### mqtt * Add method to publish MQTT messages with retain flag ### tello * Add graceful halt for Tello driver * Add Tello EDU driver ### keyboard * add symbol keys for platform/keyboard ### examples * Update ffmpeg command to decrease latency in tello example ## [v1.14.0](https://github.com/hybridgroup/gobot/compare/v1.13.0...v1.14.0) (2019-10-15) ### core * migrating from dep to go modules * update codegangsta to urfave (#690) ### docs * Fix a link in package docs' example code. ### examples * fixed broken imports due to changed path causing go get to fail ### gpio * Added ability to make a relay driver inverted (#674) ### opencv * Update to GoCV 0.21.0 ### spi * Apa102 use default brightness (#671) ### tello * Updated videoPort for DJI Tello to 11111 ## [v1.13.0](https://github.com/hybridgroup/gobot/compare/v1.12.0...v1.13.0) (2019-05-22) ### api * Initial stab at Robot-based work ### build * correct package version as suggested by @dlisin thanks * only build last 2 versions of Go plus tip for CI * Update dep script for AppVeyor * update deps to latest versions of dependencies for GoCV and others * Update Gopkg and add test dep to Travis YML * update OpenCV build script for OpenCV 4.1.0 ### docs * update to remove Gitter and replace with Slack, and update copyright dates ### example * add missing nobuild header ### gpio * Add SparkFun’s EasyDriver (and BigEasyDriver) * Add unit tests for TH02 & Minor improvement * Added rudiementary support for TH02 Grove Sensor * pwm_pin * Fix DutyCycle() parse error, need to trim off trailing '\n' before calling strconv.Atoi(), as other functions in this package do * Simplify code as suggested in #617 ### grovepi * add mutex to control transactionality of the device communication ### i2c * add 128x32 and 96x16 sizes to the i2c ssd1306 driver * build out the ccs811 driver * update PCA9685 driver to use same protocol as Adafruit Python lib ### leapmotion * Parser error in Pointable.Bases: Write test and fix * Update gobot leap platform to support Leap Motion API v6 ### mavlink * fix mavlink README to use correct example code ### mqtt * Add some new MQTT adaptor functions with QOS * Allow setting QoS on MTT adaptor * make tests run correctly even when a local MQTT server is in fact running * Do not skip verification of root CA certificates by default InsecureSkipVerify ### nats * Update Go NATS client library import ### opencv * minor updates to opencv README * update to OpenCV 4.1.0 ### sphero * Added methods to read Sphero Power States * Added some new features to the sphero ollie, bb-8 and sprkplus ### spi * correct param used for APA102 Draw() method * Stop using Red parameter for brightness value ### tello * add direct vector access * add example with keyboard * Change fps to 60 * Check for error immediately and skip publish if error occurred * update FlightData struct ### up2 * add support for built-in LEDs * correct i2c default bus information to match correct values * finalize docs for UP2 config steps * update README to include more complete setup information * useful constant values to access the built-in LEDs ## [v1.12.0](https://github.com/hybridgroup/gobot/compare/1.11.1...v1.12.0) (2018-08-27) ### api * further improvement of the modular API changes * modify Start() for more modular initialization, and add StartRaw() for completely custom API implementations * settled on StartWithoutDefaults() as the method to start API without default routes ### core * add Rescale utility function for straight linear rescaling ### digispark * add examples using digispark with i2c devices blinkm and mlp115a2 * Added i2c to digispark, but not working yet * Added some tests for digispark i2c connector * Digispark i2c fixes, added Test for checking available addresses * remove test method that should not be in adaptor * remove test that is expected to ofail, but passes when digispark board is actually connected ### docs * add GrovePi to README * adjust order of badges in README * Fixing broken link ### examples * add example that uses both the API and also a custom handler with MJPEG streaming from an attached camera * small improvements to Tello examples * update Tello examples for main thread friendly macOS/Windows, add Tello face tracker ### i2c * add commands to JHD1313MDriver * add commands to PCA9685Driver * add missing methods so the GrovePi fully implements the Adaptor interface * add ShowImage() function to ssd1306 driver based on @mikegleasonjr suggestion * GrovePi digitalwrite implemented * implemented DigitalRead, DigitalWrite, and AnalogRead for GrovePi * improve godocs for PCA9685 * mention that GrovePi requires running firmware 1.3.0 * update GrovePi to v1.3.0 firmware * work in progress on GrovePi plus driver ### joystick * add config file for Magicsee R1 contributed by @carl-ranson * add some additional test coverage for file-based config * added error handling for config loading in joystick driver * mention need to be running a Linux kernel v4.14+ for controller mappings to work as expected * provide constant values for existing joystick configurations ### raspi * export PiBlasterPeriod in Adaptor ### spi * add ShowImage() function to ssd1306 driver based on @mikegleasonjr suggestion ### tello * specify end of msgType position * add handleResponse testing * Add motion cessation commands to Tello * handleResponse only needs an io.Reader * handleResponse should not send commands * rename reqConn to cmdConn * reqConn is only an io.WriteCloser * send Land() command to drone on Halt() to avoid floating mid-air ## [1.11.1](https://github.com/hybridgroup/gobot/compare/1.11.0...1.11.1) (2018-07-10) ### build * exclude vendor and other previously excluded subpackages * update Travis build to use OpenCV 3.4.2 release * update deps for GoCV to v0.14.0 release * Bump periph.io/x/periph to v3.0.0 * update to Go 1.10.3 and 1.9.7 for Travis builds ### docs * Fix Leap Motion package link ### i2c * fix write/read gpio on mcp23017, and cleaned up some comments * correct pca9685 SetPWMFreq function scaling ### gopigo3 * update with default spi values, cleanup ## [1.11.0](https://github.com/hybridgroup/gobot/compare/1.10.2...1.11.0) (2018-05-31) ### build * correct profile file location for codecov upload * Make Go Lint happier by adding some explicit type conversions and ignoring unused error returns * single quotes needed to upload any .cov file to codecov for reporting * update deps to latest versions for Paho MQTT, go-sdl, and gocv * upload any .cov file to codecov for reporting * use go 1.10.2 and 1.9.6 for Travis builds * add step to call dep ensure before contributing #524 ### examples * correct events used by XBox360 joystick example ### firmata * Update the Firmata homepage in platform README ### gpio * Improve Stepper Driver * Initial support for MAX7219 (gpio) led driver ### joystick * full corrected ds3 and ds4 mappings plus examples to match for latest sdl 2.0.8 * add instructions to README on how to install SDL on Linux from source * add missing type conversion * add new contributions to README * Add T-Flight Hotas X flight controoller * add xbox360 rock band drums controller * Correct Dualshock4 controller mappings and add ps/left/right buttons * correct test issue * exclude scanner from test builds * Fix joystick_driver to detect dpad input for xbox controllers * Update dualshock4.json to match joystick_dualshock4.go * update scanner to match go-sdl 0.3 API changes * Update the joystick driver test to read DPAD properly ### leapmotion * change timestamp to uint64 to fix #516 ### tello * slow/fast mode switch function * StopLanding feature * Add Bounce() and PalmLand() funcs and their associated events. * bug fix * Change several fields in FlightData struct from int16 to bool * Export the FlightData fields (see Issue #531) ## [1.10.2](https://github.com/hybridgroup/gobot/compare/1.10.1...1.10.2) (2018-04-24) ### opencv * update GoCV to latest version ## [1.10.1](https://github.com/hybridgroup/gobot/compare/1.10.0...1.10.1) (2018-04-24) ### tello * improve support for DJI Tello drone, especially video ## [1.10.0](https://github.com/hybridgroup/gobot/compare/v1.9.0...1.10.0) (2018-04-20) ### docs * add gitter badge to readme ### gpio * AIP1640 led driver, used in Wemos D1 mini's matrix LED shield ### spi * switch to using periph.io for SPI interfaces * add support for ssd1306 * add optional params such as bus/chip to all current drivers * complete refactoring to spi.Connection * remove unneeded code as suggested by @maruel * remove unneeded type and cleanup GoDocs ### ble * correct spelling error in function name ### build * update to latest version of Go 1.10 for Travis build ### cli * remove extra newline ### docs * add recently contributed GPIO devices to README ### joystick * able to configure joysticks without external json file * correct error in scanning script * correct events used by gamepad-style up/down/left/right buttons * correct scanner error from ID * removed double release event ### tello * add support for DJI Tello drone ## [v1.9.0](https://github.com/hybridgroup/gobot/compare/v1.8.0...v1.9.0) (2018-02-14) ### beaglebone * update pin naming, docs, and examples for the latest Debian OS releases ### opencv * update build settings needed to build OpenCV/GoCV as part of test suite * deps for latest GoCV v0.9.0 ### build * update Travis build to use very latest Go versions ### docs * add references to new drivers for ADXL345, BH1750, and TM1638. * improve docs for installation and use of OpenCV/GoCV from Gobot * update copyright date to 2018 ### gpio * Initial support for TM1638 modules ### i2c * Added basic driver for BH1750 (light sensor), board GY-302 * support for accel ADXL345 ### bb8/ollie/sprkplus * add Boost command * add Set Back LED Output command * add Set Raw Motor Values command * add Set Rotation Rate command * add Set Stabilization command ### test * Refactor TestAdaptorDigitalPinConcurrency test ## [v1.8.0](https://github.com/hybridgroup/gobot/compare/v1.7.1...v1.8.0) (2017-12-21) ### sysfs * pause briefly to allow udev rules to apply when exporting PWMPin ### beaglebone * correct uboot installation instructions * add SPI support * no more slots, add docs on configuring u-boot overlays * handle gpio pinmux without relying on specific pre-existing setup ### pocketbeagle * add support for PocketBeagle * use universal io cape manager to initialize board setup * improve docs for latest Debian OS ### build * Add dep, change how tests run in CI * update dependencies to latest GoCV version ### spi * Add MCP3002, MCP3202, MCP3204, MCP3208, MCP3304, MCP3004, and MCP3008 A/D converter drivers * adding initial support for APA102 LEDs, thanks to code sample from @rakyll * extract shared SPI init code into spi package ### up2 * initial work on support for UP2 board ### gopigo3 * fixed set/get bug with motor dps ### gpio * Adding stepper motor module ### firmata * handle cases where out of sync data is read from serial port on first connecting ### i2c * Change init payload sequence within jhd1313m1 driver Start() func. ## [v1.7.1](https://github.com/hybridgroup/gobot/compare/v1.7.0...v1.7.1) (2017-11-05) ### sprkplus * add new platform for Sphero SPRK+ ### firmata * correct problem where last analog pin(s) were being ignored from capabilities query ### ble * use go-ble/ble fork for BLE interactions ### build * update to use latest OpenCV version * update to use latest Golang versions ## [v1.7.0](https://github.com/hybridgroup/gobot/compare/v1.6.1...v1.7.0) (2017-10-23) ### curie * Add Linux specific step to Intel Curie docs ### mqtt * Added SetCleanSession ### build * add go1.9 to versions tested in Travis CI * add missing OpenCV lib dependency * Update build to use latest Golang versions * Travis build will now require sudo to install due to OpenCV ### docs * some helpful edits for the initial spi implementation ### gopigo3 * integration of recent GoPiGo3 contributions * Added grove support, and more gopigo3 examples ### gpio * Add ButtonDriver.DefaultState to allow for 'reverse' buttons (ones that go from HIGH to LOW) ### holystone * Add initial support for HS-200 ### i2c * SSD1306.WithDisplayHeight() and SSD1306.WithDisplayWidth() for SSD1306 that use different display ratios ### joystick * add CLI utilty to scan display events to make it easier to add new joyticks * update README to address #441 ### opencv * Switchover to use GoCV and OpenCV 3.3 * Switch to use custom domain for GoCV package * all examples using new GoCV based code * correct formatting in face detect example * OpenCV face detector that is much more concurrent * update interface and examples to indicate multipurpose ## [v1.6.1](https://github.com/hybridgroup/gobot/compare/v1.6.0...v1.6.1) (2017-07-15) ### core * log failure errors on Robot Start() ### build * run test coverage with covermode=set * update build to use Golang 1.7.6 and 1.8.3 ### docs * work on ROADMAP doc ### sysfs * increase test coverage ### bb8 * use updated ble adaptor interface for tests ### ble * allow for characteristic writes both with and without a response * allow override of specific HCI device to use * eliminate race conditions from response handling ### curie * Implement Accelerometer, Gyroscope, and Temperature sensors implemented * motion detect implemented * shock detect implemented * step count implemented * tap detect implemented ### digispark * update blink example to display error message on Start() * update README with latest development info ### edison * auto-discovery of Edison board option * removed commented lines ### firmata * expose WriteSysex to external callers * adjust client test timeout values * cleanup error handling for connection code * client tests don't need so many goroutines * expose WriteSysex to external callers * improve connection code to use a proper timeout * increase test coverage * make it possible to test external devices that use firmata adaptor * refactoring firmata client * remove circular import in test * remove unused code, increase test coverage * return connect errors to client * switch to using go-serial package * Sysex response events now being handled as expected ### bme280 * fix signed/unsigned bug * Fixed incorrect error condition check when reading the 'ctrl_hum' register. * Expanded the BME280 unit test for TestBME280DriverStart() to support reading from the 'ctrl_hum' register. * Enables humidity readings in the BME280 driver by enforcing the write to the 'ctrl_meas' register, as per Section 5.4.3 of the BME280 data sheet ### chip * Fixed PWM duty cycle calculation for C.H.I.P ServoWrite * Fixed PWM init bug for C.H.I.P * C.H.I.P PWM init robust for already enabled state ### i2c * remove unused test code * write config register in little endian ### joystick * add needed constants for all PS3 buttons ### littlewire * littlewire.cc links changed to littlewire.github.io ### mavlink * switch to using go-serial package ### megapi * switch to using go-serial package ### microbit * use updated ble adaptor interface for tests ### minidrone * add example for Parrot Mambo * add support for Mambo external accessories * increase test coverage * never expect responses for characteristic writes * remove unneeded code, increase test coverage * separate flight status processing and add test coverage ### neurosky * switch to using go-serial package ### ollie * use updated ble adaptor interface for tests ### sphero * switch to using go-serial package ### tinkerboard * Updated Tinkerboard and sysfs tests to updated PWM polarity contract ## [v1.6.0](https://github.com/hybridgroup/gobot/compare/v1.5.0...v1.6.0) (2017-06-15) ### Bb8 * use updated ble adaptor interface for tests ### Ble * eliminate race conditions from response handling * allow for characteristic writes both with and without a response * allow override of specific HCI device to use ### Build * update build to use Golang 1.8.3 * update build to use Golang 1.7.6 and 1.8.2 * run test coverage with covermode=set ### Core * log failure errors on Robot Start() ### Curie * update docs formatting * add Curie to main README platform list * more improvements for README setup instructions * improve README info * improve tests and examples * increase test coverage * increase test coverage * motion detect implemented * tap detect implemented * step count implemented * shock detect implemented * Accelerometer, Gyroscope, and Temperature sensors implemented * WIP on adding support for Intel Curie IMU ### Digispark * update blink example to display error message on Start() * update README with latest development info ### Docs * add more wishlist to ROADMAP * add helpful information to examples themselves * correct installation instructions to match latest versions * more wishlish items for roadmap * update BLE connect info to latest * more work on ROADMAP doc * add first attempt at roadmap document ### Edison * refactor auto-discovery of Edison board option * removed commented lines ### Firmata * remove circular import in test * make it possible to test external devices that use firmata adaptor * Sysex response events now being handled as expected * expose WriteSysex to external callers * expose WriteSysex to external callers * cleanup error handling for connection code * improve connection code to use a proper timeout * remove unused code, increase test coverage * increase test coverage * switch to using go-serial package * return connect errors to client * client tests don't need so many goroutines * adjust client test timeout values * refactoring firmata client ### Fix * signed/unsigned bug ### Fixed * incorrect error condition check when reading the 'ctrl_hum' register. Expanded the BME280 unit test for TestBME280DriverStart() to support reading from the 'ctrl_hum' register. * PWM duty cycle calculation for C.H.I.P ServoWrite * PWM init bug for C.H.I.P ### I2c * remove unused test code ### Improved * BME280 humidity initialisation so that it does not override existing oversampling rates that have been set up for the ctrl_meas register. ### Issue * [#424](https://github.com/hybridgroup/gobot/issues/424): Enables humidity readings in the BME280 driver by enforcing the write to the 'ctrl_meas' register, as per Section 5.4.3 of the BME280 data sheet ### Joystick * add needed constants for all PS3 buttons ### Made * C.H.I.P PWM init robust for already enabled state ### Mavlink * switch to using go-serial package ### Megapi * switch to using go-serial package ### Microbit * use updated ble adaptor interface for tests ### Minidrone * never expect responses for characteristic writes * add example for Parrot Mambo * separate flight status processing and add test coverage * add support for Mambo external accessories * remove unneeded code, increase test coverage * increase test coverage ### Neurosky * switch to using go-serial package ### Ollie * use updated ble adaptor interface for tests ### Prepare * for v1.6.0 release ### Release * correct changelog incorrect section titles ### Sphero * switch to using go-serial package ### Sysfs * increase test coverage ### Updated * Tinkerboard and sysfs tests to updated PWM polarity contract ### Write * config register in little endian ## [v1.5.0](https://github.com/hybridgroup/gobot/compare/v1.4.0...v1.5.0) (2017-05-10) ### core * Add Running() methods for Manager and Robot and increase test coverage accordingly ### sysfs * define DigitalPinnerProvider and PWMPinnerProvider interfaces * add Chip to be able to change pwmchip, and some related refactoring * add file read/write testing for failure conditions * proper handling of busy state vs. other errors * return sensible result when no valid data read ### test * increase coverage on test helpers ### build * switching to Travis builds using Ubuntu 14.04 Trusty ### aio * only need to support AnalogReader interface * avoid test race conditions * ensure that AnalogSensor event Data is always int ### gpio * only need to support DigitalReader/DigitalWriter interface ### i2c * Added support for the ADS1015 and ADS1115 ADCs * Add INA3221 Voltage Monitor * Ensure lock of i2c bus for each individual operation * Small refactoring and increase test coverage for BMP180 ### beaglebone * implement DigitalPinner and PWMPinner interfaces * protect against pin map races * increase test coverage ### chip * add preliminary support for C.H.I.P. Pro * add back ServoWrite implementation * implement DigitalPinnerProvider and PWMPinnerProvider interfaces * protect against pin map races ### dragonboard * export DigitalPin and PWMPin adaptor methods * protect against pin map races * increase test coverage ### edison * auto-detect arduino breakout board, if no specific board is expected * ensure that we initialize tristate if arduino breakout board * export DigitalPin and PWMPin adaptor methods * implement DigitalPinnerProvider and PWMPinnerProvider interfaces * protect against pin map races * refactoring to reduce code duplication ### firmata * remove processing that might have been eating test events, increase test coverage ### joule * implement DigitalPinnerProvider and PWMPinnerProvider interfaces * protect against pin map races * remove incorrect pin assignment and improve test coverage * add examples using Joule with ADS1015 ADC * naming system changes * correct pin mappings and add PWM example ### mavlink * add a Mavlink-over-UDP adaptor. ### microbit * Add DigitalWriter, DigitalReader, and AnalogReader support using IOPinDriver * Handle start error and increase test coverage ### mqtt * Add a (topic, payload) event type * change the On handler to take mqtt.Message * increase test coverage * update examples that use mqtt for updated notification signature ### nats * change the On() handler to take the subject as an argument * increase test coverage ### raspi * implement DigitalPinnerProvider and PWMPinnerProvider interfaces * add implementation for PWMPinner interface that wraps pi blaster * fix adaptor race conditions * increase test coverage ### tinkerboard * Add support for ASUS Tinker Board ## [v1.4.0](https://github.com/hybridgroup/gobot/compare/v1.3.0...v1.4.0) (2017-04-12) ### core * Use 10-buffered chans for events, see #374 ### i2c * Many refactors and increases in test coverage * Eliminate race conditions introduced by tests * Adds Altitude() function to BMP280/BME280 * bme280 driver Humidity compensation formula * ssd1306 driver implementation ### aio * Eliminate race conditions introduced by tests ### gpio * Fix motor mode change when speed is set * Eliminate race conditions introduced by tests * Reduce test side effects ### ardrone * Increase test coverage ### audio * Increase test coverage ### bb8 * Refactoring to use BLEConnector interface and provide tests ### bebop * Increase test coverage ### beaglebone * Increase test coverage ### ble * Increase test coverage for battery, device information, and generic access drivers * Refactoring drivers to use BLEConnector interface and provide tests ### chip * Added PWM0 support * Increase test coverage ### digispark * Increase test coverage ### dragonboard * Increase test coverage ### edison * Remove pointless error checking code * Refactor digital pin creation process method * Increase test coverage ### firmata * Eliminate race conditions introduced by tests * Increase test coverage for i2c commands ### joule * Increase test coverage ### joystick * Increase test coverage ### keyboard * Increase test coverage ### mavlink * Eliminate race conditions introduced by tests * Increase test coverage ### mavlink * Increase test coverage ### microbit * Refactoring to use BLEConnector interface and provide tests * Address #404 by adding info about required magnetometer calibration step to README * Increase test coverage ### minidrone * Refactoring to use BLEConnector interface and provide tests ### mqtt * Increase test coverage ### nats * Increase test coverage ### neurosky * Update neurosky README & example * Eliminate race conditions introduced by tests * Increase test coverage ### ollie * Refactoring to use BLEConnector interface and provide tests * Correct race condition error on seq * Increase test coverage ### opencv * Increase test coverage ### particle * Increase test coverage ### raspi * Address #391 by providing more details about normal development workflow * Increase test coverage ### sphero * Eliminate race conditions * Increase test coverage ### sysfs * Address race condition from udev rules when exporting GPIO pins * Increase test coverage ### docs * Improve explanations for scp/ssh workflow on SoC boards * Include entire Apache 2.0 license in the license text ### test * Add crude travis check for gofmt; format all sources * Significantly speed up travis and make runs * Remove test code no longer being called * Update Travis to run tests using Golang 1.8.1 * Increase gobottest test coverage ## [v1.3.0](https://github.com/hybridgroup/gobot/compare/v1.2.1...v1.3.0) (2017-03-22) ### microbit * Add new platform support ### dragonboard * Add new platform support ### gpio * Increase test coverage ### i2c * Update list of supported i2c devices * Minor adjustments and test coverage improvements * Added more capabilities checks for I2C * Removed smbus block operations ### core * Increase test coverage ### test * Improvements to run tests much faster thanks @maruel * Use codecov.io for code coverage reporting ### docs * Update CoC based on Contributor Covenant ## [v1.2.1](https://github.com/hybridgroup/gobot/compare/v1.2.0...v1.2.1) (2017-02-16) ### Allow * NATS options to pass in the NATS adaptor for TLS support. ### Chip * correct docs to describe valid pin mappings ### Update * version to 1.2.1 for point release ## [v1.2.0](https://github.com/hybridgroup/gobot/compare/v1.1.0...v1.2.0) (2017-02-16) ### core * Use new improved default namer to avoid API conflicts ### gpio * Removed scaling function from servo driver * Correct servo driver to pass along angle to adaptor to sort out implementation ### i2c * Refactored platforms and drivers to new I2C interfaces * Change to make I2C support more than one bus * Refactor drivers to support new optional params ### bb8 * Added collision detection support and example ### beaglebone * Correct i2c buses to match actual mapping ### ble * Switch to using [ble](https://github.com/currantlabs/ble) package for Bluetooth LE * Basic serial over BLE working with Arduino101 with StandardFirmataBLE * WIP on multiple simultaneous ble devices ### chip * Fixed chip XIO base address lookup ### digispark * Fix #288 by using pkg-config to locate libusb-compat includes ### firmata * Remove race conditions identified in Firmata client * Correct error in I2C reads not listening to board events ### mqtt * Add driver for syntactical sugar around virtual devices * Add SSL/TLS client options support * Fix #277 by adding SetAutoReconnect method to set Paho MQTT client * Change both 'On' and 'Publish' method function signatures to match Eventer interface ### nats * Add driver to make it easier to create virtual devices ### ollie * Added collision detection support and example ### parrot * Add ValidatePitch helper function for Parrot Minidrone, Parrot Bebop & ARDrone 2.0 to package ### docs * Fix #363 by using atomic.Value to protect current values used by multiple goroutines in drone examples ### test * Remove Golang 1.5 from TravisCI tests in prep for Golang 1.8 release ## [v1.1.0](https://github.com/hybridgroup/gobot/compare/v1.0.0...v1.1.0) (2017-01-09) ### core * use canonical import path for sysfs package ### i2c * Add a driver for the SHT3X chip * Add a driver for BMP180 * Add support for L3GD20H gyroscope ### firmata * Add support for TCPFirmata connections, allowing ESP8266 and other WiFi-connected controllers * Add mention to README to use 'tty.' serial port on OSX * Add mention of A4 and A5 normally unavailable on Firmata ### raspi * Correct README build instructions with missing 'go build' command ### snapcraft * Add the packaging metadata to build the gobot snap for Ubuntu Snappy ### particle * Update examples to take key params via command line * Address #160 by adding support for tinker-servo sketch if installed on Particle device ### esp8266 add experimental ESP8266 support to list of supported platforms ### sysfs * Should fix #272 by using first byte of data as command register for I2C reads * Some additional cleanup suggested by golint ### ble * Add generic access service driver * Update docs to include reference to included drivers * Move various test code to test file ### ollie * Refactoring so no need to expose internal implementation details ### bebop * Add support/example of RTP video * Enable video on firmware 3.3+ * Update ps3 and video example to enable the video stream * Update README for brief explanation of how to get drone video * Corrected import paths for client examples ### bb8 * Correct NewDriver params and set name * Add missing constructor to wrap Ollie implementation ### minidrone * Update README with example and which specific models are currently supported * Add all piloting flying state events * Adds Emergency() and TakePicture() commands ### test * Add Golang 1.8beta2 to Travis builds * Correct aio references for AnalogRead tests ## [v1.0.0](https://github.com/hybridgroup/gobot/compare/v0.13.0...v1.0.0) (2016-12-21) ### core * Refactoring to allow 'Metal' development using Gobot packages * Able to run robots without being part of a Manager. * Now running all work in separate goroutines * Rename internal name of Manager type * Refactor events to use channels all the way down. * Eliminate potential race conditions from Events and Every functions * Add Unsubscribe() to Eventer, now Once() works as expected * DeleteEvent function added to Eventer interface * Ranges over event channels instead of using select * No longer return non-standard slices of errors, instead use hashicorp/go-multierror * Ensure that all drivers have default names * Now both Robot and Manager operate using AutoRun as expected * Use canonical import domain of gobot.io for all code * Use time.Sleep unless waiting for a timeout in a select * Uses time.NewTimer() instead of time.After() to be more efficient ### test * Add deps tasks to Makefile * Add golang 1.7 to Travis CI tests * Add golang 1.8beta1 to build matrix for Travis * Reduce Travis builds to golang 1.4+ since it is late 2016 already * Complete move of test interfaces into the test files where they belong * Adds Parrot Minidrone and Sphero Ollie to Travis tests ### Add missing godocs for everything ### i2c * Move I2C drivers into appropriately named 'drivers/i2c' directory * Add support for Adafruit Servo/PWM HAT ### gpio * Move GPIO drivers into appropriately named 'drivers/gpio' directory * Add support for PIR motion detector ### beaglebone * auto-detect Linux kernel version * map usr LEDs to match all kernels ### ble * Rename drivers to make them more obvious * Add test placeholders ### chip * Auto-detect OS version to adjust pin mappings * Correct base for new 4.4 GPIO ### edison * Support for other breakout boards besides Arduino ### firmata * Use io.ReadFull in platforms/firmata/client * Update tarm/goserial to tarm/serial ### joule * Add support for Intel Joule ### megapi * Adding support for MakeBlock megapi ### nats * Add support for NATS server ### particle * Complete renaming Spark platform to Particle ### parrot * Move Parrot Minidrone into own platform * Move both ARDrone and Bebop under Parrot package ### raspi * Add missing godocs and small refactors for platform ### sphero * Add initial support for Sphero BB-8 platform * Move Sphero Ollie into own platform ## [v0.13.0](https://github.com/hybridgroup/gobot/compare/v0.12.1...v0.13.0) (2016-10-10) ### Add * PinMode test case * PinMode func for MCP23017 * example for Edison blink demo without gobot initialization. * ServoConfig to the FirmataAdaptor * unit tests for ServoConfig ### Adding * support for MakeBlock megapi * tests for the Adafruit driver, and corresponding minor driver changes. * support for MakeBlock megapi * a Servo example program for the Adafruit Servo Hat driver code. * support for the Adafruit Servo/PWM HAT. This required a slight refactor to the existing Motor HAT code to support multiple I2C addresses. * two API funcs for the Adafruit driver with respect to the DC Motor, fleshing out the raspi_adafruit example with a runner function. * the initial NATS platform support ### Another * attempt at correct Travis syntax for gnatsd -[#5](https://github.com/hybridgroup/gobot/issues/5) * attempt at correct Travis syntax for gnatsd -[#4](https://github.com/hybridgroup/gobot/issues/4) * attempt at correct Travis syntax for gnatsd -[#3](https://github.com/hybridgroup/gobot/issues/3) * attempt at correct Travis syntax for gnatsd -[#2](https://github.com/hybridgroup/gobot/issues/2) * attempt at correct Travis syntax for gnatsd ### Ble * fix unused var * populate descriptors after descovering characterisitcs ### Bug * fix in the Adafruit stepper code, specifically with respect to the AdafruitDouble step-style. ### Code * cleanups suggested by gosimple ### Core * update README with an example of 'Metal' Gobot * should correct occasional test errors due to event overlap with test * correct behavior in Mavlink driver, correct tests to match * Add Unsubscribe() to eventer, now Once() works as expected * Add further tests for Eventer * cleanup comments on Eventer interface * function DeleteEvent added to Eventer interface * Refactor tests to allow 'metal' development using Gobot adaptors/drivers. * Refactor tests to allow 'metal' development using Gobot adaptors/drivers. * Refactor tests to allow 'metal' development using Gobot adaptors/drivers. * Refactor examples to allow 'metal' development using Gobot adaptors/drivers. * Refactoring to allow 'metal' development using Gobot adaptors/drivers. * Continue refactoring to allow 'metal' development using Gobot libs. * Refactor events to use channels all the way down. Allows 'metal' development using Gobot libs. * update README with an example of 'Metal' Gobot * should correct occasional test errors due to event overlap with test * correct behavior in Mavlink driver, correct tests to match * Add Unsubscribe() to eventer, now Once() works as expected * Add further tests for Eventer * cleanup comments on Eventer interface * function DeleteEvent added to Eventer interface * Refactor tests to allow 'metal' development using Gobot adaptors/drivers. * Refactor tests to allow 'metal' development using Gobot adaptors/drivers. * Refactor tests to allow 'metal' development using Gobot adaptors/drivers. * Refactor examples to allow 'metal' development using Gobot adaptors/drivers. * Refactoring to allow 'metal' development using Gobot adaptors/drivers. * Continue refactoring to allow 'metal' development using Gobot libs. * Refactor events to use channels all the way down. Allows 'metal' development using Gobot libs. ### Docs * go fmt files that needed it from recent changes * go fmt files that needed it from recent changes ### File * rename, adding a test file for the Adafruit driver, and slight func naming changes. * rename, adding a test file for the Adafruit driver, and slight func naming changes. ### Fix * a typo and update the doc comment for FirmataAdaptor.ServoConfig * the ServoConfig byte order * issues flagged by 'go vet' * misspellings ### Fixing * some code and finally have Travis building * tests, adding a few more, adding nats server to Travis CI for testing ### Initial * significant changes to the Adafruit Motor HAT driver to support Stepper Motors. * commit of driver code, with accompanying example, for the Adafruit_MotorHat. ### Joule * add i2c example and notes to README about pullup resistors * adds pin mappings from the second header * add pin mapping info to README * go fmt the multi-LED example ### Merge * branch 'dev' of github.com:jfinken/gobot into dev * branch 'dev' of github.com:jfinken/gobot into dev ### Misc * update all LICENSE files for current year ### More * explicit initialization in Start, slight refactor, and separate DC Motor and Stepper Motor examples. ### Move * interface assertions to test files. ### Release * update to version 0.13.0 ### Remove * debug message from i2c_device.go ### Removing * the raspi_adafruit program as it has been split into three separate programs, removing my Makefile for the raspi adafruit programs, and fixing up a few comments. * my fork from the Adafruit tests. ### Starting * support for Intel Joule with the built-in LEDs and more ### Test * add golang 1.7 to Travis CI tests * add golang 1.7 to Travis CI tests ### Tests * complete move of test interfaces into the test files where they belong * refactor test interfaces out of implementations and into the tests where they belong ### Update * READMEs with up to date info for Edison/Joule ### Updating * platform support info ## [v0.12.1](https://github.com/hybridgroup/gobot/compare/v0.12.0...v0.12.1) (2016-07-13) ### A * little more WIP, can open a connection to a specific peripheral ### Add * MQTT authentication support * MQTT authentication support * Go Reportcard badge for fun * Go Reportcard badge for fun ### Added * example of how to use temp36 temperature sensor with firmata * example of how to use temp36 temperature sensor with firmata ### Adds * support for Dualshock4 wireless gamepad * support for Dualshock4 wireless gamepad ### Allow * failures in Travis builds for Golang 1.3 due to SDL changes ### Almost * reading battery info ### BLE * seems to require Golang 1.4+ ### Can * see BLE devices, and connect to a specific one ### Change * default value for PCMD flag to match the Bebop 2.0.57+ expectations * default value for PCMD flag to match the Bebop 2.0.57+ expectations * test delay to 50ms * test delay to 50ms ### Code * cleanup, improve go report card * cleanup, improve go report card ### Fix * specs * specs * for analog (quick changes lag) * for analog (quick changes lag) * [#201](https://github.com/hybridgroup/gobot/issues/201) by add 'make examples' command to Makefile * mavlink link typo ### Fixes * failing test * failing test ### Go * fmt the code ### Increase * hover time and remove cruft from simple Bebop drone example * hover time and remove cruft from simple Bebop drone example ### Introduce * `gobottest` package with test helpers * `gobottest` package with test helpers ### Make * dev branch target more explicit ### Making * sure tests pass ### Merge * branch 'feature/audio' into dev * branch 'bugfix/gpio-button-tests' into dev * branch 'feature/ble' into feature/ble-wip ### More * WIP on reading characteristics ### Pin * 229 value left out of test fixture on edison ### Refactor * to use `gobottest` test helpers * to use `gobottest` test helpers ### Remove * fmt no longer used here * commented lines * test code ### Resolve * merge conflicts * merge conflict in Travis CI file ### Simple * implementation that can read data ### Support * gpio pin turn on and off * gpio pin turn on and off ### Switching * to currantlabs fork of gatt, and some related refactoring ### Test * generated error messages as well * generated error messages as well ### Tests * also need to be pointed to [@veandco](https://github.com/veandco) go-sdl2 fork ### Update * to 0.12.1 * missing changelog entries * missing changelog entries * ARDrone face tracking example to use main go-opencv fork ### Use * main go-sdl fork from [@veandco](https://github.com/veandco) to pickup any upstream changes * OpenCV 2.4, as well as switch to main fork of go-opencv * Seek to speed up read/write in sysfs ### WIP * on BLE ## [v0.12.0](https://github.com/hybridgroup/gobot/compare/v.0.11.1...v0.12.0) (2016-07-13) ### Refactor Gobot test helpers into separate package ### Improve Gobot.Every method to return channel, allowing it to be halted ### Refactor of sysfs adds substantial speed improvements ### ble * Experimental support for Bluetooth LE. * Initial support for Battery & Device Information services * Initial support for Sphero BLE robots such as Ollie * Initial support for Parrot Minidrone ### audio * Add new platform for Audio playback ### gpio * Support added for new GPIO device: * RGB LED * Bugfixes: * Correct analog to better handle quick changes * Correct handling of errors and buffering for Wiichuk ### mqtt * Add support for MQTT authentication ### opencv * Switching to use main fork of OpenCV * Some minor bugfixes related to face tracking ## [v.0.11.1](https://github.com/hybridgroup/gobot/compare/v0.11.0...v.0.11.1) (2016-02-17) ### Add * support for 'hand' and 'gesture' Leap Motion events * MMA7660 accelerometer example for C.H.I.P. * C.H.I.P. to supported platforms * support for the CHIP platform * MCP23017 write and read functionality to GPIO ### Adds * MCP23017 i2c device to README * additional examples for C.H.I.P. ### Better * I2C device descriptions in README ### Correct * the release command sent to pi-blaster. * Intel Edison docs location thanks to [@seanmarcia](https://github.com/seanmarcia) ### Default * the new MQTT 'AutoReconnect' to false ### Failure * is no longer an option for Go 1.6 ### Fix * [#236](https://github.com/hybridgroup/gobot/issues/236) & fix [#239](https://github.com/hybridgroup/gobot/issues/239) by correcting initialization and temperature conversion for MPU-6050 ### Fixed * event race condition ### Get * I2C functionality before doing SMBus block I/O ### Golang * 1.3.3 still works, adding back to build ### Increase * button delay hack for test suite * test delay hack for button tests ### Name * C.H.I.P. pins according to printed names ### Need * to explicitly set content type to text/html for Robeaux main page ### No * coveralls repo token for provate repos? ### Remove * coveralls badge ### Run * builds against the latest major releases ### The * take-off-before-event-handling bug again ### Trying * to remove coveralls based code coverage * conditional build before_install * conditional build ### Update * version to v.0.11.1 * version to 0.11 * MQTT README for latest info * targeted golang versions to include 1.6, and to begin deprecating 1.3.3 and earlier * coveralls badge in README * API example ### Use * newer naming system for C.H.I.P. pins ### What * about -v ### Why * do this twice? ## [v0.11.0](https://github.com/hybridgroup/gobot/compare/0.10.0...v0.11.0) (2016-02-17) ### Support for Golang 1.6 ### Determine I2C adaptor capabilities dynamically to avoid use of block I/O when unavailable ### chip * Add support for GPIO & I2C interfaces on C.H.I.P. $9 computer ### leap motion * Add support additional "hand" and "gesture" events ### mqtt * Support latest update to Eclipse Paho MQTT client library ### raspberry pi * Proper release of Pi Blaster for PWM pins ### bebop * Prevent event race conditions on takeoff/landing ### i2c * Support added for new i2c device: * MCP23017 Port Expander * Bugfixes: * Correct init and data parsing for MPU-6050 * Correct handling of errors and buffering for Wiichuk ## [0.10.0](https://github.com/hybridgroup/gobot/compare/0.8.2...0.10.0) (2015-10-27) ### Refactor core to cleanup robot initialization and shutdown ### Remove unnecessary goroutines spawned by NewEvent ### api * Update Robeaux to v0.5.0 ### bebop * Add support for the Parrot Bebop drone ### keyboard * Add support for keyboard control ### gpio * Support added for 10 new Grove GPIO devices: * Grove Touch Sensor * Grove Sound Sensor * Grove Button * Grove Buzzer * Grove Led * Grove Light Sensor * Grove Vibration Sensor * Grove Rotary * Grove Relay * Grove Temperature Sensor ### i2c * Support added for 2 new Grove i2c devices: * Grove Accelerometer * Grove LCD with RGB backlit display ### docs * Many useful fixes and updates for docs, mostly contributed by our wonderful community. ## [0.8.2](https://github.com/hybridgroup/gobot/compare/0.8.1...0.8.2) (2015-06-30) ### firmata * Refactor firmata adaptor and split firmata protocol implementation into sub `client` package ### gpio * Add support for LIDAR-Lite ### raspi * Add PWM support via pi-blaster ### sphero * Add `ConfigureLocator`, `ReadLocator` and `SetRotationRate` ## [0.8.1](https://github.com/hybridgroup/gobot/compare/0.8...0.8.1) (2014-12-28) ### spark * Add support for spark Events, Functions and Variables ### sphero * Add `SetDataStreaming` and `ConfigureCollisionDetection` methods ## [0.8](https://github.com/hybridgroup/gobot/compare/0.7.1...0.8) (2014-12-24) ### Refactor core, gpio, and i2c interfaces ### Correctly pass errors throughout packages and remove all panics ### Numerous bug fixes and performance improvements ### api * Update robeaux to v0.3.0 ### firmata * Add optional io.ReadWriteCloser parameter to FirmataAdaptor * Fix `thread exhaustion` error ### cli * generator * Update generator for new adaptor and driver interfaces * Add driver, adaptor and project generators * Add optional package name parameter ## [0.7.1](https://github.com/hybridgroup/gobot/compare/0.7...0.7.1) (2014-11-17) ### opencv * Fix pthread_create issue on Mac OS ## [0.7](https://github.com/hybridgroup/gobot/compare/0.6.3...0.7) (2014-11-10) ### Dramatically increased test coverage and documentation ### api * Conform to the [cppp.io](https://gobot.io/x/cppp-io) spec * Add support for basic middleware * Add support for custom routes * Add SSE support ### ardrone * Add optional parameter to specify the drones network address ### core * Add `Once(e *Event, f func(s interface{})` Event function * Rename `Expect` to `Assert` and add `Refute` test helper function ### i2c * Add support for MPL115A2 * Add support for MPU6050 ### mavlink * Add support for `common` mavlink messages ### mqtt * Add support for mqtt ### raspi * Add support for the Raspberry Pi ### sphero * Enable stop on sphero disconnect * Add `Collision` data struct ### sysfs * Add generic linux filesystem gpio implementation ## [0.6.3](https://github.com/hybridgroup/gobot/compare/0.6.2...0.6.3) (2014-09-24) ### Add support for the Intel Edison ## [0.6.2](https://github.com/hybridgroup/gobot/compare/0.6.1...0.6.2) (2014-07-28) ### cli * Fix typo in generator ### leap * Fix incorrect Port reference * Fix incorrect Event name ### neurosky * Fix incorrect Event names ### sphero * Correctly format output of GetRGB ## [0.6.1](https://github.com/hybridgroup/gobot/compare/0.6...0.6.1) (2014-07-12) ### cli * Fix template error in generator ## [0.6](https://github.com/hybridgroup/gobot/compare/0.5.2...0.6) (2014-07-11) ### api * Add robeaux support ### core * Refactor `Connection` and `Device` * Connections are now a collection of Adaptors * Devices are now a collection of Drivers * Add `Event(string)` function instead of `Events[string]` for retrieving Driver event * Add `AddEvent(string)` function to register an event on a Driver ### firmata * Fix slice bounds out of range error ### sphero * Fix issue where the driver would not halt correctly on OSX ## [0.5.2](https://github.com/hybridgroup/gobot/compare/0.5.1...0.5.2) (2014-06-30) ### beaglebone * Add `DirectPinDriver` * Ensure slots are properly loaded ## [0.5.1](https://github.com/hybridgroup/gobot/compare/0.5...0.5.1) (2014-06-28) ### core * Add `Version()` function for Gobot version retrieval ### firmata * Fix issue with reading analog inputs * Add `data` event for `AnalogSensorDriver` ## [0.5](https://github.com/hybridgroup/gobot/compare/0.4...0.5) (2014-06-17) ### Idomatic clean up * Removed reflections throughout packages * All officially supported platforms are now in ./platforms * API is now a new package ./api * All platforms examples are in ./examples * Replaced martini with net/http * Replaced ginkgo/gomega with system testing package * Refactor gobot/robot/device commands * Added Event type * Replaced Manager type with Gobot type * Every` and `After` now accept `time.Duration` * Removed reflection helper methods ## [0.4](https://github.com/hybridgroup/gobot/compare/0.3...0.4) (2014-06-12) ### API * commands now return an array of results ### Add * cors support * basic auth support to api * Joystick & Neurosky platforms to README * utils tests * coveralls ### Allow * user to set Host and Port when starting up Api ### Change * README image source to gobot-site repo * startApi to private function ### Display * warning when using API without SSL ### Fixed * the logo link ### Format * device and connection type ### Green * tests ### More * api test coverage * tests ### Refactor * tests ### Remove * Travis build from IRC * ConnectToSerial * ConnectToTcp util * Reconnect and Disconnect from AdaptorInterface ### Robot * is now a pointer ### SSL * support in Api ### Update * README.md * README for new API security features * api robeaux api compatibility * .travis.yml * generated driver * examples * coveralls badge * platforms and drivers ### Use * go-martini/martini ### WIP * for API host/port params * api tests ## [0.3](https://github.com/hybridgroup/gobot/compare/0.2...0.3) (2014-04-07) ### Add * Godeps file * IRC notifications to Travis builds * tests for generated projects * Init function to DriverInterface * Halt function to DriverInterface * more GPIO devices to README * scale functions ### All * updates for new gonuts/commander api ### Fix * typo in generator ### Merge * branch 'master' of github.com:hybridgroup/gobot ### Update * generator ## [0.2](https://github.com/hybridgroup/gobot/compare/0.1...0.2) (2014-02-04) ### Add * robeaux submodule * Finalize on SIGINT * Publish function for driver events * device test coverage * manager and robot test coverage ### Clean * up tests ### Do * not run tests on gobot.io branch ### JSON * compatibility with cylon and artoo ### More * test coverage ### Refactor * robot and manager ### Remove * robeaux submodule ### Update * README.md * examples ### Use * golang log ### WIP * robeaux support ## 0.1 (2013-12-30) ### Accept * POST and GET for commands ### Adaptor * and driver generator ### Add * support for additional parameters * serialport support * Travis banner to README * api commands * POST command * manager example * robot manager * Sphero example * Digispark to list of supported platforms * helper functions * Driver channel for events * port to adaptor ### Alter * structure ### Beaglebone * Black GPIO ### Clean * up files * up variables * up some comments ### Correctly * start drivers ### DRY * up On function ### Dots * for ignoring imports ### Drop * unnecessary api parameters ### Expose * robot functions via api ### Fix * example ### Go * fmt examples ### Initial * GETs for api * commit ### Install * ginkgo and gomega dependencies ### Merge * branch 'examples' * branch 'master' into ginkgo * branch 'master' into ginkgo ### More * WIP of base structs ### Now * using Connection.Connect() ### Pending * tests for Robot ### Proper * formatting for README example ### Properly * set default interval ### Refactor * robot name assignment func, and tests to prove it ### Reformat * examples using gofmt * source using gofmt ### Remove * Params from driver struct * extra nesting ### Rename * Gobot struct to Manager ### Set * GOMAXPROCS property in GobotManager ### Skeleton * for ginkgo/gomega testing ### Small * refactor * robot refactor ### StartDriver * is now optional ### Switch * to adaptor, driver, connection and device interfaces ### Travis * lang build ### Tweak * json output ### Update * examples * README.md * timers and fix issues ### WIP * multiple robot support * connections and devices ### Work * is optional ================================================ FILE: CODE_OF_CONDUCT.md ================================================ # Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at gobot@hybridgroup.com. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] [homepage]: http://contributor-covenant.org [version]: http://contributor-covenant.org/version/1/4/ ================================================ FILE: CONTRIBUTING.md ================================================ # Contributing to Gobot ## Target Branch **Please open all non-hotfix PRs against the `dev` branch!** Gobot follows a ["git flow"](http://nvie.com/posts/a-successful-git-branching-model/)-style model for managing development. ## Issue Contributions When opening new issues or commenting on existing issues on this repository please make sure discussions are related to concrete technical issues with the Gobot software. ## Code Contributions The Gobot project welcomes new contributors. This document will guide you through the contribution process. What do you want to contribute? * I want to otherwise correct or improve the docs or examples * I want to report a bug * I want to add some feature or functionality to an existing hardware platform * I want to add support for a new hardware platform Descriptions for each of these will eventually be provided below. ## General Guidelines * All active development is in the `dev` branch. New or updated features must be added to the `dev` branch. * All patches must be provided under the Apache 2.0 License * Please use the -S option in git to "sign off" that the commit is your work and you are providing it under the Apache 2.0 License * Submit a Github Pull Request to the appropriate branch and describe the changes sufficient. * Please follow our naming conventions for Pull Requests. * We will look at the patch, test it out, and give you feedback. * Avoid doing minor whitespace changes, renamings, etc. along with merged content. These will be done by the maintainers from time to time but they can complicate merges and should be done separately. * Take care to maintain the existing coding style. * `golangci-lint` your code, see [instruction for local installation](https://golangci-lint.run/usage/install/#local-installation) * `gofumpt` your code (the go version will be automatically obtained from go.mod), see [instructions](https://github.com/mvdan/gofumpt/blob/master/README.md) * Add unit tests for any new or changed functionality and run tests with `-race` flag activated. * All pull requests should be "fast forward" * If there are commits after yours use “git rebase -i ” * If you have local changes you may need to use “git stash” * For git help see [progit](http://git-scm.com/book) which is an awesome (and free) book on git * Use one of the latest existing platforms/drivers etc. as a blueprint for creating a new one ## Creating Pull Requests Because Gobot makes use of self-referencing import paths, you will want to implement the local copy of your fork as a remote on your copy of the original Gobot repo. Katrina Owen has [an excellent post on this workflow](https://splice.com/blog/contributing-open-source-git-repositories-go/). The basics are as follows: 1. Fork the project via the GitHub UI 2. `git clone` the upstream repo and set it up as the `upstream` remote and your own repo as the `origin` remote: `git clone https://github.com/hybridgroup/gobot.git` `cd $GOPATH/src/gobot.io/x/gobot` `git remote rename origin upstream` `git remote add origin git@github.com/YOUR_GITHUB_NAME/gobot` All import paths should now work fine assuming that you've got the proper branch checked out. 3. Get all dependencies: * `cd $GOPATH/src/gobot.io/x/gobot` * `go mod tidy` will fetch all the dependencies at their needed version. ## Landing Pull Requests (This is for committers only. If you are unsure whether you are a committer, you are not.) 1. Set the contributor's fork as an upstream on your checkout `git remote add contrib1 https://github.com/contrib1/gobot` 2. Fetch the contributor's repo `git fetch contrib1` 3. Checkout a copy of the PR branch `git checkout pr-1234 --track contrib1/branch-for-pr-1234` 4. Review the PR as normal 5. Land when you're ready via the GitHub UI ## Convention for Pull Request Descriptions Making unified descriptions helps a lot to generate the [CHANGELOG](./CHANGELOG.md) for the next release. We support the style from , so you can use something like this: * type(scope): description * i2c(PCF8583): added * gpio(HD44780): fix wrong constants * raspi(PWM): refactor usage * docs(core): usage of Kernel driver * or alternative: core(docs): usage of Kernel driver * build(style): adjust rule for golangci-lint We try to keep it as simple as possible: * Do not use "fix" or "bugfix" for `type` * Please assign "fix", "style", "refactor", "perf", "test" etc. to the related `type` (driver-type/platform-name etc.), and start the description with e.g. "fix...", "test..." etc. * For `type` use the name of the deepest folder (e.g. i2c/raspi/system). Feel free to order "examples" to the related driver. * Further values for `type` are: "docs", "build", "core" * Please use "build" instead of "CI" * For the `scope` use the name of the driver or feature (e.g. grove/PWM). * If unsure don't panic, follow your feeling. Possibly the reviewer will correct it or suggest a better description. ## Developer's Certificate of Origin 1.0 By making a contribution to this project, I certify that: * (a) The contribution was created in whole or in part by me and I have the right to submit it under the open source license indicated in the file; or * (b) The contribution is based upon previous work that, to the best of my knowledge, is covered under an appropriate open source license and I have the right under that license to submit that work with modifications, whether created in whole or in part by me, under the same open source license (unless I am permitted to submit under a different license), as indicated in the file; or * (c) The contribution was provided directly to me by some other person who certified (a), (b) or (c) and I have not modified it. ## Code of Conduct Gobot is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms. [You can read about it here](CODE_OF_CONDUCT.md). ## Origins This document is based on the original [io.js contribution guidelines](https://github.com/nodejs/io.js/blob/main/CONTRIBUTING.md) ================================================ FILE: LICENSE.txt ================================================ Copyright (c) 2013-2020 The Hybrid Group Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: MIGRATION.md ================================================ # Migration guide From time to time a breaking change of API can happen. Following to [SemVer](https://semver.org/), the gobot main version should be increased. In such case all users needs to adjust there projects for the next update, although they not using a driver or platform with changed API. To prevent this scenario for most users, the main version will not always increased, but affected drivers and platforms are listed here and a migration strategy is provided. ## Switch from version 2.4.0 (applications using the gpiod options and some import paths affected) ### RockPi adaptor was moved to radxa folder For cleanup purposes and future preparation the folders and files were moved. Please search and replace to change the import path as follows. ```go // old ... "gobot.io/x/gobot/v2/platforms/rockpi" ... // new ... "gobot.io/x/gobot/v2/platforms/radxa/rockpi" ... ``` ### Tinkerboard adaptors were moved to asus folder For cleanup purposes and future preparation the folders and files were moved. Please search and replace to change the import path as follows. ```go // old ... "gobot.io/x/gobot/v2/platforms/tinkerboard/tinkerboard2" ... // new ... "gobot.io/x/gobot/v2/platforms/asus/tinkerboard2" ... ``` ```go // old ... "gobot.io/x/gobot/v2/platforms/tinkerboard" ... // new ... "gobot.io/x/gobot/v2/platforms/asus/tinkerboard" ... ``` ### NanoPi NEO adaptor was moved to friendlyelec folder With introduce of FriendlyELEC NanoPC-T6 a second adaptor from FriendlyELEC (formerly friendlarm) now exists. Please search and replace to change the import path of nanopi as follows. ```go // old ... "gobot.io/x/gobot/v2/platforms/nanopi" ... // new ... "gobot.io/x/gobot/v2/platforms/friendlyelec/nanopi" ... ``` ### The term gpiod was renamed to cdev Using the term "cdev" (short for character device Kernel ABI for GPIO access) is more suitable than using "gpiod" (the name of the user space driver in Linux). Also it relates better to the term "sysfs" (the legacy sysfs Kernel ABI for GPIO access). The former name was chosen so there would be no difference to the used go module "gpiod". Since also this module is now renamed to "go-gpiocdev", we choose the better name "cdev" from now on. This change affects all applications, which using the With... options of "gpiod" or "sysfs". A search and replace is suitable: ```go // old ... a := NewAdaptor(adaptors.WithGpiodAccess()) ... // new ... a := NewAdaptor(adaptors.WithGpioCdevAccess()) ... ``` ```go // old ... a := NewAdaptor(adaptors.WithSysfsAccess()) ... // new ... a := NewAdaptor(adaptors.WithGpioSysfsAccess()) ... ``` Also those findings needs to be replaced, which usually affects developers, but not users: * `system.WithDigitalPinGpiodAccess()` --> `system.WithDigitalPinCdevAccess()` * `IsGpiodDigitalPinAccess()` --> `HasDigitalPinCdevAccess()` ### PocketBeagle adaptor goes cdev The beagle board "PocketBeagle" supports with latest images the Linux Kernel character device API, so the adaptor was changed to use this as the default. By "adaptors.WithSysfsAccess()" the old behavior can be forced. This is most likely needed if an old image with old Kernel is used which does not support this new API. A small renaming is also done, please search and replace: ```go // old ... "gobot.io/x/gobot/v2/platforms/beaglebone" ... beaglebone.NewPocketBeagleAdaptor(...) ... // new ... "gobot.io/x/gobot/v2/platforms/beagleboard/pocketbeagle" ... pocketbeagle.NewAdaptor(...) ... ``` ## Switch from version 2.3.0 (ble and sphero adaptors affected) ### BLE drivers and client adaptor All BLE drivers now can be found in the folder "drivers/ble". Formerly the drivers are located below "platforms/ble". In addition the location of the BLE client adaptor was changed to "platforms/bleclient". Therefore a change for the import paths is needed. The constructor function was also renamed, see below. ```go // old import( ... "gobot.io/x/gobot/v2/platforms/ble" ... ) ... bleAdaptor := ble.NewClientAdaptor(os.Args[1]) ... // new import( ... "gobot.io/x/gobot/v2/drivers/ble" "gobot.io/x/gobot/v2/platforms/bleclient" ... ) ... bleAdaptor := bleclient.NewAdaptor(os.Args[1]) ... ``` ### BLE client adaptor changed signature for Subscribe() Since introducing the usage of "github.com/muka/go-bluetooth" in 2020, the callback do not support the given error parameter anymore. The switch to usage of "tinygo.org/x/bluetooth" has not changed this. Therefore it is removed now from the function. ### BLE generic drivers changed signature for Get*() functions All those functions log an error only or panic, so the caller gets no nice programmatic feedback. The error is now returned instead and the log output needs to be done at caller side. ```go // old ... devName := access.GetDeviceName() appearance := access.GetAppearance() modelNo := info.GetModelNumber() fwRev := info.GetFirmwareRevision() hwRev := info.GetHardwareRevision() manuName := info.GetManufacturerName() pid := info.GetPnPId() level := battery.GetBatteryLevel() ... // new ... devName, err := access.GetDeviceName() if err != nil { fmt.Println(err) } appearance, err := access.GetAppearance() if err != nil { fmt.Println(err) } ... ... ``` ### Sphero adaptor split off The Serial Based Sphero adaptor was split off into a generic serial adaptor and the driver part. With this, the imports needs to be adjusted. In addition all events now have a suffix "Event", see below. ```go // old import( ... "gobot.io/x/gobot/v2/platforms/sphero" ... ) ... adaptor := sphero.NewAdaptor("/dev/rfcomm0") spheroDriver := sphero.NewSpheroDriver(adaptor) ... _ = spheroDriver.On(sphero.Collision, func(data interface{}) { ... // new import( ... "gobot.io/x/gobot/v2/drivers/common/spherocommon" "gobot.io/x/gobot/v2/drivers/serial" "gobot.io/x/gobot/v2/platforms/serialport" ... ) ... adaptor := serialport.NewAdaptor("/dev/rfcomm0") spheroDriver := sphero.NewSpheroDriver(adaptor) ... _ = spheroDriver.On(sphero.CollisionEvent, func(data interface{}) { ... ``` ### Neurosky adaptor split off The Neurosky adaptor now use the generic serial adaptor. The driver part was moved. With this, the imports needs to be adjusted. In addition all events now have a suffix "Event", see below. ```go // old import( ... "gobot.io/x/gobot/v2/platforms/neurosky" ... ) ... adaptor := neurosky.NewAdaptor("/dev/rfcomm0") neuro := neurosky.NewDriver(adaptor) ... _ = neuro.On(neurosky.Extended, func(data interface{}) { ... // new import( ... "gobot.io/x/gobot/v2/drivers/serial/neurosky" "gobot.io/x/gobot/v2/platforms/serialport" ... ) ... adaptor := serialport.NewAdaptor("/dev/rfcomm0", serialport.WithName("Neurosky"), serialport.WithBaudRate(57600)) neuro := neurosky.NewMindWaveDriver(adaptor) ... _ = neuro.On(neurosky.ExtendedEvent, func(data interface{}) { ... ``` ### MegaPi adaptor split off The MegaPi adaptor now use the generic serial adaptor. The driver part was moved. With this, the imports needs to be adjusted. ```go // old import( ... "gobot.io/x/gobot/v2/platforms/megapi" ... ) ... megaPiAdaptor := megapi.NewAdaptor("/dev/ttyS0") motor := megapi.NewMotorDriver(megaPiAdaptor, 1) ... // new import( ... "gobot.io/x/gobot/v2/drivers/serial/megapi" "gobot.io/x/gobot/v2/platforms/serialport" ... ) ... adaptor := serialport.NewAdaptor("/dev/ttyS0", serialport.WithName("MegaPi")) motor := megapi.NewMotorDriver(adaptor, 1) ... ``` ## Switch from version 2.2.0 (gpio drivers affected) ### gpio.ButtonDriver, gpio.PIRMotionDriver: substitute parameter "v time.duration" A backward compatible case is still included, but it is recommended to use "WithButtonPollInterval" instead, see example below. ```go // old d := gpio.NewButtonDriver(adaptor, "1", 50*time.Millisecond) // new d := gpio.NewButtonDriver(adaptor, "1", gpio.WithButtonPollInterval(50*time.Millisecond)) ``` ### gpio.EasyDriver: optional pins There is no need to use the direction, enable or sleep feature of the driver. Therefore the parameters are removed from constructor. Please migrate according to the examples below. The order of the optional functions does not matter. ```go // old d0 := gpio.NewEasyDriver(adaptor, 0.80, "1", "", "", "") d1 := gpio.NewEasyDriver(adaptor, 0.81, "11", "12", "", "") d2 := gpio.NewEasyDriver(adaptor, 0.82, "21", "22", "23", "") d3 := gpio.NewEasyDriver(adaptor, 0.83, "31", "32", "33", "34") // new d0 := gpio.NewEasyDriver(adaptor, 0.80, "1") d1 := gpio.NewEasyDriver(adaptor, 0.81, "11", gpio.WithEasyDirectionPin("12")) d2 := gpio.NewEasyDriver(adaptor, 0.82, "21", gpio.WithEasyDirectionPin("22"), gpio.WithEasyEnablePin("23")) d3 := gpio.NewEasyDriver(adaptor, 0.83, "31", gpio.WithEasyDirectionPin("32"), gpio.WithEasyEnablePin("33"), gpio.WithEasySleepPin("34")) ``` ### gpio.BuzzerDriver: unexport 'BPM' attribute ```go d := gpio.NewBuzzerDriver(adaptor, "1") // old d.BPM = 120.0 fmt.Println("BPM:", d.BPM) // new d.SetBPM(120.0) fmt.Println("BPM:", d.BPM()) ``` ### gpio.RelayDriver: unexport 'Inverted' attribute Usually the relay is inverted or not, except be rewired. From now on the inverted behavior can only be changed on initialization. If there is really a different use case, please file a new issue. ```go // old d := gpio.NewRelayDriver(adaptor, "1") d.Inverted = true fmt.Println("is inverted:", d.Inverted) // new d := gpio.NewRelayDriver(adaptor, "1", gpio.WithRelayInverted()) fmt.Println("is inverted:", d.IsInverted()) ``` ### gpio.HD44780Driver: make 'SetRWPin()' an option ```go // old d := gpio.NewHD44780Driver(adaptor, ...) d.SetRWPin("10") // new d := gpio.NewHD44780Driver(adaptor, ..., gpio.WithHD44780RWPin("10")) ``` ### gpio.ServoDriver: unexport 'CurrentAngle' and rename functions 'Min()', 'Max()', 'Center()' ```go d := gpio.NewServoDriver(adaptor, "1") // old d.Min() fmt.Println("current position:", d.CurrentAngle) d.Center() d.Max() // new d.ToMin() fmt.Println("current position:", d.Angle()) d.ToCenter() d.ToMax() ``` ### gpio.MotorDriver: unexport pin and state attributes, rename functions The motor driver was heavily revised - sorry for the inconveniences. affected pins: * SpeedPin * SwitchPin (removed, was unused) * DirectionPin * ForwardPin * BackwardPin Usually the pins will not change without a hardware rewiring. All pins, except the speed pin are optionally, so options are designed for that. ```go // old d := gpio.NewMotorDriver(adaptor, "1") d.DirectionPin = "10" // new d := gpio.NewMotorDriver(adaptor, "1", gpio.WithMotorDirectionPin("10")) ``` ```go // old d := gpio.NewMotorDriver(adaptor, "1") d.ForwardPin = "10" d.BackWardPin = "11" // new d := gpio.NewMotorDriver(adaptor, "1", gpio.WithMotorForwardPin("10"), gpio.WithMotorBackwardPin("11")) ``` affected functions: * Speed() --> SetSpeed() * Direction() --> SetDirection() * Max() --> RunMax() * Min() --> RunMin() affected states: * CurrentState * CurrentSpeed * CurrentMode * CurrentDirection Most of the attributes were used only for reading. If there is something missing, please file a new issue. ```go d := gpio.NewMotorDriver(adaptor, "1") // old d.On() fmt.Println("is on:", d.CurrentState==1) fmt.Println("speed:", d.CurrentSpeed) d.Off() fmt.Println("is off:", d.CurrentState==0) fmt.Println("mode is digital:", d.CurrentMode=="digital") fmt.Println("direction:", d.CurrentDirection) // new d.On() fmt.Println("is on:", d.IsOn()) d.Off() fmt.Println("is on:", d.IsOff()) fmt.Println("speed:", d.Speed()) fmt.Println("mode is digital:", d.IsDigital()) fmt.Println("direction:", d.Direction()) ``` ```go d := gpio.NewMotorDriver(adaptor, "1") // old d.Speed(123) fmt.Println("is mode now analog?", d.CurrentMode!="digital") // new d.SetSpeed(123) fmt.Println("is mode now analog?", d.IsAnalog()) ``` Although, it is working like above, it will be more clear, if the mode is defined at the beginning, like so. ```go // old d := gpio.NewMotorDriver(adaptor, "1") d.CurrentMode=="analog" d.Max() // new d := gpio.NewMotorDriver(adaptor, "1", gpio.WithMotorAnalog()) d.RunMax() ``` ================================================ FILE: Makefile ================================================ # include also examples in other than ./examples folder ALL_EXAMPLES := $(shell grep -l -r --include "*.go" 'build example' ./) # prevent examples with gocv (opencv) dependencies EXAMPLES_NO_GOCV := $(shell grep -L 'gocv' $(ALL_EXAMPLES)) # used examples EXAMPLES := $(EXAMPLES_NO_GOCV) .PHONY: test test_race test_cover robeaux version_check fmt_check fmt_fix examples examples_check examples_fmt_fix $(EXAMPLES) # opencv platform currently skipped to prevent install of preconditions including_except := $(shell go list ./... | grep -v platforms/opencv) # Run tests on nearly all directories without test cache, with race detection test_race: go test -failfast -count=1 -race $(including_except) -tags libusb # Run tests on nearly all directories without test cache test: go test -failfast -count=1 $(including_except) # Test, generate and show coverage in browser test_cover: go test -v $(including_except) -coverprofile=coverage.txt ; \ go tool cover -html=coverage.txt ; \ robeaux: ifeq (,$(shell which go-bindata)) $(error robeaux not built! https://github.com/jteeuwen/go-bindata is required to build robeaux assets ) endif cd api ; \ npm install robeaux ; \ cp -r node_modules/robeaux robeaux-tmp ; \ cd robeaux-tmp ; \ rm Makefile package.json README.markdown ; \ touch css/fonts.css ; \ echo "Updating robeaux..." ; \ go-bindata -pkg="robeaux" -o robeaux.go -ignore=\\.git ./... ; \ mv robeaux.go ../robeaux ; \ cd .. ; \ rm -rf robeaux-tmp/ ; \ rm -rf node_modules/ ; \ go fmt ./robeaux/robeaux.go ; \ # Check for installed and module version match. Will exit with code 50 if not match. # There is nothing bad in general, if you program with a higher version. # At least the recipe "fmt_fix" will not work in that case. version_check: @gv=$$(echo $$(go version) | sed "s/^.* go\([0-9].[0-9]*\).*/\1/") ; \ mv=$$(grep -m 1 'go 1.' ./go.mod | sed "s/^go \([0-9].[0-9]*\).*/\1/") ; \ echo "go: $${gv}.*, go.mod: $${mv}" ; \ if [ "$${gv}" != "$${mv}" ]; then exit 50; fi ; \ # Check for bad code style and other issues (gofumpt and gofmt check is activated for the linter) fmt_check: golangci-lint run -v # Fix bad code style (the go version will be automatically obtained from go.mod) fmt_fix: $(MAKE) version_check || true gofumpt -l -w . golangci-lint run -v --fix examples: $(EXAMPLES) examples_check: $(MAKE) CHECK=ON examples examples_fmt_fix: $(MAKE) CHECK=FMT examples $(EXAMPLES): ifeq ($(CHECK),ON) go vet -tags libusb ./$@ else ifeq ($(CHECK),FMT) gofumpt -l -w ./$@ golangci-lint run ./$@ --fix --build-tags example,libusb --disable forcetypeassert --disable noctx else go build -tags libusb -o /tmp/gobot_examples/$@ ./$@ endif ================================================ FILE: README.md ================================================ [![Gobot](https://raw.githubusercontent.com/hybridgroup/gobot-site/master/source/images/elements/gobot-logo-small.png)](http://gobot.io/) [![GoDoc](https://godoc.org/gobot.io/x/gobot/v2?status.svg)](https://godoc.org/gobot.io/x/gobot/v2) [![CircleCI Build status](https://circleci.com/gh/hybridgroup/gobot/tree/dev.svg?style=svg)](https://circleci.com/gh/hybridgroup/gobot/tree/dev) [![Appveyor Build status](https://ci.appveyor.com/api/projects/status/ix29evnbdrhkr7ud/branch/dev?svg=true)](https://ci.appveyor.com/project/deadprogram/gobot/branch/dev) [![codecov](https://codecov.io/gh/hybridgroup/gobot/branch/dev/graph/badge.svg)](https://codecov.io/gh/hybridgroup/gobot) [![Go Report Card](https://goreportcard.com/badge/hybridgroup/gobot)](https://goreportcard.com/report/hybridgroup/gobot) [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/hybridgroup/gobot/blob/release/LICENSE.txt) Gobot () is a framework using the Go programming language () for robotics, physical computing, and the Internet of Things. It provides a simple, yet powerful way to create solutions that incorporate multiple, different hardware devices at the same time. Want to run Go directly on microcontrollers? Check out our sister project TinyGo () ## Getting Started ### Get in touch Get the Gobot source code by running this commands: ```sh git clone https://github.com/hybridgroup/gobot.git git checkout release ``` Afterwards have a look at the [examples directory](./examples). You need to find an example matching your platform for your first test (e.g. "raspi_blink.go"). Than build the binary (cross compile), transfer it to your target and run it. `env GOOS=linux GOARCH=arm GOARM=5 go build -o ./output/my_raspi_bink examples/raspi_blink.go` > Building the code on your local machine with the example code above will create a binary for ARMv5. This is probably not > what you need for your specific target platform. Please read also the platform specific documentation in the platform > subfolders. ### Create your first project Create a new folder and a new Go module project. ```sh mkdir ~/my_gobot_example cd ~/my_gobot_example go mod init my.gobot.example.com ``` Copy your example file besides the go.mod file, import the requirements and build. ```sh cp //examples/raspi_blink.go ~/my_gobot_example/ go mod tidy env GOOS=linux GOARCH=arm GOARM=5 go build -o ./output/my_raspi_bink raspi_blink.go ``` Now you are ready to modify the example and test your changes. Start by removing the build directives at the beginning of the file. ## Examples ### Gobot with Arduino ```go package main import ( "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/firmata" ) func main() { firmataAdaptor := firmata.NewAdaptor("/dev/ttyACM0") led := gpio.NewLedDriver(firmataAdaptor, "13") work := func() { gobot.Every(1*time.Second, func() { if err := led.Toggle(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("bot", []gobot.Connection{firmataAdaptor}, []gobot.Device{led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ``` ### Gobot with Sphero ```go package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/serial" "gobot.io/x/gobot/v2/platforms/serialport" ) func main() { adaptor := serialport.NewAdaptor("/dev/rfcomm0") driver := sphero.NewSpheroDriver(adaptor) work := func() { gobot.Every(3*time.Second, func() { driver.Roll(30, uint16(gobot.Rand(360))) }) } robot := gobot.NewRobot("sphero", []gobot.Connection{adaptor}, []gobot.Device{driver}, work, ) if err := robot.Start(); err != nil { panic(err) } } ``` ### "Metal" Gobot You can use the entire Gobot framework as shown in the examples above ("Classic" Gobot), or you can pick and choose from the various Gobot packages to control hardware with nothing but pure idiomatic Golang code ("Metal" Gobot). For example: ```go package main import ( "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/intel-iot/edison" "time" ) func main() { e := edison.NewAdaptor() if err := e.Connect(); err != nil { fmt.Println(err) } led := gpio.NewLedDriver(e, "13") if err := led.Start(); err != nil { fmt.Println(err) } for { if err := led.Toggle(); err != nil { fmt.Println(err) } time.Sleep(1000 * time.Millisecond) } } ``` ### "Manager" Gobot You can also use the full capabilities of the framework aka "Manager Gobot" to control swarms of robots or other features such as the built-in API server. For example: ```go package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/api" "gobot.io/x/gobot/v2/drivers/common/spherocommon" "gobot.io/x/gobot/v2/drivers/serial" "gobot.io/x/gobot/v2/platforms/serialport" ) func NewSwarmBot(port string) *gobot.Robot { spheroAdaptor := serialport.NewAdaptor(port) spheroDriver := sphero.NewSpheroDriver(spheroAdaptor, serial.WithName("Sphero" + port)) work := func() { spheroDriver.Stop() _ = spheroDriver.On(sphero.CollisionEvent, func(data interface{}) { fmt.Println("Collision Detected!") }) gobot.Every(1*time.Second, func() { spheroDriver.Roll(100, uint16(gobot.Rand(360))) }) gobot.Every(3*time.Second, func() { spheroDriver.SetRGB(uint8(gobot.Rand(255)), uint8(gobot.Rand(255)), uint8(gobot.Rand(255)), ) }) } robot := gobot.NewRobot("sphero", []gobot.Connection{spheroAdaptor}, []gobot.Device{spheroDriver}, work, ) return robot } func main() { manager := gobot.NewManager() api.NewAPI(manager).Start() spheros := []string{ "/dev/rfcomm0", "/dev/rfcomm1", "/dev/rfcomm2", "/dev/rfcomm3", } for _, port := range spheros { manager.AddRobot(NewSwarmBot(port)) } if err := manager.Start(); err != nil { panic(err) } } ``` ## Hardware Support Gobot has a extensible system for connecting to hardware devices. The following robotics and physical computing platforms are currently supported: - [Arduino](http://www.arduino.cc/) <=> [Package](https://github.com/hybridgroup/gobot/blob/release/platforms/firmata) - [ASUS Tinker Board](https://www.asus.com/us/Single-Board-Computer/Tinker-Board/) <=> [Package](https://github.com/hybridgroup/gobot/blob/release/platforms/asus/tinkerboard) - [ASUS Tinker Board 2](https://tinker-board.asus.com/series/tinker-board-2.html/) <=> [Package](https://github.com/hybridgroup/gobot/blob/release/platforms/asus/tinkerboard2) - Audio <=> [Package](https://github.com/hybridgroup/gobot/blob/release/platforms/audio) - [BeagleBoard BeagleBone Black](http://beagleboard.org/boards) <=> [Package](https://github.com/hybridgroup/gobot/blob/release/platforms/beagleboard/beaglebone) - [BeagleBoard PocketBeagle](http://beagleboard.org/pocket/) <=> [Package](https://github.com/hybridgroup/gobot/blob/release/platforms/beagleboard/pocketbeagle) - [Bluetooth LE](https://www.bluetooth.com/what-is-bluetooth-technology/bluetooth-technology-basics/low-energy) <=> [Package](https://github.com/hybridgroup/gobot/blob/release/platforms/bleclient) - [C.H.I.P](http://www.nextthing.co/pages/chip) <=> [Package](https://github.com/hybridgroup/gobot/blob/release/platforms/chip) - [C.H.I.P Pro](https://docs.getchip.com/chip_pro.html) <=> [Package](https://github.com/hybridgroup/gobot/blob/release/platforms/chip) - [Digispark](http://digistump.com/products/1) <=> [Package](https://github.com/hybridgroup/gobot/blob/release/platforms/digispark) - [DJI Tello](https://www.ryzerobotics.com/tello) <=> [Package](https://github.com/hybridgroup/gobot/blob/release/platforms/dji/tello) - [DragonBoard](https://developer.qualcomm.com/hardware/dragonboard-410c) <=> [Package](https://github.com/hybridgroup/gobot/blob/release/platforms/dragonboard) - [ESP8266](http://esp8266.net/) <=> [Package](https://github.com/hybridgroup/gobot/blob/release/platforms/firmata) - [FriendlyELEC NanoPi NEO](https://wiki.friendlyelec.com/wiki/index.php/NanoPi_NEO) <=> [Package](https://github.com/hybridgroup/gobot/blob/release/platforms/friendlyelec/nanopi) - [FriendlyELEC NanoPC-T6](https://wiki.friendlyelec.com/wiki/index.php/NanoPC-T6) <=> [Package](https://github.com/hybridgroup/gobot/blob/release/platforms/friendlyelec/nanopct6) - [GoPiGo 3](https://www.dexterindustries.com/gopigo3/) <=> [Package](https://github.com/hybridgroup/gobot/blob/release/platforms/dexter/gopigo3) - [Intel Curie](https://www.intel.com/content/www/us/en/products/boards-kits/curie.html) <=> [Package](https://github.com/hybridgroup/gobot/blob/release/platforms/intel-iot/curie) - [Intel Edison](http://www.intel.com/content/www/us/en/do-it-yourself/edison.html) <=> [Package](https://github.com/hybridgroup/gobot/blob/release/platforms/intel-iot/edison) - [Intel Joule](http://intel.com/joule/getstarted) <=> [Package](https://github.com/hybridgroup/gobot/blob/release/platforms/intel-iot/joule) - [Jetson Nano](https://developer.nvidia.com/embedded/jetson-nano/) <=> [Package](https://github.com/hybridgroup/gobot/blob/release/platforms/jetson) - [Joystick](http://en.wikipedia.org/wiki/Joystick) <=> [Package](https://github.com/hybridgroup/gobot/blob/release/platforms/joystick) - [Keyboard](https://en.wikipedia.org/wiki/Computer_keyboard) <=> [Package](https://github.com/hybridgroup/gobot/blob/release/platforms/keyboard) - [Leap Motion](https://www.leapmotion.com/) <=> [Package](https://github.com/hybridgroup/gobot/blob/release/platforms/leap) - [MavLink](http://qgroundcontrol.org/mavlink/start) <=> [Package](https://github.com/hybridgroup/gobot/blob/release/platforms/mavlink) - [MegaPi](http://www.makeblock.com/megapi) <=> [Package](https://github.com/hybridgroup/gobot/blob/release/platforms/megapi) - [Microbit](http://microbit.org/) <=> [Package](https://github.com/hybridgroup/gobot/blob/release/platforms/microbit) - [MQTT](http://mqtt.org/) <=> [Package](https://github.com/hybridgroup/gobot/blob/release/platforms/mqtt) - [NATS](http://nats.io/) <=> [Package](https://github.com/hybridgroup/gobot/blob/release/platforms/nats) - [Neurosky](http://neurosky.com/products-markets/eeg-biosensors/hardware/) <=> [Package](https://github.com/hybridgroup/gobot/blob/release/platforms/neurosky) - [OpenCV](http://opencv.org/) <=> [Package](https://github.com/hybridgroup/gobot/blob/release/platforms/opencv) - [OrangePi 5 Pro](http://www.orangepi.org/html/hardWare/computerAndMicrocontrollers/details/Orange-Pi-5-Pro.html) <=> [Package](https://github.com/hybridgroup/gobot/blob/release/platforms/orangepi/orangepi5pro) - [Particle](https://www.particle.io/) <=> [Package](https://github.com/hybridgroup/gobot/blob/release/platforms/particle) - [Parrot ARDrone 2.0](http://ardrone2.parrot.com/) <=> [Package](https://github.com/hybridgroup/gobot/blob/release/platforms/parrot/ardrone) - [Parrot Bebop](http://www.parrot.com/usa/products/bebop-drone/) <=> [Package](https://github.com/hybridgroup/gobot/blob/release/platforms/parrot/bebop) - [Parrot Minidrone](https://www.parrot.com/us/minidrones) <=> [Package](https://github.com/hybridgroup/gobot/blob/release/platforms/parrot/minidrone) - [Pebble](https://www.getpebble.com/) <=> [Package](https://github.com/hybridgroup/gobot/blob/release/platforms/pebble) - [PINE64 ROCK64](https://pine64.org/documentation/ROCK64/) <=> [Package](https://github.com/hybridgroup/gobot/blob/release/platforms/pine64/rock64) - [Radxa Rock Pi 4](https://wiki.radxa.com/Rock4/) <=> [Package](https://github.com/hybridgroup/gobot/blob/release/platforms/radxa/rockpi) - [Raspberry Pi](http://www.raspberrypi.org/) <=> [Package](https://github.com/hybridgroup/gobot/blob/release/platforms/raspi) - [Serial Port](https://en.wikipedia.org/wiki/Serial_port) <=> [Package](https://github.com/hybridgroup/gobot/blob/release/platforms/serialport) - [Sphero](http://www.sphero.com/) <=> [Package](https://github.com/hybridgroup/gobot/blob/release/platforms/sphero/sphero) - [Sphero BB-8](http://www.sphero.com/bb8) <=> [Package](https://github.com/hybridgroup/gobot/blob/release/platforms/sphero/bb8) - [Sphero Ollie](http://www.sphero.com/ollie) <=> [Package](https://github.com/hybridgroup/gobot/blob/release/platforms/sphero/ollie) - [Sphero SPRK+](http://www.sphero.com/sprk-plus) <=> [Package](https://github.com/hybridgroup/gobot/blob/release/platforms/sphero/sprkplus) - [UP2](http://www.up-board.org/upsquared/) <=> [Package](https://github.com/hybridgroup/gobot/blob/release/platforms/upboard/up2) Support for many devices that use Analog Input/Output (AIO) have a shared set of drivers provided using the `gobot/drivers/aio` package: - [AIO](https://en.wikipedia.org/wiki/Analog-to-digital_converter) <=> [Drivers](https://github.com/hybridgroup/gobot/blob/release/drivers/aio) - Analog Actuator - Analog Sensor - Grove Light Sensor - Grove Piezo Vibration Sensor - Grove Rotary Dial - Grove Sound Sensor - Grove Temperature Sensor - Temperature Sensor (supports linear and NTC thermistor in normal and inverse mode) - Thermal Zone Temperature Sensor Support for many devices that use Bluetooth LE (BLE) have a shared set of drivers provided using the `gobot/drivers/ble` package: - [BLE](http://en.wikipedia.org/wiki/Bluetooth_low_energy) <=> [Drivers](https://github.com/hybridgroup/gobot/blob/release/drivers/ble) - Battery Service - Device Information Service - Generic Access Service - Microbit: AccelerometerDriver - Microbit: ButtonDriver - Microbit: IOPinDriver - Microbit: LEDDriver - Microbit: MagnetometerDriver - Microbit: TemperatureDriver - Sphero: BB8 - Sphero: Ollie - Sphero: SPRK+ Support for many devices that use General Purpose Input/Output (GPIO) have a shared set of drivers provided using the `gobot/drivers/gpio` package: - [GPIO](https://en.wikipedia.org/wiki/General_Purpose_Input/Output) <=> [Drivers](https://github.com/hybridgroup/gobot/blob/release/drivers/gpio) - AIP1640 LED Dot Matrix/7 Segment Controller - Button - Buzzer - Direct Pin - EasyDriver - Grove Button (by using driver for Button) - Grove Buzzer (by using driver for Buzzer) - Grove LED (by using driver for LED) - Grove Magnetic Switch (by using driver for Button) - Grove Relay (by using driver for Relay) - Grove Touch Sensor (by using driver for Button) - HC-SR04 Ultrasonic Ranging Module - HD44780 LCD controller - LED - Makey Button (by using driver for Button) - MAX7219 LED Dot Matrix - Motor - Proximity Infra Red (PIR) Motion Sensor - Relay - RGB LED - Servo - Stepper Motor - TM1638 LED Controller Support for devices that use Inter-Integrated Circuit (I2C) have a shared set of drivers provided using the `gobot/drivers/i2c` package: - [I2C](https://en.wikipedia.org/wiki/I%C2%B2C) <=> [Drivers](https://github.com/hybridgroup/gobot/blob/release/drivers/i2c) - Adafruit 1109 2x16 RGB-LCD with 5 keys - Adafruit 2327 16-Channel PWM/Servo HAT Hat - Adafruit 2348 DC and Stepper Motor Hat - ADS1015 Analog to Digital Converter - ADS1115 Analog to Digital Converter - ADXL345 Digital Accelerometer - BH1750 Digital Luminosity/Lux/Light Sensor - BlinkM LED - BME280 Barometric Pressure/Temperature/Altitude/Humidity Sensor - BMP180 Barometric Pressure/Temperature/Altitude Sensor - BMP280 Barometric Pressure/Temperature/Altitude Sensor - BMP388 Barometric Pressure/Temperature/Altitude Sensor - DRV2605L Haptic Controller - Generic driver for read and write values to/from register address - Grove Digital Accelerometer - GrovePi Expansion Board - Grove RGB LCD - HMC6352 Compass - HMC5883L 3-Axis Digital Compass - INA3221 Voltage Monitor - JHD1313M1 LCD Display w/RGB Backlight - L3GD20H 3-Axis Gyroscope - LIDAR-Lite - MCP23017 Port Expander - MMA7660 3-Axis Accelerometer - MPL115A2 Barometric Pressure/Temperature - MPU6050 Accelerometer/Gyroscope - PCA9501 8-bit I/O port with interrupt, 2-kbit EEPROM - PCA953x LED Dimmer for PCA9530 (2-bit), PCA9533 (4-bit), PCA9531 (8-bit), PCA9532 (16-bit) - PCA9685 16-channel 12-bit PWM/Servo Driver - PCF8583 clock and calendar or event counter, 240 x 8-bit RAM - PCF8591 8-bit 4xA/D & 1xD/A converter - SHT2x Temperature/Humidity - SHT3x-D Temperature/Humidity - SSD1306 OLED Display Controller - TSL2561 Digital Luminosity/Lux/Light Sensor - Wii Nunchuck Controller - YL-40 Brightness/Temperature sensor, Potentiometer, analog input, analog output Driver Support for many devices that use Serial communication (UART) have a shared set of drivers provided using the `gobot/drivers/serial` package: - [UART](https://en.wikipedia.org/wiki/Serial_port) <=> [Drivers](https://github.com/hybridgroup/gobot/blob/release/drivers/serial) - Sphero: Sphero - Neurosky: MindWave - MegaPi: MotorDriver Support for devices that use Serial Peripheral Interface (SPI) have a shared set of drivers provided using the `gobot/drivers/spi` package: - [SPI](https://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus) <=> [Drivers](https://github.com/hybridgroup/gobot/blob/release/drivers/spi) - APA102 Programmable LEDs - MCP3002 Analog/Digital Converter - MCP3004 Analog/Digital Converter - MCP3008 Analog/Digital Converter - MCP3202 Analog/Digital Converter - MCP3204 Analog/Digital Converter - MCP3208 Analog/Digital Converter - MCP3304 Analog/Digital Converter - MFRC522 RFID Card Reader - SSD1306 OLED Display Controller Support for devices that use 1-wire bus with Linux Kernel support (w1-gpio) have a shared set of drivers provided using the `gobot/drivers/onewire` package: - [1-wire](https://en.wikipedia.org/wiki/1-Wire) <=> [Drivers](https://github.com/hybridgroup/gobot/blob/release/drivers/onewire) - DS18B20 Temperature Sensor ## API Gobot includes a RESTful API to query the status of any robot running within a group, including the connection and device status, and execute device commands. To activate the API, import the `gobot.io/x/gobot/v2/api` package and instantiate the `API` like this: ```go manager := gobot.NewManager() api.NewAPI(manager).Start() ``` You can also specify the api host and port, and turn on authentication: ```go manager := gobot.NewManager() server := api.NewAPI(manager) server.Port = "4000" server.AddHandler(api.BasicAuth("gort", "klatuu")) server.Start() ``` You may access the [robeaux](https://github.com/hybridgroup/robeaux) React.js interface with Gobot by navigating to `http://localhost:3000/index.html`. ## CLI Gobot uses the Gort [http://gort.io](http://gort.io) Command Line Interface (CLI) so you can access important features right from the command line. We call it "RobotOps", aka "DevOps For Robotics". You can scan, connect, update device firmware, and more! ## Documentation We're always adding documentation to our web site at please check there as we continue to work on Gobot Thank you! ## Need help? - Issues: - Twitter: [@gobotio](https://twitter.com/gobotio) - Slack: [https://gophers.slack.com/messages/C0N5HDB08](https://gophers.slack.com/messages/C0N5HDB08) - Mailing list: ## Contributing For our contribution guidelines, please go to [https://github.com/hybridgroup/gobot/blob/release/CONTRIBUTING.md ](https://github.com/hybridgroup/gobot/blob/release/CONTRIBUTING.md ). Gobot is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms. [You can read about it here](https://github.com/hybridgroup/gobot/blob/release/CODE_OF_CONDUCT.md). ## License Copyright (c) 2013-2020 The Hybrid Group. Licensed under the Apache 2.0 license. The Contributor Covenant is released under the Creative Commons Attribution 4.0 International Public License, which requires that attribution be included. ================================================ FILE: adaptor.go ================================================ package gobot import ( "io" "time" ) // DigitalPinOptioner is the interface to provide the possibility to change pin behavior for the next usage type DigitalPinOptioner interface { // SetLabel change the pins label SetLabel(label string) (changed bool) // SetDirectionOutput sets the pins direction to output with the given initial value SetDirectionOutput(initialState int) (changed bool) // SetDirectionInput sets the pins direction to input SetDirectionInput() (changed bool) // SetActiveLow initializes the pin with inverse reaction (applies on input and output). SetActiveLow() (changed bool) // SetBias initializes the pin with the given bias (applies on input and output). SetBias(bias int) (changed bool) // SetDrive initializes the output pin with the given drive option. SetDrive(drive int) (changed bool) // SetDebounce initializes the input pin with the given debounce period. SetDebounce(period time.Duration) (changed bool) // SetEventHandlerForEdge initializes the input pin for edge detection to call the event handler on specified edge. // lineOffset is within the GPIO chip (needs to transformed to the pin id), timestamp is the detection time, // detectedEdge contains the direction of the pin changes, seqno is the sequence number for this event in the sequence // of events for all the lines in this line request, lseqno is the same but for this line SetEventHandlerForEdge(handler func(lineOffset int, timestamp time.Duration, detectedEdge string, seqno uint32, lseqno uint32), edge int) (changed bool) // SetPollForEdgeDetection use a discrete input polling method to detect edges. A poll interval of zero or smaller // will deactivate this function. Please note: Using this feature is CPU consuming and less accurate than using cdev // event handler (go-gpiocdev package) and should be done only if the former is not implemented or not working for // the adaptor. E.g. sysfs driver in gobot has not implemented edge detection yet. The function is only useful // together with SetEventHandlerForEdge() and its corresponding With*() functions. SetPollForEdgeDetection(pollInterval time.Duration, pollQuitChan chan struct{}) (changed bool) } // DigitalPinOptionApplier is the interface to apply options to change pin behavior immediately type DigitalPinOptionApplier interface { // ApplyOptions apply all given options to the pin immediately ApplyOptions(options ...func(DigitalPinOptioner) bool) error } // DigitalPinner is the interface for system gpio interactions type DigitalPinner interface { // Export exports the pin for use by the adaptor Export() error // Unexport releases the pin from the adaptor, so it is free for the operating system Unexport() error // Read reads the current value of the pin Read() (int, error) // Write writes to the pin Write(val int) error // DigitalPinOptionApplier is the interface to change pin behavior immediately DigitalPinOptionApplier } // DigitalPinValuer is the interface to get pin behavior for the next usage. The interface is and should be rarely used. type DigitalPinValuer interface { // DirectionBehavior gets the direction behavior when the pin is used the next time. // This means its possibly not in this direction type at the moment. DirectionBehavior() string } // DigitalPinnerProvider is the interface that an Adaptor should implement to allow clients to obtain // access to any DigitalPin's available on that board. If the pin is initially acquired, it is an input. // Pin direction and other options can be changed afterwards by pin.ApplyOptions() at any time. type DigitalPinnerProvider interface { DigitalPin(id string) (DigitalPinner, error) } // PWMPinner is the interface for system PWM interactions type PWMPinner interface { // Export exports the PWM pin for use by the operating system Export() error // Unexport releases the PWM pin from the operating system Unexport() error // Enabled returns the enabled state of the PWM pin Enabled() (bool, error) // SetEnabled enables/disables the PWM pin SetEnabled(val bool) error // Polarity returns true if the polarity of the PWM pin is normal, otherwise false Polarity() (bool, error) // SetPolarity sets the polarity of the PWM pin to normal if called with true and to inverted if called with false SetPolarity(normal bool) error // Period returns the current PWM period in nanoseconds for pin Period() (uint32, error) // SetPeriod sets the current PWM period in nanoseconds for pin SetPeriod(period uint32) error // DutyCycle returns the duty cycle in nanoseconds for the PWM pin DutyCycle() (uint32, error) // SetDutyCycle writes the duty cycle in nanoseconds to the PWM pin SetDutyCycle(dutyCyle uint32) error } // PWMPinnerProvider is the interface that an Adaptor should implement to allow // clients to obtain access to any PWMPin's available on that board. type PWMPinnerProvider interface { PWMPin(id string) (PWMPinner, error) } // AnalogPinner is the interface for system analog io interactions type AnalogPinner interface { // Read reads the current value of the pin Read() (int, error) // Write writes to the pin Write(val int) error } // I2cSystemDevicer is the interface to a i2c bus at system level, according to I2C/SMBus specification. // Some functions are not in the interface yet: // * Process Call (WriteWordDataReadWordData) // * Block Write - Block Read (WriteBlockDataReadBlockData) // * Host Notify - WriteWordData() can be used instead // // see: https://docs.kernel.org/i2c/smbus-protocol.html#key-to-symbols // // S: Start condition; Sr: Repeated start condition, used to switch from write to read mode. // P: Stop condition; Rd/Wr (1 bit): Read/Write bit. Rd equals 1, Wr equals 0. // A, NA (1 bit): Acknowledge (ACK) and Not Acknowledge (NACK) bit // Addr (7 bits): I2C 7 bit address. (10 bit I2C address not yet supported by gobot). // Comm (8 bits): Command byte, a data byte which often selects a register on the device. // Data (8 bits): A plain data byte. DataLow and DataHigh represent the low and high byte of a 16 bit word. // Count (8 bits): A data byte containing the length of a block operation. // [..]: Data sent by I2C device, as opposed to data sent by the host adapter. type I2cSystemDevicer interface { // ReadByte must be implemented as the sequence: // "S Addr Rd [A] [Data] NA P" ReadByte(address int) (byte, error) // ReadByteData must be implemented as the sequence: // "S Addr Wr [A] Comm [A] Sr Addr Rd [A] [Data] NA P" ReadByteData(address int, reg uint8) (uint8, error) // ReadWordData must be implemented as the sequence: // "S Addr Wr [A] Comm [A] Sr Addr Rd [A] [DataLow] A [DataHigh] NA P" ReadWordData(address int, reg uint8) (uint16, error) // ReadBlockData must be implemented as the sequence: // "S Addr Wr [A] Comm [A] Sr Addr Rd [A] [Count] A [Data] A [Data] A ... A [Data] NA P" ReadBlockData(address int, reg uint8, data []byte) error // WriteByte must be implemented as the sequence: // "S Addr Wr [A] Data [A] P" WriteByte(address int, val byte) error // WriteByteData must be implemented as the sequence: // "S Addr Wr [A] Comm [A] Data [A] P" WriteByteData(address int, reg uint8, val uint8) error // WriteBlockData must be implemented as the sequence: // "S Addr Wr [A] Comm [A] Count [A] Data [A] Data [A] ... [A] Data [A] P" WriteBlockData(address int, reg uint8, data []byte) error // WriteWordData must be implemented as the sequence: // "S Addr Wr [A] Comm [A] DataLow [A] DataHigh [A] P" WriteWordData(address int, reg uint8, val uint16) error // WriteBytes writes the given data starting from the current register of bus device. WriteBytes(address int, data []byte) error // Read implements direct read operations. Read(address int, b []byte) (int, error) // Write implements direct write operations. Write(address int, b []byte) (n int, err error) // Close closes the character device file. Close() error } // SpiSystemDevicer is the interface to a SPI bus at system level. type SpiSystemDevicer interface { TxRx(tx []byte, rx []byte) error // Close the SPI connection. Close() error } // OneWireSystemDevicer is the interface to a 1-wire device at system level. // //nolint:iface // ok for now type OneWireSystemDevicer interface { // ID returns the device id in the form "family code"-"serial number". ID() string // ReadData reads byte data from the device ReadData(command string, data []byte) error // WriteData writes byte data to the device WriteData(command string, data []byte) error // ReadInteger reads an integer value from the device ReadInteger(command string) (int, error) // WriteInteger writes an integer value to the device WriteInteger(command string, val int) error // Close the 1-wire connection. Close() error } // BusOperations are functions provided by a bus device, e.g. SPI, i2c. type BusOperations interface { // ReadByteData reads a byte from the given register of bus device. ReadByteData(reg uint8) (uint8, error) // ReadBlockData fills the given buffer with reads starting from the given register of bus device. ReadBlockData(reg uint8, data []byte) error // WriteByteData writes the given byte value to the given register of bus device. WriteByteData(reg uint8, val uint8) error // WriteBlockData writes the given data starting from the given register of bus device. WriteBlockData(reg uint8, data []byte) error // WriteByte writes the given byte value to the current register of bus device. WriteByte(val byte) error // WriteBytes writes the given data starting from the current register of bus device. WriteBytes(data []byte) error } // I2cOperations represents the i2c methods according to I2C/SMBus specification. type I2cOperations interface { io.ReadWriteCloser BusOperations // ReadByte reads a byte from the current register of an i2c device. ReadByte() (byte, error) // ReadWordData reads a 16 bit value starting from the given register of an i2c device. ReadWordData(reg uint8) (uint16, error) // WriteWordData writes the given 16 bit value starting from the given register of an i2c device. WriteWordData(reg uint8, val uint16) error } // SpiOperations are the wrappers around the actual functions used by the SPI device interface type SpiOperations interface { BusOperations // ReadCommandData uses the SPI device TX to send/receive data. ReadCommandData(command []byte, data []byte) error // Close the connection. Close() error } // OneWireOperations are the wrappers around the actual functions used by the 1-wire device interface // //nolint:iface // ok for now type OneWireOperations interface { // ID returns the device id in the form "family code"-"serial number". ID() string // ReadData reads from the device ReadData(command string, data []byte) error // WriteData writes to the device WriteData(command string, data []byte) error // ReadInteger reads an integer value from the device ReadInteger(command string) (int, error) // WriteInteger writes an integer value to the device WriteInteger(command string, val int) error // Close the connection. Close() error } // Adaptor is the interface that describes an adaptor in gobot type Adaptor interface { // Name returns the label for the Adaptor Name() string // SetName sets the label for the Adaptor SetName(name string) // Connect initiates the Adaptor Connect() error // Finalize terminates the Adaptor Finalize() error } // BLEConnector is the interface that a BLE ClientAdaptor must implement type BLEConnector interface { Adaptor Reconnect() error Disconnect() error Address() string ReadCharacteristic(cUUID string) ([]byte, error) WriteCharacteristic(cUUID string, data []byte) error Subscribe(cUUID string, f func(data []byte)) error WithoutResponses(use bool) } // Porter is the interface that describes an adaptor's port type Porter interface { Port() string } ================================================ FILE: api/api.go ================================================ package api import ( "encoding/json" "fmt" "log" "net/http" "net/http/httptest" "strings" "time" "github.com/bmizerany/pat" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/api/robeaux" ) // API represents an API server type API struct { manager *gobot.Manager router *pat.PatternServeMux Host string Port string Cert string Key string handlers []func(http.ResponseWriter, *http.Request) start func(*API) } // NewAPI returns a new api instance func NewAPI(m *gobot.Manager) *API { return &API{ manager: m, router: pat.New(), Port: "3000", start: func(a *API) { log.Println("Initializing API on " + a.Host + ":" + a.Port + "...") http.Handle("/", a) server := &http.Server{ Addr: a.Host + ":" + a.Port, ReadHeaderTimeout: 30 * time.Second, } go func() { if a.Cert != "" && a.Key != "" { if err := server.ListenAndServeTLS(a.Cert, a.Key); err != nil { panic(err) } } else { log.Println("WARNING: API using insecure connection. " + "We recommend using an SSL certificate with Gobot.") if err := server.ListenAndServe(); err != nil { panic(err) } } }() }, } } // ServeHTTP calls api handlers and then serves request using api router func (a *API) ServeHTTP(res http.ResponseWriter, req *http.Request) { for _, handler := range a.handlers { rec := httptest.NewRecorder() handler(rec, req) for k, v := range rec.Header() { res.Header()[k] = v } if rec.Code == http.StatusUnauthorized { http.Error(res, "Not Authorized", http.StatusUnauthorized) return } } a.router.ServeHTTP(res, req) } // Post wraps api router Post call func (a *API) Post(path string, f func(http.ResponseWriter, *http.Request)) { a.router.Post(path, http.HandlerFunc(f)) } // Put wraps api router Put call func (a *API) Put(path string, f func(http.ResponseWriter, *http.Request)) { a.router.Put(path, http.HandlerFunc(f)) } // Delete wraps api router Delete call func (a *API) Delete(path string, f func(http.ResponseWriter, *http.Request)) { a.router.Del(path, http.HandlerFunc(f)) } // Options wraps api router Options call func (a *API) Options(path string, f func(http.ResponseWriter, *http.Request)) { a.router.Options(path, http.HandlerFunc(f)) } // Get wraps api router Get call func (a *API) Get(path string, f func(http.ResponseWriter, *http.Request)) { a.router.Get(path, http.HandlerFunc(f)) } // Head wraps api router Head call func (a *API) Head(path string, f func(http.ResponseWriter, *http.Request)) { a.router.Head(path, http.HandlerFunc(f)) } // AddHandler appends handler to api handlers func (a *API) AddHandler(f func(http.ResponseWriter, *http.Request)) { a.handlers = append(a.handlers, f) } // Start initializes the api by setting up Robeaux web interface. func (a *API) Start() { a.AddRobeauxRoutes() a.start(a) } // StartWithoutDefaults initializes the api without setting up the default routes. // Good for custom web interfaces. func (a *API) StartWithoutDefaults() { a.start(a) } // AddC3PIORoutes adds all of the standard C3PIO routes to the API. // For more information, please see: // http://cppp.io/ func (a *API) AddC3PIORoutes() { mcpCommandRoute := "/api/commands/:command" robotDeviceCommandRoute := "/api/robots/:robot/devices/:device/commands/:command" robotCommandRoute := "/api/robots/:robot/commands/:command" a.Get("/api/commands", a.mcpCommands) a.Get(mcpCommandRoute, a.executeMcpCommand) a.Post(mcpCommandRoute, a.executeMcpCommand) a.Get("/api/robots", a.robots) a.Get("/api/robots/:robot", a.robot) a.Get("/api/robots/:robot/commands", a.robotCommands) a.Get(robotCommandRoute, a.executeRobotCommand) a.Post(robotCommandRoute, a.executeRobotCommand) a.Get("/api/robots/:robot/devices", a.robotDevices) a.Get("/api/robots/:robot/devices/:device", a.robotDevice) a.Get("/api/robots/:robot/devices/:device/events/:event", a.robotDeviceEvent) a.Get("/api/robots/:robot/devices/:device/commands", a.robotDeviceCommands) a.Get(robotDeviceCommandRoute, a.executeRobotDeviceCommand) a.Post(robotDeviceCommandRoute, a.executeRobotDeviceCommand) a.Get("/api/robots/:robot/connections", a.robotConnections) a.Get("/api/robots/:robot/connections/:connection", a.robotConnection) a.Get("/api/", a.mcp) } // AddRobeauxRoutes adds all of the robeaux web interface routes to the API. // The Robeaux web interface requires the C3PIO API, so it is also // activated when you call this method. func (a *API) AddRobeauxRoutes() { a.AddC3PIORoutes() a.Get("/", func(res http.ResponseWriter, req *http.Request) { http.Redirect(res, req, "/index.html", http.StatusMovedPermanently) }) a.Get("/index.html", a.robeaux) a.Get("/images/:a", a.robeaux) a.Get("/js/:a", a.robeaux) a.Get("/js/:a/", a.robeaux) a.Get("/js/:a/:b", a.robeaux) a.Get("/css/:a", a.robeaux) a.Get("/css/:a/", a.robeaux) a.Get("/css/:a/:b", a.robeaux) a.Get("/partials/:a", a.robeaux) } // robeaux returns handler for robeaux routes. // Writes asset in response and sets correct header func (a *API) robeaux(res http.ResponseWriter, req *http.Request) { path := req.URL.Path buf, err := robeaux.Asset(path[1:]) if err != nil { http.Error(res, err.Error(), http.StatusNotFound) return } split := strings.Split(path, ".") ext := split[len(split)-1] switch ext { case "js": res.Header().Set("Content-Type", "text/javascript; charset=utf-8") case "css": res.Header().Set("Content-Type", "text/css; charset=utf-8") case "html": res.Header().Set("Content-Type", "text/html; charset=utf-8") } if _, err := res.Write(buf); err != nil { panic(err) } } // mcp returns MCP route handler. // Writes JSON with gobot representation func (a *API) mcp(res http.ResponseWriter, req *http.Request) { a.writeJSON(map[string]interface{}{"MCP": gobot.NewJSONManager(a.manager)}, res) } // mcpCommands returns commands route handler. // Writes JSON with global commands representation func (a *API) mcpCommands(res http.ResponseWriter, req *http.Request) { a.writeJSON(map[string]interface{}{"commands": gobot.NewJSONManager(a.manager).Commands}, res) } // robots returns route handler. // Writes JSON with robots representation func (a *API) robots(res http.ResponseWriter, req *http.Request) { jsonRobots := []*gobot.JSONRobot{} a.manager.Robots().Each(func(r *gobot.Robot) { jsonRobots = append(jsonRobots, gobot.NewJSONRobot(r)) }) a.writeJSON(map[string]interface{}{"robots": jsonRobots}, res) } // robot returns route handler. // Writes JSON with robot representation func (a *API) robot(res http.ResponseWriter, req *http.Request) { if robot, err := a.jsonRobotFor(req.URL.Query().Get(":robot")); err != nil { a.writeJSON(map[string]interface{}{"error": err.Error()}, res) } else { a.writeJSON(map[string]interface{}{"robot": robot}, res) } } // robotCommands returns commands route handler // Writes JSON with robot commands representation func (a *API) robotCommands(res http.ResponseWriter, req *http.Request) { if robot, err := a.jsonRobotFor(req.URL.Query().Get(":robot")); err != nil { a.writeJSON(map[string]interface{}{"error": err.Error()}, res) } else { a.writeJSON(map[string]interface{}{"commands": robot.Commands}, res) } } // robotDevices returns devices route handler. // Writes JSON with robot devices representation func (a *API) robotDevices(res http.ResponseWriter, req *http.Request) { if robot := a.manager.Robot(req.URL.Query().Get(":robot")); robot != nil { jsonDevices := []*gobot.JSONDevice{} robot.Devices().Each(func(d gobot.Device) { jsonDevices = append(jsonDevices, gobot.NewJSONDevice(d)) }) a.writeJSON(map[string]interface{}{"devices": jsonDevices}, res) } else { a.writeJSON(map[string]interface{}{"error": "No Robot found with the name " + req.URL.Query().Get(":robot")}, res) } } // robotDevice returns device route handler. // Writes JSON with robot device representation func (a *API) robotDevice(res http.ResponseWriter, req *http.Request) { if device, err := a.jsonDeviceFor(req.URL.Query().Get(":robot"), req.URL.Query().Get(":device")); err != nil { a.writeJSON(map[string]interface{}{"error": err.Error()}, res) } else { a.writeJSON(map[string]interface{}{"device": device}, res) } } func (a *API) robotDeviceEvent(res http.ResponseWriter, req *http.Request) { f, _ := res.(http.Flusher) dataChan := make(chan string) res.Header().Set("Content-Type", "text/event-stream") res.Header().Set("Cache-Control", "no-cache") res.Header().Set("Connection", "keep-alive") device := a.manager.Robot(req.URL.Query().Get(":robot")). Device(req.URL.Query().Get(":device")) //nolint:forcetypeassert // no error return value, so there is no better way if event := a.manager.Robot(req.URL.Query().Get(":robot")). Device(req.URL.Query().Get(":device")).(gobot.Eventer). Event(req.URL.Query().Get(":event")); len(event) > 0 { //nolint:forcetypeassert // no error return value, so there is no better way if err := device.(gobot.Eventer).On(event, func(data interface{}) { d, _ := json.Marshal(data) dataChan <- string(d) }); err != nil { panic(err) } for { select { case data := <-dataChan: fmt.Fprintf(res, "data: %v\n\n", data) f.Flush() case <-req.Context().Done(): log.Println("Closing connection") return } } } else { a.writeJSON(map[string]interface{}{ "error": "No Event found with the name " + req.URL.Query().Get(":event"), }, res) } } // robotDeviceCommands returns device commands route handler // writes JSON with robot device commands representation func (a *API) robotDeviceCommands(res http.ResponseWriter, req *http.Request) { if device, err := a.jsonDeviceFor(req.URL.Query().Get(":robot"), req.URL.Query().Get(":device")); err != nil { a.writeJSON(map[string]interface{}{"error": err.Error()}, res) } else { a.writeJSON(map[string]interface{}{"commands": device.Commands}, res) } } // robotConnections returns connections route handler // writes JSON with robot connections representation func (a *API) robotConnections(res http.ResponseWriter, req *http.Request) { jsonConnections := []*gobot.JSONConnection{} if robot := a.manager.Robot(req.URL.Query().Get(":robot")); robot != nil { robot.Connections().Each(func(c gobot.Connection) { jsonConnections = append(jsonConnections, gobot.NewJSONConnection(c)) }) a.writeJSON(map[string]interface{}{"connections": jsonConnections}, res) } else { a.writeJSON(map[string]interface{}{"error": "No Robot found with the name " + req.URL.Query().Get(":robot")}, res) } } // robotConnection returns connection route handler // writes JSON with robot connection representation func (a *API) robotConnection(res http.ResponseWriter, req *http.Request) { if conn, err := a.jsonConnectionFor(req.URL.Query().Get(":robot"), req.URL.Query().Get(":connection")); err != nil { a.writeJSON(map[string]interface{}{"error": err.Error()}, res) } else { a.writeJSON(map[string]interface{}{"connection": conn}, res) } } // executeMcpCommand calls a global command associated to requested route func (a *API) executeMcpCommand(res http.ResponseWriter, req *http.Request) { a.executeCommand(a.manager.Command(req.URL.Query().Get(":command")), res, req, ) } // executeRobotDeviceCommand calls a device command associated to requested route func (a *API) executeRobotDeviceCommand(res http.ResponseWriter, req *http.Request) { if _, err := a.jsonDeviceFor(req.URL.Query().Get(":robot"), req.URL.Query().Get(":device")); err != nil { a.writeJSON(map[string]interface{}{"error": err.Error()}, res) } else { a.executeCommand( //nolint:forcetypeassert // no error return value, so there is no better way a.manager.Robot(req.URL.Query().Get(":robot")). Device(req.URL.Query().Get(":device")).(gobot.Commander). Command(req.URL.Query().Get(":command")), res, req, ) } } // executeRobotCommand calls a robot command associated to requested route func (a *API) executeRobotCommand(res http.ResponseWriter, req *http.Request) { if _, err := a.jsonRobotFor(req.URL.Query().Get(":robot")); err != nil { a.writeJSON(map[string]interface{}{"error": err.Error()}, res) } else { a.executeCommand( a.manager.Robot(req.URL.Query().Get(":robot")). Command(req.URL.Query().Get(":command")), res, req, ) } } // executeCommand writes JSON response with `f` returned value. func (a *API) executeCommand(f func(map[string]interface{}) interface{}, res http.ResponseWriter, req *http.Request, ) { body := make(map[string]interface{}) if err := json.NewDecoder(req.Body).Decode(&body); err != nil { panic(err) } if f != nil { a.writeJSON(map[string]interface{}{"result": f(body)}, res) } else { a.writeJSON(map[string]interface{}{"error": "Unknown Command"}, res) } } // writeJSON writes `j` as JSON in response func (a *API) writeJSON(j interface{}, res http.ResponseWriter) { data, err := json.Marshal(j) if err != nil { panic(err) } res.Header().Set("Content-Type", "application/json; charset=utf-8") if _, err := res.Write(data); err != nil { panic(err) } } // Debug add handler to api that prints each request func (a *API) Debug() { a.AddHandler(func(res http.ResponseWriter, req *http.Request) { log.Println(req) }) } func (a *API) jsonRobotFor(name string) (*gobot.JSONRobot, error) { if robot := a.manager.Robot(name); robot != nil { return gobot.NewJSONRobot(robot), nil } return nil, fmt.Errorf("no Robot found with the name %s", name) } func (a *API) jsonDeviceFor(robot string, name string) (*gobot.JSONDevice, error) { if device := a.manager.Robot(robot).Device(name); device != nil { return gobot.NewJSONDevice(device), nil } return nil, fmt.Errorf("no Device found with the name %s", name) } func (a *API) jsonConnectionFor(robot string, name string) (*gobot.JSONConnection, error) { if connection := a.manager.Robot(robot).Connection(name); connection != nil { return gobot.NewJSONConnection(connection), nil } return nil, fmt.Errorf("no Connection found with the name %s", name) } ================================================ FILE: api/api_test.go ================================================ //nolint:forcetypeassert,usestdlibvars,bodyclose,noctx // ok here package api import ( "bufio" "bytes" "encoding/json" "fmt" "log" "net/http" "net/http/httptest" "testing" "time" "github.com/stretchr/testify/assert" "gobot.io/x/gobot/v2" ) func initTestAPI() *API { log.SetOutput(NullReadWriteCloser{}) g := gobot.NewManager() a := NewAPI(g) a.start = func(m *API) {} a.Start() a.Debug() g.AddRobot(newTestRobot("Robot1")) g.AddRobot(newTestRobot("Robot2")) g.AddRobot(newTestRobot("Robot3")) g.AddCommand("TestFunction", func(params map[string]interface{}) interface{} { message := params["message"].(string) return fmt.Sprintf("hey %v", message) }) return a } func TestStartWithoutDefaults(t *testing.T) { log.SetOutput(NullReadWriteCloser{}) g := gobot.NewManager() a := NewAPI(g) a.start = func(m *API) {} a.Get("/", func(res http.ResponseWriter, req *http.Request) {}) a.StartWithoutDefaults() request, _ := http.NewRequest("GET", "/", nil) response := httptest.NewRecorder() a.ServeHTTP(response, request) assert.Equal(t, 200, response.Code) } func TestRobeaux(t *testing.T) { a := initTestAPI() // html assets request, _ := http.NewRequest("GET", "/index.html", nil) response := httptest.NewRecorder() a.ServeHTTP(response, request) assert.Equal(t, 200, response.Code) // js assets request, _ = http.NewRequest("GET", "/js/script.js", nil) response = httptest.NewRecorder() a.ServeHTTP(response, request) assert.Equal(t, 200, response.Code) // css assets request, _ = http.NewRequest("GET", "/css/application.css", nil) response = httptest.NewRecorder() a.ServeHTTP(response, request) assert.Equal(t, 200, response.Code) // unknown asset request, _ = http.NewRequest("GET", "/js/fake/file.js", nil) response = httptest.NewRecorder() a.ServeHTTP(response, request) assert.Equal(t, 404, response.Code) } func TestIndex(t *testing.T) { a := initTestAPI() request, _ := http.NewRequest("GET", "/", nil) response := httptest.NewRecorder() a.ServeHTTP(response, request) assert.Equal(t, http.StatusMovedPermanently, response.Code) assert.Equal(t, "/index.html", response.Header()["Location"][0]) } func TestMcp(t *testing.T) { a := initTestAPI() request, _ := http.NewRequest("GET", "/api/", nil) response := httptest.NewRecorder() a.ServeHTTP(response, request) var body map[string]interface{} _ = json.NewDecoder(response.Body).Decode(&body) assert.NotNil(t, body["MCP"].(map[string]interface{})["robots"]) assert.NotNil(t, body["MCP"].(map[string]interface{})["commands"]) } func TestMcpCommands(t *testing.T) { a := initTestAPI() request, _ := http.NewRequest("GET", "/api/commands", nil) response := httptest.NewRecorder() a.ServeHTTP(response, request) var body map[string]interface{} _ = json.NewDecoder(response.Body).Decode(&body) assert.Equal(t, []interface{}{"TestFunction"}, body["commands"]) } func TestExecuteMcpCommand(t *testing.T) { var body interface{} a := initTestAPI() // known command request, _ := http.NewRequest("GET", "/api/commands/TestFunction", bytes.NewBufferString(`{"message":"Beep Boop"}`), ) request.Header.Add("Content-Type", "application/json") response := httptest.NewRecorder() a.ServeHTTP(response, request) _ = json.NewDecoder(response.Body).Decode(&body) assert.Equal(t, "hey Beep Boop", body.(map[string]interface{})["result"]) // unknown command request, _ = http.NewRequest("GET", "/api/commands/TestFuntion1", bytes.NewBufferString(`{"message":"Beep Boop"}`), ) request.Header.Add("Content-Type", "application/json") response = httptest.NewRecorder() a.ServeHTTP(response, request) _ = json.NewDecoder(response.Body).Decode(&body) assert.Equal(t, "Unknown Command", body.(map[string]interface{})["error"]) } func TestRobots(t *testing.T) { a := initTestAPI() request, _ := http.NewRequest("GET", "/api/robots", nil) response := httptest.NewRecorder() a.ServeHTTP(response, request) var body map[string]interface{} _ = json.NewDecoder(response.Body).Decode(&body) assert.Len(t, body["robots"].([]interface{}), 3) } func TestRobot(t *testing.T) { a := initTestAPI() // known robot request, _ := http.NewRequest("GET", "/api/robots/Robot1", nil) response := httptest.NewRecorder() a.ServeHTTP(response, request) var body map[string]interface{} _ = json.NewDecoder(response.Body).Decode(&body) assert.Equal(t, "Robot1", body["robot"].(map[string]interface{})["name"].(string)) // unknown robot request, _ = http.NewRequest("GET", "/api/robots/UnknownRobot1", nil) a.ServeHTTP(response, request) _ = json.NewDecoder(response.Body).Decode(&body) assert.Equal(t, "no Robot found with the name UnknownRobot1", body["error"]) } func TestRobotDevices(t *testing.T) { a := initTestAPI() // known robot request, _ := http.NewRequest("GET", "/api/robots/Robot1/devices", nil) response := httptest.NewRecorder() a.ServeHTTP(response, request) var body map[string]interface{} _ = json.NewDecoder(response.Body).Decode(&body) assert.Len(t, body["devices"].([]interface{}), 3) // unknown robot request, _ = http.NewRequest("GET", "/api/robots/UnknownRobot1/devices", nil) a.ServeHTTP(response, request) _ = json.NewDecoder(response.Body).Decode(&body) assert.Equal(t, "No Robot found with the name UnknownRobot1", body["error"]) } func TestRobotCommands(t *testing.T) { a := initTestAPI() // known robot request, _ := http.NewRequest("GET", "/api/robots/Robot1/commands", nil) response := httptest.NewRecorder() a.ServeHTTP(response, request) var body map[string]interface{} _ = json.NewDecoder(response.Body).Decode(&body) assert.Equal(t, []interface{}{"robotTestFunction"}, body["commands"]) // unknown robot request, _ = http.NewRequest("GET", "/api/robots/UnknownRobot1/commands", nil) a.ServeHTTP(response, request) _ = json.NewDecoder(response.Body).Decode(&body) assert.Equal(t, "no Robot found with the name UnknownRobot1", body["error"]) } func TestExecuteRobotCommand(t *testing.T) { var body interface{} a := initTestAPI() // known command request, _ := http.NewRequest("GET", "/api/robots/Robot1/commands/robotTestFunction", bytes.NewBufferString(`{"message":"Beep Boop", "robot":"Robot1"}`), ) request.Header.Add("Content-Type", "application/json") response := httptest.NewRecorder() a.ServeHTTP(response, request) _ = json.NewDecoder(response.Body).Decode(&body) assert.Equal(t, "hey Robot1, Beep Boop", body.(map[string]interface{})["result"]) // unknown command request, _ = http.NewRequest("GET", "/api/robots/Robot1/commands/robotTestFuntion1", bytes.NewBufferString(`{"message":"Beep Boop"}`), ) request.Header.Add("Content-Type", "application/json") response = httptest.NewRecorder() a.ServeHTTP(response, request) _ = json.NewDecoder(response.Body).Decode(&body) assert.Equal(t, "Unknown Command", body.(map[string]interface{})["error"]) // uknown robot request, _ = http.NewRequest("GET", "/api/robots/UnknownRobot1/commands/robotTestFuntion1", bytes.NewBufferString(`{"message":"Beep Boop"}`), ) request.Header.Add("Content-Type", "application/json") a.ServeHTTP(response, request) _ = json.NewDecoder(response.Body).Decode(&body) assert.Equal(t, "no Robot found with the name UnknownRobot1", body.(map[string]interface{})["error"]) } func TestRobotDevice(t *testing.T) { a := initTestAPI() // known device request, _ := http.NewRequest("GET", "/api/robots/Robot1/devices/Device1", nil, ) response := httptest.NewRecorder() a.ServeHTTP(response, request) var body map[string]interface{} _ = json.NewDecoder(response.Body).Decode(&body) assert.Equal(t, "Device1", body["device"].(map[string]interface{})["name"].(string)) // unknown device request, _ = http.NewRequest("GET", "/api/robots/Robot1/devices/UnknownDevice1", nil) a.ServeHTTP(response, request) _ = json.NewDecoder(response.Body).Decode(&body) assert.Equal(t, "no Device found with the name UnknownDevice1", body["error"]) } func TestRobotDeviceCommands(t *testing.T) { a := initTestAPI() // known device request, _ := http.NewRequest("GET", "/api/robots/Robot1/devices/Device1/commands", nil, ) response := httptest.NewRecorder() a.ServeHTTP(response, request) var body map[string]interface{} _ = json.NewDecoder(response.Body).Decode(&body) assert.Len(t, body["commands"].([]interface{}), 2) // unknown device request, _ = http.NewRequest("GET", "/api/robots/Robot1/devices/UnknownDevice1/commands", nil, ) a.ServeHTTP(response, request) _ = json.NewDecoder(response.Body).Decode(&body) assert.Equal(t, "no Device found with the name UnknownDevice1", body["error"]) } func TestExecuteRobotDeviceCommand(t *testing.T) { var body interface{} a := initTestAPI() // known command request, _ := http.NewRequest("GET", "/api/robots/Robot1/devices/Device1/commands/TestDriverCommand", bytes.NewBufferString(`{"name":"human"}`), ) request.Header.Add("Content-Type", "application/json") response := httptest.NewRecorder() a.ServeHTTP(response, request) _ = json.NewDecoder(response.Body).Decode(&body) assert.Equal(t, "hello human", body.(map[string]interface{})["result"].(string)) // unknown command request, _ = http.NewRequest("GET", "/api/robots/Robot1/devices/Device1/commands/DriverCommand1", bytes.NewBufferString(`{"name":"human"}`), ) request.Header.Add("Content-Type", "application/json") response = httptest.NewRecorder() a.ServeHTTP(response, request) _ = json.NewDecoder(response.Body).Decode(&body) assert.Equal(t, "Unknown Command", body.(map[string]interface{})["error"]) // unknown device request, _ = http.NewRequest("GET", "/api/robots/Robot1/devices/UnknownDevice1/commands/DriverCommand1", bytes.NewBufferString(`{"name":"human"}`), ) request.Header.Add("Content-Type", "application/json") a.ServeHTTP(response, request) _ = json.NewDecoder(response.Body).Decode(&body) assert.Equal(t, "no Device found with the name UnknownDevice1", body.(map[string]interface{})["error"]) } func TestRobotConnections(t *testing.T) { a := initTestAPI() // known robot request, _ := http.NewRequest("GET", "/api/robots/Robot1/connections", nil) response := httptest.NewRecorder() a.ServeHTTP(response, request) var body map[string]interface{} _ = json.NewDecoder(response.Body).Decode(&body) assert.Len(t, body["connections"].([]interface{}), 3) // unknown robot request, _ = http.NewRequest("GET", "/api/robots/UnknownRobot1/connections", nil) a.ServeHTTP(response, request) _ = json.NewDecoder(response.Body).Decode(&body) assert.Equal(t, "No Robot found with the name UnknownRobot1", body["error"]) } func TestRobotConnection(t *testing.T) { a := initTestAPI() // known connection request, _ := http.NewRequest("GET", "/api/robots/Robot1/connections/Connection1", nil, ) response := httptest.NewRecorder() a.ServeHTTP(response, request) var body map[string]interface{} _ = json.NewDecoder(response.Body).Decode(&body) assert.Equal(t, "Connection1", body["connection"].(map[string]interface{})["name"].(string)) // unknown connection request, _ = http.NewRequest("GET", "/api/robots/Robot1/connections/UnknownConnection1", nil, ) a.ServeHTTP(response, request) _ = json.NewDecoder(response.Body).Decode(&body) assert.Equal(t, "no Connection found with the name UnknownConnection1", body["error"]) } func TestRobotDeviceEvent(t *testing.T) { a := initTestAPI() server := httptest.NewServer(a) defer server.Close() eventsURL := "/api/robots/Robot1/devices/Device1/events/" // known event respc := make(chan *http.Response, 1) go func() { resp, _ := http.Get(server.URL + eventsURL + "TestEvent") respc <- resp }() event := a.manager.Robot("Robot1"). Device("Device1").(gobot.Eventer). Event("TestEvent") go func() { time.Sleep(time.Millisecond * 10) // wait some time, so select below is ready a.manager.Robot("Robot1"). Device("Device1").(gobot.Eventer).Publish(event, "event-data") }() select { case resp := <-respc: reader := bufio.NewReader(resp.Body) data, _ := reader.ReadString('\n') assert.Equal(t, "data: \"event-data\"\n", data) case <-time.After(50 * time.Millisecond): t.Error("Not receiving data") } server.CloseClientConnections() // unknown event response, _ := http.Get(server.URL + eventsURL + "UnknownEvent") var body map[string]interface{} _ = json.NewDecoder(response.Body).Decode(&body) assert.Equal(t, "No Event found with the name UnknownEvent", body["error"]) } func TestAPIRouter(t *testing.T) { a := initTestAPI() a.Head("/test", func(res http.ResponseWriter, req *http.Request) {}) request, _ := http.NewRequest("HEAD", "/test", nil) response := httptest.NewRecorder() a.ServeHTTP(response, request) assert.Equal(t, 200, response.Code) a.Get("/test", func(res http.ResponseWriter, req *http.Request) {}) request, _ = http.NewRequest("GET", "/test", nil) response = httptest.NewRecorder() a.ServeHTTP(response, request) assert.Equal(t, 200, response.Code) a.Post("/test", func(res http.ResponseWriter, req *http.Request) {}) request, _ = http.NewRequest("POST", "/test", nil) response = httptest.NewRecorder() a.ServeHTTP(response, request) assert.Equal(t, 200, response.Code) a.Put("/test", func(res http.ResponseWriter, req *http.Request) {}) request, _ = http.NewRequest("PUT", "/test", nil) response = httptest.NewRecorder() a.ServeHTTP(response, request) assert.Equal(t, 200, response.Code) a.Delete("/test", func(res http.ResponseWriter, req *http.Request) {}) request, _ = http.NewRequest("DELETE", "/test", nil) response = httptest.NewRecorder() a.ServeHTTP(response, request) assert.Equal(t, 200, response.Code) a.Options("/test", func(res http.ResponseWriter, req *http.Request) {}) request, _ = http.NewRequest("OPTIONS", "/test", nil) response = httptest.NewRecorder() a.ServeHTTP(response, request) assert.Equal(t, 200, response.Code) } ================================================ FILE: api/basic_auth.go ================================================ package api import ( "crypto/subtle" "encoding/base64" "net/http" ) // BasicAuth returns basic auth handler. func BasicAuth(username, password string) http.HandlerFunc { // Inspired by https://github.com/codegangsta/martini-contrib/tree/v0.1/auth return func(res http.ResponseWriter, req *http.Request) { if !secureCompare(req.Header.Get("Authorization"), "Basic "+base64.StdEncoding.EncodeToString([]byte(username+":"+password)), ) { res.Header().Set("WWW-Authenticate", "Basic realm=\"Authorization Required\"", ) http.Error(res, "Not Authorized", http.StatusUnauthorized) } } } func secureCompare(given string, actual string) bool { //nolint:gosec // TODO: fix later if subtle.ConstantTimeEq(int32(len(given)), int32(len(actual))) == 1 { return subtle.ConstantTimeCompare([]byte(given), []byte(actual)) == 1 } // Securely compare actual to itself to keep constant time, // but always return false return subtle.ConstantTimeCompare([]byte(actual), []byte(actual)) == 1 && false } ================================================ FILE: api/basic_auth_test.go ================================================ //nolint:usestdlibvars,noctx // ok here package api import ( "net/http" "net/http/httptest" "testing" "github.com/stretchr/testify/assert" ) func TestBasicAuth(t *testing.T) { a := initTestAPI() a.AddHandler(BasicAuth("admin", "password")) request, _ := http.NewRequest("GET", "/api/", nil) request.SetBasicAuth("admin", "password") response := httptest.NewRecorder() a.ServeHTTP(response, request) assert.Equal(t, 200, response.Code) request, _ = http.NewRequest("GET", "/api/", nil) request.SetBasicAuth("admin", "wrongPassword") response = httptest.NewRecorder() a.ServeHTTP(response, request) assert.Equal(t, 401, response.Code) } ================================================ FILE: api/cors.go ================================================ package api import ( "net/http" "regexp" "strings" ) // CORS represents CORS configuration type CORS struct { AllowOrigins []string AllowHeaders []string AllowMethods []string ContentType string allowOriginPatterns []string } // AllowRequestsFrom returns handler to verify that requests come from allowedOrigins func AllowRequestsFrom(allowedOrigins ...string) http.HandlerFunc { c := &CORS{ AllowOrigins: allowedOrigins, AllowMethods: []string{"GET", "POST"}, AllowHeaders: []string{"Origin", "Content-Type"}, ContentType: "application/json; charset=utf-8", } c.generatePatterns() return func(w http.ResponseWriter, req *http.Request) { origin := req.Header.Get("Origin") if c.isOriginAllowed(origin) { w.Header().Set("Access-Control-Allow-Origin", origin) w.Header().Set("Access-Control-Allow-Headers", c.AllowedHeaders()) w.Header().Set("Access-Control-Allow-Methods", c.AllowedMethods()) w.Header().Set("Content-Type", c.ContentType) } } } // isOriginAllowed returns true if origin matches an allowed origin pattern. func (c *CORS) isOriginAllowed(origin string) bool { for _, allowedOriginPattern := range c.allowOriginPatterns { if allowed, _ := regexp.MatchString(allowedOriginPattern, origin); allowed { return true } } return false } // generatePatterns generates regex expression for AllowOrigins func (c *CORS) generatePatterns() { if c.AllowOrigins != nil { for _, origin := range c.AllowOrigins { pattern := regexp.QuoteMeta(origin) pattern = strings.ReplaceAll(pattern, "\\*", ".*") pattern = strings.ReplaceAll(pattern, "\\?", ".") c.allowOriginPatterns = append(c.allowOriginPatterns, "^"+pattern+"$") } } } // AllowedHeaders returns allowed headers in a string func (c *CORS) AllowedHeaders() string { return strings.Join(c.AllowHeaders, ",") } // AllowedMethods returns allowed http methods in a string func (c *CORS) AllowedMethods() string { return strings.Join(c.AllowMethods, ",") } ================================================ FILE: api/cors_test.go ================================================ //nolint:usestdlibvars,noctx // ok here package api import ( "net/http" "net/http/httptest" "testing" "github.com/stretchr/testify/assert" ) func TestCORSIsOriginAllowed(t *testing.T) { cors := &CORS{AllowOrigins: []string{"*"}} cors.generatePatterns() // When all the origins are accepted assert.True(t, cors.isOriginAllowed("http://localhost:8000")) assert.True(t, cors.isOriginAllowed("http://localhost:3001")) assert.True(t, cors.isOriginAllowed("http://server.com")) // When one origin is accepted cors = &CORS{AllowOrigins: []string{"http://localhost:8000"}} cors.generatePatterns() assert.True(t, cors.isOriginAllowed("http://localhost:8000")) assert.False(t, cors.isOriginAllowed("http://localhost:3001")) assert.False(t, cors.isOriginAllowed("http://server.com")) // When several origins are accepted cors = &CORS{AllowOrigins: []string{"http://localhost:*", "http://server.com"}} cors.generatePatterns() assert.True(t, cors.isOriginAllowed("http://localhost:8000")) assert.True(t, cors.isOriginAllowed("http://localhost:3001")) assert.True(t, cors.isOriginAllowed("http://server.com")) // When several origins are accepted within the same domain cors = &CORS{AllowOrigins: []string{"http://*.server.com"}} cors.generatePatterns() assert.False(t, cors.isOriginAllowed("http://localhost:8000")) assert.False(t, cors.isOriginAllowed("http://localhost:3001")) assert.True(t, cors.isOriginAllowed("http://foo.server.com")) assert.True(t, cors.isOriginAllowed("http://api.server.com")) } func TestCORSAllowedHeaders(t *testing.T) { cors := &CORS{AllowOrigins: []string{"*"}, AllowHeaders: []string{"Header1", "Header2"}} assert.Equal(t, "Header1,Header2", cors.AllowedHeaders()) } func TestCORSAllowedMethods(t *testing.T) { cors := &CORS{AllowOrigins: []string{"*"}, AllowMethods: []string{"GET", "POST"}} assert.Equal(t, "GET,POST", cors.AllowedMethods()) cors.AllowMethods = []string{"GET", "POST", "PUT"} assert.Equal(t, "GET,POST,PUT", cors.AllowedMethods()) } func TestCORS(t *testing.T) { api := initTestAPI() // Accepted origin allowedOrigin := []string{"http://server.com"} api.AddHandler(AllowRequestsFrom(allowedOrigin[0])) request, _ := http.NewRequest("GET", "/api/", nil) request.Header.Set("Origin", allowedOrigin[0]) response := httptest.NewRecorder() api.ServeHTTP(response, request) assert.Equal(t, allowedOrigin, response.Header()["Access-Control-Allow-Origin"]) // Not accepted Origin disallowedOrigin := []string{"http://disallowed.com"} request, _ = http.NewRequest("GET", "/api/", nil) request.Header.Set("Origin", disallowedOrigin[0]) response = httptest.NewRecorder() api.ServeHTTP(response, request) assert.NotEqual(t, disallowedOrigin, response.Header()["Access-Control-Allow-Origin"]) assert.NotEqual(t, allowedOrigin, response.Header()["Access-Control-Allow-Origin"]) } ================================================ FILE: api/doc.go ================================================ /* Package api provides a webserver to interact with your Gobot program over the network. Example: package main import ( "fmt" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/api" ) func main() { gbot := gobot.NewManager() // Starts the API server on default port 3000 api.NewAPI(gbot).Start() // Accessible via http://localhost:3000/api/commands/say_hello gbot.AddCommand("say_hello", func(params map[string]interface{}) interface{} { return "Manager says hello!" }) hello := gbot.AddRobot(gobot.NewRobot("Eve")) // Accessible via http://localhost:3000/api/robots/Eve/commands/say_hello hello.AddCommand("say_hello", func(params map[string]interface{}) interface{} { return fmt.Sprintf("%v says hello!", hello.Name) }) gbot.Start() } It follows Common Protocol for Programming Physical Input and Output (CPPP-IO) spec: https://gobot.io/x/cppp-io */ package api ================================================ FILE: api/helpers_test.go ================================================ //nolint:forcetypeassert // ok here package api import ( "fmt" "gobot.io/x/gobot/v2" ) type NullReadWriteCloser struct{} func (NullReadWriteCloser) Write(p []byte) (int, error) { return len(p), nil } func (NullReadWriteCloser) Read(b []byte) (int, error) { return len(b), nil } func (NullReadWriteCloser) Close() error { return nil } type testDriver struct { gobot.Commander gobot.Eventer name string pin string connection gobot.Connection } func (t *testDriver) Start() error { return nil } func (t *testDriver) Halt() error { return nil } func (t *testDriver) Name() string { return t.name } func (t *testDriver) SetName(n string) { t.name = n } func (t *testDriver) Pin() string { return t.pin } func (t *testDriver) Connection() gobot.Connection { return t.connection } func newTestDriver(adaptor *testAdaptor, name string, pin string) *testDriver { t := &testDriver{ name: name, connection: adaptor, pin: pin, Eventer: gobot.NewEventer(), Commander: gobot.NewCommander(), } t.AddEvent("TestEvent") t.AddCommand("TestDriverCommand", func(params map[string]interface{}) interface{} { name := params["name"].(string) return fmt.Sprintf("hello %v", name) }) t.AddCommand("DriverCommand", func(params map[string]interface{}) interface{} { name := params["name"].(string) return fmt.Sprintf("hello %v", name) }) return t } type testAdaptor struct { name string port string } var ( testAdaptorConnect = func() error { return nil } testAdaptorFinalize = func() error { return nil } ) func (t *testAdaptor) Finalize() error { return testAdaptorFinalize() } func (t *testAdaptor) Connect() error { return testAdaptorConnect() } func (t *testAdaptor) Name() string { return t.name } func (t *testAdaptor) SetName(n string) { t.name = n } func (t *testAdaptor) Port() string { return t.port } func newTestAdaptor(name string, port string) *testAdaptor { return &testAdaptor{ name: name, port: port, } } func newTestRobot(name string) *gobot.Robot { adaptor1 := newTestAdaptor("Connection1", "/dev/null") adaptor2 := newTestAdaptor("Connection2", "/dev/null") adaptor3 := newTestAdaptor("", "/dev/null") driver1 := newTestDriver(adaptor1, "Device1", "0") driver2 := newTestDriver(adaptor2, "Device2", "2") driver3 := newTestDriver(adaptor3, "", "1") work := func() {} r := gobot.NewRobot(name, []gobot.Connection{adaptor1, adaptor2, adaptor3}, []gobot.Device{driver1, driver2, driver3}, work, ) r.AddCommand("robotTestFunction", func(params map[string]interface{}) interface{} { message := params["message"].(string) robot := params["robot"].(string) return fmt.Sprintf("hey %v, %v", robot, message) }) return r } ================================================ FILE: api/robeaux/robeaux.go ================================================ // Code generated by go-bindata. // sources: // css/.keep // css/application.css // css/application.css.map // css/fonts.css // fonts/inconsolata-bold-webfont.eot // fonts/inconsolata-bold-webfont.svg // fonts/inconsolata-bold-webfont.ttf // fonts/inconsolata-bold-webfont.woff // fonts/inconsolata-regular-webfont.eot // fonts/inconsolata-regular-webfont.svg // fonts/inconsolata-regular-webfont.ttf // fonts/inconsolata-regular-webfont.woff // fonts/roboto-bold-webfont.eot // fonts/roboto-bold-webfont.svg // fonts/roboto-bold-webfont.ttf // fonts/roboto-bold-webfont.woff // fonts/roboto-regular-webfont.eot // fonts/roboto-regular-webfont.svg // fonts/roboto-regular-webfont.ttf // fonts/roboto-regular-webfont.woff // fonts/robotoslab-bold-webfont.eot // fonts/robotoslab-bold-webfont.svg // fonts/robotoslab-bold-webfont.ttf // fonts/robotoslab-bold-webfont.woff // images/bullet-connections-2.png // images/bullet-connections.png // images/bullet-devices-2.png // images/bullet-devices.png // images/delete.png // images/devices-image-2.png // images/devices-image.png // images/logo-robeaux.png // images/robots-icon_03.png // index.html // js/.keep // js/script.js // DO NOT EDIT! package robeaux import ( "bytes" "compress/gzip" "fmt" "io" "os" "path/filepath" "strings" "time" ) func bindataRead(data []byte, name string) ([]byte, error) { gz, err := gzip.NewReader(bytes.NewBuffer(data)) if err != nil { return nil, fmt.Errorf("read %q: %v", name, err) } var buf bytes.Buffer _, err = io.Copy(&buf, gz) clErr := gz.Close() if err != nil { return nil, fmt.Errorf("read %q: %v", name, err) } if clErr != nil { return nil, err } return buf.Bytes(), nil } type asset struct { bytes []byte info os.FileInfo } type bindataFileInfo struct { name string size int64 mode os.FileMode modTime time.Time } func (fi bindataFileInfo) Name() string { return fi.name } func (fi bindataFileInfo) Size() int64 { return fi.size } func (fi bindataFileInfo) Mode() os.FileMode { return fi.mode } func (fi bindataFileInfo) ModTime() time.Time { return fi.modTime } func (fi bindataFileInfo) IsDir() bool { return false } func (fi bindataFileInfo) Sys() interface{} { return nil } var _cssKeep = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x01\x00\x00\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00") func cssKeepBytes() ([]byte, error) { return bindataRead( _cssKeep, "css/.keep", ) } func cssKeep() (*asset, error) { bytes, err := cssKeepBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "css/.keep", size: 0, mode: os.FileMode(436), modTime: time.Unix(1492020681, 0)} a := &asset{bytes: bytes, info: info} return a, nil } var _cssApplicationCss = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x1c\x59\x8f\xe3\xb6\xf9\x3d\xbf\x42\xf5\x60\xb0\x3b\x0b\x49\x2b\xdf\xb3\x32\xd2\x26\xd9\x6c\xd0\x00\x49\x1f\xd2\xf6\x69\x31\x28\x28\x89\xb6\xd9\x91\x48\x81\xa4\x3c\x9e\x75\xfc\xdf\x0b\xea\x32\x45\x51\x12\xe5\x99\x04\x4d\xd1\x0c\x82\xb5\xc9\xef\xbe\xf4\xf1\x90\xdf\xbf\xfb\x93\x85\x09\x4d\x40\x8c\xbe\x40\x37\x64\xcc\x3a\xcc\x5d\xcf\x9d\x59\xbf\x5a\x3f\xff\xf8\x0f\xeb\x27\x14\x42\xcc\xa0\xf5\xab\xb5\x43\xdc\x45\xe4\x7d\x0d\x6b\xbd\x7b\xbf\xe7\x49\x7c\xda\x12\xcc\x9d\x2d\x48\x50\xfc\xec\x33\x80\x99\xc3\x20\x45\xdb\x8d\x93\x30\x87\xc3\x23\x77\x18\xfa\x02\x1d\x10\xfd\x3b\x63\xdc\x9f\x7a\xde\xed\xc6\x79\x82\xc1\x23\xe2\xfa\xd9\x73\x40\xa2\xe7\x53\x02\xe8\x0e\x61\xdf\x3b\x03\xca\x51\x18\x43\x1b\x30\x14\x41\x3b\x82\x1c\xa0\x98\xd9\x5b\xb4\x0b\x41\xca\x11\xc1\xe2\x63\x46\xa1\xbd\x25\x84\x43\x6a\xef\x21\x88\xc4\x3f\x3b\x4a\xb2\xd4\x4e\x00\xc2\x76\x02\x71\x66\x63\x70\xb0\x19\x0c\x73\x0c\x96\x25\x09\xa0\xcf\xa7\x08\xb1\x34\x06\xcf\x7e\x10\x93\xf0\xf1\x0c\xb2\x08\x11\x3b\x04\xf8\x00\x98\x9d\x52\xb2\xa3\x90\x31\xfb\x80\x22\x48\x6a\x48\x84\x63\x84\xa1\x93\x23\x6c\x0e\x50\x88\x06\x62\x07\xc4\x68\x87\xfd\x00\x30\x28\x66\x0b\x42\x3e\x26\xfc\xed\xe7\x90\x60\x4e\x49\xcc\x1e\xee\x6a\x12\x98\x60\xb8\xd9\x43\xb4\xdb\x73\xdf\x3b\x7f\xde\xa3\x28\x82\xf8\xc1\xe6\x30\x49\x63\xc0\x61\x03\xee\x0c\x4e\x01\x08\x1f\x85\x2e\x38\x72\x42\x12\x13\xea\x73\x0a\x30\x4b\x01\x85\x98\x9f\x81\x0f\x42\x8e\x0e\xd0\x06\xfe\x9e\x1c\x20\x3d\x91\x8c\x0b\x11\x84\xd9\x82\x80\x7e\xe6\x88\xc7\xf0\xe1\x14\x10\x1a\x41\xea\x04\x84\x73\x92\xf8\xd3\xf4\x68\x45\x84\x73\x18\x9d\x03\x9b\x71\x4a\xf0\xae\xf0\xe0\x53\x21\x54\x40\xe2\xe8\x1c\x6d\x71\x31\xc8\xf8\x73\x0c\x7d\xc4\x41\x8c\xc2\xf3\x7e\x5a\x0e\xa2\x2f\xd0\x9f\xc1\x64\x53\x79\xc9\x5d\xad\x61\x62\x79\xe7\x04\xd0\x47\x49\x64\xff\x66\xbb\xf5\x36\x85\xdc\x37\x9e\xe7\x9d\x59\x02\xe2\x58\xa2\x71\xef\xdd\x9e\x59\x16\xd8\x2c\x4b\xa5\xd1\xf5\xf2\x76\x93\xdb\xb9\x32\xd3\x26\x25\x0c\x09\xd7\xf9\x14\xc6\x40\x68\xdc\x69\x7c\x41\x89\x93\xd4\x77\x3c\x77\x09\x13\x41\xfc\x54\xea\xed\x78\xee\x4c\x0c\xa1\x64\x57\x5a\xc4\xf7\xce\xec\xb0\xcb\x3d\xe5\x53\x42\xf8\xdd\x49\x18\x71\x1b\x93\x27\xbf\x70\xcb\xb9\x88\xad\x2a\x18\xa7\x30\xb1\x16\x5e\x7a\x3c\xef\xe9\xc9\x49\xc8\x17\x27\x20\x47\x21\x31\xc2\x3b\x5f\x78\x1a\x62\x2e\x86\x36\x1d\xc3\xb5\xd3\x53\x0a\x2f\x9c\x40\xc6\xc9\x39\x24\x11\xb4\x1f\x83\xc8\x4e\x29\xb4\x19\x48\xd2\x46\x4e\x25\x04\x13\x96\x82\x10\xda\x56\xfd\x71\x73\x31\xd7\x14\x26\xe7\x20\xe3\x9c\x60\x1b\xe1\x34\xe3\x36\x49\x79\x11\xfe\x0c\xc6\x30\xe4\xb6\x48\x33\x40\x21\x38\x15\x9e\x40\x78\x0f\x29\xe2\x39\x85\xfa\x4b\x9d\x6f\x05\xa5\x8b\x7c\x07\xc4\x50\x10\xc3\x8a\x43\x41\xf2\x94\x67\x6e\x1e\x8a\x5b\x42\x93\x22\x58\x4b\x08\x51\x12\xac\x5c\x90\xcf\xfc\x39\x85\x5f\x4f\x8a\xf1\xc9\x83\x2d\x0f\x52\xc8\x20\x57\xc6\x58\x16\x24\x88\x4f\x1e\x4e\x55\x7d\x00\x69\x0a\x01\x05\x38\x84\x7e\x41\x64\x13\x66\x94\x11\xea\xa7\x04\x61\x0e\x69\xc9\xf2\x73\x84\x18\x08\x62\x18\x3d\xc8\xcc\xeb\xc1\x53\x89\x14\xc1\x2d\xc8\x62\x5e\x22\xf9\x7e\xee\xc2\x2d\x09\x33\xe6\x20\x8c\x21\x2d\x64\x69\x8f\xd7\xd1\xb2\x49\x41\x14\x09\xaf\x7a\xe7\x1c\xf4\x24\x07\x69\x51\x15\xcf\xb2\x3e\xe1\x1e\x86\x8f\x01\x39\xaa\xaa\x83\x08\x91\x89\x48\xcb\x3a\x4c\xea\x0c\x3d\xaa\x3c\x4a\x1c\x9c\x25\x01\xa4\x93\x07\xdf\xaf\x6c\x93\x8b\xe6\xb0\x14\x61\x47\x76\x7e\x27\x3c\xc9\x78\x13\xfe\x54\x0a\x9e\x07\x60\xc3\x0d\x10\xd0\x70\xaf\x77\x83\xf0\xfb\x16\xc1\x38\xda\xf4\x25\x40\x85\x38\x2a\x3f\xb4\x32\x5c\xe4\x2f\x46\x9c\x50\x88\x11\xeb\x54\xee\x44\x89\x60\x48\x28\x10\xe5\x43\xa7\x51\x1e\xba\xb9\x4a\x0c\xf2\xca\xd5\xa2\x46\x32\x12\xa3\xc8\xba\x09\x3d\xf1\x57\xe7\x87\x35\x4b\x25\x1f\xb9\xf3\xa5\xa8\x7b\xee\x6a\x56\xfc\xbb\x16\x05\x26\x86\x3b\x88\x23\x5d\xd4\xd4\x89\xd8\xcc\xfe\x2a\x5f\xdb\x65\x98\x8b\x08\xae\xea\x77\x48\xe2\x18\xa4\x0c\xfa\xd5\x87\x4d\x39\x21\x0a\x42\xc9\x20\xb2\xf9\xfe\x74\x61\xf8\x4d\x59\x46\x42\xd8\x28\x28\x6f\x7e\xc4\x21\xc1\x8c\xc4\x80\x83\x37\x1b\x46\x43\x3f\xa3\xf1\xdb\xc9\x7b\x01\xc3\xde\xa3\xcb\xa4\x23\xa4\x10\x46\x13\x33\x2e\x24\x7c\x72\x37\x0a\xfc\x2f\x37\x08\x6e\xd1\x71\x72\x67\x89\x32\x01\xf8\xdb\x09\x4c\x02\x18\x45\x30\x72\x48\x0a\xb1\x70\xdc\xe4\xce\x36\xa2\xf6\x44\xb6\x5b\x89\x4e\xf1\xd5\x0c\x95\x73\x19\x93\xd3\x0c\x8e\x61\xcc\x0e\xbb\x1b\x69\x52\xcc\x49\xd4\xd8\x61\x37\xb9\xdb\xc8\x8e\x5b\x7b\xde\x46\x7a\x74\x96\x75\xe1\xc5\x9e\xa0\x70\x97\xc5\x80\x8e\x70\x86\x06\xe3\x65\xfe\x50\x09\x8e\x73\x89\x8a\x3d\xda\x2b\x2a\x01\xc5\x31\xe5\x74\xaf\x6f\x16\xa3\x7c\xf3\x0b\x09\x08\x27\xd6\xdf\x63\x10\xb4\x7d\x43\xf3\x49\x16\x83\xc0\x24\x49\x7a\xa0\xc7\xfb\xa4\x8b\xd8\xb0\x3f\xba\x30\x8d\x7c\xd1\x85\x2c\xfc\x50\xcc\xfd\x4b\x4c\xbe\x72\x82\x14\x4e\xe8\xb2\xbf\xb9\xed\x5f\xcd\xee\xd7\xd9\xfc\x6a\x7b\x77\xd9\xfa\xf7\x35\xb3\x59\xf5\xe9\x06\xbe\xda\xd8\xe3\x6b\x4e\x07\xe2\x18\x93\xeb\x2a\x4d\x31\x75\x7d\x91\xc9\x57\xca\xda\x96\xef\xfc\xce\x7e\xe7\x07\x70\x4b\x28\xb4\xdf\xf9\x60\xcb\xf3\x96\xb3\x06\x2c\x3b\xf4\xa2\x3d\x6a\xb5\xf4\xd5\xb3\x7e\x95\x1e\xad\xa9\xe8\x4d\x5a\x0b\xc6\x9b\xed\x76\x2b\x8f\xa2\x04\xec\x8a\xb6\x67\xa3\xe9\x76\xc2\xb0\xea\x2a\x44\x9b\x9a\x31\x7f\x91\x96\x0d\xdb\x1e\x44\xe4\xc9\x47\x98\x41\x6e\x79\x96\xc0\x11\xff\xd3\x5d\x00\xde\x7a\x76\xfe\xe7\x7a\xeb\xe5\xdd\x26\x5f\x15\x14\xab\xb5\x4b\xe3\x42\xa8\x05\x01\x83\x0e\xc2\xa2\x11\xb5\xdc\xe9\x92\xd9\x17\xaa\xad\xb9\xb3\x1b\x70\x6c\xbb\xf0\x20\x7a\x43\x4e\x48\x6c\x95\x9f\x63\xc4\x38\xc4\x90\x5a\x65\x03\xe8\x86\x24\x49\x00\x8e\xfa\x80\x6a\x1b\x4d\x3d\x21\xf4\x32\x3d\xca\x8b\x27\xf1\x55\xee\xe3\x67\x5e\xae\xb0\x6c\x02\x01\xa2\xdd\x01\xa8\x5b\xbc\x7c\x39\x74\xe9\x33\x8b\xa6\x52\xe8\x50\xac\xcb\x0d\x34\xa9\x00\x0d\xf4\x29\xd7\xfa\xca\x52\x48\x70\x73\x02\xb4\xbb\x68\xbb\x4c\x8f\xd6\xdc\xeb\xd7\x36\x1f\x68\x69\x5b\x10\xcb\x23\xfe\xd5\x9c\xa0\x0f\xc6\x72\x74\xfa\xf1\xbb\xef\xbe\xbf\xdf\xc8\xf1\x52\x80\x2a\xeb\xcc\x2c\x4d\x21\x0d\x01\x83\x92\x84\xbf\x9d\x89\x6d\x89\x49\xbe\x1e\x34\x61\x52\x02\x9a\x30\x29\x41\x2f\x4c\xca\xdd\x1c\x03\x2e\x15\xa4\x09\x9b\x0a\xb6\xe6\xe3\x1a\xf3\x71\x47\xf0\x29\x61\x07\x1c\xbd\xfa\xb0\x00\x81\xe2\x68\xe8\x89\xbf\xf3\xff\x9a\x21\xb4\x35\x57\xd2\xd2\xad\x76\x28\x4c\xf8\x5f\x60\x4d\x24\xb8\x40\xb7\xb9\x19\xe7\x4b\x0b\x63\x0c\xe7\x56\x06\x5d\x66\x4c\x53\xa9\x85\x31\x8a\xbf\x9a\x5c\x97\x19\x73\xa7\xb7\x50\x46\x49\xd0\x0e\xb7\x6a\x6a\x44\xdc\xb5\x50\xc6\x88\xe0\xb6\x44\x90\xb6\xca\x86\x99\xcb\xc0\x06\x6c\x65\x70\x0d\x43\xe3\xb8\x6b\xa3\x8c\x62\xde\x8a\x3c\x69\xca\x34\xf4\xda\x28\xe3\x44\x50\x83\x4f\x9a\x32\x76\xbd\x06\x67\x9c\x10\x3d\xce\x37\x0f\x40\x0d\xce\x28\x29\x2a\xac\x6a\x87\xed\x32\x63\x49\x4d\x86\x6e\xd6\xa0\xef\xe8\x01\xd1\x50\x2c\xb1\x74\xbc\x0c\x54\x1a\xd0\x7b\x1c\x3f\xb5\x79\xb9\x4a\x7f\x83\x84\xea\x94\xaa\x87\xef\x88\xf6\xe8\x3a\x8b\xf4\xf0\x56\xfb\xad\xeb\xec\x32\x9c\xe5\xdd\xb2\x75\xf3\x1d\xd1\xd1\x5d\x69\x97\x6e\xde\xad\xce\xe8\x3a\xc3\x18\x64\x7d\xb7\x74\x3d\x9c\xc7\x34\x5f\x57\xda\xc6\xa4\x8c\xf4\xd5\x1a\xf3\x0e\xef\x1a\xe3\xf4\x71\x36\xef\x18\xaf\x35\x8e\xa6\xe1\x1c\x58\x57\x95\x5d\x68\x86\xcb\xa7\x03\x64\x90\xf7\x37\xee\x1f\xe7\xab\xe9\xe2\x8a\x15\x5a\xd6\x5c\x4b\x65\xcd\x55\x4f\xa6\x34\xe5\x19\x6e\xb6\x2c\x42\xae\x06\x7e\x3e\x20\x53\xc8\x07\x5a\x38\x46\x6b\x11\x30\x5f\x84\xf3\x65\xdf\x5a\xc4\x48\xbc\x4e\xe6\x7d\xfd\x7f\xd6\xea\xd1\xb3\x8e\xde\x39\xeb\xe8\x69\xb3\xae\x4e\x33\xeb\xea\xff\xb2\x76\x87\x96\x75\xf5\x4d\x59\x57\x37\x93\x75\x76\x18\xd9\x98\xa7\x7e\xd6\xf3\x5c\xcc\x06\x9f\x10\xd9\x60\xad\xcc\x86\x2b\x86\xce\x99\xaa\x53\x1a\x63\xad\x40\xd4\x3b\xa6\x39\xd3\xcd\xa2\xcd\xbd\xe5\x9e\xe6\x60\x8b\x7f\x87\x8b\x94\xa9\x1e\x36\x83\x6e\x12\xe0\xfd\xb3\x43\xae\x92\x12\xb6\x1f\xc6\x44\x94\xee\x42\xd7\x55\x9e\x8a\x74\x8b\xe0\x01\x85\xa5\x09\x18\x18\xaa\x0b\x8b\xfb\x8f\xdf\x7e\xfb\x71\x74\xa9\x2b\x98\xc8\x4e\x2a\x47\x24\xdf\x94\x23\xb2\x4b\x8a\xa1\x46\x30\x08\x11\x65\x3a\xf9\x77\x89\x4a\xfe\x5d\x45\x30\x2a\x79\xf3\x19\x88\x3e\x4c\x7b\x4a\xde\x08\x01\xbb\x04\xe8\x29\x7b\x25\xa9\x66\x92\x29\x83\x6d\x03\x6a\xd3\x4c\x9d\xd2\x48\xac\x4d\xb4\x62\x4e\xcd\x34\x75\xb4\x2d\x84\x3e\xd7\x5a\x73\x7d\xac\x86\xb2\xad\x8c\xd2\xfe\xe9\x81\x7c\x6b\x84\xdc\x00\x90\x91\x38\x2d\xbf\x2b\xde\x6b\x0c\xa9\x41\xab\xf5\x5c\x73\xa2\x93\x7c\x8b\xb1\xea\xb3\xe6\x98\xca\x5a\xef\x2f\x65\xa6\x9b\xc5\x90\xaf\x04\x74\xef\xe4\x80\x9f\xa4\x94\xee\x05\x31\x10\xa3\xbb\x28\x76\x15\xb2\x22\x19\x43\x82\x31\x0c\x07\xda\xbe\xef\x3f\x7d\x5c\xaf\xe6\xa3\x6b\x61\x49\x5b\x76\x4a\x35\x24\x79\xa3\x1a\x92\xdd\x50\x8e\x19\x55\xb3\x68\x19\xdc\xcf\x3f\xf4\x54\x33\x03\x06\x3d\xd5\xaa\x82\x6c\x06\xbc\x3a\xaa\xd1\x51\x1b\xf6\xad\x39\x9d\x50\xda\xe0\x2f\x27\xd5\xf8\x6f\x0d\x6b\x24\xd1\x67\x41\x7b\xb2\x97\xdd\x50\x2e\x94\x08\x43\xf3\x03\x19\xd1\x8c\x8f\x21\x28\x33\x91\xba\x53\xa3\x2b\xae\x8b\xcb\xc7\xf2\x0d\xd6\x4f\x3f\x7c\xfa\xf4\xc3\x62\x23\x1f\x96\x4f\x8a\xc3\xf2\x89\x6d\x4d\xfe\x0a\xe3\x03\xe4\x28\x04\xd6\xdf\x60\x06\x27\xb6\x55\x0f\xd8\xd6\xb7\x14\x81\xd8\xb6\xa4\x1b\xd1\x55\x5e\x2e\x16\xe7\x9b\x98\x80\x08\xe1\xdd\x29\x01\x47\xe7\x09\x45\x7c\xef\x7f\x58\xad\xd2\x63\x79\xd1\xcc\x89\xe1\xb6\xb8\x9a\x57\x0d\xd0\xfa\xb2\x5e\x91\x7b\xc5\xbd\xd7\x10\xe6\x87\x7f\x15\x35\xbf\x3c\x3e\x0e\x63\x08\xa8\x1f\x10\xbe\xdf\x94\x37\xec\xfc\xc9\xa4\x3e\xc3\xcc\x6f\x95\x9d\x6f\x30\xe1\xce\x56\x28\xf9\x4a\x32\xd4\xf4\xc6\x48\xe1\x52\xf2\xa4\xdc\x18\xde\x6e\xe4\x23\xcc\x8a\x37\x27\x69\x7e\x80\x7b\x76\x05\x2d\x80\x30\xa4\x57\xc8\x2d\x61\x8f\x91\x52\x7f\xf6\xae\x3d\x13\x6e\x9c\xae\xba\x8b\xd9\xfd\x72\x5d\xdd\xfc\x5d\x68\x0e\x63\x2f\x21\x51\x6b\x7d\x5f\x1f\xe5\x8f\x39\x76\x57\xef\x63\x4a\x57\x4a\x35\xd7\x31\xa5\x59\xfd\x9d\x84\xe2\x2e\x6c\x91\x8c\x85\xde\xe5\x97\x4a\xfb\xe2\xeb\xa9\x99\x41\xe5\x7e\xc3\xe5\x1a\x7a\x75\x9b\xb8\x1c\x90\xee\x09\x77\xdd\xbf\x6d\xde\x0f\x1e\x80\xaa\xae\x16\x0f\x80\x55\x17\x8b\x07\xc0\xb6\x28\x86\x93\x87\x3f\x9b\x31\xd0\xea\x94\xcf\x1b\x6a\x66\x02\x5b\xb3\x37\x01\xae\xb5\x34\x01\xee\xd3\xb5\x03\xbf\xa9\x71\x9e\x18\x16\xdf\x6b\xde\x2e\x90\xee\x92\xc8\xd9\x30\x5f\xa4\xc7\x0a\x2d\x6a\xdc\x3e\x92\x2e\x41\xda\x97\x1b\xee\x55\x3e\xcc\x45\xd2\x17\xdd\xa8\x53\x6e\x90\x29\x7b\xac\x57\x15\x02\x85\x62\x59\x0e\x9a\x84\x47\x55\x32\x85\x60\x73\xe7\xcf\x6e\x4f\x5f\x36\x1a\xd5\x8d\xbf\x26\xa2\x6e\x53\x30\xd7\x7a\x1b\x13\xc0\x7d\xa1\xe4\xa6\xf1\x2a\x4b\x53\xdb\x99\x3b\x5f\xae\x57\xcb\xdb\x4d\x61\xa0\xc5\xbd\x7b\x3f\x9b\x4e\xd7\xb7\x03\x02\xfb\x31\x60\xdc\x09\xf7\x28\x8e\x7a\x65\x6f\xc0\x75\xab\xd1\x03\xa6\xa5\x75\x6a\xe8\xe0\x9d\xbf\x49\x60\x84\x80\xc5\x42\x0a\x21\xb6\x00\x8e\xac\xb7\x17\xa7\x5b\xeb\xd5\x7d\x7a\xbc\x3b\xfd\x41\x5c\x90\xbf\xe5\xf4\x87\xb2\xbe\x46\x5a\xd1\xf6\xab\xb4\xc4\xd8\xa9\xdd\x19\xb4\x91\xeb\xdd\xe7\x26\x7e\x39\x7c\x65\x60\x7b\xee\xec\xc3\x74\xbe\xbe\xdd\x14\xe8\xf9\x0d\x37\xdd\x23\xba\x5b\x9e\x1e\x33\xb5\x21\x54\x1b\xb5\xa9\x56\x3b\xf7\xcc\xa9\x9b\x0e\x95\xac\x06\xe4\x85\x69\xdd\x84\xf2\xf4\x17\xd7\x4a\x98\xb2\x66\xcf\x3d\x4d\x85\xd5\xca\xd6\x63\xa0\x7e\xe8\xab\x8c\x25\x0d\x1a\x70\x93\x06\x4f\xbd\x79\x96\x47\xbc\xfe\x94\x6e\x00\x93\xc2\x84\xb4\x8f\x69\x8a\xd1\x1a\xf3\xb6\xd1\xb1\xce\xd2\xe3\x6f\x5e\xbb\xfe\x9b\xaa\x50\xab\x72\x60\x70\x68\xf4\xf7\x9e\xe7\x55\xfd\xf0\xda\xbb\x3c\xaa\xcb\x50\x9c\x89\x50\xc4\xe0\x60\xb9\x31\xd9\x75\xbc\x77\x59\xbd\x8d\xb7\x2c\x6f\x73\x5a\x9e\xe5\x95\x38\x08\x3f\xb2\xd2\x1a\xb9\x00\x0d\x57\x2c\x6b\xd2\x02\xcc\x02\x27\x75\x3b\x43\xb9\xc0\xa9\x4f\x9d\x97\x5e\x26\x9d\x29\x52\x54\xb7\x39\x1b\x0d\xb4\xf6\x3e\xa9\x84\xd5\x5e\xd8\x56\xa8\x1a\xa8\x26\x87\x7c\xff\x27\x3f\x2e\x75\x10\xde\x92\xab\x5a\xa7\x0b\xfa\x98\x06\xc9\x2c\x0d\x24\xd1\xda\x4f\x12\x99\xb5\xe5\x56\x2f\x03\x37\x06\x43\x92\xa4\x04\x8b\x5c\x16\x9f\xf3\x6d\x00\x44\xb0\xe5\x62\x90\x14\x99\xab\x9d\x95\x29\x08\xc8\x46\x10\xc9\x1e\x5d\xcc\x8d\x13\xfa\xf7\x15\xf5\x8a\xec\x57\x72\xcf\xc9\x33\x44\x27\x76\xa3\x0e\x98\x6a\xa0\x3e\x2b\x8c\x94\xe9\xed\x41\x34\x92\x59\x6e\x90\xc5\x31\xe4\xce\x85\xe8\x08\x23\xeb\xb1\x4d\x65\x1d\xe6\xad\x0a\x59\x94\xd0\x6b\x04\xac\x31\x47\x0b\x57\x62\x2a\x05\x46\xce\xf2\xa5\xf7\x92\x90\xfe\xbf\x07\x4c\x3d\x20\xdb\x3c\x7f\xce\xe9\x23\xba\x78\x25\x7f\x84\x84\x15\x82\xb1\x60\xe5\x4b\xff\xd2\xd6\x53\xb3\x52\x78\x6a\x19\xc8\xcb\x8c\x2a\xbe\xfa\x2e\xb6\x2a\xb0\xbc\xaa\x36\xdd\x0a\x6c\x13\xa8\x5e\x1f\x68\x56\x36\xf5\x45\xd9\xd6\x73\x5e\x4f\xeb\xca\x3d\x8b\x5e\x62\xa3\x77\x32\xc2\x34\x4d\x1d\x44\x9c\xd2\xdf\xd7\x6c\xbe\xb6\xb4\x55\x68\x8e\xb2\xba\x82\x6b\x71\x7a\x6a\x3e\x17\x44\xa7\x53\xa9\x50\x2f\x19\x34\x5c\x2d\xf7\x11\x3e\xb7\xde\x61\x96\x77\x8a\x8b\xc7\x69\x45\xaa\x50\x28\xa7\xfe\xb4\x47\x1c\xe6\xef\x31\x43\x1f\x93\x27\x0a\x52\x0d\xf5\x03\x88\x33\x68\x45\xe8\xa0\x6f\x0b\xeb\x77\xaa\x59\x48\x49\x1c\x6f\x9a\x3e\x9e\x5d\x7c\x1c\x45\x91\x86\x61\xb5\x13\x7b\x7f\x7f\x7f\x96\x52\xe9\xca\x3d\xe6\x0a\x7d\x9c\x27\xa4\x04\xae\xae\x2c\xe8\x93\x5a\x79\x36\x36\x36\xcc\x2d\xd3\xcd\x92\x11\xec\x34\x6b\xfa\x36\x76\xbe\x48\xb6\xb5\x13\x2f\xbb\xcb\xab\x23\x29\x5d\xca\x6d\x71\x7b\xf9\x6d\x5e\x53\x8e\x72\x99\x6d\x29\x2f\x4f\xbe\xa2\x01\x24\xb2\x43\x22\xbd\xb2\x21\x5a\x9c\x4f\x8d\x00\xbe\xfc\x46\x82\xc8\x02\x6b\x5a\x3c\xe2\x74\x0e\xea\x6f\x70\xf3\xa7\x4d\xf3\xe1\xd2\xbb\x8b\x71\x79\x22\xb5\x7e\x3f\xe1\xda\x44\x30\x12\x51\x66\xdf\xad\x6b\xdd\xf9\xeb\x23\xd5\xb4\xeb\x37\x93\x4b\xcb\xac\x25\xb8\x99\x31\x1b\x0d\xa3\x4e\xb7\x4e\x36\xec\x75\xb7\xb0\xb4\xbc\x0d\x56\x17\xac\x6f\xff\xa9\xd7\x40\x72\x1c\x95\xaf\xef\xca\xe9\xb9\x9f\x29\x59\xb3\x9f\xe9\x2a\xa4\x9c\xd0\x29\xa0\x20\x61\x96\x9b\x9f\xb7\x58\xfe\x16\xd1\xae\x7d\xb4\x6e\xc8\x66\xc0\xf5\xd0\xef\x25\x29\x3d\x8a\xb4\x24\x4a\x0a\x9a\x99\xf2\xf8\x53\x4f\xbc\x8f\x71\xf9\x9b\x41\x57\x05\xc5\x6c\xed\x2e\x3e\xac\x56\xab\x5b\xa5\x04\x6c\x24\x6a\xd5\x86\x90\x97\x1e\xad\x99\xeb\xdd\xcf\xf3\xff\x6e\xbb\xd5\x6b\x04\x4f\xa7\xa6\x3d\x9b\x9d\x9d\xc4\x7a\xf4\xef\x8b\xc6\xee\xda\xdf\x5f\x9f\x5f\x7c\x04\xd4\xcd\x78\xf0\xc8\x40\x03\x38\x42\x2f\x5d\x9c\x5d\xf3\x80\xd2\xc6\x9d\xfe\x0d\xe4\xdf\xce\x56\x03\x51\xa5\x7f\x21\xc2\xd4\xbe\x83\x51\x36\x44\xbe\xcf\x2b\xd2\xf9\xef\x1b\x51\xc2\xde\xa8\xaf\xfa\xb5\x01\xae\xb3\xe3\x7c\xea\xae\x57\xd3\xa5\x62\xc7\x36\xf5\x6e\x3d\x7b\x61\x7b\x23\xaf\x22\xc3\x38\xe0\xad\xdd\xfb\xc6\xe4\x4b\x76\xd2\x3b\x39\x1a\x9c\xd1\xa9\x70\xfd\xea\xc4\x84\xb5\xd5\x10\x83\xd7\x89\xbf\x72\xa7\xeb\xd9\x54\xf9\xcd\x3d\xb1\xf0\x6d\x1d\x64\xb4\xc5\xe8\xd3\x4d\x99\x1f\xd6\x49\xff\x5a\x99\x34\x55\xef\x61\x7b\x9e\xba\xfb\xf0\xd5\xfb\x77\x37\x16\x23\x19\x0d\xe1\xcf\x20\x4d\x11\xde\xfd\xf3\x97\x9f\xbe\x06\x69\x1a\xa3\x30\xdf\x43\x77\x43\xc6\xdc\x04\xa4\xd6\xbb\xf7\x5f\xfd\x27\x00\x00\xff\xff\x7c\x22\x8a\xed\xf2\x52\x00\x00") func cssApplicationCssBytes() ([]byte, error) { return bindataRead( _cssApplicationCss, "css/application.css", ) } func cssApplicationCss() (*asset, error) { bytes, err := cssApplicationCssBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "css/application.css", size: 21234, mode: os.FileMode(436), modTime: time.Unix(1492020681, 0)} a := &asset{bytes: bytes, info: info} return a, nil } var _cssApplicationCssMap = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xcc\x59\x5b\x77\xda\x3e\x12\x7f\xef\xa7\xe8\xe1\x35\xea\x9f\x24\x24\x24\xe9\xdb\xcc\xd8\x38\x6e\x9a\x82\x4b\x68\x2e\x7b\xf6\xf4\x70\x0b\x18\x8c\x4d\x6c\x73\xdd\xb3\xdf\x7d\x8f\x6c\xc9\x12\xc8\xa5\xf9\x6f\x9a\x3d\xfb\x06\xd2\x48\x33\xf3\x9b\xbb\xfc\xaf\x0f\x95\xe5\x30\x4e\xfc\x28\xac\x7c\xfe\x58\x63\x1f\x2a\xb3\xee\x7c\xee\x87\xa3\xa4\xf2\xf9\x63\x05\x00\x80\x9d\x59\x00\x67\x16\x03\xf0\xce\x2d\xe6\x02\xdc\x30\x02\xba\x66\xf7\x00\xf7\x8c\x00\x6c\xd6\x01\xe8\xf0\xb5\x25\xb2\x08\x01\x22\xcc\x97\x5d\x00\x97\x2f\x9f\x20\x5b\x21\xc0\x6a\x77\xb9\x39\x26\xed\xb2\x5b\x80\xdb\x7c\x9b\x00\x88\x11\x74\x1f\xd8\x71\x03\x1e\x3d\xbe\xfd\x8d\x35\x01\x9a\xf9\xf6\x4d\x7e\xc4\x1b\x23\x3b\x45\x70\xf8\x21\xfa\xa2\xed\x3f\x02\x3c\xf2\xb5\x18\x59\x1f\xa0\x9f\x2f\x7a\x00\xfc\x22\xef\x04\xd9\x0b\x02\x24\x5c\x12\x9a\xa3\x76\x4c\xca\xda\x33\x25\xf1\x1e\x98\x8f\x40\x6d\xbe\xdd\x32\x8f\x74\x9e\x25\x35\x01\x1b\x21\xc0\x48\xe8\x29\xf0\x69\x56\x91\x2f\x93\xa1\x89\xb8\xbe\xf3\xc4\x29\x33\x99\x7f\xb0\x2e\x40\x77\x07\xd3\x66\x0d\x99\x07\xc4\x8f\xd0\x57\x0d\x72\x09\x62\x88\xcc\x11\xa2\x37\xe4\x19\xb0\xa5\x12\xde\x1c\x99\x0d\xe0\xf0\x6d\x8b\xb5\x01\xda\xf9\xb6\x23\xd6\x06\x9a\xb6\x02\xa3\x66\x80\x9a\x59\xd4\x8d\x12\xa0\x31\x4a\x13\x68\x52\xf4\xf8\x9a\x30\x85\xc1\xa5\x39\xe6\x40\x93\x90\xb1\x4c\x08\xa5\x96\xc0\x84\x06\x52\x1c\x25\x18\x05\x25\x16\x75\x4e\x74\xfd\xc5\x8d\x4a\x7f\xa7\xa7\xed\x2a\x55\x85\x0d\x3a\x13\x2c\xdd\x16\x42\x34\x1f\x38\xbf\x61\xee\x15\x4a\x1c\x41\xd7\x09\x90\xff\x14\x86\x29\x85\x51\x21\x3f\xcc\xef\x51\x4e\x41\xe7\xa8\x61\x2b\x17\x97\x58\x2a\x85\x92\x51\x49\x51\x04\x11\x72\xe7\x74\x8c\x90\x2c\xe2\x90\x26\x64\x62\x3e\xc5\x31\xb2\x17\x02\x57\x38\xb5\xb2\xa8\x80\x86\x06\x92\x83\xb6\x56\x12\x1b\xcd\x07\x0d\x04\x25\x9d\x04\x38\x44\xd6\x2d\x9c\x57\x19\x4f\x5c\x7d\x9f\x22\xdb\xd8\xe0\xbc\x64\x72\x86\xc8\xa6\x08\x30\xc5\x1d\x98\x79\xf2\x30\x0c\xd7\x9c\x64\xd2\x53\x71\xb0\x94\x62\x64\x01\x65\x39\x87\xd2\x12\x5c\xe9\xce\x0c\x45\xef\x49\xf3\x63\x85\xa5\x38\x7b\x1f\x23\x3b\x26\xa0\x1c\xd6\x40\x37\xa0\x4c\x80\x29\x9a\x97\xb6\x9f\xd8\x51\x03\x68\x64\x71\x82\x2b\xd2\x24\x11\x30\xb4\x07\x99\xb5\x4a\x51\x10\x96\xa3\x0b\x2c\xf7\x21\x9d\x56\x2e\x57\x4b\x5c\xab\xbd\x45\x36\x75\x34\x29\xf4\x83\xd2\x97\x4e\x78\xaa\x01\xe1\x12\x4a\x4c\x1f\x01\xfc\x4c\xb8\xad\x8e\xa3\xf0\x19\xea\x69\x2a\xbf\x48\x3d\xbc\x31\x95\x46\xc7\x01\xf0\x9b\x4f\x1a\x77\xc3\xd1\x79\xbe\x57\xdb\x46\x1e\xe4\x9e\xa6\x4c\xa7\xa0\x92\xb9\x63\xab\xe7\x0e\xc1\xd0\xc9\xce\x90\x08\xd1\x7d\x79\x68\xdb\x7d\x62\x1d\xe8\x70\xca\x3b\x47\xe3\x28\x52\x34\xe5\x99\x47\xe4\x9b\x63\x02\x38\xce\x34\xab\x92\xb6\x7c\xe4\x81\xb3\xca\x4a\xc3\x85\xad\x5d\x21\x33\xdf\x18\xcd\x94\xed\xa6\xf8\x7a\xb6\x75\x02\xa8\x67\x6c\x03\x4b\x5b\xbe\xfc\x0e\xce\x65\xc6\x36\x6c\xbc\x07\xdb\x0d\x01\x6c\x48\x78\x92\x5a\x3e\xf5\xc0\x59\x64\x6c\xcf\xdf\xaa\xad\xb4\x5b\xac\xb3\x7d\x21\x80\x97\x8c\xed\x89\xce\x36\x69\x81\x73\x99\xf9\x75\xf8\x2e\x6c\x57\x04\xb0\xca\xd8\x5e\xe8\x6c\x5f\x3c\x70\xa2\x4c\xdb\xed\x2b\xd9\x52\x6c\xcd\xcb\x8b\xab\xf8\xc5\xc5\x9a\x22\xd8\xa2\x55\x50\xfb\xb9\x73\x52\x1d\xb7\x79\x03\x93\x99\xe4\x41\xf3\x59\x29\xf8\x04\x77\x5a\x10\x59\xb4\xd3\x5f\x2e\xab\xd0\x14\xf1\xc1\x17\x55\x17\x22\xb5\xd9\xc9\x76\x3e\x01\x8c\x32\x40\xce\x49\x5b\xde\x58\x00\x1b\x8b\x11\x55\x69\x69\xb3\x33\x3b\xd3\xd3\x9a\xd2\xb5\x26\x67\x5b\x5a\xf0\x4a\x56\x25\x0a\x78\x92\xce\x25\xb2\x66\x14\x93\xc0\x92\x42\x3a\x2b\xd6\x23\xaa\x91\x90\x8a\xe6\x34\x22\x85\xb2\x55\xde\xfa\x95\x65\x1c\x95\x15\x84\xfe\x76\x8c\xec\xb2\x21\x90\xfb\x66\x16\x11\x37\x94\x39\xc7\x5a\x60\xeb\xb0\x16\x4b\x54\x5a\xac\x50\x69\xb1\x46\xa5\xc5\x06\x95\x16\x5b\x54\x5a\x38\x81\xc5\xa6\x8d\x8c\xde\x1a\xdc\x89\xc4\x6a\x6f\x68\x26\x4f\x36\xd6\x3c\xd7\x4b\x0b\xda\x89\xe5\x71\x61\x3c\x46\x8d\xd8\x1a\x93\xd0\xdb\x5e\xd0\xa3\xe4\xb4\xc5\x73\x3d\xe1\xe5\x32\x5a\x4f\x5b\x64\x9b\x27\x70\x76\x8a\xbe\xed\x93\x5f\xf0\x19\xf3\x38\xd7\x3d\xa5\x29\xda\x76\x4a\x25\x1b\xb1\x9a\x15\x41\x67\x4d\xec\xe8\xb6\x68\x8d\x4b\x5c\xec\x36\x45\x76\x1c\x34\x8a\x46\xa3\xd0\xa1\x8e\xae\xd4\xe1\x1c\xd7\x28\x75\xe8\xbb\x52\x85\x14\xaf\x90\xcd\x44\x3d\xb1\x42\x0c\x65\xdf\x69\x9f\x6a\xc0\x9c\xec\x00\x73\x4a\x9e\xb0\x52\xe3\x84\x97\x41\x71\xe9\x46\x01\x93\x96\x02\x33\xe1\x71\x35\x73\xf7\x91\x99\x69\xc8\x04\x7f\x1f\x99\x99\xfd\x3b\x64\x66\xc7\x68\x22\x33\xcd\x91\xe1\x4a\x4c\x70\x59\x28\x31\xc2\x02\x9a\x90\x43\xc3\xd3\xc0\x82\x43\xb3\xc6\xb8\x80\xa6\xae\x41\x73\xbe\x03\x4d\x5d\x41\x73\xae\x41\x73\xaa\xa0\x09\x4b\xa1\x49\x39\x34\xa7\x06\x34\x2f\x1a\x34\xf3\xbf\x0f\xcd\xe2\xb7\xd0\xf8\xa7\x25\xd0\x44\x0a\x9a\x50\x83\x66\xaa\xa0\x19\x73\x68\x1e\xb3\x10\xb3\x2e\xf0\x41\x8a\x7b\xa4\xe1\x72\xb5\x83\xcb\x91\xc2\xe5\x4a\xc3\xa5\xae\x70\x19\x97\xe2\x52\xe3\xb8\xd4\xed\x7d\x5c\x16\x1a\x2e\xe9\x7f\x81\x0b\xfd\x0e\x97\xcb\xbe\x09\x4b\xa2\x60\x89\x35\x58\xa2\x02\x16\x1a\x5b\x57\x66\xe1\xb1\x16\xf8\x28\x62\x90\xb2\x68\x53\x45\x6c\x65\x01\xac\xb2\x92\x1a\xcb\x46\xcf\x4a\x30\x57\x8d\x93\x87\x38\x26\x91\x1a\xe9\x18\x5b\x02\x94\xc6\x16\xbb\x45\x90\x72\x7c\xee\x8b\x11\x42\x56\x9c\x1f\x5c\xb8\x9d\xe1\xd1\xaa\x61\xcf\xa8\x94\xf6\x7d\x90\x35\xbc\xc6\x78\x22\xef\xd1\x6b\x9f\x2d\xa6\xef\x07\xe3\x95\xa0\xf1\x90\xd7\x2d\x9e\x88\x5f\xf0\xee\x4d\x62\xa6\x65\x62\xde\x06\xd9\xf8\xf5\x66\x39\xbf\x05\x58\x1c\x69\x94\x0f\xdd\x65\x4f\x15\x06\xa1\xa3\xf4\xed\xbc\x49\x5d\x1a\x63\xef\x8f\x68\xe6\x06\x79\xaa\x2a\x06\xb1\xd2\x72\x9d\x7b\x9e\x05\xf7\x7c\x9b\x4b\xcf\xa7\x56\x63\x50\xa2\x27\x19\x7d\xd7\x5d\x29\xa7\x7b\x22\x93\x9f\xf5\x4d\xf9\x67\xf3\x0a\xcd\xe6\xc8\x9e\x94\x36\x31\xf6\x39\x69\xad\x81\x9c\xe4\x6a\xbb\xb3\x95\x5c\xbe\x32\xa7\xbe\xeb\x7e\x8a\x3c\x70\x65\x1b\x21\xa2\xcf\xe9\xc8\xfa\xd6\xb8\x32\xa7\x42\xa7\x37\xd0\xe6\x23\xc3\xb6\xce\x33\x4b\x6e\xc1\x3d\xcb\x42\xf0\xc4\x2a\x25\x88\x9a\xe0\x4e\x33\xd8\xc7\xb6\x49\xe0\x66\x4f\x16\x62\xb6\x51\xfd\x9c\x6c\xf2\x2e\xd0\x9c\xa1\x9c\xbc\xdd\x11\x67\x84\x49\xe6\xd4\x2e\x9e\xcc\xe8\x85\x37\xde\x8a\x55\xde\xbe\x38\xb1\x3d\x46\x76\x89\x39\x9c\x8d\x11\xc7\xe8\xad\x9e\x77\x46\x6f\xf6\x3c\x9e\xa3\x90\xf9\xd7\x00\xc7\x5c\xf4\x4b\x6b\xbd\xf7\x70\x95\x3d\x02\x3a\x35\x34\xdf\x16\x87\x03\x2e\x95\x7c\xc5\xf4\x00\x8e\x32\xe7\x8d\x2d\xed\x82\x36\xc0\x22\xf3\x9e\x2b\x62\xf5\x2f\x45\x47\xae\x9d\x13\x63\xa4\x55\x43\x16\x51\x5e\xab\x1b\x61\x63\xfb\x8e\x32\xb9\xaf\x93\xc9\xb6\xce\xed\x8b\xec\x29\x43\xce\xcb\xc6\x7c\xe4\xcc\xb3\xe7\x93\x2c\xbf\x4f\xad\xd6\x3b\x00\x67\x85\xf6\xd8\xfa\x8d\x71\xf3\x48\xa2\xc8\x0e\x91\x25\xf6\xaf\x31\xb6\x02\xae\xcf\xca\xce\x7b\x45\x3a\xa3\xf0\x3d\x4c\x6d\x5f\xe0\x15\x99\xcc\xaf\xab\xdc\xb3\x4b\xb3\x9a\x0a\x3b\xe1\xda\x75\x6b\x92\x4f\x1c\xbf\xd4\xe4\x82\xbb\xcb\x65\x43\xbc\xe4\xdc\x99\x00\xb9\xcf\xec\x52\xe5\x1a\x63\xdb\xe9\x95\x6f\xcb\x79\xe9\x87\x51\x33\x6c\xdf\x1a\x6b\x1e\x5a\xa3\x25\xb2\x53\x0b\xe0\x94\x43\x99\x60\xed\xdd\x3c\xd4\xff\x35\x0e\xb6\xb3\x6c\x54\xcd\x87\xed\xef\xb2\xeb\xf4\x18\x79\x73\x0a\xcb\x4b\xc4\x3e\xea\xc0\xdd\xa7\x5d\xf8\xfa\x6f\xc6\x45\x71\xda\x59\x66\x89\x5e\xe4\x67\xa5\x80\x7c\xf4\x7a\x2a\x2f\xd2\x8f\x20\x3f\x04\xe4\x84\xdf\x13\x9c\xca\xca\xee\xc5\x1c\x4c\x63\x08\xe5\xec\xf7\x65\xfa\x31\xdd\xf5\x29\x73\xde\xec\x04\x6a\xae\xfc\x31\xc3\xad\x9c\x37\x3b\x21\x9f\x2b\xc5\x7a\x84\x55\x39\x6f\x76\xe6\x18\x15\xf3\x26\x8f\x3c\x5e\xdc\x76\xbc\xe4\x7b\x44\x5d\x51\xb1\xbc\x90\x77\xae\x86\xa4\xee\x16\xf5\x63\xc2\x26\x97\x28\x0b\x9d\x77\xc1\x3b\xe5\x95\x71\xb1\x37\x92\x92\xb6\xe7\xbc\xae\xe7\x5f\x3b\x5a\x23\xfa\xf1\xe6\x3a\x31\x7d\x7b\x87\xe2\x8c\xec\x41\xe1\xfe\x4e\xda\xa8\xa1\xfc\x1c\xe3\x7e\xdf\x4f\x8c\x76\x96\x18\x57\x4e\x09\x53\xe5\x18\xfb\x75\xf5\xba\xce\x1b\x8f\x82\x43\xd5\xde\x16\x57\x7c\x39\xfe\xb3\xb9\x55\x84\x97\xbb\xe4\xf1\xa5\xe2\x20\x27\xf8\xb2\xb1\xe7\xc8\x36\xee\xaf\xa3\xce\x5d\xda\x35\x64\xf5\x3b\xe9\x6d\x21\x89\xa3\x77\x0b\x1a\x0a\x23\xb7\x53\x3e\x3e\x19\x3a\x66\x39\x5a\xa1\x68\x2f\xb5\x7b\x6e\x26\xb4\x7f\xc0\x06\x37\x46\x56\xbf\xde\x8b\xb0\x3b\xab\x2b\xc2\xbb\x6d\x9f\xa0\x36\x23\x49\x0f\x4c\xf3\x76\xdb\x78\xa1\x97\x26\x9f\x98\x9f\x02\xbe\x0d\x26\xc8\xce\xde\xee\x27\xb7\x3e\x0e\xb2\x7b\x8c\x9e\x4d\x9a\x7e\x50\x2e\x90\x91\x28\x5c\xd1\x2e\xfd\xed\xe6\x4c\x3b\x94\xef\xdf\xcd\xf1\xa6\xe8\xce\xda\x2f\x98\x9a\xdd\x59\xfe\xe6\x38\x12\x4f\xf8\xdf\x47\xf4\xfc\x96\xa0\xf3\x26\x25\x53\x47\xcb\xe7\x9d\xd6\xe2\xed\x10\x37\x03\x7e\xd1\xac\x0c\x1a\x79\x51\xa8\x8f\xe2\xf2\xf9\x2c\xce\x47\x0c\xe3\x1b\x58\xa9\x11\xa4\xb5\x26\x66\x7d\xce\xae\x37\x3e\xfb\xf0\xeb\x4f\xb1\xa8\xc8\xa5\xf5\xc3\xf8\x3a\xc8\x8b\xc1\x6f\x0c\x2b\x29\xf7\x9b\x15\x9e\xdb\x62\x7c\x16\x59\xe8\xee\xff\x24\x4d\x7a\x59\x3b\x7d\x4a\x79\x8f\xf5\x25\xe2\x9d\x8c\xd1\xbe\xb8\x81\xb5\x53\xb7\x72\x15\xbf\xfa\x8d\xe7\x22\x37\xdc\x64\x2d\xb0\xbc\x07\x6e\x26\x25\xaf\xf3\x36\x9f\x19\xb9\xcb\x8a\xea\x5f\x16\x6a\x2a\xcc\x33\x44\x6d\x70\x97\xc8\x16\x56\x91\x1b\x8c\xc7\x5c\x7a\x3e\x34\x7a\xee\xb9\xcb\xfe\xe2\xd7\xa9\x9e\xdf\x6e\xb2\xfc\x26\x99\x35\x8d\x4f\x2c\x36\xb8\x73\x64\x8b\x9b\x02\xf4\xd7\x33\xce\x15\x7c\x38\x46\x99\x6f\xef\x53\x1c\x53\xf6\x9d\x87\x73\xfe\x76\xa4\x1e\xfb\xfe\x07\xbd\x6d\xe3\x08\x97\xc8\x66\x07\x5a\xef\xdb\xb1\x75\x81\xac\x2e\xbf\x10\xda\xcf\x86\x83\xd3\x9a\x2b\x7b\x84\x45\x67\x64\x7e\x8c\x09\x30\x6b\x06\x67\x68\xa0\x2f\xbf\xd4\x8d\x73\xb8\x8d\x76\x4c\x75\xbd\x75\x27\x13\xb2\x35\xb3\x7a\xef\x80\x4f\x73\xce\x2b\xea\xbe\x63\x73\x9f\x2a\x8b\x27\xe5\x7b\xf2\x89\xae\x15\xd9\x6b\x64\x9b\x03\x73\x62\x73\xc2\x67\x98\x8d\x95\x35\x5d\xad\x53\x7a\x0f\x2d\xb2\xb6\xfb\xe8\x80\x35\x9b\x57\x7c\xfc\xa8\xe7\x2d\x42\x6b\xf5\x7e\x42\x6c\xbe\x1e\x10\x22\xe6\x2e\x75\x64\xe5\x0e\xd1\x3a\xc2\xc9\xbb\x0d\xee\x2f\x07\x46\xb1\xe6\x84\x8b\xb1\x90\x06\xc1\x3f\x8a\xc5\xce\xa4\x7e\xc8\x20\x17\xbc\x66\x2c\x28\xe3\xd1\x5a\xe0\xd7\x3f\x29\x84\x27\x7c\x7b\x4d\x63\xeb\x75\xad\x4b\x6b\x43\x03\x56\xb7\x0e\xc8\xbb\xa6\x1a\xb2\x99\xf5\xeb\x01\x75\x27\x3c\xb8\xd8\x15\xf6\xa1\x92\x44\x8b\xb8\x3f\x4c\x2a\x9f\x3f\xfe\xa3\xf2\xd7\x5f\xd5\x24\xee\x57\x93\x74\x13\x0c\x93\xf1\x70\x98\x26\xd5\xe5\x30\x1c\x44\x71\x35\x8c\xe2\x59\x37\xf0\xb7\xc3\xbf\x92\x7e\x92\x54\xd8\x01\xd2\xe7\x28\x4c\x93\x03\x64\xe1\xb0\x9b\x56\x47\xb1\x3f\xa8\xfe\xec\x45\xeb\x4f\x89\xbf\xf5\xc3\xd1\x01\xfa\x64\x31\x9f\x47\x71\x5a\xfd\x39\xf3\xd7\x7e\x78\xe8\xe6\x82\xb2\xb7\x48\xd3\xe8\x20\x69\x77\x3e\x0f\xfc\x7e\x37\xf5\xa3\xf0\x90\x46\xfe\x70\x95\x54\x7b\xd1\x60\xf3\x3a\x7d\xa2\x45\x3a\x8c\x3f\xf5\xa3\x30\xed\xfa\xe1\x30\x3e\x70\xa8\x17\x2d\xe2\x5e\x14\x56\xbb\x83\x41\x14\x26\xd5\x9f\xfd\x60\xd8\x8d\x9f\xfd\xf5\x81\x23\x51\x6f\x32\xec\xa7\x49\xf5\xe7\x60\xb8\xf4\xfb\x87\x0c\xa1\x49\x94\xcc\xbb\xe1\xa7\x7e\x14\x2c\x66\x07\xe1\xd0\x4e\xcc\x86\x03\xbf\xfb\x4a\x75\x67\xc3\xd1\x21\xd2\x42\xe2\xb0\xbb\x7c\x0d\x59\x1c\xf5\xa2\x83\xae\x53\x50\xf6\xe7\xf3\xf9\x27\x3f\xfa\x34\x18\xa6\x5d\x3f\x78\xdd\x91\x68\x36\x8f\xc2\xe1\x61\xdf\x2c\xa8\xd3\x28\x0a\x72\xba\x7f\xb2\x0f\x95\xb0\x3b\xcb\x23\x84\xff\x79\xf6\x83\x61\xe5\xf3\xc7\x8a\xee\x42\x9c\xf0\xc3\xbf\x3f\xfc\x27\x00\x00\xff\xff\x32\xe0\x02\xf9\xcf\x29\x00\x00") func cssApplicationCssMapBytes() ([]byte, error) { return bindataRead( _cssApplicationCssMap, "css/application.css.map", ) } func cssApplicationCssMap() (*asset, error) { bytes, err := cssApplicationCssMapBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "css/application.css.map", size: 10703, mode: os.FileMode(436), modTime: time.Unix(1492020681, 0)} a := &asset{bytes: bytes, info: info} return a, nil } var _cssFontsCss = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x01\x00\x00\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00") func cssFontsCssBytes() ([]byte, error) { return bindataRead( _cssFontsCss, "css/fonts.css", ) } func cssFontsCss() (*asset, error) { bytes, err := cssFontsCssBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "css/fonts.css", size: 0, mode: os.FileMode(436), modTime: time.Unix(1492020681, 0)} a := &asset{bytes: bytes, info: info} return a, nil } var _fontsInconsolataBoldWebfontEot = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x74\x8f\x73\x70\xdd\x0f\xf4\xa6\x3f\x49\x6e\x6c\xdb\xb6\x8d\xde\xd8\xb6\x6d\xa3\xb1\x6d\x3b\x8d\x6d\xa3\xb1\xd9\xd8\x6c\xdc\xb0\x8d\x1a\x27\xdd\x99\xef\xfc\x66\x67\x67\x77\xf6\xfd\xe7\x3c\xef\xcc\x99\x33\xcf\xd9\x34\x02\x80\x62\x43\x00\x80\x04\x20\x01\x10\x00\x00\x90\x88\x30\xf0\x50\x00\x14\x00\x00\x10\x40\x2f\x24\x00\x80\x00\x05\x15\x56\x00\x08\xb6\x87\x00\xfe\x77\x30\xff\x67\x46\x87\x65\xba\x00\xff\x4f\x70\x00\x59\xc0\x09\x30\x07\x9c\x01\x27\xc0\x1d\x70\x06\x1c\x00\x53\xc0\x03\x30\x05\x00\x00\x0e\x10\xfb\xaf\x5b\x00\x00\x10\x0a\x68\x01\x96\x80\x1b\xe0\x0e\xd8\xfe\xb7\x49\x06\xb0\x03\x2c\x00\x1b\xc0\x0e\x70\x01\x82\x00\x19\xe0\x01\x78\x00\x56\x80\x29\xf0\x15\xf0\x00\x9c\x01\x1b\xc0\x16\x70\x02\x3c\x00\x32\x80\x0e\xf0\x04\xd8\x00\x16\x80\x1f\xe0\x00\xe8\x01\x32\x80\x19\x70\x00\xc8\x00\xbe\xff\xc8\x0d\x20\x03\xb8\x01\xb6\xff\x58\x1a\x20\x03\x38\x00\xb6\xff\x69\xde\xff\xdd\xe7\xfa\x8f\xbd\x00\x32\x80\x02\x90\x06\x28\x00\x00\x20\xfb\xff\xb8\x92\xfd\x1f\xa6\x00\x20\xa6\x2e\xad\xf2\x7f\x7f\x09\x05\x04\x7f\x03\xf8\x4d\x01\x7e\x6b\x80\x43\x09\x63\xf6\x3c\x76\xd2\x64\x43\x7b\xca\x46\xde\x55\x2e\xc8\x9b\x42\x53\xc0\x8d\x89\x35\x93\xcb\x20\x6f\x07\x1b\x05\xc9\xc1\x76\x69\x7b\xf9\x36\x7a\x3a\x17\x15\x26\x5f\x72\x42\x41\x4a\xb1\x8d\x78\x7c\x05\x5a\xa7\xb8\x50\xd5\xc0\x44\x63\xc0\x81\xc4\x42\xeb\x38\xd3\x18\x73\x2e\x8c\x7e\x92\x93\x59\x59\x24\x54\x7c\xc0\x99\x67\x28\xab\xcc\xf2\xab\x1a\x51\x2e\xa8\xc9\xdc\x36\x3d\xcc\x23\xe7\x62\xf6\xbb\xd5\x2b\x17\x49\x34\xdb\x9a\x4b\x21\xca\x48\xc3\xa4\x69\x12\x9c\xe4\x7e\x9f\x52\x4d\x18\x6c\xf1\x40\x2c\x19\x1a\xa3\x38\xab\x2e\xcb\x41\x02\xc3\x50\xa5\xc6\xe1\xe6\x14\xc1\x2a\x46\x9d\xe6\x88\x7b\x3d\x31\xa6\x5e\xcb\x65\xa8\x00\xab\x0c\x7f\xf1\xcc\xb8\x54\x38\x14\xde\x5f\xdf\x62\x64\xdb\x6f\xa6\xcc\x92\x06\xf4\x39\x75\xc4\xd3\x85\xf6\x54\xea\xee\x64\x9b\xbc\x38\x6e\x8b\x8f\x41\xfb\x47\xfc\x78\x9c\x02\xb7\xae\x66\x50\xdf\xf6\xad\x79\xbf\xe9\xa0\x31\x9d\x40\x3b\xe3\x73\xe0\x1e\x43\xc5\x0a\x71\xbb\x54\x9a\x40\xf0\x4c\xa4\x4d\xa6\x36\x42\xec\x49\x09\xab\x78\x73\x2c\x40\x23\xf8\x24\x9d\x87\x71\x5b\xdc\x6e\xe4\xa4\x9d\xef\x85\xac\xfd\xd0\x15\x6e\x01\x1b\xfd\xcd\x0b\x49\x4b\xab\x39\x94\xda\x43\x41\xf3\x28\xf7\xf4\x2c\x72\xf1\xf9\x05\x46\x1d\xfd\x89\x9b\xcc\xe1\x26\x8a\xe1\x63\x0d\x3b\xf0\x8a\x35\xa3\x6e\x2b\x71\x3e\x22\xd6\xaa\xf6\x8f\xd4\x49\xfe\xe1\x65\x99\x53\x31\x9f\xd3\x42\x8a\xe2\x6b\xcc\x12\xde\x9c\xd7\xbf\xb2\xaf\x7b\xde\x8b\x25\x52\x54\x4c\xdc\x2d\xe4\x94\xb0\x26\xb9\x91\x1b\x54\x14\x52\xb5\x6f\x84\x0b\xb4\x68\xbe\xd2\xb1\xdd\x8f\x49\xfb\x22\x04\x4f\x43\x17\x6c\x53\xad\xb3\xb5\x0e\x50\x58\xf5\x04\x13\xe9\x72\x06\xb8\x6e\x36\x05\x0f\x5b\x90\x3b\x29\x89\xaa\x7c\x7d\x3b\x79\xe3\xfb\x36\x93\x69\x96\x52\xaa\xc1\x51\x5f\xee\xba\xb8\x87\x7c\x3e\x2b\xf7\x12\x45\xf5\xd6\x6e\xb4\x76\xd8\xbc\x03\xe1\xb3\x9a\x33\x30\xaf\xdf\xa4\x70\x10\x07\x5a\x45\x63\x09\x44\x2b\x2a\x8a\x70\xf6\x75\xdf\xee\xd1\x47\xd7\xae\x55\xa0\xf7\x8d\x5b\xd0\x90\xd8\xa8\x4c\x3f\x6f\x7a\x61\xab\x60\x22\xdb\x74\x5c\xb3\x20\xde\x30\xa6\x8e\x41\xa4\x57\xaf\x02\xdf\xa2\x7f\xc4\x43\x4c\x5b\xfd\x43\x0c\x65\xda\x2e\xf6\xfa\x82\xb8\x84\x29\x7a\xcd\x72\xd4\x05\xb2\xd3\xd8\x5c\xf9\x0c\xe2\x11\x53\x15\xd2\x5f\x84\x7d\x10\x23\x2b\xf2\x1b\xdc\xfc\x1c\xec\xdb\x87\x53\x47\x7d\xa7\x9c\xdc\x4b\xf6\x10\x60\x16\x4d\x02\x99\xa7\x27\x8e\x5f\x83\x81\xda\x8d\xe4\x05\xe9\x7f\x24\xf0\xbe\xa9\x14\xd4\x36\xfa\x28\xef\xa8\xe1\x81\xde\x5e\x0e\x96\x14\x32\x09\xa4\x28\x5e\xe6\xf0\x38\x02\xb0\xc1\x29\x68\xc1\x62\xf8\xd2\xba\xdf\xbe\x03\xa6\x98\xf8\xc9\xa2\x8c\x0c\xcd\x4d\xc3\x8b\xcd\xcf\xd3\x08\x01\x29\xf0\x51\x3f\x42\x40\x2c\x1c\xc5\xfc\x30\x6c\x48\x5f\x26\x92\xa2\x54\x2f\x6f\xea\x53\x49\xb8\x0c\xc9\x7d\xb5\xd9\x75\xe6\x7a\x2d\x02\xb8\xec\x8b\x43\xa7\xe5\xa6\x21\x71\xca\x3f\x55\x26\xde\x07\x3b\x34\x43\x96\xd7\xde\xf6\x42\x7e\x76\xac\x3c\x11\x80\x96\x5b\xf2\xb0\x84\x07\x7e\x69\x05\x87\x79\x7c\xa0\x40\x5d\xdf\x51\x7d\xc0\xb8\x37\xf1\xd9\x8f\xb8\x44\x36\x2e\xcb\x49\xee\xec\x3f\xc8\x00\x67\xe6\x51\xf7\xfe\x97\x08\xcc\x91\xb6\x36\xf0\xfc\x04\x28\xfe\x1e\xc1\xfd\x9f\x08\x77\x01\x1f\x21\x9a\x1e\x90\xaa\x77\x88\xe5\x94\x1c\x50\xf2\xba\x72\x2b\xd3\x62\xf0\x88\x5f\x95\xb4\x44\x44\x33\x7e\x14\x30\xb2\xf3\xa5\xd7\xfd\x10\x43\x73\xb5\x40\x2f\x5b\x08\x8b\x2e\x81\x46\x70\x9a\xbd\xaa\x16\xbe\xb3\xe5\x90\xcd\x97\x28\xf5\xc7\xeb\x60\xa7\x08\xe7\x87\x73\x83\x92\x7f\x65\xb1\xdd\x23\xa1\xd4\x68\x99\x29\x62\x53\x73\xbc\xfa\xe7\xd5\xdc\x22\xe1\x45\xec\x42\xf8\x99\x69\x93\xdb\xbd\x62\x5c\x5a\x82\x4b\x11\xc9\x1d\xa8\xbe\x76\xef\x98\x8f\xef\xd6\xcd\xf8\x77\x09\xf7\xbb\x9a\x45\x58\xbf\x90\x57\x7d\x5b\xa0\x9b\x58\x11\x92\xdc\xd2\x11\x59\xb0\xd9\x43\xac\xef\x90\x0c\x9a\x21\xb6\xec\xf7\x45\xee\x35\x62\xe4\x12\x03\xf3\x54\xb6\x1c\x08\x79\x0b\x0f\x24\x95\xba\x62\x94\x0c\xb5\x26\x41\x64\x97\x84\xc8\x11\x52\x2c\x61\x8b\xd4\x1d\x8c\x24\x8e\xd6\x64\x60\xd3\xb0\xba\x63\xc4\x29\xab\xe1\xc1\x95\x45\x96\x77\xd7\x48\x7d\xc9\x73\x31\x2e\x38\xa5\x56\x2a\x25\x4a\x97\xfc\x87\xe3\x42\xf3\x20\x92\x75\xbe\x3e\x5a\x44\x9f\x8c\x34\xd2\x31\x89\xc3\x96\xf3\x07\x57\xf2\xaf\xfe\xfb\xa4\xe5\xea\xaa\xde\x7b\xbb\xfa\x44\x95\x12\x53\x83\x26\x06\x8a\x95\x68\xbd\x2a\x51\xa8\x4d\x93\x23\x51\xf8\xe0\x0b\x21\x1b\x33\x2b\x53\x80\x37\x52\xfd\x53\x6e\x7e\xf3\x7a\x16\xe7\x12\x33\xcb\xe9\x00\x8d\xe1\xdd\x1a\x8a\x50\xe2\x16\x35\x2d\x71\x46\xe1\x03\x85\x0e\x33\xf6\x60\xdd\xea\x1f\x21\x2c\x9e\xd1\xd5\xbd\xdb\xaa\x92\x1b\x13\xa6\x7b\x9f\x2d\x08\x69\xc2\x19\x02\xe1\x0b\xf2\x39\x6a\x0b\x34\x98\x4e\x0c\xee\x11\x4f\xc2\x34\x4c\x4a\xd2\xc9\x00\x92\xea\x5f\x30\xb3\xaf\x80\x63\x92\x5d\x11\xc1\x7c\xd7\xbd\x53\xd4\xd8\xcd\x00\x08\x71\x14\xb7\x70\xb6\x20\x41\x77\x8b\x23\x98\x8a\xc5\x55\xa3\x70\x93\x30\x32\x49\x97\x2a\x2c\x6c\x29\x58\x6c\x5a\x7a\x71\x2e\x66\xd3\x64\x96\xe6\x7b\x08\x43\x40\x6b\xb5\x54\x2f\x7c\xb3\x1c\x2a\x28\xe5\xfc\x19\x52\x3e\xb6\xd9\x32\x2d\x39\x37\x04\x8a\x81\x51\x6a\xc9\x17\x3e\xde\x84\x28\x80\x6a\x5c\x5d\xea\x77\x05\xd9\x12\x22\xe7\x68\x2c\x5c\x3b\x34\x70\x7e\x66\x33\x95\x9e\x4e\x91\xa4\x5c\x70\x9f\xcd\x44\x19\x02\xd7\xf1\x0b\x6a\x3b\x37\x21\xed\x06\xff\x55\x90\xad\xac\x62\xc0\x3c\x6f\x2f\x0a\x52\x81\xa1\x8b\x1f\x18\xe3\x8d\x5d\x16\xf1\x56\xf6\x48\x2e\x70\x99\x05\xd1\xeb\xba\xa8\x09\xf7\xfd\x1d\xaa\x82\x9c\x96\x2d\x35\xfb\x46\x25\xc3\x80\xeb\x52\xdc\xc8\xcd\xb8\x55\xd6\x93\xb4\x01\xda\x81\x4e\x6f\x8a\xa4\x4b\x21\x4c\x0f\xca\x15\x19\x0c\x89\xb8\xd7\x66\x90\x1a\x10\x28\x61\xa3\xad\xbf\x84\xf6\x40\xbe\xc7\x8d\xdd\x35\xbb\x4f\x8d\x69\x39\xc5\x99\x40\x30\xbf\x65\x17\xc8\x2e\x8e\xcc\xfe\x32\xe8\x19\x42\x0f\x87\x15\x17\x35\x64\x0f\x60\xc0\x81\x86\x46\xfe\xe8\xe4\xe1\xed\xac\xd3\xb5\xfc\x21\x11\x85\x6c\x29\x05\xce\x94\x0f\xeb\x46\x89\x51\xa9\x81\xd5\xbc\x26\xad\x8c\x67\xbd\xaf\x67\x3b\xe9\x89\x15\xd8\x57\xcb\x10\x6e\x95\x0b\x3b\xa1\xc6\x44\xed\x08\x4e\x69\x96\x63\x09\xf1\x1b\x1e\x6b\xb2\x25\xe5\x17\x6c\xa6\xd8\xf8\x63\xdd\x20\xfb\xf8\xab\x7f\x67\x89\xf3\xb6\x79\x19\x44\xc5\x45\x49\xcd\x8e\xe4\x54\xb7\xd1\xf6\x55\xd1\x10\x4f\x63\x83\xf0\x4d\xb4\x0d\xf9\x38\x64\x55\x4f\xdf\x31\xa3\xfd\x99\xab\x88\x2f\x88\x39\x0b\x3a\x1e\xf8\xa4\xac\x24\xe6\x53\xb3\x11\x1e\x44\x19\x32\xa0\x53\x46\xe9\xd2\xb3\x65\xc9\xe9\xce\x30\x6c\x0c\x12\xe2\xf6\x3e\xb7\x46\x34\x64\x6f\xef\x66\xbc\x88\x6f\x2a\x34\xdb\xf8\x58\x93\x7c\x3d\x83\x6f\x0c\xff\x48\x55\x7e\xbc\x34\xbc\x76\x3f\x93\xba\xef\x15\x6c\x3e\xc0\xf6\x79\xc2\xac\x8d\x06\x75\x84\x2a\x84\x71\xd7\x3a\x69\x97\x10\x04\x47\xca\x8a\xf9\x51\x65\x4f\x87\xaa\x32\xa5\x51\xe5\x9e\xc1\xb4\xa6\xaa\x66\xeb\xa4\x50\x3e\xda\x45\x20\x27\x1d\xdb\x7a\x59\xf3\x0e\x1d\xf5\xe9\x32\xb7\xd2\xd6\x9e\xf8\x84\x97\x06\xd2\x70\xc1\x7a\x7c\x88\x98\xff\x4c\xa3\xa9\x27\xdb\x2d\x86\x8c\x5a\x7a\x3c\x15\x9d\x70\x86\x76\x97\x04\x7d\x0f\xf3\xcb\x12\x49\x3f\xb9\x24\x51\xa7\x5d\xf0\x5c\x77\x4f\x81\x5a\x06\x9b\x93\x8b\xd7\x95\xc2\x2e\x37\x76\xff\x84\x36\x0c\xce\x45\x1b\x1d\x69\xae\x31\xfc\x47\xf4\x97\x6b\xba\xd8\x0b\x88\x51\x28\x83\x2b\x41\x36\xe5\x1b\x89\x8a\x21\xe7\xb2\xf0\xc6\xb0\x61\xee\x4c\xd1\xc5\xf7\x2b\x30\x6f\xbe\x92\x36\x1b\xde\xb3\x9a\xeb\x68\x0c\xb3\x7b\x7f\x22\x0c\x13\xe7\xd7\xd8\x4b\xe1\xd2\xa3\xdb\xa0\x34\x02\xa7\x58\x5e\x99\x53\x34\x3f\xf5\xe0\xa9\x62\x37\x72\xf7\x3f\x54\x67\x9f\x5b\x8d\x34\xb8\x9f\x27\x84\xc9\x4d\x43\x6e\x6f\x71\x18\x20\xf7\xae\x1e\xf9\xec\xae\x11\x25\x30\xab\x85\x76\x4a\xe8\xd4\xb8\xfc\x66\x31\x38\x3c\xc7\x7f\x77\xb3\x6b\xe8\xc4\x9c\xaa\x51\x6a\x03\xae\xf1\xeb\x46\x47\x97\x53\x0e\x06\xc7\x33\xc5\x1e\x68\xb8\xf3\x85\x96\xe4\xc5\x43\x7e\x03\x9b\x05\xe2\x3b\xc1\x2a\xa7\x7a\xd5\x60\xbc\x3f\x50\xa2\x12\x37\x36\x23\xc4\x1e\xd0\x2c\xb0\x3a\x7c\xc5\xfe\xa7\xfa\xb5\xe9\x71\xa2\xf9\xd6\xd0\x7f\xe4\x68\x38\x83\xc4\x63\x1c\xe6\x54\xd8\xf2\x8f\x53\x28\xc0\xa6\xf6\xf8\x5e\x58\x85\xf6\x82\x41\xc2\x21\xd1\x1d\xfa\xd3\x09\x17\xca\x89\xb0\xf3\xbf\xc5\x03\x7f\xe2\x46\x7f\xc7\x19\x74\x2c\xdc\xa1\x19\x95\xfa\xde\x07\x5c\xb8\x8e\xc6\x42\x9c\xed\x36\xef\xb5\x39\x49\xd4\x0b\xc4\xfd\xd8\xe0\xca\x56\x7d\x5a\xa3\x40\x18\xc1\x6b\xde\x82\x57\xc8\x3c\x0c\x58\x93\xda\x3c\xd3\x04\x1f\x78\xc2\x82\x1f\x25\xe4\x82\xa1\xd9\x7c\xd0\xad\x9c\x96\xa9\x75\x8d\x11\x12\x5b\x55\x6a\x0f\x94\x0b\x2f\xf2\x68\xf7\x76\x18\x46\x0b\x2d\xa5\x42\x32\x36\x30\x54\xba\xca\x27\x29\xfe\xc2\x15\xb1\x89\x1d\x24\xe0\xf2\x6a\xde\xa8\x0c\x4a\xb1\x83\xe2\xb5\xa9\x05\x50\x70\x6d\xb0\x06\xde\x9d\xc1\x95\x31\x04\x51\xa8\x55\x05\xfb\x3f\xea\x6c\x0c\x08\xe8\x61\xeb\x11\x36\x34\xea\x3f\xae\x1c\x72\x3b\xab\x23\xe8\xf7\x37\x1f\xc3\x29\xc5\x2c\x97\x43\x92\x67\xb1\x60\x41\x68\xd2\x76\x91\x64\x60\x9a\x2e\x4d\xd3\x75\x54\xe0\x91\x4a\x89\x76\xa5\xf7\x22\x9f\xdb\xec\x9d\xf6\xe7\x28\xb5\x98\x91\x3b\xfc\xa9\xb4\x35\x15\xbd\x91\x11\x2f\x0a\x52\x4c\xec\xec\x58\x05\xf3\x40\x63\x64\xd1\x4a\x36\x25\x9c\x8d\x2b\x7d\x0e\x8c\xf9\x58\x18\xab\x41\x11\x22\xc8\xfa\xa3\x81\x9f\xcb\x38\x75\x5b\x2c\xe3\xb0\x0a\xe7\xde\xfd\x4c\xea\x02\x06\x43\xa9\x31\x06\xfb\x39\x77\x6a\x39\x44\x1a\xf2\x2f\x86\x54\xc8\x60\x0d\x2d\x5e\x7a\x22\x07\xe1\x6b\x7c\xc1\x5a\x6d\x74\x73\xbf\x03\xfe\x16\x57\x63\x35\x6c\xc5\x8f\x90\x52\xd3\xfc\xf8\x26\xb3\xf6\x03\xd1\xdd\xa2\x8a\x6f\xbb\x4c\x19\xd1\x48\xc9\xd9\x25\x6b\x7f\x3d\x67\xcd\xb9\x8a\x24\xe4\x0e\x8f\x22\x59\x53\x6e\x3c\xfc\x2b\x6c\x3d\x83\xe7\x84\x26\xae\xbb\xac\x24\x9b\x56\xa4\x53\x2b\xda\xf3\x4e\x14\x7e\x71\xf1\x52\x4c\x1a\xda\x09\xac\x36\xc0\x74\xc4\xcd\xe8\x4b\x45\x23\x50\xac\x4a\x3d\xe9\xd9\x78\xf5\xac\x22\xee\x74\x6c\xeb\x91\x4d\x4c\x07\xfe\x94\xfc\x08\x0c\x8d\xf8\x43\x0e\x0b\x7f\xcc\xf3\x18\x4b\x30\x09\xd9\x54\x1a\xc7\xce\x74\xcd\x5f\xac\xb4\x93\x86\x93\xab\x07\x51\x26\xc3\x8a\x3c\x0c\x7e\x17\x2f\xee\xd5\xab\x17\xa6\xaf\xbd\xd7\x7e\xe1\xae\x3e\xa8\x8e\xb6\xe6\x99\x70\xcc\x3a\x19\x4a\x6c\xf1\x26\x49\xb2\xc9\xd9\x93\xcd\x7e\xc7\x0a\x88\xe0\xeb\x71\xad\x5e\x13\xe4\x7a\x74\xb8\xc6\x6e\x85\x75\x50\xc7\xa1\x28\xb8\x0c\xae\xf9\x84\x22\x33\x6a\xb4\x97\xdc\x67\xb6\x4c\x97\xef\x78\x10\x39\x75\xaa\x0d\x6b\xc3\x58\xb0\x15\x6c\xd0\x6e\x41\x4b\x87\x29\x0d\xd0\x2b\x38\xce\x83\x23\x85\x2a\xc6\x93\xa2\x11\xab\x6e\x96\x85\x8a\x7d\x2f\x5f\xd6\x03\xe0\x71\xee\xc6\xe2\x90\xb7\xb6\x89\x1b\xd6\x22\x66\x64\x5c\xd8\x4b\x67\x05\xe4\xe1\x20\x34\x97\xf4\x83\x2e\xc7\xb7\x35\x92\x86\xa9\xe0\x70\xc9\xd3\xa0\x3b\xff\x98\x4f\x94\xb1\x75\xeb\x44\xb9\xd6\xa0\xdf\x27\x67\x4e\x2c\x61\xa2\x6d\xe8\x29\x2f\x4d\xa4\x54\x86\xf7\x6e\xec\xd3\x29\x65\x18\x6e\x77\xd4\x5b\xd0\xed\x8f\xc1\x5e\xf8\xf2\x55\x43\x91\xc6\x12\xf6\x82\x2d\xc8\x5d\x44\x90\x2e\xa1\xc1\x4b\xc9\x56\x58\x4e\x14\xb7\x8c\x87\xfe\x35\xfe\x2e\xbb\x66\x7e\x61\x2c\xa1\xfc\x79\x34\xf9\x97\xc9\xa5\x56\x5d\x94\x56\xc6\x65\x8b\x57\x25\x46\x31\x88\x49\x1a\x37\x58\xbf\x5b\x6c\xe3\x3f\x6b\xa2\xef\x39\x50\xe0\x9e\x87\xce\x95\x5a\xf8\x5e\x31\x72\x13\x7e\xff\x6b\x2d\xe0\x8b\x1d\xec\xd2\x7e\xa2\x2e\x8b\x75\xcd\x16\xac\xff\x95\x29\x1e\xee\x3c\x61\xea\x31\x3a\x85\x66\x0b\xff\xc7\x26\x1a\xaa\x61\xcf\xfa\x61\x27\xf3\x5f\x3d\x1e\x9d\x18\x0a\x29\x36\xf4\xda\xf7\xc6\x1c\x61\x37\xfa\xb2\x21\x6b\x1e\x05\x18\xb2\xc2\xa5\xb6\x9a\x10\xf5\x42\x90\xaf\x7e\x13\x32\xf7\x35\x8b\x71\x9e\x09\x11\x89\x89\xb9\x0d\x3b\xae\xec\x33\xbb\x82\x4a\x33\x9d\x6d\x8a\x3e\x70\x40\x61\x20\x3c\x38\xd2\x7d\x8f\x44\x4b\x74\x4b\xbe\x20\x73\xec\xe2\xa6\xe8\x88\x1a\xb0\x8b\x8c\xdb\x78\x0e\x40\x7e\x21\x20\xd7\x35\x91\x5a\x25\xd4\x1d\xbc\x11\x49\x2a\x3f\x6f\x0d\x82\xb8\xcf\xae\x21\x59\x5f\x82\xe6\x81\xf0\xc5\xc0\x24\x61\x55\xae\x0c\x65\x7b\xe5\xa2\x89\xb6\xba\x90\xa9\x86\x98\xa6\x99\x6f\x73\x89\x27\x7b\xb5\xe7\x0d\x24\x30\x2e\x73\x3a\xbd\xc9\x82\xda\xbf\xcb\x01\xfb\xa8\xc7\xa9\x04\x83\x3f\x10\x54\xad\xe1\xd1\xc5\x9d\x91\xeb\x20\x4c\xf1\xd5\x76\x7c\x30\xff\x32\x0a\x40\x6a\x48\xca\xa7\xfa\x50\x95\x11\x45\x9f\xc2\xe8\x94\xc4\x60\x25\xee\x47\xe2\x9a\x39\x95\x9f\x1e\x87\x0d\x9a\x66\x13\xf4\x0e\xe0\xf0\xe9\xd5\x55\x78\xc3\xa1\x2d\x4b\xd9\xdd\xe3\x49\x23\x94\x12\x67\xd8\xfa\x68\xe7\xce\x94\x5c\x95\xb6\xb0\x80\x4c\xc2\x39\x2e\xd0\x0d\xe6\x72\x22\xe0\x7e\x9f\xf8\x23\xd7\xfb\x46\x6b\x8d\x15\x21\x3a\x8c\x1b\x88\x4f\xa3\x04\x18\xed\x08\xa6\xce\x9b\xee\xcf\x91\x7f\xe1\xbf\x4e\x66\xc3\x6f\xe2\xc0\xe9\x25\xd0\xad\xe4\x5e\xc6\xf7\x60\xa3\x5c\x4a\x57\xc5\x5f\x5e\xde\xaa\xcf\x43\xc5\x76\x18\xbc\x91\x0d\x40\x23\x77\x42\x33\x1d\xb2\x3b\x40\xfd\x3b\x6d\x69\xe2\x71\x57\x6c\x1f\xe0\x12\xfa\xc3\x11\x05\xc7\xda\x2d\x6e\x49\x77\x63\x91\xcd\xaa\x0f\xce\xf4\xb0\xe5\x4b\xc5\xfe\x48\x7b\xba\xbc\x59\x26\xb5\xd5\x54\x79\x89\xe8\xf8\x26\x86\xdb\xbd\x55\xb6\x48\x13\x2f\x01\x11\xb1\xd4\x4f\x09\x07\x07\x2b\x00\x2a\x1f\x49\xb7\xf9\x56\x7e\x3d\xa4\xea\x36\xfb\x76\x45\x6e\xcc\x58\x98\x10\x04\x1f\x0b\x61\xbd\x5d\xfb\x4f\xb1\x7b\x70\x09\x1f\x43\xb7\xf1\x64\x12\x5f\x81\xea\x41\x8f\xee\x0c\x75\xb8\x93\x59\xf6\xb7\xcf\x49\xa3\x19\x72\xee\xdf\x6d\x21\xd7\xc4\x69\x6e\x14\xf0\xdf\x95\xb7\x34\x83\xa2\xf8\x75\x1c\x9c\x03\xce\xf5\x15\x5e\xe9\x16\xdd\x29\x09\x01\xde\xc8\x7e\x06\x65\x5b\x06\xce\x14\x05\xd7\x0c\x05\xe5\xb0\x7e\xa5\xfd\x75\x8f\x83\xe5\x5b\xab\xf8\x87\xc8\xa9\xbd\x5e\x72\x36\x55\x52\x8e\xc8\xe1\x57\x73\xbe\x63\x16\xcf\xa4\xa2\xc2\x7d\x0c\x38\xfa\x2b\xa8\x0b\x64\x9e\x07\xfa\xa2\x0a\x6e\xbc\xf0\x47\x15\x36\xce\xfc\xba\xa6\x83\x83\x0f\x9f\x60\x87\xd2\xdf\xaf\xdf\x78\x16\xbe\x2c\x5e\x96\x28\x2a\xc7\x88\x07\x8d\x61\xed\x55\xb9\x44\x5c\xac\xa3\xa9\xcb\x10\xd5\x32\x76\xff\xb8\x1d\xd1\x7f\x7f\x44\x41\x47\x08\xed\x59\x24\x23\x3d\x51\xf5\xcc\x5d\x5a\xef\x5c\x96\x66\x27\xea\xf9\x3e\x7d\xa0\xaf\x0d\xa7\x6a\x46\xa4\x8d\x37\x5e\xd6\x6b\x73\x87\xb4\x77\x7b\x68\x9c\x4a\xb4\x53\x7a\x59\x59\xba\x93\x81\xce\x80\x0b\x45\x82\x76\xfe\xfc\xfe\x2f\x38\x2b\xa7\x4a\xe0\xd3\xf3\x40\x68\x22\x6e\xac\xfd\x59\xd5\x3d\x79\xf3\x15\x6d\x0c\xff\xe7\xdf\x3d\xdf\x25\xb6\x5a\x93\x36\x50\x16\x69\xb8\xa7\x8e\xb6\x46\xbc\x2a\x66\x73\x36\xc9\x9f\xfb\x37\x33\x50\x85\xc5\x8f\x8d\x61\x5b\x09\x4a\xd6\x33\x0d\xb0\x9b\x7b\x25\x7e\x65\xaa\xac\x1b\x7a\x0f\xd6\x55\x40\xc7\x8b\xa7\x3c\x72\xbe\x99\x98\x71\x60\x34\x3a\xab\x9e\x23\xa4\x35\xad\x2f\x0e\x92\x8e\x86\x4d\xe5\x66\x2b\x83\x4d\x2c\x30\x87\x0d\x2f\x14\x0c\x28\x42\x2c\xee\x72\x94\x4e\x38\xc0\x54\x5e\x8b\xb2\x6d\x91\x95\x6f\x05\xd1\x71\x5e\xf4\xf4\x7c\x59\xad\x40\xd8\x11\xb6\x4d\x51\x57\xef\x2c\xda\x47\x3f\x63\x08\xef\xcb\x39\x63\x39\xa8\xe5\x31\x98\x66\x5f\x34\x72\x3a\x7d\x6c\x15\x2b\x8d\x78\x68\x4d\xaa\x9b\x13\xaf\xba\x36\x89\x5b\x92\xec\x8f\xdf\xc8\x2e\x92\xe0\x6a\x63\x55\x6a\xb7\xb1\xc1\x6a\xb3\x97\x8c\xef\x5c\xb3\x14\x18\x6e\x5c\x34\x70\x85\xac\xf1\xf7\xcf\xdd\xfc\x02\x40\xa4\x07\x6b\xc9\xe1\xeb\xcd\x31\x45\xc2\x85\x94\x3b\xac\x5a\xea\x19\x40\xa2\x09\xb4\x20\xb7\x7e\xf9\x93\x48\x67\x8b\x19\x4e\x5a\x81\x04\x86\x3b\x4c\x6f\x56\x33\x7d\xb1\x27\x39\x0c\xd3\x49\xec\x69\xe6\x0a\xa1\xb2\xda\xc0\xe0\xd6\x61\x99\x74\x41\xa4\x9a\x78\xb4\x56\xfd\x88\x95\x0e\xff\x89\x03\xff\x4b\x46\x6b\x7d\x2b\xb8\x3d\x34\x85\x69\x16\xa2\xea\x1e\x96\xf6\xdb\xc4\xd7\x78\xbb\xf0\xb8\xc9\x2a\xe9\xd4\x91\x16\x4e\xc7\x19\xfa\xaf\x0d\x83\x85\x90\x45\x4e\xef\x63\xf6\xdf\x07\x0f\x5d\xbb\x0c\x6b\x49\x1e\xeb\x8b\xe4\x8d\x3d\x4a\x0f\xa3\xb3\xc3\xff\x5a\x3b\x74\x89\x14\x2c\x24\x5c\x76\x92\x3f\x3c\x97\x17\x9a\x6c\x24\x0b\x5c\xb5\xe9\x59\x51\x26\x25\x0b\xb3\x3e\xed\xf0\xcb\xc6\x2c\x92\x1c\x13\x7a\xdc\x00\x50\xa6\x11\xae\x93\x77\xb4\x5b\xd7\x7a\xee\xc3\x48\x12\x32\x7c\x6e\xf4\x63\x9c\x19\xdb\xda\x8e\x4a\xa1\xc0\xa7\xc5\x32\x96\xef\x72\x7b\x2d\x49\xdf\x71\xc1\x82\x43\xbe\xf6\x77\x5b\xb0\x44\xfa\x80\x5b\x92\x4a\xbc\xc0\xde\xbe\x19\x7e\x1c\x04\x1d\x93\xce\xf7\xdb\xc9\xf9\x98\x87\xb4\x0b\xf4\x0f\x95\xca\xfc\x10\x05\x86\x25\x88\xe6\xfe\x7d\x67\xe8\x5b\x88\xda\x26\x29\xd2\xce\x1f\x5e\xa0\xdc\x66\x1b\x69\xd4\x0b\x3b\xb5\x0a\xb2\x08\x8d\x22\x0e\xe9\xf1\xe9\xc2\x4e\xde\x3d\x13\xf3\xcc\x3f\xc5\xa7\x5f\x12\xad\x1f\x0a\xe2\x16\x20\xab\xeb\xbe\x5c\x93\x3e\x59\x3e\x4e\x35\xac\x3f\x42\xa2\x1b\xed\x31\xdc\xe2\xa9\x28\x43\xa3\xac\x5c\x5f\x91\x6c\x68\xfa\x67\x32\x84\x07\x6e\x90\x29\x93\x6a\x89\xf4\x8b\x71\xcc\xcc\x2d\x18\xa6\xdf\x94\xa3\xae\xc4\x36\x94\x42\x05\xc6\xe5\x90\x95\x22\x55\x26\x13\x72\xd2\xd4\xc0\xd8\x51\x12\x08\x87\xe3\xf5\xa9\xa2\xdb\x6d\x9b\x2c\x3f\x79\x54\xa8\x6c\xd6\x05\xab\x65\xec\x29\xdc\xe7\xba\x21\x50\x19\xf6\x8b\x59\x4e\xb9\xde\xdb\xab\xff\xdd\x4b\x35\x21\xa2\xdd\x09\xa2\x86\xd8\xd2\x52\xb6\x4d\x69\xa5\x09\x14\x44\xea\x41\xfb\x40\x25\xbe\xd1\x40\x2f\x21\xae\xc6\x1e\x63\x13\x66\x5a\x60\x3f\xe1\x46\x6b\xa0\x46\xfb\xab\xc7\xbd\x18\xa4\xa7\x8b\xaa\x5f\xc3\xc9\x9c\xb1\xc2\x52\x67\x1d\x76\x4d\x72\x77\x85\x0d\x8b\x70\xe3\x32\x66\x85\x40\x2d\x42\x5e\xee\x0b\xd3\x76\x26\xba\x3f\xcc\x9d\xd4\xc0\x93\xd1\x37\x41\xee\x3c\x27\x54\x6f\x79\xc7\x9b\x55\xcd\x4b\x2f\xc7\x0a\x9b\x01\xb5\x43\x71\x74\x85\xa6\xbe\x11\x44\xb3\xf0\xea\xfd\x6e\xe4\x96\xeb\x3a\x3a\x67\x69\x1a\xcb\x0b\x52\x09\xa2\x2c\xab\x27\x3d\x36\xc9\x74\xcb\x57\xa1\x64\xf7\x1f\xa1\xac\x1a\x6a\xe1\xa9\xf9\x23\x77\x31\xec\x12\xc2\x93\x3d\x58\x47\xcd\xdc\x4f\x5c\xaa\xb7\xd1\xf4\x4f\x39\xb3\x9e\x4c\xb2\x4e\x65\xc2\x01\x3a\xfd\x34\xa9\x06\x16\x99\xef\x51\x0b\x33\x25\xbe\x42\x08\x22\xdc\xbb\x54\x05\x50\x42\x38\xe5\x0f\x72\x21\x5b\xe3\x8d\xac\x8a\x2a\x36\xa1\x3b\xaa\xc5\xb7\xe4\x25\x22\x61\xcf\x32\x9c\x90\x5c\x30\x0e\xba\x55\x41\xd5\x0a\x99\x2d\x42\x76\x1a\x33\x98\x81\x15\x17\xfb\xb2\x78\xe9\x5d\x15\xdd\x6e\xf8\xc6\x00\x66\x22\xee\x70\x70\xce\x9b\xd6\x83\x69\x43\x70\xdf\xda\xc7\x24\x4c\x54\x50\x11\x29\xfc\xa9\x1b\x8b\xb7\xd9\x09\x0f\x37\x05\xff\x53\xaa\x37\x2d\x24\x06\x08\xbd\x84\x83\x99\xd1\xe9\xc6\x8b\xf1\x53\xc5\xa4\x6b\x0e\x26\x99\x93\x6a\x41\xc6\x6d\xa2\xf9\x21\xed\x37\x3c\xd7\x1b\x6a\x6e\xd3\x28\x05\xcf\xbb\x47\xe9\x1d\xed\x1c\xa7\x26\x6f\x96\xb9\xe2\xb1\x0f\x27\xe1\x02\xb1\x10\x24\xd6\xc4\x78\x66\xfb\xb8\x34\xd5\x9f\xc7\x0a\xfe\x03\x1f\x18\x8f\xee\x73\xaf\xa5\x64\xa6\x92\x5a\x3e\x2d\x82\x0b\x07\xab\xcc\xb7\xc9\x29\xda\x99\x79\x9d\xad\x41\x1c\x5c\x68\xa6\xe6\x3b\x76\xa4\x70\x3e\x1f\x6e\x4e\xe1\x6b\x52\xd9\x85\xda\x0c\x51\x6e\xca\x6c\x84\xd4\xfa\x27\xa9\x6e\x07\xca\x4e\x6e\x24\xbb\x3f\x63\x9b\xd1\x47\x04\xe9\x0a\x3a\x20\xbf\x69\x7f\x21\xcd\x24\x30\xaf\xad\xdd\x84\x4e\x6f\x6a\xf9\x62\x43\xc6\x71\x67\x44\xfd\xbb\x87\x64\x4a\x04\x08\xe3\x28\x25\x52\x80\xae\x2d\x26\xae\xa4\xe1\xbc\x7f\x7f\x69\x5c\x46\x46\x56\x88\xeb\x69\x7f\x5a\xce\x84\x21\x18\x41\x83\xdd\x09\xfe\x34\xd4\x49\x22\xfe\xc9\x10\x82\x3e\x90\x94\x75\x9c\x5f\x3d\x9f\x35\x0d\xdd\x99\x5a\xa7\x70\x5c\x32\xbd\x16\x5c\xea\xd0\xb9\x40\x9b\x1a\x5e\xe1\xb0\x06\xd6\x8e\xe7\xfb\x1b\x56\x98\x4c\xea\x2f\xac\xf1\xe2\xb4\xef\x41\x35\xc9\xdf\x9b\x7d\x37\xaa\x56\x6f\xaf\xa9\x76\x8a\x03\x3b\xc0\xb8\xdf\x78\x64\x5e\x32\xab\x74\xa9\x66\x40\xff\x33\xf6\x09\x4c\xb5\xfc\xf8\xc7\xce\x34\x64\x53\x0f\x62\xd6\x43\xf4\x46\x5f\xce\x2e\x4e\xce\xe0\xd0\x17\xf4\x2d\xcd\x88\x84\xa4\x8c\x82\x2c\xf1\x1d\x48\xa2\x80\xa7\x7b\x7c\xf9\xa1\x86\xd5\x3c\xa7\x87\x96\x6c\xc3\xcf\x68\x92\x9c\x70\xc4\xb7\x6f\x23\xaf\xcf\xeb\xfe\x7c\xcf\x78\x46\x25\x5b\x87\x91\xde\x24\x0d\xd0\x9b\xb8\xf3\xc1\x08\x2e\xd1\x8f\x9c\x79\x09\x62\x4a\x98\xf8\xb3\x0b\x98\x2d\x3e\x7f\xaa\xc2\x38\x37\x59\x5b\xe2\x7a\x56\xaf\x8c\x96\x25\x58\x20\xfe\x18\x5e\x87\xff\x99\x60\xd0\xe6\xaf\x65\x6d\x2b\xe4\x3f\x6c\x0b\x87\x8e\xc4\x2d\x86\x23\x38\xc3\xb1\x80\x4a\xf8\x45\x9e\x15\x56\xa9\x65\xe1\x2e\x9a\x20\x7f\x7e\xb8\x84\x6e\xdf\xea\x29\xb9\xa6\x34\x58\xb3\xdb\x0e\xfe\x41\x77\x3c\x52\xd5\x38\xc7\x56\xdf\xf2\x24\xce\xc6\xea\x14\xcc\xc0\xba\x08\x15\x13\x1b\x24\x39\xcc\x17\x89\x00\x5d\xc2\x83\x10\x3e\xc2\xf5\x71\xbd\xb4\x8e\x4e\xc2\xcb\xae\x77\x58\x06\x0a\xb3\xc0\xd4\x8b\xec\x07\x89\xf3\xde\x88\x85\xa6\x0f\x09\x2a\x40\x0d\x6c\xf2\x7e\xaf\x10\xeb\x3b\xc7\xdc\x1f\x5d\xa2\xb6\x29\xbf\xd1\xa5\xe8\x09\xf7\x0b\x77\xd9\xa7\x4b\x22\xe0\xa3\x7c\x57\x1e\x64\xf2\xed\x34\x04\x71\xc1\x49\x6d\xe8\x16\xa0\x34\xc3\x8b\xe6\x91\x5b\x50\x60\x3c\x87\xa6\xd8\xfc\x82\x0a\xde\x4f\xf9\x1a\x6d\xbe\x56\x34\xc5\xb1\x7a\x50\xfa\xbc\x27\x5f\xac\xa0\xba\x2b\x43\x16\xa3\x2e\x38\x79\x38\x70\x5f\x44\xc4\x7b\x41\x0e\xf6\x59\x0e\xc7\x1b\x42\x7e\x25\xf9\x17\xa1\x27\xea\x33\x10\x90\xab\x3d\xf9\x9e\xaf\x70\x50\x9e\x49\xa0\xe2\x23\x85\xcb\x42\x64\xfa\x50\x86\xb1\xf0\x3b\x15\x8e\x1a\x8b\x5d\xb5\x01\xd7\x2a\xbd\x71\x82\x46\xc6\x58\x23\xad\xc1\x96\x52\xc5\xa5\x90\x00\xf3\xf9\x93\xae\xe8\x77\x5e\x9a\xca\x15\x8e\xae\x9e\x7c\x97\x27\x4c\x41\xbe\xbe\x1a\x53\x61\x75\x40\xcb\x34\xa2\xc8\xc0\x36\x9f\x56\x5c\x05\x4c\x22\xf4\xbd\xc0\xe2\x40\x33\xfa\xbb\x6c\xfd\x21\xa6\x27\x0a\x73\x91\xc3\x9b\x3a\x3a\xf2\x19\xba\x4b\xc5\xb7\x64\x80\x82\x28\x62\x00\x92\x46\x65\x17\x76\x55\x62\xc2\x58\xa3\x80\x2a\xdd\x25\x38\x87\x52\x2f\x10\x56\x9d\x49\x9d\x6b\x84\xbf\x9a\x6b\xc5\x85\xf9\x78\x65\x61\x14\x1f\x0e\xb2\x10\x83\x50\xb8\x86\x8f\x83\xed\x37\x46\x0a\xb4\xfb\xc2\x14\x50\x3c\xf0\x09\x07\x01\x1d\x9d\x02\x21\x63\x9f\x8c\xd0\x45\xc6\x90\xf7\x6e\x1b\x89\x70\xd9\xc0\xd7\x3e\x1d\xf5\x4c\xe8\x75\x1b\xa2\xfe\x57\x48\x6c\x1d\x35\x6a\x2a\xc2\x27\xa6\xdc\x2b\x01\x55\x25\x0a\x67\xf4\xbd\x30\xcc\xa5\x53\x1b\x8f\xae\x03\xac\x10\xfc\xac\xdc\xeb\x9f\x35\x1a\xc1\xd3\x67\x9e\x6a\x62\xc1\xc7\x16\xb6\x36\x5c\x22\xa7\xa0\x24\x57\xa4\xcd\xa5\x2e\x5c\xc8\x39\x24\xd5\x9d\x2a\x95\xee\x7c\x7e\xd1\x55\xe8\x81\x02\xab\x31\x61\xeb\x44\x0d\xe3\xc2\xa1\x6e\x27\x38\x50\xd0\xfc\xf2\x5b\x43\x4e\xbd\x43\xff\x86\x3a\x69\xab\x68\x7c\xf0\xc7\x78\xbc\x84\x66\x88\x84\x57\xad\xc6\x3a\x8e\x9e\x1d\xca\x77\xbf\x4c\x77\x68\x09\x95\xe9\x4f\x52\xd6\xec\x54\xa7\x24\x57\x82\x8a\x50\xe5\x01\xac\xaf\x46\x5d\x9d\x32\x39\x89\x31\xa2\xd9\x14\x0c\x7c\xb9\x7e\xf9\x1c\x07\xa2\x6f\x85\xdd\xdb\x31\x11\xdf\xe9\x25\xe9\x37\x6d\x66\x91\x31\xf1\x1b\x96\xc4\x99\xf1\x2c\xef\xba\xb9\x5d\x48\xad\x50\xd1\x6b\x40\x4f\xd0\x8a\x85\x91\x88\x4f\xe5\xcf\x07\x3a\x35\x39\x16\xa9\x8a\x3b\x5f\x3d\x57\xff\xb4\xc5\xca\xe4\x7e\xbc\xbe\x9f\x8d\xee\x15\x1a\x4c\xbe\xbb\xba\x97\x42\x63\x28\x74\x8b\x53\xf2\x82\xf5\x31\x0d\x6b\x84\xd8\x09\x17\xb7\xe3\xad\x56\x99\xdd\x29\x9a\x9c\xbd\x0b\x30\xc5\x9e\x5f\xd0\x84\xa1\x90\x9b\x54\x7e\xe2\xed\x22\xfb\xe6\x2a\xbe\x84\xb1\x1f\xe7\x58\x7e\x84\x61\xb8\x1d\x8a\xe7\xba\xe2\x33\x49\x52\xe2\xcb\x8d\x31\x10\xc5\xd6\x7e\xf1\xbd\xaa\xbf\x3c\x7c\x6d\x0d\x05\x67\x9b\x98\x67\x80\xb6\x0e\xf8\x79\xdd\x19\xda\x0a\xa2\x3d\x49\xd8\xe4\xe2\x25\x54\x2c\x19\x8f\x64\xd9\xc9\x13\x53\x28\x99\x20\xa0\x4f\x3b\xaa\xc6\xbf\xcd\xa0\xb5\x98\x75\xdf\x79\x1f\x74\x62\x0f\x41\xc2\x89\xcd\xfd\x21\x9c\x81\xaf\xd8\xbd\x37\x4f\x6f\x41\x13\xc7\xab\xda\x1d\xdc\x4e\x9e\x5d\xe5\x4a\x1d\xea\x89\xe2\x40\xf1\x22\x95\x1a\x9b\x5a\x7a\x3d\xb4\x8e\xe8\x78\x23\xff\x21\xd1\x29\xec\xf1\x56\x75\x50\xe3\x77\x7b\xff\x3e\x42\x9b\xf5\x9e\xaf\x84\x78\xfd\x2d\x8f\x09\x87\xac\x2a\x6c\x5a\x61\xbc\x05\x1d\x61\x15\x26\x59\x57\x95\x62\xcb\x50\x19\x43\xdc\xa6\x14\xdb\x65\x14\x9d\x72\xc6\x5f\x26\xa9\x58\x03\x72\x2d\x83\xc1\xe4\xeb\x6d\x66\xa6\x8b\xb6\x06\x8a\xe8\x0e\x64\x12\xa5\x30\x66\xb8\x83\x33\x89\xb8\x77\x4c\x8a\x2f\xe4\x6f\x2b\x3e\xd8\x51\x9e\x10\x1e\xbe\x22\xfe\x5e\xaa\xde\x39\xb2\x3c\x12\x33\xc6\x1d\xab\x41\xfb\xd0\xab\xaf\x25\x8d\xe6\x04\x55\x42\x9e\x2d\x93\x92\xbb\x7c\xba\x5b\xef\x8d\xf6\x3c\xf2\xfe\x97\xab\xa4\x6c\xb2\x3f\x0c\x3e\xad\x9c\xa3\x76\x8e\x0f\x6e\xd7\xf8\x8a\xb6\xfd\xe7\xb5\x8b\x16\x0b\x06\xfb\x22\xb1\x71\x99\xbe\x9d\x14\xc8\xe4\xf5\xbb\x70\x8f\x3b\x97\x9b\x03\x7c\x8c\x2b\x4f\x9f\x53\xa2\xbf\x9c\x44\x4f\xf3\x7d\x00\x1c\xad\xce\x05\x35\x0e\xec\x3f\x84\x5a\x04\xe2\x0b\xc5\xe7\xff\x1e\x07\x1d\xd5\x67\x37\x74\xce\x32\x8b\x0f\xf5\xb7\x58\xa6\x5e\xa6\x43\x56\x68\x18\x88\x99\x1d\x19\x15\x50\x7c\xdd\x23\x83\xfa\x81\x2d\x5f\x0f\xe2\x44\xb3\x0e\x29\xd1\xa1\x2f\x8b\xd7\xcb\x9a\x23\x05\x2c\xec\xa1\x92\x1d\x57\xc5\x10\x7f\xaf\x33\x33\xeb\x87\x01\x57\x90\xc1\xe5\x47\xe9\xa7\x20\x75\x48\xf4\x83\xd4\x84\x20\x3c\x13\x3e\x96\x04\xb4\xc5\x59\xac\xa7\xaf\xd8\xfe\xaf\x9a\x5b\x95\x98\xbf\xf2\x9c\x06\x3e\xd7\x1b\xe7\x1e\x59\x13\x4f\x90\x70\xe1\x63\xc6\x94\x5f\xc8\x90\xc9\xb9\x73\x60\xb9\xfc\xd2\x9b\x1a\x8d\xe0\x85\xcb\xe2\x4e\x52\x0d\xb4\xf7\xb2\xad\x94\xeb\xbd\xfa\x95\x4d\x1e\x1c\x95\x4b\xb3\xf8\x22\xf6\x21\xf6\xf8\xce\xd9\x2f\xa0\x8a\xc9\x6a\x33\x94\x06\xf3\xaa\xab\xaf\x02\xae\xb8\x60\x34\xd3\x3c\x22\xea\x26\x94\x8f\x52\xcb\x96\x3f\xf1\x9d\x49\x90\x88\x45\x6a\x27\xf8\x0d\x50\x05\xfb\x10\x85\xae\x56\x75\x1d\x82\xb2\x22\x1d\x69\xa8\x12\x8f\x1e\x5d\x8c\x08\xc9\xab\x8f\xca\x87\xe6\xa6\x67\x09\xe5\x11\x8b\xe5\x45\x45\xe4\x64\x8d\x82\x3f\x64\xb4\xe3\x98\xae\x15\x10\x30\xc3\xbb\x62\x38\xaa\x51\x08\xe7\xd3\x14\xfd\x84\xd1\x6e\x5b\x74\xb2\xcb\x8d\x17\xe3\xb1\x7d\x63\x4a\xaa\x9e\xed\x4a\x55\x7d\xad\xbc\x29\xbf\x03\xca\xb2\x13\xf3\x2c\x99\x8b\x94\xa5\x38\x58\xec\x95\xd0\x0d\x64\x9c\x6f\x8f\x83\xef\x28\xc9\x11\xea\xab\x6a\x8d\x0f\xd9\x44\x01\x28\xe8\x31\x2e\x12\xa8\xc5\x64\xa8\x94\xa9\x60\x18\x89\x41\x36\x31\xca\x5a\x13\x08\xcf\x8b\x5c\xf9\x84\x1d\x4c\x1d\x27\xe1\x3f\x3a\xd3\x5a\x27\x78\x55\xdb\xa4\x32\x6a\x51\x32\x2e\x6a\xed\x73\x12\x32\xfb\x73\x4c\x42\xcd\x67\x44\x82\xba\xdb\xf8\x83\xc9\x45\x8e\x69\xf8\x4a\x19\xc5\xfe\x3d\x84\x12\x88\x32\xe2\xeb\xf5\xcb\x53\x7a\x34\x51\x3c\x5e\xda\x60\xca\x75\xce\x3f\x1c\xa7\x94\x97\x20\xbf\xe6\xc8\x89\xc8\xd1\xbf\x99\x03\xda\xde\x65\xcb\xed\x15\xbc\x5c\xd3\x64\xa8\x13\xca\x76\x6a\x69\xaa\xae\x16\x45\xba\x96\xae\xb8\x80\xb1\x38\x6f\x31\x29\xc5\x35\x01\x44\x2c\xa3\x97\xc4\x01\x84\x3f\x58\x95\xad\x57\x23\xb6\x6e\xd9\x41\xf3\x82\x21\x3b\x17\xa4\x0e\x53\xaf\x0f\x9d\xab\x97\xb8\xb4\xef\xea\xcc\x0a\xd5\x26\x00\xc2\x93\x75\x9b\x29\x37\x10\x2f\x08\xb1\x28\x39\xff\x76\x82\x1f\x65\xe0\x99\x9e\x4e\x26\x11\xc7\xe1\xa0\xdd\x83\xc9\x67\xbd\xf2\xcc\x89\xcd\x1f\xbd\x14\x57\xd3\xfa\xfc\xef\x24\xd7\x0f\x5e\xed\xee\x6b\xb1\xb6\x99\x35\x07\xdd\x12\x68\x62\x16\x8e\x6a\x7e\x6c\x7d\x6c\x51\x28\x66\x9d\x9f\xfe\x8c\x9f\x07\xff\xdb\xe2\xe3\xf7\x28\xe8\xde\x1e\x62\x02\xfc\x20\x2c\x5b\xc3\xf1\xa4\x4c\xda\x76\x95\x5d\x3f\x1c\x28\x8d\xd1\x54\xdd\xb7\xf5\xe1\x84\xce\xe8\x68\xef\x3b\xf4\x07\xd0\x29\xbc\x0a\x5c\x68\x46\xd6\x23\x63\x78\x0a\x6f\x74\xd0\x12\x56\x82\x0c\x7d\x8e\xa3\x18\x4d\x3b\x5f\x99\xc2\x81\x9f\x2c\x66\x4c\x3a\x9b\x87\x35\x63\x11\xc1\xa0\x0a\x5f\x57\xb3\x85\x8c\x4a\x08\x88\x4c\x6a\xc4\x8d\xdc\xed\x6f\xb9\x92\x46\xac\x62\x95\x3f\xa5\x4e\x2a\xb1\xc6\x02\xb2\xac\xcd\x77\x39\x3a\x53\xd9\xfb\x92\xb3\x28\xfd\xfa\x16\x64\x9e\xf6\x15\xc9\x22\x13\xb8\xe9\xea\xf0\x84\x0d\x48\x11\x53\x69\xd6\xfe\x80\xd0\x62\x3d\xe6\x0c\xb8\x71\xb3\xa8\x5c\x68\xa7\x31\xd8\x08\xa8\xc7\x49\x3a\x49\x2a\x2d\xbe\x4e\x2f\xb4\x75\xf9\xf7\x84\xd2\x12\xb0\x56\x73\x43\x8d\xa2\x73\x29\x3c\x8d\xd2\x68\xf9\xa1\xea\x1f\x7b\xbc\x54\xe4\xf4\xa4\x20\x63\xdb\xd4\x39\x98\x45\x0e\xf0\xc3\x3f\x27\xd6\x50\xde\xcd\xc2\x04\x39\x68\x5e\xdb\x5d\x65\xc4\x4b\x67\x57\x72\x6e\x49\x5c\xa6\xf3\x9f\xef\xb7\x1a\x5f\x70\xb9\x73\xc1\x2d\x13\x5d\x92\x48\x4d\x21\x3f\xf8\xdb\x1b\x90\x4e\xc2\xa6\x4e\x2e\x2c\x8e\xd4\x3b\xc8\xb0\xff\x41\x0f\x44\x25\x9b\x21\x8a\xc1\x4f\x81\xce\xd9\xc9\x19\x41\x6c\x71\x76\x3c\x49\x67\xa7\x23\x92\x61\x28\x4d\xf3\x82\xae\x50\xdc\xfa\x70\x81\x68\xb4\x6b\x14\xa2\x1f\x84\xa9\x4e\xb1\xa6\x2e\x36\x3e\x6d\x02\xc7\xb3\xb6\xbc\x7c\x24\xe5\xfd\x96\x94\x29\x3d\x2d\xd6\x73\x8f\x0a\xe0\x32\x8c\x9c\x51\xf9\x97\x73\x50\xc6\x1b\x1d\xf4\x7c\x14\xcc\xbb\xb1\xf2\x5a\x59\xbf\x03\x47\xd2\x7d\x8a\x28\xee\xcd\x41\x0f\xf0\x1b\x03\xcc\x07\x5f\x2a\x0b\xdf\xa5\xc9\x2f\x57\x4b\xa0\xbc\xc5\xd4\xc6\xee\x82\x4a\x25\x96\xf0\x9c\xd9\xc9\x79\xeb\x2e\x9d\x7b\xfe\x13\x36\x1c\xd2\xec\x2b\xc5\xa2\x10\xf7\x84\xe8\x3c\xd8\x62\xc6\x69\x85\x09\x4a\x65\x59\x84\x7c\x70\x66\x17\x0b\xbb\x44\x67\xbc\xed\x2f\x0a\x5d\xd1\xe1\x91\x53\x17\x44\xbb\x99\xf3\xa0\xb9\x9b\xc9\xb4\x86\x62\x74\x16\xc4\x8f\x01\xe1\x48\x82\x3b\x62\xa4\x5e\xb1\x8f\x32\x7b\x55\x8a\x40\x18\x8f\x06\x7d\x24\x96\x04\x7b\xe4\x88\x04\x0e\x0f\x02\xda\x00\x09\x4f\xbb\x99\x89\x04\x4e\x1f\x3b\xa8\x3b\x39\x6e\x28\x12\x02\x49\x48\x39\x45\x44\x50\x3c\x05\xdb\x92\x38\x7c\x3a\xdc\x8b\x1e\xb1\x45\x60\x1a\x3d\x83\x0e\x99\x59\x64\xc6\x8c\xb8\x26\xfb\x04\x63\xdb\x07\x36\x24\x9a\xa3\xe1\x16\xb3\x82\x80\x7b\xb4\x0a\x3a\x2b\x9f\x00\xd3\x95\x5e\x70\xeb\x6e\x02\xab\x62\x32\x4c\xad\xa2\x24\xd3\xf6\x8a\x6b\x00\x55\xf0\xe1\xdd\xbb\xa0\xc4\xdc\x17\x21\x1a\x3b\x37\xad\xeb\xdf\xd4\xf2\xbd\x65\x21\xcc\x28\x4a\xc2\x4b\x62\xab\x47\x8e\x6c\x0b\x7a\xd3\x72\xec\xa1\x64\x8b\xfc\x7d\xf4\xfe\xe7\xb3\xdc\xec\xcb\x91\x07\x70\xc7\x24\xe9\x1a\xe4\xff\x6a\x6c\xdc\x02\xfd\x50\x04\xfb\x67\x75\x2d\xcd\xe8\x82\x44\x39\x7e\x49\xee\xff\xa5\x85\x8b\x0c\x97\x49\x1c\x5e\x0b\x2d\xa7\xdf\x55\x38\x27\xec\x9b\x9f\x4e\x28\xae\x68\xd5\x0d\xba\x0e\x6a\xe6\xc7\x60\x89\x36\x7d\xf9\x23\x40\x84\x9e\x6d\xe4\x67\xc5\x12\x51\x1c\x7f\xef\x22\x92\x21\x9a\xd9\x55\x89\xcf\xa3\x68\x04\x8a\xf6\x56\xff\xe7\x7f\x62\xf7\x3e\x5d\x5a\x46\x5a\x6c\x01\x17\x77\x2e\xaf\x30\xaf\x3c\x36\x61\x44\x84\x56\x43\x35\x83\xfe\xf9\x2f\x9a\x36\x60\x3b\x1c\xd4\x3c\x5d\x2e\x8a\xef\xed\x05\x92\xfb\xf5\x17\xda\x4d\x80\xdf\x6e\xa4\x58\x1d\x5f\xad\x58\x52\x77\xef\xdc\x88\xa2\xca\xc4\x30\x93\xe5\xc7\xdd\xb1\x90\x87\x92\x24\x1d\xc4\x83\x26\x3d\x76\x9d\x5b\x43\x30\x24\x36\x34\x22\xc7\xb0\xe5\xca\x6f\x06\x4c\x6f\xac\x1b\xc6\x4e\x12\x46\x8e\x76\xf8\xda\x51\x6c\xee\xa3\x30\x9a\x83\xb1\x7c\xf5\xad\xa6\xc3\x17\x2d\x5e\x9b\x81\xf2\x0a\xa5\x01\xce\xe9\x53\x41\xae\x3a\x93\xf0\x0c\x84\x15\x3d\x36\x03\xeb\x3c\x1a\xac\xb1\x2f\x78\x9a\xf5\x39\x7f\xf5\xc6\x39\xb0\x80\x58\x2b\xc7\x60\x74\x0e\xca\x76\x32\x2c\x98\xcd\x5f\x57\xf9\x3f\xc5\x6d\x93\xa9\xc2\x6d\xf9\x5f\x5e\xab\x61\xfe\x3e\x08\xcf\x58\xe3\x8c\xcc\x17\xdf\x62\x84\x1d\xfd\xb4\xb3\x63\xce\x71\xff\x5d\x59\xc7\xac\x12\xb0\xc6\x20\x93\x8f\xa1\xe8\x80\x68\x91\xfd\xc8\xcd\x87\x5a\xcc\xb9\x08\x01\xc9\xc4\x8b\xc3\x23\x7e\x14\xfa\xf2\xaf\x26\xf5\x72\x58\x44\xc6\x3d\xc1\x1d\x9f\xe1\xc7\x20\x76\x53\x13\x28\xa5\x30\x3d\x13\xcd\xf6\x17\x9d\xc2\xd7\xa1\x56\xb6\x6e\x38\xb9\xe9\xe4\x37\x0f\x83\x40\xc0\x3f\x8a\xcd\x84\x32\x30\xd6\x92\x86\xfb\x37\xf9\x08\x9b\x61\x00\xcb\x89\xd0\xa2\xb9\xe8\xdb\x20\x3c\x57\xc3\x3d\xf1\xaa\x69\xe3\x3f\x7f\x8f\x6f\x17\xf9\x79\xea\x8e\x89\x5a\xd2\x2f\x59\x68\x5a\xb4\xaa\xc9\x9f\xb6\xf1\x2f\x7d\x16\x3f\x07\x1f\xd2\xa3\x7e\x76\x34\x34\x81\x14\x84\xfe\xc5\xbe\x53\x99\x8f\x9a\x77\xb2\x07\x88\x49\xc1\x08\x62\xe8\xab\x11\xb6\xf0\x37\x3b\x02\xf6\x98\x9a\x3f\xfe\x68\xd9\xfe\x21\x47\xf3\x88\xbb\xee\x84\xca\x32\xec\x16\x1b\x0b\xe0\x00\x7b\xc2\xd8\x8c\xf1\x2c\x8f\xb5\x60\xd6\x97\x0d\x66\x01\x81\x6a\x9f\x28\x2d\x09\x02\x16\xf7\xb3\x13\xe2\x29\xac\xc3\x08\xaf\xc1\xed\x0f\xc7\xf2\x99\xf3\x56\xbf\x75\x4c\xa5\xe0\x99\x7a\x69\xff\xe1\x0e\x98\x31\xcf\x43\xf2\xf7\x04\x6a\x9c\x85\x7e\x0e\x0d\x85\x3b\x49\xe9\xfd\x91\x1a\x8c\x2d\x82\xd9\x78\xd8\x99\x38\xfd\xe9\xab\xc5\x69\xe9\x44\xfe\xc0\x17\x08\x52\xa4\x58\x97\x38\x4c\x42\x4e\x7b\xa8\xd6\x94\x4b\x7b\x4e\xaf\x78\xa6\x51\xb7\xe0\xb0\xa4\xb7\x46\x04\x6b\x08\x7d\x1d\x42\xe8\x79\xbc\x57\x41\x99\xd7\x39\x4a\x46\xd2\xf6\x82\x81\x42\x4b\x30\x0a\x7a\x45\x6b\x94\xf5\xbe\x51\x83\x1e\x96\x28\x11\xef\xbc\x75\xd2\x91\x8e\x17\xdd\x51\xa8\x5b\xd8\x8f\x79\x12\x61\xd4\x82\x2f\x42\xa5\x9a\xff\xc5\x13\xfa\x7e\x6f\xf6\x2e\x45\xc4\x8d\x54\x07\x20\x3a\xb4\x0a\xd0\xba\x70\x82\x88\xc2\xf5\xba\x77\xaa\x7e\x5a\xa6\xea\x07\x6b\xd8\x27\xa5\xcc\xf8\x0d\x93\x27\xf4\x21\xbe\x96\xc3\xc2\x18\x1c\x1c\x48\x0c\xac\x5d\x9f\x0b\x14\xa0\x89\x1f\x59\x12\x2b\xb9\x78\x58\x0e\xa0\xed\x7b\xe7\x90\x8c\xcb\x46\xb8\x33\x0e\xbd\xcd\x7b\x51\x71\xb0\x70\x18\x15\x49\x5f\xa2\xa4\xb9\x56\x63\x2b\x22\xf2\xb2\x60\x22\x3a\xe2\x4e\x21\xa8\x3c\xb3\x5a\xe7\xf1\x24\x88\x5b\x99\xfb\x49\x60\xca\x65\x41\xa4\x42\x3b\xcd\xe2\xf8\xf2\x99\x31\xec\x3d\xb4\xb0\x0d\x4a\x73\xa2\x68\xf8\xf7\x09\x85\xc6\x99\xc5\x39\x7f\xb2\x54\xd2\x98\x04\x05\x06\x7c\x55\x79\xd9\x44\xd5\x35\x0d\x23\x2d\x0b\xf6\x8b\x2e\x24\xab\x81\xc2\x1a\x20\x9e\x19\x57\xda\xa7\xb2\x9c\x49\xdd\x9f\x91\x2d\x62\x4b\xe9\x64\x19\x97\x95\x0f\x38\x6c\xb5\x81\x29\xcb\x4e\x23\xf6\x69\xe2\x2b\x60\xb9\x2e\x52\x28\x40\x56\xc5\x0d\xac\x2a\xe7\xb2\x71\x8a\x69\x9f\xfb\x53\xa5\x56\x92\x78\x5e\xa0\x0d\x1f\xab\xf4\x2f\x8e\x95\x0d\x4e\x04\x76\xc9\xea\x8d\x03\x6f\xc9\x93\xc1\x0f\x99\x78\xed\x20\xbc\xb8\x4f\xf4\xea\x9f\xa6\xb7\x31\xea\x42\x46\xcc\xb7\xb7\x5a\x21\xed\xe4\x1f\x75\x85\xc3\x75\x1d\x8b\x99\xcb\x88\x8a\xfb\xd2\x97\xad\xe9\x7b\xbb\xb4\x75\x53\xa7\xdc\xaa\x0c\x81\x19\xb3\x0f\x8d\xe5\x7c\x84\xd8\xf8\x4c\x9d\xd9\xd2\x26\x3f\x8b\x94\xfb\xc3\x24\x8a\xfa\xcd\x48\x39\x08\xe8\xbe\x4b\xf3\x7a\x3a\xae\x5a\xb8\xbd\x62\x31\x42\xcc\xc2\x1c\x9c\xf8\x2e\xaa\x96\xca\xc5\x8f\xbc\x4d\x0c\xef\x2f\x95\x8c\x8d\xdf\xa8\xa8\x8c\x28\x9e\xca\x32\x2d\xaf\x91\x05\x33\xd0\xc5\x6e\xb1\x37\x96\xf0\x7f\x69\x74\x09\x49\x7c\x4b\x7f\x79\x5a\xa2\xb9\xf1\x15\xd5\x17\x4e\xa3\xe0\xb0\x2e\x26\x85\xd4\x64\x8d\xd8\xf1\xd4\xa4\x65\xd5\xd2\x3e\x73\x09\x96\x9b\x89\xd3\xe3\x73\xb8\xac\x94\x23\x2d\xa3\x6e\xd1\x61\xec\xfd\x47\x4d\x6e\x3f\x8e\x02\xf1\xf3\xb7\x17\x19\x04\xd3\x55\x0f\xd8\xd2\xf8\x40\x86\x66\x7f\x17\x9a\xbb\x3a\x68\xcb\xe0\x08\xbb\xc3\xe2\x58\xce\xbf\x15\x69\x77\xf1\x46\x28\x61\xed\x54\x98\xf9\x02\x20\xf8\x21\xba\xe8\x9f\x8e\x14\xc1\x78\xe8\x18\x0f\x1f\x86\x43\xf9\x56\x22\x76\x53\xb8\xab\xe1\xa8\xb6\x45\x98\x5b\x80\xc2\x23\xec\xaf\xc6\xcf\x13\x47\xda\x4e\x5e\x04\xa7\x56\xe4\x53\x2d\xef\x89\x1e\xc5\x5f\xf3\x3b\x8d\x0f\x41\x81\x44\xb6\x44\x2f\x16\xc3\x33\x34\x3c\x3c\x01\x79\x09\x35\x78\x6d\x22\x12\x59\x7c\xb9\x42\x0c\x9e\xe3\x05\x81\x0f\xa2\x9d\x68\x07\x0b\x9f\xe0\x55\x2a\x58\xcf\x6c\x9f\x86\x5a\x4d\xfd\x33\x62\x89\x5e\x7b\x97\x5a\x24\xd3\xd5\xcd\x40\x9d\x12\x8f\x6c\x8c\x6a\x69\x29\xc5\x72\xa2\x9e\x50\x20\xcc\x4a\x22\xf6\x76\xe5\x8b\xc3\xb5\x07\x19\x82\xca\xc0\x77\x9a\xe2\x54\x6a\x38\xdb\xef\xaf\xdf\x47\x99\xf0\x28\xc9\x9e\x15\xa5\x2c\xec\x24\x52\x23\x0e\xbf\xc9\xcd\x1a\xe4\xc2\x88\x70\x89\x0a\x66\xe1\x82\x49\xf2\x48\x8f\x8b\x1b\x0f\xef\x45\x35\xef\xec\x83\xe0\xcf\x21\xfe\x99\xc7\xa9\x98\xc5\x29\xe0\xb2\x96\x91\x4c\xe8\xdc\xc5\xf3\x23\xbb\x12\x83\x63\x2e\x97\x2d\x17\x08\x92\x51\xf9\x54\x9e\xcf\x0f\xa4\x4d\x6f\x9c\x4f\x01\x02\x06\xc2\x13\x84\x31\x1c\x4b\x27\xb2\x89\x6f\xca\x52\x49\x43\x51\xef\xfb\x21\x27\xbd\x4d\x6e\x57\x19\xb5\xf1\x0e\x47\x32\xbb\x0a\xa1\x59\x3d\x0b\x18\xc2\xfe\x69\x59\x86\x45\xf7\xa7\x7d\x8f\x1b\x4e\xf1\x1c\xe2\xc2\xd7\xe8\xa8\x78\x34\x1f\x8e\xdb\xfb\x81\xb6\xdb\x83\xad\xc3\xfd\x1e\x47\x42\x29\xee\xd9\x20\x94\xa2\xbf\xdb\x79\xc4\x0a\xe6\x1e\x55\x29\x78\xdb\x4d\x91\x74\x12\xfd\x13\x48\x4b\x67\xb1\x96\x0a\x80\x29\x8f\x4a\xda\x3d\xb3\x44\xe8\xce\x3e\xe6\xac\x44\x39\x4e\x27\xb7\xb1\xbc\xc6\x33\x0b\xb3\xd4\xae\x7c\x87\x00\x82\xe7\x50\x71\xa1\x52\xdd\x37\x05\x81\x32\x2c\x93\xaf\x57\xf3\x2e\x10\x12\x12\x5f\xbe\x6a\xae\x25\xa4\x69\xea\x14\x00\x8d\x9c\xe3\xc6\xe8\x9e\x11\x72\xdd\xba\xfb\x86\x1d\x62\x91\x46\x2e\x8f\x65\xd3\x5b\x52\x50\x18\xb3\xbd\xdc\x56\x58\xd3\x52\xd9\x78\x68\x93\x15\xfd\x3d\xe2\xf4\x9d\x45\x0d\x86\xf4\xdd\xb4\x39\x7c\xd4\xb2\x5a\xf0\xd8\x02\xd1\xe7\xbf\x12\x74\x20\x8b\x50\x17\x2a\x24\x61\xb3\x71\x7d\x2d\x16\x1a\xb7\x42\xdb\xd9\x9e\xb7\xf8\xc4\xbe\xc4\xe2\x9b\x49\x88\xc4\xfd\xee\xa3\xa9\x2b\xa2\x0e\xc8\x35\x75\xf7\x06\x73\x05\x1f\x49\x9a\xc3\xf1\xa3\x0e\x15\x9b\xb0\x98\x38\x5e\xa5\xf7\x6c\xa5\xe2\x21\xd3\x6f\x06\xb7\x68\xd4\x57\x58\xca\xe7\x14\xf7\x23\x42\xa0\x6e\x83\xc8\xc8\x36\xb6\x5d\xf5\x42\xfa\xb3\x16\xbe\x71\x67\x73\x67\x24\xd1\xaf\x7d\x4f\xcf\xe1\x0f\x0e\x8f\x98\xe2\xf7\x89\xef\x1c\x4e\x39\xca\x91\x9b\x0e\x64\xed\x57\x0e\x76\x45\xe4\xa1\x8d\xf6\x22\x23\x17\x8c\x54\x56\x1c\xbb\x2f\x94\xf8\xec\xe5\x73\xcf\x05\x63\xd3\x8b\x93\xf3\x34\x4c\x56\x46\x91\xc9\xb4\xb5\x1f\x31\x77\x9b\x7f\x9d\xe2\x89\xcd\x8d\x01\x56\xeb\x95\xaf\x5f\x53\x29\x32\x35\x89\xbd\xa9\xe4\x94\xca\xee\xa3\xf5\xb6\x04\x4e\x3e\x80\x23\x41\x63\xe5\x24\xe8\xe8\x8a\x34\x62\x5b\x9e\x15\x18\x75\x0c\x72\xb7\x65\x8d\x85\x55\xd0\xb8\x71\x3c\xe8\xd5\xc7\xc3\xac\xf8\x42\x1e\xc1\x8d\x25\x0b\xde\x05\x88\x3e\xfd\x91\x54\x94\x22\xe1\x97\xbe\x88\xa6\xcb\xd6\x17\x33\xb3\x4d\xef\x5f\x73\x3a\x41\x9f\x31\x2d\x0d\x7c\x1f\x4b\x74\xde\xa4\x4a\xe3\xbd\xd8\x54\x3d\xe6\x22\x7e\x54\xe0\x75\xa9\x52\x53\xdc\x43\x12\x1c\x15\x39\xe5\x16\x3a\x39\x70\xd8\xd7\x02\x33\x09\x3a\x53\x86\x68\xfa\x42\x5a\x56\xe2\xd5\x33\x1d\x55\x1b\x47\x78\x9d\x60\x89\x05\xca\x50\x62\x8e\xdd\x30\x24\xb6\x86\xa5\xeb\xb9\xaa\x53\xb7\x85\x4f\xb7\x22\x40\xa5\x3e\x33\x38\x11\xf9\x8c\xd7\x4b\xa6\x58\x75\x7d\x34\x6a\x29\x7e\x2d\x61\xa2\xf3\x1a\xec\x05\x6f\x82\x7d\x8d\xc2\x86\x73\x04\x0b\x9b\x81\xcc\xa6\x7d\x2e\x65\x75\x16\xb5\x62\x94\xd0\x16\x06\x44\xcd\x58\xea\x5f\x54\x85\x9c\x89\x2a\x0a\x27\x00\xa8\x18\xd7\x46\x76\x45\x2d\xe5\xa6\x06\x5e\xca\x60\xa5\x8a\xfc\x08\x49\x70\x45\x50\xd4\xd6\xa2\xa7\x6f\x5f\xb8\x71\x39\xc2\x5a\x8e\x4a\x26\x58\xa2\x41\xe7\xe1\xd3\x9a\x2d\x44\x06\xff\x60\xcb\x7f\x97\x2c\xc7\x09\x47\xfb\x68\x2a\xdb\xcf\xd9\x7f\x64\x01\xac\x71\xbe\xb0\x3b\x23\xba\xb3\x42\x26\xeb\x52\xdd\xd4\x84\x96\xad\x9a\x77\x25\x9e\x71\xd5\x4e\xe9\x56\x5f\x1b\x52\x7e\xb1\x93\x35\x5f\x09\x31\xcd\x67\xc6\xf5\xcc\xb3\xd3\x44\x7b\xa7\x7a\x3c\xe8\x2a\x38\xe4\x4e\xe5\xf9\x86\x44\xe1\xa7\x15\x7e\xf1\x0c\x1d\x85\xa4\xb3\x31\xa5\x8f\xa0\x86\x53\x4e\x8b\x46\x89\xf5\xa5\x4f\xd9\x21\x1c\x1b\x72\x7c\xf4\x63\x25\x6a\x11\x27\x61\x01\xdf\x15\xdf\x53\x75\xae\x08\xbb\x6d\x04\x06\x0d\xb1\x9f\x7a\x93\x72\xea\x65\x2a\x9b\x41\x06\xbd\xbb\x9e\x5b\x9f\x5e\x80\x0d\x46\xae\xbe\x39\xda\x89\xc5\x82\x82\xd8\xa5\x1d\x3d\x3a\xa5\xec\x88\x47\x6e\x81\x0b\xcc\x65\xd7\xda\xf9\xca\x22\xeb\x2b\x38\x8d\x23\x49\x67\xf0\x02\x23\xeb\xc0\x84\xf1\x33\xd7\x2d\xe9\x75\xe8\x9c\xc8\x58\x39\xda\xff\xe3\x2d\x98\x76\xa9\x01\x91\x45\x52\x84\x0c\x91\x5d\xe8\xb3\xd2\x5e\xec\x99\x14\xbb\x17\xb6\xcc\xb8\x04\x52\x0d\x6e\xd5\x5a\xb5\x54\xc0\xa6\xf4\x6d\xb5\xd4\xf8\x6b\x1e\xa3\xd5\x6a\x70\x25\x80\x86\x60\xe1\xca\x0a\x8e\x7a\x70\x01\x27\xc5\xb2\x27\x29\xaa\x8e\x74\x5a\x0d\x39\xe6\xa3\x49\xd7\xc6\x5f\x72\x8f\xaa\x8a\x88\x96\x65\xf6\x19\xf2\x20\x30\x58\xe0\xc0\x94\x7f\x15\xd3\x4d\x31\x9c\x8c\xa4\x26\x8f\x96\xc0\x99\x78\x28\xe9\x38\x76\xc5\xe2\x36\xa3\x0d\xa7\x19\x8a\x72\x64\x77\x4b\x1d\xf4\x43\x34\x99\x0d\xbc\x53\xcc\x57\xce\x0b\x37\xd7\x31\x61\x7a\xf7\x5e\x97\x91\xb7\xb3\x43\xee\x06\x58\x43\xc2\xdf\x44\xa1\xea\x89\x1d\xa2\xe9\x81\xd9\xf1\xe2\x3c\x83\xe9\x2c\xa3\x85\x9b\x8d\x7a\xa1\x6f\x7e\xfc\xce\x39\x52\x9d\x93\x30\xb9\xd1\x99\x49\xa6\xe8\x63\x7d\x10\xa7\x27\xcc\x8a\x79\x26\x29\x9a\x23\xbc\xde\x35\x59\xf1\x01\x26\x3e\xae\x71\xec\x36\x6f\x41\xc2\xa1\x04\x1c\x17\x76\x47\xf5\xbe\x37\x55\xd4\xeb\xe9\xa3\x1d\x37\xbd\x18\x77\x9b\x70\x25\x49\x3c\xc3\xc4\x01\xd9\x99\x15\x7c\xb5\xc0\x97\x64\xcb\x49\xfe\x29\x92\xa8\xc9\x70\xdc\x8e\x0b\x79\xf4\xf2\xe4\x97\xec\xe3\xd6\x65\x45\xf4\x23\x9d\x67\x9b\xdd\x30\xd7\x4a\xe2\x53\x39\xe4\xf8\x37\x83\x74\x34\x82\x22\x68\x30\xe7\xcc\x7c\x35\x13\x89\x56\x92\x1b\xd2\x88\xb0\x66\x06\x7a\xcd\x89\xc2\xf7\x03\xab\x36\x64\x38\xf9\x69\x2e\xb0\x94\xe7\x2f\xe4\xb5\x7f\xc5\x7c\x11\x41\xe2\xbf\xd0\x8c\xa5\x16\xa1\xfb\x8f\xd0\x2d\x4e\x1e\x9d\xc4\x50\xef\xa0\x82\xbf\xa6\xda\x56\xc8\x2a\xd4\x6c\x3f\x50\x65\xb2\xc1\x55\x67\xfd\x9c\x21\x17\xa0\xe0\xbe\x4f\xfd\x05\x9b\x6e\x80\x90\x74\xd8\x82\xac\x8b\x50\x74\xd2\xbf\x98\x9e\x22\xc9\xb9\x98\x44\x15\x01\x07\x7f\x2b\x4c\x5e\xac\xcb\x91\xff\x13\x7c\xe7\x0e\x61\x6f\x96\x1a\x41\x1c\xf9\x12\x92\x72\xbf\xc5\xec\xfc\x8f\x6d\x3c\xe6\xcb\xf7\x2b\x24\xe5\x30\xa2\xa6\x12\x46\x12\x9d\x2e\x72\x3a\x33\x37\xfa\x61\xf7\x84\x4c\x4b\xe8\x07\x1b\xf0\x11\x0c\xa7\x1f\xe8\x6a\xaf\x98\xcb\x4a\xa9\x0e\xfe\xe2\x71\x36\x19\x13\xca\x01\x18\x0e\x11\xef\xff\x01\xd7\x4b\x4a\xe2\xa6\x31\xb7\xc1\x83\x78\x1f\xbc\x35\x1e\xaa\x9b\x4d\x70\x01\xa3\x86\x95\xf1\xfb\x10\x8d\xef\x9f\xeb\xfb\x7a\x59\xf8\x1b\xd2\x58\x5b\xae\x71\xe9\xde\x77\xba\x44\xfb\xe5\xf6\x05\x09\xee\x77\xc2\x22\xf4\x1f\x68\x7b\xa4\xd1\x3e\x49\xb0\x70\x68\xba\x25\x01\x93\xd1\xae\xbe\xb4\x8e\xfe\x80\xd4\x03\x9d\x11\xb0\x9c\xf8\x79\x5c\x63\x52\xd4\xa5\x99\x19\x0a\x17\xf1\xce\x08\x82\x49\x98\x1c\x4c\x81\x43\x81\x83\x97\x86\xd7\x15\x62\x91\x7f\x85\x4a\xae\x40\x4c\x84\xca\x52\xbb\x37\xb1\x40\x8b\xb9\x22\x38\x9f\xc7\x98\x1c\x14\x42\x33\x36\xb5\xac\x73\x32\x69\xf3\x52\x37\xde\x80\x1c\x3a\x86\x09\x7b\x83\xfa\x8c\x67\x83\xc9\x16\x8b\x19\x0b\x49\x83\x83\xa1\x6f\xa5\x97\x94\xcb\x05\xdc\x8c\x0d\x51\xb8\x1c\x08\xb0\xd2\x51\x6f\xda\xf8\xb4\xc4\xc4\x45\x8a\xa1\x5a\x21\x95\xaa\xdf\x57\x1f\xda\xcb\x24\x96\xb2\x86\xaf\x17\x55\xe0\xc9\x48\xb1\x63\x5c\xbc\x43\x71\x4e\x4f\x79\x5d\x45\xf6\x7e\xb9\xde\xd1\x94\x15\xfd\xe2\xd8\x5d\x20\x13\x2c\x72\x44\xb4\x28\x2b\xfa\x0a\x59\x84\x54\x86\x46\xa8\x30\x74\xa0\x23\xc8\x3c\x7d\x91\xf4\xb8\x65\x6e\x62\x75\x00\x3f\xfd\x07\xbb\x1c\x25\x99\x52\x54\x36\xdf\x2d\x05\x7d\xf6\xe5\x74\x85\x6e\x5d\x70\x84\x60\x68\xff\xad\x7b\xa8\xd7\x91\xde\x84\x4d\x42\x4c\x29\xa5\xed\xfc\xed\x13\x1a\x39\xc7\x46\x60\xf4\x1d\x48\x38\x21\x01\xf3\x8e\xb6\x7e\x8a\x83\x74\x48\x97\x28\x0f\x18\x20\xce\x9d\xe7\xa3\x56\x44\x46\xa6\xc2\x2b\x4a\xa2\x52\x16\x86\x1a\xd1\xc6\x79\x52\xa3\x54\xa4\x96\xd7\x4b\x89\x08\x3a\x5f\xd0\x39\xf4\xeb\x5d\x4c\x61\x28\x52\x77\x2a\xd2\x69\x6d\x49\x8c\xad\xb6\x3c\x06\x64\x7e\xdb\x60\x0d\x6e\x2a\xe1\xb7\x10\xc8\xf9\xbf\x2d\xe2\xc0\xfe\xd0\xa7\xf4\xc4\x29\x41\x88\xe6\x46\x82\x8d\x5d\x54\xce\xfe\x93\xcb\xab\x88\x11\xac\xc8\x72\x85\xbe\xcd\x2d\x26\x85\x72\xbc\x75\x9d\x6c\xed\x7d\xfb\x89\xe3\x12\x5f\x86\xc2\xfc\xaa\x80\x6a\xd8\xa4\xd1\x80\x14\xbb\x43\xd6\x2c\x0c\xb0\xd5\xc0\xcf\x6a\x85\xbf\xd5\xda\x5d\x42\x0e\xf0\xcb\x0c\x74\x13\x0f\x7e\xc4\xca\x53\x31\x5e\x30\xa8\x71\x9e\x20\xd4\x8c\x5b\x3d\x70\xdd\x9e\x0f\x85\x9b\x35\xbe\xab\x9c\xe1\x79\x60\x54\x66\x39\x17\x97\xec\x21\xab\x2b\x4d\xee\x4b\x98\x3f\x43\x58\x2a\x4c\x9e\x4d\x9f\x4e\x87\x34\x0e\xc6\xf1\xfb\x6b\x9f\x48\x9d\x0c\xaa\x15\x0f\xa7\xdd\xdb\xf3\xa3\x7f\x3d\x17\xc4\x0e\x66\x53\x57\x0b\x7e\xd5\x2b\x5d\xef\xf9\x79\x7c\x86\xc6\x6a\xd8\x57\x08\x06\x85\xf8\x8f\x50\x40\xfd\xe5\xc9\x49\x52\x0b\xf3\x9d\x3d\x94\x79\x6f\xb8\xbc\xca\x39\xd6\xb5\x19\xac\x02\x86\xae\xa6\xcb\xe9\x86\x50\x23\x21\x5d\x5a\xb0\x13\x63\x9d\x31\x50\xae\x96\xba\xcb\xd5\xb1\x88\x55\x22\x59\xb2\x63\x48\x73\xb1\xe8\xbb\xa7\x7d\x76\x91\xa4\x4c\xac\x97\x2d\xe0\x04\x62\x49\x71\xb1\xd1\x4c\x3b\x8c\x52\x23\xf4\x01\xf9\x4a\xd1\xb6\xde\x20\x89\xf7\x72\x1c\x86\x0d\x00\xa6\x72\xa3\x8c\x4d\xf4\xf0\x30\x96\x47\xf5\x2c\xa0\x89\x6d\xca\x89\x1d\x36\x1d\x5d\xe5\x39\x38\x5f\x28\x58\x30\x33\x0f\x9c\x19\xeb\xb3\x91\x05\x1a\x46\xc8\xa3\xec\x30\x4e\x23\x8a\xc6\x27\x22\xee\x39\xb6\x78\x37\x0d\xa9\x67\x88\xbe\x2e\x60\xc0\x8b\x24\x1f\x9f\x0c\x1e\xff\x23\xa8\xd0\x4a\x9a\xbc\x62\x4f\x97\x4e\x24\x21\x79\x6d\x98\x06\xbf\x8f\x8e\xfe\x04\x47\x74\x48\x82\x40\xa5\xce\xd5\xeb\x36\xb2\x6f\x7c\x6e\x26\x73\x60\x21\x01\x8a\x21\x33\x3f\xb9\x4a\x02\x64\x92\x0a\x9b\x5b\xba\x15\x19\xc1\xaa\xbe\x9a\x4a\xb0\x60\xd2\x13\x9a\x33\x4e\x5d\x82\xdf\x0d\xe4\x12\x42\x33\xd6\xa5\x88\x67\x73\x26\x9d\xec\x3d\x12\xb6\xe5\xf0\x34\xd6\x46\x90\x98\x6f\x26\x86\xfb\x57\xe3\x1e\x5f\x12\x92\xad\x17\x36\x29\x3e\x98\x97\xa6\xfd\xa0\x6f\xc3\x3f\xe2\xd9\x8c\xa1\x76\x19\x7e\x9f\x0d\x36\x81\x49\xa8\x85\x36\x1d\x48\x7b\x6b\x37\xe4\x2c\xea\x3e\x93\x8c\x6a\x79\x3c\x0c\xc0\xc3\x41\xd7\xc7\x2d\xfe\xde\x57\xa7\xa8\x9b\x5e\xed\xd8\xb0\xe4\xeb\x91\x6a\xec\x8d\x95\x1d\x99\xf6\x74\x22\xb1\x7f\x2e\xa6\xdb\xa4\x97\x0d\xbe\x82\x74\x64\x15\x11\x72\x88\x64\x67\x57\x92\x1d\x64\x95\x84\x22\x97\xc2\x51\x6b\xb5\xc5\x0f\x33\x01\x63\x80\x7b\xd1\xc5\x4c\x98\xfb\x1b\xc4\xdf\x9c\x25\x18\xae\x75\xf7\x2f\xc1\x76\xf3\x28\xf0\xb9\x76\xae\x3c\xe7\xf3\xe1\x98\x1e\x42\x97\xe0\xde\x1b\x03\xcc\xcb\x8d\x48\x79\x4c\xde\x06\xef\x19\xae\x79\x4e\xf4\xbd\x50\x8e\x16\x43\x58\x59\x10\x16\xa6\x39\xe1\x1c\x4b\xeb\xf4\xc3\x65\xa8\x35\x9d\x27\x7a\xaf\x6d\x3d\xc4\xf7\xf0\x71\xe1\xa1\x06\xda\x1a\xdf\x57\x6f\x74\xa8\xac\xe4\x1c\x16\x3e\xfd\x1b\x09\xa6\x4c\x09\xdf\x0a\x7d\xbd\x8e\x63\x28\xed\x5f\x4a\x3e\x43\x5a\x7c\xae\xe5\xba\x07\x8a\xa7\x5b\x0e\xa6\x5d\x4c\x79\x9b\xc7\xa8\x20\xbf\x67\x62\x57\x51\xa1\x3a\x2a\x79\x5a\x61\xe1\x1a\x30\xab\x21\x28\x8b\xf0\xc7\x62\x61\x6f\x60\x8f\xfc\x33\x59\xaf\x96\xd1\x76\x74\x5e\x26\xa4\x54\x77\xc7\xdf\x30\x77\x37\x66\xa8\x4e\x3a\x09\xd6\x00\x87\xf8\xc7\x54\xfd\xe7\xbd\x1d\x5c\x7c\xdd\x90\xce\xb2\x64\x8f\x6b\x56\x30\xdb\x5c\x2a\x58\x86\xad\xe2\xaf\xf8\xa1\xa8\xdc\x4c\x49\xb0\xe8\xa3\x09\xb3\x3d\x1d\x68\x9c\x0e\x97\x7d\x94\xb8\xad\xf4\x3a\x66\x2b\x74\xa7\x3f\x5f\x15\x81\x38\xeb\x75\xae\x0e\x4e\x45\xf2\x9e\x0c\x46\xb4\x0c\xeb\xca\x74\xee\x82\x82\xbc\x1f\x12\x01\x38\x4a\xb0\x93\xd3\x30\xff\x25\x9b\x22\x3b\x32\x1c\xdd\xee\xf1\xaa\x57\x16\xba\x5d\xa0\xad\xc6\x55\xa2\x0e\x86\x3f\x8a\x8d\x12\x6f\x85\x0f\x30\x73\x7f\x31\x30\xd7\xaf\x9b\x07\x17\x7b\x13\x85\x37\x62\x8a\x69\x15\xb8\x00\xef\x0a\xac\x36\x83\x83\xa2\x25\x4a\xca\x2d\x2e\xbf\x33\xd9\x19\xb5\xce\x4a\x7e\xe8\x81\x6b\xb2\xff\x6d\xa9\xe2\x56\xd3\x8e\xbf\x99\x3e\xb8\xf1\x26\x77\xe2\x25\xbb\x6a\x43\x38\xa7\x05\x52\x74\x96\x48\x71\xd1\x5e\x4e\x76\x2e\xa6\x90\x2e\x27\x8a\x37\xf3\x10\x5e\xc9\xdc\xa3\x55\x62\x66\x5e\xff\x20\x83\x78\xa0\x37\x14\xef\x79\x14\x62\x57\x0f\x5d\x3f\x05\x8b\xca\x3c\x7b\x72\x50\x98\xd7\xbe\x2f\x72\xfc\x9e\xa7\xc0\x24\x43\x7e\x10\x21\xa6\xb6\xeb\xcc\x8a\x51\x2c\xfb\x13\xac\x58\xbb\x90\x3b\x25\x83\x81\x79\xd2\x30\xb9\xad\x3f\x90\x4e\xad\x9d\x74\xa3\xd3\x99\x4c\xef\x03\xa8\xa9\xac\xcf\x0d\xc3\x0e\x7a\x74\x31\x9a\xa3\x94\xda\xfe\xc2\x1f\x8b\xe3\x3e\x8b\x0a\x28\xd4\x0d\x63\xc0\x31\x73\xc1\x5a\xff\x93\x93\x2c\xd6\x0b\xf5\xbd\x92\xf6\x88\x03\xe9\x29\xb6\x45\x6e\x32\x77\x16\xe3\x43\xad\xf8\x5b\x9f\x72\x48\xb2\xaf\xf8\x03\x61\xa3\x50\x50\x11\xf6\x09\x3c\x02\x39\x7b\xec\x08\x37\x6d\xa6\xb8\xe2\x66\x2a\x8d\x68\x7e\x75\x53\xe8\x32\x24\x99\xc8\x2d\x47\x05\xcb\x08\x24\xd9\x3f\xa4\x97\x8a\x2c\x8e\x41\x41\x8c\x65\x88\x3d\x22\xba\xa6\x86\xcc\x7f\x21\x28\xc3\x7c\x20\x63\xa7\x03\x9b\x70\x87\x18\x1a\x82\xa7\xf6\x9b\x6a\x09\xd8\x0b\x4f\xf0\x6f\xed\x23\x3d\x72\xf3\xae\x43\x5f\x4e\x94\xf3\x4c\x17\x6d\x2a\x6e\xe1\xd4\x7d\x0b\xe9\x2d\x65\xed\xeb\x79\x54\x2b\x3b\x6b\x40\xb7\xa9\xb8\x11\x50\x31\x81\x3e\xbe\xc1\xa0\x71\xfd\xce\xcb\xc4\x54\x4d\x4b\xf6\x3d\xc3\x3a\xc5\x12\x6d\x91\xde\x90\xe7\xf4\xab\xa2\xb4\x92\x7b\x95\x81\xc2\x2b\xe6\x1c\x8f\xb1\x1a\x3f\xf1\x6a\x28\x85\x0b\xc2\xcb\x23\x0d\x9c\xbb\x3f\x22\x2c\x52\xef\x54\xd6\x94\xad\xc9\x5e\x1b\xa3\x28\xa7\x5b\x34\xfb\x6b\xcf\x1b\x88\xfa\xd7\xe0\x7d\xdd\xbb\xe9\xd4\xb7\x3a\x33\x0f\xd8\xcf\x37\xa7\xf6\x53\x72\xa6\x10\xb6\xee\xc6\x7d\x87\x84\x8e\x27\xc3\x83\x0c\x57\xb3\xc1\x94\xe3\xfc\x6f\xbf\x11\x30\xb5\x52\xb4\x84\x6a\xf1\x30\xb5\xe3\x05\x96\xfe\x9a\x28\xf7\x16\xe9\x94\xaa\xe0\x0b\xbe\xce\x0a\x5d\xd7\xf0\x70\x35\x43\xd5\xf5\xd7\x24\x0f\x19\x73\x55\x07\x51\x23\x2c\xa4\x4a\x9d\x36\xad\xca\x90\x45\xa0\x17\xd0\xac\x59\x73\x40\x4b\x69\x84\x51\x22\x2a\xa7\x5c\xbe\x5c\xcf\x93\x3b\x06\xff\xfd\x45\x22\xf3\xd1\x9a\x1b\xe7\x19\x11\xbc\x30\x87\x46\x19\x40\x56\xae\x74\x14\x11\x7a\x48\x9e\xfc\xac\x7e\xd7\x11\xe4\x80\x05\xe9\xcb\x8e\x7f\x9e\xa3\xef\xea\xb5\xcf\x64\x61\x4e\x0c\xaf\xdc\x34\xad\x38\x63\x63\xb8\x41\x23\x9b\x4b\xd5\xe1\x8e\x1e\x3d\x69\xb9\xb2\x2b\xda\x20\xc0\xf9\xb5\x3b\x05\x8f\x15\x79\xdd\x4a\x72\x8a\xe8\x93\x36\x46\xf7\x74\xbe\x28\x09\x13\x42\xfd\xa8\xac\xde\x9f\x27\x64\xc8\xc6\x42\x73\x1e\xc8\x6f\x59\xa2\x80\x65\xa3\xb6\x9e\xd0\xa1\xbd\x21\x9c\x6e\x02\x14\x60\xa2\x0c\xd2\xc9\x24\x22\x91\x19\xc1\xc3\xc7\x9c\xca\xd2\x53\xd1\xdc\x36\xf6\x11\x74\x19\xf7\xaf\xdf\xa4\xd1\x71\xc4\x7e\x57\xaf\x55\xc9\xa7\x44\x40\x05\x1b\xe6\xea\xe0\x28\x41\x5f\xbf\x89\xfd\x0c\xe3\x99\xdb\xc0\x39\x79\x3a\xac\xbf\x52\xbe\x69\xc5\x37\xfe\x5e\xad\x20\x69\xaf\x41\xd5\x22\xd0\x63\x5c\xc0\x72\x4e\x7c\x64\x06\x0a\x71\xc8\x25\x16\x2b\x90\xf0\x4a\x37\xdc\x2a\x47\x54\x2d\x39\xef\xc5\x88\x79\x5d\xec\x5a\xd9\xdc\x48\x0f\x27\x4a\x89\x55\xaf\x4a\x21\x25\x61\x45\x52\xb9\xb7\x7c\xe6\xec\x35\xae\x85\xa7\x3c\xc8\xa5\xaa\xd2\x25\x72\xe1\x82\x92\x4d\xcb\xe8\x81\xaf\xfc\x57\x4e\x15\xf2\x61\x7e\x63\xba\xf2\xf4\x22\xc3\x50\x41\x67\xf2\xce\x75\x2c\xe7\xf6\x84\x37\x8c\x79\x86\x62\x8f\x4a\xc3\x6f\xe5\xd6\x5e\xab\x0b\xe5\x8d\x19\xa8\xfb\xe8\xc7\x77\x66\xde\x4b\x52\xbb\xb4\xec\x49\xde\x2c\x3c\x67\x8f\x6e\xef\xd8\x2f\x6d\x39\xa3\xcb\x28\x9a\x03\x59\x76\x7a\x5f\xbd\x98\xd7\xe1\xa4\xe5\x76\x26\x4e\x87\x82\xf5\x18\x61\x7f\xef\x1e\x26\x76\xbe\xef\x41\xb3\x65\xf6\x44\xb8\x7a\xc4\x76\x5b\xd1\x5e\x61\xfb\xcb\x2a\x23\xfe\x22\xae\x52\x36\xfe\xf6\x22\x41\x49\x49\xb1\xc4\xeb\x40\x74\xea\xb6\x3c\x72\x4c\x3d\xa6\x4a\x43\xcc\x00\x3f\x25\xd7\xc8\x04\xe7\x5c\xcb\x0d\xdc\x7c\x08\xc1\xe6\x3e\xc2\x6e\x2b\x2a\xa7\x76\x34\x0d\x07\xd9\x3f\x3d\x83\xaa\x54\xc5\x08\x23\x80\x65\x65\xc5\xa0\xba\x3b\xed\x98\xc2\xe8\xf3\x41\xed\xc8\x31\x5c\xb6\x28\x93\xd9\xfc\x7a\x93\x92\xbb\x5a\xbd\x0f\x55\x72\x14\x7c\x96\xce\x89\x85\xc0\x87\x87\x83\x9d\x40\x43\x76\x32\xf1\xa5\xe2\xad\x96\x08\xe5\xfb\x64\xac\x58\xc8\x82\x51\xd6\xb7\x02\xce\x50\x65\x27\x90\xaa\xdb\x03\xcb\xdf\x7a\x14\x4f\xd1\x33\x31\x29\xad\x99\x08\xc7\xdd\x58\x63\x43\xac\xc3\x3a\xca\xce\x21\x38\x09\x45\xc6\x11\x50\xb1\xf5\x16\x4e\x5e\x68\x54\x08\x7f\xd7\xd7\x3f\x7d\xc6\xd6\xa6\x86\xab\x8a\x04\x4d\x68\x0d\xb5\xf4\xce\x17\xc3\xeb\x11\xf6\xbe\x3a\x76\xa9\x59\x93\x11\xd1\xaa\x8c\x9f\x23\x47\x2e\x5d\x36\x0a\xbd\xf0\x0a\xb5\xd3\x7d\x65\x21\xec\x50\x98\x2f\x9f\xea\xac\x36\xc1\x20\xda\xad\x02\xce\x96\x78\x07\x0c\x55\x8b\x45\x2c\x90\xca\x11\x5a\xd8\x9a\x4f\x21\x32\xa5\xf5\xde\x6e\x8c\x41\xd6\x5c\x5d\x63\xb7\xc5\x2c\x89\xef\x66\x3a\xe4\x2f\x92\x55\xaa\x79\x9d\x39\x2e\xf9\xb5\x47\x07\x05\x71\xca\xd0\x4b\x0e\x42\x8c\xd3\x97\x1a\x51\x63\x33\xa9\xa5\x24\x1f\x76\x68\xb3\xca\xa6\x5f\x60\x63\x19\x5a\xcb\x74\xc9\x51\x3d\x87\xf5\xf9\xe1\x08\x3a\xc8\x40\x0d\x04\x07\xb8\x41\x87\xd0\x2f\x92\x72\xf1\x18\x26\x97\xb7\xc6\x11\x8d\xd5\x4d\x52\xe8\xf3\xdb\x14\x1d\xbb\x4c\xcb\x67\xea\xf7\xc1\x7f\x5c\x41\x97\x20\xc5\x7c\x08\x65\x48\x35\x1e\x7a\x3a\x51\x5b\x37\xb4\xdb\xdb\xf1\x55\x59\x8e\x1a\x27\xc0\x65\x60\x55\xd6\xc4\x24\xd3\xa3\xbe\x43\x52\x92\x92\x56\xf4\x18\xf6\x0f\x21\xc2\x95\x2f\x4c\x99\x5f\x7d\xd5\x32\x47\x1d\xb8\xd7\x2e\xc7\xa4\x0e\x5b\x42\xe0\x28\x56\x37\xbb\xc8\x29\x49\xca\x05\x5d\x09\x21\xa3\xa0\x2e\x13\xd1\x2d\x88\x0d\xc2\x4e\x8b\xd3\x7f\x3a\x7f\x1c\x17\x1f\xae\x5d\xab\xa3\x0f\xea\x13\xbf\xc9\x00\x02\x56\xcc\xda\xd0\xd6\x6b\x3b\x2b\xa7\x1b\x0e\x3f\x92\x73\x8b\xa0\x3b\x9d\x99\x02\x02\x37\x2e\x37\x1f\x16\x26\x6d\x94\xcf\xde\x0d\xee\xa0\xd9\x3a\x51\x6e\x8d\x2e\xec\x85\xb1\x95\xe1\xad\xec\xb2\x68\x75\x34\xdf\xf4\x0b\x09\xa7\xc6\x83\x17\x2d\x84\x09\xa4\x88\x95\x8c\xb7\x81\x24\xb4\x7c\xd3\x73\x74\xbf\x45\x62\xae\xb3\xc8\xb8\xe8\x14\x95\x83\xfd\xa4\xea\xa0\x05\xa6\xbc\x82\xdf\x9c\x3a\x53\x5d\x0a\xb1\x7f\xaa\x1e\x20\x32\xe2\x8f\x52\x02\x35\x91\x95\x88\x37\x19\x96\x9c\x2c\x65\x80\x16\x20\xaa\x23\x9d\x1a\x89\x21\x48\x7f\x5e\xf2\x12\x75\x4a\xee\xfb\xd2\xd5\xce\xa0\x33\x99\x47\x03\xe2\x2a\xa5\x35\xf5\x72\x4e\x10\x2b\xa6\x7f\xfc\x92\x2e\x0c\xc5\x0b\x5f\x2c\x7c\x84\xe3\x48\xb6\x33\x51\x9d\xa4\x50\xba\xf9\x1b\x3f\xdb\x62\x7e\xf1\x61\xb0\x37\x33\x19\x20\x6b\x21\x49\x64\x3a\x4f\x25\x8f\xc4\x2d\x16\x2b\x8e\xca\x36\xd1\x41\xa2\x3b\xdf\xb7\x3a\xd8\x67\x15\x95\x2c\x0f\x50\x74\x28\xbe\xad\xf4\x39\x3f\x45\x3c\x6d\x1e\x85\xf8\x55\x65\xcf\x68\x55\x50\x30\x4c\x87\x2a\xfa\x04\x20\xf2\x04\x66\x2a\x96\xcb\x53\xa7\xd8\x47\x4c\x0f\xaa\x33\xfd\xf4\x11\x0d\xb2\xc0\xab\x61\xdd\x22\x1f\x28\x44\xee\x3e\x92\x54\x60\x15\xd7\x4b\x49\x92\x50\x32\xcc\x3f\xf4\x37\xc5\xe3\xb8\x58\x70\x8d\x1f\x55\xef\x76\x4c\x5f\xaf\x38\x74\x73\xf8\xfe\x8f\x3e\x0a\x1e\xaa\x7c\x06\x55\x52\xa0\x86\x20\xd5\x88\x72\x5b\x52\xa5\xc3\xdb\xc1\xcf\x7a\x4e\xe3\x00\xf2\x6c\x3f\x19\xfa\x88\xd9\x09\x71\x93\x61\x9f\x7b\x4d\x28\xa2\xfb\xe0\x9b\x77\x38\x33\x2a\xe2\x5d\xbb\xd4\x04\xff\x0b\x7c\xb6\x38\x3f\xe4\x9f\xbc\xb4\xea\x19\x98\xd7\xb8\x82\x18\x24\x72\xee\xca\xf4\x31\x14\xf9\x51\x98\x75\x99\x06\xb5\x17\xb1\x62\x88\xbe\x3a\x97\x21\xf1\xa5\x89\x30\x46\x04\x74\x6a\x09\xca\xec\xbc\x05\x8d\x37\xb0\xc8\x2e\xed\x03\x4b\x06\x34\x8d\xdb\xf1\x0a\x8f\x9b\x3d\xbf\xb4\x4f\x37\xc8\x24\x39\x65\x3d\x69\xc3\xed\x30\x85\xb4\xdc\xd6\x3c\x44\x88\xfd\xf8\x3b\xff\x78\x67\x31\x48\x12\x67\xb8\x2d\x6c\x3f\x32\x3e\x3a\x8e\x4e\xd9\xbf\x0c\xf1\xc2\x14\xc2\xe7\x0e\xde\x42\x9c\xe0\x12\xc2\xf0\x3a\x91\xe5\x0a\x06\x3f\xe1\x03\x8b\x83\x64\xe9\x4b\xee\x9c\x02\x00\xe1\xe5\xca\xd0\xb2\x50\xe7\xf7\xef\x60\xe9\xfc\x3b\x96\x44\x46\x04\x22\x8c\xd3\x85\xa2\xf8\xf1\xea\xbf\x44\x76\x2d\x3f\x29\xc6\x58\xcd\x9f\x45\xc3\x04\x64\xd6\x7e\xaf\x0c\xf3\x53\xfe\xe3\x28\xbf\x73\xb7\x45\x51\xc3\x7e\x8e\x6c\x41\xae\x95\x85\x4a\x63\x1d\xf7\x12\xfb\xa5\x61\xc5\xdd\xff\x24\xf7\xed\xd9\x31\xd7\x2b\x9d\x1d\xce\xd3\x23\x42\xa1\xb4\x55\xc8\xd0\x2c\xcc\x5e\x70\x54\xac\x0c\x12\xfe\xb9\x79\x58\xa3\xdc\x2d\x1f\x7d\x05\xf0\x3f\xe3\xdc\x82\xa0\x1a\x95\x46\xe9\xa2\xa5\x48\xcd\x9f\x86\xac\x17\x3c\x8b\x13\x29\xa9\x69\xa5\x21\xc3\x59\xc9\x96\x28\x8e\x65\xb3\xec\x86\x55\x5e\xdd\x37\x01\x2b\x42\x4b\xfe\xae\x92\x87\x0d\x1a\xc7\xe9\x52\xbd\x2a\xe4\x01\x66\xe8\x51\xa5\x52\xb3\xb9\xb6\x5a\x9b\xd7\x13\x1d\x3e\x76\x18\xd1\xce\x09\xcd\x74\x0f\xac\x98\xcc\x86\x7a\x94\x8b\x17\xbf\x03\x63\x96\x04\xd1\x3f\x96\xf2\x55\xa0\xbb\x6f\x53\x1b\x0c\x71\x46\x9d\x60\x1a\x45\x97\x4b\xd7\x9f\x88\x06\x4e\x70\xa1\x7e\x5c\x67\xd7\x62\xb0\xbc\x92\x21\xce\xcb\x63\xcc\xed\x34\x09\xce\xc1\xf9\xb8\xbe\x3e\x36\x6a\x33\x44\x98\x89\x7c\x5e\xe2\x03\xe0\x6a\x39\x70\x71\x35\x2f\x7d\x4c\x9e\xc7\x15\x46\x96\x1b\x3e\xce\x5e\x88\x3b\xbc\x21\x3e\xed\x0f\xaf\x97\xa5\xb2\xf2\x68\xc4\xbf\xeb\xca\x3b\xe1\x0c\x59\x3b\x0f\xd7\x8e\xa8\x73\x6b\xe4\x71\xe1\xed\x38\xe3\xef\xd4\xfd\x6f\xb9\x62\x84\x15\xbe\x74\x9b\x76\x06\x84\x89\x7b\xf5\x55\xc1\xe7\xe6\x05\x66\xa7\x96\xb9\x31\xd4\xb0\x14\xc5\xd9\x02\x91\x2f\x25\x7b\x3a\x9b\x53\x31\xcc\xbd\x08\x5c\x63\x9a\xfa\xd4\x71\xaf\x16\x78\x71\xca\xe4\xea\x13\x1e\x32\xe3\xc3\xef\xdd\x67\x3a\x35\x01\x5b\x45\xe2\x3b\x54\x04\x86\x91\xe1\xb9\xcf\x3e\x94\xf8\x68\xd3\x61\xa9\x32\x7d\x06\xf4\x32\x50\xbf\x5a\x67\x65\x7c\xa2\xd6\xd9\x12\x66\x2d\x0e\xea\xe8\x98\x78\xbc\xcb\x5a\x17\x0c\x92\x91\xd5\xf1\xcd\x86\x3e\x27\xfb\x0f\xf6\xfe\xc6\x44\x3a\x85\xb2\xa4\x01\x02\x0b\x62\x3f\x4e\xd0\x6a\xad\x12\x50\x79\xe8\xc6\x32\x30\x95\x6c\xbc\x30\x1a\x70\xcc\x14\x7f\x37\x90\x26\xf4\xe5\xda\x62\xdb\x52\xc5\x0d\x7b\x92\x7c\x3b\x8d\x2a\xdf\x7e\x80\xd1\x25\xb8\x07\x37\x59\xbd\xec\xaf\xea\x35\x1e\x6a\x9e\x09\x99\xb9\x77\xe1\xd6\xaa\xdf\x62\xdf\x20\x05\x68\xc6\xbb\xeb\x13\x63\x07\xda\xc7\xed\x0d\xc7\x43\x2a\x6e\xb7\x91\x31\xb7\xd7\x6b\xd8\xd7\x10\xc1\xe1\x64\xb1\xba\x89\x9b\x89\x20\x26\x4a\x40\x77\x59\x75\x90\xc2\xee\x21\x0f\x44\x1f\x58\xba\x02\xa3\x08\x5f\x45\xc7\x94\xdc\x50\x4c\xc1\x6b\x57\xe2\x20\x93\x0a\xc2\x97\x60\xa8\x20\x0a\xed\xf2\xe8\x32\xb2\xb3\x4f\xa9\x2d\x34\xee\x07\x1b\xc0\x27\x7b\xb2\x11\x37\x7a\x51\xf9\xec\xa7\x1f\x18\x14\xa9\x37\x90\x11\x68\xda\x15\x07\x56\x90\x09\x0b\x19\x92\xf3\xb5\xc3\x48\xc9\x8c\x32\x02\x0d\x07\x46\x57\xbd\xe2\xd7\xb6\x33\x30\x0e\x6d\x3c\x3a\x57\xa2\xf5\x10\x1a\x3e\x67\xaf\xe4\xa6\x0f\xb9\x31\x0a\x30\xfb\x2a\xac\x85\x05\x4c\x5d\xc3\xbf\x73\x03\x21\x39\x3c\x17\x06\x29\xf0\xe9\x69\xb2\x5f\xeb\x68\xe9\x71\x65\x31\x88\x7d\x16\xf0\x12\xa1\xfb\xf3\xdf\xd5\x95\x1c\xcf\xf6\xb0\x4f\xf4\x1d\xf3\xf5\xf3\xb6\x3f\x0c\x33\xac\xd6\x64\xc3\x3b\x7e\xfa\x72\x9a\x6e\xd3\x24\x40\x36\x4f\xfd\xee\x63\xdf\x50\xa3\xc7\x80\xf2\x86\x26\xb5\x1c\x68\xaa\xbd\xb0\xce\xfd\xa0\x90\x3e\xef\xdd\x74\x41\x24\x9a\xbc\x0b\xcb\xa6\x35\x44\x79\xee\x37\x8b\x6b\xc8\xd4\x82\xe9\xc4\xca\x54\x64\xc0\xd4\x8d\xe3\x4c\xd7\xaa\xc1\xfc\x32\x4f\x11\xab\x14\x13\x44\x45\xc9\xaf\x2b\xaa\x73\x6a\x30\x21\xc5\x24\x65\x2b\x70\xbb\x1e\x79\x22\xf4\xdd\xf8\xc6\x4a\x46\x97\x7d\xaa\xe2\x6b\x51\xc7\xca\x1a\x17\x5e\x60\xe8\x0f\x73\xb2\xd0\x51\xf7\x7d\x8a\x70\x46\x5e\x1c\x56\xfd\xb4\xab\x7f\xae\x66\x07\x4a\x07\x69\xa6\x55\x6b\xc5\x6a\xab\x1a\x3b\x64\xd8\x68\xab\x16\xb8\xbd\xf3\xa7\x50\xdc\xce\x38\xaa\xb8\x2a\x9c\x72\x39\x23\x5f\x48\xa8\xad\x8c\xf3\xf8\x6a\xd4\xed\x42\x14\xb6\xa7\xb1\xb0\x61\x69\x22\x78\x6c\x35\x57\x1b\xbe\x05\xf3\x66\xdc\x5a\xee\xac\x9d\x22\x89\x19\x6d\xd4\x04\x35\xdd\x3c\xb5\xf5\x30\xa8\xf2\x73\xc1\x2d\x4b\xc4\x61\x40\xea\x8e\xf3\x12\x87\x41\x28\x1a\x92\xc5\xe2\x39\x75\x13\x58\xbb\x20\x2f\x60\x07\xb7\xa3\x33\xd8\x94\xd5\xf3\x0c\x0b\x90\xa3\x5b\xe0\xf4\xcd\x40\xa8\x37\x43\xf7\x9f\x80\xc3\xcb\x02\x6b\xf7\x1a\x4c\x0b\xaf\x7f\x1c\x98\x3f\x8c\xc9\x1a\x70\x58\x74\x99\x2f\x07\x38\xbf\x09\x96\x7c\xe3\x5e\xba\xbd\x78\xc9\xb2\xe9\x45\xa5\x2f\x75\x8d\x91\x48\xde\x44\xf8\x24\x0e\x4d\x39\xac\x9b\x31\xee\x13\x3a\x60\xc9\x80\x0c\xed\xe0\xbf\xd2\x71\x1f\x74\x46\xf4\x18\xc5\xc7\xd7\x55\x88\x5c\x98\xa2\xee\xc5\x48\x30\x5c\x4b\x57\x6e\x9a\x95\x7a\x9f\x04\xcf\x18\xab\x95\xc9\x4a\x8c\x6c\xb6\x99\x14\x1d\x16\x34\x53\x43\x97\xdf\xd0\x8b\x31\x11\x2b\x5f\xa7\x73\x9c\x9a\x2b\x9d\x4c\x14\x82\xf0\x72\x38\x9f\xab\x29\xd5\xab\x3f\x4b\x71\x18\xd4\x8e\x92\x2c\x2f\xd4\xae\xad\x4a\x98\x05\xf6\x88\xd5\x58\xd5\xcd\x82\x22\xe5\xa7\x78\x0b\x15\xd4\x36\x90\x2c\x4a\xc8\x24\x19\x6c\x07\x93\x87\x96\xd8\x75\x08\x6d\xd2\x50\x81\x95\xb3\xd8\xa9\xd6\x4a\x7b\x72\xce\x19\xc3\x0d\x55\x98\x51\x44\x91\x61\x93\xa5\xf7\xa1\xf8\x5c\x65\xb1\x88\x7e\x93\x9e\x62\x81\x54\xdc\xed\xb9\xe0\xa1\x84\x8b\x96\x39\xe7\x00\x51\x36\x8f\x7b\x15\xd3\xeb\xe8\x22\xe8\x3f\x18\x06\x66\xee\x29\x16\x7b\x61\x18\x12\x9c\x2b\xf1\xda\xd5\x38\xbf\x90\x70\x8e\x1f\x5a\x59\x7f\xff\xcd\xce\xa3\x28\x9d\xa5\x49\x64\x5b\xfb\x13\xfc\xb9\x6c\x79\x08\x5e\x4d\x31\xa4\x39\xa8\x97\x60\x94\x6d\x52\x90\xcd\x6f\x79\xab\x03\x6d\x8c\x8b\xf2\xfc\x0b\x9d\x49\x23\xf7\xd3\x43\x10\x5d\xfe\xfb\xf4\x04\x21\x7f\xf3\x5b\x93\x1b\x5b\x8f\xb7\x9c\x05\xd1\xf6\x47\x27\x52\xf7\x8f\x07\xca\xee\x2a\x37\x11\x1d\x85\x2e\x75\x9d\xb9\xd9\xb0\x78\xb7\x53\xe6\xc8\x62\x99\xab\x08\x7d\xa1\x57\xaf\xf1\x09\x11\x02\xb8\x5c\x99\xf6\x88\xa0\xba\x10\x89\x17\x28\x9e\x00\xa4\x51\x4e\x1f\xfd\x0b\x5c\x4f\x7e\xbb\x3b\x7d\x0e\xe2\xba\xa6\x56\x04\x49\x95\x63\xa6\x01\x50\x10\x02\x8c\xcc\xfe\xa4\x32\xfb\x66\x29\xda\x04\xdd\x09\x80\xf0\x57\xe8\x46\xb3\xd5\xb2\x78\xcc\xed\xc2\x6c\xe5\xad\x3e\xe7\x80\x16\xc7\x3d\x2e\x55\x04\xfd\x46\x13\xa1\xd6\x72\x76\x4e\xe8\xc2\x3f\xb0\x1d\x3b\x71\xc5\xd6\x83\xee\x6b\xfa\x5e\x29\x87\xa7\x1a\x44\x71\xf5\x27\xbd\x2d\x3a\xf3\xc1\xa0\xca\x98\xf4\x5a\x6e\xb4\x40\xcb\x1a\xbf\xbf\x90\xde\x70\x26\x11\x3f\x6b\x6d\x12\x34\xe3\x61\x73\x93\xbd\xe6\xd3\xb0\xbb\xd4\x24\xe8\x0b\x79\xb8\xdc\x4b\xef\x57\xe3\x5f\xa1\x38\xc2\x90\x9b\x5d\x7b\x7c\x67\x6c\x1d\x26\x72\x33\x17\xe3\x3a\x7d\x5c\x77\x4b\xc3\x06\x18\x0d\xba\x3f\xae\x72\xa2\x99\x86\xb0\xbb\x42\xfb\x1e\xf9\xe8\x42\xcf\x44\xb6\xd2\xcb\x03\x7c\x44\x69\x21\xa8\x3c\x39\xf1\xe7\x43\x66\xc3\x9f\x2c\xd1\xbe\xa0\x05\xa3\x77\x5e\x7c\x35\x0d\xab\xaf\x2d\x37\x11\x83\x45\x99\x4b\x39\xaf\x48\xe9\x65\x86\x6e\x97\x31\x9e\x9f\xe1\xd7\x8b\x52\xac\x49\x9e\xcf\xf9\xd9\x7f\x19\xa7\x90\x48\x51\xdd\xcb\xed\x4a\x91\x0a\x93\xbc\xfb\x7a\xdc\xf7\xfe\xb0\x6b\xde\x1e\x9e\xa9\xb6\x29\x6b\x1e\xdb\x9b\xa1\x69\x2f\x5a\xeb\xd6\xf3\xf5\xeb\xe3\xcb\x45\x82\x44\x6c\x7c\xed\xeb\x0a\x61\xcb\x81\xd7\xf1\x53\x08\x41\x38\xdd\x8e\xdb\xc9\xd1\x6b\xf6\xab\xd2\x73\xc0\x51\x8c\xec\x2e\xd7\x46\x60\x0e\xb5\x17\x84\x5b\x09\x9b\xf1\x65\x65\x91\x66\x3b\x67\x04\xb1\xc7\xc4\xd2\x94\x5c\x39\x6f\x3a\x26\x73\xfc\x05\x8f\x60\x4f\x00\x8c\xe6\x92\x1d\xd3\xab\xfb\x65\xa1\xc5\x02\xf7\x84\xa4\xd1\x57\x82\xa0\x97\xd3\xa8\xb1\x13\x48\x68\x16\x79\x1c\x52\xbb\x1f\x98\xdc\x78\xa3\x2d\xba\x9a\xe9\xd7\xc3\x3d\x6d\x18\x75\x1f\x44\x93\x29\x54\xbd\x9d\x96\x56\x59\xaf\x94\xb1\xc3\x4a\xe3\xc2\x93\x2b\x2e\xfc\x62\x5b\x88\x93\x68\xe4\x32\x83\x8a\x84\x75\xc8\x4d\xa3\x9e\x61\x35\x48\xb0\x33\x85\x32\x3e\xd7\x7f\xa5\x2f\x48\xde\xdc\x31\x33\x58\xe1\x9d\xe6\xac\x90\x88\xf4\x37\xdf\xd0\x1e\x65\x56\xc7\x6a\xc4\xca\x7e\x06\xe8\x51\x4b\xf2\x6f\xe1\x73\x24\x9f\xdc\x69\xd0\xf1\x7d\xd8\x84\xa5\x23\x14\x63\xa5\xbb\xbd\xbf\xe2\x4c\x9c\x48\xf9\x4b\x57\x4a\x10\xd9\x28\x5b\x96\x2b\x68\x69\x82\xc2\x49\x28\x28\x8b\x4b\xfa\x16\x4a\x10\xad\x9c\x6e\x99\xc2\x59\xb4\xf8\x64\x77\x0f\x81\x47\x59\x22\x09\xbd\xc0\x75\xc4\xe8\x53\x17\xe3\x5f\x67\xe1\x74\x39\x55\xa3\x32\x96\xb6\xbf\x7f\x72\xdf\x68\x2d\x97\x1b\x04\xd4\x55\x8e\x47\x63\xef\xdc\xf8\xa5\x95\x8e\x66\x55\xb9\x57\xbf\xcb\x1a\x63\x19\xb4\x9d\xca\x53\x21\x9d\xdf\xe2\x93\x6f\x35\xbd\xd6\xde\xca\x72\x2d\xac\xc5\xf0\xb0\x4f\xd4\x46\x7c\x36\xe1\x32\x6d\x58\xad\x8e\x4f\x3d\xb0\x2d\xfb\x85\xa6\xc1\x0f\xb6\x8a\x56\x05\xfc\x71\xe5\xb2\x9e\x9f\xb8\x19\x84\x09\xcb\x59\xfb\xc0\x99\x45\xce\xcb\xd8\x61\x2e\x37\x21\xe2\x2d\x32\xf7\x7e\x5f\xd9\x19\xff\x52\xd7\x1d\xba\x42\x9c\xb8\x7b\xe9\x48\xb2\x70\xf2\x69\x0d\xf6\xd4\xfc\xec\x36\x4f\x7b\xee\x8c\x3f\x75\x9d\xfb\x1c\xf4\xd5\x10\xea\xa8\x2b\x0b\xb6\x0f\x8f\x95\x07\x03\x00\x04\x14\x84\x09\x40\x45\x58\xcf\xf9\x3b\x0f\x27\x5e\x34\x62\x77\x76\xcd\x85\xef\x47\x68\xb1\x82\x0d\x5c\xdd\x07\x3a\x31\xbe\x04\x7a\x4d\xb4\x2b\x19\xa1\xc4\x15\x24\x0e\x72\x0a\x3f\x54\x8b\xca\x47\xff\x24\x9b\x26\x6b\x7e\x2d\xcd\x75\x11\xf2\xba\x26\xa0\xb9\x96\x1a\xe7\x49\xdc\x07\x55\xc8\x16\xc8\xe9\xcf\x18\x46\x31\x29\xb2\x74\x4b\x51\x46\x84\x32\xb9\xed\xad\x33\xcd\x41\xc1\x28\xdc\x37\xb1\xfb\xd3\x0c\x7c\xa8\x6a\xcc\x3d\x5a\xa5\xde\x54\xe0\xdd\x14\x59\x98\x84\x35\xe9\x5d\x67\x6b\xa8\x14\xed\xf9\xd3\x93\x38\xf7\x9c\x61\x33\xbc\x24\xf1\x7b\x6d\xe3\x60\x0f\x17\x3d\x2b\x01\xaf\xec\x12\xb5\xdc\x87\xab\x8c\x8e\xb0\xc2\xbb\x12\x97\xf4\x7b\x34\xd2\x22\xc0\xdf\xa0\xbe\x2b\x26\x81\x0e\xd0\xb8\x3a\x53\x3c\x25\x57\x4a\xf2\xd1\x0d\x3d\x3c\x90\x39\x0e\x8d\xa4\x7d\x46\x52\x8b\x9c\x23\x82\x02\xf2\x41\xf7\x4f\x43\xca\x6c\xa9\xc2\x1b\x0c\xab\x14\x45\xac\xc0\x5b\xd4\xe0\xf7\x6f\xa5\xfe\x7c\xb8\xa6\xcf\x5d\x96\xfa\xe6\x0d\x78\x0b\x3a\x7e\x71\x0e\x18\xd3\x61\xc4\x8a\x0a\x36\x8d\xed\x6c\xd6\x4d\xfe\x86\x33\x84\xb0\xcd\xeb\xd1\xb5\x2d\xae\x27\x5b\x20\x96\xec\x7f\xf2\xb3\x33\xa5\x77\xdb\x64\xa3\xc7\x25\x3a\x65\xab\xb4\x54\x4c\xa0\xcc\x63\xb6\x27\x18\x9c\x37\x80\x9a\x0b\xca\xed\x4f\x48\x6b\xd6\xb5\x4b\x6f\x8c\x62\x34\xfb\xf1\x39\x71\x0f\xa4\x3d\xd8\xf3\x53\x49\x2b\x14\x77\x5f\x09\x79\x68\x30\xc5\x10\x62\xf2\x8c\x0f\x6e\x19\x3b\x07\x56\x67\xd1\xdc\xe4\x43\x1c\x9b\x4e\x25\x13\x59\xa3\xc9\xc8\xcb\x41\x93\x4a\xda\xd2\x64\xc0\x11\x31\x3b\xe2\x8d\x13\x06\x04\x74\xb0\xb2\xa3\xfd\x35\x03\x5e\x3f\x37\xa0\x6b\xe2\x31\xc8\xa9\x8f\x37\x08\x54\x4d\x15\x95\x5c\xaa\xf6\x30\x1d\xb4\x7a\x19\x18\xea\x7d\x87\x89\x1f\xd5\x47\xc2\x18\x24\xab\x09\xcd\x4c\x8f\xa5\xe0\xad\x4a\x11\xa9\x9a\x93\xe4\x64\x8d\xb4\xcd\x4a\x63\x0e\x44\xa5\x1a\x55\xeb\x05\x09\x38\x51\x00\x11\x1a\x94\x11\x83\x10\x5a\x84\x98\xe4\x19\xac\x89\x29\x66\x6d\x3a\x55\xc6\x1d\xa3\xbb\xea\x63\x6e\xec\xbe\x11\xdf\xd7\x08\x7b\x09\x4a\x06\xf0\x74\x2b\x9e\x99\x42\xc8\x69\x74\x88\xdf\xd3\xd6\x36\xae\xcd\xa5\xf8\xa6\xff\xa8\xe2\x47\x29\x37\x99\xdb\xd9\x8d\x95\x7d\xdc\x01\x87\x1f\x93\xa0\x77\x9a\xa9\x79\x0b\xf8\x02\x8e\x89\x4d\x37\x42\xc1\x26\xd9\xa2\x6a\xb3\xa8\xc0\x74\x53\x92\x99\x92\x14\x09\xc9\xe6\x78\xc3\x83\xb5\x62\x54\xa4\x49\xeb\xe7\xca\x7d\x98\x69\x07\x43\x32\x3e\xd9\xac\x8b\x07\x52\x57\xb4\xa3\x19\x65\xbd\x06\x25\xe8\xe2\xaf\xa3\x50\x12\xe6\xe1\x9c\xb0\x19\x95\xd8\xd8\x07\xc3\x28\x52\xcf\x6d\x37\x47\x84\xef\x68\xdd\x0e\xfc\x3e\x77\x02\xc6\x62\x43\xc5\x45\x4c\x05\x0c\x84\x93\x8e\xce\x16\xb9\x48\x83\xca\x73\x81\x3a\x67\xb3\xf4\x15\x53\xa8\xff\xb9\x5a\x81\x21\xb2\x6c\xfe\x06\x4e\x8a\x52\x97\xe8\x20\xdc\x76\x07\x49\xef\x5f\x8c\x5e\xa6\x6c\xa7\xdc\xcb\x32\xb8\xae\x7d\x93\x03\x96\x0d\x96\xf0\x86\xb9\xd1\x64\x3e\x67\x21\xc8\xdf\x66\x11\xd3\xd6\x35\x04\xf8\x27\x61\xa2\xcd\x99\xbf\xff\xf4\x1b\x09\x0b\xd5\xa0\xc5\x18\x9d\xfe\xad\xc3\xc3\xc2\x9c\xa3\x3e\x54\x0a\xee\xc7\xe0\xe2\xc7\x31\xd8\x6e\xff\x46\x34\xae\x2d\x00\xc9\x25\x89\x4d\x2c\x3d\x41\x10\xec\xea\x5e\x41\xd2\x27\x6d\x17\x3b\x17\x46\x47\x96\xf5\x23\xad\xa6\x80\x29\x37\x60\x92\xd1\x0a\x11\x02\xbc\x3d\x31\x09\x19\xd0\xe7\xa4\x4d\xaa\x9e\x4b\xba\xce\x56\x11\xa6\xb8\x96\x5b\x44\x30\xe1\x28\xa7\x12\x3d\xca\x2b\x57\x4f\x3d\x0d\x41\xa2\x3c\x0f\x83\x70\x01\xa0\xe8\xa9\x25\xbe\x22\x52\x07\xe7\xb9\x06\x99\x4c\x49\x0b\x32\x61\x20\xde\x4c\xd5\x21\x50\xce\x8b\x3c\x81\x4a\xe4\x8c\xa3\x45\x86\xf3\x72\x30\x0c\xa7\xa6\xe4\xe6\x7e\x6c\x93\x4c\x4c\xf2\x25\xe7\x20\x04\xd2\xb4\xc7\x3c\xa5\xa0\xbd\xfb\x91\x39\x0e\x6e\xf0\xfd\xd3\x96\x50\xeb\xf1\xd5\xc8\xf1\xbc\x2c\x4d\xf6\xc0\x43\xb8\x40\xd8\x23\xb1\x06\x23\xdc\x32\x7f\x3b\xc1\x31\xa5\x34\x9f\x7d\x4e\x64\xe2\xec\xa4\x76\x80\xef\x5a\x3d\xa4\x27\xf7\xbc\xfa\x45\x03\xc7\x56\x3a\x65\xd9\xdc\x83\x66\x81\x01\x29\x56\xfc\x92\xb8\xc0\xf9\x60\x21\x3f\xa9\x4f\xd4\xa5\xa5\x0e\xcc\xfc\xe4\xea\x86\x52\x37\x46\x42\x5e\xe7\xb3\x3b\x92\x13\xbb\xfb\x37\x9d\xa9\x1a\x30\x9f\xef\xb5\x18\xe1\x16\xf9\x8d\x62\x56\x3b\x84\x52\x53\x90\x58\x65\x44\xe0\x97\x5e\x7d\x09\x81\x4b\x69\x6b\xdc\x7b\x59\x00\xf2\xd5\x5d\x53\xf8\x8a\xa0\xf5\x1d\x13\x28\x12\x32\xac\x1b\x1a\xef\x21\x47\x33\x9e\x75\x9d\xce\xa6\x1e\xb4\x12\xd1\x96\x4c\x78\x20\xe7\x73\xf8\xf5\x4e\x2c\x55\x8b\x26\xa4\x9e\x20\x18\x5d\x9c\xe8\x78\xe8\xef\x37\xad\x35\x76\x5d\x20\xb6\x21\x2b\xf5\xac\xbd\x2b\xd3\xa8\xd2\x21\x37\x5e\xe5\x95\x18\x17\x7a\xca\x0a\xcd\xf8\x06\x6e\x0e\xce\x84\xda\x7d\x72\x25\x15\x46\x99\x84\x9b\x76\xe5\xce\x7c\xa5\x45\x7b\xde\x16\x73\x1d\x09\x29\x95\xab\xef\x16\xb1\xa8\xa7\x59\xd3\xbd\x52\x65\xe8\xa0\x16\xa2\x10\x0f\x03\x6b\x1d\xd4\xb7\x2f\xa3\x17\x16\xa1\xb4\x5b\x4c\x35\xd1\xe6\x68\xd0\xaa\x51\xff\xae\xd4\xaa\x2a\xf2\x10\xb0\x28\x33\xe1\x28\x6d\xe4\x27\x3b\x82\x83\x8d\x0d\x3f\x45\x20\xc2\x2e\xae\xb2\xcd\x94\xf1\x3c\x31\x90\x26\xe6\xa6\x20\x81\x25\x25\x77\x01\x6d\x65\x26\x17\xa2\x07\x58\x06\xcb\xb7\xed\x26\xaf\x94\x04\xca\x7d\x53\x09\x3e\x4d\xdd\xd3\xa3\x14\x3e\x16\xea\xc5\x31\x2a\xd5\x1a\x3e\xba\x2c\x4e\x37\xd9\x22\xe8\x58\x0e\x07\x49\x81\x66\xad\xea\xc6\xf2\xc6\x57\xec\x99\x31\xbb\x15\x56\x13\x6b\x48\xac\xa9\xdc\x2b\xa5\x06\x33\xf3\xb9\x51\xc0\x15\xc6\x4a\x52\xa0\x75\xbd\x49\xb1\x06\xb8\xa3\x9b\x12\x1a\x66\x07\x2a\x4d\xa4\xdc\xf0\x10\x37\xd9\x78\x2f\x5d\x69\x6d\x58\x77\x36\xe2\x1f\xa6\xee\x98\xb1\x96\x6e\x7d\x70\x4f\x0b\x7f\xa4\x64\xc5\xdd\xce\x42\x87\x38\x63\x48\x10\xda\x14\xbc\x91\x7a\x40\xf5\xa1\x05\x4f\xc2\x7c\xeb\xc6\x2d\xa5\xde\x92\x68\xdc\x44\x38\x2c\xe1\xf7\x2d\xc2\xe7\x83\x71\x91\x18\xa7\xf4\xe5\x6f\x0f\x22\x02\x94\x0e\xa1\x84\xd0\x5d\x98\x68\xd8\x38\xe0\x44\x8d\xf5\xc5\xd1\xa3\x2b\x85\x66\x1a\x03\xb6\x75\x62\xda\x34\x16\x1a\x0c\x4a\xd4\x9b\xe7\x11\xd6\x0a\xf7\xc2\x0a\xe1\x35\x27\x33\x6e\x2e\x3d\x56\x5a\x5a\x23\xfb\x65\x73\x7b\x62\xf6\xfc\x69\xe6\x2a\xbe\x32\x53\x49\x3f\x9d\xd7\xa8\x2e\x64\xed\x55\xc6\xba\x84\x77\xed\xbb\x37\xfc\x38\x0c\xb4\xd1\xad\x78\xfa\xd3\xbb\x9e\xee\x02\x62\x18\xad\xb2\x55\xca\x31\xc3\xa6\x48\xe3\xdc\x61\x4f\x54\x97\xba\x34\x09\xc6\x78\x4b\x45\xf1\x2f\x8e\x59\xcd\xc1\xcb\x8f\xbb\x6c\xe9\x86\x16\xb1\xba\xf4\x68\x60\x3f\x9d\x0d\x3e\x61\x85\xab\xa1\xf9\x4f\xef\xff\x05\x6e\x1e\x91\xe1\x76\xb6\xbd\x35\x33\x76\x29\x8c\x0e\x14\x5a\x42\xc1\x38\x49\xf3\x32\x00\x55\x5f\x32\xbc\x75\x59\xbe\xe6\x26\xe4\x47\xd6\xfa\xc6\x13\xde\x62\x1e\xee\x28\xa5\x92\xcf\x20\xb2\x3d\xa7\x7e\x2c\x37\xab\x0a\x1c\x4b\xfa\xe4\xb8\x71\xc4\x6e\x51\x90\xa0\x0d\x73\x9c\xce\x42\x21\xc1\xe5\x93\x1c\x46\x6e\x60\x1c\xd8\x59\xe7\xf0\x88\x4e\x6b\x8c\xb9\x9c\xfc\x52\x3d\xcf\x15\x3a\x88\x2e\x09\xee\x55\x26\x7c\x47\xb4\xc1\x3c\xdd\xa2\xc7\x55\x26\x45\x42\xa8\xd9\x41\x71\x4d\x4e\xbe\xe4\xd8\x24\x88\x03\x3a\x3d\xbf\x90\x35\x30\x89\x2c\x13\x44\x9a\xf8\x5b\x7b\x88\xb4\x10\x32\x04\xb7\xc8\x06\x99\xc7\xe9\xa8\x3c\x24\x3e\xbf\xb4\xe2\xb8\x0f\x0f\x52\x6e\xf6\xb4\x1d\xf6\x3c\xd5\xeb\xd6\xf8\xbf\x37\x81\xa4\xfc\x98\xe3\x36\xa3\xf9\xfa\x3c\x38\xe2\xe7\x49\x49\x18\x3c\xab\xdc\x3f\xc6\x7b\x82\xf3\x01\x54\x7e\xa0\x39\xbd\x22\xa0\xab\xc8\x21\x21\x3d\x0e\x64\x13\x0d\xca\xcc\xae\xf0\x4d\x4d\x21\x82\x15\xe7\x01\x8c\xb4\x79\x85\x78\x88\xf3\xde\xae\xbd\x14\x15\x8e\x3a\x99\x03\x31\x6e\x51\x0a\xce\xde\x29\x05\xeb\x4b\xee\xa2\x05\xc5\x17\xa9\x42\x60\x1c\x0c\xfb\x29\x0e\x10\xd2\xc6\xb1\x69\x5d\x64\x63\x7a\x43\x90\x4b\x50\xb1\xd9\xa2\xd1\xe7\x8e\x3d\x94\x78\xd5\xb7\xf3\x4b\x6f\xba\x8c\x6e\x8f\xef\xd7\xd2\x91\x18\x4a\xd2\xae\x06\x69\x89\x73\x20\x92\x7f\x10\x87\x44\x45\x4e\x45\x0a\x52\xa0\xf0\xbb\x5a\xe1\x4a\x96\x4d\x90\x22\xa8\x2e\xf7\xa0\xd9\xde\x15\x18\xce\xc7\x15\x21\x04\x6d\x17\xdf\x88\x65\x83\x8d\x64\xaa\x02\xc9\xf7\xa1\xea\xbc\x2f\x4c\x0c\x23\xdd\xf6\xcf\x30\x64\x7b\x21\x6c\x09\x4d\x93\x24\x3d\x2a\xac\x70\x23\xb5\x1a\x21\x40\x38\x2e\xec\x00\xe9\x6a\x63\x72\x3b\xe8\x4d\x7e\xfb\x74\xfe\xc1\x8c\xd8\x40\xaa\xbc\x5b\x11\x42\x72\x01\x48\xd6\x41\x9f\x4c\x69\xfb\xbd\x13\x50\x40\x35\xbd\x06\x10\xb0\xea\x61\xef\xdf\x80\x0a\x82\xbc\x75\x45\x99\x4e\x94\x5c\xe1\xb7\x2b\xbe\x51\xb8\x90\x3b\x3e\xcc\x00\xc6\xd8\x2c\xc6\x44\xa8\xf7\x9e\xf8\xe8\x1b\x89\x69\xe0\x4e\x14\xee\x27\xd0\x86\x13\x69\xb3\x40\x08\x5d\xb4\xc4\x03\x79\x4c\x55\x40\x33\x16\xce\x4f\xa0\xe4\x03\xae\x26\xda\x5e\x1f\xc5\xaa\x3d\xe7\xea\x64\x3c\xb0\xfe\x9f\x82\xa2\xd1\x4c\x60\x9d\xdb\x20\x87\x9e\xa6\xe8\xe5\xcb\x0c\xe2\x58\x60\xbe\x48\x20\x02\x58\x6b\x43\x5d\x7e\xaa\x19\xf5\xc3\x22\x36\x40\x6a\xc5\x03\xe1\x70\x4c\xd4\x60\x23\x11\x4a\x91\x4e\xec\x06\xb5\xa6\xf0\x63\x1d\xa2\xf4\xa3\x2a\x15\xe1\x66\xaf\xfa\x86\xc6\xa1\xec\xcf\xf4\xb5\xc0\xb3\x38\xd9\x6a\xcc\x3b\xa3\xba\xe2\xe9\x22\xa4\xce\xe7\xd6\x95\x4c\x0c\x6c\x43\x7e\x4d\x0b\x5e\x09\x2d\xc6\xc6\x00\x00\x36\x76\xf8\x05\xb4\x11\x61\x4a\x50\x10\x65\x50\x5c\xa0\x21\x02\x0c\x29\x09\x88\x23\x7b\xa8\xab\x0a\xf4\x22\x3f\x1d\x93\x10\xf4\xc0\xc3\x52\x0c\xc7\x3c\xd5\x92\x31\xad\x87\x80\x19\x06\x13\x68\x60\x8b\x52\xac\x72\x12\x23\x00\x23\xe8\x28\x56\x24\xd2\x29\x70\x94\xee\x7d\x40\x48\x3c\x9d\xea\x43\x9a\xe9\x18\x4c\x0a\xf2\x4d\xcb\x49\x95\xb0\xf7\x90\x4b\x45\x2a\x7b\x3f\x6f\x45\x53\xd0\xef\x34\x37\x14\x78\x1e\xd9\x47\x56\x16\x79\xb0\xb6\x32\x2e\x9b\x47\x30\xde\xe3\xfa\x75\xc4\x10\x10\x89\xf4\x7f\x1f\x38\x8e\xe6\xf7\x04\x8e\xdb\x26\x20\x65\xba\x49\xcb\x33\x4c\x29\xd8\xe7\xdf\x64\x8e\x05\x93\x83\xb0\xcf\x4a\xc2\xc1\x17\x96\x23\x63\x7e\x6c\xb5\x11\xb5\x8a\xbe\x65\x4c\x03\x4e\xc5\xcb\x61\xc4\x8b\x26\xcd\x6b\x36\xdf\xcc\xc3\x7a\x24\x1c\x64\xb1\x83\x64\x4b\x6d\xeb\xc7\x53\x5c\x86\xc2\x13\xc7\x48\x4b\x2b\x3a\x64\xc5\x38\x92\x10\xe9\xcc\x13\x2c\xc2\x16\xfa\xa1\xc1\xa4\x4d\xaf\x91\xae\xf9\x1a\x81\x8d\x08\xac\x2b\xcb\x01\x1c\x42\x21\x4a\x12\x8a\xc5\xd9\x7d\x28\x44\x05\x98\xf5\xdd\xf3\xe0\x1a\xf5\xdc\x3f\xe7\xb0\xf3\x2a\x8a\x3d\x73\xc5\xdc\x88\x44\xaa\xe3\x88\x58\x93\x43\xf3\xc1\x5e\xa9\x7c\xf0\x2c\xd8\x2f\x58\x23\x14\x57\x86\x2c\xe5\x4f\xe8\xf4\x37\xcb\x71\x04\x58\x49\x71\x46\x5c\x32\x29\x24\x51\x15\xc0\x0c\x6d\x8c\xe8\x48\x73\xd3\xfc\xc8\x71\x89\xf0\x5b\xb0\x62\xab\x89\x52\x11\x12\xb2\xb2\xaa\x7b\xa6\xbf\x8f\x61\x8d\x2d\x64\x79\x53\x4d\x48\x4f\xaf\x03\x64\x11\xf1\x75\x90\x09\x48\x95\x0e\xc5\xd2\xc9\x97\x1c\xc4\xc1\x9f\x8f\x12\x32\x40\x80\x14\x89\x78\xc7\xb4\xf3\x7a\x06\xf0\x3a\x82\x46\x7a\x48\x45\xa6\x54\x82\xc3\x4a\x3a\x03\x48\x88\x3e\xb9\xe2\xfa\x20\x14\xa4\x07\xa1\xf4\x24\xc9\xa0\x30\x5c\x13\x73\x5d\xab\x9c\xd0\x1a\x75\xee\xa1\x02\x76\xfb\x6f\xa1\xc0\x17\x1f\x08\xb3\x1a\x5f\x02\x30\xe2\x43\x29\x5e\x66\x4e\x77\x54\x91\x99\x3c\x79\xcf\xb0\x94\x36\x28\xe7\x04\x58\x5b\x5c\xc8\x5a\xcc\x62\x70\xc9\xb2\x94\x06\x31\x41\x96\x3a\x03\xab\x42\x21\x44\xe1\x40\x5c\x87\x88\xb1\xf8\xe8\x73\x40\x24\xd8\x3b\x70\x4c\x15\xa3\x56\x14\x13\xd8\x2f\xb5\x80\x73\x15\x74\x7c\x36\xb7\x9f\x82\xdf\x87\x04\x41\x85\x00\x60\x7f\x70\x68\x18\xc3\x0c\xb8\x84\xe9\xe3\x43\x25\x34\x40\x0b\x71\x97\x3f\x11\xc1\x98\x76\x11\x4f\x57\xf0\xf1\x22\x4a\x3b\xbe\xc5\x00\x1c\xdf\x23\x01\x22\xc3\x00\x5e\x91\x54\x3a\x93\x6b\x00\xb1\x9c\xe4\xf4\x1e\xd9\x27\x4a\x7b\xab\x28\x09\x08\xc3\x91\xa8\xc1\x42\x70\x0a\x88\x85\xb1\x87\x42\x57\xd7\x0d\xd2\xe7\x3a\x3e\xe1\xec\xc7\xc8\x64\xfe\x2d\xb9\x76\xeb\x78\x7d\x18\xfa\x04\x31\xbe\x10\xa1\xee\x4f\x13\x58\x24\x17\x5c\x01\x85\x64\xe8\xc3\x33\x03\x24\xab\x42\x4f\x34\x2d\xa9\x0f\xae\xcc\xc3\xeb\xe0\x27\x27\xb0\xc6\x63\x00\x2a\x40\x97\xaf\xaa\xdb\x5f\xdb\xd9\x60\x40\xd8\xa6\xde\x6a\x8a\xbc\x10\x22\x4a\xba\xcb\x61\xc0\x4d\x1c\xc2\xa3\x09\xe2\x9b\x00\x62\xad\x40\xec\x81\xc7\xb2\x3a\xc7\xd3\x69\x65\x99\x60\x43\x21\x15\xea\xbc\xdc\x49\x68\x61\x19\x04\x04\xc8\x1c\xaf\xc2\xe6\x39\x6b\xf8\xc9\x2a\xb0\x69\xc2\x18\xa9\xc7\x71\xaf\x1a\xd3\xe8\xe5\xeb\x49\xcc\x7f\x27\x31\x35\xf0\x42\x4b\x24\x4c\x97\x1b\x73\x29\x93\x10\x8a\xdd\x1b\xb5\x7a\x41\xde\x15\x4f\xca\x20\x46\xa5\xcd\x17\x41\x3c\xa2\xa4\xe9\x30\xa3\xa6\x22\xd2\x00\x36\xe8\xb9\x80\x6e\x61\x30\x73\x18\xd4\x87\x53\xd0\x31\x1b\x0b\x00\x58\x50\x60\xbb\xe9\xb5\xac\x2e\x70\x17\xde\x4f\xcc\x05\x86\xbc\x55\x84\x99\x56\xab\x20\x45\x65\x49\x32\x2c\x4d\x80\x29\x0e\x39\xa2\xce\x42\x82\x70\xaf\xb8\x8c\xc6\xca\xa4\x45\x4c\x53\x7d\x52\x59\x55\x6c\x34\xd2\x30\xf9\xc7\xa1\x27\x08\x13\x02\x91\xb2\x0c\x9f\xe8\x03\x7c\xc9\xa5\x8f\x76\xa5\x88\x3c\xae\xc8\xa9\x62\x0c\xb2\x29\xcb\x09\xf9\x3b\x31\xdc\x33\x2f\xdb\x90\xd4\x95\x10\xd1\x1f\xc7\x23\x94\x28\x7c\xa6\xa1\x08\x96\x52\x03\xc5\x56\x65\xc4\x3b\x31\x1e\x41\x5d\xc5\xbd\xa5\x57\xca\x6a\xd5\x05\x19\x72\x6b\x19\x2c\x01\x21\x85\xa3\x8d\x6c\xd3\x71\x65\x61\x80\x71\xdd\xc8\xf9\x10\xe3\x60\xd8\x23\xe7\x33\x6b\x2d\x0c\x75\x30\x1a\x39\x3e\xd2\x91\xea\x3e\x92\xc8\x5e\x1c\x94\xb0\x3c\x08\xaf\x5b\x9c\x11\x24\x5a\xaf\xe0\x2a\xd5\xb7\x2a\xad\xf8\xcb\x82\x96\xaa\x6d\x24\x29\xdb\x24\x0a\x75\x13\x47\xfc\x34\xb8\x07\x8c\x5b\xe0\x68\xaf\x02\x81\x3f\xd4\xc3\xac\x60\x42\x36\x65\xb8\x64\xae\xb5\x3f\x19\xa6\x1a\x81\x5e\x46\xc4\xd4\xca\xb8\x02\x66\x33\xc7\x86\x65\xd9\x88\x03\x46\xb5\xb5\x97\x86\x36\xe8\x58\x1a\x27\x09\xe0\xdc\x46\x45\x68\xac\x60\xb8\x70\x87\xe5\xfd\x09\x1b\x00\x3e\x0e\xf6\x38\xed\x44\x50\x18\x5c\x38\x31\x58\x54\x80\xd9\x39\xd6\x1a\x3c\x76\x6c\xdf\x94\x29\x94\xa6\x23\xe6\xdf\xe8\xf1\xe4\x1c\x8d\xda\xf1\x56\x0f\x59\xc4\x75\xcf\xa0\xfe\x32\xa0\x35\x89\xcf\x25\x31\x1f\x9f\x46\x54\x51\x9d\x52\x1b\x9d\xe6\x80\xb5\x9d\x28\x21\x4f\x29\x00\x90\x6c\xc3\xa3\x6b\x30\x6d\xd4\x75\x82\x6a\x2d\xa0\xed\x92\xf4\xa4\xae\x44\x04\x80\x90\x09\x22\xfe\xc8\x21\xfd\xa8\x49\x30\xf1\x44\xb8\x24\x80\x94\x0e\x04\x36\x68\xf1\xb6\xd2\x01\x74\x08\x4c\xa2\x3c\x10\x01\xfe\x2a\x58\x83\x88\x4c\xcd\x18\x31\x6b\xca\x62\x10\x42\x9b\xd6\xd4\x01\x2d\x96\x42\xa7\x72\x12\x8a\xfa\x2b\x84\x37\x14\x58\xa5\x8a\x21\x24\x3c\x97\xe5\x8a\x40\xb1\x58\xa6\x58\xa0\xe2\x31\x20\x05\x42\xd0\x2c\x54\x41\x4c\xec\x7a\x2c\x13\x99\x41\x50\x12\x21\x1b\x1e\x27\x5d\x79\xf3\xc8\x06\x3c\xaf\x43\x00\x29\xf8\x22\xd4\x0b\x74\xd9\xf9\x85\xd7\xe1\x5c\x66\xf6\x7e\x8a\x15\xdf\xcc\x30\xfe\xca\x0b\x89\x64\x4a\xd6\x79\x68\x27\x16\xc9\x31\xbc\x61\x06\x27\x0b\x12\x8b\x1d\x60\xef\x28\x81\x15\x85\x26\x98\xef\x3e\x79\x42\xdd\x37\x30\x7d\x11\x0d\x13\xc8\x60\x33\xeb\x92\xd3\xe4\x32\xf3\x19\x49\xbf\x88\x2a\xf3\x60\xfa\xe6\x25\x26\x20\x8c\xbf\x1f\xdb\xa0\x3d\xef\x46\x72\x53\xf8\xf8\x9c\x95\x06\x68\x1a\xc0\x77\x2d\x8c\x32\xe1\xc1\xb8\x72\x0f\x6b\x24\x81\x57\x0d\x70\x46\xf2\xff\x17\x90\xe5\x1d\x5c\xbc\x9d\xbd\x00\x7a\xd2\x07\xb0\xc2\x97\x51\x40\x3f\xa1\x89\x40\xae\x48\x51\xa5\xba\xbd\x93\x98\x30\xdc\x0f\x61\x4d\xf2\x65\x95\x71\x0b\x5c\x1b\x23\xc7\x48\xeb\xff\xf0\x30\x07\x1a\xcc\x09\x90\xb7\x8c\x1c\xb5\x92\xf9\x74\x15\x51\x29\x72\x34\xdc\x1d\xb6\x9a\xce\x68\x94\x15\x45\xd9\x32\x17\x94\x2f\x63\x76\xe6\xe3\xac\x9b\x82\x6a\x6b\x64\x5a\x20\xa8\x99\xf3\xaa\xfc\x20\xaf\xdf\x0a\x8b\x0b\x0d\xaa\x23\x3c\xcd\x89\x1d\xcc\x17\xba\x29\x60\x22\x72\x01\x94\x43\xe4\x54\x58\xab\xe2\xb2\x40\x05\xd3\x43\x5c\x03\x8b\x75\x12\xd0\x64\x84\x61\x42\x2c\x1a\xe2\x6f\x72\x46\xc1\x4d\x51\x98\x85\x98\x87\x32\x2f\x1a\x31\xb6\xe6\x61\x4b\xb0\x89\x55\x84\x6d\x61\x4b\x60\x1d\x4c\x0c\xc2\x58\x1a\x2c\xc2\x48\xc7\x89\x3d\x96\x55\xf5\x34\x2f\xa1\xcc\x3c\xc4\xd8\x07\xa8\xe5\x9d\x49\xf5\x18\xf4\x6d\xa3\xe5\x3d\x5f\xb7\x87\xf1\x99\xfd\xe1\x21\xdf\x34\x41\x23\x41\x13\xe6\x87\xea\x2b\x42\xbe\x75\x78\xe6\xe0\x28\xa7\xe0\xb5\x8b\x21\x6e\xfb\xd9\xd1\x0d\xc9\xb9\xc2\x5c\xb4\xda\x0d\xd0\xdd\x99\x59\xd0\x5b\xa1\xf2\x16\x76\xd4\x10\x43\xa7\x56\x3e\x32\x1e\x68\x59\xc5\x29\xa0\x65\x86\xd1\x82\x0e\x00\xed\x88\xbf\x52\x3f\xb5\xc9\x65\x6a\xe2\x15\x01\xf2\xb2\x25\xb3\x02\x94\xc7\xd7\x8c\x75\xbd\x76\x6f\xc0\x4d\x60\xb6\x3a\xd9\xc8\x33\xae\xc9\x8d\x88\x68\x41\x1a\x8b\x6b\x8d\xd5\x82\xcd\xf4\x58\x2d\x01\x4e\x61\x8c\x19\xcc\x1b\x3b\x1b\x2d\x46\x2d\x39\xa3\xd5\xb9\x53\xc3\x03\x46\xcd\x8d\x91\x6a\xc8\xc0\xa0\xee\x05\x47\x4f\x5c\xd9\xaa\x9c\xbd\x1f\x96\xee\x9f\x14\x47\xec\xfb\x20\xb1\x1e\x4f\xd9\xc6\xd8\xe2\xb3\x42\xe9\x42\xe7\xa9\x0a\xf6\xda\x6f\x07\x9a\x9a\x3c\xd5\xb7\x86\x52\xd0\xe3\xa6\x37\x2d\xbf\x30\x24\x43\xca\x16\x89\x60\xf1\x82\x8c\x02\xb6\x62\xa2\x1c\x21\xa6\x21\x52\x8c\xcd\x0e\x51\xcc\x96\x81\xa5\x67\x9f\x8d\x3d\x2e\x69\x37\xb0\x01\x79\xba\x19\x82\x01\x33\xbe\x09\x17\x81\xa5\x99\xe8\x71\x44\x91\xa9\x80\x11\x7b\x23\x1e\xcd\x80\x41\xe3\x07\x5d\x91\x9e\xe9\x7c\x12\x4c\x2e\xb5\x51\xd1\xc1\xc4\xc2\xe4\x38\x9f\x11\x26\x1a\x6c\xbb\x40\xdf\x29\xb4\x86\x58\x78\x8f\x6e\x44\x12\x7e\x48\xae\x82\x54\x8d\xa1\x79\x7e\x59\x41\xc8\x53\x1e\x25\xa6\xcf\x96\x4d\x04\xa4\x7c\xad\x02\x30\x6b\x97\x5d\xba\x85\x20\x49\x49\x2b\x02\x70\xec\x9d\x74\x8c\x9b\x12\xb7\xab\xee\x2a\x82\xd1\x07\xc8\xbd\x45\xa3\x71\xa3\xd3\xe6\x88\x03\xc4\x19\x78\x82\xf2\xa9\xc8\x61\xe6\xc7\x96\xd1\x00\xd1\x9b\x98\xaa\x37\xb0\xfe\xee\x93\x0c\x53\x0b\xa6\xc2\x17\x0e\xad\x51\xa4\x98\x54\x30\xa4\xab\x19\xb2\xa6\xd6\x0e\x20\x56\xda\x49\x61\xd0\x60\x5e\x32\x50\xd0\xa7\x7f\xef\x5f\xa4\xea\x85\xc0\xf5\x41\x97\x60\x15\x7f\xf1\xd3\x57\x1b\xda\x99\xa3\x68\x15\x0d\x26\xf9\x5b\x41\x52\xcc\x50\x68\xc2\xec\x18\x3f\x9b\x4d\x28\x0e\x8b\x24\x0b\xc4\x18\x0d\x24\x08\xe8\x31\xe5\x0c\x1c\x7e\xf1\x41\x66\x69\x20\x51\x7c\x7e\x76\x5b\xf8\x90\x61\x56\x9f\x1c\x33\xa4\x83\x76\xa0\x81\x8b\xfe\x25\x87\xec\x9d\x37\x6c\x01\xbd\xa9\x0e\xb5\xd4\x48\x37\x87\x14\x79\x8e\x6a\xf3\xe0\x56\x49\xd1\xca\xb8\xe1\xc7\x87\x37\xfa\xb6\x5d\x63\x10\x85\x86\xb5\x88\x75\x8c\xb8\x4e\x89\x55\x91\xfb\x10\x70\x0f\x89\xb9\x2c\xbe\x09\x18\xbd\x49\x79\xa0\x6d\x31\x5d\xd6\xbb\x63\x0e\xf8\xdb\x80\xce\x60\xed\x15\x7f\x5f\xad\x41\x76\x58\x60\xf0\x1d\xff\xd2\x0c\x73\x2e\x18\x93\x75\x9d\x8c\xe2\x27\xee\xe5\x27\x5e\xd8\x3d\xde\x34\x12\x4e\xef\x94\xa6\xf1\x53\x2d\x92\x22\x10\xb1\x9d\x31\x3a\x6e\xcc\x24\x5a\xc5\x28\x5b\xa7\xeb\xe3\x90\xf8\x93\x9b\x4a\xf4\x93\xa3\x63\x85\x08\xed\xb7\xa3\x76\x92\x9c\xc0\xef\x96\x4c\x01\xf0\xcd\xaa\x92\xca\xca\xb1\x05\x5d\x64\x0d\x71\xff\x94\xec\x43\x73\xe2\x10\x00\x02\x48\xfc\x6b\x56\xad\xad\x1b\xc3\x84\x00\x65\x41\xd3\x12\x37\x6e\x98\x8d\x96\x73\x86\x75\x14\x4f\x52\x7f\x44\xd6\xaa\x91\x69\x36\x0e\xe6\x3a\x7c\x8a\x7e\x41\x85\xf3\xf0\x71\x29\x73\x73\x9c\xb9\xd6\x5d\x52\x4c\xaa\xcc\x89\x87\x80\x04\x0b\x26\x8b\x59\x95\x0d\x9f\xfd\x23\xe0\x82\x06\x97\x18\x05\x74\xc6\xa3\x64\x38\xe0\x4d\xc6\x0a\x9e\xdd\x7d\xa9\x3e\x08\xc2\x1a\x40\x69\xe9\x1b\x5e\x41\xc9\x2e\x5a\x7e\x9d\xad\x05\x57\x62\x7d\x8f\xa2\x1b\xd6\x5a\x2d\x8f\xb3\xa3\x4c\xa6\xb5\x82\x50\xeb\x0e\x46\x18\x4a\x75\xe2\xae\xfd\xb1\xe2\x85\xf4\x5a\xd2\xa0\x08\x79\x2a\x7d\x40\xd5\x3a\xa0\xec\xf2\xc1\x15\x73\x6f\x09\x61\x4d\xcf\xc1\xed\x6c\x6e\x66\x7e\x44\x22\x0a\x55\x0d\x6b\x50\x07\x1f\xaf\x5b\xae\x5e\x84\xcf\x33\x48\x93\x4f\x0a\x89\xa9\xe8\x5a\x79\x9d\x36\x4a\xda\x54\x7d\x35\xf5\x12\x92\x1a\x4d\xfd\x30\xa1\xbc\x71\x29\x9d\xf8\x40\xe1\x46\xb1\x14\x5a\xc4\xb8\x7d\x1c\x06\xa7\x4d\x9c\xd6\xe0\x0b\x62\x7e\xf7\x6c\x86\x0b\x56\x13\x32\xc8\xdb\x25\xed\x69\x40\x01\xbe\xb0\xfd\x5b\x0c\x43\x8c\x18\x00\xe1\xbb\xb3\xd4\x11\x66\xc4\x82\x12\x3a\x86\xa9\xd6\x39\x83\x50\xa9\x9e\x9f\x98\xd6\x1f\x48\x2c\x07\x58\xee\x3a\x99\xce\xc6\xea\xd8\x84\xc0\x86\x37\x3f\xdc\xa3\x0f\x55\x46\x89\x93\x68\x13\xcc\x0e\x89\x17\x75\x65\x9a\x9d\xc9\x19\xb9\xef\x19\x67\x26\x28\xa4\x89\x33\xeb\xa1\x03\x5d\x0a\x3d\x4a\x2a\xbb\x74\xcf\x0b\x2b\x3a\x8d\x9f\x6b\x52\x45\xf4\xee\xd8\x02\x59\x43\x11\x5c\x24\xd0\x1e\x3e\x3e\x8b\x70\x56\x6c\x4a\x33\x43\x72\xb5\x70\x22\x18\xa9\xa1\xbb\x56\x9b\x94\x4c\xc7\xa4\xc7\x82\x64\x0f\xe0\x4c\xdf\x06\x6a\x66\x1a\x26\x50\x9e\x97\x50\x28\x8c\x78\xd9\x90\x3d\x61\x89\xfc\x95\x44\x1a\xc6\x13\x41\x2c\x98\x04\x8c\x61\x72\xc5\x54\x60\x4c\x2c\xab\xb4\x80\x9f\x73\xec\x55\x94\xda\x44\x7c\x0f\x65\x7c\x22\xe0\x00\x4c\x2b\x92\xc2\xcb\x34\x4c\x00\xee\xb3\xfd\xfe\x66\xbc\x63\xb4\xeb\xbf\x18\x83\x6b\xcb\x66\xf0\x1f\x65\x38\xe7\x46\x50\x1c\x3f\x03\x64\x3a\x4e\x20\x33\xb9\xf8\x55\x93\x8c\x2a\x72\xcd\xc1\x94\x20\xcc\x08\x16\x34\xde\x65\x17\xf6\x9b\xd0\x2b\x4e\xff\x4d\x5e\x96\x4d\x76\xf0\x68\xf1\x6a\xa1\xb4\x33\x66\x4d\x8f\xc2\x54\xbe\xf8\x22\xce\xec\x7d\xb3\xfe\x58\xb6\x0e\x78\x06\x14\xa1\xfc\xf8\x87\x0f\xb2\xcf\xe6\xce\xe8\x83\x11\xd7\x03\x29\x24\xcb\x8e\xeb\x7c\xa0\x6b\x7f\x0a\xa0\xc1\xbc\x35\xd8\xbd\x04\x0a\xd6\xc3\xd0\xa0\xe1\xfa\x98\xaf\x98\x3e\x46\x31\x76\x70\x33\x45\x1c\x35\x93\xf5\xfb\x60\x06\x64\x6c\x0e\xb4\x4c\xac\x0a\x21\x87\xb1\x60\x8b\xb2\x4e\x28\x28\x09\x82\xbd\x74\x80\x00\xfd\x52\xc0\x2e\x25\x2b\x2f\x58\x2b\x29\x40\x74\x05\x43\xe1\xda\xaf\x64\x38\x92\x5c\x27\x68\x20\x31\x02\x84\xb6\x6a\x18\xb1\x2c\x54\x46\x1e\x0f\x10\x5b\x9d\xe5\x5a\xad\x9a\x3f\xc5\xdd\x7a\x9e\xe5\x10\x06\xce\x3e\x1e\xb4\xd5\x4e\xed\xb4\x8b\xf3\x35\x74\x2a\x63\xd0\x72\xc0\x32\xc6\x54\x0d\x5a\x86\x41\x68\xa4\xe1\xc3\x5f\x23\x21\x69\x83\x70\x4d\xb3\x9a\x99\xe4\x3d\x6d\xe1\xca\x63\x09\x2f\xe6\xd6\x0e\x86\x46\x02\x24\x55\x38\x44\x66\xfd\x4b\x2d\xf0\x6c\x47\xe7\x70\x9e\xc4\x92\xed\x41\x2f\x10\x6d\xe1\x89\xa3\xd3\x8f\x8c\xc0\x28\x44\xf1\x92\x2d\x2d\xcc\x1c\xf4\xac\x01\xad\x44\x11\x79\x04\xbb\xaf\xcf\x20\x95\x72\xe1\x36\x47\xfe\x01\x49\x17\x06\x27\xa5\x02\x4d\x6c\x32\xac\x92\x0b\x86\x60\x62\x34\xdc\x94\x14\xbf\x9e\xa1\xd0\xbc\x70\xcc\x39\xe9\x2b\x10\x2c\x01\x0b\x9a\x8d\xcc\x84\xde\x4f\xf6\xa9\xd6\xb6\x86\x91\xed\x69\xc1\x37\x24\x1e\x51\x1a\xda\x10\x5b\x3b\xb6\x2b\xed\x89\xc3\xd1\x28\x18\xdf\x68\xdc\x83\xba\xa5\x61\xc8\x7a\x38\x68\x34\x10\x14\x30\x34\xa3\x05\x23\x84\x83\xb5\x2b\x46\x15\xca\xa9\x06\x17\xdf\x55\xb5\xa0\x5b\x82\x07\x8e\xb1\xd6\xc0\xdb\x2d\xd6\x92\x06\xa0\x75\xf7\x01\x05\xa6\x07\x89\xc7\x4b\x84\xd4\xcd\xd3\x76\x7e\x23\x19\xfe\xb2\x6b\x3e\x05\xd5\x06\x45\x00\x6a\xbd\x80\x04\x99\xc4\x46\xc0\x1d\xbb\xb5\x0f\x01\x9b\xcd\x80\x12\xa3\x15\x86\x61\xb7\xf8\xe1\xe3\x01\x98\x51\x97\xac\x5f\x41\xe7\xba\x64\x8a\x1b\x0e\x25\xa4\x97\x19\x69\x1f\x89\xb1\x10\xcc\x9a\x27\x6a\xbb\x69\xdc\x76\x65\x98\x5a\x6d\xb8\x69\x14\x58\x42\x9d\xe3\x5f\x51\x24\x53\x21\x46\x23\x48\xcc\x1e\x39\xab\x5a\x84\x26\x44\x8b\xa3\x6c\x1a\x12\x20\x40\xad\x4d\x7d\xc7\x17\xcb\xd5\xc0\x01\xc8\x33\xdb\x9f\x20\x03\xb5\x94\xc6\xe4\xb1\xa7\x0b\x7c\xcd\x5f\x99\x14\xa0\x04\xd8\x79\x49\x69\xa5\x15\xb0\x46\x30\x29\xc5\xe0\xa7\x93\x69\x04\xfa\x11\xc8\xc1\x30\x5d\x5a\x98\x8c\x1d\x00\xa3\x53\xcb\x78\x2b\x21\x81\x7c\x4a\x41\x2a\x33\x39\xf2\x19\x67\x0b\xe9\xd5\x95\x16\x69\x88\x25\x6e\x33\xde\xa6\x2f\x02\x58\x70\xdd\x61\x66\x78\x9f\xc2\x9b\x88\xe3\x63\xf9\x62\x40\xe3\xed\x6b\xb5\xda\x42\x22\xf1\x3b\x0a\x1e\x1c\x58\x80\x63\x31\x36\x2c\x6d\x52\xd9\xfd\x52\x76\x33\xbc\x9b\x3f\x8c\x73\x92\x3a\x42\xde\x8f\x22\xc6\x60\x83\x87\x53\x9d\x72\x46\xee\x67\x6f\x06\xc6\xbb\x5f\x7e\x49\x26\x0d\x88\x1e\x4a\x7e\x20\xdb\x21\x2b\x23\x3c\x5f\x4a\x30\x32\xce\x20\xa8\x3f\xca\x52\x28\xce\xf3\xec\x23\xcb\x30\x70\xdc\x9d\xe2\x8b\xd5\xe0\x44\x40\x38\x9b\x20\x0a\x3c\x45\x85\x1f\xac\x7b\x9f\x98\xf2\x79\x06\x79\x42\x82\xb1\x51\xb8\xb7\x81\x23\xa4\x89\xc1\x52\xe4\x72\xb0\x41\xc7\xce\x52\x5f\x92\x44\x62\x47\xdf\x52\xd2\x02\x86\xcc\xd1\x10\x5b\x18\xa1\xef\xb4\x5e\x46\xd5\x97\x23\x28\x52\xec\x75\xe6\x9d\xa0\xd9\xdb\x51\x21\xa6\x18\x54\x43\x08\xf1\xd2\x00\x71\x30\xfd\x26\x8e\x38\xb2\xd3\xe3\x0e\x04\xa8\xea\x0e\x96\xd9\xc4\xf5\x38\xce\x51\x1d\x1a\x45\xc4\x10\xb6\x66\x90\xce\x8b\x34\x6f\x86\xa0\x7b\x80\xf2\xdd\x52\x49\x89\x65\x9a\x3e\xf1\xbc\x44\x1c\xa0\xc6\x8c\x00\x84\xf9\x92\x6a\xdc\x54\xa3\xd8\x85\x15\xf2\x1e\xf8\xa0\x8d\xbf\x60\xb2\x4e\x05\x0b\x04\x4f\x1a\xdb\xaa\x29\x6d\x93\x62\x0c\xb7\xa9\xbb\xf9\x5f\x08\x59\x25\x03\x7a\x9c\x7e\x08\x03\x5c\xf3\x17\xd6\x87\x7c\x90\x72\x68\x47\x8a\xdc\x19\x53\x74\x54\x40\x13\xc3\xaa\x20\xb6\x53\x9e\x2b\x83\x8b\x70\xea\x07\x70\x1f\xb8\x8b\x0d\x89\x5d\x1d\x2d\x10\x09\xdd\x22\x3b\xa3\x31\x08\x1b\x39\x08\xdd\xa1\x82\x18\xeb\x66\xef\x90\x24\x26\xe2\x7d\x7e\x39\x0e\x80\xb0\x94\x27\x40\xf2\x3e\x41\x0e\x00\x3f\x21\x9f\xaa\xc9\x9f\x95\xcb\x0e\x93\x51\x76\xb7\x1c\x2c\x22\xc4\x06\xad\xc4\xb3\xac\x28\xbf\x12\x0f\xec\x52\x65\xb7\x03\x35\xb6\x44\x2d\xb9\x32\x85\xae\x52\x91\xa4\x1d\x58\x39\x24\x3d\xfc\xc8\xe8\x50\x05\x45\x25\x31\x52\x02\x15\xb0\xcd\xb1\x86\xb8\x23\x91\x37\xcb\x50\xbf\xc9\x28\x3d\x2c\xbe\x81\x25\x14\x81\xf8\x95\x31\x12\x07\x1b\xca\x85\x90\x04\xe1\x72\x15\xaf\x8e\xc4\x99\x62\x24\x0c\x95\xab\x5e\xa0\x70\x05\x42\x36\xe2\x89\x80\x64\x90\x41\xf5\xc8\x43\x22\xc3\xf2\x78\xfd\x90\x70\x68\x7b\xe0\xe0\x95\xd3\x8b\x2c\x1e\x12\x32\xea\xfa\xdd\x5a\xe8\x53\x24\x00\xb3\x21\x81\x32\x2c\x71\xce\x11\x39\xbf\xab\x3f\xd1\xe6\xf4\xd9\x94\x37\x4f\x6e\x5c\x09\x81\xb9\x66\xe9\x20\x5b\xb9\x74\x0f\xf2\x2c\x17\x63\xe4\x68\x2b\x15\x00\xa4\xbb\x50\xaf\x48\x04\xd7\x7a\x58\x58\x21\x6d\x35\xa3\xc2\x35\x34\x88\xd1\x4e\x1e\x0c\xfe\xc0\x32\x20\x54\x33\xc4\xd8\x21\x6b\xf9\xe6\x11\x5b\x09\x77\x88\x0f\x63\x48\xab\x40\x99\x42\x89\xad\xb1\xe1\x1c\xf2\x6d\x56\x68\x57\x8e\x64\x83\xb0\x28\xb6\x70\xb0\x01\xad\x42\x6b\x33\xd5\x0b\x20\xe4\xf0\x7c\xde\x3a\xd0\xf3\x97\x4b\x31\x9a\x1a\x08\x18\x82\x38\xec\x78\x3f\x82\x3f\x01\x64\x78\xaf\xd4\xb0\x2b\x3c\xf0\x5a\xa4\x3b\xfa\xf4\x3b\xc4\xbd\xd1\x04\x53\x21\x39\xd5\xa4\x0d\xb1\x03\xf5\xeb\x6d\xd4\xa2\x5e\x21\x5b\x01\x80\x07\x8a\x0c\x56\xa5\x7c\xb1\x61\xfc\x2f\xae\x2c\x78\xd4\x12\x56\x08\x4e\x1c\x4e\x3e\x65\xc6\x09\x07\x2f\xcb\x88\x02\xa3\x50\xcb\x36\xa0\x8b\xaa\xed\x49\x7f\x6b\x89\x73\x19\x21\x19\x31\x95\xc2\x97\x54\x10\xe6\x56\xda\x2b\x48\x35\x5a\x8d\x86\x81\xcc\x92\x91\xc2\x8a\xf7\x0e\xb1\x47\x18\xa5\x09\xac\x52\x37\x4d\xf0\xde\x72\x00\x71\x50\xc9\xf0\x35\x8f\xae\x3e\x07\x7a\x95\xdd\x53\x04\x0e\x5d\xa7\x38\xa9\xa5\xb5\x32\x72\x93\xa2\x4b\x04\xf1\x05\x4b\x84\x5b\xb9\xf5\x9b\x36\x0b\xcc\x48\x6c\x89\x5e\xff\x90\x80\x7c\x64\x00\xc8\x77\x51\xbf\x81\xc6\x12\x99\x6e\xdf\xff\x3c\xf6\xc6\x25\x61\xda\xd4\x8a\xf9\x66\x94\x4d\xcb\x6d\xa4\x55\x62\xe8\x8c\x73\x55\x22\xd6\x71\x62\x6c\x2f\xab\x77\x0f\x89\x42\xb8\x4f\xd9\xa0\xe6\x05\x77\x6a\x42\x0d\x4d\x59\x43\x0a\x90\x13\x02\x94\x4e\x30\x7f\x3c\x62\x24\x4f\xbd\xf8\x63\x45\xd3\xc6\xc9\x5d\x60\x7b\x8f\xcf\x33\x37\x9a\x22\x40\x17\x72\xf8\x3f\x24\x00\x51\xd3\x36\x2f\x90\x03\xe1\xd1\xe3\xea\x57\xa1\xb9\x65\x21\x7d\x1a\x78\xcd\x8a\x00\x56\x21\x8a\x81\x41\x19\x87\xa0\xb0\x50\xc3\x1b\x3b\x3c\xd8\x5b\x2f\x61\xb0\xab\x97\x1e\x32\x13\xad\x49\xd4\x45\xd6\x33\x1e\x25\xc0\x45\xb6\x23\x01\x39\x8a\xd9\x06\x26\x63\xa7\xc1\x9c\x4c\x60\x4e\xf8\x9e\x0b\xb7\x59\x99\xd6\xab\xbd\xaa\xa5\x0c\xb1\xe5\x88\x4c\x97\x03\xa3\x07\x74\x4f\xf3\x30\x2e\x89\x9f\x8c\xdf\x5f\x46\xcc\xc3\xfc\x8c\xb0\xdd\x9f\x08\x43\xc4\xa8\x8e\x32\xda\x6e\x49\x96\x25\x35\x81\x6a\x08\x4a\x6b\xff\xd0\x8b\x79\x35\xaa\x09\x03\xfc\x66\x2e\x2c\x46\xab\x07\x6f\x79\x43\x64\xf5\xd0\xd9\xe9\x9c\xe4\x98\x23\x77\x48\x3a\x79\x22\xe4\xc5\xbd\x20\x41\x1a\x8a\x06\xbf\x4d\x38\x56\x8f\x88\x96\x29\xa6\x8a\xc9\x4b\x97\xdc\xa3\x79\x06\xfe\x99\xcd\xcd\x41\x05\x4a\x2b\x51\x7d\x7b\x61\x4f\x56\x2b\x8a\xe1\xbd\x1b\x23\x35\xa0\x8e\x95\xb7\x95\xda\x43\x64\x53\x52\xbe\x22\xd3\xb6\x15\x2e\xd2\x82\x8e\x4a\xf9\x93\x5a\x0c\xc9\x7f\xe8\xeb\x7b\x13\xb1\x50\x01\x90\x5b\xa1\xf7\x88\x8e\xe5\x14\x89\xb7\x5d\x3e\x4e\x4a\x25\xb1\xfe\xec\x0b\xb5\x1d\xce\x27\x39\xc4\xb3\x2f\x8f\x0e\xfc\xac\xec\x62\xa6\x3b\x30\xe3\xcc\x33\x0d\xa7\xc1\x08\xaf\x37\xac\x74\x45\x49\x3a\x27\x1c\x73\x72\x3f\x04\x07\xef\x10\x67\x76\x5a\xf6\x78\x49\x94\x3e\xd3\xc4\x69\x03\xbc\xf5\x46\x90\xf2\x34\x83\xd9\x19\x35\xa6\x8c\xf6\x84\x48\x68\xdf\x65\x1d\x13\x74\x77\x7a\x75\x86\x8f\x0f\x08\xb4\x04\x18\x71\x86\xd1\xbe\x09\x58\x2a\xb4\xb5\x71\xd0\x5d\x38\x72\xe2\x48\x0e\x6b\xda\x0e\xf0\x16\x2b\x4b\x1a\xe7\xc0\x3d\xe2\x35\x64\xb5\x49\x73\xb0\x09\x8f\xe0\x62\xb8\xe5\x13\xe8\x82\x08\x5f\x62\x98\x25\x4c\x4e\x0f\xe0\x66\xd7\x44\x4a\xd5\xe6\xf5\x49\xd8\x04\x14\xc9\x1b\x68\xf8\x4d\x2d\x5e\x5a\x89\x21\x58\x72\x6d\xf3\xe1\xcc\x29\x09\x49\x9e\x11\x50\x72\x8c\x44\xf7\xdc\x4d\x6a\x1a\x39\x88\xd7\xe8\xb6\x60\x7f\x78\x44\x4a\x72\x64\x04\xc4\xce\xdc\xce\x78\x2c\xb4\x1b\xd8\x1c\x45\x56\xc6\xad\xd9\x83\x7b\x93\x85\xfd\xd9\xe6\x69\x8c\xeb\x93\xfc\xef\xac\x85\xd4\x80\xf1\x7c\xac\x91\x66\x40\xc5\xf2\x14\xb8\xbf\x26\x16\xd1\x3a\x7c\x81\xb1\x4f\x5e\x58\x6a\xce\x33\x72\x13\xb8\x58\xa7\xbb\x8b\xeb\xec\x2d\xf2\xa6\x48\x7a\x58\xb4\x07\x7a\x2c\xb8\x90\x3c\x25\x1a\x5a\xb4\x77\x4d\x33\x5e\xdf\x4d\x1c\x3b\x5d\x45\x66\x41\x31\xab\x1a\x54\xc7\x84\xdd\x0e\x9a\x89\xc1\xb1\x01\xe9\x8c\x90\x2e\xfa\x85\x14\x8f\x4f\xa0\xb4\x28\xcd\xa1\x77\x68\x82\x46\xc2\x82\xf1\xfa\x19\xc4\xab\x5c\x81\x85\xd5\xca\x5b\x08\xb7\x1e\x8e\x20\x6d\xc9\xf0\x12\xcd\x88\x4c\x6e\x01\x40\xdc\xe7\xcb\x55\xf8\x0d\x43\x67\x5f\x2b\x8b\x34\xc2\x89\xa0\x61\xec\xe7\x53\xfe\x85\x9c\x16\x27\x22\x51\xdf\x79\x01\xc1\x4a\xdc\x40\x90\xe8\x28\x46\x7f\xe7\x42\x5f\x34\x39\x34\x41\x58\x6f\x46\xe3\x58\x40\xa8\x4c\x29\x4e\x23\xf6\xb8\xd2\x4a\x71\x29\x06\xd1\x8b\x06\xef\xcb\x75\x14\x87\xf8\x3e\x8d\xbd\xa7\xe5\x3d\xeb\x32\xbd\xb8\x0d\x49\x6e\x0a\x69\x1a\xbc\x2d\xcc\xf0\x13\x31\xb2\x76\x50\x83\xa6\x6e\xa9\x11\x42\x12\x10\x34\xc8\xa5\xa3\x10\xac\x18\x32\x33\xd6\x0e\x00\xdc\x4b\x98\x6a\x15\xac\x6d\xa1\x1b\xb8\x2a\xc3\xad\xfb\x8b\x33\x49\x0a\xe8\x73\xc1\x11\x13\x0e\x65\xf8\x28\xf6\x9c\x84\x4e\x5e\x97\xbe\x70\x6e\x84\x5b\x5e\xec\xcc\x89\xb6\x0c\x58\x03\x75\x23\xc5\x7d\xd8\x43\x44\xc9\x1e\x82\xc2\x4f\x52\x78\x82\x6e\x0f\xa1\xef\x9b\xfc\x79\x90\x85\x74\x46\x04\xe4\xeb\xed\xf9\x35\xd6\xf8\x9c\xf5\x1a\x2e\xa0\x6b\xe8\xf9\xa1\xad\x69\xd1\x5f\x56\x11\xd0\x74\x84\x38\xf0\xc3\xdf\x09\xce\xdc\x68\x43\xe2\x8c\xd2\x66\xc9\x03\xcf\x03\x54\x7d\xbb\x94\x0d\x63\x45\x1b\x04\x75\x0a\x26\xce\xcc\xc3\x8c\xa3\x1b\xbc\x0e\xe8\x89\x42\x25\xdc\xc7\x5d\x0c\x5a\xf7\x31\x96\x8b\xd4\x04\xfe\xcd\x44\x46\x57\x3c\x8e\x83\x10\x7a\xe5\x68\x48\xeb\xc0\x93\x4b\xb3\xd9\xa4\x88\x9d\xe4\x02\x3d\x63\x8b\x33\x60\xe0\xfe\xba\x3d\x2e\xbd\xa2\x5b\x78\x3a\xa0\xac\xf6\xd2\x69\x5d\xe0\x08\x56\x7d\xec\x85\x6b\xce\xea\x6f\x10\x12\x91\xff\xa3\x50\x19\x01\x53\xa5\xc0\xf9\x3c\x25\x02\x6c\x95\x87\xc8\x88\xab\x95\xd3\x2a\x64\xc9\x9b\xac\x68\x04\xf0\xe2\xa5\x1e\x9f\x67\x87\x05\x12\x7f\x39\xcc\x97\x75\x0d\x59\x2d\xbe\x52\x01\xfd\x82\xf3\x11\xad\xdd\x85\x14\x91\xcd\x0e\x52\xf7\xfc\xa5\x38\x35\x7b\x52\x25\x8d\xc9\x3c\xa1\xe0\xfc\x08\x4b\x1f\xa7\xb0\x2e\xcf\x66\xbc\x04\x08\x1e\xce\x9b\x67\xe8\x05\x2a\x3f\xbc\x73\x47\x5e\x62\x24\x45\xf6\x38\xed\xee\x8a\x28\x49\xa0\x91\x11\x15\x9d\x8c\x57\x7a\x23\x00\x7a\x84\x17\xca\xb0\xf8\xf5\x0b\xd6\x2c\xec\xcb\xe8\x14\xca\x1e\xe3\x03\x7e\x27\xbc\x89\x3c\x42\xca\xd0\x4e\xff\x8b\x3e\x91\x13\xc9\x52\xba\x90\x05\x2f\xf1\x7c\x28\x87\xb8\x0d\x6d\x7a\xf1\xf9\x89\xa6\x5b\xf1\xa5\x8e\xfa\xff\x6b\x68\xba\x88\x30\x65\xe7\x6f\x61\x8a\x49\xf0\xc0\xf1\x99\x6c\x73\x9c\x87\x6f\x85\x88\xda\xbf\x66\x5e\xc0\x49\x3c\x46\x65\xb2\xc7\xe4\xbb\x4a\x84\x92\x76\x94\x46\x09\xea\xbf\xb7\x51\xb8\x2a\x85\x20\x70\x16\x72\x82\xb4\x1a\x73\x02\x13\x5b\x27\x15\x7b\x44\x7a\x5d\x8e\x75\x77\x70\xe5\x09\x98\xf1\x98\x7d\x1f\xc2\xee\xa8\x57\x3d\xd5\xdc\x7a\x15\xb3\x48\x7a\x24\xe6\x16\x86\xad\xf3\x5f\xe7\xb5\x76\xeb\x5a\x87\x6a\xf2\xeb\x57\x68\xc7\xbb\xe2\x11\x01\x6d\x00\x96\x79\x3a\xc7\xea\x40\xba\x19\x0b\x11\xb3\x53\x3d\xa6\x64\xe8\x8e\x34\x20\xf1\x6a\x8c\x2d\x98\xcc\x0a\x63\xe3\x44\x5b\x30\xf1\x44\x01\xb6\xf8\x1c\x82\x07\x33\xe4\xa4\x3f\x71\xa5\xda\x24\xde\xd1\x56\x29\x22\x51\x3d\xd9\x47\xb2\xe1\x0c\x17\x64\x6c\x92\x22\x97\x63\x64\xc1\x1b\xb0\x23\x6c\x25\xeb\xf7\x62\xb1\x84\x48\xe2\xf7\x62\x21\xd0\x50\xe6\x28\xd2\x35\x4f\xad\x76\x2d\x50\xe3\xf7\x3d\x7f\xbd\x7b\x70\x10\x52\x65\xa8\xbd\x81\x5c\xb8\xa0\x56\x95\x03\x00\x5b\xea\x5a\x70\xd3\x6a\x2d\x0f\x83\x8f\xfb\x07\x08\x37\x30\xd6\xae\xb2\x86\xaa\x34\x07\x52\x07\x6e\x12\xed\xbe\xea\x04\xd8\x91\x26\x96\xb2\x08\x44\x24\x67\xe2\x33\xac\xa3\xbc\x01\x36\x2b\x50\xc4\x6a\x1f\x4e\xf4\x25\xe7\x72\xa1\x5d\x0d\xca\x33\x84\x26\x2f\x02\x05\x72\x67\xb9\x19\x80\x28\x78\x7a\x13\xbd\x4c\xcf\xe5\x26\xf8\x01\x83\xe2\xfd\x2a\x82\x1a\x22\x0a\x7c\xfb\xf1\x39\xa7\xce\x4e\x89\x00\x33\xf8\xa2\x47\xc1\x3d\x3f\x91\x87\x06\xfd\xe4\xb5\x41\x33\xe8\x97\x06\xaa\x6e\x4b\xc1\x7a\x20\x1a\x38\xb0\x76\xf8\x27\xde\x10\x21\xde\x7c\xa7\x78\x43\xf0\x2f\x91\xd3\x8c\x77\xc7\x8c\x9a\x1c\xa8\x13\x20\xe2\x61\xbf\xe3\x07\xde\x0a\x28\xde\x08\x1e\x8d\x24\x90\x86\x48\x92\x42\x08\x3b\x32\x9c\x97\x42\xe3\x95\x55\x03\xcb\x85\x11\x68\xf6\x25\xb3\x60\xc9\x96\x12\xc1\x59\x11\x22\xc2\x9e\xd7\x1f\x43\x97\x81\xe1\x0a\xc2\xe9\x33\x88\x32\x80\x6a\xb0\x85\xc3\xa5\x93\x21\xa1\xa3\xf0\x32\xcf\xd3\x8b\x81\x3b\x61\x3a\x8f\xba\x89\x33\xd3\x45\x63\xe6\x1c\xb3\x53\xb2\x0d\x4c\x88\x1d\x1c\x1b\xed\x04\x2d\xa9\x91\x8b\xaf\x67\xbd\x12\x44\x52\xa0\xe4\xf7\xb2\x10\x5e\xe7\xbe\xaa\x98\x0a\xa4\x5b\x36\x5d\xc9\x32\x77\x6b\x00\x5c\x9c\x39\xc2\x71\x24\x98\x78\xf4\x4b\xe1\x16\xa8\x8a\x55\xd9\xe5\x1d\x59\xea\x7b\x4f\xcb\x01\xed\xb4\x15\x61\x03\x52\xf2\xfe\x32\x78\x11\x45\x0c\x60\x50\x4b\x77\x08\xb0\x11\xa0\xce\x62\x25\xe9\xd0\x13\xa1\xb4\x13\x66\x95\xba\xc5\xbb\x4a\xea\xff\xf5\x63\x81\x96\x1b\x61\x56\x36\x9f\x34\x1e\xc1\x2e\x84\x35\xe1\xbd\x40\x69\xbc\x38\x05\x61\xf6\x55\x33\x19\x8e\xa2\xca\x52\x27\xe1\xe9\x8f\x7a\x05\x0d\xb4\x5b\xc7\x0a\xc5\x21\xfa\x22\xd9\xe5\x57\x43\x00\x12\x4c\xe2\x8f\x8b\x84\x60\xc4\x83\x06\x03\x60\x95\x9c\x2f\xf2\x0f\xc0\x6c\x04\x50\xcd\xe8\x5a\x71\x55\xea\x31\x6f\x06\xb0\x2a\x28\xa3\x9b\x12\x92\x6c\xf2\x87\x20\xf3\x9d\x0d\x70\xca\x26\x62\xe3\xe0\x7e\xde\x45\x53\xde\x71\x93\x7b\x2c\xd4\x44\xac\x30\x11\x10\xaa\xc6\xb5\x76\xe7\x39\xde\x3a\x10\x9a\x9a\xf5\x43\x59\xae\x4e\x16\x33\x13\x2e\x30\xcd\x69\x61\x18\x48\x6a\x81\xad\x28\x29\x29\xca\x1a\x48\x43\x2f\xac\xe0\x78\x38\x99\x24\x39\xe2\x81\xfa\x12\x4b\xf9\xf0\x8a\x43\x5d\x35\x43\x82\xb3\x84\x89\x15\x54\x7f\xcd\xb5\x03\xce\x59\x64\x95\x80\x05\x87\x2f\x43\x84\x4f\xd8\x03\x72\xfe\x08\x9e\x77\xf7\xa5\xee\x05\x2c\x2c\x9e\x72\x8c\x51\xb6\x14\xa7\xaf\x08\x13\x01\x50\xe9\x34\x2e\x4c\x14\xee\x51\x68\xdb\x2d\x60\xcc\xbc\x8b\xad\x63\xf9\x96\x74\x2f\x5e\xef\x1a\x64\x65\xa7\xaa\x54\x7c\xe7\xc8\x88\x6b\x67\x21\x82\x71\x3a\x66\x91\x1a\x19\xa6\x3b\x90\x7c\x4a\x80\xfc\x69\x3b\xb0\x06\xe3\x68\x0f\xde\x20\x3f\x96\x30\xc1\xcc\x5e\x4e\xb6\x68\x1c\x48\x28\x74\x17\x05\xe1\x03\x8a\xd9\x30\x0f\x0c\x9c\x2f\x33\xba\x39\xa7\x84\x4e\x1d\x78\x02\x7e\x8c\x2c\x2f\x03\xa4\xb3\x1e\x88\x36\x19\x11\x99\x08\x77\x9e\x42\x74\x88\x66\x8c\xaf\x67\x6a\xb6\x09\xb8\xbe\xc8\x6f\x65\x38\x17\xb5\x3b\xad\x85\xf9\x00\x73\x60\xd1\x56\x99\xa1\x19\xb9\x75\xe7\xbb\xbc\xec\x0b\x64\xc9\x00\x18\x58\x4f\x7b\xb7\x59\xcb\x60\x05\xe8\x3c\x4c\x0d\xe8\xc5\x26\x01\x57\xa4\x4c\x71\x05\xf8\xde\x93\xa2\xfc\x28\xdd\x02\xd6\xcc\xa1\x9a\xd9\xa6\x8d\x77\xdc\xbf\xe5\xbe\x6b\x1d\xbf\x4f\xd3\xe5\x1e\x9c\xd2\xa7\xcb\xe6\x28\xc4\xb2\xe5\xd0\xea\xa6\x6f\x84\xb2\xcd\xf3\x39\x25\xf6\x51\x83\x38\x7b\x30\xf4\x26\xc9\xb0\xf8\xb0\xa1\x67\x93\x8a\xa4\xbc\x0f\x0d\x49\x1e\x24\x00\x9d\xd0\x9d\xba\x06\xb7\x71\xaf\x8e\x66\xaa\x3f\x9c\xde\xeb\xc9\x21\x53\xe8\xc6\xbe\xcf\xaf\xac\xf3\x56\x50\xa1\xee\xf4\x34\x06\x6f\x93\x3f\x27\x32\xcc\x3e\xc1\x80\xea\x4b\x29\x3f\x09\xce\x92\x1f\x1c\xd6\x3a\x51\x88\x2d\xa7\xdf\x9c\xb4\x74\xc6\x97\x26\x68\x7b\x9e\x37\x1e\xb2\xc9\x48\x75\xb7\x17\xb4\x99\x9a\xc9\x99\xe1\x95\x29\x62\x42\xd9\x28\x24\x84\xc8\x99\xa5\xdc\xa5\x54\xda\x61\xdb\xad\x7f\x17\x1e\xc3\xd3\x70\x3b\x3c\xdc\x4c\xa6\xc9\x2f\x7b\x0c\xb9\x40\xc4\x1e\xe4\x7f\xaa\xcf\x98\xa9\xb2\x1b\x3d\x62\xfb\x14\x0b\xca\x81\x88\x6b\x0a\xa5\xa2\x41\xb5\x19\x05\x07\x89\x1e\x1c\x23\x0c\x8d\x79\x9c\x50\x28\xa8\x46\x35\x8a\xbf\x98\x80\x0b\x26\xd8\x43\xb0\xec\x1c\xa5\x42\x25\x73\x5d\x27\xcf\x42\x18\x47\xdd\x6c\x5b\x32\x66\xf4\x26\x5e\x3b\xd1\xb3\x7c\xb8\x92\xf8\x9f\x11\x97\x26\xa0\x8c\x0f\x58\x74\x7e\x80\x00\xc7\x97\xc2\x71\x7a\x1a\x11\x40\x1e\x24\xc7\x29\xc6\xe7\xe0\x87\xe8\xbb\x3f\x67\x30\xa4\x0c\xc1\xfa\x7a\xd9\x97\x8f\x04\x28\x81\x42\x4f\xf0\x6b\x3f\x4a\x8e\x2a\x98\x36\x41\x0e\xa2\x25\xc1\x70\x9e\xb8\x8b\xdf\x48\x21\x26\x71\xe1\x0a\xd6\x8f\x99\xce\xbc\x23\x61\x89\x10\xa1\x48\x0c\xbe\x27\x73\x3a\x6f\x8e\xce\x1a\x62\xae\xaf\xe0\x5a\xf1\x82\x65\xe2\x64\x56\xc9\x2b\xf9\xca\x3d\x91\x02\xdd\x13\xc7\xd7\xe6\xd0\x5a\x46\x35\x86\x09\x5e\xd1\x1a\xe3\x22\x13\xdd\x2c\x2b\xb2\x1d\xe9\x2c\x07\x00\x4d\xbc\x43\x1a\xfe\x80\x51\x44\x38\x15\x53\x34\xc8\xf8\x51\xb0\x5f\x2e\x0c\xb5\xcd\x70\xda\xe0\xeb\x1a\x35\xc1\x26\x01\x6a\xb3\xa6\x7b\xde\xbf\xc2\xa8\x17\xce\x09\x5e\x5f\x95\xa5\x6b\x58\x72\x78\x19\x8b\x76\xf2\x0a\x7d\x73\x4c\x44\xf5\x1f\x32\x16\xb0\xf8\x0b\xb0\x4f\xd6\x92\xb3\xe9\xd1\xa7\xb4\x43\x8d\xb6\x1b\x93\xde\x04\x57\xc9\xe9\xc8\xbd\x52\x52\x75\x88\x6e\x43\xc4\x26\x9a\xaa\xe3\x1b\x46\xb4\xb6\xa3\x27\x72\x37\xc6\x67\x43\xcb\x89\x84\xca\x63\x87\x1f\x7c\x51\x6d\xce\x31\xfe\xa5\xf9\x47\x06\x50\x9f\xf7\x14\x3e\x6a\x20\x0f\x00\x9f\x24\x9d\xbc\x1d\x36\x33\xf1\x4b\x6d\x18\xfa\xfd\xbc\x1c\x0f\x20\xcb\xac\x77\xa6\x17\xe3\x83\x85\xa9\xe1\x61\x9a\x79\x5a\x30\x33\x17\xa3\xc9\xd1\x0c\x1f\x4e\xb7\x79\x6e\x49\xc2\x41\x10\x4b\xb4\xac\x3f\xfc\x30\x1e\x5c\x11\xe0\x61\xf5\x2e\xa3\xba\x92\x07\xd4\x67\xb9\x35\x7e\x34\x1a\x20\x71\x71\xf6\xd0\x61\xe7\x11\x7a\x04\xef\xe5\xed\x95\xb7\x72\x3f\x22\xc8\x88\x7f\xca\xc6\xe2\x27\x52\x98\x25\xb3\xd6\x20\x16\xf1\x71\xe4\x4b\x87\x52\x43\x03\x08\xff\x87\x56\x18\x26\xc0\x1f\x58\x5c\xa7\xdc\xf8\x84\x8b\x0b\xca\xe3\xce\x4f\xbd\xab\x43\x17\xf6\x95\x6e\x5f\xc6\x8b\xdb\x73\xba\xa2\xa5\x49\xd9\xf8\xad\x1c\x40\x4e\x7e\x45\x2b\xd6\xf4\x00\xe0\x93\x86\x32\xee\x31\x97\x41\xd3\x11\xf4\x40\x70\x49\xe0\xba\x68\x26\x0e\x32\x4e\x29\x26\x08\x13\x3a\x5f\xa4\x00\xce\xa3\x40\x2c\x60\x45\x91\xbc\x2e\x2d\x9a\x3b\x10\xd2\x51\xeb\x72\x48\x08\xb0\x72\x55\xe2\xab\x41\x4d\x9b\x8d\xd0\x0c\x4c\xe3\x4b\xac\xd2\x92\x99\x05\x7b\xc1\xa5\x4c\xee\xad\x9b\x19\xd6\x6a\x4f\xc4\x4c\x8f\x88\x68\x77\x13\xcb\x93\x92\xb6\x91\xa3\x85\x11\xc3\x05\x07\x23\x86\x08\xff\x70\x70\x7c\x43\xc1\xdb\x63\x9a\x20\xec\xd3\x79\xef\x60\x50\x6f\xa3\x44\xfe\x25\x26\x92\x4c\xa0\x47\xe4\x33\x44\x67\xa3\x60\x6b\x63\xd2\xc0\x2b\x26\xdb\x80\x06\x14\x8c\x28\x21\x66\x44\x70\xde\x29\x1d\x6a\x76\xcc\xa0\x11\xd0\x9c\x86\xd7\x70\xa4\xc0\x62\x22\x03\x73\x23\x80\xd6\x31\x06\xc5\x53\xac\x92\x95\x6e\x7d\x0d\x36\xd7\xd1\xa0\x80\x4a\xa7\x1d\xbf\x2e\x75\x67\xea\xbf\xe6\x9c\x86\x36\xec\xd5\xde\x84\x34\x46\xab\x95\x18\xf4\x8b\x60\x91\x70\xe2\xbe\x22\xd2\xa1\x00\x6c\xfb\x41\x0a\xf5\x34\x95\x8d\x8d\x66\xcf\x3e\x04\xee\xef\x25\xc4\x91\xbc\x7c\x61\x3b\xab\xb5\x96\x0d\x0b\x40\x50\x57\xfe\xd0\xec\x17\x5c\x03\x33\xac\xb0\x84\xe3\xc5\xb6\xd5\xac\xeb\x42\xf7\x9d\x96\xee\x06\x55\x11\x77\xa9\xd4\x72\x8e\xe7\xf9\xb5\x0b\xe0\x95\x13\x15\x4a\x8c\xe1\xd0\x2f\x08\x01\x00\x00\xff\xff\xc4\x64\x53\xf9\xd9\x5e\x00\x00") func fontsInconsolataBoldWebfontEotBytes() ([]byte, error) { return bindataRead( _fontsInconsolataBoldWebfontEot, "fonts/inconsolata-bold-webfont.eot", ) } func fontsInconsolataBoldWebfontEot() (*asset, error) { bytes, err := fontsInconsolataBoldWebfontEotBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "fonts/inconsolata-bold-webfont.eot", size: 24281, mode: os.FileMode(509), modTime: time.Unix(1492020681, 0)} a := &asset{bytes: bytes, info: info} return a, nil } var _fontsInconsolataBoldWebfontSvg = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\xfd\x6b\x9f\x25\xc7\x71\x26\x86\xbf\xd7\xa7\xc8\x1d\xfe\xff\xf2\x35\x1b\x19\x11\x79\x5d\x10\x94\xbd\xa2\x2c\xaf\xbd\xbd\x2b\x5b\x5a\xad\xd7\xf7\x21\x66\xc0\x03\xbb\x04\xa8\x88\x54\x89\xdb\xbe\x7c\x76\xff\xe2\x89\xc8\x3a\x3d\x33\x7d\x9a\xc0\xcc\x90\x00\x28\xbc\x20\xa7\xd0\xa7\x4e\x9d\xac\xbc\xc4\xf5\x89\x27\x7e\xfe\x67\xbf\xfd\xbb\x2d\x1c\xaf\x7f\xf3\xcd\x97\x5f\x7f\xf5\xd9\x0b\xba\x4b\x2f\xc2\x37\xf3\xe5\x57\xaf\x5e\x6e\x5f\x7f\xf5\xfa\xb3\x17\x5f\x7d\xfd\xe2\xcf\x7e\xf1\x27\x3f\xff\x67\xbf\xfc\x37\x7f\xfe\x37\xff\xfe\xaf\xfe\x22\x7c\x73\xfc\x3a\xfc\xd5\xbf\xfd\x17\xff\xea\x5f\xfe\x79\x78\x11\x3f\xf9\xe4\xdf\xc9\x9f\x7f\xf2\xc9\x2f\xff\xe6\x97\xe1\xaf\xff\xf6\x2f\x03\xdd\xd1\x27\x9f\xfc\xc5\xbf\x7e\x11\x5e\x5c\xe6\xfc\xfb\x7f\xfe\xc9\x27\xff\xf8\x8f\xff\x78\xf7\x8f\x72\xf7\xf5\x6f\x7e\xfd\xc9\x5f\xfe\xe6\xe5\xdf\x5f\xbe\xfc\xfc\x9b\x4f\xfe\xfa\x6f\xff\xf2\x13\xbd\xf1\x97\x7f\xf3\xcb\x4f\xbe\x39\x7e\x4d\x74\xf7\x6a\xbe\x7a\x11\x7e\xf1\x27\x3f\xd7\x47\xff\xf6\xef\xb6\xaf\xbe\xf9\xec\x89\xef\x73\x4a\x49\xef\x7f\xf1\x8b\x3f\xf9\xf9\xdf\xbd\x9e\x2f\x5f\xbd\x9c\x2f\x7f\xf1\xf3\x4f\xce\xcb\x3f\xf9\xf9\xab\xd7\x5f\x7c\xf3\x8b\x3f\xf9\xf9\x17\x5f\x7f\x35\xc3\x97\xaf\x3e\x7b\xf1\xe5\x57\x9f\x7f\xfd\xd5\x37\x5f\x6f\x2f\xe7\xcb\x5f\x7d\xbd\xbd\x7a\x11\x2e\x5f\xff\xe6\xcb\x87\xf8\xf2\xd5\x11\x7f\xfb\xd9\x0b\x4a\x9c\xf1\xab\x7a\x7f\xfc\xe2\xe5\xe7\xaf\xc3\x3f\x7c\xf5\xe5\xfc\x26\xfe\xfd\xeb\xdf\xc4\xd7\x7f\xf7\xd9\x0b\x4e\xb9\xbf\x08\x2f\xbf\xf9\xfc\xf5\x57\xf3\xb3\x17\x54\xa5\xbf\x08\xaf\x5e\xfb\x7f\xc6\x4c\xe9\x45\xf8\x44\xc7\xf2\xe5\x37\xdf\x7c\xf9\xd5\xaf\xe3\xaf\xb7\xff\xf0\xf7\x97\x37\x7f\xa2\x24\xbf\xc7\x3e\x7b\xea\xea\x1f\xbe\xfa\xf2\xf3\xaf\x5f\xbd\xfe\xec\xc5\x9f\xfe\xec\xb7\xaf\x3e\x7d\xf1\xd4\x27\xe1\xc9\xbf\xfe\xb3\x17\xe1\xd5\x67\x2f\xee\x45\x38\x10\xb7\x3d\x05\x49\x81\xf8\xae\x84\xd2\xa6\xe4\x90\xdb\x5d\x99\x25\x05\xe1\xbb\x32\x6b\xba\x2b\x81\x78\x97\x12\x52\xa8\xf9\xae\x84\x48\x32\x0b\xe9\x85\x64\xbd\x3d\xe2\x7e\xe2\x10\x4b\xbe\x2b\x7b\x0a\x51\x92\xde\x14\x62\xa9\x77\x65\x46\x29\x7a\x6f\x6e\x33\x16\x0e\x51\x78\xc6\x8a\x6f\x13\xe9\xa7\xf6\x7c\x5c\xea\x4f\xe2\x42\xc7\x80\xaf\xfa\xa0\xee\xca\xc3\xbd\x94\x14\x88\x46\xdf\x53\xe8\x25\x48\xd3\x6f\x49\xd2\x1f\x4e\xf5\xae\x84\x5c\xee\xca\x5e\x6b\x48\x81\x12\x06\x99\xeb\x94\x8e\x9f\x29\x49\xc7\xc4\xfa\x3f\x1d\x46\x98\x11\x37\x14\x1d\x10\x2e\xc6\x8c\x39\xc4\xc2\x5b\x94\x16\x62\x29\xed\x12\xa9\x97\x2d\x72\x0f\xa5\xb4\x3d\x72\x60\xfd\x3c\x94\xa2\x63\x6a\xa1\xe6\x19\xf5\x37\xab\xcc\x88\x01\xf2\x5d\x79\x78\x72\xa2\xff\xf4\x67\xbf\x65\xfe\xd4\x66\x9b\x3a\x87\xde\x78\x2b\x39\x50\xad\x7b\x0f\xac\x6f\x60\x2f\x5a\x42\xa6\xbb\xb2\x45\xca\xfa\x8e\xba\x20\x2d\x90\x4e\x8c\x4e\xf8\xe4\x8e\xd7\x9b\x99\x02\xb7\x99\xc7\x5d\x09\x63\x67\x5d\x8f\x8c\x37\x1c\x33\x73\x88\xdc\xf5\xd6\x81\x77\x1f\x93\x28\xc4\x3a\x7c\x39\x72\x88\xd4\x42\x1c\x98\xd3\x3c\x74\x4e\x44\x7f\xae\x34\xbd\xec\x0f\xf7\x45\x86\x8d\x4d\x1e\x8d\x8d\x6d\x6c\x79\x8d\x8d\x9f\x1e\x9b\x4f\xfe\x39\xba\x73\x6c\x23\xc4\x11\x1e\x0f\xed\x9d\x81\xe9\x9f\xa8\x87\x38\x32\x16\x3f\x52\xa9\x7b\xc4\x92\x05\x5b\xfa\x28\x75\xe2\xbf\xb2\xe8\xbf\x77\xeb\x2a\xeb\x27\x4f\x4f\xf9\xcf\x7c\x6f\x8f\x20\xa5\x6f\x3a\xe8\x9a\x2e\xd4\xc7\x26\x29\x70\x1b\x97\xc8\x89\x37\x4a\x81\x2a\x5d\x98\x68\x93\x16\x84\xf3\xc6\x44\x41\x37\xc0\xd0\x1d\x4a\x17\xa2\x84\x4f\xa8\x9c\x9f\xb4\x10\x85\xe4\x42\x8d\x37\x6c\x26\xaa\xf9\x12\xf1\x5f\x42\x21\x72\x6b\x17\xea\x8c\x69\x8a\x54\x86\x6e\xa1\xbe\xc5\x4c\x3a\xfd\x69\x8b\xfa\x94\x48\xb2\x65\x09\x92\xeb\x25\x12\x15\xff\x54\x74\xa7\xa5\x12\x22\xe3\x17\xa5\xe8\x53\xfb\xc3\x7d\xce\x39\x14\xe6\x0b\x91\x6c\x22\x41\x7f\x40\xbf\xf5\xf4\x5b\xff\xff\x7c\x8f\xa5\x14\x68\x8c\x8d\x74\xfd\x5a\xdd\x75\xd5\x4b\xe0\x6a\xe7\x60\x12\x36\x3e\xd3\xec\x8f\xff\xa5\xb2\xeb\x0e\x91\x16\x1a\xe6\xbc\xca\x1c\x09\x93\xdf\x0e\xa9\x75\x8f\x4d\x7f\x5d\x47\x8f\x55\x4f\x33\x8e\x16\x9a\x9c\x87\x77\xa4\x19\x99\x02\xa5\x8e\x55\x2d\x35\xe0\xbf\xda\xac\x29\x0c\x9e\x43\x7f\xb4\xe1\xa4\xb2\xe8\x66\x91\xbb\x72\x10\x8d\x0b\xa7\xb2\xf7\x10\x25\x50\x0a\x11\x3b\xc4\x64\x02\xb6\x2c\x0e\xab\x89\x05\xdd\xbd\x3a\x95\x21\xd2\x98\xf8\x73\xb9\x2b\x47\x14\x0e\x7b\x2f\xd8\xd9\xa4\x22\x22\xc4\xaa\xdb\x90\xc4\x85\xcb\xb0\x4d\x4b\xd8\xed\xbb\xee\x22\xdd\x71\xfa\x86\xcd\x05\x0b\xb5\xa9\xbf\x1b\x18\x3f\x33\xfc\x6a\xd7\xd5\x65\x95\x5e\x18\xad\x9e\x78\x7d\xa2\xd0\x11\x25\xd1\xde\x75\xb1\x6b\xa0\xac\x77\xf4\x49\x49\xef\x8a\x2d\xcf\x8a\xc9\x1b\x38\x14\xe4\x03\xd0\x57\xa9\xfa\x2e\x3a\x6a\x4e\x98\x32\xdc\x0f\x21\x35\x23\x25\x4c\x74\xa7\x19\x09\x92\x74\x1c\x91\x28\xe9\x26\x2d\x07\xa5\xbc\xc7\xa1\xd2\x42\x27\x80\x20\x6e\xa8\xe8\xc1\xe4\x87\x70\x2f\x85\xc3\x20\xc1\x64\xb1\xce\x78\xac\x75\x36\x1d\x14\x1f\xcc\x63\x8f\x19\x13\x18\x62\xd5\x39\xd6\x89\xab\x21\x36\x7e\xb8\xaf\x42\x81\xa9\xec\x2a\x87\xf4\xd4\xab\x00\xcb\x53\x74\x58\x43\x1f\x97\xbb\x1e\xcc\xbb\x12\x7a\x9e\x71\xe8\xab\x97\x7e\x44\xee\xe3\xe9\x9d\xf7\xff\xb7\x9d\xc7\x2a\x14\x58\x25\x6d\xe9\x81\x21\xd3\xd3\x98\xa5\x84\xae\x2b\xdb\xf5\x0f\x65\xcc\xd1\x6d\xb2\x87\x6d\x40\x9e\x3a\x9b\x65\xa8\x04\xc4\xd6\xec\x63\xe2\x68\xa5\x35\x77\xfa\x0e\xc3\xd6\x53\xa6\xad\x48\xec\x7d\x46\x3c\x30\xea\xb2\x9f\x93\xa8\x3f\xba\xab\x8a\x49\x21\xe2\x77\xfc\xae\xd2\xa1\x5b\x4a\xe8\x3a\x09\xa6\x6d\x54\x60\xdf\xe7\x12\xd2\xd6\x20\xe9\x5a\xbd\x70\x1a\x5b\x6c\x7a\x94\xf1\x9f\x91\x93\x3c\xdc\xd3\xd0\xd7\xa2\x0e\x61\xd5\x42\x0d\xb1\x60\x23\xe3\x40\x65\x0a\x93\xf5\x87\x75\x14\xbe\xeb\xd2\x54\x9d\x9a\x26\xab\xac\xc2\x07\xb8\x37\xd3\xac\xa1\xd8\xfa\x87\xa2\xab\x6d\x7f\xd5\x3f\xd8\xad\x7d\x46\x7c\x13\xea\xcf\x9f\x65\x9f\xaa\xf8\xf4\x2f\x44\xfb\x86\x0e\x83\x1e\xee\xf3\xc8\x81\xeb\x53\x53\x3e\xd6\x84\x63\xaa\xd7\x94\xdb\x84\x63\xae\x6a\x3a\x27\x5c\xb7\xeb\xbb\x53\x7e\x4e\x78\x88\x1d\x93\xbc\x26\x3c\x7c\x87\xf9\xc6\xc5\x9a\xf1\x87\xfb\x5a\x73\xe0\x72\x6b\x2e\x9f\x9a\x4a\xc2\x3b\x3d\x9e\xcc\xf6\xc4\x54\xb6\x77\x26\xd2\xbe\xf7\xed\xa7\xf2\xa6\xee\xae\xae\xbb\x2b\x05\x49\x10\x6e\x23\x60\x3f\x12\xf5\x89\xdd\x48\x90\x51\x78\xf1\xd1\xa6\x4d\x4d\x53\x5b\x24\x36\x0a\xad\xeb\x6f\xab\x7c\x32\x43\x48\xc5\x46\xc5\x34\xd7\xa4\x36\x05\x36\xe2\xac\x25\x0c\x9a\x03\x16\x05\x66\x84\xf4\x4c\x32\xef\xb5\xa9\x39\xc3\x78\x05\x56\x79\x31\xb0\xff\xa1\x77\x21\x79\x71\x3c\x27\xfb\x3b\x16\x5b\x40\x3d\xbf\x26\xe8\x47\x9b\x50\x31\x90\x49\xb1\xe6\x10\x3b\xa4\x76\xb7\xc7\xc8\x46\x2d\x87\xc8\x25\xed\x34\x54\xe3\x0b\x9b\x2c\xc0\x03\x4b\x0d\x3b\xa9\x11\x40\x81\xcb\xd4\xbf\x70\x99\x35\xb0\x4c\xe8\x61\x4e\x1b\x41\xfa\xaa\xa8\x51\xad\x59\x55\xbc\x98\xa2\x61\xd8\x49\xd5\xce\xad\x5a\x67\x3b\x41\xdd\x04\x91\x10\x73\x9e\x52\xd5\x3c\xd3\x95\x36\x8d\x8e\x4b\x36\xe5\xbe\xa9\x4a\xc5\x19\xdc\x22\xb4\x59\xe9\x3b\x14\xac\xb8\x28\x2b\x7d\x46\x9d\x57\xb5\x27\x75\x00\x66\x31\xf6\xee\xba\x43\xff\xa6\xdb\x19\x56\x12\xab\xf5\x90\x7a\x68\x34\xa1\x1c\xa0\x95\x54\x18\x93\xe4\x87\x7b\x56\x3b\x92\xbb\x5b\x48\x10\x95\x18\x89\x8a\xa4\x1e\x66\x6e\xbe\x31\x8b\xbd\x88\x4e\x6f\xc1\x8a\x24\x1d\xab\xe4\xd9\xf4\x8e\x2e\xaa\xbe\x7b\xe0\xa1\x13\x21\x78\x4f\x18\xbe\xba\x12\x58\xf5\xb6\x8c\x4c\xb6\xb3\xe7\xd6\x23\x34\xc1\xc3\xbd\x74\x55\x96\xc9\x86\x31\x20\xc8\x7b\x9f\x15\x27\x90\xd4\x92\x22\x53\x99\x41\xda\x84\x02\x36\x6b\xbb\xc3\xea\xd4\xa3\x20\xba\x8b\xf3\x98\x6a\x49\x65\xdb\xe8\xc3\x4e\x8b\x3e\x8f\xd2\xae\x3b\x22\xa9\xec\x57\x63\x03\x9f\xeb\x4e\xc8\xb7\x6c\xd6\xff\xc8\x0d\xa8\xda\xde\x35\x09\x3f\xd4\x5c\x1d\x6f\x19\xab\xef\x58\x84\xd5\x77\x12\x97\x74\x35\x4f\x9f\x1c\xe6\x7f\xec\x7a\x27\xa7\x50\x38\xef\x29\x50\xee\x41\x27\xb0\xf5\x49\x6a\xb2\x49\x9f\xba\xbf\x69\xf0\x64\xd5\x4e\x39\x6d\x03\xa6\x44\x87\x86\x8f\xaa\x16\x55\x02\xee\x6a\xb2\xc1\x34\x08\xaa\x60\x47\x90\x4b\xac\x53\x3f\xe6\x3d\xf6\x04\x97\x21\x52\x36\xb5\x6d\x16\x09\x25\xac\x29\xe9\x1e\xac\x76\xd9\xd5\x17\x10\x33\xab\xcc\x0e\x52\x63\x4d\x1d\xab\xc8\x6a\x74\xcc\x5e\x4c\x68\x12\x6c\x14\xf3\xa3\xd4\xde\x9a\x04\x29\x21\x55\x27\x74\xc0\x08\xce\x3a\xa4\x1e\xaa\xde\x2f\x38\x02\xf8\x51\x35\xc3\x52\x87\x00\xc6\xe6\xce\xb6\xc6\xb0\x60\x5a\x7b\x7a\x96\xfe\x13\xb7\x0b\x75\x63\xd2\x18\x3b\xa5\xac\x0a\x9e\x30\x1a\x62\x9e\x64\x9e\x14\x4c\x27\xfb\xe3\x68\xcb\x8f\x60\x28\x3e\x16\x18\x12\x29\x64\xfd\x59\x15\xa9\x35\x70\xe7\xbb\x02\x4f\xa6\xf5\x9d\xf4\x3c\x97\x16\x38\xeb\xf4\xe6\x3e\xa9\xab\x58\x49\x79\x92\x89\x5a\xd6\xc9\x9b\xd9\xb4\x46\x5d\xb3\xa3\x42\x03\x5b\xa1\xe9\xb4\x9b\x96\x67\x13\xec\xa4\xc7\x99\xed\xe7\x38\x2f\x2f\xee\xe9\x37\xfc\x4f\xed\x0d\x5b\x0a\x8d\x68\x6b\x14\xa8\xd7\x8d\x87\xbe\xaf\x34\xf8\x70\x42\xe5\xc2\x99\xb6\xa8\x26\x1b\x2c\xfa\xae\xef\x3e\xb6\xa6\x86\x55\xab\x5b\x14\xdd\x0f\x63\x6c\xac\x36\x18\xf7\xb4\xa9\x71\xbf\x84\xd0\x18\x41\x12\xb9\x8d\x2e\x49\x25\x54\x25\x7c\x9f\x6d\xbb\x3d\x3d\xae\xff\xcc\xc6\xd5\x73\x28\x3d\x1d\xd4\xf2\x45\x72\x3a\x84\xc7\x85\xc6\x50\xeb\x75\x5c\x84\xdb\x11\xf5\x93\x88\x2b\x81\xd7\x30\xc6\x81\x0b\xc9\x37\x5e\xf8\x3f\xf7\xf3\x09\x97\x21\xf3\xce\x5d\xad\xf3\x02\xd9\x8d\x63\x77\x5e\xa9\xff\x6a\x1e\x72\x10\x3b\x5f\x7a\xd4\x46\x30\x43\x94\x29\x98\x0a\xe7\x1a\xd8\x3c\x63\x73\xba\x99\x60\x39\x78\x58\x80\x42\xa9\x2a\x13\xed\x48\x77\x58\xc2\xb3\x8a\x3b\xed\xbb\xe8\xd9\x31\xd3\x97\xf2\x2c\x19\xb6\xe6\x12\x79\xfa\xdb\xd9\xd4\x82\x2e\xb9\x1a\x7b\x35\xc1\x98\xb5\x55\xd6\xd5\x57\x65\xf1\xf4\x8b\xc6\xb5\x77\x75\x08\x72\x50\x6f\x97\x56\xfb\x11\xf5\x22\xb6\x7a\x63\xde\xef\x7c\x7a\xb2\xba\xab\xa4\xfb\x77\xa8\x16\x53\x73\x67\x8a\xa8\x3d\x6f\x2f\xa1\x73\xa0\x07\x2b\x10\xed\x92\x02\x8c\x28\xb8\x05\xea\xc2\x46\x11\xb3\x88\x23\x5e\xdb\x7c\x51\x8f\x23\xe0\x36\xf5\x0e\x66\x74\x7d\x06\x97\x5a\xd2\x8c\x05\x52\x7b\x8f\x98\x14\x7d\x55\xa2\x09\x2d\x10\xd8\x8e\x0e\x43\x94\x4f\xa8\xaa\x50\xf2\xd3\x6f\xf0\xc9\xf2\xe5\x74\x7b\xa6\xad\x8a\x0a\xde\x56\x37\x6a\x2a\x3e\x79\x8b\x55\x6c\x77\xdf\xd8\x20\xe9\x3c\x11\x95\x07\x04\xe3\x08\x52\x83\x9e\x33\x18\x19\x4c\x32\x09\xa7\x91\x54\x78\x4c\xaa\x23\xa8\x94\xde\x0b\x85\x14\x20\x23\x4f\x9b\x26\xaa\xa4\x9a\x2d\x79\x2c\xc7\xe2\x3f\x4d\x8f\xb0\xba\x35\x5d\x7d\x37\x9d\x13\x92\xa9\xfe\x31\x0f\xc2\xd1\xae\x0d\xee\x64\xe4\x81\x9d\xe6\xd6\x7e\xd2\x17\xcf\xb6\x55\xcc\xe5\x22\x55\xe8\x39\xed\x71\x10\x94\x36\x1c\x2d\xd3\x9a\x6b\x80\xd8\x91\x43\x07\x4d\x53\xe5\x35\xab\x0b\xc3\x7d\x84\x5a\x4c\x8c\xf4\x40\xfa\x8c\x69\xf6\x83\x8e\x6f\xea\xaa\xe8\x34\x63\x01\xa5\x6c\xd2\x24\xe4\xae\x3b\x5d\x6d\x62\x28\x98\x21\x33\x0e\x0e\x92\xf7\x98\x61\x30\x98\x78\x46\xc4\xcb\xfc\x3d\xb3\xad\x62\x36\xe5\x9f\x7d\xc7\xba\xac\xb7\x80\x54\x0d\x3c\x44\x35\x9b\x2e\xbc\x6a\xad\x21\x73\xa8\x96\xcd\x3b\x1e\x8a\x67\xe2\x91\x78\xe2\x20\x53\x86\x94\x69\xe2\x49\x78\x90\x2e\x90\x6e\xa9\xa5\xbb\xdd\xe7\x34\x4f\x79\x46\x09\x72\xf3\x80\x90\x6f\x14\x95\xc3\x69\xa4\x4d\x72\x55\xe9\x77\xa1\x22\xc7\xf2\x62\x58\xfd\x48\xaa\x5b\x64\xc2\x9b\x3f\xfd\x24\xf6\x27\x91\xda\x22\xb9\xed\xa5\x07\x52\x27\x57\x05\x9d\xea\x4f\xa9\x41\x6d\x00\x58\x3f\x15\x01\xbe\xa9\x9f\x47\x1c\xe4\x2e\xee\xed\x4e\xc4\xfd\xb2\x2a\x63\x98\x68\x6c\xd3\x05\x17\x1a\xe2\xd4\x62\x7a\xc9\xb6\x00\x99\x07\x4c\xf9\x91\x5a\xb5\x2f\x10\xec\xc7\xee\xc6\x64\xbb\xe4\x4c\xbb\x8e\x4c\xfd\xd5\x8a\x0d\x6b\x01\x43\x32\xab\x63\xb2\x84\x7c\x57\x8e\xc8\x2c\x97\xd8\x06\x1f\xc4\x4d\xc5\x62\x1d\xa1\x5a\x9c\x90\x27\x6c\x5e\xe2\x34\x87\x1a\x70\xaa\xe2\x7a\x0f\x43\x17\x48\x45\x98\xe4\x80\x25\x6a\x3c\x5b\x0e\x9d\x26\x02\x0a\x83\xf4\xd1\x94\xd8\x2c\x1c\x0b\x1a\x34\xf3\x2b\xd4\xcf\x99\x08\x78\x06\x75\xae\x9b\x1e\x33\x15\xa6\x6e\x6b\xd9\xae\xc1\x6e\xf2\x50\x29\x5d\xdd\x91\x8c\xbf\x9b\xc6\xcb\x6a\xa2\x66\xb7\x34\xdd\x35\x51\xe3\xed\xe9\x75\x12\x5b\xa7\x51\x03\x89\x6c\x54\x59\xd5\xf5\xae\x0b\xab\xb6\x59\x24\x9e\xcd\x8c\xff\x69\x0f\x4a\x93\xd2\x7a\xe2\xae\x52\x4b\x8d\x70\x35\xa6\xf5\x8c\x41\x1d\xa6\x59\x08\x37\xaa\xab\xa7\x77\x65\x95\x5d\x0d\xdb\x33\xdb\x79\xc7\xde\xcf\x19\x73\xa9\x73\x3f\x74\x3e\x32\x82\x12\x6a\xff\xb2\xbf\x62\x25\x18\xe6\xd2\xf5\xc0\x07\x92\x3d\x9a\x25\x8e\x57\x4e\x8f\x8e\x0f\xe4\xa0\xfe\xa3\xbf\x4c\x77\xe5\xa0\x5e\xf6\xa1\x3f\x8b\xe8\x46\x9e\x94\x20\x07\x92\xfa\xb2\xaa\x69\xcc\x47\x54\x8b\x35\xe8\x4a\x58\x5c\xa3\xa6\x25\x51\xc7\x39\xcb\x66\xde\xc2\xf1\xd0\xb9\xdf\x55\x30\xc3\xb7\x65\x9b\x04\xdd\x6e\xe6\x37\xd5\x2d\xaa\x5e\xa1\xdc\xf7\xda\xc3\x20\x73\xd1\x02\x82\x47\x93\xe0\x67\xe9\x79\xdc\xe1\x4d\xd8\x67\x11\xdb\xd7\x62\x58\x11\xe1\xaf\x8e\x30\x0f\xc3\x8e\xa5\x8c\x50\x0c\xa2\x98\x26\x09\xa2\x89\xba\x06\x2b\x4d\xc5\x0e\xf4\xa1\xf9\x21\x2a\xf4\x04\xdf\x0a\xad\x21\xa6\xa9\x92\xb0\xd1\x54\xe7\x6d\x14\x33\xf0\xa3\x99\x4f\xd0\x9c\xdd\x83\xa5\xf6\xd6\xe6\x78\xe5\x19\xc9\x42\xdc\x3d\xe9\xe4\x9a\x05\xa5\xb2\x59\xbd\x2e\xbc\xb8\xda\x2e\x63\x49\x5a\x92\x9b\x71\xea\xec\xc6\x0a\x8c\xa5\x83\x72\xde\x4a\x91\xd0\xa9\x5d\xa8\x96\x23\xb6\x96\x2e\xd4\xd2\x11\x69\xc8\x25\xe2\x4a\x48\x2e\x91\x85\x0e\xb5\xae\x62\xee\xed\xe1\x5e\x54\xbc\xa6\x74\xe1\xd2\x0f\xe9\x37\xbc\xea\xb2\x94\x9b\x9a\x21\xb2\xa9\x0d\x40\x82\x2d\xac\xb3\x6f\xa7\x66\x9a\x49\x5d\x27\x84\xad\xfd\xff\xae\x8e\x51\xae\xa1\xe2\x85\xdb\x98\xee\x17\x8b\xec\x59\x54\xd6\x42\x5d\x14\x73\xa7\x73\x9b\xb0\xd7\x5b\x77\x69\x91\x86\xf9\xdc\x76\xd4\xe0\x05\x42\xbf\x34\x5b\x12\x86\xff\xd4\x55\xb8\xe9\xec\x55\xb6\x5d\xe3\x5a\x5d\x45\xfa\x50\xb3\x2f\xb7\x50\x65\xd3\xff\x6f\xe9\x52\x7b\xd5\xf9\xc0\xcb\xab\x2b\xa4\xea\x2e\xb7\x5d\x7d\x7c\x82\x90\xc0\xc3\x4c\xf2\x43\xcc\x40\xc7\x51\x2d\x8f\xa4\x67\x9b\xdd\x2c\x61\x33\xd6\xd4\xb2\x71\xe3\x18\x5a\x75\x9c\x9e\x05\x16\xdc\xc5\x86\xda\xa8\xc3\x2e\x5b\xf1\x29\x50\xe7\x5e\xbf\xa6\xe2\x0a\xd6\x34\x85\xcc\x16\xa7\x2d\xf6\x62\xc4\x4f\xaf\x47\x5d\xeb\xa1\x76\xaa\x9a\xfb\x54\x6b\x80\x7b\xc2\x63\xcc\x61\x91\x88\x32\xa9\x24\xd3\x5c\xd7\xe3\xa1\x16\x43\xef\x78\xa7\x01\xab\x8f\x0a\x4e\x26\x6d\x91\x54\x98\xa8\xd7\xa8\x07\x15\x97\x2a\x4d\xa1\xc9\x03\x21\x85\x42\xea\xaf\x26\x3c\xfc\x71\xc4\x35\x43\x7c\xa8\x11\xaf\x77\x41\xc4\x4c\x9c\x35\x73\xa0\x2d\xe8\x01\x35\x81\x68\x8a\xfe\xc6\x5d\xd9\xf5\xdb\x29\x64\xcb\x0a\x4d\x58\xc2\x66\xde\xc1\xda\xc1\x55\x0b\x3a\xb3\x3d\xe1\x34\x5b\xc8\x74\x12\x5b\xc4\x36\xcd\x6e\x1a\x49\xba\x69\xb0\x56\xcf\xc0\x51\xd3\x7d\x51\x4c\x8d\x99\xe5\xc6\xcd\x4f\x68\xa4\x52\xd5\xbc\xd0\xd3\x66\xe6\x4b\x4f\x2b\x6d\x05\xdb\x91\x74\xf3\x98\xde\x19\x7d\xf9\xe5\x85\x1f\xee\x45\x7a\xc8\xbd\xc1\xdf\xa5\x60\xd2\x9f\xa8\xbb\x87\x84\x18\xd2\xac\x1c\x62\x4b\xd8\x1f\x2a\x77\x76\xc9\x2b\xfd\xa6\xe7\x02\x0b\x80\x60\x45\x45\xb4\x69\x92\xea\xa9\xbc\x36\xb9\x85\x3a\xf2\x8c\xba\xb3\x10\xd5\x77\x55\x05\x91\xb4\x72\x6e\x79\x8f\xc5\x44\xb4\xb9\xb3\x26\x3d\x4d\xed\xaa\x30\x39\xa2\xdc\xf0\x2a\xdb\xb2\xcc\x71\x96\xca\xc1\x89\xdc\x34\xa7\xa6\x6b\x3e\x54\xd8\xc2\xb8\xcf\x6a\x38\xaa\xa0\x1a\x5d\x97\xb0\x5c\xd4\x9f\xd3\xa3\xa0\x9f\xab\x9b\x57\xb2\x4c\x4e\x35\x14\xe1\x4b\xcc\xe3\xc6\x2e\xed\x2e\x9f\x6a\x10\x51\xed\x53\x28\x40\xf9\x27\x33\xe6\x47\x9e\x2d\x5b\xc4\x7a\xa8\x88\xd8\xa3\x20\x5e\x11\x71\x0e\x2d\x4a\x5c\x6a\xa8\x66\x84\xb7\x60\x32\x19\xe2\x46\x97\x7e\x4f\xa1\x99\xb3\x23\x32\xbb\x05\x0f\xe1\xbb\x20\x60\xd3\xf2\xd4\x93\xcf\xd7\x0d\x84\x08\x39\x94\x81\x4a\x69\xb5\x19\xba\x87\xba\xa6\x9b\x3c\xec\xe7\x18\x31\x78\x0b\xb4\x62\x72\xb3\xdb\x06\x33\x5a\x50\xa9\xc1\x2a\xd0\xa9\x52\x57\x64\x2f\xe6\x5f\xa8\xc0\x81\x43\x6e\xf9\x18\xec\x4e\x0f\x47\x0d\x58\x3d\x91\x12\xb4\x8d\xee\x0e\xf8\x02\x2a\xbe\xc6\x4a\x3a\xe8\x9b\xd5\xf5\x3b\x30\xb1\x79\x9c\x26\x76\x1d\x81\xf5\xec\x89\x0a\xbf\x89\x75\x0e\x08\x38\x4e\x18\xbf\x81\xd4\xe1\x51\x59\xde\x83\xe4\x8a\xa0\x54\x0d\x54\x42\xac\xfd\xf4\xe1\xcd\x15\x48\x6e\x46\x34\x77\xfe\xd4\x76\xd0\xe9\x69\xb6\xf7\x71\xea\xf4\x24\x62\x9b\x5a\x96\x01\x1b\x55\x4d\x05\x9b\x1e\xd8\x54\x30\xba\x74\xa2\x6a\x39\xd5\x63\xb9\x1a\x80\x99\xc3\x8e\x38\x8d\x4e\xb5\x3a\xe5\xd9\x8d\x2a\x95\x16\xc8\x14\x47\xe4\x45\xd8\x62\x48\x0f\xf7\xd2\x5a\x18\xad\x78\x5e\xc4\x54\x0a\xb4\xa6\x60\x63\x17\xb1\xd3\x13\xf3\xf2\x66\x04\x33\xcf\x41\x4a\xc0\x2f\xf6\x3a\xc5\xb5\x84\x7a\x8f\xcd\x4d\x98\xc2\x2e\x14\xe0\xf0\xb5\x00\x7f\xaf\xc3\xc3\x43\x9c\x0a\x8a\x39\x5b\x82\x6d\xe0\xac\x2f\x3b\xcf\xe6\xec\x86\x3e\x1c\xe7\xce\xee\xf0\x2f\x47\x0d\x16\xbe\x6e\xc3\xe3\x31\x90\x3b\xb0\x9d\x83\x59\x06\x05\x6e\x45\xd9\x4d\xec\x90\x85\xa8\x26\xf4\x82\x8a\x1c\x8b\xee\x9a\xc8\xb1\xed\xc8\xc5\xb3\x6a\xe6\x98\xf9\x18\x4d\x1e\x37\xb8\xe0\x2a\xcc\xd2\xd5\xcd\xb1\x38\x73\x1e\x7b\x84\x80\xc7\xae\x71\x3b\xa2\xb0\x45\xad\x37\xf2\xc0\x20\x11\x52\x78\x98\x5c\xe4\x1b\x90\x69\x6c\x48\xd6\xb9\xf1\xc9\x26\xa3\x23\x4b\x40\x80\xa0\xcf\x86\xac\x5c\x98\xad\x06\xec\xbd\x26\x96\x36\x50\x97\x39\x75\xf5\x25\xa1\x3d\xd8\xf3\xf6\x19\xc9\x48\xac\xbb\x65\x85\x93\x9d\xe8\x95\x86\xb0\x25\x68\x08\xff\x26\x0c\x18\xe8\x05\xdd\x16\xec\x09\x4a\x1c\x22\x95\xf0\x51\xcf\x79\xab\x0f\xf7\x42\xe2\x73\x0e\x29\x5c\x3c\x88\x3e\xc5\x4e\x26\x9f\x49\xa9\x7c\xc2\x20\x22\xe5\xbd\x18\xc6\xa0\x5b\x08\xd8\x76\xcc\x38\x44\xf7\x4a\xa5\x65\x60\x50\xb7\xd3\x8e\x6d\x44\xb0\x30\x5a\x82\x22\xc6\x3a\x62\x47\xa7\xe0\xb6\x20\x55\x4b\xb4\xe4\x95\x24\x88\xaa\x80\xdc\x18\x4a\x72\xcb\x66\xfb\xe7\x1e\xe8\x50\x3f\xed\x1a\xe8\x58\xe7\x6c\x85\x3a\x5c\x13\x36\x0b\x74\xb0\x2e\x67\x29\x67\x4e\xc4\xbc\x5b\x04\x27\x3c\x16\x7f\x9e\x51\x4c\xef\xef\x0a\x78\x40\xdb\x90\x4b\x33\x04\x3b\xda\x13\xc1\x0e\x0e\x25\x3f\x60\xa0\xad\xa8\xf4\xe6\xee\x03\x15\x1f\x68\xbe\xf3\xa1\x3e\x3d\xd0\x35\xcc\xfe\x68\x98\xe1\xed\x51\x8e\x05\x19\x80\x58\x90\xf3\x65\x7c\xac\xcb\x08\x47\x78\x06\x7b\xc4\x7f\x6a\xc6\x35\x49\x71\x0d\xc5\x61\x27\x37\xc2\x33\x9e\x12\xe2\x3e\x3c\xfe\x36\x10\x7f\xcb\x1e\x7d\x93\x6f\x15\x7b\xe3\xb7\x62\x6f\x75\x29\x74\x4b\x12\xdc\x8c\xbf\x35\x8f\xbf\xd1\x19\x7f\x53\xe3\xd7\x73\xca\xd9\x37\xac\x8c\x29\xfd\xdb\xc4\xdf\x68\xc5\xdf\xbe\xd3\xe2\x84\xdf\xbd\x3a\xdf\xdb\xe2\xfc\xe9\xcf\x7e\x2b\x9f\xaf\xa4\x5d\x0d\x35\xe5\x83\x68\x6c\xbd\xf7\x90\xeb\x38\xa2\xfa\x1c\xb1\x1a\xca\xa3\x6d\x55\xbd\x58\xa9\x72\x44\xa6\x1b\xe9\xed\xcf\xce\x30\xae\xe4\x8e\x30\x6e\xaf\xd5\xa3\xb6\xbd\xd6\x07\xfd\xa4\xd5\xfa\xc4\x27\x37\xc7\xf7\xda\xc7\xd7\x6a\xe8\xe9\x60\x1a\x5b\xcd\x12\xa4\xea\xc8\x32\x05\xe1\x76\xe8\x30\xfb\x80\x4c\x00\x22\xe0\xc6\xe0\xfe\x6c\x85\x6d\x24\x10\x65\x52\xe7\xa3\xe4\x00\x0b\x06\x51\xfc\x31\x60\xbd\x90\xa8\x47\x64\x9e\x2b\x3c\x1c\x33\xdb\x75\xc6\xd9\xed\x9c\x80\xdc\xed\x34\x87\x42\x6d\x51\xc7\x8c\x64\x86\x57\xdb\xdd\xa8\x34\x79\x34\x11\x49\xef\x96\x55\x54\x71\xa5\xca\xda\x22\x83\xb2\xab\x94\x87\xb2\x36\x7d\xab\x12\x17\x22\xdc\xd2\x74\x2b\xe4\xa1\xf2\x84\xd5\xc4\x24\xf8\x91\x49\x0e\x02\x96\x41\x27\x22\xb4\x6e\x1e\x3f\x42\x2d\x99\xcc\x06\x6b\x1d\x09\xe5\xb0\x57\x0e\x95\x4d\x55\x5b\xfe\x94\x4d\x5b\xa7\xab\x4d\xc1\xcb\xd4\x13\x24\x32\xdd\x60\xd0\xa1\x58\xe0\x3a\xc3\x40\x4c\x26\xe5\x3d\x60\x82\xe4\x5f\x88\x16\x85\x33\x80\x5a\x35\x53\x03\x2f\xae\x93\xfa\x70\x2f\x5d\x7f\xa9\xae\x63\x62\xc0\x09\x3f\x9a\x03\x07\x33\xd9\xb1\xe4\xa6\x27\xc4\x73\x46\x66\xa4\xaa\xc0\xf4\xf3\x71\x15\xb1\x9e\x0c\x37\x01\xcb\x6e\x83\x99\x88\xed\x1e\x53\xf6\x98\x58\x78\x3b\xac\x3c\x60\x82\xe0\x58\x98\x8c\xbd\x61\x3b\xff\x17\xb6\x49\x0a\x85\x9a\x11\x0e\xae\x2d\xe4\x1c\x78\xd0\x24\x4f\xe5\xd6\x89\x50\x12\xf2\x54\x84\x95\xc4\x34\x50\x4b\x1e\xb8\x22\xf5\x8b\x46\xb3\x50\x5f\xad\x88\x78\xb0\x1a\x4e\x47\xcc\x99\x2f\xea\xb8\x1e\x55\x20\xce\x10\xdc\xb1\x08\x6a\xb9\xc6\x7e\x65\xd7\x03\xbe\x70\x06\x8e\xb8\x51\xf3\xdf\x8d\xe1\xd0\x2d\xd9\x43\x6b\x55\xd5\x26\xaf\x96\x73\x84\x1b\xdd\x2d\xed\x3a\xd5\x70\x45\x96\x91\x46\x0d\x8c\x90\x5b\x31\xc8\x0a\x87\xde\x27\xe2\xf5\x16\x24\xf0\x15\x35\xa1\xd1\xd5\x44\xd9\x75\x23\x43\x63\xc9\xd5\x8a\x18\x90\x5e\x83\xe1\x76\x46\x82\xf2\xc4\x92\x30\x32\x9b\xf0\xa9\xc5\xec\x18\x1a\xb3\xab\x41\x5f\x31\x25\x16\xbf\x1b\x26\x64\x2d\xea\x5b\xe0\x1e\xc0\x9b\x82\x59\x83\x18\x67\xd0\x61\x6c\xf8\x62\x21\x80\xa9\xd4\x17\xf1\x0c\xb5\x87\x87\xc8\x36\x9f\xc1\x8f\xc8\xf3\x91\xc4\x88\x00\x9b\x97\x4f\x40\x2e\x90\x4d\x9e\x1a\xcc\xba\x82\xe5\xe1\xbe\x88\xda\x1d\xd5\xad\x18\x0b\x19\x8c\x1e\x2c\x37\x1d\xa5\x59\x3c\x0f\x13\x82\x21\xe5\x95\xe3\xe7\x30\x78\x56\x8b\x78\x21\x7e\x10\xe1\x3f\xa4\xeb\x81\xb0\x6c\xbe\x94\xab\x61\xeb\xd9\xb9\xbc\xb2\x3b\x4f\x6f\xb8\xff\xd2\x36\x5c\x0a\x69\xcb\x6a\x9c\xf0\xe8\x17\x12\xd9\x72\xc5\x46\x1f\x5d\x9d\xc0\xb4\x45\x22\x75\xe7\xd2\x25\x8a\x64\x4b\xf6\x47\xfc\x27\x8b\x5a\x67\x8d\x42\xee\xe3\xc2\xa5\x6f\xea\x4f\x87\xcc\x37\x44\xfe\xbf\x70\x09\xcd\x21\x1d\x08\x7a\x4b\x6f\xbb\x3e\x3b\x05\x46\x18\x45\xb5\xd1\x08\x48\xd4\x5a\xc8\x0e\xd8\x2b\xdd\xaa\x24\x88\x55\x4b\x0f\x6e\xa5\x9b\xe7\xef\xd6\x1f\x94\x13\xb2\xf5\x66\x06\xaa\x4e\xce\x06\x64\xb0\x80\x41\x39\x13\x22\x3e\xaf\xb1\x37\x43\x47\x44\xc4\x48\x23\xf2\xa0\x8e\x1e\x80\xdc\x34\x1f\xcd\x12\x1c\x26\x57\xf4\x17\x99\x91\x06\xbd\x44\xe9\x2a\x63\x88\x02\x8d\x72\xa1\xd6\xf7\xa2\x5e\x3f\x82\x30\xc3\x3c\x5c\x21\xb3\x01\xa0\x1f\x3d\x2e\x6a\x09\xd5\xec\xeb\x16\xdc\xd3\xac\xa1\x36\xec\xfb\xa5\x35\x2d\x76\x70\x89\x94\xeb\x11\x65\x34\xfb\xa5\xd6\xfa\x85\x72\xda\x2b\x02\x9d\xc9\x42\xa7\xb3\x71\x10\x31\x4b\x38\x9b\x86\x08\x95\x96\x49\x12\x49\xdc\xa7\x96\x11\x72\xf7\x73\x26\x32\x01\x34\x81\xf5\x70\x89\x54\xd3\x11\x25\xdd\x08\x20\xfc\xb9\xcb\xa4\x11\xaa\xa8\xe9\x4a\x6c\x32\x21\x30\x70\x2e\x65\x04\xd2\xd7\x9d\x40\xa7\xe9\xd6\x37\x90\x6f\x37\xa7\x1b\xc7\x7a\x4c\x02\xf2\xef\xae\xec\x0d\xb1\x63\x5d\x45\xa6\x15\x17\x34\xec\x13\x12\x66\x16\x83\xb3\x79\xdf\x22\x5b\x5a\x4d\xf6\x38\x10\x9a\xe2\x30\x2c\xdb\xe2\xf9\x08\x84\x6b\x0c\x1a\xa4\x52\x8b\x2d\xb3\x03\xf9\xe3\xd6\xac\xc5\x99\x76\x3d\x6f\xe9\x3c\x32\x62\x62\xc6\x71\x37\x16\x70\xd1\x65\xe7\x69\x68\xaa\xd1\x82\x05\xf6\x2c\x22\x15\xcc\xc9\x32\x93\xca\x77\x87\x1a\x94\x64\xf8\x00\x03\xb8\xea\xab\x65\xbc\x5a\x32\x1d\xa3\x1e\x1f\x16\xd2\x90\x3b\xaa\x32\xa3\xa1\x65\x80\xf0\x85\x97\x0c\x80\x0b\xbc\x62\x95\x24\x02\x49\x92\x86\x67\x97\x4c\xce\xc0\x12\x40\x2c\x3c\xb0\xc7\xd2\x20\x57\xc6\xcd\x4c\xd3\x2f\x3d\xef\x90\xce\x33\x26\x69\xc5\xc6\x21\x23\x55\x95\xf8\x24\x40\x4b\x43\x6b\xce\xe6\x87\x4a\x77\x97\x4a\x7b\x60\xd0\x52\x31\xc3\x32\x72\x15\x77\x4b\xb3\xa7\xde\xf4\x6f\x9e\x09\x02\x5e\x41\x45\x9e\xa5\x21\x1d\x53\xc4\x88\x00\xe4\x4b\x94\x54\xcc\x83\xa3\x9e\x2e\xad\xef\x6a\xcb\xaa\x73\x65\x66\x23\x86\x81\x4d\xc9\x76\x38\x28\x75\x4f\x57\xd8\xb4\xab\xc6\x41\xa4\x63\x9a\x45\x13\x2c\xd9\xa7\xde\xad\xca\xc3\x4b\x1c\xe3\x88\x23\xdd\x98\x8d\xbf\x58\x66\x57\x59\xd3\xd1\x85\x0e\x5d\xe3\x4b\xac\xa9\x1f\x51\xa8\x5c\x4a\xca\x6a\x6e\xd2\x25\xe2\x4a\x6a\xbd\xa8\x35\x6a\x77\x75\xbe\x71\x30\xfe\xab\x15\x59\x1b\xeb\xd1\x6d\x88\xc7\x99\x0b\x0c\xd5\x31\x2e\xb9\xe0\x39\x7c\x89\xb8\x2a\x03\x42\xf3\x46\x36\xf8\x2f\x17\xd6\x3f\x54\x81\xfa\x97\x1c\x0c\x29\x27\x75\xda\x7c\xa9\xa0\xb7\xd4\x30\xa9\xb0\x24\x0e\x6d\xb8\xee\xca\x3c\x29\x65\xcb\xa6\x98\x88\x60\x0b\x57\x02\x64\x63\x81\x8d\x39\x32\x22\xf2\xaa\xd9\x28\xf1\x16\x81\x8d\xa5\x5c\x77\xb5\x03\x2d\x73\x61\x29\x3d\x3f\xb0\x86\xb5\x55\xb7\xd7\x7e\x1e\x08\x1c\x75\x33\x65\xa1\xe9\xa7\x7b\x44\xe2\xbe\x3d\x7c\x4d\x38\x86\xb1\xd8\xa9\x4b\xe4\x98\x38\x0b\x61\x79\xb4\x0b\x6a\xcc\x83\x9c\xec\x60\xe7\xbc\xd0\x38\xc0\x25\x47\x4e\x7d\xc2\xd7\xc0\x0e\xb5\x2f\x0f\x53\xd6\x66\x15\xe4\x3d\x57\xcb\x83\x13\x4d\xf5\x1b\xf8\xe0\xac\x33\x4c\xed\xa0\x91\x2f\x59\x74\xce\xa5\xee\x48\x0c\x34\xd5\x69\xdd\x21\xaa\x06\x43\x84\x10\xc5\x59\xd8\x21\x2d\x0c\x02\xe4\x79\x2a\xaa\x12\x48\xc6\x42\x51\x32\x02\x65\x16\x93\xe1\x76\x43\xc3\xfd\xd7\x67\x76\xc6\xf7\x04\x97\xb4\xeb\x41\x08\xfa\xba\x88\x60\xa8\xa2\x81\x02\xc2\x84\xdd\x5d\xab\x2b\x54\x2e\x00\x42\xcd\x6e\xab\x49\xab\x47\xa1\xfc\xde\xcf\x20\x4e\x19\x3a\xfa\x28\x8d\x2e\x51\x1f\x17\x71\xc5\xb7\x10\xf9\xff\x72\xa5\xa9\x21\x3d\x46\xba\x70\x6e\x47\x47\x2c\x58\xca\x41\x83\x2e\x8d\x58\x37\xb4\x3e\x24\xb7\x23\xf6\xd1\x90\x44\x8a\xd4\xfb\x25\x36\xb9\x71\x0c\xff\x9b\xd3\xb0\xa5\x2c\x1b\xe5\x6a\x90\x77\xa0\xc7\xe9\x1a\xe3\xf0\x2c\x8a\x63\xde\x65\xda\xb6\xd5\x23\x80\x8c\x28\x99\x19\xe9\xe6\xe0\x0a\x98\xad\x98\x65\x24\xab\x85\x81\x3b\xa0\xf2\x18\x67\x80\x2c\x14\x3f\x05\xb8\x84\xbb\x72\xd4\xdc\xf4\x6d\x1a\xde\xa6\x96\xe1\x6f\x43\x83\x8f\x58\x9b\xd8\xfe\x6b\xe6\x08\x1b\x04\x2c\xb6\x81\xcc\xcf\xc4\xc6\x34\xef\x2b\x52\x06\xb8\x7c\x87\xfc\x4b\x6b\x63\x65\x93\x4c\x88\x5f\xc9\xd3\x53\xf1\xdf\x7e\xb4\x1d\x42\x75\xcb\x92\x43\x49\x19\x45\x01\x86\x42\x23\x06\xb2\x27\x5f\x08\x30\xaa\x06\x47\x5e\xb6\xac\x1e\x6a\x13\xda\x22\x03\xc3\x86\x2a\x89\x11\xca\xe0\x2d\x16\x84\x5d\x8f\x58\x98\x9f\xd9\x1a\xff\xca\xb7\x06\x97\xdb\x03\xef\x88\xec\x19\x0e\xdc\x91\x33\x08\xc9\x1d\x2a\x04\xe8\x52\xfa\xca\x4b\xf6\x5b\xc5\x11\xf7\x27\x88\x77\xfd\x48\xe6\x8d\x11\xd4\x4e\x69\x63\x92\x50\x13\x5f\x38\x67\xa0\x26\xd4\x3c\x4d\xed\x18\x5c\xb7\x08\x6c\x5e\xee\xea\xe1\x14\x36\x68\x6a\xee\x7c\xc4\xc1\x40\x88\xdf\xf8\xbd\x7f\x7d\xc6\x1f\xd6\xef\xf5\xb4\x65\xb5\x3b\x06\xe5\x63\xe8\xe1\x63\xfa\xf6\x6f\x69\x07\xae\xc8\x16\xb3\x48\x18\xb5\x1c\x71\x54\x3d\x3d\xe9\xc6\xac\xfe\x1b\x17\xf9\xea\x29\xd1\x42\x46\x0a\x24\x0c\x4d\x75\x9b\x88\x26\x21\x61\x4e\xd2\xa6\x1a\xc9\x79\xec\x03\x71\x4d\x75\x53\x32\x79\xba\x0f\x39\xe6\x95\x3c\x4f\x16\x54\xe2\x51\x97\x57\x04\xc3\x86\x99\xac\xae\x8b\x9a\x18\x30\x97\x10\x09\x52\x27\xc4\xa1\xe3\x44\xa4\xae\xc3\xb4\x23\x40\xf5\x91\x5d\xc2\x8e\xe4\x3e\xd3\x8b\x6a\x43\x06\xa6\x95\x8d\xe0\x06\xb7\x9b\x1b\x87\x5a\xce\x63\x44\x30\x23\x9a\x1f\x4b\x2a\x34\x55\x0a\x0f\xf6\xb2\x02\xa1\x60\x22\x1c\x96\x08\x8b\x59\xce\xad\x5b\xd1\x9a\xa9\x7d\x73\xa4\xd8\x74\x03\x31\x4c\xc7\xc0\x88\xc4\xe6\xe0\x99\x56\xff\x1a\x74\x0c\x06\x93\x17\xa0\xc0\xe2\xe3\xac\x3e\xa3\xa5\xa3\xb3\x9b\x7b\xe2\x90\x77\x7d\x5c\xbd\x65\x4c\xfd\xd5\x4a\xb9\x9e\x1e\x4b\x16\xd9\xd5\xe6\x4b\x6a\xf8\xbb\x24\xb2\x1c\x62\xec\x82\x97\x23\xe6\xe9\x9a\xd7\x60\x9f\xb0\xf8\x2c\x62\xd8\xca\xa3\xc4\xcf\xb5\x9e\xc4\x6b\x78\x50\x4c\x32\x8e\x58\xd4\xf6\x67\xc9\x0f\xf7\x22\x35\x34\xa2\x0b\x0d\xde\x8b\x2e\xc4\x20\xcb\xd7\x00\xc6\x27\x6d\x4a\xb5\x18\x26\x76\x61\xd3\xed\x99\xb1\xe4\x41\xdf\x13\x61\x1d\x24\x63\x19\xc8\x97\x6e\x50\x11\x15\x76\x30\x73\x6e\x44\x21\xfe\xbb\x3f\xc0\x9e\x2c\xcd\x4a\x0f\x81\x28\x75\xbb\x71\x54\xec\x3b\xfb\x66\x03\xae\x2c\xc4\x5a\x77\x01\xfa\x17\xd8\xad\xb6\x63\x23\x1b\x02\x90\xd3\xa5\x6d\xba\x31\xfb\xa6\xa2\x91\x53\x53\x5f\x26\xef\x80\xdf\xea\xb3\x8b\xc7\x1f\x62\x6f\x26\xfc\x77\x5c\x89\x5b\x14\xc1\x63\xab\xb4\x76\x1a\xb2\xd9\xea\x91\x9b\x41\xc2\x32\xbe\xfb\x7e\xfe\x41\x6f\xe7\xff\xfe\xc4\x24\xad\xdd\x9c\xf2\x4e\x34\xe0\x7f\xdb\x93\x61\x5e\x19\x54\x05\xf1\x0e\xe8\x3e\x4e\x28\xf9\x20\x0b\x82\x99\x08\x59\x39\x18\xb8\xde\x96\xa1\xd2\xa9\xe8\x7c\x56\x9d\xa0\x70\x91\xd5\xb1\x2b\x45\x65\x60\xe9\x1b\xbc\x82\xc2\x5d\x5d\x5b\xdd\xe8\x7a\xe5\x1b\x3d\x85\xc6\x72\xa1\x9e\x0d\xdb\x68\x7b\x15\xe9\x1c\xc0\x85\x3c\x60\x6d\x89\xc9\x73\xb3\x0f\xc3\x7c\x93\x64\x4b\x8b\xa9\xbf\x41\x5d\x37\xf7\x2d\x0c\xf2\x5f\xbb\x25\x82\x4a\x8f\x4d\x97\x94\x75\x0e\x18\x96\x88\x97\x68\x9a\x48\x07\xba\xc9\xcc\x67\x94\x85\x01\xd6\xc2\xd5\x0b\x39\x0b\x79\x15\x59\xce\xd8\x02\x10\x04\x80\x32\xeb\x3e\x1b\x10\x10\x70\xff\x61\x18\x5b\xfd\x89\x58\x8c\xdd\x42\xec\x9e\x39\x45\xe2\x49\x5d\x4f\x84\x70\xe0\x83\x32\xe1\xb3\x3d\x8e\x1a\x80\x3c\xaa\x19\xd0\x2d\xb3\xe2\x07\xaf\xd0\x68\xca\x58\x70\xa2\xb6\xa7\xd0\x4a\x00\x48\x2a\x4d\x0f\xb7\xe6\x49\xc2\xa1\xb5\x49\x88\x28\x71\x0f\x2b\xd2\xa2\x7b\x58\x7d\x72\x38\x01\x19\x75\x90\x03\x08\x77\x54\xde\x91\xc5\xb6\x02\xea\x31\x00\x51\x29\x2b\x20\x15\x3b\xa6\x68\x8f\x6a\x75\x50\x88\xa3\x84\x0e\x53\x28\x03\x9d\x29\xf5\x51\xa2\x6c\x55\x09\x47\xa1\x13\x4b\x87\xc3\x66\xfb\x62\xb7\x74\x38\x5d\x83\xb7\x19\x99\x75\x84\x2d\x4b\xbb\x0a\xd5\xca\xfb\x68\x28\xb7\x20\x8b\xf4\xe2\xd0\xc2\xe9\x1c\x09\xa6\x0e\x25\xf2\x48\x0e\x2d\x07\x02\x80\x06\x17\xc1\x1c\xdc\x80\x33\x17\xc4\xc0\xaa\x71\x15\x3c\x0d\x78\x11\x2a\x8c\x21\x31\xa4\x2d\xdb\x7f\x78\x3a\xf7\xe9\x5d\xf4\x37\xb6\x8b\x32\x8a\x27\xd5\x94\x1c\x97\x91\x61\xdc\x8c\x4b\x14\x35\xa6\xf4\xef\xd8\xdb\x87\x5d\x49\xbe\x61\x01\xfc\xdb\x33\xc3\x90\x0b\x1d\x9d\xcb\x85\xb3\xa8\xc5\x01\xa4\x64\x88\x65\xda\x61\x7a\xd6\x30\x34\xf3\xd7\xab\xa5\xd5\x38\x6c\x06\xb9\xad\x15\x15\x9b\x0e\xf9\xcc\x3a\x67\x80\x06\xa3\xa4\x7a\x40\x94\xee\x88\x8d\x18\x8e\x0f\x19\xaf\xea\x75\x61\x70\x74\x86\x3a\x95\x81\x98\x8f\xce\x74\x61\x7d\x74\x5f\xc1\x56\xd3\xdf\x26\x6f\xbc\xac\xa7\x98\x44\x55\x49\xdf\xc7\x4a\x5b\x8d\x1d\x95\x55\x38\x4b\x1d\xc1\x27\x92\x1a\x86\x3a\x7e\x96\xea\x2d\x34\x21\x78\x02\xa7\x1b\xa9\xf7\xbf\xf5\x44\x5e\x0a\x57\xa3\xb0\x76\x7d\x9d\xb2\x71\xc9\x61\xa4\x72\x61\xa9\x5b\xcc\x78\x5d\xe0\x69\xa9\xdd\x98\xf1\x7f\xb7\x2c\x59\x7f\x18\xe7\xad\x21\x49\xc2\x9b\xca\x90\x26\xed\x42\xb9\xe1\x1a\x26\x73\x91\xd0\xa5\x5e\x98\x64\x8b\x06\x9c\xb2\xe7\x5b\xf1\x41\x0f\xad\xc1\xfc\xd4\xbb\xed\xef\x37\x7c\xc3\xff\xc1\x37\x8d\x84\xb4\x49\xce\xa1\x16\xda\xa2\xe4\x14\xaa\x2e\x7a\x49\x1b\x03\x38\x47\x1d\x06\x6f\xa6\x7e\x61\xe9\x5b\x14\xc0\x29\x58\x36\x01\x20\xba\xc8\x12\xa5\x92\x43\xd6\x1b\x98\x81\x4b\x54\x51\x7a\x4b\xea\xfd\xfb\x55\xd7\xee\xaf\x5c\xea\xc6\x55\x4f\x1a\xd5\x8d\x45\x82\x5a\x1c\x9c\xf5\xc7\x2a\x04\xbf\xba\xcd\x49\xbd\x81\x4c\x47\x49\x37\xde\xe7\x7f\x3c\xf3\x6d\xe9\x20\x19\x5b\x69\x3d\x0c\x1d\x46\x29\x15\x47\xa2\x8b\x3a\x86\x32\xb6\x58\xaa\x6a\xc9\x9c\x2e\x79\xd0\xce\x1c\x0c\x2a\x1d\xfa\xe4\x8c\xaa\x41\x0a\x80\x40\x20\x0e\x64\xf0\xe0\x76\x89\x7d\xdc\xd8\x0d\xff\xd3\xaa\x27\xd2\xb5\xe8\xf9\xa0\x52\xf2\xa5\x8a\x1a\xe0\x23\x5d\x62\x66\x3d\x7f\xd4\xd3\xc5\xae\x7a\xbe\xc4\x7a\xcb\x33\xfd\x9f\xaf\xa0\x3a\x52\xdb\x9f\xda\x08\x23\x6f\xc8\x3b\x92\xf4\xac\x2b\x3b\x42\xec\x37\xf6\xd2\xff\xe2\x5f\xcf\x2d\xa4\x4b\xa6\x7e\xe0\x77\x63\xa6\x02\xf7\xb9\x8a\x0e\x40\x87\x17\xab\xc8\x71\x73\x6b\xfc\xaf\xcb\xef\xee\xa1\xd5\xb4\x89\x50\x28\x6a\xde\x64\x2b\x8f\x29\xec\x5b\x2d\x62\xcf\xb5\x14\xa4\xe8\xc8\x80\x60\xbf\x95\x5f\xfd\xdf\xce\xc0\x6d\xa4\x7a\x19\xa9\xba\xa7\xab\x57\x74\x6b\x6a\xff\xf7\x35\xb5\x59\x3d\x58\xd9\xa8\xa7\xd0\xf3\x06\xcf\xb2\x56\x5d\x3a\x55\xff\x06\x70\xea\xbc\x34\x9b\x41\xa2\xbc\xf4\xcf\x40\xd4\x10\x21\x5e\x45\x67\x38\x57\xcf\x2d\x8b\x85\xe7\x01\xee\x88\x2a\x0c\x10\xd2\xef\xf6\x2f\xd4\x1e\x03\x20\x99\x47\x30\x9b\xc8\xc2\xb5\x50\xb6\x26\xb5\x9b\x85\xc7\x6f\x14\x95\xbc\x3c\x73\x0c\x5c\xb2\x2a\xc6\xec\x28\x1d\x64\x47\x06\x04\x4e\xaa\x6e\xa2\x56\xab\xa9\x05\xf8\xb0\x5c\x88\x69\x8f\x1c\x80\x26\xd5\x09\x28\x5d\x45\x15\xab\x79\x0b\xe3\x0f\x1a\xa2\xaf\x62\x23\xaa\x2a\xb9\x76\xb5\x8e\xa9\xd4\x20\x95\xf5\xdf\x85\x1d\x15\x0b\x60\xb0\x67\xd8\xdc\x33\x90\x89\x0c\xa2\x5a\x56\x47\x2c\xea\xac\x32\x8d\xa3\xd7\x1d\x46\x1c\x40\xd6\x16\xd6\x80\x5b\x60\x69\x27\x49\x7b\xec\x86\x19\x45\xc6\x8c\x1d\xaa\x44\xab\x08\xd5\x20\x1d\x7d\x04\x07\xaa\x53\x6a\x0f\xf7\x92\x46\xe0\x6a\x49\x4b\xab\x98\xcc\x06\xfa\x47\x8e\xce\xc1\x4f\x0b\x36\x83\x74\x89\xbe\x5f\xcf\x0b\x0c\x0b\x35\x0e\x20\x51\x6e\x21\x77\x54\x0a\xca\xae\xaf\x0a\xb6\x09\x20\x0d\x82\xae\xc4\xa6\x83\x83\xa8\xd8\x63\x73\x68\xab\xb9\xca\x96\x8b\xe6\x80\x54\x8a\xad\x62\x2e\x6e\x3b\x2d\x8c\xc1\x4d\x53\xf5\x57\x6f\x78\x5e\xd2\xf9\xe2\xf5\xc8\xfa\x40\xe7\x17\x70\x00\xdf\x8a\x52\x3e\x8a\x92\xd4\x23\xe6\x3c\xf6\x5c\x42\x51\xdd\x26\xa1\x2d\x0c\x20\x10\x9a\x88\x40\x13\x00\x4e\x69\xfa\x8c\x8f\x34\xa1\xc2\xb0\x39\x65\x39\x2d\xab\x00\x8e\x83\x73\xa3\xb0\x55\x07\x98\x1d\x6e\xb5\x78\xf6\xf1\x18\x8e\xcc\x12\x8b\xf4\xe3\x6b\xdd\x59\x52\xd4\x63\x1c\xa8\xc3\xd4\x43\x32\x18\x49\x17\xb3\x7a\x73\x87\x3a\xed\xc3\xca\x02\x70\x7a\x50\xa1\x43\x89\xad\xea\xc9\xec\xa1\xe6\xc5\x8b\x06\x2f\x55\x4f\xa5\xce\xda\xd5\x62\xc4\x4e\x1e\x79\xf9\x16\x94\xcd\x0a\x42\x02\x0b\x7f\xf0\xb4\x3a\xec\xc2\x64\x47\xac\xa3\xb6\x00\x1b\xc7\x3d\xd3\xe1\xa0\xec\x3d\x02\x36\x85\x45\x33\x93\xc9\xf6\x48\xad\x2b\xdb\x6a\xdc\x24\xed\xb4\xb8\x9e\x5e\xc0\xcf\xdd\xae\x01\x9a\x03\x71\xfd\x16\xa4\x04\x1a\x9e\xed\xa1\xaa\x66\x9b\x19\xb2\x7d\xa2\x94\xd1\xe0\x37\x15\x99\x59\x30\x29\xa8\xf1\x61\xb8\xe9\xe2\x3c\x17\x36\x15\x64\x41\x64\xc3\x79\x9b\xe5\x3a\x02\x43\xb8\x34\xdb\x02\xb6\x2b\x64\x01\xcd\x61\x18\x51\xf3\x57\xcf\xdd\xa2\x78\x01\x60\x7c\x2c\xbf\xf0\xa3\xfa\xf8\x68\x47\xac\x27\x03\x2c\xea\x3e\x19\x75\xb9\x57\xc4\x70\x06\x6b\x77\x77\xc1\xd2\x1d\x30\x0b\x80\x06\xc6\xb7\x5a\x58\x6c\x13\x9c\x1d\x82\xa3\x37\xd7\xe5\xce\x20\xa9\x5e\xc9\x0e\x58\x19\xc8\xad\x6f\x56\xf9\x59\xf2\x0e\xf4\x0f\x96\xcf\xea\x4d\x0d\x87\x84\x9a\xc6\x61\x25\x03\x86\x05\x86\x30\x93\x7e\xc6\x64\xd2\x4a\xe2\x93\x3a\xfd\x62\x80\x81\x1b\x16\xc1\xab\x33\xd0\x96\xab\xc0\x13\x45\xcd\xb7\x19\x73\xdd\xad\xed\x49\x3c\x1c\x17\x47\x56\x3f\x53\xd6\xdb\x84\xd8\x56\xb5\x35\xde\xa1\xba\x0b\x64\xaa\x41\xc6\x51\x12\x9d\x47\x96\xec\xc8\xf6\x75\x64\x65\x1d\x58\x5e\x07\xb6\x78\xf8\xcc\x28\x07\x4a\x28\xc6\x50\x04\xd7\x4b\x85\x1c\x62\xfa\x6a\xa7\x07\xb8\x2a\x81\x11\x07\x15\x3e\x60\x5d\xd6\x70\x82\x38\x4d\xba\x14\x4f\xa9\xaf\x84\x30\xcb\xba\xea\xe1\x94\xa6\x65\xe1\x95\xec\x2d\xd5\xb1\xea\x2a\xe0\xf2\x8a\x68\x11\xd8\x8c\x54\x03\xe7\x0a\x08\x78\xaf\xc1\x29\x2e\x20\x00\x2d\x08\x80\x93\x67\xa5\xc5\xe5\x4c\x60\x56\x2b\x75\xc0\xa1\x25\x64\x31\xb0\x73\x05\xd8\x08\x83\x94\x90\x43\x3d\x2b\x42\x8a\x5e\x63\xc5\x3d\xd8\x56\x43\x80\xc2\xce\x1c\x76\x3e\xbf\x5b\xb2\x54\x4e\xd9\x8f\x14\xcc\x0e\x14\xbe\x6e\x1d\xfd\x97\x6f\x45\x77\x5e\x5f\xfd\x8d\x6a\x58\xb7\x11\x24\x07\xa6\x6c\xf4\x2f\x38\x97\x59\x82\xa7\x37\x71\x4e\x74\x2b\xad\x1c\xe2\x70\xa1\x39\x4e\x37\xaa\x7b\x85\x75\x9d\x2a\x07\x39\xb1\x23\xc9\x8a\xb1\x38\x19\x65\x53\x6e\x97\x58\xb9\xed\x1d\x85\xe3\x56\x18\xd4\x51\xd7\x89\x98\x81\xa1\x99\x72\x9f\x96\x96\x85\x20\xf2\x24\xd6\x09\x53\x34\xb4\x86\xba\xb7\x1b\x19\x10\x47\x77\x44\xb6\xea\x6c\x55\x6c\xbc\xbc\x58\x0f\xc9\x63\xe2\x2c\x34\x40\x01\x71\x9d\xf1\x48\x1e\x4a\x0d\x10\xf0\x96\x5c\x57\x65\x2c\x08\x4e\xe1\x81\xc0\x9b\x63\x82\xc5\x39\x09\x92\x57\x3b\x9a\xa0\xec\x20\x6d\x49\x16\x24\x31\x5c\xa8\xfe\x7c\x76\xc0\x55\x4b\x33\x7a\xc9\xc2\x8d\x65\xf8\xe2\x8a\xcb\x6f\xac\x96\x21\x5f\x38\xb5\xa3\xa2\xae\x23\x2d\x64\x71\xaf\x8e\x2c\x16\x43\x16\x17\x13\x5a\x96\x62\x80\x2a\x23\xd8\x1b\xf0\x11\xa8\xd4\x2d\x5a\xdd\x7c\xc6\xa1\x48\xee\xca\x53\xf2\x30\xb5\xaa\x26\x75\x7b\xba\x1d\x56\xc8\x8e\x2c\x41\xcf\x49\x29\xc1\x82\xc1\x56\xb8\x60\xc1\x32\xab\x4c\xe2\x6e\xd8\x0a\x98\xdb\x63\x1c\x31\x8f\x0b\x23\xd5\x09\x03\x46\xaf\x1a\xab\x57\xc2\x72\xd8\xc5\x2d\x2c\xc1\xaf\xcf\x68\x7b\xb4\x3a\x1f\x2e\x61\xc0\x60\x34\xe2\x10\x5c\x19\x94\xa1\x81\xd5\x6c\xec\x2b\xf4\x97\x17\x00\x89\x24\x38\x03\x01\xc2\x92\x61\xb4\xd9\x55\xb9\x82\x7a\x82\x10\x6c\xd2\x6f\xc7\x4c\xe0\x3f\x62\x03\x57\x0c\x8b\x17\x35\x36\x80\x10\x49\x79\xa3\x7a\xc0\x30\x6c\x32\xc9\x84\x26\x26\x16\xe9\x40\x86\x00\x6a\x6a\x49\x48\x0a\xa3\x79\x72\x9f\x32\xf4\xca\xa5\xd6\x0d\x28\x8b\xa1\x52\x19\x20\x05\x83\xcf\x1b\xd8\xcb\xe3\x88\xa8\xf2\x09\x14\xf6\x08\x99\x60\x9e\x72\xdb\x01\x1c\xe0\x60\x45\x6a\x30\x24\x70\xa4\x1c\x70\x0f\x02\x8d\x55\xa2\xd0\xe7\xda\x67\xc9\x8c\x09\x84\xe7\xe8\x8c\x66\xb0\x01\xb0\x81\xdd\x0b\x8c\x35\x1d\xbb\xa1\x81\x87\x57\xda\x42\x18\x2e\x3a\x15\xc7\x0a\xab\xcc\x04\x56\xbb\xb9\x0d\x08\xa8\x73\x93\x20\x53\xcf\xe8\x42\xad\xbb\x48\x1b\x86\x75\x00\xfe\x01\x15\xc5\xb4\x2c\x8e\x68\xf5\x2c\xc0\x85\xb2\xdb\x05\x72\x06\x2f\x91\xb2\x0d\x1e\x15\xa8\x06\xa8\x19\xd9\xd3\x7a\xd1\x62\x52\x28\x7f\xbb\x16\x44\x14\xcb\x4f\xb4\x0e\x26\x18\x15\x4b\x0f\xf7\x0c\xe9\x96\x1c\xa3\x6a\xba\x17\x27\xd2\xa4\xb0\xa0\x1c\x14\xc9\xc3\x61\x7e\x04\x02\xa6\x23\xc1\xb3\x6c\x14\x38\xab\x25\x2b\x6d\xd2\xc0\x49\xde\xa3\x04\xc1\x41\x08\x55\x25\xff\x08\x8f\x2c\x58\x69\x01\x3c\x4f\x14\xea\x6e\xe5\xd1\x4e\x99\x17\xa2\x87\x38\x4c\xde\x9f\x05\x18\x86\xd7\x5b\xbc\x40\x60\xed\x59\xfc\x6e\x61\x02\xba\x2a\xa6\xf1\xa1\xf3\x9c\xa1\x4f\xcc\x4c\x31\xa4\xb0\x2c\x2a\x87\x3c\x26\x25\xec\x5d\xfd\x87\xa6\xc1\x92\xca\x42\x6c\x0b\x88\xa9\x50\xb4\x29\x74\xe2\x6f\x01\xed\xce\x86\x02\x7b\x54\xbe\x5a\xd6\xc9\xc7\xb6\x7a\xfa\x50\x5e\x56\x38\x44\x4e\x4b\x1b\x4c\x45\x8f\x2d\xed\xb1\x74\x35\xa5\xb7\xcd\xec\x8a\x5a\x98\x92\x61\xb2\x19\xea\x47\x32\x4a\xa9\x77\x84\xe1\x61\x1c\xb3\x5a\x72\xc9\xea\x3e\xa6\x43\xa0\xd5\x19\x32\x4c\x67\x67\x73\x87\x92\xca\x90\x7a\x94\xa6\x42\xb0\x60\x5f\x85\x61\x4a\xd1\x0c\x6d\xc8\x2a\xb3\x65\x03\xf1\x79\x9e\xd2\x0a\x7f\x55\xd3\x21\x31\x3b\xd1\x97\x65\xf1\xad\x08\xec\x88\xa5\x58\x1d\xe4\xd3\xd3\xf0\xa5\x4f\xc3\x68\x3a\x0d\xad\x5f\x58\xe8\xa8\x09\x63\x22\xfc\x21\xe7\x7e\xc4\xa6\x9f\x10\x1d\x6a\x9b\x5d\x62\xad\xe3\xe1\x3e\x03\xea\x83\x1c\x01\xe7\x30\x8c\xf5\x85\x5b\xc8\x3c\x21\x36\xf4\xb4\x18\xd2\x74\x84\xf5\x5e\xba\xec\xe6\x4f\x74\xb0\xd8\x58\xb5\x1e\x9d\xde\xd1\x79\x85\x0f\x79\x79\x4e\x2a\x09\xec\x01\x6e\x21\xe8\x45\xae\x4e\xa5\x84\x42\x42\xab\x80\xb9\xf1\x92\xff\xc7\x35\x26\x80\x92\xce\xac\xca\xa0\x21\x11\x9f\xbd\x00\x67\x4c\xa0\xed\xa6\x17\x0d\x3b\xfc\xd5\x72\xf0\xf0\x41\x21\x8e\x79\x38\xe9\x02\xf7\x99\xa1\x67\xdc\xa7\xec\x3b\x76\x65\x19\x56\xf7\x6d\x04\x0e\x27\x6b\x50\xcd\x93\x38\x8c\x72\x34\xa1\x4b\x14\xe1\x83\x7a\xbd\x00\x2d\x33\x92\x85\x15\xd3\x52\x4e\x91\x4c\x01\x03\xc8\x8a\x7c\xd0\xaa\xe7\x35\xf4\x0f\x38\x5c\xf6\x38\x2c\xb2\xd8\x4e\x28\xac\x13\xc0\xc0\xbc\x78\xb8\x2f\x49\xb7\x4a\x01\xa4\x8b\x51\xd9\x68\x11\x5e\x23\x43\xcc\xb6\x0a\x6f\xc0\xf4\x7d\x95\xee\xce\x75\x32\xbc\xe7\x80\x75\xe3\x15\x3e\x2a\x06\xdf\xc0\x03\xdb\x99\x63\xe3\x3c\x5c\xdf\xb8\x42\x92\x51\x78\x51\x16\x4e\xbe\x5e\x0b\x2f\xc8\xb9\x03\x7c\xd5\x6e\x9d\xd1\xff\xf3\xdb\x9e\xd1\x75\x42\xdd\xaa\x56\xcd\x4c\x9b\xd4\x16\xa4\xca\x8e\x80\x7f\x0b\x96\xdb\x6d\x17\xca\x63\x8b\x02\xe7\xbc\xb5\xbd\x90\x15\xd7\xa4\xe6\x14\x37\x93\xcc\x47\x87\xb1\x01\x9e\x1e\xf3\x33\xbc\xe6\x3b\x02\x8e\xba\x45\x46\x5d\x6c\xda\x40\x36\x93\x73\xda\x90\x59\x6e\xc8\xc1\xf4\x67\xce\xdb\xb6\x0c\xa0\xf3\xbc\x55\x3e\x28\x21\x5b\x9f\x87\x1d\xb8\x36\x3c\xa7\xae\x9f\xd9\x89\x6b\xb7\xc2\x5d\x7f\xf7\x28\x93\x3f\x6a\xbb\xd0\xa8\x47\xac\x49\x35\x77\xee\x61\x58\xb4\xc7\xac\x29\xa6\x1d\x39\x2f\x2f\x91\xf3\xe4\x03\x0d\xaf\x27\x42\xa0\x48\x54\xd5\x65\x15\xd4\xa5\x86\xde\x43\x07\x7b\x69\xe0\xb1\xa3\x10\x73\xd8\x14\xf4\xc5\x4c\x12\xcb\x22\x43\x1b\xe4\x30\x16\x86\xd0\x69\xa9\xa9\xef\x22\x47\x85\x69\x67\x45\xc4\x27\xf2\xcd\x45\x3a\x6c\xfb\x66\xb6\x3d\xa2\x61\xfd\x88\x95\x87\x7e\x91\x8e\x5a\x9a\x95\x51\x22\xe2\xdf\x4d\x0c\xe7\xc5\xbd\x31\x02\x4b\x70\x34\x76\x85\x11\x92\x56\xdd\x98\xa5\x38\xd6\xee\x45\xd9\xb3\xe5\x9c\x54\x91\x8e\x23\x56\x79\x0e\x99\xf0\xd5\xe3\x2d\x37\x4a\x85\x3c\x8c\xa3\xdf\x96\xf6\x06\xed\xa4\x25\xed\xa1\x75\x86\xa7\x1b\x7e\x68\xd2\xfe\xeb\x53\x10\xae\xe8\xc4\x80\x98\x0a\x9c\x78\x9a\x97\x00\x3f\xc8\x62\x26\xd5\xb8\x9f\x60\x31\xdf\x95\x7d\x40\xaf\xa9\xb9\x21\x79\xa2\x10\x2f\xc0\xef\x9e\x03\xc7\xe5\x4c\x9e\x80\x6c\x05\x75\x8f\xb8\xf0\x98\x91\xfa\xe6\xeb\x4b\x66\xf1\xe8\x9a\x5b\x7c\x8c\xe0\x5d\xc0\x54\xcb\xd5\x32\x7c\xa3\xbf\xe1\xce\xb3\x3a\xa4\x6a\xe1\xc2\x21\x6d\x79\xc1\xa7\x60\x3f\x98\x08\x36\xcf\xcd\x00\x9d\xd5\x43\x9e\x91\x25\xec\xaa\x82\xe1\xc2\x21\xf7\x6d\xee\x3b\x03\x57\x8d\x5d\x57\x57\xd9\x9d\xbf\x35\x79\x4a\xbc\x8a\x99\x47\x74\xa5\x69\x70\x02\x03\x33\x04\xc6\x2a\xbf\xb0\x9f\xf7\x97\x82\x16\xb9\xc9\x62\xf0\xf7\x57\x16\x13\xec\x2d\xb6\xbd\xc5\xa2\xae\x61\x21\xcb\xf3\xaa\x83\xde\xac\x9c\x8f\x7d\xb8\x88\xde\x21\xb9\xea\x2e\x3e\x5b\x94\xc2\x81\x81\xee\x8a\x82\x89\x02\x76\x87\x24\x8f\xe0\xb1\xd7\xdf\xb2\x55\x7f\x76\x67\xaa\x32\x63\xce\x23\x80\x0e\x2c\xcd\xa6\x80\xf6\x58\xad\x40\x91\x53\x60\xc7\x9f\x12\xe0\xf9\x47\xcc\x49\x8f\x0e\x8f\x07\x90\x17\x79\x81\xf8\xe3\x10\xde\x73\x11\xbc\xe0\x76\x36\x23\x84\xd7\x2c\xed\x5b\xd2\x13\x21\x3c\x2a\x6e\x64\x06\x06\xfc\xcc\x56\xee\x2c\x06\x1f\xe9\x0c\xd1\x21\x40\xe7\x59\xb4\x38\xea\xef\x0e\xcf\xed\xd7\x03\xd0\x70\x00\x48\x82\x50\xe0\x54\x66\x57\x17\xb9\x79\x5c\xd4\x82\x5a\xe4\x49\xf8\xa5\x1e\x2d\x15\xdb\xdc\x94\xe3\xe4\xaf\x29\xe4\x56\x4d\x4e\x47\x6b\xb6\xaa\x5e\x45\xc0\xe3\xc8\xc9\xe9\xdc\xd8\x2b\x28\x57\xa9\x11\x82\x47\x57\x86\x69\x07\x56\xd5\x64\x38\xbe\x33\x5c\x03\x51\xd9\x7c\xc1\x2c\x92\xe9\x95\xc7\x54\x51\x8f\x13\xd4\xf1\xbc\xe7\x41\x6b\x45\x9a\x18\x23\xab\xc8\x04\xe1\x19\xb0\x28\x16\xda\x06\x05\xab\xed\x62\x39\xcb\xac\xa4\x85\x36\x66\x56\x57\x40\xb5\x2b\x0a\x41\x64\xa1\x9d\x64\x78\x68\x06\x2f\x5f\xf4\xb7\xc9\x63\x8a\x28\xa6\x8e\xcd\x69\xe3\xce\x74\x85\xd3\x88\x58\x58\x6a\x11\x11\xb8\x47\x77\x6b\x5d\x7e\x73\x65\xa0\x5e\x62\xb7\x1e\x70\xb0\x58\x02\xd7\x50\x40\x80\x51\x39\xe4\x34\xeb\x70\x67\xd5\x70\x26\xe3\x51\x64\x7b\xd9\x6c\xd3\x61\x46\x1e\x2e\x4d\x70\x65\x64\x8f\x25\x05\x3d\xb7\xa3\x5a\xd1\xeb\x60\x8b\x80\x8a\x45\x40\xef\xca\x1b\x31\x50\xf2\x18\x68\x5a\x4c\x38\xa8\xa9\x3d\x62\x81\x75\x2c\x37\x22\x1c\xdf\x5c\x09\x70\x78\x6c\xa4\x9a\x8a\x9c\xd9\xc6\x68\x94\xb0\xdd\x17\xfc\x16\x31\xbc\x0a\xae\x1a\x18\x19\xb5\x79\xdd\xa1\x57\xc7\xf0\x3a\x3e\xbc\x77\xb6\xb8\x10\x5c\x67\x35\xb1\x9b\x1d\x72\x4b\x3b\xc0\x08\x96\x2b\xc5\x8c\x31\x4b\x0c\xdd\x29\xc1\x18\x57\x18\x48\x67\x33\xc7\xea\xb2\xcb\x06\xe2\xde\x60\x03\x4e\xc9\x4c\x78\x4b\x34\xf9\x1a\x22\x40\xb0\x54\x0c\x38\x3d\xfc\x78\x38\xa5\xc0\xb8\x16\x1a\xd5\x1a\x56\x84\xc6\xac\x66\xc3\xd7\x58\x39\xf4\x98\xcb\x9f\xb6\x24\x52\x72\xf6\x0d\xab\x76\x02\xa5\xd4\x9d\xd1\x6e\x90\x47\xad\xf3\x74\xbe\x15\x60\xb4\x51\x82\x6a\xec\x10\x1e\xfc\x13\xa7\xf0\x54\x0f\xd7\xaa\xe4\xc6\xe9\x1a\xaa\xf7\x7f\xf7\x88\x1a\xcb\x00\xcc\x3a\xd3\x2b\x03\x03\xa0\x39\x58\x92\xad\xd4\xf3\x4a\xff\x27\x0c\xa6\x1b\x20\x82\x50\x7b\xde\x77\x6a\x84\x48\x0c\x17\x5a\x2e\xdc\x52\xc7\x8c\x9a\x09\xf0\x20\x0e\xfb\x24\xe2\xf8\x24\x7e\x24\x61\x9b\x57\x36\xf4\x15\xb4\x20\x26\xc3\x5c\x8b\xeb\xd6\xe9\x51\x6d\xd8\xfa\x4f\xef\xab\x79\x85\xf4\xb7\x96\xe0\x40\x30\x8d\x4d\x1d\x13\xce\x40\x03\x18\xbf\x0f\x68\x5b\x1e\x91\x90\x8f\x0d\x7c\x9f\xd4\xcb\x85\xd5\xfc\xd1\x2f\x46\x1e\x6d\x8f\x02\x45\x1a\x57\xf5\xcf\xc2\x53\x18\xda\xa9\xf5\x60\x7a\x5b\x75\xbd\xd9\x77\x22\x6e\xf1\x5b\x59\x3b\x9d\xa4\x1f\x23\x79\xa4\x92\x1b\x6a\x7b\x36\x54\x7c\xf4\x01\x19\x66\xf5\xbc\x16\x85\x76\x52\x18\x0b\xde\xc2\x7a\x5a\xd5\xf0\xd2\xce\x14\xdf\x28\xa8\x44\x07\x8d\x34\x59\x08\xc5\x40\xf8\x28\x60\x1f\x21\x07\x32\xae\xee\x12\x38\xa3\x14\xe2\x66\xe0\xed\x1f\xae\x59\x6e\x29\xfd\x28\xa3\x5f\xd4\xf6\x8a\x65\x78\x80\x3e\x05\xc7\x50\x23\xa3\x68\x85\x76\x7a\x0e\x1f\x33\xf6\x34\x67\xec\x31\x42\xaa\x75\x1e\xf4\x38\xa8\xc1\x55\x9a\x98\x89\xd8\x3d\xbe\x54\x43\x71\xc3\x78\x31\x3b\xa8\x1a\x60\x44\x20\x87\x81\xb9\x57\x10\x5f\x68\xc7\xda\x20\x27\x45\x56\x8d\x58\x9d\x67\xcb\x4e\x8b\x6e\x58\xb3\x68\xc6\x1e\x9b\xa5\x3f\x44\x57\x1c\x68\x33\xcc\x53\x65\xaf\x8a\xf0\xa0\x67\xbf\x01\xc0\x3e\x4e\x2c\x3a\xc4\xab\x19\x52\xea\xdd\xf0\x69\xd2\xc7\xf3\xb0\x9c\x17\xf6\x61\xbb\x2b\x1b\xab\x21\x5d\x89\xb7\x21\x81\x5b\x02\x8d\x50\x2a\xa1\xb6\xc0\x8b\x93\x90\x54\x95\xeb\xae\xdc\x0d\xfc\x99\xc4\x73\x6d\x56\xe3\xb0\x68\x7d\xb1\xed\x75\x57\x62\x3f\x75\xf0\xd0\x3f\x3d\xe6\x7f\xf4\xf5\xab\x36\x66\x24\xb6\x31\x66\x59\xc3\x3a\x35\xfe\xf5\x32\xad\x14\xd8\x4a\xaf\xa4\x2b\x71\xfb\xd6\x51\x75\xde\x21\x97\x4b\x2d\x80\x8b\x93\x20\x25\x2b\x3b\x78\x98\xbc\xf6\xc4\xd8\x29\x48\xd7\x3f\x4f\x70\xb3\xce\x55\xb4\x7c\x54\xb9\xac\xb4\x8c\x89\x32\x2b\x36\xb5\xdc\x1b\x92\x5f\xcd\x88\x54\xd8\x92\x8c\x19\x59\x71\xc0\x5c\x65\x03\x82\xa8\x08\xab\x14\xd4\xc1\x08\x03\xfe\xfa\xf4\x04\xfc\xf6\x5c\xb4\xb4\x59\xd6\x54\x05\xf9\x50\x69\x8f\xb0\x5b\x0d\xb9\x21\xdf\xb4\x39\x2c\x77\x6c\xd4\x6b\x90\x34\x1c\xd7\x92\x90\x25\xc9\xbb\x65\x0e\x3a\x07\x26\x58\x1d\xc8\xff\x06\x0f\x65\x57\xf4\x0b\x18\xe8\x32\x80\x3a\xb0\x28\x9c\x2f\xb7\x73\x29\xff\xc1\xd1\x12\xfa\x5a\x25\x6f\x08\x0b\x8f\x06\x1d\x57\x03\xbc\x6c\x99\xb0\xac\x11\x4d\x41\x5c\x2f\x32\x23\xf2\xcb\xe6\xf6\x21\x2e\xbb\xa4\xe9\xce\xaa\xd9\x32\x07\xf7\x44\x85\xac\x2f\x46\xe9\x53\xd4\x85\xdd\xa2\x94\x11\x46\xce\x17\xee\x74\xee\xda\x67\xf6\xec\xb9\x63\xb1\xff\xf2\x36\x38\x70\x61\x75\x7e\x0b\x99\xbb\x03\x16\x0d\x76\xa2\x2d\x23\x86\x37\x52\x7c\x95\x50\xbe\x83\x8b\xef\xe0\x0a\x52\x3a\xb9\x33\xe0\x16\x28\x83\xb0\x7d\xd5\xd4\xad\x7a\xb0\x55\xe2\xc2\x1b\x48\x56\x98\x0e\xa9\xda\xd3\xa2\x65\x32\x8c\xed\xc8\x4b\x15\xed\x28\xa2\x40\xa6\x48\x02\xa5\x1b\x5b\xff\xe1\x71\xbd\x04\x2a\x19\x6a\x50\xf9\x15\x73\x69\x07\x8d\x72\x69\x35\x1f\x51\x3f\x89\x79\xa0\xe6\x3a\x5d\xb2\xc0\xa0\xa0\xa0\xbe\xe4\xb4\x62\x7a\x6c\x7e\x76\x72\x2b\xdd\x2f\x4e\x42\xd8\xf3\x8d\x1f\xfe\xbf\xdc\x7e\xe1\x90\xb9\x23\x41\xd3\xf3\x5e\xc5\xea\x8d\xa0\xab\x04\x71\x3f\x07\xf2\x82\x38\xcf\x95\x31\x59\x18\xd7\xfe\xc5\xe1\xc4\x67\x09\x04\x92\x12\x46\x0f\xdc\xea\xe4\x21\x61\xc8\x85\x40\x45\xd0\x21\xbe\x69\x8f\xd5\xb2\xef\x8b\xd1\x7a\xb1\x5b\x59\xd6\x99\x72\x30\xdd\x0c\x8f\xf4\x6e\x31\x72\x2f\x78\xa5\x7d\x86\xad\x31\x9c\x3a\x50\x77\x1f\x84\xa4\xa9\x2a\x32\x98\x0e\xa7\xe0\xbc\xd7\xe3\x74\x1b\x6b\xf3\x90\x75\xe7\xe0\x74\x30\xe3\x2c\xc8\xb2\xb7\x8b\xae\xa2\x21\xd7\xeb\xba\x60\x7b\xbd\xc8\x27\x23\x5a\x09\x30\xb7\xa1\x23\x91\xa0\xd3\x51\x5e\x28\x23\x67\x44\xe8\x8d\x01\x81\x9f\xcc\x73\x0c\x66\x6a\x0e\x44\x33\xe1\x25\x33\x81\x53\x4c\x8c\xe3\x4d\x90\xb1\x1f\xd9\x92\x81\x88\x74\x82\x17\x03\x15\xf2\x81\xcc\x18\x72\x40\x2d\x07\x75\x5d\x42\xee\x1e\x33\xe9\xe8\x8d\xc0\xe2\xb5\x6a\xa6\x5e\x2d\xaa\x00\x04\xc0\xe5\x26\xb4\xeb\xff\x76\xb8\x5e\x02\xf7\xe2\x38\xa8\xea\xc1\x03\xa2\x4c\xaf\x22\xf3\x8d\xd4\xfa\xff\xe3\xc2\xba\x81\x7f\x47\x2d\x94\x72\x01\xfd\xce\x40\x46\x69\x88\xb1\x8f\xc2\xb6\xaa\x5e\x50\xe2\x05\x00\x3e\xa5\xb6\x67\xec\x72\xf8\xec\x8a\x73\xc6\xf7\x16\xac\xf3\x01\x32\x46\xd9\xd6\xe4\xd2\xb3\xa7\xe3\x7a\x45\x21\x6c\x32\x45\xda\xa7\x65\x2f\xac\x0e\x41\x8c\xc9\x01\x84\xd9\x3d\x7b\xa7\x1d\x58\x74\xaa\x16\x4a\xc3\xff\xc3\x69\xb0\x5c\xba\x2d\x26\x9b\x5e\x76\x26\x92\x91\x17\x67\x96\xe1\xf7\xc5\xd2\xcd\x10\x26\x2b\xc4\x81\xfe\x02\xc3\xa2\xd4\xe6\x08\x59\x9d\x31\x95\x43\x97\x9f\xf2\x99\x5a\xca\x0e\x3f\x01\xda\xca\x56\x34\xdb\x64\xf0\x39\x05\xc0\x44\x83\x1c\xc2\x8f\x91\xf7\x2e\x49\x96\x6a\xb1\x2e\x1e\x23\x74\xb6\x7d\x5c\xdb\x2c\x86\xe2\xdd\x63\xed\xb6\x11\x93\x41\xa2\x17\x05\x37\x55\x46\xc8\x07\x67\x49\x08\xc7\x27\xdb\x29\xc2\x68\x92\xc7\xac\xdd\x05\xb4\x54\xac\x5a\xb4\x38\x95\x99\x70\x52\x9f\x5e\xfb\xff\xd7\xf5\x94\xda\xa6\x55\x8f\x5a\x49\xc6\x30\x38\xc8\x12\x8e\xb0\xd8\x7a\xb6\x3c\x62\xeb\x81\xaa\x07\xcc\x8d\x67\xde\x39\x8d\x21\xd1\xcf\xc0\x33\x50\x45\x7d\xf7\x5a\x01\xe7\x65\xc2\x6d\x6d\xc7\x29\xc2\x5b\xf5\x29\x35\xf0\xca\x9f\x8a\x51\xc1\xd4\xec\xfc\x4f\x90\x20\x48\x09\x66\x47\x5c\x87\xd8\x9d\xed\xd5\xcc\x72\xd4\x6e\xf4\x93\xcc\x15\x4b\x0c\x96\x04\x03\x20\xa8\x3c\x87\xc3\x99\x13\xce\x2e\x5a\xfd\xa4\x00\x78\x77\x83\x67\x15\xd6\xf1\x4a\xa7\xd7\xdb\x97\x27\x62\xf8\x08\xa1\x55\xb7\x40\xb7\x70\x29\x7f\xfa\xb3\xdf\xbe\x4c\x4f\x37\xc8\xd2\x8f\xe8\xd3\xc7\xfd\xb0\xac\x21\x16\x85\xb3\xf7\xd4\x5c\xed\xa8\x56\x7f\xaa\x6b\xcb\xaa\x47\x8d\xac\xbc\xb7\xd5\xd9\xec\x6a\xf5\xbf\xba\xf2\xdf\x38\xfa\x04\x46\x0c\xcc\x60\x30\xcb\x67\x93\xa0\x7a\x71\x65\xf8\xb0\x2a\x7c\x34\xc4\xb2\x60\x9f\xce\xa1\x0f\xc8\x5b\x61\xc1\x91\x60\x0e\x67\xc9\xac\x77\xa4\x42\x7b\x2a\xa3\x50\xdb\xac\x81\xd5\x85\x7a\xd9\xbc\xb3\xd5\x4e\x38\x5e\x68\x77\x35\xbd\xfb\x55\x98\xf9\x0c\x27\x39\x17\x91\x1d\xd2\x7c\x4a\x7b\xa4\xfc\x56\x5f\xad\x5d\xf5\x71\x5a\x27\xc0\x14\xf0\xb5\x1f\xd7\xed\x15\x58\x8d\xb0\x7a\x0a\x25\x03\x4c\x36\x30\xcf\xbd\x4e\x87\xc8\x10\xd8\x33\xd3\xa4\x56\x42\xc9\x1b\x8f\xc0\x3c\x0c\xc1\xcc\x66\x9b\x34\x0b\x58\x7b\x1e\xc4\x2b\x76\x0b\x2c\x06\xd4\x72\xa6\x1d\xf6\xa6\x6e\x5a\xeb\xfc\x53\x36\x70\xdd\xa9\xa4\x79\x17\xcf\x25\x8e\xe6\xaa\x8f\xb1\x5c\xf0\x7c\x5c\xf8\xe4\xe5\xe6\x4a\xdd\x20\x92\x4a\x6f\x7b\x56\x57\x1f\xf1\x0c\x69\x56\x36\xdd\xeb\x23\x9c\x55\xc3\x21\x00\x8e\x0f\x12\x15\xd4\xac\x58\xe7\xcd\x78\x45\x12\x58\x08\x28\x70\xd9\xb8\x05\x4e\x03\x13\x0a\x3e\x0a\xae\xc1\x28\x01\x21\x14\x2c\x46\x6c\x89\x59\x2b\x7f\x37\x64\xbb\xe3\x4b\x04\xdd\xc9\x8c\xd7\x89\xad\x32\x6c\x22\xe6\x4a\xb4\xd5\x16\x4a\x6e\xd6\x99\x83\xfc\x34\x9e\x91\x31\x07\x07\x98\xd7\xde\x8d\x3d\x06\x01\x9a\xdb\x6b\x27\x9f\x5e\x4b\x5c\x72\xdb\x65\xe8\x51\x05\x99\x00\x9b\x54\xb1\x68\xa6\xae\x98\x18\x2d\x05\x83\x99\x3e\x57\xe3\x9c\x74\xe0\x8f\xc1\x40\xdc\xba\xd1\x21\x3b\x10\x57\x10\x60\x29\x90\x95\x86\xe7\xd2\x6d\x75\x89\x24\x86\x62\x19\xbc\x47\x83\x6c\x5c\xb7\x1c\x2d\x8e\x5e\x34\x84\xe3\x2b\x08\xc7\x1c\x4b\x00\x65\xcd\xcb\x9c\x94\x47\xe0\xb1\x50\xb4\x19\xd0\x3f\x70\x82\x50\x02\x11\x30\x52\x57\x09\xca\x87\x3c\x1f\x87\x83\xa7\x16\x1d\x07\xe0\x2e\xc4\x97\xe2\x04\x34\xae\x60\xc8\xdd\x09\x39\x73\xcc\x40\xb7\x13\x5e\xc5\x81\x25\xd1\xb0\x98\xd4\x02\xb9\x69\x6e\x44\x84\x74\xe1\x54\x5c\xc1\xaa\xf2\xe8\xa0\x8b\xb4\x24\x6d\xef\x46\x5e\xde\xfa\x62\x60\xf3\xd0\x1f\x32\x72\xb0\xbd\xfa\xfa\x83\x00\xd7\xbc\xeb\xde\x86\x51\xca\x17\x1e\x06\x9c\x4e\xb6\x42\xe6\xa3\x35\xf2\xf0\x5b\x6d\x7e\xe1\xf4\x44\xc9\x02\x65\xc9\xdb\xbf\x38\xf9\x61\x01\x62\xf4\x8c\x05\x5a\x4a\xa9\x6d\xdd\x5a\x26\xec\xd1\xf6\x7b\x52\xd7\xcc\x60\x8a\x03\x15\x3c\x2b\x97\x62\x50\x8d\x51\x3d\x25\x09\xa2\x6d\xbb\x54\xf5\x24\x5e\xef\x93\x82\x5b\xee\x4e\x48\x61\x38\xbf\xfa\xec\x4e\xcc\x9f\x5e\xe9\xf1\xb3\xa4\xcd\xc8\xaf\xd4\xf4\x63\x83\x5e\xc8\xc2\x60\x92\xc5\xb5\x41\x2a\x45\x29\x74\x99\x52\x02\x5a\xb4\xe1\x2b\xb2\xa9\xb3\x4f\x4c\x9b\x05\xcc\x88\x76\x69\x81\x46\xb0\x74\x49\x32\xd4\x18\xd1\x62\x87\x4d\x1e\x2c\x44\xdc\x11\xc9\x9d\xcd\x38\x17\x99\xec\x91\xea\xad\xee\x7a\x8c\xb3\xfb\x41\xb1\x8b\xdb\xbc\xdd\x2a\x6d\x8c\xc8\x09\xca\xd0\x88\xfe\x54\x7b\x6f\xfe\x5d\x7d\xca\xf5\x79\xa9\x07\x9b\x53\xa3\x36\x72\x0d\x87\xb8\xeb\xf2\xf4\x11\x77\x44\x65\xa0\xda\x6f\x36\xb9\x23\x58\x02\xd5\x08\x2f\x88\x1e\xee\xa5\xaa\xb1\x00\x39\x21\x65\xd5\x46\x59\x22\x03\x6a\xc3\xb9\xa9\x8a\x53\x7a\x92\x80\xc3\x4a\x3c\xc9\x5e\x2c\xe7\xe1\xd9\x5a\xd5\x30\x20\x81\xf1\x1e\x01\x5e\x09\xa9\x37\x18\xe9\x8c\x25\xe6\x11\x66\x57\xe1\xea\x0f\x8c\xfe\x1b\xd5\xb2\xd9\xe5\xda\x02\x01\xc0\xb0\xdb\x6b\x5d\x3e\x3d\xab\x46\xbd\xc4\x24\xa3\xe9\x46\xcc\x5d\x36\x70\x2a\x74\xb9\xb0\x0c\xf5\x61\x81\x6e\xca\x17\x2e\xbc\x30\x64\x7a\x55\x79\xfd\x25\xf9\x5f\xa8\x76\x43\x95\xd9\x45\xcd\x87\x7e\xa6\xff\x56\x5e\xff\x0d\x5c\xf8\xed\x61\xad\xae\x50\xa7\x15\xdf\x4a\x31\x23\xbe\xa1\x26\x91\xd3\x03\x3e\x2b\xa5\x1d\x80\x76\xe0\x23\x14\x96\xdf\x32\xef\xf5\xb1\xed\xd3\x2b\x37\xb6\x6a\x94\x4c\x46\xb0\x09\x03\xdf\x02\xee\xde\x89\x82\xeb\x5e\xad\xc4\xd3\x5c\xb4\x5c\x51\x32\x58\xad\xf8\x01\x34\x4b\xb2\xa3\x72\xae\xa2\x14\xc6\xc0\x01\xd5\x68\x09\xa5\x23\x97\xec\xd9\x20\xb6\x8d\x04\xb9\x6b\xf0\xbd\xe1\x9c\x63\x26\x99\xc7\x0a\x7a\xef\xa7\x9a\x91\x0e\xb3\x79\x88\x31\xc2\xc7\x02\xbe\x10\x84\xb0\xd3\xaa\x45\x24\x67\x84\x17\x23\x0e\xb2\xdd\x54\xf2\xac\x6c\xa6\xb6\xca\x34\x42\xf3\xad\x90\x53\x70\x02\x9a\x72\x6d\xe3\x55\xba\x4a\x3a\xa7\x41\xac\x14\x40\x72\xd9\x67\x43\xc3\x09\x50\x94\xd4\x01\x44\x29\xd7\xd5\x94\xc9\xfd\xd2\x39\xae\x44\x96\x20\x3c\x1c\xb3\x3a\xa1\xf1\x06\x22\x53\x15\x33\xc8\x69\x67\xab\x62\xc8\xfa\x4b\x99\x96\x82\x81\x60\xf5\xd6\x3a\xe2\xac\xa7\xf9\x74\xef\x96\xd7\x8f\xb8\x84\x37\xdb\x32\xd0\xc5\x95\x38\xc2\xde\xc0\x09\x4b\x1d\x2a\xb7\x10\x66\xf0\x96\x3c\x16\x9e\x25\x78\x42\x55\xc6\x84\x4b\x94\xd3\x0e\xd0\x80\x5a\x14\x86\xcb\xf6\x74\x52\x5d\xc9\xb0\xee\xfd\x0e\xd4\xd6\x75\x6c\x18\xc0\x19\x96\x2b\xb5\x4c\x9d\x71\x33\x59\x32\xd8\x12\xfa\xb0\x4d\x75\x14\x60\x71\xe0\x60\xf2\x63\x94\xb3\x61\x28\xa0\x75\x08\x4c\x93\xe3\x4f\x84\x9d\x80\x3b\xa1\x80\xba\x3e\x8a\xb4\x3b\xdf\x63\x79\xcc\x55\x96\x1c\x71\x89\x19\x86\xd7\xf5\x70\x2f\x4d\x42\xed\xd5\x7b\x92\x65\x80\x14\xad\x78\xa5\xd6\xe0\x3c\x1d\xae\xd2\x67\x71\xda\xea\x9d\x54\x24\x1b\x17\x94\x34\x10\xc1\x17\xf2\xa6\x84\xe6\x90\x58\xb0\x00\x9a\xae\x62\x4d\x2b\x6c\x8d\x08\x06\x79\x07\x23\xd2\xa2\x89\xf4\x84\x93\xc9\xed\xe6\x01\xd7\xdb\xed\x15\xf4\x14\xf6\xb3\x5d\x6b\x3e\x01\x58\x0d\x34\x9c\xe4\xfd\xb7\x78\xe1\xac\x18\xdd\xf6\xb0\x1d\x8c\xef\xcf\x72\x72\x57\x18\x56\x5b\x6d\xcd\x78\xb5\x90\x59\x5b\x61\xb1\x0a\x3b\xa5\xda\x89\xd6\x3a\x21\x59\x2b\x01\x6b\x01\xd7\xb2\xfa\xd9\xd9\xef\x1a\x67\x53\x3a\x5b\x08\xea\xe8\x12\x80\x49\xf5\x8a\x1a\xeb\x18\x34\xaf\x41\xcf\xec\x5f\x2c\x79\xed\x61\x6c\x61\x8b\x13\x3e\x1e\x74\x78\x7e\xd4\xe7\x98\x1f\x99\x94\x37\x46\x9d\x17\x98\xcc\xfb\xf2\xf9\x48\x30\xde\xdb\x5d\xf7\x5e\x8e\x53\x10\x86\x52\x86\xd3\x37\x65\x94\x93\x4f\x3b\xe7\x54\xeb\x24\x10\x21\xf2\x24\x1c\xf8\x4c\x3b\xca\x7a\xc2\x22\x2f\xa6\x49\x9e\xf8\x45\xc5\x87\x6d\xf3\x5a\x57\x1b\x2a\x23\xd0\x66\xeb\xd6\x8a\x0a\xa6\x6a\x5c\x5a\xd8\xf4\x40\x97\xa8\x5b\x00\xde\x72\x75\x4e\xd5\x1b\x02\xa4\x34\x5f\x67\xdd\x49\x4a\x1d\xc3\x58\x7c\x5c\xde\x91\x2b\xf1\xc3\x3d\x95\xea\x6f\x80\x7a\x26\xc0\xa9\xdb\x5c\x5d\xf2\xba\x73\x2c\x99\x3d\x00\xee\x17\x44\x05\x16\xe9\xd7\x58\xdd\x63\xd4\x3d\xec\x1d\x8e\x3d\x0f\x4f\x11\x1a\xe8\x86\x51\x26\x86\x22\x79\x72\x97\xc8\xee\x45\x14\x54\x1c\xd6\x43\xd6\x75\x79\xfd\x5a\x9b\x67\xa3\xbe\xe1\x0f\x89\xee\x54\xb0\x05\xee\x55\xe6\x82\xd3\xc0\xea\x9b\x2b\x07\x2b\xb0\x01\xde\xa9\xce\xd5\x7f\x6c\x47\xd7\x01\xeb\xe0\xd2\x1c\x26\x01\xc9\xe9\x99\x7c\x46\xa7\xbf\x25\x79\x81\x2a\xdd\x63\x87\x0f\x86\x30\xd9\x8c\x26\x7e\x19\x9d\x58\x21\x5a\x7b\xb0\x9e\x01\xec\xc7\xbd\xb0\x83\xc7\x39\xad\xe0\x9e\x09\xb6\x76\x7a\x9d\x91\x4f\xc9\xe7\xec\xfb\xa6\x2b\x69\x25\xda\x0c\x6e\x8e\x3a\xfa\x92\xac\x24\xad\xd5\xc0\x75\xe6\x11\x5a\xdb\x28\xa3\xa1\xc2\x1e\xf5\xdf\x76\xb6\xdd\xb0\x74\xa3\xef\xa1\x6c\x71\x1f\xab\xd4\x59\xba\xd4\x6c\x57\xc7\xf1\x3b\x3b\x1c\x83\xa0\xed\xf6\xd6\x7e\xb9\xb6\x76\xa6\xc0\x43\x8d\x90\x74\x69\xb9\xab\x59\x92\x2e\xb1\xe5\xfe\x80\x2c\x7d\xcb\xc6\x5a\x46\xa1\x3a\x6c\x08\x28\x8e\xe6\x0c\x0e\xaa\xf2\x8a\xb9\xa0\x88\xf8\xe8\x90\x4c\xf5\xa2\x44\xb0\xa1\xec\xa4\xf5\x80\x36\xb0\x46\xf1\xc0\x6b\xa6\x9c\x2e\xab\xb9\x19\x2c\xb2\xd7\x11\xd0\xbe\xe6\x2c\xcf\xa8\x56\xdd\xb8\x13\x20\x08\x6c\xae\x06\x50\x57\x6d\x75\x72\x02\x5e\xa5\x82\x04\x87\x8f\x42\xbb\xb5\x6c\x46\xcc\x6e\x39\xe7\xd9\x4b\x64\x10\x53\x72\x5c\x9a\xca\xe8\x3d\x16\x43\x57\xda\x89\x69\x53\xcf\x46\x36\x0c\x2a\x60\x98\xa8\x9b\x91\x87\x7b\x19\x14\x5a\xb6\x5c\xa2\x58\xde\x8f\x2b\xe8\xef\x59\xac\x5d\xc6\x49\x2d\x0f\x4c\x07\xb0\xf5\x85\x42\x33\x6f\x85\xab\xb3\x3b\xd0\xa4\x1c\x3a\x9f\x2b\xe8\xdc\xab\x73\xb1\xbf\xd6\x53\x7b\x8f\x93\x79\xe7\x99\x25\xfc\xd5\x5a\x42\xa6\x90\x6b\x39\x6a\xdb\x44\x2a\xd2\x3b\x00\xaa\x59\xdb\x39\x03\x28\xcb\x86\xa6\x78\x5c\xcb\x72\x33\xa5\x3c\xdc\xe7\x2a\xd7\x6f\x66\xff\xe6\xd9\xb0\x0e\xa9\xf4\xb7\xbe\x59\xec\x9b\x37\xc7\xb4\x28\x8f\xa9\xaa\xc0\x29\x96\xc2\x48\x7c\xc4\x0c\x38\x1e\x15\xa3\x30\xcb\xfd\x46\x2a\x57\x9f\xf1\xea\xd3\xdf\xd5\x6f\x6d\x7d\x74\xfb\x19\xaf\x7f\x92\xdc\xdf\x93\xe4\x96\xa4\x3a\x96\x8e\xd2\xca\x85\x06\xed\x08\xd1\x9d\xc4\x37\xa7\x21\x29\xc0\xb6\x78\x19\x9c\xca\x3b\x5e\x5d\x8b\x1c\xe5\x65\xa9\xde\xb6\x7c\xb3\xcd\x9a\x79\x08\x9a\xba\x20\x34\xbf\xa1\xee\x94\x85\x2f\xb1\x54\x4f\x77\x51\xa6\x87\x70\x9f\x73\x0d\x95\xfa\xa5\x54\x2b\x93\xf0\x26\x38\xd6\x4e\x16\x5d\xc1\xd8\x30\x83\x68\x98\x65\xa4\x41\x05\x55\xf5\xcf\xec\xa8\x2f\x16\xdd\xba\x4a\x56\x92\x02\x6f\xad\xb4\xec\x2e\x5d\xb9\xc5\x99\xf7\xa7\x3f\xfb\xed\xaf\xd2\xf9\x5d\x15\x6d\xa0\x61\x53\x57\x22\x9f\x48\xd9\xea\xa8\x9b\x51\x83\x73\xfa\xe6\xd5\x92\x06\x39\x39\xe4\x90\x11\x9b\x30\xa7\x02\x31\x1d\xdd\x61\x43\x2c\x01\xa8\x2e\xf6\xea\xfb\x89\x4b\xff\x30\x3e\xba\x3f\x5e\x9f\x82\xcb\x85\xc3\x50\x5d\x0a\xed\x66\x63\xb0\xa7\x10\xe5\x87\xfb\x4c\x1d\x7d\x55\xb0\x34\x15\x15\x35\x63\x95\x7b\x4b\x59\x62\xd8\x7c\xf3\xe4\x30\x21\xb3\xf8\x62\x37\x7b\xce\x43\x85\x06\x5d\x77\x72\x41\x70\x06\x3f\x6a\x07\xdb\x3c\xe3\x87\xe8\xf4\xb8\x09\xaa\xd4\x89\x5c\x01\xf2\xd6\x43\xad\x15\x24\x04\x22\xf9\x10\xce\x17\x26\x39\x90\xd0\x16\xe0\xf2\x46\xba\x44\x5c\x09\x90\xb2\x24\x07\x2e\x44\xf2\xc3\x7d\x4f\x41\xe4\xa0\xc1\x97\x0e\xb1\x32\x90\x59\xba\xed\x67\xff\x6a\x05\x8c\x69\x20\x5e\x93\x54\xed\x8d\x8e\x04\x8f\xe1\xc7\x39\x19\xa8\xf3\x6c\xca\xe0\x49\x8e\x61\x6c\xda\xe8\x78\x0c\x87\x29\x9f\x2d\x53\x32\x9d\x5c\xbf\x62\x79\xac\x9a\x8d\xfa\xd9\xab\x88\xcc\xe4\xed\x48\x12\x22\xa6\xdc\x1c\xe3\x59\x9c\xc9\x55\xee\x4e\x24\xaa\xd1\x70\x31\x70\x19\x15\xd4\x83\x06\xde\x0b\x75\x92\xe5\x84\x8d\xa1\xd7\x7b\xd4\x1d\x11\x54\x6e\x95\xe9\x20\x1e\xea\x8c\xa9\x3f\xab\x8b\x2d\x75\xa2\xe4\x9f\xeb\x56\x72\xc8\x14\x76\x64\x41\xbc\xc0\xd7\x6a\x26\x9d\xa8\xc8\x92\x13\x56\x04\x66\xf9\x04\x04\x25\xad\x6e\xc1\x96\xb6\x3f\xc2\xda\x99\x24\xad\x46\x58\x6b\xb1\xe0\xe1\xdd\x6b\xf0\x1f\x7c\xb3\x58\x5e\x57\x60\x85\x7d\xa9\xd5\x50\x47\x06\x7d\x09\xb5\x64\xc4\x89\xe8\x1f\xef\x64\x65\x0b\x71\xe7\x18\x1c\xf6\xc4\x8c\xb1\x71\xc1\x0c\xa4\xe1\x02\xbc\x59\x31\xf6\x68\x38\x89\x53\xda\xd9\xed\x60\xa5\xc5\x8c\xca\xa1\x2f\x1a\xed\x8b\x03\x50\xcc\x2c\x5b\x1d\x8e\xa3\x39\x1e\x7a\xb4\x0e\x6a\x1d\x6d\x18\x05\x5e\x66\xf6\x15\xe7\xb3\xd0\x84\x2e\x30\x9a\x06\xc8\x08\xd4\xe4\xe0\x62\x78\x2e\xf5\xc7\xdb\x02\xe2\x0e\x3f\x9a\xea\xa7\x57\xcf\x3c\x05\x03\x8b\x8a\x97\x83\x40\x27\x19\xb7\x11\x09\xed\x68\x21\x57\x4a\x90\xa4\x4e\x6f\x71\xd6\x1b\x6f\xe8\x34\xbc\x5d\x37\xfc\x62\xcb\x8d\xb5\x3a\x57\x01\xa7\x7b\x54\x6c\x11\xed\xd5\x2a\xe6\x6c\xd5\x7f\x77\xf6\x63\xb2\xbd\xb7\xc3\xe7\x27\x64\x1e\xb9\xbb\xd1\x23\x8e\x3a\x30\x2f\xdf\xe0\x55\x79\x91\x69\xb9\x3c\x3f\xfb\x67\x39\xc3\x64\xaa\x2b\x0d\x05\xae\x1d\x35\xab\xc9\x5a\x66\xa3\x91\x48\xb9\x01\x95\xd1\xcd\x90\xcf\xb0\x97\xba\x96\x5c\x37\xaa\x12\x44\xf4\xdf\x0a\x58\xf0\x16\x41\xaa\xc8\xfd\x99\x87\xac\x90\x1e\x10\x36\x04\x2b\x77\x04\xf2\x3c\x9b\x9e\x15\xf0\x6d\xc2\x6f\x94\xd9\xd0\xd4\x4a\x42\xa9\xe1\x4a\xf7\x5f\x1d\x58\x52\x1c\x31\x19\xea\x38\x0a\xf5\x0b\xd3\x38\x62\xb1\x92\xb9\xda\x3d\xd2\xa9\x42\x59\xbc\x6a\x00\x70\x5d\x69\x56\x56\x9f\xd5\xfb\x55\xe3\x30\x70\x9a\xc0\x3e\x7a\x31\x51\x5b\xfd\x5e\x01\x46\x2a\x45\x2e\x6a\x3e\xc5\x6a\x55\x82\x83\xd1\x11\x68\xf0\x8e\xc0\x07\x57\x57\x71\x28\x9a\x17\x34\xcb\x4e\xbc\x51\xc2\x06\xc8\x3b\x0a\xff\x91\x69\x00\x41\x96\x5e\x81\x95\x23\x59\xf1\xbf\x6f\x38\x40\x17\xab\x1d\xe0\xe2\x4d\xa3\x52\x36\xc9\x64\xca\x83\xcf\x36\xa5\xdd\x53\x83\x16\xa4\x2e\x47\x14\xc0\x06\xe8\xb6\x3b\xfd\xab\xfa\xe9\x23\x3a\x1a\xeb\x34\xde\x00\xfb\x05\x2e\x70\xf6\xaa\xc2\x75\x82\x26\xa6\x4d\xce\x8c\x30\xc1\x45\x48\x75\x6c\x01\x26\x3d\xc9\x41\x02\x5c\x8b\xaa\x6b\xb1\x72\xdc\x72\xb4\x91\xc0\x67\x8f\x2a\x1e\x59\x74\xbd\x94\x9a\x65\x5d\x2c\xe9\xe4\xdd\xda\x0c\xf6\xf5\xbc\xb4\x69\x67\x1e\x36\x85\xda\xd9\x1b\xa0\x88\x75\x70\x10\xc4\x28\x8b\x67\xd7\xbd\x73\xef\x99\xe7\x48\xa7\x9d\x63\x79\x58\x6b\x8d\x16\x73\x5d\x9d\x16\x8c\xe8\x3d\x85\x47\x1c\x21\xae\x19\xd1\x8f\x62\x35\xe9\x74\x69\xea\xbd\xe4\xd1\x5c\x25\x7a\x15\x97\xa5\x63\xbd\x17\x89\x47\x4c\x89\xb1\x73\x6f\xbf\xd2\x8a\x26\xf1\x80\x7f\x51\xb6\x06\xe4\xf2\x2e\xce\x48\x50\x3d\x82\x82\x26\x9c\xd5\x5b\xa9\x90\xac\xfa\xd3\x05\x8d\xcf\x29\x80\x63\x3b\xb0\x01\x4f\x99\x01\x81\x23\xba\x44\x4a\x69\x63\xf5\x9c\xf9\x42\x35\x6f\xc8\x0f\xc9\xde\xba\xd5\xff\x0f\xe4\xa2\x55\xe9\x8d\x71\xc6\x0b\xab\xd9\x76\x2b\x2e\x5f\xfa\x44\x22\x62\x05\x73\x8c\x26\xa3\xee\xb1\x3a\x24\x32\x9d\x1d\x1b\xac\x70\xbe\x3d\x6b\x2c\x9c\xd1\x9b\x01\xc6\x8d\xb6\xf1\xa0\x40\x95\x2f\x20\x9e\x6f\x20\xab\x26\x3d\x59\x6a\x53\xa2\xbe\xfd\x99\xbd\x7b\xfa\xcb\xd2\x82\xa4\x76\x50\xab\x97\x86\x30\x7e\xab\x97\xd8\x8a\x9a\xea\x2d\x87\x01\x49\xd2\x3b\xc2\xb4\xc1\xf0\xa6\x2d\x7b\xf8\xc2\x4b\xfc\x93\x63\x68\x81\xd7\x86\x2b\x68\x6f\xa3\x9a\xdd\x79\x35\x9a\x18\xfc\x3d\x12\x0d\x2b\x1e\x8f\x06\xeb\x00\xd5\x33\x3f\xaa\x03\x71\xa1\xba\xfa\x18\x1b\x10\x0a\x6d\x9b\xbc\x36\xea\x9a\x25\xe7\xee\xe6\x97\x9e\xbf\x56\xad\x57\xac\xa1\x2b\xed\x50\x78\xb4\xb4\x53\x18\x68\x64\x0f\xf2\xc1\x64\x2d\xe3\x02\xb8\x7d\x2a\x4d\x59\x65\xd5\xd9\x10\x80\xb9\x2d\x2a\x43\xb5\x14\xda\xc4\xe0\xaa\x77\x1c\xea\xe2\x21\x53\xbd\x46\x05\xc7\xca\xd4\x18\xd6\x62\x55\xe3\xc8\xe3\x40\xf6\x5d\x59\xc6\x8d\x57\xac\x99\x8b\xd1\x4e\x33\xd6\xbb\x24\xdf\x5e\xac\xc7\x9e\xb1\xba\x0c\xea\xc1\xc2\x81\x65\xa0\x6a\x05\x5e\xae\x3a\xb9\xea\xf5\xaa\xd1\x78\xc4\xda\xb6\x28\xe8\x9e\x81\xa2\xd7\xfa\xce\x17\xd9\xbf\x48\xfe\xc5\xfa\xd4\x17\x6f\x8e\x68\xf9\xc5\xe8\x30\xd0\x36\xc6\x39\x1a\x17\x62\x95\xe8\x02\x70\x6c\x39\x72\x49\xd6\x62\x22\xaa\x73\x6e\xd9\xb8\x37\xda\x6e\xf7\xb7\xdb\x6e\xdf\xe7\xd2\x42\x3f\x06\x6f\xa2\x96\x04\xe5\x0b\xf1\x38\xa2\xb4\x71\x19\x0d\x24\xc2\x97\x88\x8b\x42\xa0\x8c\x3b\x70\xc1\xad\x3f\xdc\x57\x69\x6a\x3a\x5c\x28\x81\x2d\xf3\xf6\xd0\x5f\x7d\xf7\xa1\x8f\xf4\xbb\x47\x5e\x92\x5a\xe1\x75\x2f\x29\xb4\x81\xaa\x4d\x6f\xfb\x52\x4d\x7e\xef\x30\x21\x01\xb4\x6a\xce\x3b\x92\x2b\xda\xd2\x56\x2b\x58\xbb\x73\x12\x4f\x48\x13\x30\x44\x47\x50\x22\x8c\x85\x03\xb3\x1a\x2a\x64\x88\x78\x05\x8e\x0c\x89\x0d\x94\x0b\x9d\xc5\xe4\xcd\xae\x2e\xcc\x79\x27\x09\x12\xd8\xca\x85\x01\x81\x54\x99\xe3\xc9\xba\x92\xfa\x41\x09\x9d\x89\xf3\x40\xc3\x71\xeb\xe0\x81\xc1\xab\x76\xd9\x41\xb6\x6a\xf9\x6b\x6b\x43\xc5\x96\x6c\xe6\xac\xba\xc2\xbc\x71\xd5\x26\xde\xc4\xd7\x59\x32\xeb\x62\x27\x5c\xb9\x68\x2f\xab\x1d\xab\x0d\x4f\x11\xc0\xf8\xd1\x5e\x19\xf8\x33\xd4\x99\x3c\xe3\x70\xbe\x3e\xd7\xac\xf7\xb2\xd9\xe4\x8e\x1d\xa1\x31\xf1\x14\x1e\x9f\xf6\x85\xb5\xea\x85\x3d\x8e\x08\xea\x58\x8e\xca\xf0\xf8\x3b\x5c\x54\x3b\x8b\xd5\x5a\x2b\x22\xb7\x32\x79\x04\x58\x39\x16\x62\x3a\xb3\x55\xd6\x26\x06\xb0\x89\x33\x8e\xb5\x1a\xfd\x47\x9e\xab\x1f\xd3\x5d\x39\xc0\x30\x36\x74\xe9\xe4\xec\x50\x64\xfa\xc6\xbb\xc5\x24\x23\x38\x22\xbb\x61\xb7\xe6\xac\x18\xbf\x33\xf2\x97\xb7\x66\xce\x8b\x2f\x52\x58\x41\xb5\xda\xc1\x1a\x42\x89\xf7\x42\xa1\x32\x38\xd3\xd1\x7a\x41\x8f\x32\xa2\x8b\x80\x81\x8d\x13\x4a\xbe\xd8\x5a\x78\xb1\xad\xb3\xf9\x3c\x78\xaf\xdd\xdb\x2a\x7b\xbf\xdb\x55\xf2\x24\x57\xc7\xd9\x93\x0f\x96\xce\x62\xcb\xa3\x31\x07\x75\xec\x8c\x35\x6e\x78\xdf\xfa\x84\x36\xc2\xb0\xbc\x7b\x5e\x54\x37\xd5\xcb\xbe\xae\x3d\x1b\xbd\x4a\xf9\x5a\x17\xd0\xbc\xa1\x20\x85\xd1\x2c\x12\xf6\xf8\xac\x85\x1b\x62\x62\xbc\xb7\x98\x18\xdf\x4e\x4c\xac\xf8\x08\x4a\xed\x50\x60\x56\x01\x62\x40\x3f\xd9\x11\x46\xb2\x62\x40\x8b\xde\xa2\x1d\x96\x4e\x02\x4b\xd0\xc5\xad\x96\x65\xe3\x14\x32\xcd\xbe\x90\x8a\x96\xcd\x3f\x88\xe8\xa2\x96\x5f\xb4\xee\x82\xc0\xd9\x8b\x4d\xe2\xf2\xc5\x2c\x21\xe8\x01\x79\x71\x74\x07\x6c\x54\x34\x51\xc6\xff\x1c\xf9\x67\xce\xf2\x5d\xb9\x66\x2e\x5b\x58\x4d\x3b\xbd\xea\xbf\xd4\x2b\xf1\x46\xb7\x02\xdf\xbc\x4b\xf3\xaa\xc6\x3c\x6b\x43\x7d\x1a\x32\xcb\xa8\xb9\x3b\xf9\x96\x1d\x8c\x08\x04\x5d\x05\x59\x0b\x80\x87\xd6\x75\x77\x0c\x63\x34\x76\xcf\x3e\x5f\x8b\xfe\xad\xdb\x73\x37\x35\x6d\x85\xab\x1e\x89\x1b\xcb\x60\xf0\x53\x45\xd7\xb2\x67\xb0\x29\x3f\xdc\x0b\xb0\x23\x28\x74\xf2\x56\x60\xbc\xf8\x08\x16\x4c\x52\xd2\x32\x53\xad\xe1\x04\x4d\x6f\x9b\x28\xd7\xaa\x28\xb7\x46\xf9\xdd\x3e\x79\xa7\x9d\xf9\x56\xa7\xbc\xb0\x5a\xe5\x41\xaa\x22\x92\x8e\xfe\xff\x86\x40\x0a\x56\x64\x6a\x65\x7d\xe8\x52\x9f\xcc\x4a\xbd\x8d\x3b\xf8\x3c\x7d\xfa\x31\x1a\x36\xa5\x90\x1e\xee\xb9\xf5\x40\xb9\xf6\xcd\x7a\xcb\xc8\x26\x88\x31\x08\x6d\xd6\xf3\x2a\xd1\x77\xe9\xec\xa4\x83\xa3\x8f\x37\x38\x51\xbf\x35\xe7\xb4\x89\x4a\x63\xa1\x0d\xf4\x03\xa8\x1a\x11\xe0\x02\x50\x7a\xfb\x9d\x46\xc7\x1f\x6f\x74\x34\x5a\xa0\x4c\x6d\x63\x75\xce\x98\x2e\x55\x36\x06\x23\x39\x35\xa3\x3f\x50\xe1\xa2\x0e\x36\x09\x2c\x23\x7a\xaf\x11\xcb\x47\x1c\x71\xad\xba\xd8\x19\xac\x46\x9c\x4a\xd0\xe1\x72\xf2\xf2\x2e\x4f\x15\xd1\x5c\xdd\xb3\x76\x73\x49\x9a\x97\x16\x79\xd1\x27\x64\x33\x42\xf9\x1e\x51\x5d\x80\x17\x00\xf7\xd9\x13\x39\xdc\x4e\x1b\x37\xe7\x8d\x88\x9d\xa8\x0b\xfd\x48\xd9\x11\xb3\xc6\x5b\xee\x9a\xfb\xee\x2c\x50\x54\x75\x61\x7f\x85\x4e\x3c\x5b\xff\x81\xec\x10\xbd\xdf\x81\x0c\xed\xae\xe1\x54\xcf\x33\x7e\xd4\x98\x92\xd4\xd5\x92\xf4\xa8\xfc\xf1\x8c\xcc\xe8\xe2\x0c\xef\x39\xfc\x5d\x96\x20\x7f\xcc\x25\xc8\x81\x0a\x6a\x40\x1e\x81\x14\x16\x44\xe1\x31\x40\xc1\xf0\xe0\xd7\x72\x2e\xd0\x07\x25\x04\xe8\x70\xb7\xc5\x44\x2d\x7a\xf2\x08\x9d\x40\x6f\x60\x13\xea\x22\x8b\xb9\x7b\x0a\x99\xe0\x39\xfe\x47\x98\x84\x5b\xa7\x3d\xdc\x97\x4c\xe7\xc0\xaf\x40\x85\x37\x60\x0a\x6b\xe0\xec\xd4\x80\x36\xec\xb7\x5b\xb5\x64\x41\x01\x94\xa5\x09\x4f\x80\x02\x39\x2c\x92\xce\x44\x64\x7f\x07\x4e\xf1\x08\xd6\xf3\xc6\xa0\x6f\x94\x65\xe9\xca\x95\xc7\x2b\x47\xba\x72\xb5\x1a\x6a\x14\xf5\x85\x68\x53\x04\xf0\x68\xce\xbe\x7b\x8a\x39\x4e\x60\x43\xcc\xac\xbb\x1f\xfa\xd3\xba\x14\x5a\x0a\xc2\x6e\xef\xba\x1d\xf7\xac\xd6\x94\x35\x59\x9c\x66\x53\x65\x30\x4c\x99\xbf\xee\xc6\xb7\x5b\x31\xb2\xf2\xe8\xd1\x7a\x66\xd9\x7c\x98\xe2\xc8\xde\xa7\xd7\x68\x07\xb6\x8c\x0e\xd5\x5c\xdf\xb3\xf3\x1e\xa5\x87\x70\x8f\x9d\x9a\xeb\x42\x1d\x81\x14\xcd\xc6\xc6\x6c\xf0\x97\x5c\xf5\xb0\xd0\x08\x05\x0d\xdf\xf1\xee\xd9\xbb\xa8\xe1\xc8\x65\x4b\xdd\x46\x23\x54\xbb\x3d\xcd\x2b\x60\x15\x73\x48\x9b\x0c\x31\xf0\x5f\xe5\xe6\x8d\xb0\x84\xf9\x88\x42\xed\xc2\x8d\xbc\xc7\x16\xae\xa4\xd6\x8b\x50\xf7\x1e\x5b\x45\xe8\x10\x06\x67\x77\xde\x40\x6b\x80\xff\x62\xd6\x5d\x59\x7a\x28\xb0\xc7\xd4\x87\xba\x9d\x7e\xfa\x7c\x85\xa4\x7e\xea\x54\xf7\xe1\x9d\xea\x40\xa5\x88\xc8\xa8\x53\x8a\xd4\x93\x9c\x04\x78\x04\x50\x9f\xfc\xfe\x23\x57\xcf\x87\xe0\xc2\x7b\xc7\xe0\x08\xcc\xcd\x60\x3f\x40\xa9\x4b\x75\x3b\xd5\x48\xea\x48\x65\xc3\x48\x4e\x55\xbb\xba\xdb\x3c\x63\x95\x9d\x38\xb4\x0f\xeb\x32\x67\xdf\xff\x56\x96\xd9\xcd\xa1\x8c\x8f\x3b\x14\xd1\x59\xfb\x1d\x76\xd8\xcd\xb1\xbc\xfc\xc8\xd3\x42\xf9\xbd\xac\xae\x9b\xe3\xfb\xd5\xc7\x1d\x1f\xe9\x66\xfd\x41\x2b\xf8\x52\x04\x23\x0c\x3f\x2e\x55\x7e\x22\x66\x3e\xa0\x2b\x9d\x7d\xf9\xc3\xce\xd6\xab\x8f\x38\x8e\x0f\x3a\x58\xaf\x3f\xe2\x40\xac\xd1\xc9\x47\x3c\x55\x5f\x7c\xcc\xc1\xb5\xf4\x43\x3f\x52\xb9\xbd\x6d\x1c\x87\x1f\xfe\x91\x7a\x95\x1e\x81\xbf\x7a\x3a\x74\xe2\x7b\x3a\x4a\xea\x3f\x84\x6e\xb1\x07\xb8\xe1\x7a\xfa\x3d\x76\x8d\x0d\xd6\x36\x56\x0d\x53\x32\x26\xe3\x7e\x89\xb8\xca\xcf\x14\xa6\xbe\x5a\x11\x8e\x3f\x44\xbb\x40\xfc\x88\x6b\x95\xef\xd3\x73\x0f\xef\xe3\xba\xff\x1e\x3c\xf7\x9b\x8b\xc2\xd7\xca\x23\xdd\x32\xff\xd4\x3a\x29\x86\x1f\x5c\xeb\xb9\x0f\x51\xb2\xaf\xe4\xa7\xd5\xfc\x81\xad\xe6\x87\x98\x2a\xaf\xf2\x1f\xeb\x72\xd2\xf8\x9d\x66\x53\x78\x32\x06\xfc\x47\xd5\x50\x52\x97\xb8\xfc\x91\x2e\xf1\xb7\xd3\xbc\xe1\x07\x16\x34\xff\x7d\xc4\xcc\x9f\xde\xb2\xe1\x47\xbc\x67\xeb\x1f\xf3\x9e\xfd\x36\x0e\x53\xf8\xde\x3c\xa6\xef\x57\xfe\x85\x0f\x50\x84\x2b\x7c\xf2\xa3\x8a\x9e\xbc\x6a\x8f\xca\xd8\x72\xe6\x8d\xa5\x07\xce\x75\x43\x2b\x3b\x2e\xd6\xf3\x92\x72\x41\x1f\xc8\xc8\xb8\xc8\x81\xb3\x78\xa6\x1e\xbc\x99\xd9\x19\xee\xc0\xf5\xc6\xe8\xaf\x0e\x70\x5b\x1e\xd7\xe7\xa8\x7b\xaf\x0f\x78\x66\x2c\xfd\xd3\xf7\x69\x2d\x6d\x45\xe3\x94\x4e\xf8\x89\x9f\x34\x9d\xd7\x0d\xa6\x66\xdf\xa8\xab\xb4\x42\xa5\x1c\x7a\x10\xf5\x3d\x0f\x20\x0b\x9c\x35\x76\xac\xb9\x3f\xbb\xc8\xbd\xff\xb1\x9c\x1e\x9e\xb7\xd8\xfe\x58\xb4\xe0\x68\x84\x17\xa9\xe8\x20\x7a\x0a\x23\x83\x2d\x82\x49\xc2\xae\xde\xe8\x30\x86\x68\x7d\x43\x5d\x3b\xae\xf9\x8d\xb3\x50\x4b\xa8\xd6\x69\x99\x8c\x6f\x0f\xc8\xbb\xca\x63\x47\xe1\x7d\x31\x06\x8f\x5c\xbe\xfb\xb6\xcd\x30\xc2\xc7\xee\x6f\x8c\xd2\xa0\x8e\x86\x5d\xe3\xbb\x9d\x2d\x54\x70\x81\x71\xcb\xda\x77\xf5\x67\x56\x7a\xc5\xa1\x1b\x9c\xd8\x9f\x9a\xdb\x7a\x73\x5b\x74\xb1\x79\x5f\xd7\xe8\xe5\x4f\x73\xfa\xe4\x9c\x7e\x90\x83\xf2\xab\x9f\x26\xf5\xe9\x8d\xfa\x2d\x1c\x9c\xef\x12\x17\x7e\xf5\xf9\x4f\x13\xfd\xe4\x44\xa3\x62\xee\x87\x1d\xe3\x7e\x14\x85\x7f\x3f\xbb\x27\x7c\x1f\x86\xcf\x99\xae\xe9\x88\xa3\xbe\x6f\xeb\xeb\x0f\x13\x2f\xd7\x2a\x6b\x3e\x43\xc6\x25\xbd\x15\x21\xbe\xb9\xcf\x7d\x97\xdb\x1e\xa7\xdc\x2e\x60\x17\x26\xa4\xef\xc7\xb2\x29\xbd\x51\x7e\x17\xef\x31\xcc\x73\xb5\xbe\xb7\xc2\x05\x80\x33\xad\x65\x6b\x59\x67\xc3\xf3\xed\xd6\x66\x78\x38\xf9\x28\xe8\x97\x8f\xc8\xc3\x1a\xd7\x3f\xdc\x8b\xd4\x90\x07\x5f\x68\xf0\x8e\xd6\x00\x83\x0c\xf5\x0d\x4c\xa7\xa0\x58\xd0\xf8\x42\x8d\xd9\x72\x4f\x01\xe5\x83\x6c\x54\x08\x8e\x63\x36\x02\x7d\x38\xa2\x77\xab\xf3\x86\x61\x9f\xe9\x56\x73\x44\x9d\xb9\x2f\xae\x85\xac\xe9\xe8\x28\x0a\x22\xae\x56\xc6\xc5\x9c\x8d\xe1\xcb\x1a\xf0\x5a\x5f\x44\x4a\x32\xa9\x8e\xb3\x5d\x25\xca\x46\x9c\x67\x09\x54\x36\xfd\x51\x13\x0e\xce\xd3\x6b\x44\x16\xd1\x69\x76\x9e\xdb\x66\x27\xc0\xba\x36\x7b\x4b\x13\x74\x40\x30\x80\xa7\x3e\x1a\xf0\x03\x0a\x60\xa9\x28\xce\xd7\xd6\xad\xa5\x17\x4c\xb7\x69\xcd\x6b\xe9\xac\x46\x01\x82\xe2\xda\x52\x60\xd5\x84\x3b\xb6\xb5\x1b\x04\xa4\xb1\xd1\x31\x3c\x62\x5d\x68\xd6\x8b\x19\xa5\x80\xba\x9a\x1b\xa9\xbc\xed\x69\x2f\x68\xac\x89\x46\x91\x7a\xe0\x8d\x3f\xaa\x2e\x9b\xb4\x48\xc8\x64\x8c\x0a\xd5\x2a\x2b\x03\x4a\xe2\x70\x32\x2b\x2a\xf2\xac\xf1\x50\xcf\x6e\x3e\x7a\x99\xa1\xca\xbe\x81\x95\x49\x0c\x6e\x2d\xf0\x05\xcb\xaa\xda\xf2\x8e\x5e\x41\xaa\xf5\x3a\xb2\x87\x53\x18\xb4\x56\x3e\xdd\x19\x67\xbd\x7d\x9c\x74\xd6\xc0\x22\xd3\x74\xa9\x56\x61\x9c\x2a\x0f\x3e\xfb\x0a\x9f\xb7\x47\x2b\xfe\xf1\x0e\x56\x82\x16\xd9\x1d\x2d\xa4\xf8\xb6\x51\xf4\x7a\x65\xb2\x3a\xeb\x29\xff\xa9\xeb\xf7\x1f\xb4\xeb\xf7\x1e\x47\x02\x47\x8c\x15\x30\xc1\x1d\x7a\xbb\xd7\xb7\x77\xd8\xbd\x5b\xdd\xbe\xef\xa5\xd4\x40\xa2\x3e\x9b\xaa\x6b\xca\x9b\xd1\x3c\x4a\xdd\x8c\x5c\xb5\xde\x86\xd0\xbf\xa6\x9f\x56\xfb\x47\xb6\xda\x1f\x52\x81\xfc\x9a\x7f\x5a\xee\x47\xcb\xcd\x28\x95\x96\xb4\xb1\xa8\x5d\xd8\x2e\x55\x2d\x18\x90\xf8\x0c\x1d\xfc\x08\xb1\xf7\x2d\xea\xc8\xa9\xa3\x62\x13\x6c\x4f\xe3\x47\xb1\x51\x6e\xee\x01\xf9\x69\x0f\x3c\xda\x03\x04\x16\x7c\x6a\x9e\x94\xc8\x9e\x94\xc8\x06\x47\xf6\x86\x56\xe6\xf4\xdc\x39\xa7\xe0\xde\x90\x97\x30\xa7\xa9\xaf\xbc\xc4\x30\xae\x97\xe7\xf3\x12\xd6\xc7\x54\xac\x9f\x29\xca\x65\x9c\x01\xf5\xcc\x4d\xd0\x99\x9b\x38\xb3\x10\x25\xa3\xba\x65\x65\x11\xf8\xcc\x4b\x8c\xe0\x66\x95\x5b\x35\xf5\xa4\x05\xf6\xfc\x04\x79\x76\x02\xbf\x1d\xbe\x0b\xa8\xff\x47\xbc\xbf\xf3\x4f\xfb\xfb\xb1\x8c\x4b\xe3\xc7\x47\xe5\xf8\x5d\xb7\x5f\xf8\x3e\x14\x71\xe9\xf5\xc3\xf9\x26\x3f\x84\x6e\x32\x7c\x04\xbe\xc9\xd7\xe5\xa7\xd3\xf2\xf8\xb4\x8c\xf3\xb4\x3c\x5d\xb1\xd2\xac\x5e\x05\xfb\xec\x46\xc5\x8a\xf5\x9d\xb0\x9a\x95\xb3\x64\x54\xaf\xc6\x6a\x64\x5c\x17\xef\x09\xea\x54\xec\x01\x67\x37\x56\x72\x52\x7e\xfb\x29\x5b\x6e\x2b\x16\x08\xbf\x07\xcb\x23\xfc\x7e\x6c\xd4\x8c\xa3\x51\x1e\xd7\xcb\x88\xf3\x37\xa0\x24\x21\x37\x2b\x4d\xa0\xe1\xec\xd9\xab\x64\xa6\xa1\xc2\xe0\x5b\x16\xcb\xbc\x3e\xc9\xa8\x03\xd7\xec\xd4\x2e\x43\x7d\xa1\xd9\x05\x9d\x98\x2c\x2a\xd3\x92\xf7\x08\xe4\x61\x9d\x17\xbc\x03\x89\x2a\x56\xd4\xae\x94\x6b\x96\xbf\x2e\x22\x63\x74\xc7\x6f\xa0\xef\x24\x0e\x94\xf3\x5e\x38\xa8\xc1\x68\x8d\x08\xac\x8b\x27\x0e\x34\xda\xcd\x19\x15\x8b\xd8\xe9\x36\x0e\x50\x3c\xa7\x78\x4f\x2a\xef\x89\x9c\xbd\x35\x23\x67\xeb\x0f\x87\xa4\x50\xf6\x5a\x64\x6f\x71\x68\x5d\xf0\x74\xed\x50\x7f\x4d\x58\xdd\x34\x91\xef\x32\x8e\x17\xf4\x81\x0d\xd3\xa0\x11\x86\x7c\x4c\x69\x8b\xc0\x4d\x52\x3b\x22\xe8\xde\xd4\x66\xd0\xfd\x81\x90\xad\x30\x02\x03\x85\xbc\x6b\x54\x45\xe4\xc2\xbb\x5b\x82\xfd\x72\x71\xb1\xcb\xb0\x63\x55\x17\xc5\xc7\xd9\x80\xd6\xc3\x8f\xd6\x5b\xd9\xaa\x6a\x1e\xb5\x85\xb4\x1c\x22\xe8\xd8\xc0\xe5\x84\xce\x28\x62\xd1\x48\x9f\x84\x15\xb7\xf2\x19\xb6\xb6\xa1\xe3\xca\x2e\x6a\x79\x64\xe7\x4e\xb0\x5a\x97\x32\x16\x43\x1c\xa1\xa3\xd5\x3d\x27\xd1\xc5\x0e\xc6\x83\xa8\x56\x0e\xc4\x22\xb3\x9f\x00\x10\x03\x54\x00\x06\x28\xed\xe8\xfd\x84\xcc\x1e\xde\xda\x18\x52\xf4\xbe\x63\x74\x2b\xca\x11\xe7\x1b\x42\xff\xe3\xee\x44\xed\xed\xee\x8d\xb6\xf1\x95\x1f\xee\x6b\xaa\xa1\xa6\x8e\x86\x1c\xf5\x40\x55\x78\xb6\x7e\xaa\xde\xc5\x92\x53\x40\x47\x02\xf1\xb6\x8b\xd9\x7a\x4d\x9e\xcd\x83\x2c\xdb\xea\xec\xf7\xeb\xec\x1b\x23\x96\xbd\xaa\x17\xb8\xdd\xde\xed\xed\x1a\xc0\x5b\x3d\x96\x5b\x90\xe2\x65\x35\x2a\xb9\x2a\x4d\x72\x9a\xee\xee\x94\xa9\x3a\xe9\x46\x3a\x66\x05\x42\x3c\x8d\xf3\x31\x8a\x73\xda\x7a\x2b\x5d\x3a\x5b\x9a\x66\xdb\x55\xef\x76\x0c\xb1\x7e\x4f\x1e\x6c\x7c\xdc\x35\x44\x45\x48\xf7\xe6\x07\xe8\x3e\x00\x69\x8c\xfe\xa7\x6c\xfd\x4f\xdf\xe8\x7e\x2a\xde\xfd\xb4\xae\xbc\xaa\xf7\xe2\xd2\xc3\x65\x4c\x2c\x76\x72\x50\x32\x85\xee\x3e\xe8\x77\x13\x16\x53\x0d\xe7\x1d\x35\x75\x46\x10\xb7\x8e\x1b\x5b\x4f\x1a\x93\x6d\xc5\xf8\xd3\x1f\x75\x26\x41\xf3\xdb\xb1\xea\xa2\x2c\x34\xa6\x7b\xda\x20\xd8\xac\x6f\x9e\xc1\x99\xf9\x3d\xd7\x60\x3d\x51\x82\x15\xbe\x7d\x0d\x96\xec\x71\x88\xa5\x6c\x5a\x5a\xac\xe4\x2a\x81\x53\xf3\xa6\x71\xa8\x75\x13\xeb\x3f\xf4\x1c\x7b\xd3\xeb\xfe\x4e\x7a\x09\xdc\xc8\x3a\x31\x92\x03\x53\x9e\xc3\x94\x0a\xcd\x47\xf4\xb9\x3d\x9d\xe1\x62\xc3\xbc\x5b\xd5\x3f\x79\x23\xb4\x7e\x6d\x29\x9d\xab\x9d\xd5\xb4\xea\xff\x0b\x5a\xef\xe5\x81\xf8\x7c\x6e\x97\x58\xb9\xed\x1d\xab\x86\xb9\xf7\xde\xf0\x21\x76\x5e\x7c\x19\xdd\xfa\x54\x18\x7b\x3a\xe6\xdc\xa6\xd9\x7a\x86\x1a\xf5\x51\xd5\x6d\x00\xfb\x41\x7d\x2c\x00\xe8\x11\x19\x16\x94\xe4\xe9\x3e\xa7\x64\x14\x77\x38\x0e\x92\x67\xa4\x42\x61\xf4\x30\xe3\xb8\x36\x56\x41\x5b\x9d\xe4\xdd\x67\x28\xa8\x15\x22\x00\x24\x65\xa7\x0e\x0a\xdd\x9a\x01\xf5\xc5\x8a\x6c\xf4\xf3\xf0\x20\xa9\xef\x11\xec\x22\xce\x2e\xea\x40\xb2\x98\xbd\x5c\xb5\xa5\x25\x0a\x06\x7f\x58\x3c\xef\x5d\x98\xc0\x4f\xab\xf6\x87\x59\xb5\x0f\x8a\xcb\xbd\x8b\x44\xf8\x69\xd9\x6c\xd9\xb8\xe4\xf7\x8d\xd1\xfd\x7e\x17\xfc\xe6\x5a\xbe\x0b\x80\xf8\x69\x2d\x6d\x2d\xe9\x91\xc7\xfc\xe3\x89\x45\x7c\xfb\x6d\x14\xde\x4b\x70\x94\x2a\xdf\x6f\x1c\xe1\x63\x84\x11\xce\x92\x52\xb4\xd9\xa7\x9e\x2f\x2c\xe9\x28\xbd\x9b\xaf\xae\x7f\xc8\xb9\x1f\xb1\x35\xbe\x20\x29\xae\x7f\x89\xb5\x3a\xe7\x7f\xd2\x83\x5e\xde\x5b\xeb\xbd\xfa\xe0\x5f\x07\xd3\xc2\xfb\x4a\xef\xd7\x1f\xfe\xf2\xf4\x9e\x52\xee\xe6\x98\xce\xaa\xd1\x3a\x8c\x2c\xe5\x47\x18\x06\x7c\x8f\xf9\x2c\x16\x79\x90\xf0\x63\x3e\x4d\x5f\xa4\xab\x0a\xc9\x68\x73\x48\x89\x83\x19\xed\x23\x83\xb4\xb6\xf2\x04\xa1\x24\xd1\x44\xcf\xfa\x90\x69\xe7\x6c\x3d\x20\x62\x31\xc8\x42\xa4\x45\x29\x06\x02\xf6\x6c\x0d\x23\x79\x57\x9f\x0b\xb1\x88\x76\x96\x71\xb6\xb3\xe5\xe2\x16\x55\xe3\xc6\x46\x5b\xac\xa0\x2e\xdd\xd4\x93\xc8\x02\x89\x26\x08\x27\x04\xeb\x7f\xdc\x42\x95\x8d\x73\x0d\x05\x15\x1c\xea\x05\x76\x59\xee\x64\x33\x66\x16\xec\xe7\x4a\x1b\x80\x12\x45\x7c\xe3\x66\xd9\x07\xf4\x4a\x0f\x94\x87\x7e\x73\xf9\x7b\x82\x31\x19\x3c\xec\x64\x1d\x65\xf7\x1d\xc5\xa3\x1d\x0e\x10\x23\x02\x6b\x87\xad\x54\x02\xf9\x44\xf2\x28\xa1\x65\x58\x22\x81\x9d\x8d\x92\x78\x1f\x5d\x2a\x8b\x57\x0c\x0d\x11\x54\xb6\x97\x90\x8d\x6b\xbe\x76\xa3\xae\x50\x0f\xcc\x7b\xde\x25\x74\x13\x03\x20\xc6\x59\xc5\xe5\xda\xbf\xdf\xe8\x47\x6a\x36\xac\x5b\xe6\x30\x3a\x7a\xba\x83\x15\xad\x93\xf5\x3c\xb4\x61\x60\x6f\x58\x14\x03\x21\x0f\xa3\x8a\x6c\x86\x45\x41\xeb\x95\x14\xa2\x37\xda\x33\x98\x8f\xb5\x2e\xf4\x5e\x56\xea\x2a\x67\x67\x5d\xe7\xdb\xe1\x81\x2f\xe8\x64\x20\x95\x90\x0e\xb4\xb5\x17\x3a\xe2\xe8\x7b\x49\x01\x56\x54\x75\x6a\x16\x31\xbe\xc8\xc5\xc8\x82\xe6\x88\x13\xae\xb6\x73\xd2\x41\xba\xb0\x38\x61\x37\x75\xb6\xc0\x6b\xba\x44\xe6\x7a\x14\x74\x66\xb4\x5d\x1e\x86\xb5\x62\x30\x12\xc1\x2c\x3e\xf3\x2a\xa7\xf8\x0c\x69\x9a\xc7\xdd\x26\x62\x4a\xb9\x3b\x4f\x50\xb4\xb8\x89\xbe\xd7\x40\x4f\x95\x02\xda\x7c\xa1\x07\x7b\x85\x25\xb4\x7e\x77\x6e\x2e\xfc\xf8\x93\x73\x1f\x5e\xb6\xfb\x05\x5f\xe9\x7a\xd2\x83\xfe\xff\x0a\x12\x0d\x23\x3b\xe4\xc4\x73\x8c\xd3\xf2\xac\xeb\xc4\x4f\x6a\x0b\x71\xbf\x0f\x74\x7e\x68\x60\xa3\x99\x76\x7c\x8c\x49\x70\x60\xf2\x4e\x58\x67\x64\xb2\xde\xbc\x76\xb1\x98\x2c\xc7\x3a\x73\x2b\x64\xd8\xfa\x0a\x15\x1b\xd7\x8d\x34\xbd\xa3\x06\x4a\x19\x05\x01\xf8\x8a\x94\xd5\x79\x84\x87\x9e\x47\xf4\x6b\x6c\xd9\xfa\x70\x46\xa0\xf1\x3c\xb0\x6d\xb6\xb2\xd5\xca\x57\x4f\x4b\x44\x96\xb0\x53\x4a\x66\x34\x83\x14\x71\x1a\x9f\xa1\x20\x24\xec\xbd\x72\x02\x49\x5f\xd4\xbf\xc9\x64\x1e\x85\x2a\xd3\x4a\x08\xee\xce\x32\x00\x6b\x11\x64\x31\x1b\xb4\xde\xe7\x2b\x6a\xcd\x5f\xaa\x7a\x00\xf6\x83\x3c\xf5\x2f\xe4\xa7\xe5\xfa\x43\x2f\xd7\x87\xb8\xe8\x5f\xe4\x3f\x82\xf5\x7a\x5f\x5f\x3a\xbc\xef\x52\x7f\x4f\x2b\x7d\x73\x11\xcb\x8f\x7f\x11\x51\x91\xf8\xdd\x00\x2b\xe1\x8f\x5e\x29\xde\xde\x9f\xe1\xc7\xb5\x41\xeb\x1f\xc1\x06\xfd\x80\xe6\xa1\xe1\x7b\xf3\x35\xbf\x3f\x01\x17\xde\x4b\x97\x7d\x94\x6e\xa7\xdf\xb7\x9f\x7b\x96\xd2\x72\x0b\xa5\x8c\x83\x93\x5c\x5a\xe3\x23\xea\x85\xba\xf7\x0f\xf7\xd2\x75\xe7\xb7\xb5\x99\x56\x87\x24\x49\x96\x66\xcd\x9e\x32\xcf\x23\x0c\xaf\x96\xf1\x26\x71\x48\xdd\x59\x8d\x30\x1c\xc4\x69\xe5\xcf\xc3\xdf\x70\x81\xeb\xe1\x8f\x70\xb7\xde\xf5\xf9\x9a\xb7\x07\xac\x64\x5c\x7b\x44\x94\x64\x5d\xc6\xfd\x07\xef\x16\xdf\xba\x7e\x8d\x28\xe4\x6e\x3d\x1b\x47\xae\xd6\xeb\x0d\x7f\x03\x5d\x7d\x9a\x78\x2c\x37\x4b\xed\x51\x5a\xa5\xe2\xc5\xbb\xb6\x58\x5b\x00\x6b\x66\xa4\xe3\x1d\x3a\xd9\x0e\xf0\x58\x83\xac\x6b\x90\x77\x27\xe9\xb8\xf5\xb1\x02\xfa\x25\x79\x03\x7e\x2c\x01\x9d\x3d\x3a\x79\x89\x04\xef\x0b\x9a\xeb\xed\xa5\xe8\x57\xc1\xf3\x1e\x22\x47\x0a\x7a\xde\x59\xe8\x01\x4c\xbe\xe5\xae\x6c\x55\xcd\x8d\xe2\xec\xf0\x75\x8b\x2d\x99\xde\xa8\x02\x78\xc1\x18\x4b\xe0\x58\x42\x9c\xc9\x0a\xfc\xd1\x59\xeb\x5b\x4b\xa5\x3d\xf6\x64\x24\xe6\x35\xf0\xd8\xd0\xce\x0c\x15\x74\xaa\x28\x07\x6f\x9d\x8d\x9b\xb2\x96\x80\x81\x25\x83\x7e\x8c\x33\x11\x0f\x9a\xad\x37\x4d\x9c\xec\xb5\x73\x9d\xa6\x49\x82\xc6\x1b\x97\x14\x72\x65\x34\x46\x6b\x40\x1d\xb5\xf7\x33\x42\x55\x22\x55\x46\x67\x84\x12\xbc\x3f\xd3\xa2\x4f\x8f\x68\x3d\x7a\x53\xa4\x0c\x31\xd4\x4f\xbd\xcd\xb0\xfc\xc5\x78\xd4\xf1\x48\x7d\xe8\x94\x83\x94\x7e\x94\xd1\x2f\xea\xbc\xc7\x32\xac\x5e\x9b\x92\x21\x50\xac\xcd\xab\xad\x30\x76\xd1\x8a\x70\x78\x7a\x7f\xd6\x62\x39\x12\x38\xed\xf0\xd9\xa9\x06\x78\xec\xa5\x89\xc5\x18\xba\xef\xd7\x6a\x9d\x4a\xcb\xea\x3d\x56\x11\x31\xe0\x1d\xfc\xad\xd6\x1d\x0d\xe5\x57\xc2\x87\x90\xf5\xc5\x10\x32\x04\x57\x29\x1e\x1e\xa0\x69\x06\x42\xe4\xea\x5d\x94\xe2\xb8\x76\x22\xb0\xb4\xb7\xce\x50\x4b\x13\x13\x1d\x88\xf3\xc4\xe4\x07\xea\xf2\x10\x3e\xc8\x29\x7b\xf9\x4f\x7d\xf2\x3e\xc8\x45\xfa\xd5\x3f\xf5\xd9\x7b\x6f\x07\xeb\xe6\x94\x7e\xfe\x4f\x7d\x4a\x7f\x6a\x45\xff\xbd\x59\x67\x2b\xab\x66\xc1\x58\x76\xc6\x12\x42\xef\xcb\x86\x36\x98\xd5\xd8\x99\x64\x76\xc3\xc0\xc2\xa9\x24\xf4\x76\xdc\x41\xc3\x50\x82\x38\xfe\xd1\x48\x30\x22\xf1\xce\x6a\xa5\x65\x0e\xc3\xfa\xfb\x08\x4d\xeb\x76\xde\xa7\xf4\x30\xd2\x16\xa5\x8c\x30\x72\xbe\x70\xa7\xdd\x6b\x48\xd9\x89\x9f\x62\x59\xfd\xb4\xcf\x0b\x36\x7a\xa8\x8d\xd5\x2b\x2d\x23\x6f\x83\x03\x17\xde\x69\x84\x42\x66\xc1\x50\x72\xf5\x4a\xa9\xa9\x37\x0b\xa8\xe2\x64\x42\x50\xfe\xc2\x34\x76\xab\x28\x4d\x62\x6d\x5b\x18\xfb\x7d\xa2\x8f\x0a\xb8\x3a\xb6\x08\x9e\x96\xaa\x9b\x5f\xcd\x34\x28\x79\x0c\xad\x4f\x75\x17\x62\x4f\x0e\xaf\x32\x74\xa5\x75\x47\xc7\x00\x77\x74\x32\x46\x9a\x5e\x0c\xc1\xf8\x41\x22\xf6\x71\xf9\x73\x94\xcc\x07\x35\xce\x97\x93\x83\x05\xa5\xcf\x34\x66\x74\x1c\x1d\xc6\x72\xf7\x46\xfd\x73\x3d\x62\xce\x63\xcf\x25\x14\x74\x6e\x0f\xcd\xe8\xda\x3b\x8c\x46\x47\x84\x1a\x77\xfe\x74\x58\xf5\x48\x13\xd5\xf9\x66\x79\x2f\x52\x26\x67\x24\x45\xe7\x52\xc3\xe5\x59\x6f\xab\xee\x4d\xab\x8d\x2b\x94\xe1\xa2\x4f\x6f\x57\x2d\xa7\x39\x5d\x43\x75\x08\xb6\xce\x61\x69\xde\x7e\x06\xe1\x0a\xb5\x82\x8f\x98\xd1\x7e\x51\xd4\x07\x90\x14\x72\x1f\xc8\x0b\xf5\x81\xc6\xa5\xc6\x14\x80\xae\xe2\x89\xad\xd5\xcc\xca\x3c\x59\x90\x63\x47\x73\x26\x23\xed\xaa\x5d\x0f\x20\x2c\xe4\x91\x17\x09\x0b\xe0\xac\x3b\x4a\xb0\x1d\x00\x6e\x70\x85\xe2\x3b\xc6\x81\x8d\x90\x68\x63\xb5\x07\xf2\xfc\x3e\x3e\x44\xdf\x5d\x80\xa1\x39\x9f\xc7\xcc\x3a\x85\xe1\x88\x1a\xbe\xd1\xd9\x05\xf2\x73\x4e\xff\x17\x3f\x1d\xb4\xdf\xc7\x41\xfb\x81\xab\x8e\xf0\x7b\xd4\x1d\xdf\xb3\xea\xa0\xb2\x92\x51\x35\x54\xb1\x7e\x6d\x76\xf6\x42\x1e\x69\x72\xb5\x6e\xf8\xc5\x70\xbc\x15\x05\x1c\xe8\x13\x25\xe5\x10\xba\x14\x5e\xa4\xf1\xe8\x68\x81\x6e\x17\x75\xe8\x9f\xc6\x25\xe2\x4a\x6a\xf7\x26\xad\xe8\x76\x41\xe3\x80\x68\x69\xde\x55\xd8\x1a\x9a\x5e\x1b\x44\x43\x12\xee\xb1\x1b\x68\xdd\xe0\xf6\xe8\x13\xc7\x81\x54\x5a\x36\x0e\x6c\x7d\x23\x2c\xf2\x38\x8c\x92\x92\x17\xab\x56\x64\xb6\x78\x83\x8a\x30\x40\xa4\x3c\x72\xaa\x82\x63\x47\xe5\x40\xe5\x60\xd4\x21\x5d\x8e\xda\x39\xec\x98\x22\x34\xdd\x0d\x23\x79\xd4\x07\xcd\x22\x56\x14\xb3\x2d\x50\xb4\x4d\x7d\x2b\xd7\x25\x71\x92\x35\x1c\x48\x7e\x2e\x5e\x48\x45\xce\x89\xb6\x44\x36\x89\xef\x2e\x96\x34\xbd\x2d\x9e\x35\x02\xed\x9e\xfd\x65\xb5\xdb\x1e\x6f\x77\xd4\x26\x0c\xe7\x53\xce\xde\x50\x6e\x0a\x5e\x76\xa7\x1a\xa8\x06\xeb\x00\x77\xb5\x7a\xac\x75\x30\xa0\xe6\xed\xae\xec\x0d\x0e\xab\x1e\x58\xae\x88\x32\x42\xa7\x58\x7b\x39\x70\x32\x4c\xef\xa6\x51\xd1\xf1\xad\x5e\x62\x96\xb4\x93\x35\xec\x30\xbf\x97\x87\x51\x20\x00\x4f\x6d\x1d\x3e\x63\x16\xaf\xa4\xc0\xf2\x59\x9f\x95\x11\x9a\x07\x7d\x90\xf8\xcd\x56\x80\x80\x2e\xc6\x65\xb5\xec\xa7\x3c\xf6\xa8\x4a\x15\x55\x0e\x16\x5c\x00\x02\x9a\x56\x21\xc2\x42\xe5\x57\x0a\x6d\x19\x9e\xfd\x94\xfe\x16\x3d\xc9\x02\x08\x3b\xe6\xc1\x49\x25\xbc\x9f\xde\x6a\x91\x67\x7d\xc7\x8b\xf5\x50\xa3\x86\xda\x05\xb4\x67\x44\x63\xb6\xb3\x2b\xa1\x49\xcf\x11\x38\xe7\x87\x7b\x95\x9e\xd9\x99\x0c\x75\xcf\x00\xcf\xde\x26\xfa\xd0\x74\x34\xa7\x03\xf3\x03\xf1\x24\xb1\x7a\x15\x09\xd6\xee\xc4\x8e\xe9\x9d\xb1\xb6\xd8\xfe\xaa\x2e\xfb\x02\x79\x6f\x5e\xdc\x67\x9a\xb9\x97\x60\x15\x08\x69\x5a\x20\x61\x57\xab\x9d\x31\xdf\x87\xb5\x15\xc4\x5c\x51\x10\x03\xe9\x51\x3d\xfb\xa1\x8e\x55\xa9\x90\xc9\x7b\x78\x7b\x87\x9d\x3e\xce\x60\x92\xa1\xdb\x1f\xee\x4b\xcf\xa1\xa6\x0a\x9e\x6e\x94\x81\x09\x7a\x0d\x53\xae\x33\xf6\x06\xe4\x08\xba\x1d\xda\x6c\xbc\xf1\x34\xe0\x23\x6e\xef\xed\xd6\x3f\x12\xe1\x0c\xe9\x36\xfb\x61\x33\x02\xe9\x0d\x3f\x3a\xd6\x7b\x3e\xbb\x15\x7d\x74\xc7\x97\x4f\x7a\xab\xf7\xc8\x77\xfd\x71\xa4\xbb\xc2\x7b\x80\x40\x38\xa5\xf4\xe9\x8b\x70\xf9\xfa\x37\x5f\x3e\xc4\x97\xaf\x8e\xf8\xdb\xcf\x5e\x74\x29\xcf\xdc\x4e\x6f\xdf\x4e\xb5\xd1\x33\xf7\xf3\x77\x7b\xbc\x7c\xc7\xc7\xe7\xb7\xef\x2f\xa5\x3d\x73\x7b\x79\xfb\xf6\x4c\xcf\xdd\x5e\xdf\xbe\x9d\x5b\x7f\xe6\xf6\xf6\xdd\x6e\xef\xef\xdc\x9e\x9e\xbb\x7d\xbc\x7d\xbb\x48\x7e\xe6\xf6\x97\x6f\xdf\x3e\xf8\xf6\xdd\x74\xf6\xa3\x10\x0a\xa5\xca\x41\xbd\x5d\x5a\x45\x4b\x90\x76\x89\xad\xde\xc6\x91\x71\x22\xfa\x90\x2f\xf3\x87\x7c\xf9\xdd\xed\xc2\x3d\xbd\xfb\x3c\x4a\x9c\xfd\x81\x7a\xf9\xdc\x13\xdf\xd9\x50\x2c\x29\xbf\xfb\x44\x4e\x79\x0d\x51\x2f\x9f\x7b\xe2\xc9\xb9\x2a\x35\x0c\x4e\x06\xf7\xab\x49\x05\x1b\x80\xfc\x1c\x98\xcd\x14\x41\xfa\xc6\x2a\x00\x21\x8a\xcb\xe2\xb7\x02\x05\xb5\x5d\xa9\x7f\xec\x05\xb4\xe9\x9a\x9e\x22\x0a\xc3\xc5\x1a\x70\x90\x6e\xea\xab\x75\x6b\x25\xc4\xd6\xac\xd6\x92\x07\xc9\x7b\xe2\xb9\x0b\x57\xaa\x6b\xa3\x72\x3a\xd4\xa6\x20\xcc\xce\x89\x44\x7b\x84\x12\x71\xbb\xc7\x78\x4e\xd5\x1e\x46\x04\xb1\x78\xb1\x27\xe2\x02\xcf\xcd\xc3\x4a\x34\x48\x92\xd0\xa5\xaa\x2d\xcf\xcd\x4c\x4a\xbc\x5a\xb6\xab\xc9\x3d\x94\xa4\x4a\xc9\x5f\x0e\x35\xa9\x46\x15\x08\x01\x98\x3c\xc9\xc6\x80\xa4\x86\xdc\xf0\x67\x34\xdb\xb3\xee\x82\xa5\x4e\x21\xaf\x94\x45\xc6\x09\xd2\xde\x6c\x1d\x53\x87\xa8\x48\xc8\x66\x8f\x46\x19\xd3\x0b\x38\x61\xa9\xe7\x6b\x17\x65\x75\x33\xdd\x28\xed\x66\x60\x5b\xf1\x1e\xd6\xeb\xb9\x57\x7d\x79\xbe\xaa\x11\xf2\xde\x7a\xd7\x3b\x7f\x5b\xeb\x44\xff\x2d\xdf\xb7\xfa\x07\xc5\x6e\xbf\xf1\xce\xb4\xde\x78\x99\x00\xbe\x98\x79\xc2\xc9\x78\xf7\x9d\xab\xbf\x33\xb9\x07\x6d\x26\x29\x99\xab\xfd\x3b\xde\xf7\xf3\x47\x67\xf8\x5b\x6e\xf1\xee\x5b\xdc\x14\x62\x39\x53\xa5\xbf\x73\x9b\x9f\xfa\xdb\xb4\xf3\x1b\x5b\xbd\xad\x8d\x4e\xb7\xb6\xf9\x35\x12\xb0\x7a\x04\xbf\xd7\x36\x07\x15\xf5\x60\x34\xf2\xfa\x7e\x5e\xf5\x87\x72\xaa\xcf\x52\x8a\x94\xfe\x00\xa7\xfa\xac\x80\x7f\x74\xae\x1f\x9d\xea\xe7\x77\xf8\xa3\x53\x6d\x3b\x9c\xdf\xda\xe1\xf7\x85\xf9\xdb\xbf\x44\xf8\x7d\xc9\xa6\x0f\x7c\x8b\x67\x16\xeb\xf5\xa3\xc5\xfa\x03\xca\xa5\x37\x57\x8d\x6c\xcd\x3e\x9a\x5c\xc2\xaa\x7d\xbb\xb7\x09\x3f\x6a\x31\xcb\x67\xa3\x25\x92\x50\x01\x7e\xc8\xc9\xdc\x16\x04\x83\xe0\xdb\x55\x36\xca\x8e\xcc\xd3\x92\x78\x28\x47\x20\x27\x6e\xaf\xe8\xda\x3f\x73\xd6\x63\x0f\x96\x4c\x0b\x23\xd9\x95\x15\x0f\x58\x9f\x30\xbf\x33\x9e\x5f\x8d\xd7\xc7\xc5\xf5\x0b\x86\x59\xf0\xc6\x62\x36\x8e\xe7\xc6\x5f\xaf\x4d\xcf\xac\x4f\x3e\x5c\xa9\xc5\x7e\xa9\x4e\x64\x5e\x61\x56\xab\x40\xd4\x33\x41\xa7\xfb\x0a\xef\x9a\x1d\xcd\x13\x73\x9e\x90\x73\x79\x45\xbe\xbc\x0d\x7c\x3a\x9b\xc0\x9b\x2f\x1e\xed\xcb\x4b\xda\xe1\xa9\x1e\x43\xd3\x4f\xf1\xab\x67\x90\xa2\x58\x99\x47\xf9\xc8\x03\x0c\x1f\x7b\x84\xb5\xf7\xa7\x46\x08\x84\xd1\x9b\x63\xb4\x76\x6d\xf3\x1c\x20\x14\x89\x0d\xf1\xae\x3c\x33\x8b\x77\xd7\x66\xfa\xd5\x74\xc7\x1a\xe7\x8c\xeb\xa1\xd7\x31\xfa\x0f\xbf\x39\xca\x67\x76\xc2\x17\xdf\xc9\x97\x91\x71\x86\x0d\x52\xc8\xa5\x1d\x75\x6c\x6a\x4d\x0b\xd7\x8d\xa4\xac\x1e\x09\xc0\x00\x71\xde\x58\x77\x31\x57\xde\xf4\xef\xf8\xf0\x99\xa1\xc8\xcb\xf3\xd9\x7a\xf6\x1b\xbe\x8d\x2f\xa3\x0b\x03\x67\xfc\x82\xfe\x80\xfe\x62\x14\xae\x47\xac\x63\x8b\x92\x51\xda\xfa\xdc\xa3\xcb\x3b\x6f\xf9\xac\xb7\xf9\x72\x59\x51\x32\x42\xa6\xb4\x65\x09\xd4\xf3\x56\x4b\xc8\x47\x76\x89\xe5\x0d\x64\x10\xcf\x64\x75\x66\x86\xdd\x56\x2f\xa3\xee\x40\x91\x09\x92\xf4\x01\x75\x4e\xe8\x38\x6c\x54\xb7\x94\x29\x34\x99\x64\xf1\x4a\xd9\x69\xa4\x90\x82\x90\x45\xd5\x36\xb0\xd7\xd0\x18\xa0\x62\xe1\x1c\xdc\x08\x20\x5f\xfd\x92\xbc\xc6\x48\xfa\x44\x1f\xe4\x40\x65\x8f\xdd\x02\x99\x2a\xc6\xdc\x5c\x48\xec\xcd\x7c\x2f\xb9\xb3\xe3\xb7\x7a\xbd\xc4\x9c\x79\xb7\x7c\x90\x13\x2d\x8b\xcc\x68\x95\x66\x88\xd7\x5f\x32\xd5\xe0\x50\xac\x9e\x2f\x51\x38\xef\x3c\xac\xa8\x6b\xe8\xbf\xbd\x4d\x6a\x40\x81\xed\x15\x45\x48\x94\x03\x0f\x0b\x52\xd3\x36\xd4\xd4\xaa\x7d\x8f\xb8\x05\xd9\x3e\x43\x0e\xb4\x19\xa9\x99\x91\x9f\xc1\x74\x91\xbc\x24\x0c\x9b\x96\x32\x87\xae\xb7\x24\x2c\xb0\x87\x5b\xa8\x97\x4b\x24\xbe\x0d\xfa\x61\xba\x0a\xe2\x16\x88\x1a\x1d\x24\x7c\xc9\x85\x8f\xa8\x17\x91\x0a\x1d\xb1\x50\xbd\x44\xca\xfd\xb0\x8b\x22\x0f\xf7\x85\x6a\xa8\xa5\x1c\x35\xf7\x0b\xd1\xd8\xd0\xcd\x82\x6b\xd9\x10\xa9\xaa\xe5\x42\xc4\x47\xd4\x4f\x23\xe5\x72\x48\x91\xcd\x22\xd2\x99\x2f\xb1\xd2\x06\xc9\x20\xe5\x88\x92\xf1\xec\xdb\xf9\x14\x2e\x00\x82\xbc\xe9\xfe\x97\x72\x36\x64\x3f\x46\x29\x97\x51\xca\x11\xf5\x42\xff\xcf\x1f\xf5\xc9\x17\x5f\x7f\x35\xf5\xdf\x57\xaf\xbf\xf8\xe6\x17\x3f\xff\xe4\x9b\xe3\xd7\xbf\x08\xff\x5f\x00\x00\x00\xff\xff\x68\xff\x0b\x82\xb9\x18\x01\x00") func fontsInconsolataBoldWebfontSvgBytes() ([]byte, error) { return bindataRead( _fontsInconsolataBoldWebfontSvg, "fonts/inconsolata-bold-webfont.svg", ) } func fontsInconsolataBoldWebfontSvg() (*asset, error) { bytes, err := fontsInconsolataBoldWebfontSvgBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "fonts/inconsolata-bold-webfont.svg", size: 71865, mode: os.FileMode(509), modTime: time.Unix(1492020681, 0)} a := &asset{bytes: bytes, info: info} return a, nil } var _fontsInconsolataBoldWebfontTtf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x8c\xbc\x09\x7c\x5c\xc5\x95\x2f\x7c\xea\x2e\xbd\x6f\xb7\xf7\x7d\x95\xd4\x92\xae\x5a\xdd\xea\x56\xab\x75\xb5\x4b\xd6\x62\x59\xb2\x2d\xc9\xb2\x2d\x2f\x18\xef\x36\xde\x8d\x01\xdb\x61\x0c\x61\x35\x36\x21\x24\x6c\x21\x0c\x43\x08\x43\x1c\x86\x21\xa4\x6e\xab\x31\x4b\x3c\x40\x58\x1e\xc3\x23\x4c\x3e\x1e\x83\x19\x86\x30\x26\x93\xc7\x84\x9b\x21\x19\x5e\x5e\x26\x61\x91\x5a\xdf\xaf\xea\xb6\xe4\x25\xc9\xbc\xb1\x7f\xdd\x5d\xf7\xf6\x55\x57\xd5\x59\xff\xe7\xd4\xa9\x02\x04\x00\x02\x02\xe0\xc0\x36\x38\x38\xb9\x74\xfb\xcb\x57\xce\x02\xa0\x20\x00\x04\x87\xfa\x07\x06\x91\x03\x38\x00\xd4\x0a\x00\xd1\xe5\x2b\xd2\xd9\x7d\xab\x3d\x4b\x00\xd0\x14\x00\x6c\xdc\xb2\x77\xd3\x01\x4e\xe8\x05\x00\xf4\x0c\x00\xfa\xe7\x2d\xd7\x5c\x15\x15\x5e\x31\xfe\x6f\x00\xf6\x1e\x00\xc8\x6e\x3f\xb0\x63\xef\x8a\x52\xfa\xfb\x00\xec\xdf\x03\x30\xdb\x76\x6c\x3a\x74\x00\x00\x6c\x00\x9a\x0c\x00\xe8\x76\xec\x39\xba\xfd\xe1\x1f\xbc\xfe\x9f\x00\x9a\x56\x80\x53\xff\xb4\x73\xdb\xa6\xad\x9a\xe2\x4d\xdf\x04\xf8\x81\x0d\x00\x5a\x76\xee\xdc\xb6\xc9\xba\x49\x17\x00\xf8\xc1\x62\x00\xa8\xda\xb9\xf7\xaa\x23\xc7\xbf\xb3\x76\x15\xc0\x0f\xf6\x00\xb0\xf7\xef\xd9\xbf\x65\xd3\x3f\xbf\x52\x7c\x09\x40\x26\x63\xfc\x87\xbd\x9b\x8e\x1c\x60\x58\xf4\x32\x40\xf1\x1f\xc9\x78\xf7\x6d\xda\xbb\xed\x9c\xf3\xdf\x5b\x01\x8a\xbf\x03\xd0\x3d\x74\x60\xff\xa1\xab\x1e\x6b\x1e\xff\x3d\xc0\x8f\xee\x01\x60\xfe\xee\xc0\x95\xdb\x0e\x7c\x26\xd7\xe9\x01\x9e\x9f\x04\x80\x5f\x1c\xde\xb6\x79\xfb\x27\x4b\x56\xac\x01\x78\x81\xcc\x57\x43\x26\x06\x00\xf0\x93\xce\x47\x7e\x4a\x3e\xdf\xd0\xe4\xb6\x92\xcf\x9f\x5e\xff\xe0\xeb\xf4\x1b\x0b\x00\x78\xc9\x1d\x60\x00\x01\x82\x8f\x00\x11\x6a\x01\x03\x00\x2c\xfb\x1b\xe6\x0c\xf0\xc0\xf1\x39\xfe\x01\x00\x14\x51\x3f\xd9\x77\x61\x2b\x63\x03\x60\x8c\x1a\x3d\x0b\x2c\x00\x7c\x15\x20\x0d\x80\x76\x43\xe5\xdf\xd8\xf6\x81\xad\x10\x05\x73\xf5\x8c\x66\x7b\x79\x3b\x80\xe6\x1c\xfa\x01\x00\x38\xc8\x77\xec\x19\x6e\x86\xcc\x8c\xf6\xce\x56\x5e\x41\x75\x94\xf0\x8f\xc0\xd2\x56\x10\x38\x78\x06\x00\xea\x21\x0a\x1c\x18\x00\xc0\x0c\xd7\xc1\x1c\x5a\x81\x8e\x30\xff\x83\xf9\x59\xd4\x10\x75\x46\xfd\xd1\x70\x34\x1e\xad\x89\xa6\xa3\x6d\xd1\xcb\xa3\x4f\xc4\xe2\xd5\x33\x73\x73\xf4\x57\xcc\x10\x85\x87\xd1\x44\xe5\x59\x88\xda\xa2\xde\x68\xb0\xf2\xac\x74\xc1\xb3\x68\xee\x3f\xe7\x7e\x31\xf7\xd2\xdc\x81\xb9\xd1\xd9\xb9\xd9\x5f\x7d\xf8\xda\x87\x2f\x7d\xf8\xc2\x87\xcf\x7f\xf8\xa3\x0f\x9f\xf9\x10\x7f\xf8\xfd\x0f\x6f\xfa\xb0\x70\xee\xa5\x7f\x56\x2a\x63\xfb\x6f\xfe\x43\x1a\x58\xf8\x03\xc4\x54\x28\x79\xd1\x03\x00\x2c\xc7\x6b\xb4\x3a\xbd\xc1\x68\x32\x5b\xac\x36\xc1\xee\x70\xba\xdc\x1e\xaf\xcf\x1f\x08\x86\xc2\x91\x68\x2c\x9e\xa8\xaa\xae\x49\xd6\xd6\xd5\x8b\x0d\xa9\xc6\x74\xa6\x29\x9b\x6b\xce\xb7\x14\x5a\xa5\xb6\xf6\x8e\xce\xae\xee\x9e\xde\xbe\x45\xfd\x03\x83\x43\x8b\x87\x97\x8c\x8c\x2e\x5d\xb6\x7c\x6c\x7c\x62\xc5\xe4\xca\x55\xab\xa7\xd6\xac\x5d\xb7\xfe\xb2\x0d\x97\x6f\xdc\x04\xb7\x1e\x3f\x71\xfb\xdd\xf7\x3f\xf4\xd7\x8f\x3c\x7a\xea\x7b\xdf\xff\x9b\xbf\x7d\xfc\x89\x1f\xfc\xf0\x49\x2c\x4f\x3f\x55\x3a\xfd\xcc\xd3\x67\x7e\xf4\x77\xcf\xc3\x95\x5b\xb7\x5d\xf1\xc1\x91\xef\x1e\xd8\xfd\xbf\xaf\xd9\x05\xb7\x3d\x00\x87\x00\x76\x1c\xa6\xa3\xdb\xf3\x17\xf0\xd8\x73\x37\x6c\xd9\x47\xda\x7b\x8f\xfd\xcb\xe6\x1b\x6f\xf9\xd6\x4b\x2f\xbf\x73\xf6\x9f\xdf\x7f\xf7\x9f\x9e\x85\x1f\xbf\x02\xbf\xf8\xf0\xe7\x00\x70\xf4\xbd\x9f\xc1\xcd\x5f\xbb\xe9\x8e\x93\x77\x7e\xe3\x9b\x5f\xbf\xf7\x3e\xb8\xe7\xc1\xbf\xfa\x4b\x78\xf5\x7f\x1c\x04\x80\xaf\x54\xa6\xc9\x3e\xc6\xcd\xc0\xcb\xf0\x1c\x14\xe1\x34\x3c\x06\x2f\xc0\x6b\xf0\x06\xfc\x1b\xfc\x03\x9c\x83\x7f\x83\x4f\xe0\x2d\xf8\x27\xb8\x1b\xde\x86\xd7\xe1\x19\xf8\x19\xf4\xf3\x02\x00\x86\x06\x0c\x8e\x11\x3c\x3a\x36\x85\x97\x5c\xb3\x06\x43\xa2\xdb\x8b\x35\xe2\x54\xe7\x1a\x7a\xef\xd8\x9a\xe8\x3f\x62\xe4\x68\xf4\xa6\x30\x6a\x88\xfe\x33\x36\x89\x29\xcc\x34\x8c\x4c\x4c\x0d\x24\xd6\xc4\x52\x98\x6d\xb8\xc2\x1b\xc5\x3d\x63\x53\x31\xdc\xb3\x26\x85\xb9\x06\xf2\xa7\xb1\x44\xec\x2b\x53\x1f\x04\xde\x5c\x13\x18\x99\x98\x9a\x9a\x0d\xfc\x7a\x4d\x20\x11\xc3\xbc\x38\x85\x07\xaf\x59\x43\xbf\x58\xb3\xc6\x9b\xc2\x7c\x83\x79\xfd\xda\x14\xd6\x34\xc8\x71\x74\xdb\xd8\x14\x8e\xde\xb6\x7e\x7d\x00\xc3\x9a\x14\xd6\x36\xc8\x55\xf4\x56\xcf\xc2\x2d\x5d\x83\x5d\x88\x4a\xe9\x14\xd6\x37\x44\x8f\x91\x4e\x5e\x09\xbc\xb9\x26\x8a\xd9\xea\xe1\x44\x14\x73\x35\x4b\x30\x8c\x4d\x9d\xdc\x76\x72\x53\x94\x34\x5a\x03\xb1\xd8\x9a\xc0\x49\x7a\x35\xa1\x5e\x91\x0e\x0d\xea\xe8\x6c\x01\x5b\x6c\x4d\x0a\x1b\x1b\xa2\xff\x8b\x4e\xc7\xd4\x10\x4d\x63\xad\xb8\x7e\x2a\x1a\x1d\x4a\x0c\x6e\xda\x15\x9d\x8a\x6e\xdd\xac\xfe\x04\x79\xce\x4c\x7a\x8e\x4a\xe9\xe8\xc9\xe8\xd0\xc9\xc1\x4d\x89\x93\xd1\x93\x09\xda\x5d\x82\xfc\x38\xee\x69\x0d\xc4\xd6\x04\x12\xe4\x06\xee\xd9\x46\x2e\xd6\xa4\xb0\x85\xf6\xd4\x79\xd6\x1b\x8b\x05\xa2\x67\x4f\x8e\x4c\x4c\x45\x4f\x26\x86\xa3\x18\x56\x56\xc6\x16\xa3\x8f\x59\x1b\x12\xd1\xb3\x95\xce\x13\xd1\xa9\x91\x15\x81\x18\x46\x6b\xa6\x4e\x62\xae\x66\x38\x71\x32\x11\x3d\x39\x7c\x32\xb1\x89\xfc\x81\xfa\x27\xe4\x23\x85\x6d\x84\x0d\x76\x31\x85\x05\x32\x01\xd2\xb0\x5f\x32\x81\x93\xe4\x23\xb1\x69\xd7\xc6\x0b\x67\x42\xfe\xd4\xd1\x10\x3d\x19\x3d\x79\x9c\x90\x6d\xc9\xd6\xc4\x49\x2d\x8e\x8e\x4d\x75\x04\x5e\x5c\x93\xc2\xce\x86\x69\xe8\x41\x3d\x7d\x7d\x68\xe4\x19\x1b\x6c\x01\xfa\x4e\x1e\x5e\x39\x45\xde\x27\xa6\x12\x9b\xa3\x18\x12\x7d\x81\xcd\x51\x8c\x12\x7d\x6b\xa2\xb8\x67\x62\xaa\x08\x51\x58\xb4\xa5\xaf\x88\xa2\x68\xd1\x96\x3e\x1c\xdd\x82\x7d\xdb\x82\xf3\x7d\xb9\x1a\x30\x5a\xb4\x25\x81\x61\xd1\x96\x44\x4a\xd5\x40\x34\x37\x07\x56\x60\xa0\x1f\x80\xd9\xca\xaf\x04\x16\xb4\xd0\x28\x23\x48\x77\x14\xb5\x9c\xe7\xd7\x59\x59\xc3\xff\xac\xa3\xc8\x32\x9e\x5f\x67\x41\x66\xc9\x6d\x9e\xdc\x2e\x6a\x35\xde\x99\x8e\x22\x22\xf7\x73\x42\x4c\xa8\x8e\x09\xb1\x7e\x26\x5a\xae\x42\xf7\x97\x77\xf2\x2b\xbf\xf8\xdb\x7e\xee\x4d\xa2\xf1\x68\x74\xee\x13\xe6\x76\x7e\x03\x38\xa0\x06\xa6\xa0\x68\x05\x10\x4b\xbc\x01\x2c\x9c\x88\x70\x32\x8d\xe1\x6c\xc9\x60\x05\x33\x27\x62\x7f\x16\x1b\x6c\x25\xa7\x15\xdc\x9c\x88\x9d\x69\x72\x01\xea\x37\x90\x9e\x8e\x19\x9c\x3a\xb1\x14\x35\x41\x94\x13\xe5\x5a\x24\xca\xd1\x98\x60\x2f\x5a\x3d\xbc\x24\x49\x90\x69\xaa\x6e\xee\x62\x72\xd9\x30\xe3\x72\x5a\x98\x44\xbc\x91\x71\x34\xb7\xe4\xb2\x6e\x72\xa5\x65\x13\x6c\x23\x8b\x46\x7d\xa2\x14\x4d\xb4\x37\x78\xfd\xa9\xf6\x68\x54\x12\x7d\xf6\x91\x81\xbe\xa5\x1c\xaf\x41\xd5\xcf\x06\x19\x8d\x8e\xbf\x3e\xdc\x52\xe7\xf5\xd7\xe7\x83\xe1\x7c\x9d\xc7\x53\x9b\xe7\x96\xad\x5c\xb7\x7e\xa7\xb3\xa5\xa3\xcd\x33\xfb\x36\x93\xf2\x76\xf7\x76\xaa\x9e\xe1\x34\xdb\xce\x4e\xf1\xfb\xc1\x01\x22\x0c\x02\x76\xa4\xb1\x98\x2b\x19\x0c\xa0\xe3\x44\x1c\xce\x22\xdc\x90\xc6\xdc\x59\xd9\x6a\x55\xb0\xd5\x26\x7b\x91\x28\x27\xac\x8a\x9c\x42\xa2\x6c\xe5\x04\xbb\x6c\x70\x48\x12\xf6\x0a\xd8\x29\xe1\x84\x5d\x0e\x8b\x74\xf4\x8e\x42\x17\xca\x27\x17\xa6\xa0\xb1\xa2\x6e\x74\xf1\x1d\xad\x85\xd5\x9e\x6e\xd1\x19\x2c\xae\x44\xda\xef\x4b\x57\xbb\xe3\x51\xe9\x91\xbc\x4e\x67\x72\x55\x35\xfa\x7d\x99\x2a\x77\x55\x94\xb7\x5a\x6d\x1a\x76\xe7\x29\x9f\xe8\x3c\x5c\x5d\xa8\xb2\xdb\x93\xed\xb5\xf1\x63\xeb\x1e\x4a\x5d\x74\x27\x74\xe3\x3a\x6b\x7d\x43\xbd\x55\x9d\x4b\x12\x2c\xec\x39\x9e\x83\x00\x44\xd0\x04\x14\x75\x0c\x88\x45\xad\xd1\x94\xcb\xe5\x8a\x3c\x02\x71\x5a\xa3\x37\x98\xab\x3c\x39\x99\xd3\x2a\xd3\xac\x2d\x1c\xa9\xf2\x64\x09\x33\x9c\x1e\x6f\x80\xdc\x46\x5a\x65\x9a\x11\x82\xa1\x2a\x4f\xb6\x08\xc8\x20\x4e\xf7\x80\x5f\x2f\x22\x4c\x04\xff\xac\xac\x33\x29\xd3\x3e\x9d\x56\x27\xca\x7e\x93\x82\xfd\x69\xd9\x67\x52\xb0\xce\x26\x1b\x91\x28\x9b\x4c\x8a\x1c\x43\x22\x6e\xf1\x3f\xd7\xfd\xc8\xe7\xb5\xe0\x12\x0d\x1c\xf6\xdb\x64\x9f\xe1\xf3\xe7\xba\xbf\xf1\xd9\x09\x72\xc3\x82\x8d\x36\xec\x7e\x11\x9b\x6c\xd8\xf5\x22\x8f\xfd\xb6\x69\xc6\xaf\x75\x88\xd3\x2c\x7d\xd7\x90\x77\xec\xb3\x4d\xeb\x7d\x3a\x87\x88\xdd\xb6\x69\x83\xdb\xe8\x10\xb1\xcb\x36\x6d\x76\x99\x1c\xe2\xb4\x8d\xbe\x0b\xf4\xdd\x49\xde\xc9\x33\x1e\xfa\x8c\xcf\x36\xed\xa5\x7f\xe5\xb7\x4d\x07\xe6\x7f\x27\x38\xff\x3b\x21\xf2\xcc\x74\x78\xfe\xc9\x08\xb9\xcf\x42\xd1\xe5\xf6\x35\x36\x36\xa2\x1e\x3b\xc3\x12\xb2\xd8\x04\xea\xa8\xa8\x9b\x6a\xfc\xa3\x7f\xb8\xc7\x4f\xf9\x9a\x73\x24\x0a\x39\x47\x81\xa5\x2f\x6d\x82\xbe\xb4\x0e\xf2\x22\x5f\x25\x4d\x7f\x17\xfe\x9f\x86\xb7\xab\xdf\x4e\xee\xab\x7e\xbb\xfa\x09\xe7\x13\x91\xd3\xa6\x33\x75\x6f\x8b\x87\xea\xde\xac\xfe\xc5\xc1\xd8\x21\xb4\xfd\x61\xe4\xf9\x2e\xea\x67\xca\x2f\xa0\x76\xa6\xfc\xda\xa3\xe5\x7f\xff\x4e\xf9\x09\x33\x5a\x5b\x96\x19\xb4\xfc\x51\xe4\x22\x88\x61\xeb\xdc\x29\xf6\xc7\x7c\x1e\xda\xa1\x0f\x86\xe1\x2e\xc0\x52\x5a\xd6\xeb\x14\x2c\xa6\x71\x4f\x4e\x8e\xb0\x4a\x31\x22\x12\xd6\x44\xdc\x84\x35\x4b\xd2\xd8\x7a\x56\xee\x30\x2b\xb8\xc3\x26\xeb\x91\x58\x74\xb6\x76\x67\xb3\xd9\xd2\x22\xaa\x59\x58\xcc\xca\x05\x93\x22\xfb\xc2\xd9\x2c\x5e\x64\x93\x07\x91\x28\x37\x99\x14\x79\x04\x89\xf2\x22\xab\x60\xc7\x48\xc2\x83\x02\x76\x4b\xb8\xc9\x2e\x27\xe3\x92\x04\xb2\x5e\x12\xec\x32\xb4\x48\x12\x16\x85\xa7\x91\x35\xd1\xd4\xd1\xbd\x68\xb8\xca\x23\xe1\x88\x5d\x76\xc6\x25\x29\xd3\xd4\x8d\xc2\xac\x27\x8c\x3c\x42\x23\x9b\x6f\xee\x62\x0a\xf9\x5c\x18\x11\xcd\x0c\xa1\x30\xf2\x68\xe3\x8d\x4c\xb2\x11\x25\x85\x30\x4b\xb5\xd5\x95\xc8\x37\x22\x87\xd3\xed\xc9\x5b\x10\xd1\x81\xe6\x9a\xe4\xd6\x63\x82\xc3\xa0\xe5\xe3\x4b\x9b\x87\x0f\x2d\xaf\xaf\x5f\xb6\xbf\xff\x4d\x1d\xc7\x71\xdc\xca\x6f\xb6\x1f\xb5\x5a\x0d\x5a\x8d\x73\x51\xcd\xf8\x5f\xac\xa8\x6f\x58\x71\xcd\xc8\x9b\x1b\x9e\x7c\xa6\xbe\xb9\xbe\x19\x79\x5a\x16\xb5\x77\xbd\x86\x79\xa7\xdb\xc9\x57\x37\x1b\xd1\xbe\x40\xdf\xf8\x96\xf6\xd6\xed\x13\xed\x96\xc3\xac\x51\xc3\x0a\x0e\x87\x26\x2a\x6c\x1a\xfa\xb6\xc5\xe9\x31\x78\x1a\xf4\xe5\xb7\xfd\x3d\x93\x57\x2c\xea\x3e\xb4\xa1\xdf\xba\x6f\xa7\x6d\x03\xeb\x8a\xf6\xdb\x3f\x32\xb6\xce\xfa\x1d\x83\x6d\x99\xc5\x6e\xa2\x2f\x3c\x04\xe6\x3e\x61\x15\xde\x0e\x0e\xf0\x80\x08\xdd\xb0\x02\xa6\xa1\xe8\x04\x10\x8b\xed\xc4\xac\x0d\x68\x21\xc0\x89\x45\x17\x51\x23\x9e\x01\xb1\x94\xa4\x37\x4a\xcb\x9b\xda\x79\xb3\x58\x5a\xae\x5e\x85\xac\xf4\x2a\x44\xaf\x10\x9e\xa4\x36\xd0\x6b\x02\x0f\x27\x62\xaf\x4d\x6e\x40\x62\xa9\x87\x5e\x4d\x1b\x7a\x1a\x74\x62\x29\xae\xb2\x26\x9e\x2e\x19\xd4\x56\x8f\x4d\x5e\x82\xc4\x52\x0b\x7d\x48\x5e\x89\x44\x39\xee\x5d\x30\x86\xf2\x92\x1e\xc1\x5e\x74\xb5\x37\x11\xc3\x28\x2f\x77\x0a\x76\xb9\xa1\x45\x92\xe4\x64\x88\x58\x1f\x20\x0c\x71\x5c\x6a\x2c\x51\x0e\xb1\xce\x30\x93\xcb\x76\x31\xf9\xe6\x46\x26\x11\xb7\x30\xe8\x92\x67\x0a\x97\x7c\x1f\xa8\x1b\x58\xdf\xdc\x7c\xd9\x40\x6d\xb2\xff\xb2\x96\xe6\xf5\x03\x75\x76\xe6\x9d\xb7\x66\xab\x73\x26\x57\x48\x10\xc2\x2e\x93\xc9\x15\x16\x84\x90\xcb\x84\xea\xe8\x83\xeb\x07\x6a\x6b\x2a\x0f\x3e\x4e\x1f\x09\xb9\x4d\x26\x77\x88\x3e\xc2\xce\xb4\x6d\x1f\x11\x1b\x46\x76\xb4\x75\x6d\x5f\x52\x57\x3f\xb2\x63\xa6\x97\x9b\xf9\x92\x63\xbf\x08\xa4\x13\x4e\x67\x22\x1d\x08\x64\x12\x2e\x57\x22\x33\xf3\x1f\x6d\xdb\x47\xc5\x86\x51\xf2\xdc\x70\x5d\xfd\xc8\xf6\xf6\x4b\x1e\xa0\x50\x0b\x3a\xe7\xde\x61\x7f\xc3\xdb\xa0\x19\xfa\x60\x02\x8e\x40\x31\x03\x20\xca\x6d\xbc\x52\x34\x33\x20\xca\x63\x5a\x05\xe1\x15\x84\xe6\x72\xde\xac\xe0\xbc\x0d\x2f\x8a\x9e\x15\x88\xb1\xc2\xba\xb4\xbc\xc8\x44\x6e\x51\x79\xb7\x9b\x14\x79\x92\xc8\x7d\x5e\xb0\x63\x5e\xc2\x23\x42\xc9\x9c\x69\xeb\xf2\x10\xd9\xb6\xdb\x8b\x5e\xb1\x93\x52\xb8\x2d\x23\xd8\xe5\x3a\x51\x92\xf0\x98\xf0\x14\xe8\xec\x35\x5d\x83\x55\x9e\x0a\x91\x0b\x8d\x28\x7f\x01\x1d\xb5\x9e\x2e\x54\x68\x69\xee\x42\x05\x8f\x05\x69\xc3\xac\x47\x9b\xb4\xb0\xe7\x89\xdb\x52\x60\x2d\x2c\x11\xfd\x2e\x56\xa5\xb2\xa6\x93\x10\x77\x68\x71\x66\x62\x7f\xd7\xa2\xbd\xcb\xc4\x50\x7e\xa4\xf1\x49\x47\x40\x87\x58\xbd\xf1\xd9\xe4\x48\xd4\x5a\x55\x95\xb0\x3e\xb1\x35\xb2\x64\x62\xaa\x61\xe5\x0d\xab\x1b\x3e\x74\xd7\x16\xa2\xd2\xba\xe8\xff\x17\x4b\x07\xcd\x1b\xeb\x33\xbe\x6a\xaf\xc9\xe4\x8d\xbb\x33\x19\xd4\xd4\x7e\xcd\x15\x6b\x22\xcb\xfe\xaa\xbf\xe3\x8a\xa5\x0d\x4d\x63\x3b\x5a\x32\x9b\xd7\x8d\xfa\xbe\xf0\xb5\x05\x4c\x7e\xaf\x5b\x7f\x43\xdf\xe1\xb4\xab\x31\xdd\xe8\xbc\xfe\xa1\x48\x4b\xad\xa7\x79\xed\x5f\x5c\x1e\xef\xcd\x45\xfa\x9b\x90\xe8\x2a\x74\xf7\x32\x27\x92\x9b\xbb\xac\x0d\xb9\x16\xbf\xbf\x31\xe1\x5c\x44\x71\x03\xda\xcf\xb6\x33\x4f\xf0\xfb\xc1\x0e\x49\xc0\xf6\x74\xc5\x05\x22\xe2\x10\x55\xff\x27\x3b\x17\x9c\x9e\x9d\xba\x39\x74\xb1\x9b\xb3\x22\xb4\x3f\x3f\xef\xd2\x32\x55\xee\x3e\xe9\x12\xef\x35\xf0\xd4\x43\x80\xe0\xd3\xf2\x37\xd9\xab\xf9\xf5\x10\x02\x07\x20\x1c\xa6\x9c\x73\x98\x14\x39\x82\x44\x62\x62\x9b\xed\x84\x9e\x9a\x44\xbc\x26\x51\x8f\xb4\x16\xd6\xe5\x0c\x33\x1e\x6d\x23\xc3\x7c\xba\xec\x1b\x3f\x39\xb6\xc1\x69\x35\x39\xf5\xac\x86\x1f\xbb\x7e\x2a\xdd\xb1\xff\xa1\x2d\x6b\xbf\xfa\x93\xaf\x2f\x65\x4c\xf7\x20\xee\x9f\x1e\x6b\x3d\xa3\xd3\x30\xe9\x1b\xbe\xf7\xfa\x35\x87\xde\x3d\xf3\x57\x6d\x0f\xf4\xfe\xe8\x23\x64\xa0\x98\xe8\x96\xf2\xed\xac\x8d\x62\x16\xd2\xa7\x33\x8d\xf9\xb3\xb2\xc5\xa4\xc8\x2e\xda\x27\x65\x10\x93\x2c\x84\x19\xbb\xcb\xc9\x58\x90\xf6\x96\x9d\x7f\x7d\xa0\xfd\x67\xff\xd0\x72\xdb\x3f\xdd\x3f\x3e\xf9\x97\x1f\x9c\x7c\x2d\x73\xcf\xd3\xff\x78\xe0\x63\xb4\xe5\x8a\xa2\x74\xfa\x5f\xcb\x5f\x9e\xbc\xbd\xfc\x3b\xe5\x39\x49\xc5\x5b\x83\xf0\x26\xfb\x2a\x97\x23\xd1\xa6\xa3\xc0\xb3\x39\xb6\xda\xc3\x3b\xb4\x46\x94\x74\x0c\x0e\xa1\xea\xe0\xff\x11\x51\x68\xb4\xfc\xe2\xaf\x1e\x7d\xed\xcd\xef\xfe\x07\xf3\xda\x73\x27\x50\x7b\xf9\xd5\x1b\xf0\x96\xf2\xc7\xd7\xa3\x54\xf9\xad\x1b\x90\x1b\x10\x4c\xc2\x07\xec\x69\xae\x1d\x8c\x30\x01\x18\xd2\x58\x9b\x93\x11\xaf\x60\x7e\xc1\x0d\x1b\xf4\x62\x11\x01\x69\x22\x96\x98\x7d\x53\x1a\x1b\xce\x62\x26\x2b\xeb\x4d\x0a\xe6\xb2\x45\xbd\x81\x7c\xa7\xd7\xea\xc5\xa2\x41\x4f\x9a\x06\xd0\x8b\xb2\x59\x25\x69\x3e\x26\xe4\x84\x98\x2b\x26\x24\x84\x49\x34\xf9\x1a\x1a\x2a\x3f\xfb\x1a\xd3\xff\x24\x1a\x2e\x3f\xfd\x64\xf9\xdb\x68\x87\xca\xff\xa6\xf2\x29\xe6\x3e\xf8\x02\xbc\x50\x0b\xd8\x9b\x2e\xd9\x0c\xa0\x25\xfc\xf7\x51\x6a\xb9\xcc\x4a\x91\x77\x19\xc4\x69\xe0\x8d\x7a\x51\xf6\xd3\x5f\xe6\x09\xe1\x6a\x92\x17\x6a\x85\x46\x8b\x9a\x82\x4d\x55\x4e\xbb\xc9\x5f\xef\xae\x95\x12\xd1\xce\x74\xf0\xc8\x57\x7e\x1b\x90\x5a\xd2\x36\xa3\xc3\xe8\x6e\x4a\x84\x9b\x93\x9e\x60\x76\xa0\x7e\xfc\xf5\x63\x94\x7e\x37\x31\x39\xf6\x26\xe6\x37\xc0\x82\x87\xcc\x5d\x46\x9c\x42\x5e\x08\x73\x69\x99\x9f\x9f\x80\xeb\x26\x16\x98\xdc\x8f\x7e\x04\x08\xad\x9a\xfb\x88\x39\x0e\x33\xe0\x80\xfc\x79\xf4\x69\xe5\xc4\x0b\xdb\x94\xc7\x2a\x12\x75\x71\x62\xe5\xa3\xc2\xed\x4b\xa1\x25\x5a\xe5\xad\x2f\x44\xc2\xad\xf5\x3e\x6f\x7d\x6b\x24\xda\x5a\xe7\xd9\x1f\xca\x25\xdd\xbe\xba\xac\x2f\x98\xad\x71\xbb\xab\xb3\x2a\x9f\x77\xcd\x3d\xcc\xde\xcf\xaf\x22\x31\xbd\x07\x79\xd0\x2e\xe6\xda\xe9\xd9\xe3\x06\x7e\xe3\xfa\x2f\x4e\x51\x3b\x35\x38\xf7\x1e\xfb\x3c\xef\x01\x37\x54\x41\x16\x96\x40\xd1\x4e\xec\x54\xad\x41\xa1\xae\x43\x8e\xea\x15\x84\x73\x54\xda\x3d\x66\x05\x7b\x6c\x14\x43\x9a\xcd\x8a\xdc\x8c\x44\x39\xe5\x11\xec\xd3\x76\x3e\x54\x5d\xe5\x91\x40\x8e\xd6\x0a\xf6\x69\x33\x04\xb3\x0b\x96\x87\x0c\xd8\xe3\xb6\x5f\x68\xbd\x3d\xa8\x11\x11\xcb\xed\x08\xa3\x79\x43\x9e\x1c\x5c\x7c\xf4\xe1\x35\xb9\x55\x23\xbd\xd1\xee\x25\x4b\xae\x7d\x64\xf5\xba\xef\x1e\x19\x7c\x9f\x61\x59\x06\x5d\xed\x9b\xc8\xa5\xc6\xbb\xaa\x17\x55\x3e\x19\x96\x43\xcc\xd5\xf7\x7e\x56\xdc\xe2\x69\x5c\x94\x5a\x51\x9e\xf9\xee\xf7\xff\xf0\xd7\x63\x9b\xf0\xef\x7f\x68\x6f\x48\xd5\x5b\xd0\x47\xed\xfd\xbd\xd7\x7c\xaf\xdc\xd4\xde\xdf\x7b\xf5\xf7\xb6\xd9\x53\xa9\x3a\x2b\x20\x78\x00\x80\xb9\x83\x9b\x01\x0d\xe4\xa0\xc8\x11\x3f\x89\x18\x02\x2b\x39\xa4\x13\x11\xd6\x52\x4b\xc1\x9a\x15\x59\x87\x44\x99\xe5\x28\xbe\x00\x19\x69\xa8\xc1\xcd\x34\x39\xaa\x73\x42\x42\xd0\x3e\x80\xd6\x7e\xfb\xe7\xef\x73\x7d\xcf\x7d\xc9\xb1\x9f\xf5\x51\xda\xee\x07\x60\xef\xe0\x7d\xd0\x08\x6b\xa1\xe8\x21\x74\xb3\xea\x14\xb5\xe1\x32\x28\x45\x96\x10\x30\xc9\x2a\x08\xa7\xd3\x38\x7e\x56\xd6\x59\x15\xec\xca\x16\xe3\x3a\x22\xe9\x71\x8f\x5e\x94\x33\x48\x94\x75\x71\xc1\x8e\x1d\x12\xc8\x56\x8f\x60\xc7\x5e\x49\x4e\xba\x04\x7b\x09\x4c\xba\x48\xa3\x4a\xc7\x2e\x54\xe1\x3b\xa7\x8d\x75\xb1\x39\x57\x2c\xdf\xc5\x16\xe6\x8d\xb3\x85\xd3\xee\x6f\xfb\x87\x5b\x56\xdf\xb5\xab\x43\x5a\x77\xe5\x95\x3b\x12\xe8\x59\xa3\xcd\x66\xb7\xcc\x7c\x1c\x5c\x3e\xb5\xbe\x3e\xba\x7c\xa0\xd1\x97\xea\xa9\xc9\x74\xd7\x7a\x6c\x66\x03\xe7\xb9\xee\xe6\x8e\x1d\xb7\x8d\x2e\xbb\xf5\xf0\xbe\x83\xd7\xf4\x23\xa3\x49\x7f\xee\xfa\x81\xeb\xae\xdc\x96\x8a\x8f\xae\xda\xd8\x52\xbd\xa8\x29\xe4\xab\x49\xa7\xaa\xf5\xaa\xec\x6c\x9c\x7b\x8f\x3d\xc1\xfb\xa0\x0f\xf6\x42\xb1\x87\x4c\xcb\xa8\x57\x8a\x0d\x64\x5a\xd5\xac\x52\x0a\xb8\x7a\x1a\xcc\xa2\x1c\xd0\x28\xd3\xb5\x04\x22\x20\xbc\x28\x8d\x6d\x67\xe5\x76\xa3\x82\xdb\x6d\xb8\x89\x38\xb4\xa8\x51\xc1\xd1\xb4\xdc\x64\x54\xe4\x7e\x82\xe2\x6c\x82\x1d\xb7\x48\x20\xbb\x8c\x82\x5d\x46\xed\x92\x24\xd7\xf6\x08\x76\x39\xda\x24\x49\x72\x43\xb5\x60\xc7\x75\x0b\x50\x8d\xbd\xd0\xd1\x6b\xf3\x0b\x17\x1a\x6d\x72\x81\x24\x8c\x56\x05\x6c\x89\x78\xcd\xc6\x47\xf4\x3a\x8d\x56\x6b\xaa\xc9\xb4\xf8\xeb\x87\x5b\xa3\xd5\x7d\x6b\xf3\xbc\xd9\x5b\x1b\x59\x7f\xdd\xd2\x98\xbb\xbe\x33\xd9\xb4\x5b\xba\xa9\x5f\xbe\x62\xe5\x9d\x3b\xdb\xa2\xf9\xde\x58\x72\xb4\xa3\xaa\xed\xc0\xf7\x76\xef\x7a\xee\x96\x57\x35\x26\xc1\x63\x73\x25\x7c\xd6\x60\x61\xac\xb9\x71\x71\xd6\x8f\x10\x42\xcf\x06\x9b\x47\xd2\x51\xa9\xde\xd7\x32\x70\xcf\xba\xf1\xfc\x86\x1b\x97\x65\x57\x0d\x64\xad\x96\xb6\xc9\xdd\xdd\x53\xdf\xdc\x21\x2d\xa7\xb1\xcb\x14\x00\xfb\xff\x71\x33\x60\x00\x33\x6c\x84\xa2\x9e\x48\x17\x43\x40\x17\x18\xf5\x8c\x59\xc4\x5c\x4e\x06\x4e\xc1\x9a\x2c\xc2\x96\x34\x36\x9d\xc5\xfa\xac\xcc\x99\x15\xac\xcd\x16\x39\x13\x11\x04\x4e\xa3\x17\x8b\x26\x8e\x34\x4d\xc4\xfa\x59\x91\x28\x73\x26\xc1\x8e\x19\x09\x64\x23\xa8\x68\x97\x11\xb0\x99\xc8\x42\x1e\xe5\x84\x9c\x2b\x21\x24\x84\x64\x4c\x98\x62\xea\xbe\xf7\xf8\xe3\xbf\xfc\x02\x31\xa8\xfd\x1b\x6c\xd3\x4c\xf9\xc7\xe5\xd7\x50\xfb\xb3\xe8\x18\xe1\xdd\xde\xb9\xf7\x58\xcc\xcd\x40\x0a\x96\x41\xb1\x8e\xf0\x4e\x6f\x50\x8a\x5e\xc2\xbb\x00\xab\x94\x22\x8e\x3a\xaf\x59\x94\x23\x3a\x05\xe1\xc6\x34\xb6\x9c\x95\xab\x8c\x8a\x9c\x46\xa2\x5c\x65\x11\xec\xb2\xcf\x4f\x40\x85\x43\x4f\x24\x11\xb9\x3d\x55\x14\x49\x0b\x38\x78\x1e\x47\xe7\x2e\xe4\x87\x23\xe6\x8a\x69\xcf\x33\x85\xe8\xfa\xde\xd3\x7a\xbd\x86\x63\x5d\x97\x2f\x11\x47\x0a\xd1\x50\xf3\xe2\x86\xae\x0d\xa9\xbb\xd3\xcc\x93\xe5\x80\x50\x35\x50\xbd\xee\x9e\x9d\xad\xed\xfb\xff\x6a\x53\xcf\x35\x3b\xd7\xbe\x71\x82\xb7\xd8\xed\xfa\xc6\xbe\x48\xf7\x86\xae\x8e\x0d\xbd\xb1\x8e\xee\x6e\xe6\xa1\x97\xff\x60\x34\x76\x5c\xf9\xbd\x2b\xb6\x9e\x3a\xdc\xe7\x6f\x5b\x4f\x68\xbd\x73\xee\x3d\xf6\x11\xde\x03\x75\xd0\x01\xfb\xa1\x58\x4d\x66\x95\x9e\xb7\x54\x02\x91\x48\xa9\x9a\x27\x12\x69\x50\x10\xee\xa4\x46\xab\xde\xaa\x60\x77\x16\xd7\xdb\xa8\xbd\x8a\x1a\x15\xb9\x0b\x89\x72\x73\xbd\x60\x9f\x16\xf8\x00\xb1\x5b\x38\x2a\xc8\x66\x1d\x99\xae\x94\x26\x31\x44\x54\x92\x70\x80\x06\x17\x82\x1d\xeb\x25\xcc\x0b\x58\x27\x55\x3c\x7c\x2e\xeb\xf6\x68\x1b\xd9\xa4\x6a\xc2\xb4\x5d\xec\x9f\xc7\xa6\x1a\xed\xce\x81\xeb\x7e\xb8\x6b\xea\x91\xa1\x6f\x1b\x8d\x5a\xad\xd6\xd9\x5f\x5d\xbd\x6c\xa0\xd9\xe0\xcc\x16\xda\x82\x63\x5f\xbb\xa2\xa3\x7b\xcf\x5d\x2b\xb6\x3d\xb4\xb7\xed\x57\x84\x36\xf1\xce\x46\x7f\x24\xd3\x19\x2e\x5c\x11\x67\x46\x4f\x21\xc3\x33\x5b\x96\x2d\x3e\xc5\x9a\x05\x97\xc9\x13\xae\x9a\x38\xbe\xc5\x99\xf0\x5b\x7b\xae\x7a\x78\xe3\xc6\x53\x47\x07\x2f\xfb\xfe\xbf\x55\x75\x5e\xb9\x3a\x1f\xed\x5c\xdb\xde\x31\x25\x05\x17\xb5\x12\x7e\x1f\x07\x60\x8f\x53\x39\xac\x83\xa2\x76\xde\xc6\xc9\x40\xec\xb7\x91\x06\xc2\x1a\xab\x22\x9b\x90\x08\x32\x22\x42\xc5\x4a\xaa\x87\x32\x20\x36\xe1\x47\x8e\xe3\x2c\x1c\xfe\x5f\x97\x7d\xb6\xee\xa5\xbd\x5c\xee\xf5\xab\xcb\x9f\xce\x3e\x53\x7e\x0b\xd9\x98\x30\xe2\x81\x85\x55\x73\xef\xb1\x4f\xf0\x21\x48\x42\x3b\x2c\x85\xab\xa0\x98\x20\x94\x4f\x19\x94\xa2\x95\xf4\x31\x4c\xfa\x58\x46\xc9\x5d\x6b\x55\x70\xad\x0d\x77\x10\xd5\x37\x18\x15\x6c\x48\xcb\x1d\x46\x72\x4b\xce\x22\x51\x0e\x5b\x15\xdc\x4f\xbe\x72\x1a\x15\x79\x39\x12\xe5\x0e\x83\x0a\x6a\xfb\x85\xe9\x44\xaa\x60\x25\xdc\x70\xda\xb1\x4f\x02\x79\x38\x25\xd8\x9f\x02\x83\x33\x5c\xe8\xbd\x00\xc7\xb2\x17\xe1\xd8\x79\xd5\xbf\x98\xf4\x49\x82\x5e\xc3\x8c\x87\x44\x6d\xaa\xed\x58\x15\xef\x5e\x95\xaf\xe9\x4d\x07\x3a\x76\x9c\x5c\x36\x76\xdb\x56\x29\x94\xeb\xaf\xc9\x4e\x76\xc6\xfb\xae\x7a\x70\xed\xba\x07\xaf\xec\xfd\x6d\x38\x37\x50\x53\xbb\x28\x13\x08\xb7\x2c\xcd\x24\xda\x1a\xbc\x4d\x81\xc6\xce\x78\xf3\x80\xa7\xb6\x25\x12\x69\xae\x76\xa1\xd1\xdc\xe6\xb5\xcb\x42\xbe\xde\x25\xe3\xf5\x83\xd7\x5d\x56\xc8\xaf\x3b\xba\xa8\x7e\xc5\xe8\x22\x5f\x70\x64\xed\xd6\xfc\xd8\xc9\x6d\x6d\x6d\x5b\x8f\xaf\xaf\xea\xcd\x84\x02\x8d\xdd\x55\xd5\x83\x9d\x59\xc1\xde\xd4\xbe\x88\x19\x8f\x4a\x4d\x75\xf6\xc4\xf6\xd6\x40\xb6\xc6\xed\xaa\xce\x10\x19\x26\xb4\xbc\xf3\xbc\x0c\x13\xef\x2f\x07\xf4\x15\x19\x6e\x35\x28\xa5\xea\xb4\x95\xc8\x70\xf5\x05\x32\x6c\x54\x88\x00\x67\x91\x88\xa3\x59\x42\x56\x2a\xc3\xf5\x20\xd8\x65\xbb\x47\x92\x70\x56\x98\xb6\x06\xaa\x79\xea\x83\x03\x24\x3c\xb6\x4b\xb8\x5a\xc0\x0e\x09\xa7\xed\x38\x2a\xe1\x56\xe1\x8f\x22\x2e\xc6\x82\x12\xf1\x9a\x64\x61\x41\x95\x0b\x17\x87\x00\x0b\xa4\xeb\xde\xf3\xcd\x15\xdb\x1e\xda\x27\x0d\x1c\xbb\x54\x96\xfb\x9b\x8d\x0b\xb2\xfc\x0b\x22\xbb\xad\x57\xc4\x89\x28\x27\x3a\x53\x01\x76\x82\x08\xea\x86\x53\xbf\xbc\xed\xfb\xe5\x3f\x3c\xbb\x79\xf9\xf0\xbc\x2c\x27\x26\x6e\x5d\x90\xe5\xce\x29\x29\xd8\x5f\xa8\xee\x3c\x44\x44\x79\x1d\x00\x83\x06\xe7\x3e\x62\x0e\xb3\xd7\x82\x03\x92\x20\x5d\x84\x92\x70\x22\x5d\xf2\x55\x30\x52\x2d\x21\x0a\x76\x66\x2b\xf8\x08\x87\xe7\x5b\x72\xdd\x9f\x44\x4a\xc2\xa5\xc8\x69\xd0\x57\x57\x08\x07\x0b\x0d\x01\x6f\x7d\x6b\x34\x5a\xa8\xf5\xce\x5f\xfb\xea\x5b\x23\xe1\x42\x9d\x8f\x22\x29\x57\x4d\x2e\x52\x41\x52\xcc\x43\xc1\x5c\x8d\xdb\x59\x9d\x8b\x84\xb2\x49\xb7\x3b\x99\x05\x06\xc5\xca\xa7\x98\xe3\xec\xb5\xe0\x85\x06\x58\x0c\xb8\x36\x5d\x0a\x57\xc6\x97\x4a\x63\xdf\x59\x6c\xcc\x96\x12\xea\xf8\x12\x36\xec\x22\x42\xcf\x9b\x15\xcc\xa7\x09\x24\x95\x1b\x91\x28\xf3\x3e\xea\xee\x71\x42\x28\xda\xc2\xb5\x6a\xfe\xf0\x4f\x22\x53\xf6\xd2\xf1\xc7\x42\xd9\x2a\xa7\xdd\xec\xaf\x73\xd7\x16\xe2\xb1\xce\x4c\xf0\xc8\xd1\xb1\x4b\xa7\xf0\x67\xa0\x2b\xb7\xe4\xd2\x99\x10\xdb\xd1\x07\x63\xec\x8f\xb9\xc7\x40\x03\xe0\xc8\x23\x97\x1e\xb9\xfa\xd8\x23\xb3\x37\x30\xb7\x32\xeb\x0f\xa3\x77\xde\x28\x3f\x5b\xbe\xf7\x7d\x22\xbb\x93\x68\x3d\x7b\x9a\x7d\x82\xe6\x66\x83\x40\x73\x73\x32\xc7\x2b\x14\xfe\xf2\x0a\x22\x91\xab\x7e\x01\xfa\xa2\x7c\xcc\x35\xc9\x6e\x9e\x79\x88\xdd\x8c\xd6\x3f\xf9\x24\x7a\xe4\xc9\x27\x49\x5f\xa3\x30\xc6\xbe\xa1\xf6\x55\xc8\xeb\x51\x1e\xb9\x46\x99\x9b\x66\xaf\x67\x8f\x8d\xbd\x8f\x76\xa3\xa1\x37\xca\xe2\x61\xea\x57\x0f\xce\xfd\x9c\xbd\x93\xdf\x08\x75\xd0\x09\x3b\xa0\x28\x11\x59\x48\xab\xb2\x50\x95\x96\x79\x8d\x82\x70\x57\x1a\xbb\xcf\xca\x2e\x93\x32\xed\x72\xd7\x5b\xc4\x52\xb3\x4a\x6f\x97\x8d\x04\x65\x54\x4f\xba\x91\x28\xbb\xdc\x82\xbd\xc4\x87\xaa\xd2\x52\xc5\x89\xd9\x24\xd9\xd0\x2c\xd8\xb1\x55\x02\xb9\x2a\x2d\xd8\xa7\xc1\xe0\xaa\xab\x40\xad\x05\x83\xae\xb5\xb0\x21\x94\xa0\x89\xa2\xf3\x86\x44\x7b\x69\xca\xe2\x60\xd5\xba\xdd\x87\x7b\xa6\xbe\xbe\x39\x1f\x29\x2c\x6d\xf4\x04\xcc\xdc\x1b\x9a\x40\x6b\xb6\xab\xc9\x2b\xb6\xc7\x6b\x06\x7a\xda\xfd\x87\x89\x8c\x05\xf2\x0d\x01\x6f\x5d\x21\x12\x6d\xad\xf7\x72\x57\xb7\xac\xee\x8c\xb5\x6f\xbf\x75\xa4\x6d\xdd\xb2\xc5\xd5\xf6\x5a\xb1\x29\x78\xf0\xa0\x38\x38\xb4\x34\xdb\xb5\x2d\x5b\xdd\x9b\x09\x86\x9a\x87\x53\x33\xc7\x83\xcd\x49\x8f\xbb\xa6\x39\x4c\x4c\x87\xbb\x26\x4b\x69\x92\x9b\xfb\x05\xfb\x3a\x1f\x82\x66\xe8\x85\x5b\x2a\x19\x85\x3a\x6d\xc5\x76\x44\xb4\x4a\xc9\xd6\x9a\x21\xb6\xc3\xa6\x55\x4a\xfe\x4e\xda\xf4\x6b\x15\x84\xfb\xa8\x19\xa9\x32\x29\xb8\xca\x46\xc2\x09\x39\xaf\xe6\x17\x4c\x48\xc4\x9d\x59\xd9\x68\x52\xe4\x45\x48\x94\x4d\x79\xc1\xfe\x14\x6f\xf3\x47\xea\x32\x84\x54\x46\x41\x6e\x48\x11\xbf\x68\xab\x13\xec\xb8\x81\xda\x11\xa3\x59\x92\x70\xa7\xbd\xe8\xaa\x02\xe9\x22\x8b\x22\x24\xf2\xc4\xa4\x34\x32\x79\xd5\x50\x13\x72\xb9\x2a\xc6\xc4\xa3\x7e\x53\xed\x74\x53\x1b\x6d\x61\x73\x53\x77\x3e\xb5\x61\xc3\xfd\x7b\xda\x7e\xe4\x5f\x97\x6f\xdf\x36\x22\x66\x77\x3d\x7a\x25\x1f\x97\x46\x53\x6d\xfb\xa7\x5a\x3a\x77\xdc\xb6\x24\x7b\x48\x9a\x18\xfe\xf6\xda\x03\x7f\xff\xad\x29\x74\xae\x3d\x53\x9f\x8f\x9a\x7a\x2e\xeb\x08\x31\x27\xbe\xff\xd9\xa3\xe3\xdd\x37\xbd\x7e\xb2\x3c\xd8\x1d\x6d\x14\x47\x77\x74\x8e\x1e\x9d\x4c\x31\x99\x31\x29\xda\x79\xed\x73\xd7\x5d\xfb\xe2\x4d\xfd\x89\xa6\x6f\xb5\x8a\xab\x1e\x2f\x1f\xef\x5c\x92\x18\xde\x3f\x8a\x02\x0d\x52\x65\xc5\x8f\x63\x78\x3b\x68\xc1\x40\xa2\x00\x00\x10\x31\x9b\xa3\x4e\xb2\xa4\xd1\x01\x32\x8b\xb2\x46\xab\xfa\x4a\x38\x2b\x6b\x17\x7c\xa5\x4e\xb0\x63\x83\x94\x69\x6a\x42\x39\x94\x60\x63\xac\x23\xc6\xa2\xc7\x6f\x41\x6f\x7f\x7a\x55\xb9\xb8\xf5\x38\x62\x6e\xe1\xed\x5f\xfc\x06\x2d\x29\x9f\x46\x0a\x7a\x0c\x58\x98\x00\x60\x5f\xe5\x66\xc0\x0d\x09\xc8\xc0\x16\x28\xba\x09\x97\x3c\xac\x42\x51\xa1\x9c\xd1\x29\xa5\xaa\x84\x9b\x31\x8b\x72\x15\x89\x16\x9b\xd4\xd0\xca\xa8\xe0\xaa\x2c\x89\xae\x42\x48\x94\x05\xab\x82\xeb\x89\xc5\xd0\x1a\x15\xea\x37\xb5\x21\xc1\x8e\x4d\x12\xc8\x09\x12\x22\x08\x12\xae\x12\xb0\x49\xc2\x19\x3b\xd6\x4a\x99\xa6\x9c\x10\xbb\xc4\x23\x26\xe7\x7d\xa1\x88\xf2\xe7\x9b\x13\xe8\xa6\xab\x1e\xdb\xd7\xec\xaa\x93\xaa\x52\x23\x2d\x91\xf6\x6b\xcf\x7c\xf5\xc1\x62\xcb\xea\xae\x58\xa8\x7b\xc7\xf0\x5d\x5f\xeb\x5d\x53\xf0\xfa\x9b\xc7\x5b\x1e\xe6\x66\x32\xab\xbf\x32\x5c\x33\x3a\xd0\xee\x74\xf5\x4f\xac\x6f\x9c\xbc\x7d\x73\xcb\xcb\xf6\x86\xa1\x7c\x6a\xa9\x14\x7d\xce\x5b\x2f\xc5\x88\x81\x21\xba\xdc\x3e\xf7\x3e\xfb\x11\x1f\x82\x7a\x42\xd1\x1a\x32\xcf\x08\xab\x14\xb5\x64\x9e\x2e\x32\x39\x91\x4e\xce\x6f\x55\xe4\x06\x42\x4b\x57\x44\xb0\x97\x4c\x60\x8e\x27\xe6\x5d\x3a\x47\x03\xc4\xf3\x88\xea\x12\x89\x69\x17\x47\xb6\x1e\x3c\x22\x2d\xbe\x79\xff\xea\xe0\x3f\xe8\x35\x88\xe1\x43\x9b\x47\x3b\xb7\x0c\xd6\xd4\x2d\xd9\xd9\xb5\xe4\x40\xea\xc9\xc5\xff\x70\xf4\xe0\x8b\x77\x2c\x67\x0e\x1f\x7b\xed\xbe\x5d\x8b\x22\xf5\x4b\x77\xf7\xee\x60\x4d\x82\xdb\xd4\x37\x32\x70\x5d\x71\xcf\x15\xf2\x8d\xc3\xeb\x96\x1f\xfc\x8b\xeb\xc6\x4f\x7d\x49\x64\x60\x2d\x00\xfb\x53\x6e\x06\xac\xe0\x87\xd6\x8a\xef\xb5\xf1\x15\xce\xf8\x09\x14\x0e\xd0\x11\xdb\xcc\x0a\xb6\xd9\x68\xe2\x88\x58\x91\x20\x19\xbc\xdf\x56\x11\x04\x95\xdc\x1e\x35\x79\x4c\x48\xdd\xa2\x92\x77\x2d\x5a\xb2\xf2\xc6\xad\x4b\xa3\xbd\x7d\xbd\x77\xfc\xec\x81\x89\x65\x4f\xfd\xa0\x7a\xfc\xba\x35\x5b\xb8\x19\x6f\xaa\x4f\x9c\xfa\xf7\xbb\xbe\xa9\xfc\xf5\x54\xe9\xa3\xb3\x7b\xfe\xf6\x48\x37\xa1\xdd\x21\x00\xb6\xc8\xcd\x80\x11\x86\x54\x69\x94\xf5\xac\xa2\x62\x36\x8e\x55\x4a\xbc\x2a\x92\x3c\x81\x56\x26\x3a\x28\xbd\x59\x4d\x99\xd0\x74\x8a\xde\xa8\x17\x31\x93\x55\x73\x27\x95\x84\x89\x9a\x2c\x51\x5f\x87\xd8\xee\xd9\x87\xd1\x67\x65\x1d\xb3\x9e\x9b\x79\xb5\xfc\xea\xeb\xe5\xbb\x5e\x55\x63\xba\xdb\x01\xd8\x47\xb9\x19\xd0\x43\x8f\xda\xef\x1f\xf7\x49\x08\x61\x50\xfb\x34\x5e\xd8\x27\xab\xaf\x24\x6b\x64\xe3\x25\x1d\xde\xce\xfa\x66\xdf\x44\xff\xa3\xdc\xc6\xcd\xbc\x5c\x7e\xe7\xc5\xd9\xa2\xda\x57\x6c\xee\x7d\xf6\x0c\x1f\x82\x0c\x1c\x86\x62\x03\x99\x63\x6c\x5e\x3e\x3c\xac\x52\xaa\x49\x36\x68\xcd\xa2\x5c\xc3\x2e\xe8\x41\xd0\xaa\xe0\xa0\x4d\xae\x42\xa2\x5c\x67\x56\xb0\x29\x5b\xac\xaa\x23\x5d\x57\xd5\xe8\x45\xaa\x09\x55\x41\xc1\x5e\xd4\x7a\x1a\x24\x49\xc2\x75\x82\x2c\x98\x89\x7d\x8a\x35\xd0\xb8\x51\x4e\xd6\x08\x76\x0c\x12\xf6\x08\x45\x93\x39\x38\x6f\x9f\x2e\x90\xb1\x8b\xac\x52\x3e\x91\x8f\x09\xaa\x9c\xc5\x72\x93\x7b\x0f\x5d\x99\xee\x3d\xbc\x73\x32\x72\xa7\xdd\x6d\xd2\x72\xa6\xba\xe6\xae\x78\x6e\xeb\xf2\xa6\xfa\xd1\x1d\x5d\x8d\x1b\x6b\xdf\x43\xc5\xf5\x2f\x1f\x38\xf6\xd2\xcd\x03\xcc\xf5\xb7\xfe\xe4\xde\x2d\xed\xbe\xaa\xbe\xf5\xad\x77\xe9\xac\x36\x9b\x3e\xd8\x54\xe3\x6e\xda\xf7\xc3\xeb\xaf\x7a\xe6\xfa\x7e\x77\xe4\xd3\x97\x66\x3f\x5e\x3a\xb0\x65\xfa\x33\x40\x34\x36\x7c\x8e\x9b\x01\x1f\x5c\x5e\xb1\x38\x2e\xd5\xe2\x60\x53\xae\x64\xf0\x52\x6a\x1b\x08\xb5\xfd\x74\xf6\x3e\xab\x42\xa3\x43\xab\x82\x7d\x74\x7d\x0a\xbb\xb3\xb2\xd3\xaa\xd0\x2c\x66\x80\x84\x85\x3e\x1a\x16\xca\x56\xa7\x60\xc7\x66\x09\x64\x64\xa0\xf6\x80\xb0\x22\xa7\x2e\x33\x0a\xb1\x85\x56\x42\x88\x09\x53\x5f\x70\xbc\x46\x83\xd0\x11\xf5\xf3\x93\xf2\x6d\xdc\x0c\xa7\xe1\xf4\x16\xa7\xb5\x3c\xc8\x30\x95\xe6\x97\xa3\x4c\xfb\x6c\x45\x3e\xee\x03\x60\xaf\xa6\x72\xd9\x0f\x45\x23\x95\x4b\x4e\xc1\x28\xab\x3a\x19\x4e\x47\x22\x57\x2a\x92\x0c\x15\x8f\xa2\x9e\x99\x4f\xe1\x61\x43\xb6\xc8\xd0\x2c\x1e\xc3\x9d\x17\xca\x7c\x4e\x48\xe4\x63\xae\x84\x10\x73\xdd\xf7\x87\x7f\x67\xfe\xfe\x0f\x88\x79\x9e\xbd\xfe\x85\x17\x66\xae\x3f\x43\xfb\xcb\xcd\x7d\xc0\x9e\xe6\x66\x20\x08\xa3\x50\xf4\xd3\x1c\x03\xab\x14\x05\xd2\x99\x4d\xa7\x60\x47\x16\xe1\x10\x8d\x4f\x5d\x46\xa5\xe8\xb2\x90\x9f\x77\x39\xf4\x62\xd1\xe2\x22\x4d\x8b\x4d\x2f\xca\x61\xa2\x9f\x46\xbf\xca\x7c\x9b\x80\xd1\x85\x29\x84\x96\x7c\xa5\x7f\x35\x4b\x90\xbb\xcb\x60\xd4\xe9\xb5\x26\x5f\x54\x0c\x8d\x0c\xfe\x9a\xb9\xfb\xc5\xb6\xad\x37\x8f\xec\xf8\xc1\x9d\x98\xb5\xba\x7c\x66\x5b\xc8\x6d\xbe\xe1\x6e\xe6\xf8\x0b\x2f\xcc\x5e\x7e\xf5\xdf\xec\x6d\x5e\x4b\xc7\x38\x35\xf7\x7b\xce\xc4\x9b\xc0\x05\x5d\x15\x3e\x0a\x2a\x1f\x65\xa3\x25\x97\x43\xd8\x4d\xd9\xe7\x5a\x60\x9f\xec\x21\xcc\x72\x55\x62\x78\x12\x6e\xd1\x05\xd7\x0b\xd9\x84\xc2\xa8\x1d\xe9\x11\x8f\xb4\x0b\x3c\x2a\xc6\xbb\x3c\x77\x94\xab\xd1\xaf\xcb\xbf\x2a\xdf\x52\x38\xcf\xa7\x8d\xe8\x33\x9d\x6e\xf6\xe7\xb3\xd5\x26\x66\xac\x63\xf6\xf7\x80\xe0\x18\x00\xfb\x04\x8d\xf5\xda\x2b\xb6\x43\x57\xb1\x1d\xf3\xfe\x4b\x67\x55\x8a\x3a\xaa\xb5\x3a\x83\x5e\xc4\x60\xa3\xc3\x32\x91\x61\xe9\xd4\x61\xcd\x0f\x46\xa3\x15\x62\xae\x63\x5f\x70\x56\x8e\xe9\x27\x7d\xea\x3c\x91\x19\xf3\x8f\x55\x59\xe8\xa4\xf6\xb2\x0c\xa6\x79\x1b\x85\x35\xb9\x22\x47\xe4\x17\xa9\x9f\x08\x9b\x69\x77\x26\x93\x82\x4d\x36\x59\x8b\x44\x59\x63\x52\x64\x0b\xf1\x59\x26\xc1\x2e\x33\x1c\xd1\x4f\x8e\x10\x80\xd5\x55\x08\x10\x40\x39\x21\x21\xb0\x09\x56\xe8\xfc\xed\xbb\xef\xfc\xee\xa7\xc5\xfb\x9f\xe0\x66\x66\x1f\x63\xd6\x7e\xc9\xb0\x0f\x95\xc3\xe8\x5f\x67\x36\xab\x98\x14\xd8\xb7\xb8\x19\xb0\xc0\xb2\x4a\xdf\xc6\x8a\xee\x70\x39\x84\xad\xb4\x5b\x8b\x49\xc1\x16\x9b\xcc\x22\x91\x62\x18\xad\x59\x91\x6d\x48\x94\x59\x0b\xe9\xda\x24\x49\xb2\xd6\x48\xe3\xcb\x0a\x0f\x58\xb3\x3a\x84\x18\x9a\x9f\x79\x02\x09\x7d\xc8\x8b\xee\xfb\x80\xb3\x72\xb3\xe5\xe5\xdc\xcc\xcc\x3e\xf6\x2e\x4a\x83\x2f\x47\xd9\x57\x67\xda\x81\x81\xc4\xdc\xfb\xec\x07\x7c\x08\x5c\x50\x47\x34\x42\xa0\xf1\xda\x7c\xce\x81\x06\x69\xf5\x74\x2c\x6e\xab\x82\xdd\x36\x39\x4a\x7c\x86\x55\x91\x45\x24\xca\x51\xb7\x60\x97\x79\x81\x90\xa0\x3a\x20\xd8\x65\x30\x5c\xb2\xec\xc5\xfd\xa9\x25\xad\xc4\xa2\x63\xc5\xfd\x1b\x9f\xb8\x61\xb4\xa6\x6f\xed\xae\xab\xda\x0f\x16\xaf\xed\xfd\x75\x55\xef\x9a\x96\xc6\x95\x3d\xc9\xfa\xbe\x15\x75\x4d\x6b\xfa\x6b\x99\x1b\xee\xf9\x3d\xde\x3c\x71\x6a\xe6\xf1\x6b\x5f\xb9\x6f\x77\x7f\x74\xdb\x53\x9f\x7f\xe7\xea\xd2\x57\xba\x1a\xf7\x3d\x75\xeb\x57\xf1\xde\x4c\xc3\xce\x1f\x10\x7f\xb7\xbd\x82\x45\x2c\x10\x80\xbe\x8a\xb5\xa7\xbe\x2e\x60\x50\x4a\x66\x2b\x10\x14\x62\x26\xd6\x37\xa8\x92\xd3\xaa\x60\x6b\x96\x50\x94\x60\x44\x02\x81\x42\x44\xb3\x68\x48\x79\x31\xd0\x10\x91\x0f\x9d\x07\x16\xdb\x91\x7c\xe5\x23\x57\x34\x65\xb6\x7f\x67\xff\x5b\x2f\xe6\x47\x9b\x3c\xde\xa6\x91\xdc\x4b\xdc\x4c\xe7\x15\xb7\x2f\x5b\x76\x62\x7b\xc7\xec\x0c\xf3\x5a\x20\xdd\x53\x53\xdb\x9f\x0d\x52\x1c\x9b\x28\xbf\x43\x69\x1a\x81\x1c\x8c\x83\x4a\xca\xb4\x41\xc1\xde\xb4\xec\x20\x0e\xaf\x99\x0e\x27\x6a\x55\x70\xd4\x26\xd7\x57\x28\x9a\x27\x31\x6f\x94\x60\x79\x87\x3f\x40\x53\x05\x06\x41\x76\x7b\x08\x75\xd3\x0e\x8a\xe2\x69\x3a\xe7\xe2\x75\x45\xad\xdb\xe3\xce\x65\x73\x05\x2d\x89\x76\x1b\xd9\x3f\x4b\xeb\x8e\x6d\xb7\x0e\xb3\x6e\x47\x92\xe5\xfe\xa7\xe6\xd1\x1f\x3c\xca\xaf\x3e\x71\x59\xd3\x7f\x41\xf5\xbf\xfa\xf8\xe1\x0d\x8e\x84\xdb\xa9\xfb\xe9\x0d\x77\x7b\xae\x7e\xf2\x5f\xbe\x76\x29\xf1\x19\xd8\x08\xc0\x2a\xdc\x0c\x08\x10\x84\x75\x15\x09\x36\xe7\x54\xf2\x07\x0d\x4a\xc9\x66\xa7\xe4\xb7\x11\xf2\x87\xe8\x7c\x09\xec\xb3\x67\xb1\xa0\x96\x6b\x10\xf2\x87\x91\x28\x7b\x05\xc1\x2e\x5b\x4d\x92\x84\xb5\x02\xb6\x48\x20\xdb\x6d\x14\x0c\xe2\xa0\x70\x29\xfa\x43\x31\x94\x98\xe7\x4b\x8d\x88\x36\xa2\x7b\x0e\xff\xcd\x9e\x6c\xa2\x7b\x5d\x01\x89\xe5\x72\xf9\xb3\x7b\x9f\xc9\x8d\x64\x3c\x1b\x76\x3c\xc3\xcd\x14\xb6\x7e\x6d\x55\xf3\xae\xcb\x86\xec\xb3\xef\x30\xb6\xd9\x4f\x99\xb7\x7d\xa9\x9e\x9a\xb5\x53\x80\x40\x9a\x7b\x9f\x7d\x92\x0f\x41\x37\x1c\x82\x62\xe7\xbc\x3d\x0e\x91\x61\xd7\xe9\x94\xe9\x58\x67\x48\x27\x62\x6f\x0e\xe1\x9e\x34\xf6\x9e\x95\x1b\xad\x0a\x6e\xb4\x51\x8d\x6f\x35\x2a\x72\x2f\x12\xe5\x46\x2f\x11\x7b\x24\x49\xd8\x22\x3c\x65\x74\x86\xea\x9a\x3b\x09\xb7\x5a\xed\x72\xb4\x9a\x70\xcb\xd8\xa9\x5a\xea\x98\x30\x8d\x9c\xb9\x56\xf2\x5d\x9d\x5d\x8e\x36\x4a\x17\x9b\xed\xe6\x46\x26\x39\x9f\xf0\x71\x5f\x82\x11\x3d\x0b\x59\x5f\xe9\x6a\x93\xd9\x60\xd0\xb9\x0a\x83\x93\xb9\x0d\xbb\xbd\xd2\xc6\xe1\x8d\xb7\xad\xae\xed\xda\xff\xed\xf5\x57\xfd\x64\xe8\x06\xab\x59\xcb\x69\xe2\x5f\x59\x51\xd5\x5e\xe7\xf6\x74\x5e\x31\xbe\xe9\x86\xa5\x91\xa6\xbd\x4f\x5c\x7b\xe3\xd9\x07\x7f\xc2\x9a\x6c\x4e\x93\x3f\x5b\xe3\x59\x7d\x59\x28\x9f\xcb\x87\x92\xab\x36\xef\xeb\x1a\xb9\x71\x73\xeb\xe6\xcb\x9e\x40\x06\x9b\x43\x9f\xeb\xf7\x24\x73\xc1\x58\xbb\xd4\x16\x4b\xae\xbc\x7c\x77\xe7\xe2\xaf\xed\xed\xdf\x42\xed\x62\x1d\x00\xfb\x0e\x37\x03\x5a\x68\x83\xa2\xe6\xc2\x5c\x1b\x66\xb3\x24\x0c\xc6\x9a\xb3\x32\x6f\x55\x8a\xbc\x86\x98\x60\x9e\xd5\x8b\x45\x0d\x4f\x9a\x1a\xd0\x8b\x17\xc4\xc8\x31\x21\x21\xd4\xb1\x4f\x94\xef\xff\x15\x97\x7f\xed\xb5\x2f\xdf\xe0\xf2\xf4\xf7\x47\xe7\x7e\xc1\x96\xb8\x19\x88\xc1\x00\x14\x43\xa0\xba\xc2\x0a\x4e\x73\x13\x87\x13\xa7\x02\x63\x34\x2a\xa4\x17\x6c\x54\x15\xd6\x6b\x56\xe4\x04\x12\x65\xde\x48\x2d\x3c\x76\x09\xb2\x2d\xa4\x16\xf6\x08\x95\x5a\x07\xad\x30\xaf\x00\x42\x4e\xa8\xc4\xb0\xa3\xff\x97\x43\xbc\x46\x8b\x9c\x99\xb1\xf6\xce\xf1\x26\xe7\xcf\xbb\xae\x7c\x64\xeb\xee\x47\xf6\x15\xd0\xcb\xac\xc4\x72\x2c\x75\x42\xb3\xe6\xbe\xdd\x4b\x6a\xeb\x46\xf7\xf4\xb3\xf9\x99\x37\x8f\x3d\x7d\xa4\xad\xef\x2f\x8a\x74\xac\x4e\x00\x76\x86\xae\xad\x74\x56\x68\x01\x0c\x0d\xad\xe8\xc2\x0a\x9c\x95\x91\x55\xc1\x48\x35\xd2\xc4\x07\xd1\x35\x16\x44\x24\x44\x43\x84\x01\x34\x74\xb0\x99\x26\x47\x0e\x39\x72\x28\xe1\xfc\x2d\x32\x95\x3f\x29\x6f\xc7\xdc\xcc\xcc\x61\xf6\xc4\x97\x1c\xe9\xc3\x04\xc0\x96\xb9\x19\x30\x11\x99\x34\x11\x4d\xd2\xe5\xd4\x6e\x34\xb9\x79\x17\x84\xcc\xf3\xdd\x94\x38\x13\x58\x38\x11\x73\x36\x59\x43\x1d\x91\x32\xad\xd3\x6a\x74\x62\x49\xaf\xd6\x2d\xe8\xd3\x25\x9d\x5a\xc0\x65\xa9\x8c\x05\x1b\x25\xcc\x09\xd8\x20\xc9\x3a\x7d\xc5\x61\x00\x75\x5f\xaa\xc1\x26\x2e\x2b\x80\x72\x6c\xc2\x88\x12\xa6\x0f\x87\xef\xbb\xfb\xbe\xfc\x3b\xf7\x97\x1e\x7b\xfc\x19\x6e\x66\xe6\x34\xf3\xf3\xd9\x6a\xb6\xff\x4b\x8e\xd5\xcd\x7c\x46\xc6\x2a\x02\xb0\xbf\xa3\xf8\xa9\xa6\xa2\xf5\x3a\x55\xeb\x31\x9f\x23\xb8\x89\xe2\x22\x99\x21\xfe\x88\xa3\x3f\x9f\xd3\xd3\x5f\xd7\xa3\x98\x11\x89\x68\xaa\xfc\xc4\x17\x1f\xbc\xfb\x9b\xf2\x4b\x68\x47\xb9\xfc\xab\x5f\x30\xb7\x33\x07\xcb\x1b\xd0\x23\xb3\xdf\x9c\x3d\x84\x4e\x97\x97\xa8\x7e\xd9\x0e\xc0\x7e\xc1\xcd\x80\x0e\x32\x95\x5c\xef\x02\xcd\xf5\x0b\xa9\x5e\x03\x71\xc6\xda\x0a\x06\x01\xed\x3c\x99\x63\x84\xcc\x42\x42\xb0\x23\x40\x5a\xe5\xb3\xf2\xdd\xff\x87\x9b\x99\x9d\x61\xb8\x99\x2f\xca\x06\xf4\x99\xfa\xfb\x93\x95\x38\xc9\x42\xe4\x9b\xe2\x0b\x2d\xab\xd0\x46\xc9\x6c\x80\x46\x4e\xa4\xce\x5f\x66\x89\xad\xb6\xa6\x89\xcf\x05\x59\xab\xae\x54\xc8\x1c\x2b\xd8\xb1\x86\xcc\x2b\x8f\x62\xf9\x98\x0b\xd1\x35\xab\x49\xa6\x6f\xf6\x1f\xd9\xc1\xd9\xd7\xd1\xbf\xbb\x03\x2e\x97\xed\x76\xf6\xf1\xd7\x6e\x9f\x99\x64\x0d\x06\xed\x2f\xd4\x3e\x7f\x3b\xb7\x98\xdd\xcb\xaf\x05\x2d\x34\x41\x91\x27\x7d\x02\xa7\x60\x2e\x2d\x23\x1d\xcd\x2c\x11\x1e\xf3\x66\xa5\xc8\xc3\xbc\x4a\x61\x4d\xb6\xa2\x4a\x9e\x4a\x20\xf2\x5b\xe6\xda\xf2\x7a\xf4\xe8\x33\x1a\xfb\xf3\x5f\x6e\x7d\x46\xfd\xdd\x9d\x73\x0f\xb3\x0f\xf0\x1b\x80\x05\x70\x14\x90\x76\xe7\x34\x73\xfd\x34\x0f\x1b\xbe\xb8\x7f\x95\xfa\xfd\xdd\x73\x8b\x59\xd3\x7c\xbf\xea\x5c\x39\x05\xb3\x69\x02\x75\x69\xbf\xe8\xac\xac\x31\x2b\x45\xa4\x99\x5f\xc6\xc6\x30\xdf\x6f\x2e\x26\xc4\xf2\x31\x21\x76\x37\x7a\xa4\xbc\x89\xb9\x66\xf6\x38\xf7\xe0\xf3\x9f\xff\x46\xfd\xdd\x87\x98\xc7\xd8\x29\x1e\x40\x03\x09\xa8\x64\x19\xe8\xca\x34\xe6\xb2\x44\x33\x88\x1e\x5c\xb8\xc6\x88\x72\x48\x6b\x44\x0f\xa1\x91\x25\xa8\xfa\xb1\xc7\x5f\x64\x3e\x63\x74\xb3\x9f\x8d\xa1\xcd\xe5\x87\x68\x9c\xdd\xc4\xbe\x3a\xf7\x29\xb0\xe0\xaf\x8c\x91\xd5\xa9\xfc\xb8\x60\xb9\xd9\x13\x73\xc5\xda\xd9\x93\x33\xd7\xd8\x5e\x20\xfd\xff\x8e\xdd\xcb\xdc\xc7\x9f\x00\x3b\x44\x01\x9b\xd3\x25\x74\xbe\x2e\x02\xce\x96\x74\x56\x30\x70\x22\x89\x70\x69\x7d\x98\x27\x8c\x48\x40\xab\xe6\x80\x93\xbf\x2b\xf5\xba\x73\xc1\x48\x1d\xf2\x56\xd5\xda\xbd\xd9\xb6\x45\x75\x7c\x7e\xf2\x54\x73\x67\x30\x52\xa8\x0b\xd5\xf9\x8c\x26\xe9\xc8\x1e\xea\xc7\x27\xe6\x7e\xc9\x9e\x60\xdf\x82\x10\xe4\x60\x3f\x14\x5d\x44\x12\x7d\x64\x78\x09\x5e\x29\x5a\x10\x89\x1d\x78\xa5\xc4\x37\xfa\x2c\x24\xac\xd4\x2e\x78\xf6\xb0\x51\xc1\x61\xd5\x68\x69\xc4\x6c\x56\x76\x9a\x55\xf7\x1e\x26\x5a\x61\x24\xbe\xce\x25\x94\xf4\x16\x5f\xa2\x91\xe6\xb4\x69\xa6\xd4\x2d\x61\xbd\x40\x14\xd5\x42\xbc\x5f\xa6\xa9\xd0\xdc\xc5\xb4\xd3\xb5\x64\x6d\xb2\xe5\xe2\x14\xd4\xbc\x97\xa7\x75\x1e\xf1\x44\x5c\x6b\x61\x26\xba\xbf\x32\x7d\xf5\x51\x66\x72\xed\xd5\x47\xaf\xba\xe7\xec\xba\x6f\x6c\x6d\x79\xbf\xe5\xde\x91\xc9\x6b\xc7\x92\xbf\x70\xd7\xe4\x42\xe9\x91\xd6\x1a\xbd\x4e\x37\x69\x32\x2d\xc9\xb6\xf5\xf9\xca\x4b\xae\x5d\x93\xdd\xbb\xf9\xfa\x6f\x3d\xd8\xb8\xe9\xde\x1d\xb3\xcf\xad\xca\x75\xa4\x46\xb7\xf7\x7b\xeb\x23\x8e\x58\x63\xd6\x6e\x6d\x4f\x31\x06\x53\x4a\xa2\x34\xd8\x3e\xf7\x73\xf6\x0c\xbf\x1d\x7c\xd0\x08\xdb\x2a\x18\xcb\x45\x53\x21\x3a\xa5\x68\x24\x34\xa8\xe7\xd4\x15\x60\x74\x56\xd6\x19\x15\xec\xcf\xca\x8c\x95\x56\x20\x92\x30\xd7\x66\x54\xd4\x55\x60\xa4\x2e\xfe\x56\x31\x82\x7d\xda\xe8\x8a\xd4\xd3\x99\x47\x40\xcd\x11\xd7\x0b\xd8\x26\x61\xa3\x9d\xae\x44\xe5\x84\x18\x35\xe5\x17\xae\xb7\xd5\x24\xb5\x8e\x05\x6c\x53\x53\xf1\x94\xdb\x11\xa3\xd3\x1b\x50\xea\xaa\x8e\xf1\xbb\xf6\xf7\x0e\x5d\x75\xcf\xe8\xe2\x9b\x33\x91\x7e\x7f\x66\x40\x8c\x2f\xe9\x4a\x26\xab\x83\xdd\x99\xd6\xc1\xa4\x95\xdf\x6e\xb2\x18\x4d\x86\x72\x77\x36\xdf\x71\x64\xfa\xc8\xcd\xaf\xdd\xdc\xd7\xdd\xb1\x1e\x29\x6b\x8e\x2d\xaf\x8a\x2e\xbe\x7a\xd5\xba\x9b\x6a\x23\x91\xa6\xc9\xbd\x54\xae\x97\xcd\x9d\x63\x8b\xec\x5b\x50\x4f\xec\x3d\xcd\xf9\x84\x58\x45\x4d\x05\x3b\x74\x0b\x39\x1f\xaf\xb1\x92\xf3\x09\x91\x98\x3c\x21\x61\x87\x50\x04\x63\x9c\x84\xed\xbc\x9a\x46\x59\x28\x0f\xb8\x34\xfb\xd3\xc5\xcc\xa7\x7f\x96\x0d\x7e\x75\x7a\x4f\xc7\x81\x2d\x13\xe1\xbb\xf5\x3a\x8e\x65\x83\x57\x8c\x36\xaf\xef\xaf\xad\x5e\x74\x99\x14\xec\xec\xea\x08\xdd\x32\xfe\xd2\x9e\x2b\x7e\x78\xdd\x10\x7a\x67\xf7\xb3\x27\x96\x7b\x1b\x07\x52\x4f\x30\x46\x8b\xa0\xcf\xf4\xa4\xc6\x0f\x2c\xea\x3f\xb4\x2a\x63\x0e\x37\x25\x1e\x58\xb7\x7c\xf4\xd6\x67\x28\xaf\x3a\xe7\x7e\xce\x16\xf9\xed\x90\x80\x02\xf1\x24\x6e\xc2\xab\x08\xa8\xc8\x46\x9d\x42\x8e\x53\x8a\x7c\x8e\x5a\x18\xa3\x5e\x44\xb8\x55\xcd\x9c\x1a\x69\xe6\x94\x58\x54\x5f\x63\x36\x2b\x0b\x46\x45\x36\xd1\xc5\x7c\x59\x22\xe8\xb4\x4a\xb0\x4f\xf3\x91\xba\x1c\x81\x32\x82\x80\xdd\x12\xc8\x75\x6e\xc1\x8e\xfd\x12\xce\x09\x04\xea\x5c\x3a\xe7\x0a\x07\x9d\x6e\x4f\xa2\x11\x75\xa2\x0b\xd7\x5e\xce\xaf\x1f\x6a\x3a\xfb\x0e\xdc\x3d\x1e\xec\x68\xcf\xbb\x54\x46\x1a\x74\xef\x99\x75\xb6\x7c\xd7\xa2\xc8\xe4\x3d\xfb\x7b\x3f\x4e\x76\x0d\x27\xc4\x81\xa6\x80\xad\x76\xa8\x90\xe9\x0e\x8e\xa2\x9f\x1e\x7d\xe1\xe6\x41\x8b\xaf\xca\x85\xfe\xd3\x68\x31\x99\xf5\x5f\x2e\xf6\xb5\x47\xf4\x55\x96\x50\xa8\x21\x6c\xeb\xbc\xf6\xd9\x1b\x56\x5d\xbd\x38\x5a\xb5\xfc\xd8\x9a\x8e\xbd\x93\x4d\x91\xc8\x38\xa5\xc9\xe8\xdc\x39\xf6\x31\xaa\xc3\xb5\xb0\x0b\x54\xf5\x75\x68\x2a\xe4\xa8\xd2\x2a\xa5\xb0\xc5\xc7\x9b\x45\x39\x4c\xd4\xb7\x4e\x8d\x13\x88\xfa\xd2\x38\x61\x3e\xcf\x4e\x30\x7a\xc4\x22\xd8\x8b\xbc\xc3\x47\x78\x6c\x10\x8a\x66\x02\xcd\x25\x90\x1d\x44\x79\x3d\x04\x0b\x12\x15\x0e\xff\x71\x14\xa4\xd1\xc6\x28\xe0\xa3\xd5\x53\x8d\x4c\x21\x56\xc1\xe6\xa3\xfd\x47\xbf\xb7\x79\xe5\x3d\xfb\x7b\x38\x66\xf6\x0e\x5d\xa6\x7f\x85\xd8\x7b\x2c\x75\xfd\x37\xdf\xdb\xf1\xc3\xeb\x17\xff\x3b\xfa\x5a\xa0\x69\xa8\xa1\x7e\x28\x1f\x43\x6f\x1d\x7e\xfe\xe6\xa1\x8e\xab\x7f\x78\xc8\x97\xf1\x0c\x6c\xe9\x8d\xb4\x4b\xd7\x3f\xd1\xff\xd5\x67\x7f\x95\x1a\xef\xac\x8a\xb6\x4d\x54\xd6\x46\xb9\x08\x7f\x18\x42\x04\x89\x07\x89\x4f\x86\x34\xf6\xe5\x64\xa4\x51\xb0\x27\x8b\x1d\x69\x59\xa7\x51\x8a\x0e\x5a\x97\xe1\xa0\x7c\x0f\xa7\x71\x90\x16\x2a\x05\xcc\x0a\x76\x67\x8b\x81\x20\xf9\x2e\xe0\xd3\x8b\xc5\x60\x80\x34\x83\x04\xc8\x45\x88\x84\xeb\x1c\x95\xc4\xa0\x23\x9f\x53\xd1\xaa\x47\x4b\x83\x8d\x44\x5c\x13\x42\x2a\xc6\x3b\xfe\xd3\xee\x3d\x77\x8e\xbf\x70\xfd\x06\x9b\x51\x63\xaa\x6e\xea\x8c\xaf\x9a\x44\xd5\xe5\xf7\xcf\x31\x6f\x9f\xee\xdf\xf5\xf0\xee\xfc\x83\xcf\x38\x3d\xf6\xda\xb8\xe7\xab\xc7\x9b\x4e\xcf\xa6\x98\xb7\x81\x85\xbe\xf2\x43\xec\x2f\xd9\xf7\x60\x00\xa6\x60\x0f\x3c\x0f\x45\x17\x61\xc8\x4e\x5e\x29\x06\x48\x23\xc8\x2a\x38\x96\xc5\xbd\x69\x79\x44\xab\xe0\x95\x69\xb9\x59\xa3\x60\x31\x2d\x6f\xe0\x15\x84\xf7\xa6\xb1\xee\x2c\xb6\x65\xe5\x26\x93\x82\xd7\x64\x71\x93\x0d\x0f\x46\xcf\x0a\x32\x98\xe8\x5a\xcd\xa0\x49\xc1\x4d\x36\x79\x0b\x12\xe5\x1a\x93\x22\xef\x43\xa2\x3c\xa8\x23\x88\xcc\x28\x49\xf2\x96\x26\xc1\xde\xa3\x17\x5d\x85\xde\x91\x15\xab\x36\xec\x24\x22\x5d\x23\x94\x3c\x89\xe5\x63\xe3\xd4\x24\xad\x1c\x11\xec\xc5\x0e\x18\x24\x6c\x6e\x16\x30\x2f\x61\xd1\x2e\xeb\x9a\x24\x09\x6f\x10\x64\x63\xa3\x24\xe1\xa0\xbd\x64\x4b\xd4\xac\xd9\x42\xfe\x34\x20\x60\x12\x92\x79\xe6\xab\x10\x5b\x16\xd6\x70\x3d\x5d\xa8\x1d\x79\x08\x95\xb4\x95\x54\x6a\xbc\x26\x69\x41\x2e\xa7\x3b\x97\x6d\xf9\x53\xcb\xea\x85\x46\xa4\x3e\xe2\xb8\x24\x88\xeb\xb3\xc7\x1a\x03\x09\x7f\x5f\x2e\x92\x89\xdb\x3b\xb7\xdf\x34\x78\x6c\x2a\xb5\xb3\xab\x2f\xec\xa8\x0e\x39\x91\x98\xb2\x38\xa4\xcd\x37\x8d\x38\xeb\xdd\xc1\x58\x5b\x63\x62\x34\xb2\xed\x8e\xd5\xc9\xc2\xbe\x53\xfb\xaf\x3a\xb5\x2b\xfb\xbf\xaa\x7b\x26\xd3\x4d\x13\x1d\x71\x86\x6d\xe9\x5a\x72\x5d\x7f\x75\xa2\xd9\x55\xd3\x12\x4f\xb4\x26\x9d\xce\x64\x6b\x22\x92\xaf\xf5\xec\xf5\xe5\xb3\x0d\x82\x6f\x20\x91\xd9\x5c\xef\x68\xed\x19\x4c\x2c\xbe\xee\xb2\xfc\xa2\x70\xe4\x65\x96\xe3\x18\x21\xba\x28\xde\x7f\x64\x6d\x33\xa7\x75\x54\x79\x82\x0e\x4d\xcd\xc0\x06\xa9\x7d\xef\xaa\x5c\x72\xd1\x9a\xe5\xa1\xa4\xcf\x28\x44\xc4\x40\x4d\x86\xe1\xdd\xed\xcc\x0b\xd1\xd6\x7a\x9f\xaf\xbe\x35\x1a\x6d\x6b\xf0\xbb\xeb\xda\x89\x5c\x5e\x0b\xc0\x3e\xc0\x6f\x87\x30\x2c\x3e\x9f\x57\xa2\x3e\xc3\x4b\x4c\x69\x64\xc1\x59\x6a\x55\x9f\x11\xb6\xc9\x76\x24\xca\x82\x59\xa1\x79\x06\x3b\x43\xdc\xa5\x97\xc6\x54\x5e\xe1\x4f\x3a\x07\x21\x21\x54\xa8\xe4\x12\xae\x45\x9c\xce\x60\x40\xd9\x9b\xfb\x87\xaf\x99\x48\xfd\xab\xb3\x2a\x1b\x11\x47\x0a\xd1\x79\xeb\x9f\x6e\xe9\x6d\xb8\xfc\x5b\xbb\x67\xcf\x30\x7d\x85\xb1\x9c\x37\xde\xb5\xba\x79\xf6\x5d\xb5\x3e\xff\x55\x00\x76\x33\xbf\x13\xf4\x10\x82\xcd\x15\x04\x82\x78\x5a\xc3\xb2\xb0\x06\xe8\x4b\x97\xac\x06\xf0\x72\xaa\xf2\x30\x67\x65\xad\x51\x29\x6a\x69\x72\x50\xab\xd7\x8b\x45\x46\x4b\x33\x83\xa0\x17\x31\x63\x9b\x76\x33\x06\x8b\x58\xd9\x64\x41\xad\x88\x96\xcc\xc5\xea\xa3\xe1\x4a\x25\x67\x28\xe4\x5c\x97\x96\xff\xbe\xfa\xcb\x0f\xd0\x8b\x6f\x97\xd3\xf6\xaa\x96\xaa\x50\x73\xd2\xe3\x49\x36\x87\x42\xf9\xa4\xa7\xc8\x4c\x15\x67\x7e\x5f\xe4\x3e\xf2\xa6\xab\x3d\xae\x44\x26\x10\xc8\x54\x39\x9d\x55\x19\x60\xa0\xbd\x7c\x1f\x1b\xe2\x0f\x42\x10\x32\xb0\x1a\x8a\x88\xd8\x7c\x07\x19\xb4\x9d\xa3\xbb\x01\x8c\xac\x82\x1b\xd2\xa5\xb8\x01\x3c\x64\xec\x4d\xb4\x82\xc9\x65\x54\x8a\x36\x9a\x60\xb4\xd9\xf5\x22\xb6\xd9\xa6\xdd\xb6\x90\x45\x2c\x25\xd5\x01\x67\x91\x28\xbb\x6c\x82\x5d\x8e\x37\xd0\x01\x7b\x0a\xe7\xeb\x95\x28\x22\x54\xc5\xf9\xd2\xd1\xb7\x7f\xdd\xa0\xe5\xb5\x06\x43\xb8\x5a\xf4\x44\x5a\xeb\xbc\xe5\x12\x93\xeb\xbc\xe2\xeb\xe3\x9b\xfe\x12\x1d\x73\xd4\xe4\x13\xa1\x7c\xad\xd7\x5b\x9b\x0f\x85\xf2\xb5\x9e\x37\x7e\xc4\x19\x6c\x2e\xab\x25\xec\xb7\x79\xb2\xcb\x5a\x99\xf7\x9f\x9b\x39\xb4\xe7\x2f\xb7\xa4\xc7\x35\x8c\xaf\x29\xe9\x71\x55\x67\x83\x81\xa6\x6a\xb7\xbb\xba\x89\xc8\xd1\xdc\x67\x1c\xc7\x6f\x07\xf7\x3c\x86\xc5\xf6\x5c\x51\x8f\x08\x3c\xf4\xa8\xc9\xa9\x05\x19\x92\xbd\xc4\x66\xe9\x09\xd0\xd2\x39\xa5\x0b\x04\x06\xb9\xdb\x11\x09\xbe\x79\xa4\x9d\x97\x14\xb4\x7f\xb8\xe1\xde\xf2\xd1\xdc\x81\x83\x7b\xd3\xe5\x8f\xcb\xaf\x2c\x23\xa2\x62\x30\xe9\x67\xd3\x68\xb7\x50\x3e\xde\xf9\xad\x07\xee\x6e\x33\xa0\x67\x96\x94\x1f\x00\x04\x27\x00\xd8\x6b\xf9\xed\xa0\x87\x8e\x8b\x24\x84\x02\x54\x5e\x5d\x51\xf8\xaf\xa4\x62\x7e\x4d\x21\x1f\xa3\xbc\x8f\xb9\x4e\x20\xcd\xe7\xe8\x1c\xd2\x14\x39\xa6\xf8\xe5\x68\x71\x3e\x27\xf8\x36\xfb\x11\xd4\xc1\x8e\x4a\x1f\xce\x60\x2e\x57\x44\x08\xc4\x69\x1b\xd2\x58\x44\x6c\xc9\x11\xec\x89\x7d\xd9\xf9\xb4\x5c\x9d\x49\xc1\x4c\x16\xd7\xa9\x2b\x6b\x41\x13\x5d\x5f\x20\xc0\xd3\x69\x52\x93\x74\xc1\x90\x60\x97\x35\xc4\xf2\x39\x5d\x82\x9d\x66\x58\x50\x42\xb0\xcb\xac\xb1\x92\xaf\x74\xa9\xaa\xe4\xb9\x40\xa3\x6a\x12\xf1\x8b\x34\xab\xef\x95\xd4\xba\x5a\x87\x58\x57\x63\x4d\xec\xca\x17\x86\x1b\x1c\xef\x04\xe2\xcb\xde\x36\x0a\x2e\xa3\x23\xe2\x36\xb1\xaf\x75\x64\xea\x8d\x81\x86\x68\x6b\x5b\xf5\xf0\xde\xa1\xd9\x4e\xe6\xc1\xb1\x81\x33\xb3\xb7\x33\xdf\xcc\x75\xc7\x4d\x42\xdd\x60\xcb\xec\x2d\x6a\xcc\x40\xed\x01\xfb\x16\xf8\x16\xf2\xad\x26\x75\x76\x45\xcd\x02\xbe\xaa\x2c\x15\x18\xe9\xb4\x7c\x36\x12\x4e\xca\x26\xb3\xba\x3e\x60\xf6\xd1\xd8\x0b\x64\xe4\xa8\x54\xf8\x9c\x1f\xff\xc5\xa6\xe0\x97\xd9\x9b\xfb\x17\x5f\xb3\xe2\xbc\x15\x60\xcf\x6c\xfe\xf3\xfa\xdf\x3e\x77\x8e\x7d\x95\x7d\x0b\x1c\x50\x0d\xfd\x95\x75\x33\x1f\x57\xc1\x08\x31\x02\x6f\x6b\xe8\xa8\x9c\x56\x05\x3b\x6d\x72\xb0\x82\x0a\x92\x84\xbc\x4e\xe2\x58\xac\x74\x99\xc6\xf7\xa7\x72\xa0\x17\xd8\xf8\x96\x79\x8b\xde\x3e\x7c\xdd\xf7\x2f\xbf\xec\x91\xa3\x03\xfd\x87\x1f\xdd\xb8\xf1\xfb\xc7\x86\x3e\x89\xb4\xad\xc8\x6d\x3d\x1c\xeb\x98\xc8\x34\x8d\x4b\x51\xf4\xce\xde\xe7\x6e\x5b\xda\x7f\xc3\x99\xc3\x87\xcf\xdc\x38\xb0\xe4\xd6\x67\xae\x59\x72\x78\xb2\xf1\x91\x6f\x2f\x3b\xb2\x42\x14\x27\xae\xa6\x63\xde\x5f\x7e\x9c\x7d\x8d\x7d\x0b\xdc\x50\x4b\xbc\x3e\xcd\xdb\x06\x49\xd4\x44\xc8\xa9\xa5\xe0\x46\xa7\x60\x77\x9a\x82\x1a\x37\x55\x79\x19\x79\xb2\x59\xec\xb2\xc9\x31\x42\xd3\x0a\xac\x89\xb9\x04\xbb\x2c\x68\xc9\x04\x82\x82\x60\xc7\xce\xf9\xd5\x57\x98\xcf\x5b\xb8\x2e\x2c\x03\xab\x49\x0a\x89\x0b\x90\x38\x99\xcd\xfe\x0f\x3c\xad\x1d\x9d\xa1\xc9\xbb\xf7\xf7\xf4\xed\xbf\x6b\xbc\xe3\x48\xdd\x47\x1f\x11\x0c\x9e\x58\xd2\x99\xdc\xbf\xb3\x30\x58\x6b\x65\xcf\x6c\x8e\xa6\x42\xe6\xde\x1b\x5f\xbd\xf9\xc8\x53\x5f\xe9\xcc\x89\xe5\xdd\x6c\xe7\x3c\xfa\xfe\xcb\xc7\x9a\x56\xec\xad\xf0\xa1\xfc\x38\x7b\x37\xfb\x16\x78\xa1\x9e\xcc\xc9\x49\xe6\x14\x66\xd5\x30\x43\x65\x46\x0d\xa7\x60\x4b\x7a\x1e\x85\x13\x29\xf1\xa9\xc9\x39\x43\x2c\x9b\x95\xcd\x2a\x2a\x97\x2d\x84\x13\xbc\x93\xcc\x29\xec\xa4\x95\x10\xb8\x86\xe2\x54\xe3\x25\x38\x95\x18\x62\xe1\xa2\xca\xa0\x05\x16\x75\xed\xb9\x77\x75\xa8\xb7\xab\x60\xff\xe0\x23\x67\xbe\xbd\x2b\x34\x79\xf7\xde\x9e\x8f\xa3\xad\x23\xf5\x53\x9b\x03\xb9\xc5\xa9\xda\xa1\x96\x08\x3a\x77\xf0\x99\x1b\x87\x2c\xfe\x2a\xf7\xd2\x2f\x7e\x83\xee\xf7\x54\xfb\xcd\x23\xb7\x9d\x39\x3a\x7c\x64\x65\xfa\xa1\xef\x4e\x5c\x33\x92\xa8\x5b\x76\x90\xca\xfd\x69\x00\xf6\xc7\xec\x5b\xe0\x02\x69\x7e\x4d\x92\xcc\x48\x47\x66\x64\x65\x95\x85\x05\x16\x2a\xf4\xb2\x87\x58\x30\x2b\xa8\x59\x50\x24\x5c\xa8\xa9\xac\x9a\x2a\x54\xa3\x09\xe1\xf4\x27\x9e\xb6\xbe\xe1\x9a\xf1\xbb\xa5\xdd\xd9\xf5\x8d\xf9\x75\x03\x49\xf6\xcc\x4e\x7f\x63\xdc\x91\x6b\x39\x37\xd0\x93\x5a\xba\x43\x2a\x9b\x2a\x75\xae\xe7\xd8\xfb\xd9\xb7\xa0\x07\xfe\x19\x8a\x5d\x74\xcd\x4b\xa7\x14\xc3\xa4\xfb\x06\x5e\x29\x36\x84\x89\x91\x6a\x88\x13\x60\xd8\x9b\xc6\xbe\xb3\x14\x57\x35\xd1\xfa\x09\x59\x32\x2a\x72\x9f\xba\x85\xec\xd7\x91\x97\xde\x53\x77\x8c\x39\x6c\x58\x78\x51\x6e\x16\x3e\xc7\x85\x17\xb1\xc3\x36\x6d\x77\x08\x0e\x11\x37\xdb\xa6\xf3\xcd\x05\x87\x38\xdd\x42\xde\x8b\xf9\xe6\x42\xf4\x64\xf4\x64\x42\x63\x11\xec\x12\x6e\x91\x8a\x76\x87\x20\xd8\x25\x78\x4a\x68\xb1\x3b\x9a\xf3\xea\x0e\x2e\x74\xd1\x15\xee\xf1\x23\xb9\x89\x70\x0f\xf1\x92\x84\x4d\xc2\xb4\x3e\xdc\xd0\x45\x80\x96\x64\x97\x63\x35\x74\x23\x54\x97\x9a\x5d\x6d\x10\x8a\x88\x60\x71\x82\xb9\x71\x4c\x4d\xad\xa2\x0b\x53\xab\xe8\xc2\xec\x2a\xdd\xfe\xc4\x9e\x4f\xaf\xce\x23\xb2\x8d\x87\x4d\x26\xbd\xad\x63\xc9\x78\xf5\xc4\x5a\xa7\x38\x98\x0b\x16\x82\xad\x53\x9d\x51\x69\xeb\xed\x2b\xf6\xfe\x68\xd9\x3e\x9d\x9e\xe7\x58\x7b\x4b\xef\x70\x55\xa4\x55\xf4\x05\x5a\x26\x5a\xff\xf6\xbb\x6d\xbb\xbe\x75\xd9\xd1\x37\x6f\x78\x97\xf1\xb9\xfd\x4d\xb5\xde\x74\xda\x5b\x15\x09\x58\x75\x36\xa3\x2b\xdf\xb7\x22\x97\xdb\x3e\x9e\x5b\x36\x75\x4a\x6f\xb6\x6a\xdc\x75\x61\xbb\xde\x19\xf5\xf8\x13\x21\xbf\x35\x73\xdf\xa6\xde\xab\xd6\x34\x2f\xa5\xfc\x38\x34\x77\x8e\x7d\x94\x7b\x0d\xe2\x70\x59\x65\x4d\xd0\xa1\x57\xa8\x4c\x60\x9d\x5a\x4e\x6b\xc8\x22\x9c\x48\xe3\xc8\x59\xd9\x66\x55\x8a\xb6\x08\x75\xd5\x06\xbd\x58\x8c\xd8\xe8\x26\x33\xe2\x50\x68\x78\x1d\x11\xec\x45\x86\x8d\xab\xa1\x88\x5f\x0d\x45\x40\x90\xdd\x11\x49\x45\xec\xdd\xc8\xa9\xb1\x12\x94\x4e\xa0\xe7\x45\xc5\x07\x04\xac\x1e\x7a\xdf\x52\xb6\x69\x5c\x28\x56\x7e\x97\x35\x6b\x3d\x62\x22\x7e\x60\x68\xf1\xe4\x77\x97\x8f\x1d\x1a\x49\xe8\x8c\x2c\xf3\xdc\x87\xa2\x3f\xee\x7e\xf6\xb9\x25\x0f\x2d\x5d\x76\x60\x30\xd6\xde\xf2\x77\x1d\xbd\xa9\xcb\xef\xd9\x31\xf0\xc6\xd7\xd4\xdc\xd3\xbb\xec\x03\xec\x19\x88\xc0\x52\xb5\xae\xbe\x18\x20\x93\xd1\x70\x95\xc9\x98\x72\x74\x93\x22\xd0\xea\x73\xcc\xaa\x6b\xbe\xae\x2c\x09\xb0\xa8\x0d\x32\xb2\x82\x1d\x07\x68\xec\x64\x97\x40\xd6\xd8\x69\x1e\x84\xe6\x73\x85\x4a\x31\x0d\x6d\x5d\x18\x45\xee\xfc\xd7\x91\x2e\x62\xd0\x7f\x69\xd4\xfd\x8b\x49\xe7\xea\x18\x1c\x8e\x8f\x5c\x33\x21\xa2\xed\xcc\xaa\xd9\xc7\xf7\x6d\x4b\x74\xad\x6e\x66\x3a\x67\x9e\xf6\xb7\x91\xc8\x30\x42\x20\x73\xc3\xc6\xfb\x01\x41\x0e\x80\x7d\x9e\x3d\x03\x02\xd4\xaa\xd6\x92\x5a\x4a\x6c\xcc\x21\x6c\x4f\x63\xe3\x59\xea\x64\x1c\x44\xf5\x40\xa8\xac\x07\x39\x08\x72\x70\x05\x50\x17\x2a\xe4\x2c\x48\xcb\x26\x72\xc8\xc5\xf3\xfc\x7b\x97\x55\x75\xd9\xdf\xf7\x0e\x65\xde\x39\xc3\x9e\x31\x5a\x2d\x56\xc3\xec\x83\xc8\x72\xc5\xbb\xab\x77\x9c\x3b\x30\xfb\x05\xa1\x8b\x0d\x80\xfd\x25\x7b\x06\x42\xf0\xae\x9a\xdf\xc6\xfe\x9c\xda\x9d\x23\x47\xe1\xa3\xf1\x6c\xc9\xa4\x26\x71\x4d\x36\xd2\x29\xcd\x10\x45\x54\x2d\xfb\xf1\x2b\xff\xc7\x49\xb4\x0c\xfb\x1b\x2d\x38\xf0\xa2\x6c\xb6\x7f\xce\x61\xd3\x8b\xcf\x75\xaf\xfb\xfd\x6f\xc8\x7d\xd9\x64\xd6\x61\xb3\xcd\x82\xad\x2f\xca\x5e\xed\xe7\xd8\xf5\x22\x36\xdb\xa6\x2d\x66\xab\x43\xc4\x5e\xdb\xb4\xdb\xeb\x72\x88\xd3\x1e\xf2\x5e\xb4\x98\xad\xe7\x35\xb0\xe8\xf1\xba\x88\x22\xba\x25\xe8\xd1\x9b\xcc\x01\x8b\xd5\xe5\xf6\x78\x17\xb6\x52\xa2\x1e\xbd\xd9\x7f\xe9\x4d\xaa\x8f\x4e\xe2\x6c\x7d\x12\xc8\x40\xf7\xb6\x19\xd5\x9c\x31\x21\x4d\x10\x79\x02\x28\xe7\xe8\x62\x3b\x51\xce\xc2\x6a\x13\x46\x94\xb0\x95\xb5\x3a\x2d\x33\x75\xf8\x8e\xe3\x36\x87\x91\x7d\xcf\x1c\xad\xa9\x77\xbf\x71\xec\x9a\xb7\xd8\x33\x46\xb3\xc1\x68\xe0\x8d\x9a\xd9\xc7\x99\xfc\xec\x9b\x3b\xff\xee\x3b\x47\xab\xbb\xf7\xfd\xe7\xe7\xbf\xdb\xc3\x38\x67\x3f\x51\xf1\x01\xe1\xd1\x3b\xec\x19\xb0\x2c\xe4\x96\x8d\xb9\x22\x8b\x2a\x79\xf0\xf9\x4c\x2c\x4b\xc0\x1d\xaf\xae\x75\x22\x48\xc6\x02\x28\x87\xdc\x76\x4f\xcc\x88\x72\x68\x49\xf9\x5f\xaa\x10\xf3\xf2\x73\x9f\x95\x7f\x7a\x7d\x31\x59\xfe\xe2\xad\x57\xd1\x47\xe8\xd1\x5c\xf9\x0d\x94\x2f\x67\x4e\xcf\x41\x0b\xea\x2f\xab\xeb\xf2\x9e\xf2\x7d\xec\x1b\xec\x19\x48\x82\x08\x45\x2b\xe9\x23\x98\xc3\x35\x69\x59\x4f\xdc\x7d\x6d\x9a\xd6\x5a\xca\xfa\x4a\xc5\x85\x55\x90\x91\x9b\x74\xe8\xb9\xa0\xa2\x14\x51\xf1\x70\x14\xba\x58\x55\x3c\x88\x7c\x7a\xae\x34\x19\x34\x1a\xad\xa5\x2e\xe2\xae\x4d\xd6\x38\xca\xdf\x46\x3e\x4e\xc3\xbd\xb3\xde\x91\x08\x7b\xf5\xef\xfb\x96\xa4\x7e\xed\xef\x1f\x5b\xd7\x74\x47\xf9\x55\x8d\xc5\xee\x34\xf9\xbc\xf6\x86\xc5\x2d\x2c\x56\xa5\xe8\xc9\x99\xdc\x9e\x5d\x5b\xc4\x1d\x1f\x5c\x39\x7b\xd7\xc0\xe6\xae\x90\xba\x36\x0f\xc0\x3e\xc6\x3e\x06\x16\x28\x5c\x92\xab\x96\xcd\x06\xa5\xc8\x11\x23\xce\xb2\xff\xed\x44\xf5\x14\xfa\xb4\x5c\x60\x66\xca\x6e\x34\x6d\xf3\x7a\xdc\xd6\x3b\x99\x55\x2f\xdf\x39\xfb\x18\x32\x18\x75\xe7\x68\x7f\xeb\xcb\xcf\xb1\xab\x78\x1f\x74\xc2\x4e\x50\xb7\xf2\xd9\x38\x1a\x79\xd7\x6a\xd4\x42\xc8\x4a\x65\x62\xeb\x59\x99\xcf\x65\xb3\xb4\xe4\xdc\x51\x9d\xcd\x16\xa3\xad\xc4\x32\x45\x2d\x7a\x11\xd7\x65\x69\x65\x62\xb4\x95\xaa\x37\xc8\xb5\xa2\x60\xc7\x29\x6a\x98\xa2\x39\x49\xc2\x88\x6a\xbd\x4d\x90\x0d\xde\x8a\x99\x52\x8d\x76\xbe\xb9\xa5\x1d\xb9\x12\x71\x0d\x31\x55\x2e\xa7\xa6\x52\xef\xe5\x72\xba\xe9\x6d\x6a\xd5\x89\x49\xa7\x4e\x7a\xfd\x64\x77\x17\x62\xd0\x2b\x2f\x9f\x7a\xbd\xaf\x1b\x31\x68\x69\x7f\x24\x57\xe3\x42\x0c\x9a\xda\x76\xe7\x21\xd7\x8a\xcb\xd7\x87\xbb\xbb\x18\x86\xb1\x85\x53\x41\xf4\xc4\xe9\xa5\xab\x4d\xe9\x5c\x83\xee\xe9\xe7\x9e\x9d\x98\xb0\xa4\x32\xf5\x86\x75\x5f\x6f\x70\xb6\x8f\xac\xc9\x1a\x0b\x52\x9a\xbb\xe2\xb2\xa7\x78\x6b\xc0\x93\xf9\xce\x76\x5b\xbe\xad\xd5\x99\xeb\x4b\xda\x00\x10\xba\xbb\xfc\x06\xb3\x9f\x2f\xd0\x3d\x50\x08\x73\xf3\x96\x8c\xbe\xd4\xa4\x34\x12\x72\x02\xba\xfb\x67\xe5\x37\x34\x7b\x3e\xbf\x87\xd2\xef\x89\xf2\x73\xec\x29\x4a\xbf\x5d\x50\x59\x36\xe3\x14\x9c\x48\xcb\x55\x1a\x05\xdb\xd2\xb2\xb9\x42\xbf\xd4\x59\xb9\x36\x9f\xcd\xd2\x50\x8c\x37\xf8\xb3\xd9\x6c\x31\x45\x23\xb2\x14\xd2\x8b\x38\xa1\x52\xd0\x95\x12\xec\x38\x2b\x81\x5c\x95\x10\x68\xa9\xb3\x4d\x90\xfd\x29\x49\xc2\x66\x72\x9b\xd0\x93\xcf\xcf\x53\xd0\x7d\x21\xa9\x54\x3f\xa7\xee\x68\xa7\x45\x72\x15\xfa\x2e\x6c\x96\x24\xd8\xed\x89\x53\x2f\xbf\x82\x18\xd4\xd5\x3d\xb9\x2a\xd4\x10\xb6\x31\x0c\xd3\xd5\x1d\x5e\x7f\xf9\x0a\xd7\xa1\x3b\xb7\x4d\x21\x06\xb9\xaa\x9b\x23\xfd\x4b\x11\x83\xba\xfb\xb8\x8d\xcf\x3e\xf7\xb4\xae\x21\x97\x36\xad\x5e\x7a\xda\x96\xec\xcb\x39\x5b\xdb\xf2\xb6\xed\xdf\xc9\x78\x02\x56\xfe\xa9\xcb\xae\xe0\xd2\x52\xc1\x98\x5d\x33\xd2\xee\x6c\xf8\xfa\x3a\x43\x7d\x26\x65\x99\x98\x50\x75\xba\xc0\x9c\x60\x3f\x60\x7f\x09\x09\xc8\x02\x8e\xa6\x65\xde\xa0\x60\x7b\x76\xda\xcc\x47\x75\xa2\xec\x35\x28\x08\x57\xa5\xe5\x6a\x22\xb8\x51\x2f\xc1\xcf\x09\x49\x92\x79\x33\xdd\x32\xb4\x50\xb0\x3a\xaf\x71\x1e\xa2\x62\x95\xd4\x93\xb6\x10\x59\x3e\x39\x59\x15\xc9\xa5\x1b\x03\xc1\x66\x8f\x2b\x51\x5d\x1f\xf8\x76\x70\x60\xf9\xca\x86\xec\x78\xc8\x55\x53\x95\xf4\x44\x86\xeb\x59\x5d\x76\xa2\x3d\x6a\xf6\xc6\x5d\xae\xb8\x2d\x9e\xaf\xb9\x36\x35\xd6\x99\xa8\x72\x5b\xa3\x3e\x5b\xd7\x00\xfc\xd1\xb9\x09\x1b\xa1\x58\x45\x3c\x83\x9f\x98\x03\x6b\xfa\x4f\x9f\x9f\x10\xfb\xaf\xce\x4f\xf0\xd3\xf3\x13\x02\xe7\xcf\x4f\x08\xf8\x05\x7b\xd1\xca\x57\xa9\xf5\xcf\xe8\x82\xac\xa0\x46\x3d\x40\xa1\x8b\x29\x38\x72\x0e\x22\xe8\x1a\x12\x52\xd3\x03\x14\xa2\xed\x29\xbf\xd7\x93\xee\xa7\x07\x28\xf0\x3a\x0d\x13\x7c\xb6\x1a\x69\x78\x6e\x69\xdf\xc0\x08\xf7\x46\x24\x5f\xeb\xf1\xd4\xe5\xc3\xa1\x9c\x2f\xe5\xad\x6f\xf9\xf2\x3f\xdc\x9d\xbd\xdd\x5e\x26\x35\xfb\xb6\xa7\xad\xa3\xe0\xd8\xb9\x7e\x1d\xc1\xd2\x63\x73\x1b\x58\xcc\x95\xa1\x1a\x1a\xe1\x63\x28\x6a\x18\x10\x71\x24\x4d\x13\xf5\x70\x56\xae\x31\x2a\xb8\x46\xad\xe6\xc8\x50\xb7\x83\x6b\xfc\x48\x8e\x44\x1b\x5f\x07\x39\x1a\x69\x7c\x9d\x9e\x18\xb0\xe3\x0f\x8b\x89\xc3\xe1\x71\xd4\x86\x35\x2f\x5a\x70\xc4\x86\x0d\x2f\xe2\xa8\x6d\x9a\x8f\x6a\x1c\x22\x8e\xd8\xa6\x8d\x11\x83\x43\x9c\x76\xd3\x77\x0f\x7d\x0f\x93\x77\xf2\x4c\x8c\x3c\x33\x5d\x47\xdf\xeb\xc9\x7b\x31\x16\xd5\x5c\x80\x07\xeb\x24\x5c\x2f\x61\x5e\x2a\x86\x23\x06\x72\xed\x21\x9e\x09\x1b\x89\x73\xe2\x0d\x46\xb7\x27\x1c\xab\xab\xbf\xc0\x39\x19\x78\xcd\x1f\xdd\xa5\xee\x09\x64\x4d\x44\xb0\xcb\x16\xff\x7c\xdc\xd5\x8d\x3c\x04\xf2\xcc\x2f\xa9\x27\x59\x75\x23\xb0\x15\x25\x0b\x8d\x6c\xc1\xe9\xf6\x38\x2c\xec\x58\xd7\x95\x0f\x6d\x0c\x7d\x60\xd4\xb9\x8f\xaf\x3a\x4e\x73\xef\x56\x31\x38\x9a\xd9\xd6\x78\xcb\x48\x69\x4b\xe0\xf5\xc0\xc0\x95\xe3\x29\x25\x9b\x5f\x94\xec\x6e\xf0\x32\xb1\x2d\x4f\xde\xba\xca\xf8\x91\x4b\xf0\x79\x1e\xae\x3a\xfc\x14\x63\xb4\x0a\x7a\x6f\xbd\x75\xf6\x29\x5d\x9b\xf4\xc0\xca\x31\xfe\x4d\xdf\x5b\xfe\x75\x5f\xb9\x77\xd3\xf8\xcd\x29\x26\x61\x29\x8c\x5c\x46\xe5\x5e\x9a\xfb\x80\x7d\x97\xd7\xc1\x28\xea\x84\x62\x3f\x31\xd7\x03\xa3\xb9\x9c\xdc\xa1\x57\x70\x7b\x16\x77\xd8\x70\x21\x7a\x56\xc0\xad\x39\x79\x58\xa3\xe0\xc5\x59\x75\xe7\x52\x8c\x53\x4a\x56\x4b\xbf\xd7\x2c\x62\x31\x27\x5b\x35\x0a\xae\xcb\x4e\x07\xfb\xbd\x3a\x11\xe1\xa5\x69\xec\xa0\x49\xcf\x1a\xb3\x22\xd7\x35\x67\xb3\x45\x47\x0d\x4d\xe8\x12\x8b\x5b\x63\xc3\x69\xba\xbf\xda\x4c\xf7\x57\xa7\xcd\x4a\x31\x4d\xd3\xbd\x69\x51\x2f\xca\xcb\x54\x64\xf1\x9b\xbf\x7f\x69\x3d\x45\x16\x8b\x1b\x71\x7b\x23\x5e\x6c\x93\x5b\x9d\x9f\xe3\x76\x9b\x3c\xe0\xfc\xfc\xb9\x4f\xb6\xbc\x4c\x60\x87\x11\xb7\xda\xa6\xa5\xd6\x76\x87\x38\xdd\x46\xde\xf1\x62\xdb\xf4\xe0\xe2\x01\x87\x38\x3d\x44\xde\x8b\x52\x6b\xfb\x05\x4c\x6c\x93\x8a\x43\x8b\x07\x48\x6b\x50\x82\x69\xa9\x6d\x70\x88\x72\xeb\xe9\x56\xa9\xad\x7d\x60\x70\x68\xf1\x45\x38\x82\x26\x92\xcd\x34\x14\x1b\x96\x70\xda\x2e\x37\x14\x08\x6a\x2d\x0c\x13\xb5\xef\xa3\xe5\x14\x45\x5d\xba\x57\x92\x24\x39\x68\x15\xec\xb2\xa3\x86\xb0\x94\xb8\x57\xb5\x42\x3d\x99\xc8\xe7\xe6\x77\x0e\x50\xee\xaa\x66\xce\xed\xc9\xb9\x12\x95\xe5\xff\x96\x2c\xd1\x2e\xd5\x56\x50\xfd\x22\x86\x42\x4a\x16\xaa\x5d\x9a\x60\x88\xe1\xb4\xfc\x2d\xeb\x79\xb6\x7d\xfb\xc9\xb1\x75\x77\xf5\x9d\x08\x07\x7c\x75\x62\x44\x6a\xf0\xb3\xfc\x9b\x8f\xe8\xb4\xbc\xd9\x6b\xd7\x87\xac\x91\xa1\xa1\x6e\xb7\x2d\x56\x25\xfa\x57\xdd\x72\x38\x7e\xd9\x96\xf5\xd1\xf8\xd1\xd5\x77\x5b\x03\x5e\xb7\xb1\x71\x7f\x87\x35\x99\x4a\xbb\x4f\xfb\xea\x9c\x2b\xef\xdc\xd1\x36\x38\xf4\xb8\xa9\xbe\x3e\xe2\xcb\x8d\xe6\x84\xda\xc8\xe9\xfa\xf5\xd1\x60\x57\x57\xab\x8b\x71\x79\x5d\x06\x57\xd4\x85\xf7\x06\xa2\x81\x74\x0a\x18\xd8\x85\xf2\xec\x7d\xdc\x24\x5d\x97\xb9\x0a\x70\x24\x2d\xd7\x69\x15\x9c\x4b\xcb\x66\xad\x42\xd7\x60\xb8\x85\xea\xf5\x46\x24\xca\x6e\x93\x42\xd7\x5d\xaa\x38\xc1\xfe\x14\xd2\xea\x0d\xb4\xa0\x18\x37\x0a\x72\xc4\x2c\x49\xd8\x6d\x7f\xca\x26\x38\x7c\x81\x20\xcd\x57\xd7\x45\x04\x7b\xc9\xe7\x87\x60\x9c\x3c\x93\x13\x8a\x48\xeb\x96\xa8\x87\x28\xe9\x0c\x36\xbb\x43\x2d\x19\xaa\x24\xa7\x93\x05\x8f\xba\xc9\xab\xe0\xa1\x59\x69\x8d\xd6\xa3\x4d\xaa\x5b\x65\xb4\x97\xa6\x9d\x77\x1d\x74\x7b\x9c\xbe\x83\xb7\xee\xab\x5e\x59\x5f\x3f\x5e\xbd\xef\xd6\x83\x7e\x97\xdb\x77\xf0\xd6\x3d\x35\xe3\x62\xe3\x44\xcd\x9e\x23\x9e\xba\xd6\x68\xb4\xb5\xce\x33\xff\x89\x9e\x3c\x54\x33\x59\x2f\x8e\xd5\x1f\x3c\xba\xdf\xe1\x76\x3a\xf6\x1e\xdd\x57\x37\x29\xa6\x56\xd4\xee\x3f\xba\xd7\x2d\x38\xdc\xfb\xd1\xd7\x13\x1d\x29\xbf\x3f\xd5\x91\x88\x77\x36\xfa\xfd\x8d\x9d\x44\x4f\x12\x00\xec\x07\xb4\x9e\xfc\x08\x14\x2d\x17\xac\xf5\x97\x6c\x82\x05\xcc\x22\xd6\xe7\x64\x1b\xaf\x60\x63\xb6\xe4\x74\xd1\x1b\x7c\x4e\x76\x6a\xd4\x32\x4d\x0f\xad\x9c\xb4\xbb\x49\xec\x4f\x7c\xb2\x2e\x9b\x2d\x9a\x69\x0d\xa5\xb9\x52\xb0\x69\x31\xd3\x32\x4a\xa7\x5e\x24\xaa\xe3\x45\xa2\x6c\xb6\xcc\xd7\x0c\xb8\x16\x4a\x33\x08\x84\xcc\xb9\x12\x2e\xf2\x4a\xe4\x63\xea\xff\x44\xf9\x3f\xfe\xe5\x3f\xca\x8f\xcc\xcc\xcc\xcc\x9c\x2b\x7f\x86\x74\xe5\xcf\x10\xc3\xcd\x94\x43\xe8\x17\xb3\x93\xa7\xbb\x4a\x8f\x3d\x56\xea\x3a\xad\xfa\x90\xf3\x38\x41\x0b\x21\xa8\xac\xe6\x63\x2e\x4b\xc3\x1e\x4d\x96\x16\xee\xe9\x17\xf0\x02\xab\x62\x86\x9f\xfd\xac\xfc\x06\xf3\x7f\x67\xcd\xec\x66\xd6\x30\xf3\x7b\x9a\xff\xd8\x3b\x77\x3b\xbb\x8b\xdf\x05\x2b\x60\x1b\xdc\x08\x78\x3c\x2d\xeb\xf5\x4a\x51\x3f\x4e\x2b\x50\x09\x2c\xc8\xa7\xe5\x24\xc1\xa7\xdb\x69\x6d\xd2\xa4\x51\xc1\x93\x36\xdc\x46\x14\x3f\x6e\x54\x70\x3c\x2d\xb7\xd1\x5b\xb2\x05\x89\xf8\xb2\xac\x3c\x6a\x54\xf0\x60\x56\xee\xb7\x2a\xb8\x21\x2b\xef\x40\xa2\x6c\xf1\x0a\xf6\xd3\x28\x94\xcc\x77\x8f\x6f\x22\xf2\x32\x2a\x4c\xa7\x9a\x7a\x86\xa9\x24\xe5\xf5\x82\xfd\x34\xc4\x1b\x52\xa3\x6b\x37\x51\xa9\xe9\x46\x59\xf7\x05\xdb\x54\x2b\xf1\xf4\x05\xbb\xd4\x3c\x5a\x1a\x65\x5f\x52\xb5\x74\x7e\xbd\xc3\xe1\x74\x7b\xc2\x88\xee\x54\xab\x49\x23\x0b\xbb\xf7\x0e\xab\x51\xab\xa9\x69\xe9\x8b\x57\xb5\x56\x3b\x84\x86\xe1\xc2\xf8\x95\x8b\xa3\x9e\xba\xd6\x78\xb0\x31\x66\x6f\xde\x70\xe3\x32\x69\xc7\xd4\x92\xe0\xdf\x38\x0c\x1c\x1f\x48\xe6\x82\xfe\x86\x98\xdd\x5f\x58\xd5\x5e\x3f\x35\xd4\xe8\x4c\x64\x82\x2d\xed\x2d\x9b\x8f\x4f\x1c\x78\xe9\xc5\xb1\x09\x43\x38\x61\xb1\x2e\x5d\xd9\xab\xb7\x1a\xf8\x55\xa7\x2c\x0e\x57\xa6\xd6\xef\x8c\x89\x1e\x5f\x7d\x55\x4c\xf0\x75\x0d\xaf\xcc\x84\x7a\xda\x9b\x2c\xb6\x4c\xa1\x33\xd4\x79\xe5\xaa\xe6\xa8\x34\xde\x74\x37\xe7\x8c\xf8\x52\x71\x97\x23\x2a\x7a\x42\x8d\xb5\x35\x2e\x6b\xd3\xd0\xda\x42\xb4\xb3\x45\x34\xd7\xef\xee\x18\xfa\xca\xda\xdc\x0e\xe6\x4c\x66\xcc\xcf\x6a\x4d\xa6\xac\x3f\x33\x1e\x72\xf3\x4e\x5f\x08\x18\x78\x86\xdb\xcc\x8e\xf2\xbb\xe8\xbe\xad\x76\xc0\xd6\x34\x4e\xe4\x08\x38\xf0\x72\x22\xf6\x65\x2b\xad\xca\xc6\x2d\x02\x13\x08\x32\x30\xd0\xfa\xfa\x52\x58\xcd\xa8\xd7\x55\x4e\x51\xb8\x38\x2d\x78\xe9\x4e\xae\x67\xdc\xc9\xe6\x50\x20\x57\xeb\xa3\x79\xff\xe6\xa4\x1b\x1d\x75\x27\x73\x21\x7f\xae\xd6\x47\xbe\x09\xe5\x92\x6e\xee\xa3\x40\xa6\xda\xe5\x48\x34\x85\x03\xe9\x2a\x97\xab\x2a\x1d\x08\x66\xaa\x16\xae\x9d\x55\x19\x00\x16\x0c\x50\xcd\x7e\xc1\x49\x74\xbc\xcb\xe0\x2b\x50\x4c\x20\x10\x4b\xbc\x16\x6c\x1c\xc5\x35\x3e\xb5\xb5\x24\x2d\x2f\xd2\x2a\xb8\x3d\x2d\xa7\x88\x1d\x5a\x4e\x87\xef\x54\xe3\x52\xa7\x8d\xc0\x97\x52\xcf\xc2\x51\x28\x61\x24\x96\x0c\xf4\x3b\x79\x0c\x89\x72\xb8\x47\xb0\x3f\x6d\xe5\x7d\x89\x54\x76\x68\x09\x15\x9f\xf6\x45\x82\xbd\x47\x6f\x70\x42\x6d\x36\x9c\x1b\x1c\xba\xa4\x54\x51\x7b\x71\xe9\xc2\xbc\x91\xf1\xfc\xa9\x55\x72\xf7\x05\x59\x0a\xc3\xd8\x89\xa7\x77\x6e\x7f\xfa\xe4\xf8\x7d\x8b\x9f\xd9\xb5\xf3\xa9\x5b\x97\xde\xd5\xba\xe9\xe6\x91\x25\x37\x6d\x91\x5a\x37\xdf\x3c\x32\x72\xf3\xa6\xd6\xee\xc6\x65\x3b\xda\x7a\xb6\x8e\x64\x4c\x0f\xeb\x78\x16\xb1\xc6\x42\xb5\xab\x2e\xee\xea\xe8\x4e\xb7\x39\xbf\xd1\xf0\xcd\xa9\xfe\xfd\xcb\xea\x99\xf4\x9e\xe7\xbf\x3e\x31\xf1\xf5\xe7\xf7\xfc\xe3\x03\xa3\x63\x2b\xbe\xfe\xfc\xee\xc9\xbb\xf6\x75\xf7\xee\xbf\x7b\x62\xe2\x9e\xfd\xbd\x3d\xfb\xee\x5d\xbe\xe8\xd0\x64\x26\xde\xb9\x22\x23\x31\x26\x9b\x5d\x1f\xad\xb5\x26\xda\xea\x97\x6d\x6d\xce\xad\x5f\xb6\x36\xbf\xe6\x1a\x60\xe1\x0e\x54\xcd\x1e\xe5\x66\x80\xa5\x48\xf6\x20\x14\x9d\xc4\x61\x9b\xb5\x6a\x50\xa4\x55\x88\x55\xaf\xd7\x2a\x38\x9d\x2e\xe9\x2b\x47\xce\xe4\xa8\x61\xaf\x36\x29\xb8\xda\x26\xfb\x90\x28\x1b\xd2\xd9\xac\xec\x35\xa9\x67\x0b\x54\x73\x82\x5d\xb6\x09\x92\x84\x7d\xc2\xb4\xd9\x59\xa9\x88\xa8\x27\x60\xc6\xeb\x97\x24\x9c\x16\x30\x27\xc9\x66\xbd\x60\xc7\xb6\xca\x5e\x56\xd4\xdc\x52\xe8\x42\xb9\xe6\x9a\x85\x4d\xe2\x6e\x5a\x15\x42\x13\x23\x2d\xf3\xe5\x05\xf9\xb8\x05\xdd\xc1\x7c\x32\xdb\x79\xfb\x57\xa5\x15\xd1\x96\x5c\xd3\xea\xc6\x83\x03\xf7\xac\xfd\xda\x5f\xfd\x4f\x6b\x7d\x26\xeb\x96\x36\x0d\x25\xdf\x32\x7a\x62\x2e\x5f\xb3\x18\xec\x5f\xd7\x82\xaa\x1f\x7e\x18\xbd\xb2\xed\xa8\x9d\x47\xdd\x6d\xd9\xe6\x5b\x06\xbb\x6f\xbf\xad\xdc\x98\xb3\x05\x1c\x86\x78\xd7\xe4\x98\xdf\xec\x77\x9a\x2d\x35\x3d\x59\x83\x9b\xda\xa8\xa3\xb0\x91\x7d\x82\x9d\x02\x0d\x98\xe9\x6e\x3a\x8f\xd6\xa1\x15\xd4\x8f\xa3\x68\xec\xa6\x8f\x7f\x77\x02\x2d\xbb\xe5\x57\xbf\x3b\x8e\xde\x5a\x84\xfa\x4f\x9c\x2b\xff\xe1\x38\x3a\x38\xdf\x22\xf6\xfe\x14\x6a\x67\xb7\x32\xbf\x01\x1e\x32\xea\xb9\x12\x24\x9a\x55\x4f\xd3\xe0\xf4\x22\xc2\x9a\xf9\xd3\x0a\x8a\x1c\x4b\xb7\x8f\x83\x5e\x94\xb5\x0b\x27\x66\x24\xf2\xa7\x98\xe7\xdf\x65\xc4\x97\xcb\x4b\x3f\xa5\xe3\x39\x7f\x4e\x05\x07\x91\x8b\x4f\xaa\xe0\xd3\xb2\x66\x61\x3f\x30\x57\xa1\x61\xec\x26\x16\x66\xd5\x43\x2b\x00\xe8\x49\x8f\xe7\x75\xa5\x00\x3d\x80\xff\x9c\xb6\xb4\xa4\x4b\xad\xb4\x55\x6c\xa1\x91\x6e\x4b\xad\x5e\xc4\x3d\xe9\x52\x3d\xbd\x49\x33\xa7\x7f\xa4\x3e\x05\xf5\xaa\x35\x8b\x0b\x36\xb9\x03\x89\xa5\xb4\x7a\xfe\x50\xfa\x22\x7d\xea\x43\xa2\xdc\x51\x10\xec\x25\x2b\x9f\xc8\xfb\x88\x59\x4e\x0b\x72\xb6\x59\x4d\x6d\xe6\x24\x90\x5b\x7c\x82\x5d\xce\x91\x1b\xad\x42\xc9\xe0\x84\x6c\x98\x3c\xd4\x63\xc7\xe9\xff\x8e\x8e\x39\x84\xf9\x90\xc3\xa3\x4d\x26\x5c\x02\x0d\x06\x6b\x44\xf4\xff\x56\xad\x7b\x5f\x18\xd8\xd4\x15\x2c\x64\x0f\xdf\x77\x65\x6b\x6b\x93\xd8\xd8\x9c\xfd\x7f\x2a\x52\xf9\x5e\xa6\xdb\x97\xea\xa9\xcd\xae\xf0\xfc\xd2\xf3\xf1\x39\x34\x1e\x0d\xfa\x82\x84\xef\x1f\x70\xfb\xd9\x00\x9f\x00\x16\xe2\x50\xd9\x50\xa9\x6e\xaa\xe4\xd2\x32\x20\xb1\xc4\x5a\x41\xc7\x89\x17\x1c\x2d\xf2\x01\xd3\xc5\xed\x2f\x95\x08\x8f\xcf\xb1\x16\x56\xe2\x27\xc1\x01\x31\xe8\x83\xa2\x87\xe6\xcd\x55\x95\xa3\x55\x57\x6a\xb9\xa8\xd3\x44\x57\x67\xfc\x44\xd1\x4c\x6a\xa9\xa8\xdf\x29\xd8\x65\x2b\x4f\x60\x66\xc4\xf3\x67\x0f\x66\x2a\x50\x8b\x53\x29\x4b\x39\xd7\xb4\x62\x6f\x47\xf7\xbe\xf1\x74\x7a\x7c\x5f\x37\xf9\x7c\xb9\x2d\x93\xe9\xb4\x85\x6a\xbd\x99\x36\xae\xa9\x73\xf7\xb2\x54\x7a\x6c\x57\x5b\xdb\xae\xb1\x74\x6a\xf9\xae\xee\xd6\xa1\xa1\xd6\x60\x3a\xee\x1c\xa6\xb2\xb8\x0c\x62\x6c\x89\x7b\x10\x8c\x60\x85\xcb\x81\x16\x43\xea\x94\xf9\x83\x63\x74\xff\xd5\xc1\x31\xb6\x3f\x7d\x70\x8c\x95\x56\x01\xce\x9f\x1d\x63\x52\x6b\xf3\x84\x3f\x3a\x3e\x06\xe5\x63\xae\x65\x68\xd9\x3b\xa8\xb7\xfc\xc2\x3b\xe5\x12\xbb\x95\x79\xe0\x79\xd4\x5f\x3e\xf3\x7c\xf9\x3b\x68\xd3\xec\xf1\x17\x5f\x04\x04\x3f\x66\x02\xec\x12\x5e\x02\x11\x96\x01\xf6\xa7\x65\x3b\xaf\x90\xf0\x1b\x57\xa7\x65\x96\xd0\xb0\x41\x3d\xc2\xc3\xa4\xcc\x9f\xdf\xe1\xd7\x8b\xf4\x2c\x14\x7a\x7e\x87\x4b\x02\xd9\xee\xa7\xe9\x1c\xb9\xda\x2b\xd8\x4b\x60\xd3\x85\xc5\x4b\xce\xef\x60\xb4\x16\x76\xe1\x08\x0f\xf5\x6c\x3d\xd5\x54\x59\x90\xf6\xc7\x12\x3e\xd8\xba\x73\x2c\xe3\xca\xaf\xe9\x77\xbb\x6d\x36\x1b\x32\x18\xac\x56\xbb\x65\xf6\xee\x96\xaf\x4e\xb6\xd4\x56\x37\x25\x33\xe3\x4e\x8d\xc6\xc8\xed\xda\xbc\xb7\x7a\xd1\x86\xd6\xba\x9e\x9e\xe1\xac\x60\x33\x5a\x05\x64\xd0\xeb\x7e\x72\xc3\xf0\x75\xdd\x75\x91\x4e\x6f\x24\x9d\x4a\x59\x7c\x16\x40\x80\x19\x0f\xdb\xc7\x4b\xd0\x01\x9b\x81\xb8\x30\x3d\xaf\x60\x6b\x5a\xf6\x6b\x15\xec\xca\x12\x28\x94\xe4\xd5\x0d\xe6\xa6\xb3\x72\x8b\x49\xc1\x21\x82\x92\x1a\x4c\xea\xde\xf2\x06\x93\x60\xc7\x4d\x12\xc8\xfa\xf6\xf3\x09\xbe\x16\x49\xc2\x7e\xbb\xec\x6d\x92\x24\x1c\x17\xe4\xaa\x06\x49\xc2\x49\x3b\xae\xa6\xf8\xf9\xfc\xda\x42\x4d\xa2\x1e\x59\x90\x36\x1f\x66\xb2\x0b\x52\x33\x5f\xa2\x77\xe1\xae\x7d\x7c\x9f\xc9\xa2\xd3\x07\x62\x49\x57\xc7\x92\xee\x56\x8d\xd1\x5d\x15\xf6\x85\xed\x7a\xae\x3d\x6b\xf1\xc6\x9d\x2b\xd6\xdd\x70\x53\xb1\x73\xf7\x58\xca\xec\x09\xdb\x3d\xf5\x31\x47\x61\xfd\x91\xde\x67\x99\xd3\x8f\x5b\x62\x76\x5b\xd8\x6b\x69\x4a\x44\x13\x88\x41\x45\x96\x65\xe2\x7e\xb3\xcf\x69\x3e\x70\xd3\x5f\xd6\xf4\xae\x6e\x72\xd7\x55\x87\x0d\xc6\x78\xaa\x39\xd8\xbc\x7e\xa0\x16\x10\xba\x9f\x4b\x30\x3f\xe7\x4f\x03\x0b\x51\xc0\x2c\xad\x83\x34\x72\x62\x25\x5b\x55\x62\x68\x66\x62\x3e\x59\xe5\xf0\xb0\xe8\xfe\xbf\x3e\xf5\x2e\xb7\x1d\x8d\x5d\x59\x56\xf3\x7d\xce\xf2\xab\xec\x27\xec\x63\x90\x82\xdd\xea\xb9\x07\xb8\x2e\x27\x07\x35\x0a\xb6\x67\x8b\x09\x5a\x15\x94\x00\xbd\x48\x97\xe0\x68\x59\x7c\x23\x91\x54\x82\xb6\x31\x10\x8a\xa6\x4c\x0a\x36\xdb\xe8\x86\x20\xbf\x59\x3d\x60\xc3\x63\xa6\xdb\xd5\xb0\x5f\xc0\x35\x12\xc8\xc1\x84\x60\x2f\xc6\x6a\xe8\x96\x36\xa3\x20\x6b\xa3\xf3\x2a\x58\xe8\x62\x69\x7a\x3f\xcc\x78\x2a\xad\x5c\xb6\xa5\x1b\xd1\x43\xa6\x2a\x41\x89\xe0\x64\x78\x0d\xc7\x6a\x35\xdc\xfb\x9e\x9a\x6c\xc0\x9f\xad\xf5\xbd\x1b\x30\x85\x74\xf9\x2b\x36\x1f\x69\x59\xe9\x4f\x5d\xd3\x9e\x5a\x5d\x55\x7e\xd5\xb1\x74\xf3\x9e\x6c\xeb\xc1\x6d\x93\x01\x46\x33\xfb\x7e\xff\xaa\x66\x37\xcb\x87\x5b\xc6\x25\xa6\x6e\x76\x6a\x7d\x54\xd8\xfe\xd2\xed\xa9\xba\xfa\x06\xaf\xa7\xfc\xd8\x7c\xcd\xec\x21\xf6\x11\x7e\x12\x04\x62\xef\x0d\x74\xb7\x75\xd1\xc0\x2f\xe8\x18\x89\x2c\xec\x54\x70\x8c\x26\x05\x1b\x69\x7e\x47\x47\xf3\x3b\xd8\x68\xa3\x05\xde\x5a\x93\xba\x56\x50\xb1\x25\x44\x07\xc9\xff\x46\x76\x67\xf3\x91\x57\xbe\x81\xda\xde\x18\x7b\x73\xf8\x2f\xd6\xe6\xd8\x4f\x87\x6f\xd8\x24\x7d\x11\xe1\xc5\x2f\xde\x61\xdd\xc6\xde\x8d\x47\xd5\x33\x9d\x96\x30\x3e\xe6\x04\xdb\x0e\x0e\x68\x84\x4a\x9e\xc9\xca\xfd\x89\x43\x92\xcc\xea\x21\x49\xe6\x85\x43\x92\x2e\xad\xb8\x40\x4b\xfc\x0d\x52\x38\xd2\x9e\x0a\xf8\x1a\xda\xe3\x31\x49\xf4\x32\x8f\x87\xf3\x49\x8f\xaf\xb6\x39\x48\x3e\xdd\xc9\x3c\xe9\x2f\x59\xbe\x96\x4d\x03\x80\x1f\x46\xd4\x18\x4b\x36\x6b\x14\xec\x4d\x97\x34\x15\xa4\x12\x20\x71\x54\xc9\xa6\x9e\x74\x17\x44\xa2\x6c\xb3\x08\xf6\xa2\x46\xef\xa5\xeb\x4a\x1a\xaf\xaa\x24\x66\x7a\xe6\x82\xc5\x2e\x23\x1b\xe1\x21\x2a\xcc\x6b\x84\x88\x0a\xb9\xf3\xa8\x1f\x25\x47\xc3\xcd\xd9\x26\x7f\xc8\x1d\xf4\x6f\xf5\x3d\xaa\x5f\x36\x11\xed\xdd\xbc\xa8\xf7\xa6\xf2\x7b\x37\xf8\x62\x0e\xad\xd7\x68\x74\x9f\xee\xd6\x2d\xeb\x88\xf6\xe6\xa2\x22\xe5\xc7\xf3\x4c\x80\x39\xc4\x37\x81\x06\x02\xf0\xe7\xce\x2b\x5a\x38\xa7\xe8\x79\x94\xb8\xeb\xdd\x47\xb8\x3b\x1f\x99\xf9\x15\x93\xac\xa3\x67\x3c\x9d\x40\x39\xf6\x28\x1f\xa2\x79\x5a\x11\x86\xa1\xa8\x27\xd8\x6c\x3e\x61\xcd\x2b\xd8\x91\x96\xc3\x9c\x32\x7f\x68\xa8\xcf\x44\x97\x8d\x89\x83\xb0\x98\xd4\x43\x43\x13\xc4\xc3\xea\x1d\x64\xb6\xb5\x61\xc1\x2e\x73\x16\x69\x01\x73\x5d\x4c\xf2\xf3\x30\x4b\x75\xaf\xe8\x04\xf3\xe9\x6c\xbe\x70\xd9\x57\xfa\xfa\x0f\x4f\xe5\x0a\xeb\x8f\xf6\x0d\x1c\x5e\x93\xfb\xa9\x33\xde\xe0\xf3\xa5\x12\x4e\x67\x3c\xe5\xf5\xa7\xe2\x28\x87\x31\xb3\x71\xea\x9b\x3b\xa5\xec\xc6\xaf\xaf\x5b\x7f\xe7\xd6\xe6\x96\xcd\x27\xbe\x96\x49\x0f\x37\xf9\x7d\x4d\x8b\xd3\x99\xd1\x7c\x20\xd0\xfc\xc7\xf8\xaa\xe0\x48\x16\x90\x0b\x55\x3e\x8e\xfe\xee\x57\xb7\xa0\x65\xe5\xc7\xdf\xfc\xdd\xc7\x37\xa1\xb1\xf2\xe3\xbf\x44\xfa\x73\x27\xca\x67\x16\x95\xef\x3c\xbe\xd0\xa2\x98\x06\xe6\x0e\xb2\x9f\xf2\xbb\x40\x03\x06\x70\x81\x17\x6e\x05\xec\x4a\x63\x21\x57\x72\x57\x40\x4d\xb6\xe8\x72\xd3\x9d\x86\x4e\xbd\x58\x74\xd3\xb4\xb3\xdb\xac\x57\x4f\x15\xe3\xce\x96\x58\x15\xf5\xb3\x34\x84\xc1\x9e\x6c\xc9\xa1\xc2\x16\x4b\xb6\xe8\x70\xd2\x9c\x93\xa0\x17\x8b\x4e\x07\x69\x3a\x2b\xe7\x8e\x51\x46\xc9\xc8\x20\x49\xd8\x49\x4b\x21\x1d\x76\x59\x47\xb7\xaf\xba\x5d\x82\x5a\xd2\x2c\x14\x28\x03\x1d\xc8\x83\x0a\x95\x83\x7e\x5c\x89\x7c\x32\x97\xff\xf4\xd8\xb3\xb7\xf4\x31\xd7\x16\x67\x8f\x3f\x8a\x06\x6e\xd8\xb4\x09\x6f\xde\xca\x29\x37\xcc\xde\x88\x5e\x4a\x7c\xb9\x9b\x1e\xe5\xb5\x73\x3d\x7a\xa8\x7c\xcb\xf5\xdf\xfa\xd6\xb5\xd7\x03\x0b\x30\xb7\x8b\x2d\x57\xe6\x97\x83\x5b\x81\x2e\x3b\x96\x62\xea\xb1\x90\x81\x18\x2d\x65\x8c\xe8\x45\xba\x75\x00\xa7\xd2\x25\x4b\x45\xcc\x9b\x2f\x99\x5d\x3d\x12\xc9\xd4\xa2\x9c\x58\xac\xa7\x93\xa9\x8f\xe9\x45\x5a\xa9\x7d\x7e\x32\xf5\x42\x49\x67\xb4\x78\x03\x04\x71\x39\xec\x58\x2f\x81\x1c\x88\x11\x28\x11\x97\x24\x9c\x12\xa6\x8d\x8e\x64\x8e\xfa\xc1\x0b\x66\x77\x91\x4b\x44\xda\x5c\x17\x52\x5d\x22\x3d\xd5\x6a\xde\x23\x92\x49\x8b\x74\xd2\xff\x96\xbd\x75\x73\x66\xa2\x33\x61\xab\x1f\x6e\x75\xd5\x0a\x1f\x9a\xdd\xce\x32\x57\x7f\x55\xbb\x35\x11\x72\xe4\x13\x71\xd1\xc8\x6a\xf4\x97\xd0\x03\xe1\xe5\xab\xe3\x6d\x23\xb5\xf1\xe6\x7c\x7b\xad\x35\x66\x65\x5d\x8f\x5d\xd1\xb4\x3f\x6f\x09\x85\xa3\xb6\x44\x5d\x4d\x5c\xef\x35\x55\xe4\xe0\xb7\xfc\x0d\x20\x41\x27\x2c\x86\x11\x78\x0b\xf0\xe2\x34\xee\xcf\x95\x86\x55\x39\xe8\xcb\x16\x17\x0f\x93\x79\x2f\x1e\xd2\x8b\xc5\xe1\xc5\xa4\x39\xdc\xa3\x17\x71\x61\x3e\x88\x21\xb1\xae\x33\x57\xf2\xaa\x17\xe1\x74\xa9\xba\x42\xca\x51\x62\x1f\x4b\x59\x55\x2e\x02\xd1\xb3\x42\xa9\x5e\x6d\x67\x6d\xf2\x10\x12\xf1\x92\x6c\x69\x50\xbd\xd1\x9b\x2d\x0e\x0e\x91\x5f\x1e\xec\xd7\x8b\xc5\xa1\x41\xd2\x1c\xea\xd2\x8b\xf2\x52\x24\xca\xf5\xc4\x11\xa7\x25\x79\x28\x2b\xd8\xf1\xb0\x84\x07\x05\xb9\xbd\x67\x3e\x2b\x88\x47\x68\x4d\x3c\x71\xcf\x76\x19\x65\xd5\x13\x7d\xd3\x04\x15\x17\x5d\xb1\x7a\xba\xff\x59\xf8\x53\x8e\x19\x55\x2e\x2f\x3d\x49\x6b\x21\x2d\xf1\x47\x02\x78\xb5\xd5\xa8\xe5\x9c\xc1\x6a\x57\x6d\x5b\x2a\xcf\xeb\xac\x01\x8f\x23\xe4\xaf\xaf\xaa\x4b\xc4\x07\x6a\x36\xe4\xae\x59\x9c\x5d\xdd\x53\xfd\xff\x33\xf7\x26\xe0\x6d\x5c\xd7\xbd\xf8\xb9\xc0\x60\x21\x40\x2c\x33\xd8\x88\x8d\x00\xb8\x00\x04\x07\xc4\x32\x00\x09\x82\x14\x25\x52\x12\x49\x51\xa2\x28\x89\x92\x1d\xd9\xf1\x22\x59\xbb\x23\x8b\xb2\x68\x59\xf2\xa2\xc8\x89\xe2\x2a\xb6\x23\x27\x8e\x52\xbb\x76\xd2\xd6\xb5\x5d\xfd\x1d\xf5\x9f\xbc\x19\x00\x76\xf5\x5c\xd7\x4d\xec\x38\xb1\xe3\x36\x49\x5f\x1b\xb9\xad\x93\x97\x26\xed\x73\x0a\xc7\x49\xf3\x5c\x37\xed\x73\x25\xea\x7d\x77\x01\x08\x82\x84\xc0\xb4\xee\xfb\x2a\x7e\xd0\xec\x33\xe7\xfc\xce\xb9\xf7\x9e\xbb\xfd\xae\xd1\xee\xb5\x76\x0f\xc4\x36\xec\xec\xdb\x70\xef\x3a\x62\xb7\x2f\x94\x9d\x55\x7d\xf4\x13\x26\xbf\xb9\xc9\xc1\x37\xb7\xb6\x05\x03\x48\xad\x7a\x4c\xaf\x0d\x08\xae\x68\x57\x72\xef\xca\x55\x81\xde\xf1\x2e\x6b\x5b\xc0\xa3\x73\x4e\x74\xc7\x27\xb3\xad\xc3\x97\x5e\x5e\xe4\xd2\x0b\xf8\x40\x56\xc2\x71\xc6\xfd\xe4\xd1\xd2\xb1\x2f\x72\x2e\xc1\xb8\x41\x90\xbc\xaa\x32\x54\xc4\x41\x47\x6c\x9b\x48\x09\x5c\x70\x98\x32\x66\xb1\xd8\x4d\x29\x42\xba\x13\x8c\x2c\x44\x19\x66\x4c\x3a\xb2\x26\xa7\x18\x1c\xa4\x47\x50\x36\xf1\x45\x9b\xa7\x93\xf0\x85\xd0\x79\xc5\x79\x08\x04\x73\x55\xc5\xf2\x10\x4a\x33\xdf\xad\x1a\xb2\xae\x2e\xf7\x57\x54\x0f\x06\x8a\xa3\xdb\xc3\x2b\x36\x74\x2c\x60\x06\x19\x68\xef\x1c\x1b\x1e\xf4\x3c\xde\x71\xc3\xad\xc7\x86\xaf\x3b\x73\x4b\xef\x0f\x5b\xa2\xd9\x40\x80\x0e\x0f\x0d\x78\xfb\x5c\xae\x16\xb4\x6d\xcd\xde\xa9\x21\x9f\x10\x8e\xa5\xfc\x33\x33\xe2\xf8\xd8\x46\x69\xe5\xde\x54\xe7\x48\xd2\xe7\xcb\x4c\xf4\x3c\x92\x25\x0c\x22\xa7\xd5\xdf\xf1\xa5\xc2\x4e\x67\x38\xe5\xf3\xa7\xc3\x2e\x87\xdd\x93\x24\xeb\x04\x00\xa7\xd2\x9e\x06\x1d\xe8\xa1\x19\x2c\xd0\x3f\xcf\x75\xa1\x2f\xcf\x54\x2b\x6a\x4d\xf3\x84\x17\xd6\x0a\xe1\x05\x4f\x2a\x83\x26\x32\x20\x68\x9e\xf0\xa2\x1d\x65\x35\x3a\x54\xcd\x7a\xf1\x2e\x72\x1e\x42\x03\xfd\x73\x3f\xaf\x62\xbf\xd0\xbc\xf8\xc6\x4f\xf7\x5c\xfa\x2a\x7a\x16\xfe\x73\x64\xe8\x74\x69\x6c\x0b\x65\xc8\xa0\xdc\xcc\xdc\x67\xf5\xd5\x32\x3c\xf9\xd3\x37\x3e\xb1\x50\x86\xbd\x44\x06\x0b\x08\x65\xb6\x83\x1a\x19\xac\xf3\x32\xd8\x2a\x32\xd8\x71\x04\x03\x3c\xcd\xcc\x90\x95\x10\x2a\x55\xc9\x62\xeb\x4c\x6b\x74\x11\xdd\x42\x71\x5e\x45\xfc\x2a\xa4\x9a\x7a\xf3\xa7\xfb\xab\x05\x7a\xe0\x87\x7f\x7d\xc3\xe9\x4f\x5c\xca\x63\x91\x2a\x32\xdd\x4f\x64\x8a\x42\x0c\x6e\x5a\x52\xa6\xee\xb2\x4c\x72\x38\xa1\x18\x35\xa5\x82\xcd\x18\xd6\x8b\x4a\x2b\xe9\xed\x20\xf4\x42\x4c\xce\xf8\x02\x39\xbb\x09\x49\x8b\x62\xc3\xc5\x73\x93\x3b\xb7\x40\xe2\xbe\x74\xa5\xa5\x72\x61\x27\xe1\x42\x25\xce\x9d\xb8\x5f\x1c\xf7\xeb\x05\x87\xab\xd9\xe2\xf3\x7a\xcd\x87\x43\x59\x29\xe5\x0b\xaf\xf6\x37\xb9\xbc\xad\x96\x40\xb2\x6d\xb8\x5a\xb9\x0b\x7f\xd6\xed\xd3\xdb\x84\x66\x7b\xb0\xdb\x75\xb2\x7b\x58\x74\x05\xdd\x7a\x8f\x47\x58\xb3\xfa\xd2\x63\x44\x5f\x0d\xd3\xf7\x24\xd1\xd7\x47\x66\xfb\x3e\xb0\xa4\xc6\xfe\x8a\xc6\x2d\x09\x39\x91\x2e\x9a\x69\xd3\x61\xa7\x44\x8a\xa4\xa6\x8b\x45\x1b\x69\x25\x2c\xe8\x6c\x4d\x7a\x51\x01\x0b\x89\x5b\x74\x96\x92\x6c\x23\x5d\x74\x38\x55\x3b\x39\x5a\x30\xd9\x74\xbc\x50\x44\x5a\x73\x8b\x9f\x52\xbb\xc9\x81\x9c\xdc\x2d\x14\x54\x9c\xa6\x95\x24\x67\xe4\xe7\x05\x39\xb0\x00\x9c\x5a\x1a\xe2\x90\xba\xf6\x54\x15\x44\xcf\x38\xc3\x19\x7f\xa0\x37\xe2\x70\x45\x7a\xfd\xfe\x4c\xd8\xf9\x5d\xa4\xba\xbf\x07\x9f\x0c\x66\x3a\xed\x78\x8b\x4f\x56\x30\xfa\xc0\x9b\xec\x74\xb8\x3a\x93\xee\x32\x79\xb0\x01\x3d\xab\x3a\xe0\x4b\x76\x38\x5c\xe1\x64\x0b\x3e\x69\x27\x84\xc1\x6a\x86\xd5\x09\xf0\x80\x1f\xa2\x70\x94\xe1\xe4\x4c\xcb\xee\x84\xe2\xd5\x95\xe4\x48\xa2\x68\x64\x2d\x29\xdd\x65\x5a\x15\xd9\x43\xa6\x38\x16\x5b\x69\x33\x4a\x2b\x99\x52\x54\x0e\x53\x45\x84\x7d\x86\x17\xf2\xc8\xed\xc5\x75\x8b\x0e\x5e\xf1\x1b\x73\x39\xd9\x2a\xe4\x1d\x2d\x3e\x12\xb8\x46\xbc\xbc\xf0\x9c\xd6\xea\x40\xfe\x10\x29\xa2\x53\xa8\x86\x61\x8d\x31\xde\x18\x11\x6b\x01\xc0\x65\x06\x7a\xb2\x55\xea\xb4\xb7\xe5\x26\xc5\xd8\xd4\x60\xbb\xa3\x43\xf2\xa3\xd7\x2b\x64\x38\x63\x61\x9f\x37\x1c\xf6\xfa\xc2\xdc\x7b\xc6\xb0\xb4\x22\xd4\x3d\xd1\x1f\x0c\xf6\x4f\x74\x07\x07\xa5\xb0\xf1\xdf\x9a\x19\x4f\xce\x13\xaa\x54\x30\x16\x0b\x06\xe3\x71\xd2\x3f\x70\xe5\x12\x80\xfa\x5f\x09\x2f\x8b\x00\x47\xd8\x0c\x4f\x48\x2f\x24\x44\x31\x5b\x9b\xb1\x93\x98\xb9\x52\x51\xa3\x6f\xae\x70\xa3\xd0\x54\x6b\x31\x11\x9a\x7b\x1e\x89\x72\xb3\x44\x48\x94\x39\x29\xaf\xe7\x09\xff\x81\xaa\x09\xff\xaf\x6b\x22\xb3\xdd\x14\xde\xc2\xd3\xf8\x1c\x14\x4e\xc3\x52\x76\x3b\x9a\x27\x4e\x09\xf1\xed\x6a\x5b\x9a\xe7\xd0\x03\xaa\xd9\xb9\x97\x90\x65\xee\x7f\xa3\x95\x97\x7f\xfe\xd5\xeb\xcf\x9c\xe0\x2e\xbd\x32\xf7\xca\xeb\x73\x9f\x7f\x15\x8d\xcd\xbd\xa0\x52\x21\xc6\x97\x31\x38\x77\x0f\xe1\xc0\x59\x0b\x37\x42\x85\xfa\x46\x4e\x90\xc6\x30\x1c\x13\xac\x4c\x14\x03\x06\x5c\x45\x41\xf2\x68\x85\x0e\x67\x0c\x57\x07\x81\x8d\x5d\xe8\x4f\x90\x1d\x79\x25\x2f\x77\xe7\xe4\x80\x50\x08\x47\xd2\xc3\xd8\x7b\x1d\xfc\xb2\xd9\x72\x2c\x68\x7e\x12\x45\x75\xb5\x23\xae\x6e\xc8\xa1\xb3\xf2\xf7\x77\x72\xe5\x2a\xc8\xca\xaa\x9a\x89\x63\xc7\xef\xcd\x8e\x34\x60\xd6\x39\x70\x9c\x6f\x2b\xd7\x54\xd2\x95\xda\xcb\x63\x96\x9b\x7f\xff\x1d\xec\xd3\x84\xe3\x46\x7b\x1a\x8c\xd0\x0c\x56\xd8\x56\xc5\x73\xd3\xbc\x24\xf1\x0c\x36\x28\xdf\x88\xec\x46\x40\x22\x19\xbf\x2e\x9b\x72\x35\xa4\x37\x21\x5b\x56\xa3\xab\x62\xbe\xb9\xf4\xea\xd3\xb8\x9c\xaa\x10\xe0\x90\x32\x6a\xb1\x5c\x93\x1f\x9a\x5c\x8b\xe4\xe9\x74\x69\x16\xc8\xf3\x63\x52\x66\xcd\x0b\x84\x0b\xac\x8a\x3c\x7b\x89\x3c\x36\xb8\x76\x59\xf2\xd8\x1b\xc9\xe3\x60\x38\x29\x26\x5b\x6e\x31\x52\xb4\x0c\x5b\x20\xdc\xae\x72\x11\x36\x2f\x1f\x2d\xbf\x48\xd9\x45\x65\x3c\x49\x64\x0c\x42\x06\xee\x5b\x86\x94\xb2\x2f\x21\x27\xd3\x45\x81\x66\xe7\x61\x09\xc9\xbd\x75\xa5\x96\xc1\x2a\x9b\x70\x9c\xec\xa2\xfd\x43\x4d\x64\x18\x76\x51\xa4\x47\x5a\x49\xe9\xc3\xfa\x98\x78\x41\x11\x7c\x4b\xe8\xd3\xa0\xe7\x68\x81\xa2\x43\xb5\x79\x38\xba\xab\x36\x03\x9f\x87\xa0\x36\x07\xf7\x2e\xca\xbc\xd5\x94\x33\xa7\xe2\x4f\x13\x0b\x79\x73\x08\x38\x0b\xc8\x73\xf8\xc6\xe4\x39\xc2\x22\xf2\x1c\xe2\xdc\x65\x06\x9d\xcb\xa1\xfb\xb0\x67\x97\x89\x74\xa8\x63\xff\xbf\x92\xa3\xd3\xa5\x99\x97\xe3\x25\xe2\xd1\x15\x41\x88\x43\xc3\x3c\x26\x65\x9f\xbe\xa6\x91\x2c\xf6\xc6\xb2\x10\x87\x56\xf1\x42\xde\x6c\x11\x72\xd5\x13\x85\xca\x72\x11\x97\x9e\x17\xad\xa7\xec\xcf\x15\xe9\x2a\xee\x0c\x1c\x93\x6f\xde\x9f\x1f\xb9\xba\x84\x4b\xba\x72\x03\x89\x0b\xae\x26\x95\x5e\x2c\x9a\xa8\x0b\x9b\x12\xcc\xb5\x0b\x21\x72\x9a\x7a\x36\x71\x6b\x55\xd9\xad\x15\xb1\x89\x17\x94\x70\x72\x09\xed\x1a\x38\xf8\xbc\xda\xf6\xc6\xde\x5d\x01\xa4\xa1\x73\xab\xc0\xc0\xb8\x00\x6c\xd0\x06\xfb\xd8\x3c\x0a\xbb\xa6\x44\x19\x00\x5a\xf5\xa5\x22\x02\x9e\x33\x89\x72\x28\xad\x20\xae\x24\x07\xe8\xc0\x6c\x81\x34\xd6\xdb\x4d\x25\xb9\x55\xca\xdb\x05\xd2\x10\x12\x6a\x12\xf3\x02\x69\x1e\x11\xa0\x89\x74\x01\xb5\xb0\x79\x16\x1d\xe5\x5e\x28\xa5\xb9\x3c\xe0\x71\x01\xc9\x5a\x88\xb7\x55\x68\xd6\x70\xa5\xd4\xb0\x79\x01\xd7\xda\xdc\x77\x7f\x54\x66\x5b\xfb\xfa\xd7\x55\x6b\x5f\x44\xd5\x94\x6b\xaa\xb5\x73\x87\x29\xeb\xda\xdc\x2b\x2f\x82\x9a\xf2\x0a\x69\xef\x07\x33\x58\x20\x09\x9f\x99\x1f\x47\x6b\x29\x67\x62\x32\x97\x96\x7b\x48\x07\x40\xc1\x23\xf4\xe8\x45\xa5\x53\x5b\x92\x93\x52\x99\xa3\x6c\x09\xd2\x21\x09\x89\x8a\x19\x48\x47\xa4\xac\xe6\x9f\x53\x35\x0b\x9e\x4e\x4a\xa1\x28\x28\xb8\xe6\x28\xeb\xf8\x85\x2c\x44\x4a\x4f\x27\xbd\xdb\xc3\xcb\xc1\x9c\x2c\xd0\x90\xb4\x86\x99\xe8\x2a\x61\x7b\x35\x69\xd1\x77\x0e\x35\x8a\xda\x17\xd1\x1a\xd5\x0f\xdd\x69\xda\x20\x9c\x47\xda\xd3\x00\xe0\x84\x6e\x88\xc3\x26\xc6\x0a\xef\x33\xd0\x91\xb5\x64\xb4\x9c\x12\x36\x54\xe6\xb5\xbb\x2c\x84\x1a\x9e\x8c\x59\xb7\xd0\x09\xed\x21\x17\x2f\x14\xb4\x82\xd8\x43\xc2\xee\xb0\x8f\x17\x0a\x4e\x64\xec\x26\xb1\x4c\x9a\x6f\xc0\x81\x84\xf3\xba\xe5\xf0\x20\x69\x71\x2e\xb8\x0c\x32\x24\xd5\x57\x48\xc9\xbf\x94\x6e\xd7\xfe\x3b\x75\x2b\x6a\x05\x31\x16\xa7\x3c\x99\x72\xcf\xbf\x43\xc5\x4e\x97\x66\x39\x2a\xae\x25\x19\xec\x72\x74\x7c\x84\xe5\xbd\x65\x1d\xf7\x12\x1d\xfd\x90\x82\x1b\x98\x8e\xed\x0b\x74\xec\xc1\x3a\x4a\x44\xc7\x56\x3a\xb9\xb4\x8b\xe9\x98\xc6\x55\x07\x44\x27\x4b\x74\xf1\x45\x6d\x8b\xdb\x2b\x50\x77\x96\x3d\x39\x50\x7a\xda\x89\xa6\x29\xe3\xd2\x9a\xb2\x8c\xb8\x76\x29\x97\x25\x94\xbd\x50\xce\xa1\xf9\x65\x10\x5c\xa9\xbf\x48\x72\xef\xcb\xd7\xd6\x72\x2d\x95\xf5\xbd\x9f\xe8\x9b\x85\x0d\x70\x2f\xd3\x77\x68\x81\xbe\xe3\x86\x92\x9c\x49\x28\x6e\x4d\xa9\x10\x72\x67\xf4\xa2\x12\xd3\x96\xe4\xac\x44\xda\xea\xd0\x45\xa5\xdf\x52\x92\xfb\xad\xa4\xb3\x19\x63\xb0\x11\x89\x4a\x3f\xc3\x60\x35\x5f\xd4\xba\x43\x31\x86\x81\x12\x8e\xe0\xea\xc3\xf8\x10\x41\x61\x03\x46\x81\x50\x10\x2a\xae\x48\x6e\x49\x3c\xea\x26\xe3\x65\x40\x74\xa6\x51\xe2\xee\x59\x0e\x74\xdf\xae\x97\xde\x2f\x0f\x2e\xa2\x0d\x03\x0d\xc3\xf3\x24\x4b\x23\x2b\x61\x1a\xce\x30\x44\x93\x0b\x10\x1d\x30\x94\xe4\x70\x42\x9e\x4a\x17\x7d\xb4\x5c\x5c\x2b\x91\x45\x6d\xd0\x45\x45\xb4\x94\x0a\x2e\x11\xe9\xc5\x62\x88\x16\x7f\xa2\x95\xd4\xcf\x8d\x96\x52\x61\xc2\xd8\xab\x17\x8b\xab\xe8\xf9\x55\x89\xe2\x04\x2d\x09\xb7\x21\x51\x59\x15\x22\xb9\x46\x72\x80\xe4\x1a\x03\x49\x9a\xa4\x56\x62\x88\x7d\x61\x5e\x50\xba\xa7\x97\x86\xb8\xb6\x0e\xdf\x60\x19\xa1\xa5\x80\xae\x2d\x36\x77\xd4\x02\x8b\xdc\xb5\xe5\xe8\x12\x50\x73\xcd\xb5\x35\xfe\xaf\xd6\xa6\xd3\x9f\x2d\xae\xfe\x03\x82\x33\x28\xa4\xfe\x2c\x37\x04\x46\x00\x5b\x36\x92\x75\x65\x5d\x3a\x97\x2e\xa2\x3b\xf3\x8b\x5f\x3c\x5a\x7a\xe7\xf1\x7f\xfa\xf9\xd9\x5f\xfc\x0c\xbd\xf0\xab\x4b\x8f\xfc\xf3\x3f\x3d\x34\x77\xe9\x37\x2f\xbd\x87\x63\xac\xf6\x2b\xb3\xea\xbf\xd3\x1c\x25\xdc\x0d\x19\xb8\x93\x32\xb0\x28\xb1\x32\x3b\x5d\x87\xa1\x94\x37\x10\x96\x3e\x12\x76\xcb\x1e\xa9\x9c\xd0\x53\xb8\xc0\xb2\x94\x64\x03\x0d\xab\x09\xef\x8a\xdb\x9b\xcb\xc9\x29\xfe\x39\xbd\xa6\xc5\xd1\x16\xc5\xae\x6e\x16\x94\x26\x23\x76\xf5\x98\x83\x17\x94\x16\x2f\x69\x44\x28\x1a\xc1\x1c\xca\xe0\xcb\x1a\x81\x11\xe3\xd3\x01\xa7\x6c\xc8\x24\x36\x48\x38\xa2\x8b\x64\xe3\x28\x6b\x77\xba\x50\x78\xc1\x62\x1f\xe1\x08\x81\x3e\xf7\xb1\xd4\xd4\x8b\x87\x53\x39\x0a\xff\xe0\xbe\xc4\xb6\xe2\xed\x83\x2b\x7e\xde\xdc\x84\xa6\xd2\x03\x18\xeb\x07\x5d\x7d\x7e\x8c\xbd\x4e\x4b\x31\x0e\xf8\xbf\xb0\xf3\x7b\xd3\x3f\x79\x84\xe2\xec\x6f\xf9\xed\x9b\xbe\x7f\xfd\x7b\x5f\x1c\x39\x94\x54\x1d\xed\x89\xed\xff\xca\xe5\x97\x6d\x02\x86\x58\xda\x1e\xc6\xb8\x10\xfe\x2c\x92\xc7\xb7\x41\x18\xd7\x3b\x5b\x31\x2e\x3c\xe3\xcc\xa1\x1c\x6c\x1a\x57\x3a\x4d\x46\xae\xa3\x8b\x24\x06\xd1\x5a\x08\x85\xa1\x13\x89\x8a\xdb\x54\x22\x59\x61\x33\xa2\xdc\x25\x5a\x5e\x56\xe7\x64\xa7\x50\xe4\x5b\x3b\x3a\xc3\xd8\x33\x93\xa9\xb4\x1b\x5d\x85\x53\x0b\x97\x5f\x75\x79\xb5\x5e\xc3\x85\x56\x43\x72\x2d\xee\x00\x8d\xe9\x3f\x24\x5d\xb4\xcd\x64\x46\xb0\xec\xe4\x8b\x7c\x6b\x7b\x07\xd6\x42\x76\x0b\x72\x67\x63\x5d\x50\xa7\x4b\x53\x9f\x23\x4c\x4f\x8a\xa7\xc6\xda\x6c\xa4\x85\x53\x59\x9f\xbd\x44\x9f\x28\xdc\x74\x15\x7d\xba\xeb\xe9\x23\x32\xdb\x28\xed\xd1\x5c\x8d\x75\xba\x88\x5e\x3c\xcd\xa2\x1b\x5a\x89\x16\x54\x75\x95\xfb\x6c\xb9\x78\x6a\xac\x5e\x1f\xab\x59\x70\x4c\xbf\x93\x44\xbf\x3e\x58\x0f\x0f\xd4\xd5\x10\x97\xbd\x63\xe9\x62\x17\xcd\x3a\x57\x48\x48\xde\xb0\x40\xe3\x76\x5c\x1b\xee\xa1\xb9\xe4\xbc\xf6\xb2\xdb\x2a\x8f\xe0\x2b\x59\x7a\x25\x9b\x28\x8e\xd0\xfc\x73\x72\xde\xcc\x4a\xb6\x87\x17\x94\x56\x42\x3d\xd9\x25\xf1\x82\xbc\x3e\xd7\x10\x8c\x06\x15\x8c\xba\x28\x1d\x6d\x5c\xdf\x68\x8c\xdf\xff\xd7\xb0\x96\x8d\x7d\x87\xf0\x9e\x91\xb4\xd0\x04\x26\xc8\x02\x6d\x43\x86\xaa\xc0\x9d\x2c\xb2\xa2\xa7\xcd\xe3\x16\x24\x2a\x3a\x3d\x9b\xca\xcf\x98\xbc\xd5\x2c\xcc\xa6\x1c\x68\xea\x4e\x97\x66\x9e\x07\x6d\x1d\x6b\x9c\x99\x67\x43\x53\x3f\x8b\xbd\x76\x9e\x47\xd3\x05\x1d\xf0\x91\x2a\xd6\xe4\xa2\x93\x72\xf8\x3a\xd5\xa5\xa2\xa1\x83\xd2\xf9\xe2\xa0\xaa\x93\x92\x7a\x5b\x4a\x4a\x53\x8b\x44\x09\x7d\x5d\x64\x44\x9b\x62\xb5\x94\x94\x30\x12\x15\xce\xc5\x06\x59\x77\xb4\xb0\xf1\x8b\x15\x6a\x58\x47\x7a\x69\x92\x4d\xca\x12\xfb\xea\x62\xa6\xcd\xaf\x55\xa8\x62\xcf\x96\x19\x37\xe7\xde\x44\xef\x7a\x13\xc3\xe1\x8e\x35\x99\x00\xe1\x6c\xfa\xb1\xfa\x79\xcd\x5e\x18\x82\xdb\x99\xf4\x64\x52\x6d\x50\x4d\x26\xae\x91\x30\x28\xa1\x68\x39\x3a\xf1\x0a\x2e\x2a\x43\xa6\x92\x3c\x64\x55\x3a\x91\xa8\x38\x4c\x25\xd9\x61\x95\x8d\xc1\x8b\xbc\x22\x99\x4a\xb2\x94\x50\x8c\x26\x4a\xac\x2f\x0d\xf1\x42\xd1\xa3\x0d\x8a\xa4\xa9\xbd\x93\x97\xad\xb8\xa8\xf0\xf0\x82\x62\x6d\xcd\xe5\xe4\x2c\x2f\x1b\x6b\xca\xea\xaa\xd5\x7a\x22\x59\xe7\x12\x24\xe5\x74\xde\xf6\x54\xef\xde\xdf\xbc\x79\xfb\xe7\x76\x67\x9d\xe1\xb4\x2f\xbd\x6d\x20\x28\xed\xfa\xc2\x2d\xb9\xdd\xfd\xb3\x99\xbe\x8e\xa1\x1e\x4f\x70\xd5\x4d\xab\xf6\xce\x86\xb2\x51\xa7\xa3\x7b\x58\xec\x59\x2d\xda\xd5\xd7\x7e\xfc\x1b\xa7\xc7\x57\xdf\xf6\xd0\x44\xd7\xe4\x9a\xac\xe0\x18\xbd\xe1\xc8\xf0\x0d\x8f\x1d\x1c\x0c\x05\x8a\x29\x7f\xef\xba\xd8\xc0\x2d\x63\x91\xe7\x5d\xa9\xc9\xde\x8e\xb5\x99\xa0\x74\xfd\x89\x0d\x97\xce\x91\x38\x99\xf0\x97\x69\x9e\x07\x80\x56\x48\x41\x2f\x1c\x67\x9c\x50\x04\x9d\x0e\x0d\x4b\xb0\x16\x04\xa2\x62\xd0\x94\x8a\xda\x1e\x8f\xa5\xdc\x5b\xd4\x47\x92\x6a\xc0\x58\x92\x03\x34\x69\xea\x62\x92\x44\xd6\x76\xc8\x22\x51\x09\xe0\xdc\xa9\x99\x4c\x46\xe0\x9f\x37\x58\x3c\x1d\x52\xa6\x97\x44\x34\x5a\x0c\x8f\x2b\x45\x28\x92\xe4\xe6\x9c\x6c\x11\xc8\xba\x3e\x84\x38\x68\x39\x6c\x66\x61\x5c\x37\xb2\xe9\x96\x49\x67\x76\xfd\x1d\xab\xdd\x89\x73\xcf\xcc\x2e\x83\xcf\x4c\xe5\x8e\xe5\xb8\xd6\x23\x73\xf2\x9a\x25\x70\x39\xf1\x9f\x81\xcb\x73\x04\x17\xc2\x99\xe5\x10\xe4\xcc\x87\x03\x8e\x17\xb9\xd4\xbf\x06\x38\xbb\x9e\x3e\xf7\xe6\x32\xc1\x51\x0f\x97\xc7\x84\x95\xf1\x39\x4b\xf0\xe9\x84\x7e\xb8\xaf\x1a\x1f\x71\x31\x3e\x99\x79\x7c\x72\x04\x1f\x36\xbd\x8c\xe0\x93\x66\xf8\x0c\x20\x51\x09\x23\x5e\xc8\x37\x9b\x02\xb9\x8a\xe7\x04\x43\xed\x22\x83\xa8\xad\x0c\x51\xab\xeb\xd7\x81\xc8\x8b\xd2\xb6\xaa\xea\x58\x19\xa9\xfa\x28\xbd\xf0\xb3\xd5\xef\x1e\xfb\xd2\x33\xb9\x5a\xb0\x96\x06\x4a\xfd\x0c\x8a\xce\x7d\x7f\xfb\x73\x85\x4b\xff\x5a\x0b\x59\x15\x56\x67\x08\x56\xab\x60\x1a\xfe\xa0\x1a\xab\xd1\x32\x56\x51\x5c\x28\x66\xb4\x25\x79\x95\x54\x58\x11\xc5\x95\xb3\x90\xa6\x94\x4f\xa8\x16\xc0\x38\x35\x0f\x23\xad\x64\x0c\x1b\x4b\xf2\x30\x83\x71\x23\x85\x51\x4e\x48\xa4\x22\x31\xbc\x08\xc9\x50\x34\x33\xca\x90\x8c\xe7\x40\x99\x72\xf2\x42\xa1\x15\xb9\xa6\x71\xdd\xc2\xa0\xa5\x6c\x12\x16\x5e\x36\xe5\x94\x68\x86\xf5\x11\x5e\x0d\xd6\xc6\xb5\xba\xc6\x48\x1f\x3e\x71\x7f\x6c\xdc\xaf\xb3\xd9\x59\xe5\xee\xf6\x50\x56\x92\xbc\x91\x11\x7f\x53\x0b\xad\xdc\x79\x96\x69\x83\x7f\xfb\xd3\xa8\x4f\x6f\x17\x9a\xed\xa1\x6e\xe7\xc9\xe8\x70\xcc\x15\x6a\x61\x5d\xb1\xf2\x62\xa3\x68\x98\x4d\x6e\x25\x36\x91\x60\x14\xae\x83\xe7\xab\xad\xd2\xbf\xd8\x83\x47\xca\xd0\xcb\xf1\x84\x7c\x4d\xba\xd8\x41\x83\x96\x0d\x12\x92\xaf\x4f\xc8\x81\x8b\xc5\x28\x6d\xda\x4c\x47\x03\x7a\x51\x41\xc6\x92\x8c\x12\x4a\xda\x58\x92\xa3\xcc\x3c\xc3\xcc\x3c\x0e\xab\xbc\x19\x47\x2f\x63\x34\x7a\x19\x4b\x14\x37\xd3\xe8\xe5\xa3\x48\x24\x73\xb5\xf2\xcd\x9e\x7e\x6c\xb4\x31\x5e\x31\x10\xda\x98\x11\x66\xa8\xd1\x45\x86\x6a\x60\xa0\x3a\x75\xc2\xb2\x59\x6a\xeb\x84\xf5\xcd\x74\xb2\x76\xda\xc9\xee\x5a\xb3\x20\x47\xed\x3c\x94\xa5\x0d\xc5\x05\x6a\x66\xa7\x5c\x1a\x5e\x94\xcf\xfc\x49\xed\x84\x95\xb2\xbd\xe4\x8a\xbd\xb6\xc0\x4b\xbf\x86\xbd\x8a\x13\xb4\x27\x72\x53\xa2\xd8\xc1\x7a\x90\xa7\x49\xf2\x49\x1b\x4b\x85\x40\x1a\xd7\xd1\xc7\x68\x07\x72\x7a\xa1\xb1\x0a\x51\x87\x53\x2f\x16\x27\xe9\xc5\xc9\x44\x31\x4a\xc7\xe3\x6f\x45\xa2\x32\x16\xa0\xfc\x86\x93\x7c\xd1\x62\x88\xf7\x77\x90\xd2\xad\xbe\xa9\x94\x4d\x13\xbc\x50\x08\x44\xb7\xd0\xb5\x21\xff\x23\x76\xb3\x55\xf5\x45\xd7\xb7\xd9\x5f\xb7\xe5\x36\x8a\xb1\xa9\xc1\xb6\xb6\xc1\xa9\x98\xb8\x31\xd7\x66\xa8\xb5\xd9\x03\x61\x9f\x2f\x8c\x7f\xf5\x4c\x55\xee\xbb\xee\x5e\x8f\xb7\xeb\x2f\x6d\x5a\x64\xaa\xaf\x07\x45\x91\xf6\x62\xab\x81\xbb\xf2\x53\x0e\xd4\xdf\x85\x7e\x18\x83\x69\xf8\x43\xba\xde\x85\x9c\x49\x2b\x61\x5d\x49\x5e\x29\x51\x0a\x05\x77\x5a\xd1\xeb\x4a\xf2\x94\x54\xd4\xac\x8e\x59\x4c\xa2\x1c\x4c\x2b\x1a\x5d\x49\x1e\x97\x64\x8d\x55\x09\xcc\xaf\x09\x9c\x6b\x2e\xc9\x39\xab\x32\x82\x44\x59\x23\x15\x43\x74\x44\xde\xb8\x24\x87\xac\xca\x3a\xda\xe1\x1f\x64\x2d\x26\xb9\x0a\x67\xea\x08\x9f\xd7\x5b\x32\x38\xed\x84\x04\xc5\x9e\xc8\xe5\xe4\x75\x7c\xde\x4d\x07\x16\xb7\x0a\x72\x57\x0e\x94\xd5\x61\x5e\x50\xa0\x2b\x97\x53\x02\x31\x32\xb0\x4c\xd6\x13\x4e\x55\x8b\xa0\x34\xdb\x2b\x03\x9c\x16\x0c\x0d\x73\xd1\x29\xe6\x7e\xa4\xa1\xdd\xcd\x74\xe2\x51\x78\xe1\x92\xc1\x43\xc8\xac\x46\x95\x45\xc3\xb8\x81\x83\x8f\xdf\xbc\xaa\x3f\x3c\x19\x3e\x9c\x39\xb3\x25\x30\x3c\x28\xf1\x56\x51\xca\xfa\x37\x1c\x1a\x6b\x9b\xbb\xd5\xd9\xbd\x22\xbc\x65\xe5\xed\x7d\xa7\x37\x8e\xdf\xd5\x2d\x48\x83\x23\xa1\xb5\xb7\x4d\x76\x7f\xcb\xea\xeb\xb0\xaf\xce\xae\xdc\x96\x71\xa1\xb3\x3f\x34\x79\x23\x6e\xbf\xd8\x6a\x41\xfa\x89\xbb\xb7\x67\xd4\xbb\x0e\xa5\x57\x7e\x6e\xed\x88\x2d\x28\xba\x5a\xc4\x80\x6d\xc5\xa1\x2f\xde\xbc\x9b\x9f\x90\xb6\x0c\x06\x0f\x3c\x34\x32\xba\x66\xc0\x17\x0f\x09\xc9\x2d\xfb\xfb\x1d\xd1\xa0\xfd\xa3\x1f\xbd\x45\xed\x8b\x0d\xa0\xac\xd6\xd8\x35\x9a\xf2\x85\xb2\x8c\x33\x79\x6a\xee\x1e\xc2\x5b\xba\x16\x76\x42\x85\xae\x74\x61\x3f\xbd\xdf\x00\xcd\xf3\xfd\xf4\x2d\x46\xda\x4f\xdf\xb2\x74\x3f\xbd\x5f\x28\xb4\xb3\x7e\xfa\x5f\x97\xdb\xb4\x7e\x67\x7d\x43\xc6\xd3\x15\x67\xa6\x96\xee\xac\xbf\xf1\x89\x43\x43\x0d\x78\x50\x47\x37\x9a\xbb\x16\x77\xd6\x3f\x6e\xd8\x7a\xea\x2b\xa4\xde\xfa\x23\xf5\xb3\x2c\xe6\x8b\x42\x0f\xdc\xc3\x98\x77\xec\xda\x72\x8b\x1f\xc6\xac\x53\x57\x2a\x06\x2c\x1e\xad\x49\xa4\xde\x1a\x27\x19\x89\x05\x87\x7b\x92\x6c\xa1\x13\xe6\x8d\x6c\x21\xc9\xa0\x85\x17\x9e\xd7\xda\x3d\xd1\xee\x58\x0f\x6d\x27\xcf\x9b\x5d\x74\xc4\xb4\xdd\x43\x79\x6d\x2d\x3c\x0d\x66\x02\x82\x82\x8c\x39\x52\x89\x88\x2e\xac\x33\xd4\x63\x07\xc5\x51\xf0\x32\x19\x42\x23\xe7\x9e\x99\x6d\xc4\x12\xaa\x7a\x83\x84\xbe\x4b\xe0\x70\xef\x87\x88\x83\xc8\x70\x28\x98\x5d\x2d\x31\x92\x63\xfe\xc7\x81\xc0\x11\xef\x32\x81\xf8\xe8\xd3\xe7\xde\x6c\x04\x04\xfa\x79\x39\xcc\xad\x60\x51\x8e\x73\x93\xf0\xc9\x25\xb1\x88\xe9\x4a\xc5\x30\xc5\x22\xac\xa3\x4b\xf9\x30\x2c\xc2\x04\x8b\x08\xc3\x42\x42\xa2\x62\x41\x24\xb4\x92\x23\x3c\x46\x24\x18\x6a\x67\xdd\x64\x18\x91\xb6\x25\x11\x09\x33\x44\x62\xbc\x9c\xbc\x2a\x22\xe5\x38\x77\x39\xfc\xb1\x79\x1a\xe2\x46\x1b\xd3\xc8\xaa\xcd\x2c\xbc\x9d\xcb\x94\x09\x65\x35\x0c\x97\x72\xfc\x34\x04\x5b\xe0\xdc\x92\xc8\xe4\x74\xa5\x62\x9a\x22\x93\xa6\xa1\xd3\xc6\x4a\xe8\xb4\x46\x2a\x17\xc3\x18\xa9\xb4\x24\x07\x70\x58\x44\xc3\x28\x8c\xda\x4a\x24\x16\xd7\xd1\xa3\x75\xac\xfe\x9d\x31\x92\x0e\x0c\x8c\xe5\x56\x16\x2d\xc9\x43\x38\x3f\x2a\xd8\x3d\x5a\xb2\xba\xdd\x3a\x41\xc6\x18\x5a\xec\xe5\x5a\x42\x9a\xa7\xe8\xe5\xf0\x9d\x57\x43\x6f\xf1\x28\xb8\x72\x42\xab\x6d\x07\xba\x0a\xac\x87\x6a\x03\xa5\x13\xf3\x00\xff\xaa\x36\x42\xaa\x8b\xf8\x03\x35\x31\xd2\xe5\x7b\xcb\x89\xf4\xe0\x12\x73\x79\x9f\x07\x50\x4f\x6b\x9e\x87\x26\x30\x80\x19\x36\x95\xb9\x27\x39\xc2\x4e\x6a\x80\x32\x31\x1e\xc7\x11\x0a\xa0\xab\x53\x50\x5a\x19\x11\x69\xbe\xd9\x64\xce\xd5\x50\x91\x86\x70\x8e\xf3\xfc\xdb\x6f\xa1\xaf\xfd\xf9\xe5\xdd\x13\xe7\x9e\x99\xbd\xa0\x9a\xbc\x70\xe9\xd2\x05\xcd\x5a\x9a\x73\x2c\x96\x65\xe3\x87\x22\x8b\xd2\x6c\xae\x95\x04\x27\xf9\xb2\x24\x7f\xf1\xf4\xb9\x37\x99\x24\xe5\x59\x4b\x65\x39\xce\x12\x39\x78\xd8\x7c\x55\x39\x84\x06\x72\xd8\x98\x1c\x85\x66\x93\xc5\xca\xda\xbe\xab\x45\x21\x89\xae\x2c\x4d\x90\xa6\xab\xb2\x40\xb7\xb2\xb4\x83\xf3\x92\x2f\x13\x99\x70\x9a\xb1\x93\x54\xf3\x18\xeb\xad\x70\x72\x25\xd9\x27\xb1\x56\x29\x44\x89\x25\x65\x6b\x42\x8e\xa7\x8b\x5a\x9a\x52\x3a\x24\x32\x55\xd8\x75\x51\xf1\x19\x4b\x79\x9f\x8b\xd0\x2f\xb7\x36\x89\x79\x17\x99\x7e\xe5\x72\x37\x89\x05\xa3\xcf\xa5\x17\x8b\x88\xa6\x17\x94\x28\x1a\x69\x75\x24\x40\x4e\xd3\x44\x45\x26\x15\xbb\x70\xb5\x50\x6b\x75\xe4\x72\x39\x25\xea\xe3\x05\xa5\x23\x4e\x66\xf0\x58\x79\x41\xb1\x4b\xb5\x7d\x4b\x34\x25\xd4\x65\xa3\xfd\x72\xad\xbb\x9b\x08\x0c\x73\xdf\x6b\x38\x29\xfd\xdf\xfa\xca\x10\xfd\xaf\x45\x2e\xcd\x38\xb9\x5f\xd1\xdc\x05\x61\x18\x80\x9f\x42\xbe\x8d\xf4\xea\x94\x59\xd6\xfb\xf4\x25\xd9\x9c\x90\x5b\x12\x48\x1e\x4c\xc8\x96\x8b\x05\xb3\x05\xcc\xa2\x12\xb1\x94\x14\x37\x12\x0b\x66\xb7\xdf\x2c\x2a\x29\x4b\x49\x4e\x25\x14\xbf\xa5\xa4\xac\x98\xe7\xaf\x31\x5b\xe2\xaf\x83\x62\x31\xc7\x5f\x47\x4a\x8b\x1b\xef\xbb\x5b\x28\x97\x0d\x7f\xfa\xe5\x59\xc2\x6e\x62\xb6\x16\x4c\x66\xb7\x0d\x67\x41\x05\xab\xa5\xc5\x26\x16\x5c\xf8\x7f\x7c\xde\x83\xcf\xe7\xad\x96\x96\x2a\x82\x13\x57\x2e\x6f\x32\xbb\xf1\x9e\x27\x07\x05\x93\xd5\xe5\x21\x04\x27\x95\x3d\x42\x6c\x12\x01\x42\x57\x24\xa7\xf8\x82\xc6\x60\xa7\xd9\x7c\x5f\x8c\x17\x14\x3f\xe4\xc8\xfa\xca\x0b\x62\xa6\x38\xa2\xbd\x47\x91\x6c\x2b\x72\x65\x5d\xba\x85\xcb\xc7\x57\xb7\x14\x4e\x0e\xcd\x7c\xf1\xc6\x96\xbe\x4c\xca\x66\xcf\x4a\x73\x43\xe7\xbb\x77\x0c\xfe\x4a\xdc\xdc\xf9\xb3\x81\x67\x76\xee\xcf\xce\xfc\xfe\xa1\x1d\x4f\x1f\x5f\xf3\x8f\xad\xd9\x4d\x29\x71\x7d\x5f\x6b\x5b\x6e\x7d\x57\x6c\x63\x7f\x10\xbd\xbe\xf7\xc2\x67\xa6\x8d\x36\x9f\xd0\xbd\x2b\x37\xfe\x94\x18\x58\x19\xcc\xfa\x06\x83\x43\x8f\x8b\xf7\xcd\xbd\xfa\xd2\xdd\xaf\x7f\x6e\xf3\x86\x53\x85\x7b\xd6\xde\xb1\x2d\x11\x99\xba\x73\xf3\x96\xdb\xd7\x85\x22\x93\x87\x41\xcd\xb8\x9a\xcf\x80\x1b\x3c\x30\x08\xf7\xcf\xf3\xb3\xe2\x7c\x3f\xdf\x49\xd6\x76\xd4\x96\xe4\x41\xa9\xd0\xdf\x99\xd4\x8b\x8a\x5f\x53\xca\x8b\xaa\x32\x95\xe5\x3c\x7f\xeb\x8a\x3a\xfc\xad\x43\x48\x54\xdc\x38\x96\xf7\x0e\xe6\xc8\x14\x04\xad\xbf\x33\x49\x16\xc7\x69\x16\x94\x6e\x91\x78\x29\x65\x75\x55\x3a\x93\x64\xa2\x69\x5d\x76\xd7\xab\x0c\x1c\x59\x4c\xfc\xfa\xd3\x78\xa3\x46\x88\x3a\xd4\xb0\xdc\xd7\xeb\x35\x3a\x90\xd8\x81\x70\xc6\x92\x38\xca\x0e\x61\xe8\xc6\xb9\x90\x95\xcc\xd9\xe0\xaa\x4b\xc8\x36\xb6\x4c\x24\xa2\xcb\xa7\x39\x28\x4d\xaf\x91\xf1\x94\xfa\x1d\xbc\x50\xd4\x5a\x23\x51\x3a\xf7\xbf\xcd\xc3\x0b\x05\x3b\x32\x86\x17\x8d\x3b\x58\x8a\x44\x16\xe7\xd7\x8d\x88\x64\x87\x70\x68\x78\x75\x32\x59\xb5\xbf\x9c\xbf\xff\x17\xd0\x09\xe7\xfc\x8d\x74\xba\x1d\x47\x79\x57\xd7\x49\xb5\x6a\xbe\x2d\x93\xea\x74\x96\xe8\xe4\x85\x1e\xb8\x81\xe9\x14\x5a\xa0\x53\x94\xab\x04\xb9\x55\x6b\x34\x96\x23\x5c\x1f\x22\x53\xa0\xe5\x0e\xbe\xa8\x75\xba\xdc\x56\x36\x56\xa4\x25\x07\x4a\x34\x44\xf5\xeb\x59\x5a\xbf\x05\x8d\x93\xf5\xf9\x7f\x5f\x61\x4d\x92\x0d\x68\x80\xd5\x6a\x56\xe0\x5c\x7e\xa3\x86\x10\xb8\xac\xe7\x19\xa2\x67\x2f\x8c\xc3\x27\x98\x9e\x83\x65\x3d\x03\x38\x09\x77\x6b\x4b\x72\xaf\x54\x90\x02\xdd\x7a\x51\x71\x69\x4a\x24\x61\x53\x08\xd6\x60\x08\xd6\x11\x08\xfa\x2c\x25\xb9\x8f\x84\x68\x04\x82\x09\x24\x2a\x7d\x0c\x82\x95\x7c\x51\xeb\x0a\x74\x33\x08\x94\x0e\xb2\xe2\xd5\x9a\x41\x02\xc2\x38\x19\x2a\x12\xe8\x26\x77\x2e\x55\xd2\x34\x68\x52\xac\x8f\xcf\xd1\x46\x69\xd8\xd9\x08\xb9\xeb\xeb\x25\xe6\xcb\xa7\x6a\xb9\x95\x35\x0c\x4b\x5a\x96\x77\xc1\x00\x4c\xc1\x19\x86\x66\x7c\x81\xd7\xf4\x71\x25\xb9\x23\x21\xaf\x4f\x17\x3d\xb4\x28\x1f\x96\x08\x8d\x0a\xba\xa8\x44\x2d\xa5\x82\x23\x8a\xf4\x62\x31\x40\x0b\xed\x28\x1d\x95\x60\x34\x96\x0a\xa3\xc6\x94\x5e\x2c\x0e\xd2\xf3\x83\x89\xe2\x28\x2d\xbf\x37\x23\x51\x19\x0c\xf0\x42\x41\x6b\x8d\xf7\xd1\x42\x24\x4e\x9d\x6b\x00\xe3\xea\xe9\xe0\x05\xa5\x6b\x6a\xe9\x32\x7c\xc9\x36\xa5\xbe\x7a\xc3\x43\x16\xe1\x7b\xa2\xb6\xa4\x9f\xa9\xc1\xd3\xb0\x28\xba\x5d\x84\xf0\xc7\x6b\xc3\x5a\xdb\xc2\x34\xf9\x52\x6d\x24\xa0\x86\x93\xf0\x2b\xf5\x29\x2e\xc1\xe6\xed\x66\x41\xb6\x25\x8a\x4d\x06\xf0\x90\xb9\xd6\x0a\x32\x90\x59\x21\x7e\x03\xb8\x39\x91\xcd\xdd\x95\x5b\xa4\xa2\xd9\x02\x01\x4e\x94\xdb\x24\xa5\xa7\x42\x16\xa1\x69\x00\xc8\x49\x35\x37\xa7\x72\x75\x26\xdd\xc1\x54\x88\x77\xb4\x27\xbd\x9e\x64\xa7\x53\xe5\xec\x48\x78\x02\xc9\x36\x81\x30\xea\x27\x3a\x1c\xaa\xc4\x1b\x6f\x7c\xcd\xdb\x13\x14\x5a\x3a\x45\xc1\x13\x0b\xda\x6c\xc1\x98\xea\x46\x77\xbc\xcd\xee\xee\x8c\xd9\x5a\x62\x21\xbb\x3d\x14\x03\x35\x0c\x5e\x39\xaa\x7e\x95\x4b\x80\x87\xb0\xeb\x7d\x0c\xf2\x36\xa0\x79\x48\x85\x31\x3c\x6f\x20\xec\xf4\x94\x6c\xcf\x6b\x29\xc9\x5e\x2b\x65\xa6\x66\xcb\xe1\x78\x81\x2e\xf9\x13\xe3\x9f\x6b\xd2\x38\x6c\x81\x30\x1b\x8f\x62\x20\x5d\xb9\x51\x1b\xad\x23\x86\xf8\x02\x98\x5b\xe3\x6c\x30\x8a\x71\x89\xc1\x28\xaa\xf6\xb6\xf9\xb1\x28\xb6\xf9\xb1\x28\x7d\xbd\x99\x08\xb1\x72\xfb\x58\x70\x38\x3f\xb6\x6a\x02\x5b\x7a\xf3\xe4\xb8\x3c\x3d\x32\xf1\x6e\x93\xf1\x03\xa7\x1f\x9b\xf5\x49\x4b\x80\xdf\x7d\xac\x85\xda\xd2\x68\x98\xdd\x71\x72\xe4\xc5\xbb\xb1\x3d\xfd\xa7\x6f\x78\x6c\xcd\x7f\xbf\x4b\x9c\x6c\x43\xdf\xd1\x89\xd3\x47\xe7\xee\xd1\xa8\x9f\x7a\xfc\xc6\x71\x50\x53\xce\x5f\x52\x46\x04\xa1\x03\xae\xa3\xba\x93\x45\x47\x14\x5d\x39\x71\xa8\x10\x59\x0c\x90\x74\x14\xa3\x8b\x0a\x67\x2a\xc9\x1c\x5d\x8d\xdb\x29\xe1\xea\x20\xe9\x22\x6e\xe6\x78\xa1\xe0\x0b\xb5\x75\x60\xf5\x2c\xbc\x62\x6b\xc7\xaa\xeb\x6c\x64\x48\x1a\xed\xcd\xaf\x4b\x02\x8c\xcb\xbe\x3a\x44\xc0\x97\x70\x91\x77\x55\x32\x60\x6e\x82\x96\x78\xff\x45\x74\x41\x36\x97\xba\x1e\xa9\x71\x12\x97\x75\x57\x55\x46\xfd\xb1\x4a\x7b\x46\x59\x9f\xb3\x44\x9f\x08\xec\xb8\xba\x3e\x5d\x75\xf4\x89\x22\x51\xe1\x70\x6e\x1f\xca\xc9\xcd\x7c\xd1\xd7\xd6\xde\x19\x21\x6a\x09\x8a\xad\x63\xf9\x6a\xb1\x92\xaf\x8e\x66\x8f\xd2\x02\xaf\x81\x6e\x33\x55\xf5\x2b\xaa\xdb\xad\x44\xb7\x0c\xac\x83\xb3\x57\xd3\x4e\x4e\x92\x69\xce\x61\x9a\x2b\x0f\x48\x48\x9e\xa8\x68\x1b\x0a\x5e\xe4\xcb\xd3\x2e\x16\x68\x2e\x5b\xac\xf2\x2a\x7c\xb1\x97\x5e\xec\x4d\xb0\x31\x7c\xca\x7a\x24\x2a\x62\x88\x17\x14\x9d\x2f\x97\x53\x56\xf5\x92\x70\xbf\x02\x84\x12\xc6\xf1\xea\xba\x86\x3e\xdb\x60\x00\x4a\x1d\xa4\x36\x37\xe6\x04\x6b\x80\xe2\x3b\x0d\x19\xc3\xb0\xef\x10\x3e\x64\x92\x16\xba\x20\x06\x22\xe4\xad\x18\x4a\x7f\x5a\x8e\x24\x14\x03\x0e\x0d\x7a\x12\x4a\x1c\x89\xa0\x18\x22\x84\x90\x41\xb6\xf2\x8a\xca\x45\x4a\x23\x47\x03\x52\x64\xec\xe1\xcb\x25\x46\x46\xfc\xd3\xe7\xde\x5c\x16\x3b\xb2\xe6\x7b\xcc\xf3\x55\xb0\x77\xee\x3c\x59\xa3\xcc\x0b\x49\xd8\xcb\xea\xdd\xa1\xf2\xf2\x64\x31\x8e\x50\xf0\xa0\x44\xb9\xe5\x4e\x6f\x2c\x29\x1e\x9f\x54\x59\xa6\x2c\xcc\x96\x29\x93\x90\xa8\x84\xe9\xf2\x64\x21\xda\x7a\x19\x72\xd0\x4e\xa0\xd8\xfc\xf2\x64\x32\xe2\x09\xa9\xb2\x6d\x89\x45\xca\xe2\xaa\x08\xaf\x6e\xb0\x4a\xd9\x9a\xc3\x9f\x9b\xf2\xac\x18\xcc\x3a\xb8\x45\xcb\x94\xcd\x9d\xd7\xbe\xb8\x68\xa1\xb2\xe6\x96\x76\xd7\xdc\xc7\xd4\xab\x96\x58\xab\x8c\x63\x36\xbb\x95\xd8\x6c\x05\x6c\x86\xa3\xb5\x56\x93\xfb\x13\xf2\x64\xba\x18\xa7\xe9\x60\xb5\x84\xe4\x2d\x09\x39\x7a\xb1\x98\xa6\x1e\x9e\xb6\xe2\x6a\x59\x71\x9c\x7a\xf9\x34\x12\x95\x74\x94\x17\x8a\x06\xde\x19\x21\x0b\xd0\x0e\xf1\xb2\x2b\x27\x8f\x0b\xb2\x3f\xb7\xc8\xee\x4a\xbc\x9f\x17\xe4\xcd\xcb\xb1\x7f\x23\xcf\x5f\xae\x6f\xa4\x1a\x27\x85\x65\x79\x8e\x76\x53\xc3\x14\xa1\x02\xed\x95\xf7\xd4\xef\x69\xcc\xe0\x81\x28\x3c\xc8\x46\x07\x5b\xd4\x25\xd2\x2d\x49\x16\xa5\x20\x73\x21\x0d\xea\x52\x5e\x4d\x56\x4a\xd6\x97\x8a\x46\xb3\x53\x6d\x12\x15\x63\x53\x65\xd1\x64\xaf\x89\x94\xfc\x21\x24\x92\x29\x9c\x06\x29\x6f\x21\xec\x14\x16\x53\x13\x9d\xc0\x1a\xf2\xf2\x82\xa2\x76\xe6\x70\xa9\x51\xd0\x69\x09\x5d\x27\x28\x16\x81\xe4\x30\x8a\xd1\xcc\x0b\x0a\x78\x73\x39\x45\x67\x60\x64\xde\x36\xab\x80\xcb\xff\xde\xaa\xb9\x61\x95\xa1\x22\x84\x37\x8f\xa7\x5e\xa7\xfd\xe3\xaf\xfa\x56\x7b\x54\x4d\x73\x2f\x23\xd3\xdc\x3f\xa1\x81\xcb\xff\xc7\x3b\xea\xdf\x72\xea\xc6\xf4\x5b\x1b\xb7\x86\x93\x5a\x63\xa6\x27\x90\x89\x38\x55\x27\xd1\x28\x5a\xdf\xe2\x0a\xbc\x3a\xf7\xca\xb7\xe6\x3e\xf7\x6a\xc8\xe9\x9e\x7a\xf2\x5f\xce\xff\xe0\x1f\x57\xf4\xaa\xce\xf7\x4d\xf4\xdc\x5a\x20\x79\x83\xf6\xca\x8f\x39\xbd\xfa\xcf\x20\x09\xeb\x69\x5b\x70\x07\x80\x28\xc7\xd2\x8a\x57\x5f\x92\x33\x74\x91\x24\xd9\x92\x56\xc6\xf4\x25\x79\x93\x54\xdc\xe0\xec\xd0\x98\x44\x65\x83\xb6\x44\x9a\x80\xa1\xb2\x9e\xc4\x10\x12\x95\x0d\xcd\x25\xd9\x29\xc9\x1b\xac\x64\x3c\x9f\xbd\x99\xb6\xf5\x0e\xa5\x78\xa1\xa0\x89\x65\xc6\xb0\xdb\x6d\xe0\x8b\x86\x68\x76\x64\x0d\x21\xa8\x14\xf2\xde\x0e\x4b\x8e\xb2\x8a\x04\x73\xa0\x78\x71\x18\x1c\x8a\x92\x61\x0f\x4a\x10\x5f\xd8\x20\xe4\x21\x35\x44\xfb\xd4\xe5\xe1\xc5\x9d\x54\xe5\x0e\xbe\x50\xa5\xe6\x41\xf0\x8a\x54\xc3\x46\x93\x6b\x6f\xa6\x2f\xdb\x97\x61\xcb\x9a\x74\xa6\x31\x92\x5a\x6d\xee\xa6\xbb\x47\xbc\xe9\x44\x97\xc5\xda\x9d\xea\xf5\x8e\x1d\x9e\x8a\xce\x4d\x23\x57\x57\xb6\xcd\x1b\x8b\x76\xb7\x1c\x5b\x7d\x66\x9b\x7f\x78\x28\xc3\xb7\xef\xec\x1b\xbc\xe3\xc6\x81\xef\x8e\x8d\xb8\x3c\x6a\xb5\x51\xd7\xa4\x51\x39\xdd\x9e\x78\x87\x03\xcd\xfe\x50\xd5\x3f\x28\xa5\xd1\x5b\xa7\x5f\x3a\xd6\x67\x69\x09\xf2\xd6\xa0\xdb\x92\xd9\xf3\xf9\x9b\xbe\x34\xb5\x77\xc8\x6d\xf6\x46\x3c\xbf\xb9\x76\xca\xec\x6a\xe5\xdb\x13\xc9\xd9\x97\x9f\x7d\xea\x7c\x0b\xaf\xe6\x6d\x23\xa7\xfa\xae\x39\xe4\x69\xd2\xa9\x6c\xc1\xd0\xd8\x6d\x6d\xfb\xae\xdd\x47\xeb\xe8\x74\x8c\xe0\x49\x32\x46\xd0\x0f\x29\x78\x60\x89\x51\x82\xb2\x3b\x21\xf7\xa4\xd9\x7a\x55\x72\xbb\x44\xa6\x41\xd0\x51\x83\x05\xbb\x4e\xaf\x17\x2b\x24\x95\x09\x46\x64\x5d\x68\x25\xa7\xbb\x68\x4e\x90\x46\xa2\xa2\x37\xf0\x42\x5e\x65\x71\xe7\x72\x39\xba\x88\x8a\x3a\xa7\x74\xe9\x78\x21\xcf\xb5\xf7\xe4\xaa\xc6\x1b\x2a\x16\x37\xe1\xd2\x5a\x30\xee\xb0\x41\x82\x9f\x1f\x93\xf8\xce\x72\xa6\x2a\xce\x0f\x58\xe4\x54\xcb\x18\x47\x89\x60\x8e\xb3\xaa\x5d\x9a\xb3\xa0\x05\x11\x64\x2e\x21\x6b\xd3\x45\x15\xa3\xc5\x22\x6b\xf6\x96\xc9\xe6\xc8\x1a\xa5\x2a\x8e\xad\x51\xca\x22\x96\x39\x1a\x9a\xcc\x37\xee\x22\x90\xb9\xed\xea\x59\xcd\x19\x08\x42\x16\xc8\x88\x73\xc5\xa1\x2d\xc9\x41\xa9\xe0\x37\x38\xf4\xa2\xa2\xd2\x94\xf2\x56\x32\x0e\x3d\x94\x50\xda\xc8\xaa\x90\x0e\xc2\x98\xa4\xa8\x0c\x8c\xe8\xa1\x7e\xd5\x57\x6e\x54\xb5\xbd\x6a\x3b\x14\xaa\xe2\x3f\x04\x5c\x11\x3a\xa5\xae\x70\x1b\xfe\x87\xae\x71\xd5\xd7\xb8\x85\xd7\xf4\xd5\xd7\xf4\xf3\xd7\xd0\x66\xd5\x5b\xaa\xa2\x26\x01\x2d\xd0\x05\xb2\x3d\x51\x54\x93\x15\x61\x09\xab\x10\x9d\x15\x4b\xa7\xc4\x42\x93\x85\x72\x06\x11\x46\xab\x3e\x8c\x87\x83\x30\xc5\x56\xf8\x08\x36\x1f\xbf\xfb\x88\x3f\xd9\x61\x17\x4c\x9e\xa8\xb3\x2b\xd7\x16\x1c\x4a\xf8\xd4\xbf\xb5\xe5\xf5\x13\xfb\xbd\xb9\xbe\x84\xd5\x68\x33\x3a\x53\x1d\xad\x99\x88\xd3\x27\x8d\x02\x42\x09\xd5\x5b\xaa\xb3\xe5\xef\xb6\x24\x8a\xd6\xf9\xef\x6a\x2e\x2a\x0e\x53\x29\xaf\x71\xe0\xef\x6a\x8c\xf3\xdf\x25\x54\x3c\x91\x32\x9f\x34\xed\x31\x42\x09\x5f\xaa\xc3\x2e\x34\x7b\xba\x9d\x5d\xb9\xf6\xe0\x8a\x84\xef\xd8\xdd\xea\xb5\xde\x5c\x2f\xfd\xa4\xd4\xce\x3e\x19\x9d\x7e\xfd\x04\xd6\x37\x35\x77\x4e\xf5\x28\x7c\xf0\xeb\x7c\x57\xb3\xe4\x77\x53\x0b\xbe\x3b\x94\xf0\x1d\xbf\xfb\xbd\x79\x4d\xf1\x67\x5d\x3e\x69\xb4\x7b\x0b\xfe\x2c\xe1\xbc\x7c\x4b\x7d\x86\xe8\x9b\x82\x29\x8c\x34\x4e\xed\x14\x6c\xd9\x47\x53\xfb\x22\xbc\xe5\x26\xca\x41\xda\x66\x2a\xe5\xdb\xdc\xf8\x6c\x5b\x57\x13\x4d\xea\xee\x26\x5c\x08\x71\x74\x29\xed\xa5\xec\xd1\xb9\xd4\xc9\x53\xc7\xef\x3e\x82\xc5\xb6\x61\xb1\xa3\xd4\x46\xe8\xdc\xfc\xc9\x86\x86\xeb\xae\x63\x4f\x15\xec\x56\xbd\xa5\x9e\x99\xd7\xaf\x25\x21\xa7\xd2\x0c\x5c\x42\x11\x22\x2d\x81\xaf\xec\xa0\x23\x90\xe3\xa6\x52\xbe\x35\x8e\xcf\xb6\x76\x30\xfd\x5a\x1d\xbc\xa0\xb8\x53\x54\xbf\xa5\xf0\xef\x5c\xea\xe4\xee\x8a\x4d\xa2\xfd\xcc\x26\x28\xbd\xd8\x4e\xf5\xfc\xe3\x40\x3d\xb7\xc1\xfa\xcd\x9d\x53\xcf\x10\xbf\xf9\xd0\xf5\x73\x7d\xd8\xfa\xd5\xf1\xc3\xfd\x75\xdd\x13\x10\xca\xa1\x73\xaa\x37\xd5\x62\x35\xbf\x9d\x91\xf2\xdb\x19\x17\xf0\xdb\x19\x28\xbf\x9d\xa1\x3e\xbf\x5d\x2e\xd4\xbf\x41\x14\x27\xfb\x83\xc1\xfe\x49\x51\xdc\xd0\x1f\x52\xed\xef\x1a\xef\x0d\x04\x7a\xc7\xbb\xba\xc6\xf0\x76\x8c\xf0\x1d\x5f\xf9\x3b\xf5\x9f\xc3\x07\x8c\x9f\xf9\x5a\xb6\x82\x5b\x7b\x36\x5d\x66\x69\x56\xdc\x3d\x92\xc4\xfa\x26\x96\x24\x68\x66\xb3\x03\x8b\x12\x2d\x00\x87\x70\x26\xae\xb1\xe0\x58\xd8\xde\xda\x45\xc7\x74\x65\x1b\x14\x6a\xb5\xc7\x06\x47\x24\x13\x0c\xf4\x85\x9d\xce\x70\x5f\x20\x98\x89\x38\xd0\xb6\x45\x67\xa6\x1d\xe1\xde\x40\xa0\x2f\xe2\x74\x46\xfa\x02\x81\xde\xb0\x63\xc6\x9f\xee\x74\x3a\x3b\xd3\x7e\x7f\x1a\xdf\x86\xb7\x57\x3d\xa6\x79\xf2\x07\xb0\x5d\xf5\x96\x7a\x1b\x68\xc1\x09\xe5\x22\x4e\x63\x81\x26\x56\xc4\x25\x53\x8c\xa7\xf7\x03\xb4\xf9\xf4\x3b\xef\x3f\x84\x5e\x1f\x45\x63\x0f\xfd\xed\xdc\x07\x0f\x01\x42\x00\xdb\x55\x3f\x26\xcf\xb6\x2e\xf1\xac\xa2\xa1\xdc\xb9\x90\x4c\x75\x52\x12\x3a\x04\xef\xbf\x73\x1a\x6d\x9e\x3b\xff\x77\x48\xfb\xb7\x0f\xcd\xbd\x30\x4a\x38\xe7\x10\x44\xae\xfc\x58\xfd\x7d\x8d\x01\x24\xb8\x19\xf2\x3d\x18\xff\xb0\xbe\x94\x37\xe3\xc2\xd2\xa9\x2d\x15\x01\xf5\x98\xe9\x78\x30\xe0\x4a\x72\x9b\x54\xd4\xeb\xc8\x09\x6f\x5a\xd1\x73\x25\xd9\x2d\x15\xf8\x1e\xb3\x9e\x92\x26\xab\x2e\x2a\x41\x13\x25\x49\x0e\xaa\x78\x41\x69\x92\xc8\x4a\xfa\x61\x42\x2b\x99\x4c\xd9\x56\x91\x40\xad\x3d\x9b\xc6\x91\x1d\x5d\x08\x40\xab\x0b\xe9\x42\x66\xe4\x47\x21\x5d\x88\xb4\x7f\x55\xa2\xbc\x88\x38\x82\x54\xb7\x89\x3b\xdc\xbb\x3e\xf1\xf8\xe6\x97\x4e\x4c\x0a\x91\xbe\x4d\x03\xd7\x3d\x1c\x40\x3f\x19\x9b\x1b\x53\x21\xf4\xe4\xf8\xdc\x8b\xfe\xcf\xec\x5b\xb9\xbf\xff\xa6\x89\x2f\xee\xb8\xf1\x77\x4f\x5c\x63\x43\x4f\x5c\xe0\x7a\x8c\xf6\xe6\x17\x6e\xff\xdd\xdd\xf1\x07\xbe\xd5\xd2\x17\x6f\x3d\x76\xf4\x05\x3e\xd8\x1c\xb8\x70\xf7\x27\x07\x32\xcf\xae\x5a\xbb\xe2\xc8\x33\xfb\x40\x05\x9d\xaa\xcf\xaa\x7f\xa8\x71\x81\x0e\xec\x70\x1f\x5b\xed\xa5\xa9\x39\x9d\x2e\x02\x1d\x73\xa5\xae\xf0\xbd\x6a\x9b\x44\x45\x6f\xc6\x3e\xe8\x48\xc8\xda\x8b\x45\x0d\xe1\xb0\xc9\x6b\xb4\xe5\xc5\xde\xf3\x5a\xc2\x3f\xa9\x85\x26\x51\xd6\x10\x92\xc9\x2a\x2a\x61\x0b\x12\x8b\x66\x3a\x36\xd1\x89\x83\x66\x3d\x59\x91\x57\xb6\xcc\xaf\x17\xce\x9a\x41\xdb\xf9\x76\x1e\xf1\x69\x2f\x22\x54\x74\xed\x11\xbe\x13\x7d\xe3\xb1\x2f\xa0\xb1\x63\x47\x4f\x1c\x7e\x64\xed\xd0\x00\x77\xf6\x53\x9f\xc2\xd1\xd4\xe5\x4b\xaa\x4f\xcf\xfd\x0b\x6a\xba\x7c\x1c\xed\x7c\xf8\xf4\xdc\x39\x40\xa4\x11\xe0\x8f\xd4\x7f\x04\x6a\x88\x54\xad\x51\x57\xe6\x11\x55\x5b\x70\xe6\xc4\x36\x8c\x4e\x34\xc5\x87\x78\xfc\xc8\xa5\x51\x20\xcf\x23\x80\xc3\x8f\x9e\xfa\xf4\xcd\x96\x15\xff\x0c\x01\x3d\x7e\x21\x7c\xf7\xe4\x97\x5e\x2f\x6f\xaf\x5c\x9a\xbb\x47\x7f\x4a\x7b\x1a\x10\xe8\x41\x05\xf4\x1f\x02\xd0\xfe\x68\x6e\x2b\x0e\x66\xaf\x5c\xba\xf2\x63\xfd\x29\x2a\x49\xd5\xbf\xb7\x55\xef\xc2\x5a\x8e\xd1\x4b\xd1\x1f\x9a\xe4\x00\x9e\xe7\x00\x22\x1c\xc0\x6e\x0e\xc0\xcb\x01\x0c\x71\x80\x66\x38\x80\x5f\x72\x00\xf7\x73\x00\x63\x1c\xc0\x36\x0e\x50\x8a\x03\x38\xc5\x01\xba\x96\x03\xb8\x95\x9d\x7f\x82\x03\xc0\xf7\xee\xe0\x00\xb6\x73\x00\xb7\x71\x00\xfb\x39\x80\xd3\x1c\xc0\xb5\xf4\x87\xc6\x38\x40\x21\x0e\x60\x35\x7d\x0f\xe0\x6f\xde\xce\x01\xa4\x99\x1c\xd3\x1c\xc0\x20\x07\x70\x3d\x07\x30\xcb\x01\x3c\xc4\x01\x84\xd8\xfb\x1e\x65\xf7\xe1\xfd\x13\x54\x36\xf2\x9e\x76\x0e\x60\x2f\xdb\xe2\x6f\xe7\x38\x80\x28\x7b\xb7\x9d\x03\x68\xe6\x00\x44\x0e\x40\x60\xdf\x7c\x8f\xc9\x75\x96\x03\xf8\x1d\xf6\xbd\xf7\xd9\xb7\xf1\x7b\xa6\xd8\xbb\x27\x99\xec\xf8\x1b\xf7\x70\x00\xaf\xb2\x7b\xf1\xfe\x03\x55\xe7\x07\x99\xde\x83\x0c\xbf\x1d\x4c\xf6\xfd\x4c\x5e\x2b\xdb\xba\x98\xec\x37\x70\x80\xf0\xb7\xff\x7f\x0e\x20\x5b\x85\xfd\x66\x26\xfb\xad\x54\x17\x72\x0f\xc6\xf0\x02\x07\x60\xe0\x00\xce\x70\x00\x77\x71\x00\xe7\x28\xf6\xe4\xdc\x0f\x39\x80\x1f\x31\x99\xbf\xce\x01\xc8\x1c\xa0\xdf\x62\x7a\xef\xe7\x00\xad\xe7\x00\x61\x7b\xbe\xc4\x64\xbe\x6b\xa1\xcd\x09\xf6\xb0\xf4\xef\xca\x25\xa6\xd3\x6c\xcd\xef\xd1\x9a\x9f\xa1\xca\x0e\xb5\xbf\x33\x6c\x3b\x59\xf3\x13\xaa\xb0\x9e\xae\xf3\xe3\xd8\xf5\xda\x67\x9f\xaf\xfa\x7d\x99\x9d\x2b\xdb\xa1\xf6\x77\x92\x6d\xf7\xd7\xfc\x5c\xec\xfb\x78\xab\x65\x3f\x2c\xd3\x1c\xc6\x50\xbd\x06\x40\x7b\x1a\xa0\xbc\x55\xf5\x00\xa0\xdf\x03\x40\x4e\xfa\x83\xef\x01\xa0\x29\x00\xb8\x81\x60\x75\xaa\xfc\xd3\x00\x9c\x6a\xa2\xe9\x62\x33\x07\x28\x31\x9f\x4e\x48\x7a\xda\xcd\x01\xc2\xf6\x35\xe0\x67\x39\x80\x0f\x38\x40\xe4\xbd\x2c\xcd\x75\xaa\x49\xc0\x0f\x31\xf6\xf7\x05\xf8\x00\xfd\x40\xf5\x79\xf5\x6e\xae\x85\x9b\xe4\x7e\x83\x2b\x72\x17\x35\x2d\x9a\x6d\x9a\x83\x9a\x67\x35\x17\xb4\xdd\xda\x6b\xb5\xdf\xd4\x6d\xd7\x3d\xa3\x37\xeb\xbf\xa4\xff\x76\xd3\xe1\xa6\x39\xc3\x36\xc3\x0b\x86\xef\x18\x7e\x69\xe4\x8c\x0f\x37\xc7\x9a\x77\x34\x5f\x34\xc5\x4d\x77\x98\x64\xd3\xdb\xe6\xbd\xe6\xaf\x99\xff\xd5\xb2\xde\xf2\x79\xcb\x37\xad\x9c\x75\x9d\xf5\x9c\xf5\x3d\x7e\x37\xff\x35\x61\x5a\xf8\xa4\xf0\x57\x36\x83\x6d\x87\xed\xf3\xb6\x97\x6d\x97\xec\x5d\xf6\x7e\xfb\x6e\xfb\x83\xf6\x67\xec\x17\x1d\xdb\x1d\xdf\x73\xc6\x9d\x17\x5c\xdd\xae\x4f\xb5\xdc\xd9\xf2\x6d\x77\x97\xfb\x09\xf7\x0f\x3c\x66\xcf\xc7\x3d\xdf\xf6\x76\x78\x1f\xf6\x7e\xe0\x1b\xf0\xab\xfc\x7b\xfd\x2f\xfa\xdf\x6b\x7d\xb8\xf5\x1b\x81\x96\xc0\xe6\xc0\xc5\xc0\x2f\x83\xc7\x83\xaf\x05\x5f\x0b\x65\x42\xef\xb7\x7d\xd0\xfe\xe9\xf6\x77\x3a\xcc\x1d\x7f\xd3\x29\x75\xfe\x20\xbc\x23\x7c\x5f\xf8\xd9\xf0\x6b\x91\x7b\x23\x4f\x44\x7e\xd1\xb5\xa2\xeb\x99\x68\x57\x74\x5d\xf4\xe5\x6e\x55\xf7\x40\xf7\x83\xdd\xe7\x45\xab\x28\x89\x4f\xc5\xfa\x7a\x9a\x7b\x9e\xec\xf9\x49\xbc\x23\x7e\x28\xfe\x76\xe2\xde\xc4\x07\xc9\xed\xc9\xb7\x53\x52\xea\xee\xd4\x9f\x4a\xd7\x4b\xbf\x23\xfd\x7d\x3a\x93\x7e\x2d\x93\xcc\xbc\xdc\x9b\xec\x7d\xaa\xcf\xd3\xf7\x72\xf6\xde\xec\xa3\xfd\x6d\xfd\x9f\xee\xff\x65\x6e\xc7\x80\x79\x60\xfd\xc0\xf9\xc1\xbe\xc1\x97\x57\x4c\xaf\xf8\x87\xa1\xfc\xca\x07\x57\xdd\x30\x1c\x1b\x7e\x71\x64\x78\xe4\x9b\xab\xa7\xd7\xb4\xac\xb9\x69\xcd\x53\x6b\xde\x5d\xfb\xc9\xd1\xc9\xd1\xbf\x1f\x9b\x1a\xbb\x30\x1e\x1b\xff\x1f\xeb\x7e\x63\xdd\x4f\x26\x76\x4c\x7c\x73\x7d\x7c\xfd\x97\x36\x4c\x6e\x38\x3f\x19\x9e\xfc\xcb\x8d\xd7\x4f\x05\xa7\xf2\x53\x7f\xb3\xa9\xab\xce\x5f\xdf\xa6\xb5\x9b\xa6\x37\xed\xd8\x74\x68\xd3\xf9\x4d\x6f\x6f\x6e\xdb\xfc\xf9\x2d\xaa\x2d\x47\xb6\x9c\x9f\xee\x9e\xee\x9e\x5e\x37\x7d\x70\xfa\xe0\xf4\xdb\x5b\x27\xb7\x1e\xa4\x79\x31\xbc\x0d\xb7\x51\x5e\x3b\x50\x01\x02\x15\x60\x3f\x02\x34\xcd\xf2\x62\x33\x7c\x15\xd4\x80\xb8\x26\x00\x78\x9f\xb4\x0c\xe1\x7d\x04\x4e\x78\x9f\xed\xab\x40\x8f\x0c\x6c\x5f\x0d\xc7\x91\xc0\xf6\x39\x08\xa2\x07\xd9\xbe\x06\x3e\x89\xce\xb3\x7d\x2d\x04\x55\x31\xb6\xaf\x87\x29\xd5\x24\xdb\x6f\x82\x29\xd5\x13\x6c\xdf\xc4\x4d\xa9\xfe\x81\xed\x9b\xe1\x26\x5d\x1f\xdb\x17\xc0\xa9\xfb\x02\xdb\x7f\x0d\x9c\xba\xf2\x3b\x5f\x87\xa4\xee\x6b\xb0\x06\x8e\xc0\x1e\xd8\x09\x77\xc0\x1e\xd8\x0d\x41\xb8\x05\xee\x82\x20\x4c\xc3\x4e\x38\x0c\xfb\x21\x08\x93\xb0\x07\xee\x84\x03\xb0\x07\x0e\x41\x10\x8e\xc2\x2c\x1c\x80\x43\xb0\x0f\x82\xb0\x1f\x0e\xc0\x2c\x04\x61\x06\x8e\x91\x6b\x77\xc0\x0c\xcc\xc0\x41\x72\x6e\x27\x1c\x22\x6f\x1b\x83\x19\x38\x04\x77\x90\xed\x11\xd8\x07\x7b\x20\x0e\x41\x58\x03\x33\x70\x18\xee\x82\x23\x70\x00\xf6\xc1\x7e\xb8\x03\x82\x20\x41\x12\x92\xd0\x57\xf7\xdb\x71\x72\x65\x0f\x1c\x24\xd2\xce\x32\x69\x8f\x92\xef\xec\x81\x23\xe4\xfb\xfb\x61\x0f\x04\x61\x04\x0e\xc3\x4e\xd8\xc5\x8e\x24\x08\xc2\x41\x38\x00\xbb\xc8\x5b\x66\x89\x04\x13\x70\x08\x76\x11\xc9\x66\x89\xc4\x58\xfb\x9d\xb0\x9a\xec\xef\xae\x7c\xbf\xfa\xeb\x31\xd8\x00\x07\x88\xbc\x07\xe1\x20\x6c\x83\x8f\x55\xbe\x70\x27\x74\xc1\x2e\xa2\x0b\x96\xeb\x20\xc4\x99\xa6\x51\x18\x80\x60\x9d\x2f\x05\x2b\xdf\x1a\x60\x9a\xa7\x20\xd5\xf0\xde\x6b\x89\x9e\x18\xff\x19\x82\x77\x0a\xe2\xe4\xc9\x0c\x0c\x12\xed\xef\x80\xbd\xb0\x13\x8e\x12\x3b\xec\x27\x56\xc2\xb8\x76\xc1\x9d\x90\x84\x38\xe4\x40\x82\x28\x04\xa1\x07\x0e\x42\x10\xfa\xc9\x1e\x46\xad\x17\x92\x64\x7f\xbc\x62\x03\x7c\x74\x9c\xbc\x3f\x43\xf6\x8f\x41\x10\xda\x60\x1c\xda\xea\x48\xd8\xb3\x08\xb9\x60\x0d\x76\xc1\x05\xe8\x05\x97\x89\xdf\x87\xfb\xb6\x7a\x3e\x87\x91\xaf\xe7\x73\x26\x30\xc1\xe4\x02\xdf\x59\x9e\xcf\x2d\x7c\x06\x4b\x5c\x6b\x3b\x89\xd8\x0e\x5b\xa7\xfc\x86\xb6\x9a\xa7\xda\x20\x0a\x83\x60\x82\xbb\x60\x06\x8e\x42\x10\x6e\x83\x9d\x24\x65\x1e\x82\x19\x22\xfb\x51\x72\x17\x95\x80\xa6\xc3\xbd\x04\x11\x7c\x6e\x0f\x1c\x27\x6f\x3a\x4c\xee\x3c\x40\xbe\x88\xed\x76\x1b\x1c\x26\x69\x61\x27\xb1\x23\xbe\xf3\x18\x1c\x20\x6f\x98\xd7\x64\xb2\x26\xad\x98\xe0\xba\x1a\x09\x66\xe0\x16\x62\x77\xfa\xde\x9d\xec\xdd\x87\xd9\xb5\xbd\x75\xdf\x15\x24\xfe\x82\x31\x0d\xb2\xbf\xfd\xc4\x6b\x0f\xc3\x00\x24\x20\x01\xc7\xc8\x5f\x9c\x58\xa2\x8c\x65\xd9\x7e\x89\x9a\x34\x3c\x0b\x09\x98\x84\x09\x58\x03\xa3\x30\x05\x5b\x61\x14\x7a\x18\xa6\xf8\xfd\xd7\xc0\x21\x82\xc4\x2c\xc1\x05\xfb\xc2\xed\x70\x94\xf8\x4c\x75\x1e\x87\xbf\x73\x98\xbd\x77\x27\xdc\xc2\xb0\xc3\x5e\x7d\x8c\x68\x72\x84\xdc\xb3\x8f\x3c\x45\x9f\xc3\x29\xab\x8c\xe7\x31\xe2\x49\x77\xb0\xdc\x10\xdb\x78\x96\x68\x7f\x07\x1c\x83\x9d\xe4\x19\x13\xec\x26\x96\xb9\x83\xdc\x79\x0b\x49\x99\xf5\x3d\xa8\x16\x2b\x6a\xd3\x7a\x6f\x98\x61\xd8\x1f\x22\x9e\x33\x02\x5b\x49\x5e\xb3\x15\xda\x48\x7e\x81\x8f\xf1\x51\x0c\x4c\xf0\x11\x98\x80\x6d\xb0\x0e\x36\xc1\x35\xb0\x0d\x82\xf0\x11\x18\x81\x69\x98\x86\x11\x98\x82\x6d\x30\x01\xa3\xe4\xd9\x4d\x30\x4d\xf2\xe5\x4d\x30\x05\x6b\xc9\x13\x13\x64\x9f\x5e\x1b\x23\x1e\x3e\x05\xd7\x91\xb4\x37\x41\xee\x89\x11\x3f\x3b\xc0\xe4\x3f\xc2\xbc\xee\x30\xd1\x7c\x96\x95\x0b\x47\x88\x1e\x65\xaf\xc3\x92\x63\x7f\xda\x4a\xf0\xac\xaf\xf9\x5e\xf6\x64\xf9\xfa\x2c\x1c\x86\x3d\xb0\x0b\x0e\x10\x0f\xdf\xc5\x6c\x84\x51\x3f\x4a\xec\x83\xef\xd9\x07\x33\x70\x27\x91\xe3\x50\xa5\x7c\x3a\x4c\x8e\x6f\x23\x08\x96\x53\xde\x7c\xd9\x64\x22\x32\xdd\x46\x34\xd8\x49\xec\x58\xbe\xde\xd8\x3a\xf1\xff\x14\xcf\xa5\x6f\xbd\x0d\x0e\xd6\xc9\x67\x3f\x02\x7b\xe0\x16\x82\x0e\xcd\xd9\x69\xfe\x3f\x46\x7c\x83\xe6\x40\x47\x48\xce\xd2\x0b\x41\x92\xaf\x0d\x40\x12\x24\xf2\x7f\xaa\x92\xd7\x51\xee\x7c\xf2\x6f\xee\x71\xd8\x0b\x4b\xfd\x7b\x1b\x00\xa9\x90\x9a\xac\x14\xa4\x01\x2d\x61\xed\x6d\x02\x03\x61\xc8\x33\x11\xbe\x34\x2b\xf0\x20\x80\x0d\xec\xe0\x00\x27\xb8\xa0\x85\x8c\x86\xf5\x82\x0f\xfc\xd0\x0a\x01\x08\x42\x08\xda\xa0\x1d\x3a\xa0\x13\xc2\x10\x81\x2e\x88\x42\x37\x88\x10\x83\x1e\x88\x43\x82\x48\x22\x41\x1a\x32\xd0\x0b\x7d\x90\x85\x7e\xc8\xc1\x00\x0c\xc2\x0a\x18\x82\x95\xb0\x0a\x86\x61\x04\x56\xc3\x1a\x58\x0b\xa3\x30\x06\xe3\xb0\x0e\x26\x60\x3d\x6c\x80\x49\xd8\x08\x53\xb0\x09\x36\xc3\x16\x98\x86\xad\xb0\x0d\xae\x81\x6b\xe1\x23\xb0\x1d\xae\x83\xeb\xe1\xa3\x70\x03\xdc\x08\x37\xc1\xcd\xb0\x03\x76\x22\x0e\x9e\x86\x4f\xc1\xfd\xf0\xc7\xf0\x28\xfc\x03\xfc\x06\x3c\x0c\x0f\xc1\x6f\xc3\x97\xe1\x19\xa4\x81\x07\xe1\x6f\xe0\x14\x9c\x45\x5a\xa4\x83\x33\x48\x0f\x9f\x86\x57\xe0\x7f\xa2\x26\xf8\x1d\x38\x0f\xff\x0c\xef\xc3\xaf\xe0\x29\xf8\x0a\xbc\x0e\xdf\x82\xaf\xc2\x2d\xb0\x0b\x3e\x07\xbb\xe1\x0d\xd8\x03\xaf\xc1\xb7\xe1\xbb\xf0\xa7\xf0\x67\xf0\x1d\x28\xc1\x5e\xf8\x0b\xf8\x1e\xfc\x39\xfc\x37\xd8\x07\xbf\x84\x47\xe0\x22\xfc\x25\x7c\x1f\xf6\xc3\xcf\xe0\xe7\xf0\x00\xdc\x0a\x07\xe0\x63\xc4\x9a\x87\xe0\x49\x98\x81\xdb\x89\x7d\x66\x49\x1a\xbe\x13\x8e\xc1\x3b\x70\x1c\xee\x86\xbb\xe0\x1e\x38\x01\xf7\xc2\x05\xf8\x3d\x38\x09\x1f\x87\xfb\xe0\x13\xf0\x2e\xfc\x02\x5e\x00\x19\x14\xf8\x23\xf8\x2b\xf8\x6b\x64\x40\x46\xd4\x8c\x4c\xc8\x8c\x2c\xc8\x8a\x78\x24\x20\x1b\xb2\x23\x07\x72\x22\x17\xe4\xa1\x00\xcf\xc3\x1f\xc2\x37\xa0\x08\xcf\xc1\xab\x70\x1a\xfe\x00\xb5\xc0\x4b\xf0\x27\xc8\x8d\x3c\xf0\x19\xe4\xd5\xee\x3b\x78\xd7\xe1\xfd\x29\xdd\xd1\x43\x07\x92\xc9\xe4\x5a\xba\x1d\x49\xb2\x2d\x3b\x5e\x2d\xb1\x6d\x9a\x6d\x7b\xd9\x36\x87\xb7\x52\x32\x99\x64\xdb\x14\xdb\x4a\x6c\x9b\x66\xdb\x0c\xdb\xf6\xb2\x6d\x1f\xdb\x66\xd9\xb6\x9f\x6d\xcb\xef\x1b\xa1\xdb\x14\x7b\x6f\x2a\x65\xd8\x7b\x60\xdf\xd1\x23\x7b\x76\xef\x9c\xdd\x4f\x4f\x49\x63\x74\xdb\x3b\xc6\x8d\x1e\x3d\x32\x43\x0e\x7a\xc7\xd6\x00\xc0\x05\x74\xe5\x7e\x19\x9d\x81\x0d\xb2\x7e\xf3\x76\x05\xa1\x87\xaf\x53\xc6\xb4\xe2\xf6\x90\x6c\xbd\x6e\x83\x6c\x9f\xde\x1e\x92\xef\xbb\xce\x2f\x6b\xc5\x1b\xb6\x83\xac\x0e\x8e\xca\x6a\x71\xad\xac\x0f\x8e\xbe\x00\x6a\xd4\x0c\x2a\x91\x1c\xeb\x82\xa3\x79\x7d\x92\x1d\x68\x83\xa3\x79\xdd\x26\x76\xa0\xc1\x77\x6a\x91\xbd\x7c\x27\x17\x1c\xcd\x6b\x56\xb3\x83\x26\xfa\x1a\x67\xf9\xa2\x21\x38\x9a\x6f\xfa\x2d\x7a\x80\x64\x23\xfb\x98\x29\x38\x9a\x37\x9e\x55\x89\x8a\x7a\xec\x4e\x71\xad\xdc\x1c\x1c\xcd\x9b\x52\x95\x43\x33\x7e\x87\xf1\xe4\x15\xa8\x9c\xb1\x04\x47\xf3\xe6\x3f\x29\x1f\x5e\x27\xdb\x45\x00\xb4\xf5\xba\x77\x27\x00\xfe\x6f\x00\x00\x00\xff\xff\xd8\xb6\x1f\xe1\x40\xbf\x00\x00") func fontsInconsolataBoldWebfontTtfBytes() ([]byte, error) { return bindataRead( _fontsInconsolataBoldWebfontTtf, "fonts/inconsolata-bold-webfont.ttf", ) } func fontsInconsolataBoldWebfontTtf() (*asset, error) { bytes, err := fontsInconsolataBoldWebfontTtfBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "fonts/inconsolata-bold-webfont.ttf", size: 48960, mode: os.FileMode(509), modTime: time.Unix(1492020681, 0)} a := &asset{bytes: bytes, info: info} return a, nil } var _fontsInconsolataBoldWebfontWoff = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x64\x93\x63\x8c\x2e\x4c\xb0\xad\xdf\xb1\x6d\x63\x8f\xad\x3d\xc6\x1e\xdb\xb6\x6d\xdb\xb6\x6d\xdb\xb6\x6d\xdb\xb6\xad\x9b\xef\x9c\xf3\xef\x76\xf2\x64\xa5\xd3\xe9\x5a\x95\x55\x29\x57\x59\x11\x11\x00\x10\x00\x00\x00\x58\x2e\x01\x90\xfe\xd3\xde\x7f\xff\x7b\xff\xff\x8f\x88\x88\x92\x34\x00\x00\xe4\x07\x00\x00\x70\xff\xc3\x64\xd0\xe1\x5b\x54\x48\x58\x04\x00\x00\xca\x02\x00\x00\xf8\x00\x00\x80\x10\x08\x05\x00\x2a\xab\x48\xcf\x04\x00\x00\x75\x01\x00\x00\x75\x00\x00\xa0\x67\xa3\x8a\x21\x61\x68\xad\x6f\x07\x00\x00\x63\x02\x00\x40\xbe\x00\x00\xd0\x06\x28\x12\x3f\xc0\xd0\xc5\x89\x10\x00\x00\x49\x03\x00\x00\x4c\xff\x81\x34\x04\x73\x64\x62\x67\x6a\x0d\x00\x80\x4c\x01\x00\x40\xf5\x00\x00\xb0\xb1\x62\x13\x7d\xa9\xa9\xbe\xa3\x1d\x00\x00\xf6\x9f\x2f\xe4\xff\x81\x68\x6a\xe5\x6e\x02\x00\x80\x85\x01\x00\x5a\x5b\x00\x40\xc9\x5a\x5e\xf5\xf8\xb3\x99\xb1\xbe\x11\x00\x60\x60\x04\x00\x00\x18\x01\x00\x00\x2b\x78\x43\x60\xbc\x99\x99\xb1\x3e\x00\x60\xf0\x9f\x07\x21\x00\x00\x20\x41\xd0\x87\xc4\x31\xb3\x76\x72\x03\x00\x0c\xda\x00\x00\x20\x8f\xff\xfc\x43\x73\x35\x54\xac\x6c\x0d\xf5\x01\x00\x23\x16\x00\x00\x68\x08\x00\x00\x9a\xd9\x18\x6a\x18\xb0\xd6\x77\xb3\x03\x00\x8c\xdf\xfe\xef\x2f\x21\x30\x08\xd0\xa0\x8d\xbe\xb5\x31\x00\x60\x82\x09\x00\x80\xd0\x01\x00\x90\x39\xbb\xa8\x97\xec\x76\xb6\x8e\x4e\x00\x80\xb9\x18\x00\x00\xb4\x0f\x00\x00\x77\x97\xb1\xc8\xbf\xd8\x39\x18\xdb\x01\x00\x96\x34\x00\x00\x20\x17\x00\x00\x1c\xbe\xd5\x53\x42\xb9\x1a\x1b\x98\x00\x00\x96\x53\x00\x00\x00\xfc\x3f\xae\x24\x14\xff\xcb\xe7\x7f\xd2\x9e\xe2\x29\x98\xfd\x4f\x27\xc1\x99\xff\xeb\x1f\x30\xeb\x9b\x35\xee\xb6\x61\xa8\x67\xa4\xa7\xb7\x07\x62\x00\x05\x8e\xa8\x67\xa0\x07\x3a\x50\xfa\x6f\x0a\xf8\x84\x11\x00\x80\x27\x02\xc2\x04\x00\xfe\x7b\x37\xf1\x19\x6d\x0a\xf5\x4f\xf6\x0f\x5e\x4e\x73\x46\x07\x01\x29\xe4\x0e\x32\xe9\x99\x89\x1b\x20\xe9\xeb\xeb\x1b\x9a\x1e\x19\x9f\xea\x9b\xea\xeb\x9b\xeb\xeb\xcb\x43\x48\x9a\x35\xf1\x0b\xf0\x63\x59\x45\x05\x07\x03\xd7\x59\xe6\xb3\x32\xff\x5d\xc0\xc4\x5c\xbb\x61\xae\x01\x83\x86\x09\x3c\x4a\x7b\xad\xfb\x02\x52\x80\x86\x8d\x02\x04\x24\xc2\x63\x03\xfe\xb7\xb6\x9e\x9e\x89\x9f\x1e\x16\xb8\x08\x38\x62\x1b\xf0\x11\x63\xc0\x3b\x0d\x2c\x97\x5f\x13\x7a\x20\x70\xdc\x30\x98\xd1\x3d\xd3\x12\xe3\x97\x29\xac\x49\x95\x1e\xe7\x88\x93\xa8\xbf\x24\xbf\x10\xbf\x04\xbf\x0c\xbf\x38\xbf\x34\xbf\x6e\xbf\x04\x91\x8e\x7e\x74\x41\xc2\x45\xee\xef\x6f\x7f\xc9\x1d\xb0\x33\xad\x1e\x6c\x40\x85\xb1\x1c\xa2\x5c\x9c\x5c\x9c\x7f\x45\xb3\x90\xc2\xe4\xdb\xef\xe5\xef\xe8\x2f\xc2\x37\xfd\xdb\xed\xe3\xeb\xef\xae\x2a\x42\x0c\x1f\xfb\x93\xde\x6f\xa0\x37\x82\x0b\xdf\xda\xbd\xde\x60\xe0\x31\x42\x06\x41\xda\x2e\x9f\xd3\x25\xe9\x92\xb5\x10\xb0\x08\x2b\x78\x1b\xb8\x08\x19\x61\x7f\x50\x0d\xe0\xcc\x18\x5d\x85\xd5\x05\x5e\x86\xce\x06\x5f\x87\xd7\x07\x88\x9f\x48\x1f\x49\x9e\xd1\x1e\x4a\x9c\xd2\x1c\x4b\x9d\xc3\x1d\x4c\x98\xd4\x18\x4d\xf9\xaf\x33\x9c\x34\xad\x35\x9e\x36\x8f\x37\x88\xe0\x1f\x43\x14\x45\x66\x47\x18\x49\x6a\x4b\x1c\x4d\x2e\x4f\x08\x51\x72\x53\x0c\x55\x36\x57\x04\x59\x7a\x5b\x02\x5d\xbe\x5f\xbf\xbe\xbc\xbd\xb8\xb9\xba\xbb\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\x20\xa1\x90\x96\x97\x99\x9b\x71\xe6\x13\x5a\x9d\x26\xa3\xf5\x85\x63\x6a\xd5\x5a\x8d\x46\x97\xef\x0e\x38\x1c\x36\xdb\xed\x06\xeb\xd1\x17\x9e\xce\xd7\x1b\x43\x0a\x09\xf1\xe9\x2e\xcd\xfa\x3a\xc2\x4f\x71\x75\x74\xc1\x51\x9a\x10\x03\xf0\x90\x27\x87\xba\x4b\x07\x0b\x4c\x95\x2b\x0b\xa9\x19\x90\x7a\x47\xcb\x5b\xd2\xbf\xcd\x32\x7c\x4e\x6f\x17\xcd\x9a\xad\xb5\xbb\x6b\xe3\x76\x77\x90\x83\x87\x10\x08\xfe\x4c\xc9\x6c\xb7\x0c\x4d\x4f\x2c\xaf\x2e\xcf\xb2\x69\x6b\x6c\xce\xd8\x83\x49\x1c\x8e\xa6\xcc\xb8\x3c\x2a\x90\x49\x15\xc0\x06\x80\x42\xe7\xe0\x5b\x00\x00\x00\x52\x06\xfa\x05\x18\x04\x74\x00\x1a\x00\x2d\x80\x32\x40\x2f\x60\x14\x30\x09\x38\x01\xcc\x00\x76\x01\x27\x80\x2b\xc0\x3c\x60\x0d\x90\x08\x58\x04\x8c\x03\xda\x00\x5b\x00\x21\x30\xa4\xff\x66\xa6\x2d\xdf\x29\xa3\xc9\x8f\xb8\x0d\x87\x00\xe2\x3f\xb4\x46\xc8\xb1\x81\xda\x98\x1e\x37\xe2\x99\x0f\x06\x35\xb4\x1c\x6d\x60\xc4\x15\x7c\x0c\x69\xce\xe6\x10\x1f\x69\x0f\x44\xf0\xcf\x5f\x08\x6e\xa3\x16\x2b\x2f\xbf\x48\x2c\x13\x9c\x08\x43\xcc\x4b\x80\x97\x08\x99\xd9\x32\xac\x80\x85\x8b\xab\xd1\x71\x26\x9d\x59\x72\x22\xbe\xc2\xf5\xdc\x72\x56\xf1\x94\x24\x6e\x60\x1b\x7c\x9a\xf5\x5b\x46\xac\xb9\x11\xf0\x5a\x74\x79\x19\x1d\xd5\x14\x08\xa1\x61\x65\xf2\x34\xe1\xfc\xf9\x03\x03\x9e\x39\x9f\xc4\x65\x01\x38\xe6\xb1\xa5\x44\xc0\x92\xe6\xf2\xd7\x68\x2a\xfd\x99\xff\x82\x0e\xf9\xfc\x22\x78\xe4\xc2\x6c\x62\x59\x7c\x5a\xe2\x84\x3a\x27\x02\x3d\xc9\xb4\x97\x0c\xbc\xc5\x9a\xee\x98\x44\xf8\x08\x58\xde\x37\x60\x60\x28\x4a\x2b\x39\xa0\xe3\x2b\x51\xf8\x69\x65\x39\xb5\x98\xac\x6b\x8e\x9f\xef\x0a\x64\x46\x7a\x1f\x67\xf9\xa7\x68\x69\x0d\x9a\xf1\xb3\x44\xb4\xfc\x68\x8f\x2a\x19\x37\x59\x52\xcf\x9a\x96\xd6\xf0\x43\x82\xd2\x1f\x3c\xee\xa4\xac\xd8\x3c\xf5\xb6\xd1\xaf\xdd\xd0\x78\xa6\x17\x48\x35\xed\x0f\xb1\x36\xa8\xe2\x0e\x8b\x0f\x8f\x40\x86\xba\xd0\x4a\x32\x41\x03\x87\xf4\x62\x50\x39\x04\x89\x94\x88\x0b\xcd\x71\xbc\x35\xfe\x53\xf4\xef\x5d\x0c\x79\xa4\x4b\x5c\x82\xeb\x30\xa4\x19\x7c\x24\x7e\xb5\x2f\x8f\x55\xb6\xf1\x97\x3b\x53\xda\xda\x16\x6f\xe0\x4d\x1d\xb7\xdf\xb5\x17\x4b\x92\xf3\x6d\x2c\x64\x03\x13\xc9\x80\xcb\x80\xd2\x0f\x4a\x48\x40\x44\xf9\x3d\x04\x7b\xb6\x9b\x06\xfc\x48\xe1\x73\xf6\x5f\x92\xdf\xf1\x7d\xac\x6f\x36\x64\xd3\xcd\x9a\x10\x77\x6a\xb3\x33\x3c\xa3\x0a\xa4\x87\xcf\xe6\xd6\xc3\x64\x44\xa7\x4a\xfb\x4c\xa4\x80\xab\x6d\x85\x45\xd9\x02\xe5\xf4\xa7\xce\x4c\xcf\x28\x48\x0e\x3e\xcc\x20\xbf\x61\x7f\xe6\xec\xe7\x8f\x84\xff\x07\x37\x4d\x0d\x8b\x19\x3c\xa8\xa0\x07\x9b\xc7\x6f\x41\xf3\x45\x58\x65\x17\x06\x6f\x03\xf9\x62\x6f\xbd\x06\xe0\x7f\xb6\x1f\xe8\xf7\x17\x80\xe0\xb6\xd1\xd5\x0d\x95\x85\xb3\x9c\x4c\xaf\xd5\x2a\xf1\xa9\xb3\xf1\xea\x6d\x2e\x5e\xbd\xb2\x63\xd1\xec\xe1\x4a\x6f\xe3\xda\x79\xdd\x82\xb3\xe9\x36\x88\xb3\x83\x11\x05\x74\x88\x78\x98\x36\x6d\x0f\x49\xa4\xf7\x42\x12\x84\x78\xc0\x00\x4b\xa4\x6c\xa1\x9f\xc2\xf0\x8f\xd0\x0b\x56\x50\x2c\x64\x54\x4f\x87\x77\x80\x21\xfd\xcb\x6d\x0e\x4a\x3f\x4d\x8a\x4c\xff\x3c\xa5\xd7\xd1\x56\xbc\x7b\x3d\x26\xfd\xf5\xc4\x9b\x84\x36\x59\xa2\xe1\xa6\xdb\xf4\x3b\xd7\x71\x96\xa7\xc0\xac\x22\xb5\xe0\x8c\xf6\x20\x92\x22\x24\x41\x41\x9a\xbb\x20\xc1\xda\xb8\x7c\xec\x21\x14\x96\x1e\xe9\xb7\xa3\x7a\x6a\xce\x4e\xfc\x1e\xb6\x87\x76\xa4\x75\x52\x21\xdc\xb9\xa1\x3a\xea\xee\x9b\xe6\xd2\x50\x90\x77\x65\x55\xd2\xb3\x92\xdf\x49\xd6\xb9\xf3\xad\x60\xf6\xa7\x45\xf5\x09\x1b\x4c\x37\x3c\x64\xd6\x4b\x6c\x97\x46\x47\x16\xab\x8c\xa1\x39\x82\xca\x92\x92\x4a\x07\x89\x9a\x22\x9a\x22\xa6\x4d\x2c\xa1\x50\x46\x15\x55\x43\x82\x36\xc2\xf1\x05\xb6\x74\x4e\x39\x4a\x63\x02\x96\x3e\x4a\xfc\x2b\x00\x79\x27\x3f\xe1\x90\x37\x58\x1e\xbd\xd6\x4d\x39\x49\x15\xf5\x14\x47\x2e\xeb\xf5\x43\xcd\x5b\xdd\x12\x09\x23\x52\x98\x2a\x19\xfe\x98\xf3\xcc\x6a\x44\x3a\x33\x0a\x9b\x73\xcf\xb6\x00\xae\xfd\xc4\x6a\x24\x4a\x57\x3c\x1d\xb0\x38\x94\xa7\xaf\xd9\x75\x06\x97\x84\x5d\xfd\x22\x34\x7e\x49\x3b\x62\xfd\x91\xdf\x93\x33\x4c\x5c\x0f\x1a\x9c\xe3\xb0\x80\x9c\xfe\x16\xd6\xc9\x61\xd1\x3c\xfa\x20\xe3\xca\x6b\x51\xcf\x72\x24\xfc\x07\xa3\x5a\xbd\x73\x7b\x6d\x6b\xc5\x22\xdd\x23\x50\x46\x8d\xab\x73\x93\xb2\x0b\xff\x02\x55\xd1\x40\x25\xfc\xb5\xdf\xe3\x40\x89\x6f\x18\x2b\x41\x8b\x5b\x53\x9e\x82\x02\x4b\x6a\x29\x9b\x5f\xcb\x30\x01\x25\xfb\xa4\x79\x03\x4a\xa6\xf2\xb0\x9a\x61\xd1\xcf\x25\x40\xb6\xaf\x51\x65\xe8\xc2\x3d\x38\x5f\xed\xa8\x8a\xc6\x94\xc6\x01\x88\xe7\x36\x26\x71\x1d\x07\x1a\x8f\x82\x20\x5d\x27\x40\x28\x92\x73\x7e\x8b\x4b\x01\xee\x0f\xcf\x32\x8d\xa2\x99\x94\x7f\xd1\x76\x0a\x6c\xfa\xf7\xce\x41\xa0\x7b\xba\x94\x31\x34\xeb\xba\x75\x79\x1e\xc7\x19\x9a\x65\x33\x27\x54\xe3\x77\x11\xad\x0d\x37\x26\x15\xe8\xf3\x87\x58\x79\xbf\xaf\xdb\xf4\x77\x38\x87\xab\xd6\x6a\xf5\xfc\x08\xb6\xa1\x86\x3e\x2d\x92\xc4\x60\x17\x35\xba\x3c\xfc\x44\x60\x8a\xbc\x31\x96\xf4\xf0\xa4\x42\x31\x55\xe6\x74\xca\x70\x58\x44\xac\xe4\x11\xb4\xf3\x5c\xc2\xb1\xf0\x42\xb8\xbd\xc8\xe9\x0b\x28\x2d\xd6\x14\x6c\xe1\xf0\x45\x5f\x2b\xd2\x56\x89\x7a\x29\x8c\x4d\x2a\x65\x51\x58\xac\xab\xbc\x0b\x47\xdd\x72\xe6\x51\x51\xa9\x7b\xba\x85\xc1\x16\x59\xe2\xc4\x41\x97\xf6\xdf\xfe\xf5\xc4\x2e\xb8\x1c\x23\x4e\x1d\xa8\x26\xb9\x72\x32\x37\x82\x08\xc7\xe9\x97\x52\x2e\x82\xaf\x26\x7f\xa6\x61\x34\xe2\x99\x9a\x43\xeb\x08\xd9\xdc\x9b\xaf\x13\xf2\xd1\x7b\x38\xb8\xd2\x25\xfb\x93\x53\x8e\xe4\x18\x66\x1e\xfa\x10\xd7\x51\xf3\xce\x25\x44\x02\xd3\xb1\x42\x50\x3e\x07\xd6\xed\xb6\x2d\xb2\x40\x98\x46\x1b\x2d\x7d\x95\x81\x60\x71\xb6\x1a\xd6\xf2\x3d\x10\xce\x87\xb1\x04\xd1\x3f\x3e\x43\xb9\xf5\x71\xb3\x7d\xbd\x0d\x09\xbe\x60\xbb\xe7\x65\xbe\xb1\x8d\x3f\x3c\x74\x5f\xe9\xf6\xae\xdf\x89\xf8\x5e\xb9\xf9\x13\x64\x8d\xd5\xe5\xe5\x50\xce\xe7\xe6\xe0\x89\xc2\xa3\xd8\xd2\x26\x79\x81\x8b\xc7\x2f\x2c\xd9\xcf\x04\xab\xc6\xe4\x5e\xd3\xd8\xc0\x77\xaa\x7a\x63\xb9\x2c\xff\x7e\x8a\xc0\xbf\x42\x77\x23\xca\x7e\x66\xbe\x11\x22\xd8\x04\x6c\x85\x5e\x42\x76\x20\x79\x2c\xbc\x96\x1c\x25\x9e\xa5\x9e\xa2\xdf\xfc\xcf\x2c\xf3\x77\x6f\x5e\xf1\xfe\x69\x12\xfc\x4b\xb9\xcd\xd7\xe9\xf8\xc0\xa5\x9a\x5f\x4e\x25\xa8\xf8\xf9\xe9\x5c\x16\x5d\x36\x73\x4e\x2e\x9d\x4f\x08\x8d\x0b\x07\xb6\xde\x76\x38\x21\x79\x54\xb4\xcf\xa1\x92\xe7\x59\x22\x74\xe6\x1a\x46\x4b\xec\xd2\x62\xed\x1f\x4e\xd4\x52\x4d\x79\x65\x40\x31\x96\xc5\x6d\x1c\x31\x1c\xa9\x52\x4f\x3a\x6a\x2a\x7d\x67\x7d\x06\x5d\x2d\x39\x3c\xa6\xd0\x61\x6d\x71\x32\x61\x4a\x9f\x00\x2e\x50\xd7\xe2\x1e\xc4\xf0\xfb\xcb\xea\x4a\x36\x48\x3b\x77\xff\xdd\x57\xc1\xd2\x85\x1f\x70\x0a\xa6\xa1\x32\x9b\x4f\xbc\x3a\xeb\x70\x42\x9c\xba\xf2\x88\xc4\x07\x49\x4f\x4f\x1f\xa0\xa4\x38\x4d\xb8\x6c\xff\x02\x55\x04\x57\xb4\xc9\x89\x01\x0b\x4e\x2b\x3c\x53\x78\x1a\x7d\x17\xae\xd4\x81\xd2\x8e\x15\x89\xa3\xbe\x46\x46\x86\x80\xac\x3d\x66\xba\x0d\x69\x59\x02\xd3\x2f\x4d\x49\x61\x59\x04\x25\xac\xc6\x26\xd8\xb4\x8c\x3a\xc6\x46\x14\x38\x6f\x35\x6e\x89\xb8\xe2\xaf\xc5\xde\x70\xcc\x60\x29\x27\x36\xfc\x33\xdc\xde\x0f\x22\x69\x50\x1f\xef\xdd\x5d\x3b\x2e\x74\xb7\x2b\xdc\x9a\x0c\x6f\xde\x0c\x5d\x3e\xd4\x46\xc8\xfd\x71\x7c\x5c\x3f\x72\xac\x0a\xd7\xdd\xf2\x53\x4f\x6e\xd8\xae\x06\xaf\x9e\x81\x91\xc4\xa9\x73\x32\x24\xd2\x28\x8f\x3b\x41\x39\xaf\x23\x3a\x7b\x76\xa2\x30\xb9\x62\x4c\x3a\xcd\x2f\x42\xa9\xaf\x16\xc8\x7f\x60\xcc\x06\xbf\x55\xc9\xa8\x81\x9a\x22\xe2\xfe\x0c\xe7\xb9\xba\x16\x03\x96\x0d\xb1\xf2\x6a\xf1\x6a\xb3\x5a\x6d\x2a\xb5\xa3\xf3\xed\x39\x91\x42\xd9\x99\xdf\xfb\xb7\x79\x2e\xea\x59\x58\x8a\x63\xc6\x6b\x4c\x2a\xec\x39\xef\x13\x7d\xee\x47\xc6\x82\xe3\xaf\x4c\x72\xb4\xde\xfc\x04\xa9\xd5\xca\x47\x51\x92\x20\x2a\x7d\x66\x1d\x76\xf8\x7e\x3e\x32\x11\x1b\x95\xe4\x02\x69\x3d\x76\x4e\x90\x2a\x1d\xad\xfb\x31\x71\x2d\x22\x9b\x88\x55\x9e\xb2\xb0\xba\xdf\x8f\x0a\xde\x6e\xd8\x41\x32\xdd\x83\x85\xd6\xfc\x32\xa4\xc8\x2c\x7d\xdd\x48\x6e\x15\x45\x50\x25\x1d\x5e\x2f\x24\xef\x92\x14\xef\x90\x2e\x68\xd7\xbd\x66\x69\x34\x51\x6f\x19\x4c\x8d\x74\x31\x0b\x6b\xd4\x17\xf2\x1f\xbb\x52\xa4\xb6\x41\x51\xad\xb5\x0f\xb9\x34\xa2\x90\xf7\x11\x64\x63\x24\x43\xa7\xc1\x6e\x78\xce\x5c\xcb\x00\x4f\x6c\xec\xe9\x4f\x29\xfd\x9d\xcf\x18\xb3\xdd\x0d\x2d\x1b\x6d\x5d\xc1\x22\x57\x6d\x47\x1b\x6b\x5d\x25\xd9\xde\xf7\x0f\x25\x8a\x4a\xa6\x76\xb5\x15\x6b\x85\x72\x29\x9b\x14\xe7\x74\x25\x0a\x09\xde\xb6\x96\x5a\x22\xad\xcf\xbd\x3f\x47\x7f\xe8\x1a\x25\x8c\x5d\xe2\x63\x19\x12\xab\x35\x43\x0f\xa2\x05\x37\x35\xb8\x5a\xe8\x22\x46\x42\x5a\xa4\x5d\x22\xc9\xf8\x30\x18\x73\x39\x12\x80\x0a\x19\xe3\x9c\xd8\x15\x80\x12\x29\xe3\x32\xbe\x5a\x57\xaa\x07\xef\x47\xf4\xbf\xda\xf9\xdf\xb6\x56\x16\xba\x10\xf4\xf0\x19\x95\x3e\xd3\xd9\xd2\x63\x87\x38\xa9\x20\x3e\xea\xa2\x3a\x32\xa8\x06\xbf\xd9\x77\xa9\x72\x28\x2a\xfd\x49\xbf\x14\xce\x41\x0f\x52\x0c\x33\x1e\xdd\xe7\x02\xba\x62\x34\xf7\x78\xa6\x0d\x0c\x87\xc7\x13\xbe\x80\xd1\x7a\x84\x8f\xb4\x11\x1c\xf8\x42\x8e\x79\x11\x1c\xe8\xe9\x1c\x04\xad\x84\xb3\x2d\xae\xeb\xf4\xd6\x57\x2e\x27\x57\xdc\xb8\xf2\xed\x2c\xa1\xcf\xb0\xc1\xb8\x66\x68\x8d\x09\x4a\x8d\x3e\xec\x44\xf9\xbc\x04\x08\x1d\xf2\xa1\x8e\x4d\xe7\xe5\x2d\xce\xff\x05\x9f\xe0\x72\xab\xb1\x88\x41\x4b\x10\x45\x9b\xa5\x61\x1d\xb0\x62\x60\xc2\x05\x0a\xf7\x06\x22\x95\xd1\x98\x8f\x0e\xe1\xa9\xa5\x69\xb4\xd4\x1a\xf6\xe7\xc4\xb7\x51\xf3\x2d\x3d\xa5\xf5\x13\x09\x46\x69\xbd\x2b\x19\x8d\x55\xc2\x81\x83\x6c\x88\xb6\xba\xa1\xd3\x6a\x2e\xbb\xcd\xcf\x27\x47\xff\x1a\xd8\x50\xb8\x45\x5a\x76\xfd\x9e\x49\x72\x2e\xe3\x18\x50\x6a\x8e\x55\x28\xa8\x7f\x9f\x28\x41\x17\x4b\xaa\x5e\xb7\xad\x31\x3f\x64\xef\xb4\xe0\x45\xe2\x2c\x4a\xb6\xfe\x2d\x65\xad\xc6\x6a\xf1\x36\xb1\x74\x2e\xbb\x52\x69\xfc\x32\x9b\xed\x2f\x2a\xa7\x5c\x37\xe2\x76\xe8\x2d\x6d\xef\x4f\xd0\xfc\x3e\x96\xfc\xda\x56\x97\xb5\xc5\x1e\x96\x0e\x9e\xb1\xf9\x70\x33\x52\x0c\x6d\x61\xdc\xb4\x6a\x65\x03\x8b\x82\x61\xc8\x46\xda\x18\x4d\x3a\x13\xed\x47\xb8\xe8\x8f\xb4\xfb\x30\x9a\x06\x23\xbe\x42\x04\xfb\x1d\xc5\x29\xcd\xce\xc9\x69\xe3\x60\x59\x9d\x36\xdf\xe7\x7a\x70\x4e\x05\xa7\xab\x2a\x65\x9f\xf5\x7c\xe6\xf1\xe1\x0b\x2e\x8b\xad\x6c\x65\x54\x8d\x58\x55\xa0\x9b\xe3\x1c\x6a\x87\x3a\x85\xed\xc3\x41\x88\x30\x44\xc9\x5c\x34\xf4\x90\x00\xfe\xb1\x23\x0c\xe9\x93\xce\xf0\x4b\x41\x37\x47\x91\xf6\xe5\x7e\x98\xce\x25\xd0\xb1\x5d\xaa\x88\x72\x10\x21\xd6\xf1\x30\x52\x6e\xb0\xde\xfd\xce\x54\xf5\x3d\x3e\xdd\x55\x93\xaa\xbc\xf9\x57\xf0\xfb\x6e\x37\xc9\xcc\x04\x95\xcd\xfd\x11\xa8\x5a\xc3\x79\xb7\xc2\xbc\x6b\xde\x5d\xfb\x49\x7e\x4b\x04\xa6\x83\xe3\x6c\xf8\x6c\x22\x22\xca\x00\x83\x8f\x52\x17\xf6\xc6\x52\xeb\xcf\x28\x6d\x24\x35\x40\xc8\xa9\x60\xb7\xe8\x91\x18\x0f\xae\xb2\xd3\xf6\xfd\x99\x9a\xec\xf3\x1d\x79\x52\xfb\x33\xeb\x29\x32\xda\xf3\x3c\xb3\xaa\x23\xb3\x7d\x3f\xc4\xa7\xfd\x02\xb4\xd1\x55\xa8\xc5\xfd\x5c\xbb\x3c\xdb\xeb\xe2\xf8\x2c\x8b\x22\x8b\x01\xb5\x0d\x60\xee\x1a\xe9\x22\x99\x50\xc0\x8e\x60\x42\x1d\x92\x4a\x81\x52\x1f\x02\x2f\x47\x16\x86\xfd\x06\xa1\x38\xfa\x7a\x65\x77\x80\x53\xcd\xfd\xdd\x16\xa4\xef\x7d\xe9\xf6\x2d\xd4\xf5\xf9\x60\xa7\x52\xd6\xe5\x9c\xb0\xae\xf1\xb1\x03\x25\xad\xa8\x25\x10\x36\x79\x8b\x61\xbc\xc0\x3b\x49\x2a\x13\xa2\xe4\x1f\xe8\x27\x72\x54\xb8\x1b\x3e\x80\x92\xe1\xbe\x0e\x41\x7b\x70\xc3\x92\x7f\x43\x0e\x02\x4b\x2b\x00\x66\x77\xce\x28\x64\xee\xc2\x05\xd5\x4a\xa2\x9c\x44\x7b\xe3\x69\x47\xe5\x2d\x89\x3b\x94\x04\x23\x8d\x7d\xb4\xf0\x2f\x72\x27\x80\x09\x9b\x39\x32\x04\xb9\xc2\xc4\xf6\xc4\x82\x53\xca\xf5\x48\xbf\xf1\x86\x85\x53\xc9\x75\xab\xf2\xa0\xdf\x20\xbb\xe3\xd3\xe6\x11\xdf\x15\xf6\x16\x51\x2f\x07\x8f\x68\x24\xa3\xe6\x04\x23\x1d\xfe\x6a\x45\xb2\x48\x5f\x42\x31\xae\x87\xea\x49\x47\xa6\xde\xcf\xbc\x3e\xca\x1c\x4e\xb3\xdb\x1f\xb3\xaa\x8e\x13\x93\xdf\x48\x87\xc7\x7e\xa6\xf2\x9c\xda\x92\x83\x75\xdb\x4c\x9c\xa9\xec\x7d\x12\x15\xad\xe7\x28\x57\xc4\x4e\x3a\x71\xea\xcb\x8e\x54\xcb\x4a\xef\x59\x3b\xa3\x0e\x85\xfa\xae\x29\x6d\x9c\x7a\x7e\x12\xcd\x3b\x47\xef\x72\xc1\x0f\x27\xbb\x23\x38\x10\x12\xd7\xd1\xd2\xf5\x3b\xf7\x08\x29\x68\xe4\x7b\x87\x9a\x72\x1c\x4e\x7f\x3d\x33\x5c\x22\xb1\x63\xe2\x0b\xe4\x6d\xd6\x2b\x31\xd5\x46\xc1\x87\x11\x5b\x02\x45\xd7\x70\xab\xb0\xf7\xe4\x6d\x12\xa2\xae\xaa\x0f\x18\xdd\x46\x6e\x54\x37\xa4\xc5\xb7\x95\x5c\x6a\x98\x4d\x8e\x4e\xb3\x9e\x8f\x9a\x4e\x87\xca\x9c\xce\x8f\xea\x3b\xcd\x36\xc5\xd7\xbb\x41\xaa\xf5\x73\x57\x40\x37\xe2\xe7\x3a\xb7\x1c\x29\x8d\xa1\x1c\xc2\x59\xf1\x71\x49\x58\x2b\xff\x61\xee\x35\xc8\x41\xd3\xa4\x60\x46\x2b\x62\x5a\x22\xae\xa8\x1a\x75\xa9\xe0\x67\xe4\xd7\x82\xb8\x4d\x1e\x4c\x68\x10\xda\xa0\xd5\x2b\xa5\xe1\x0c\x20\x5a\xbe\x80\xe2\x85\x98\x85\x82\xa9\x24\x58\x8d\xd4\x26\xaa\xfb\x8b\x7a\x6b\xed\xa7\x6a\x31\x91\x9e\xde\xc2\xed\x36\x80\xde\xe8\xd3\xf2\xdc\x92\x47\x16\x44\xdb\xda\x1f\x7d\x11\xc2\xbd\xd0\x7b\x37\x07\x82\x61\xaa\x0a\xeb\xec\xc9\x85\x41\xdb\x71\xd2\x9f\x6c\xd9\xe3\xea\xfc\xbb\xc9\x32\x38\x77\x26\xb1\xd9\x60\x65\xd0\xf4\xa7\x29\xef\x45\x8a\x99\x58\x48\xd7\xfd\x94\xfc\x78\x3a\xa5\x04\x2c\xfc\x78\x79\xfc\xf6\xfb\x8e\x7e\x57\xb7\x23\xfe\xf3\x31\xf6\x39\x3a\x3c\x0d\xbc\x5b\xf5\xe2\xba\xe7\x02\x62\x99\x85\x5b\xfb\x3d\x50\xf2\x39\x5c\x48\x09\x86\xa5\x0d\xe1\xdf\x09\x6d\x81\xb8\x84\x80\x71\x79\x03\xe4\xa7\xb8\x90\xa1\x1a\xa5\x00\x53\x5e\x7b\x92\x1a\x34\x78\x0a\x49\x20\x29\x23\x71\x00\x3d\x05\xbe\x78\x58\x7f\x70\x70\x50\x03\x61\xc0\xc2\xe7\xdc\x85\xa7\xef\x63\x4b\xd9\xa9\xf9\x1d\x54\xee\x13\xe2\xc6\x0d\x08\xf0\x0e\x71\x8b\xbc\xf4\x92\x45\x85\x55\xbf\xd3\xe2\x04\x59\x10\x0c\x0a\x62\x5c\x3f\x68\x14\xc3\xbf\x3e\xa3\x84\x47\x10\x64\x30\x06\x9b\x89\xa4\x6f\x26\x9a\x73\x1f\x98\x31\x43\x68\xf0\xa4\x77\x7d\x5c\x10\xd8\x32\x30\x03\x07\x15\xbb\x78\x32\x15\xdd\x7c\x25\x26\xd9\xc4\x7f\xa3\xf0\x4a\x87\x9d\x62\x17\x97\x7a\x0d\x64\xba\x3d\x81\x94\x4b\xd1\xcc\x5b\x5b\xab\x1f\x91\x38\xaa\x3b\x3d\x8d\xd5\x6d\x27\x0f\x93\xad\x60\x73\x8a\x12\xd9\x32\xb5\xe9\x5f\x7d\xed\x46\xcb\x1b\x69\xae\xe2\xba\x89\xb4\xf3\x68\x32\xce\xac\x6a\x4e\x16\xc1\x63\x0e\xd7\x70\xd6\x9b\x3d\x9c\xdc\x0e\x8b\xfd\xdd\x9f\xb5\x17\xc2\x12\xc9\x5f\xdb\x7f\xbc\x57\x75\x7c\xcc\x07\xf8\xba\x0c\x04\x1d\xcd\xf8\x37\x8c\x61\xc8\x51\x88\xda\x09\xb9\x70\xfe\xb1\xc6\x0c\x7e\x78\x94\xf1\x28\xb5\xc3\xd0\x4b\x52\xe6\x52\xb0\x1d\x18\x07\xa7\x85\x47\x0c\x2e\x2d\x97\xc5\x3c\xc2\x8f\x0f\xb9\x81\x84\x40\x86\x69\xc6\x1d\x39\x95\xbe\x27\x38\x04\x50\x9f\xb7\xb1\xb8\x98\xe9\xb4\xbd\x90\xbd\x37\x39\x04\xdc\x0e\x53\xc8\x40\x58\x5a\x85\x0c\x67\x24\xe9\xc5\xc9\x43\x21\xf2\x83\x00\xc0\x76\x60\xd8\xfd\x6d\x61\xfb\x33\xe7\xcd\xcb\x46\xa6\x5c\x9e\x16\xbe\x9e\x60\xc2\x59\x98\xa4\x91\x35\xa8\x00\xac\x75\x9d\x38\xf8\x49\x93\x24\x0a\xe5\x54\x59\x16\x2d\xa3\xe0\x9a\x5d\xf9\x39\xcb\xee\xf5\x1b\x1b\x7b\xea\x9e\xd7\x06\xb9\x1c\x2b\xf8\xe2\xb7\x54\x3a\xbb\x93\xb7\x6d\x67\x2b\xd7\xd5\x3b\x5e\xad\xf4\x4c\x5b\xe8\x56\xdd\x57\x10\x9d\x2e\xbc\xde\x87\x92\xc8\x68\x96\xf3\xe9\xc0\xac\xd5\x8d\x75\x2c\xab\x4d\x0c\x86\xa2\x77\xbb\x8a\x33\x5b\x72\x0b\x9a\x51\xeb\x19\x9f\x37\x6a\xcc\x19\xba\xbe\xdb\x62\x26\xc2\xba\x22\x95\xe6\x78\x9b\xcb\xed\x17\x2d\xd6\xc3\xa4\x24\x2e\xea\x60\x4c\x77\xb1\x84\x9a\xd0\x12\xd2\xd6\x79\x13\x0e\x34\xda\x2c\xe0\xda\x49\x0a\x32\x95\x87\x59\x14\x93\x8a\x05\x50\x32\xc0\x44\xe9\x64\xe3\xe5\x32\x8e\x0f\xb0\xf4\xc0\xd2\x09\x26\x13\xc4\x68\xe8\xa0\xf1\xa0\x55\xb9\x12\x41\xf4\xca\x6b\x1f\xe6\xfe\x52\xc4\x68\x72\x01\xe0\x4c\x94\x94\x40\xd7\x0b\x34\xa5\x23\x0d\x71\xa2\xea\xac\x96\xd0\x7e\xdc\x22\x5e\x57\x54\x9c\x1f\x81\xa2\xf8\xee\xbf\xcc\x42\x85\x0b\x6c\xe9\x4f\x46\xcf\xa5\xcb\xa9\xf2\xe7\x94\x4e\x98\x8f\x36\x08\x77\x31\x81\xee\xa4\x65\x48\x15\xb8\xc3\x5d\x89\x81\x62\x1a\x8c\xb7\xb8\x7d\x5c\xb1\x44\x16\x60\x3b\xee\x46\x84\xd9\xd2\xe2\x32\x8e\x19\x08\xc0\x91\x09\x0c\x2e\x72\x20\x5f\x75\xeb\x8c\x65\x0c\x63\xf5\x24\xc4\x8d\xa4\x62\x71\x2c\x93\x1c\xa6\x76\x4e\x2e\xac\x7c\xb0\x7a\x25\xc5\xcc\x52\xfd\x1d\x3d\xa7\x49\x5a\x74\x48\x8c\x25\x92\xe8\xc3\xa1\xd0\x3a\xaa\x36\xfa\x86\xa3\x1f\x43\xe1\x24\xdf\x6a\xcb\xfd\xe0\x9f\x02\x96\x37\x6b\x3b\x0a\x1b\xaf\xd9\xd1\xda\xaa\xd6\xba\xdf\x17\xf6\xf5\x22\xb5\xa9\x6c\xcf\x6e\x9c\xab\xae\x4d\xd5\xb7\x2f\xcd\xce\x2e\x0b\xaf\xbd\x6f\x18\xc5\x0d\xd7\x0f\x04\x57\x6b\x0e\x0f\x7a\xb1\xdd\xce\xb4\x25\xcf\x2e\x6a\x8b\x81\x7a\x95\x05\x4a\x38\x67\x3a\x1c\x41\xaa\xc9\x55\x9a\x54\xe8\x92\x46\x8c\x24\x23\xc8\xe5\x7e\xca\xcd\x28\x85\x68\x20\xd9\xcc\xa6\x6d\x69\x31\x6b\xd4\x71\x22\x3d\x20\x39\x8e\x8c\x75\x4a\x55\x6b\xfe\xd7\xe8\xa7\xc6\xee\xcd\xb0\xf4\xad\x69\x43\x8c\x41\x18\x0c\x49\x81\xa0\x18\xff\x3c\xdc\xe3\x51\x1a\xb3\xaa\xd4\x1e\xef\x10\xa7\x02\x15\x4d\x89\x03\xa0\x12\x03\x58\x73\x30\x32\x25\x8a\x36\x3f\x6b\xbe\xef\x67\x94\x11\xe0\xb7\x2a\x95\x24\x8a\x15\x0c\x6d\x29\x58\x16\x52\x15\x31\x99\x83\x55\x4e\x17\x6a\x6f\xcd\x2e\xb7\xbc\x3f\x1f\x24\x6f\x77\x17\x3f\xb8\xa4\x70\x7c\x3d\x13\xb7\x13\x2d\x5c\x31\x5c\xde\xce\xf7\x13\xc5\xee\x8f\x4e\xe2\x83\xc9\xb1\xfe\x06\x45\xa3\xbb\xda\xad\xd7\x4f\x8f\xf8\x69\x6f\x3a\x0f\x83\xe0\xb0\x66\x71\x2f\xf5\xde\x84\xfe\x52\xaf\xf9\xbc\x4f\x74\xb5\x7a\x3b\x97\x5b\x2b\xcf\xb7\xe7\x81\x3d\x7e\x62\x8e\xed\x33\x12\x87\xca\x57\xd0\x54\x6f\xb2\xe7\x0c\xbc\x68\x8a\x03\xeb\x43\xe9\x11\xa1\xbd\x21\xe3\xeb\xe7\x1b\x44\x04\x84\x2a\x10\x92\xe9\x89\x86\x18\xc2\x3a\xdf\xf9\x56\x7d\x1a\x4d\xc3\x78\x0a\xad\xab\xd6\x54\xf9\x70\x3f\x1b\x3d\x3b\x17\x15\x6e\x8b\xc1\xf2\x1a\x80\xcd\x7d\xcb\xd7\xc3\x20\xaa\x84\x6b\x48\x69\xf3\x27\x83\xa4\x3d\x40\xe5\x75\xa1\xc7\x32\x86\x8d\x62\x12\x1d\xd9\x00\x1c\xd8\xce\xda\x58\xab\x3e\xa0\xe5\xbc\x85\x13\x6c\x15\x0f\x34\xbd\xc0\xc7\x6e\x42\x5c\x3d\xef\x35\x45\xf6\x06\x91\xdb\xe6\x4b\x10\xff\x59\xd3\x73\xe1\x8b\xa1\x36\xa5\xe1\x88\xf0\x98\x82\xe8\xc0\x92\xa9\x7d\x1f\x26\x0d\x9c\xd1\x39\xcd\x0e\xd4\x4f\xe1\xe2\x6a\xaa\x7e\xb7\x17\xc5\xea\x3d\x41\xfb\x80\x8b\x5a\x07\x5c\xab\xed\xdf\x6a\xc5\x23\xb8\x92\xe3\x59\x6f\xf6\xb0\x36\x3c\x55\x6a\x46\xd4\x58\xd9\xb2\x33\xaf\xdc\xdc\xb6\x1f\x6c\x56\xae\x7a\x7d\x3e\xdc\xf0\x75\x34\x7a\xef\x87\x80\x51\x86\x76\xba\xdb\x53\xcd\x6d\x98\x49\x73\x65\x6c\x7c\xb7\xf3\x4a\x0a\x36\x8e\x26\xc2\xa4\xcf\xd9\xb9\x2c\x5e\x20\xa5\x56\x7b\xce\x9b\x55\xfd\x6e\x38\x07\x7f\x65\x08\xc2\x18\x4c\x86\x62\xac\x65\x09\x56\xb6\x1e\xa5\xfa\x5c\x2f\xac\xac\xd0\x8e\xae\x80\x77\x2a\xd2\x89\x2a\x9a\x32\x2c\xed\xe6\xe8\x3f\x9f\x2f\x00\x7b\x2c\x69\x4a\x89\x3e\xfb\x57\xd3\xc2\xdf\x8d\x95\xc8\x41\x4f\x32\x94\x1c\x57\x33\x33\x45\x75\xf3\xdd\xc6\xad\x1a\xb5\x09\x33\xca\x43\x91\x36\xab\x85\x08\x36\x1a\x61\x52\x60\xfe\x41\x3d\xea\xc2\x92\x52\x21\x1e\x64\xdc\x23\xae\x6d\xf5\x6b\x32\x59\xb3\xaf\xfe\x43\x42\xc6\xbb\xe6\x3f\x68\xe8\x1d\x0f\x53\xbf\xa7\xd8\x56\x94\xf3\x88\xde\x8e\xfe\x52\x15\x06\xb3\x47\x9c\x26\xd5\x17\xe3\xac\x4c\x37\x05\x07\x54\x22\xbe\xda\xfe\xc9\x1a\xb7\xd0\x3d\xdc\x33\xf8\x68\xdc\xce\x56\x9a\x95\x72\xbc\x6b\xb0\x6e\xbd\xbe\x3f\x5a\x80\x6b\x26\xcb\x9e\x66\xac\x26\xb7\x9a\xeb\xf5\x5b\xc9\x57\xf5\x73\x5c\x2e\x2d\x09\x7e\xd9\x80\xab\xe6\xb2\xd8\x44\xd3\x1a\x78\xf5\x82\x2e\x70\x0d\x51\x47\x51\xdb\xcf\xd1\xe1\xd3\x27\x06\x91\x6e\x09\xf8\x23\x5c\x76\x80\x9b\x34\x04\x96\x80\xa6\x09\xf7\xe7\xaf\x5e\x81\xdd\x88\x14\x1c\x81\xfd\xcd\x07\x1a\x01\x0f\xb9\x82\xc1\xe9\x9f\x52\x1f\xcd\xa6\x3d\x17\x74\x6c\x3c\xbf\xac\xae\x1d\x81\xc0\xe6\x9f\x0d\x70\xb1\x09\xed\xb0\x0d\xc8\x04\xa6\xe0\xc6\x1c\xec\x84\x82\x5b\x57\x93\x41\x13\x43\x8a\x4b\x7b\x63\x62\x13\x47\x12\x10\xc7\x67\xa0\x1b\x6e\x70\xc7\x66\x85\xe8\x25\x01\x68\x32\x65\xfb\xd5\x93\x54\x31\x87\x96\xc5\x2c\x26\x45\x28\xc8\x47\x98\x33\x76\x14\x74\x0f\x46\x35\x6f\x7b\x64\x41\x85\x1e\xa8\x37\xf2\x16\x24\xd7\x59\xb0\xb5\x86\x99\x6d\xc2\x23\x84\xd9\x70\xa9\xf4\xf7\xc7\xd7\x76\x26\x3f\xa5\xe5\x17\x0a\x50\x0d\x1f\x5d\xcf\x09\xf7\xe7\xfc\xe2\xc7\x54\x3b\xfc\x33\x2a\x0d\x16\x5f\xd2\x35\x97\x27\x39\xc9\xf4\xdc\x08\x7c\x70\x2f\x21\xff\x50\xc6\xf1\xf8\xf2\xd0\x76\x8f\x0b\x0a\x6f\x94\xee\x17\x42\x8f\xc7\xe5\x0b\xc5\x65\xae\xdd\x91\x06\xae\x90\x15\xa6\xd2\x34\x51\x71\x9b\x15\xf1\xf8\x2d\x5c\x7a\xe0\xbe\xd8\xfd\x5a\xcc\x21\x34\x62\xd5\x77\x96\x27\xe1\x3b\xb6\x11\xab\x8c\xae\xdc\xf5\xa0\x15\xde\x17\x4c\x8f\xbb\xfa\xd1\x3b\xb5\x41\x86\x95\xca\x01\xb5\xe0\x2e\xdc\x7e\xbb\xc1\xa7\x67\x45\xd1\xb4\x41\xc9\x5d\x91\xce\xb9\xbe\xca\xe5\x37\xfe\x03\xd5\xd7\xdc\x77\xb8\xb3\x71\xf0\xb9\x44\x17\x0b\x1c\x65\x3a\x03\x75\x31\xe8\x06\x44\xd0\x20\x5a\xff\x7d\xce\x84\x2c\x2c\xc2\x1e\x0b\x83\x2d\xa3\x18\xf3\x83\xe4\xac\x7f\xb6\x89\xf0\x10\xc6\x42\xb2\x9c\xfb\xeb\x46\xe0\xe4\x64\x2e\x60\x89\xc3\x19\x28\x8b\x68\xee\xc2\xf0\x66\xb5\x60\xce\x50\x01\xe3\x04\xa5\xa8\x25\x66\x70\x16\xd2\x38\x4e\x90\xfb\x5a\x14\xff\x90\x85\x99\x43\x84\x38\xf9\x8c\xeb\xf9\xda\x4c\x56\xfb\x6b\x94\x77\xd7\x92\x5e\x51\xd1\xd9\xd4\x71\x2d\xe6\x2b\x91\x45\x25\x4b\xfe\x58\x47\xa7\x7e\xed\xf7\xd4\x24\x7c\x13\xa6\x30\x8a\xe2\x1b\xd1\x6a\x00\x92\xf0\x1b\x23\x6a\xac\x74\xd6\x6f\xa8\xad\xbb\xcd\xcb\x9c\xa7\xc7\x06\xe2\x7a\x88\x72\x5c\x6e\x76\x09\x6e\x09\xd4\xb2\xce\xdb\x58\x50\x2e\x64\x38\xb4\xdb\xfb\x87\x8e\x18\xc9\x19\xa6\x71\x67\xda\xeb\xcf\x19\x42\x99\x83\xc8\xd6\x99\x7b\x8d\x75\x80\xb8\xb2\x0a\x3b\xca\x71\x2c\xb1\x82\xcb\x9a\x4c\xb8\xb8\x17\xc2\x23\x6a\x48\x83\xad\x43\xe1\xe9\xae\xaf\x8f\x16\x62\x1e\x61\x79\x86\xa2\x40\x89\x4e\xa0\x2f\xec\xd8\xfb\x4f\x83\xbf\x80\xdd\x40\x6a\x78\x06\xa9\x89\x8a\xb4\xfc\x1a\xf3\xdd\xeb\xda\x0d\xb2\xb7\x51\xa4\xf5\x15\x28\xd5\x7b\x18\xfd\xbf\x0b\xe8\xa0\x97\x2c\x48\x5c\x84\xca\xc1\x3d\x17\x6b\xe8\x33\x03\xf4\xe4\x4c\x34\x51\x59\xe3\x46\xc9\x8a\xc3\x67\x60\x42\xb0\x13\x27\x95\x98\xc9\xd0\xf7\xb3\xe3\xe6\xa5\xac\x9a\x42\xc6\x6b\x3a\x9e\xef\x9f\x2f\x6f\xd7\xb7\x3f\x50\x3e\x33\xbc\xce\x17\xf2\xdd\x4c\x4e\x05\x53\x23\xbf\x87\xf7\x85\x2e\x7b\x94\xa7\xaf\x37\x7b\x3a\x28\x1c\xf3\xda\xac\xee\x76\x96\x53\xbf\xbf\xb7\x2b\xe7\x3a\x8b\x95\x68\x6e\x95\x9d\xab\x2d\x1d\xe7\x47\x7d\xdf\xc6\x05\x0b\xb3\x57\x7b\x1f\x9a\x2d\x7c\x4b\x5b\x29\x79\xbb\xaa\xbd\xdf\xe6\xd4\x02\x64\x68\x69\x3d\x36\x6b\xdd\x3f\x36\x2c\x73\x7a\x7b\xd8\xe2\x7a\x3a\x49\x7b\x0e\xe2\x2f\xea\x5f\x84\xfd\xfb\xbd\x07\xc7\xe6\xd5\x86\x9a\x02\x7f\x85\x9a\xd4\x10\x12\x2a\xfb\xe4\x01\x5d\x51\x8e\x52\x29\xec\xe3\x11\x42\x22\x44\x79\xc9\x42\x54\x6f\x12\x79\xc9\x4e\x1b\xaa\x13\x7a\xd7\xd0\x6a\xe6\xd8\xc6\xf2\x7e\xf7\x8c\xe0\x04\x81\xf8\xed\x48\xdd\xf7\xf7\x68\xcb\x0f\x29\x86\x61\x3d\xf2\x55\xbf\x57\x7f\x9a\xca\x3c\xa0\xa5\xf3\x42\xf9\x99\x53\xfc\x09\x7c\xa0\xbe\xea\xd2\xa1\xe5\x28\x2d\x98\x95\x59\x0d\xe9\xd4\xd3\xa0\x02\xa0\xdf\x93\xac\x0a\x90\x61\xd3\x80\xb0\x1e\xf8\x71\x69\x4b\x82\xe7\xa0\x69\xbc\x18\x02\x0b\xa9\x31\xee\xfc\xc1\xd8\xb0\x06\xd1\x05\xa1\x89\xa3\xbe\x4b\x96\xc0\x12\xe5\x80\xc8\x81\xd9\x85\xf4\x22\xb5\xe2\x82\x53\xb5\x24\x66\xc5\xf5\x4d\x10\x49\x66\x1f\xc3\xe2\x3b\xe8\xa3\x0a\xbf\xa6\x8e\x99\x9c\xbe\xd1\x10\x6e\xa7\xd3\x0b\x86\xf5\x0c\xca\xd6\x15\x3b\x4e\xd2\x6b\xbd\x3a\xb7\xba\x1a\x06\x4f\x2f\xb6\x58\xdd\x3e\x57\x3b\xe9\xe9\xd4\xae\xdb\xe7\x4f\x20\x84\x12\xcb\x93\x75\xb1\x61\x11\x5e\x93\xa3\x4a\x76\x8c\x2d\x33\x47\x6c\x76\x96\xbe\x0a\x7a\xec\x09\x73\xd5\xb4\x9e\x78\xad\xa3\xd1\xbc\xd7\xfa\xf4\xb4\xe9\xb2\xdd\x33\xdd\x11\x8e\x18\x43\x28\xb1\x47\x2e\x87\xdc\x75\x28\x75\x4a\xa1\xe8\xe9\x64\xd0\x4d\x21\x34\x58\x0d\x34\x32\xb8\xf3\xc2\xa9\x24\xae\x11\x96\xb4\x3b\xc2\x40\xc3\x98\xc3\x2c\x72\x86\x92\x0e\x04\x35\x5f\x74\xb5\xb5\xdc\x06\x7b\x92\x67\x74\xc7\x48\xc3\xd0\x3b\x59\xe1\x5a\x6d\x6f\x10\x44\x31\xac\x6f\xd5\x9c\xd4\x0f\xea\x83\x7b\xd9\x9b\x7e\xdf\x35\x53\xe6\x20\x10\x7a\xbd\x56\x67\xc0\x72\xd6\x0e\xb4\xb7\x37\x31\xd1\x2c\x55\x9e\x61\x9f\xb5\x35\x77\xba\x03\x7b\x6d\xec\xa6\x13\xbe\x75\x7b\x5c\x9e\x8e\x4e\xd5\xc0\x55\x40\x6c\x7d\xa0\xba\xe6\x15\x5c\x2a\x8a\x4f\x3c\x9d\x0f\xb0\x4d\xaf\x30\xa1\xb9\xc6\xa2\x9c\xf5\xca\x9d\x39\x13\xd8\x07\x54\x86\xc2\xc9\x6d\x57\x97\x41\xf9\x09\x5b\x85\xc5\xf0\x0d\x15\xd8\x60\x8e\xb4\xa3\xd1\xb5\x9d\xb6\x53\x86\x77\x6e\x72\x6e\x34\x7d\xbc\x77\x1b\xe2\x47\x7d\x51\xb1\xbb\x5f\x0e\xa6\x0b\xc4\x2d\x0b\xc8\x7b\x2e\x5e\x5b\x77\x59\xef\xbf\x95\x93\x5f\x65\x6e\x7f\x36\x2b\xb9\x18\xaf\xe1\xfb\xb4\x26\x18\x30\x48\xff\x12\x8a\xfd\xa1\x87\xd8\x40\x9a\x22\x03\x26\xa1\x46\x17\x52\x88\xca\x4f\x8e\x90\x92\xa8\x41\x57\x20\x23\xc9\x26\x56\x9d\x38\xc4\xcd\x46\x72\x20\x6f\x0e\x0a\x8f\xa3\x41\xfa\x81\x67\xc8\x56\x44\xc8\x93\xad\x60\xf2\xa8\x36\x7b\x28\xbe\x90\xac\x55\xb2\xf5\x15\x0f\x3b\xb7\x09\xb1\x27\x08\xb0\x3f\x56\x4a\x65\xb8\x59\x37\x34\x10\xa0\x08\x62\x4c\x6e\x1c\x35\x3a\x6a\x36\x82\xdb\xe1\x4a\x67\xde\x9b\x8e\xb2\xbe\xf8\xfb\xf4\xab\xa4\x29\x9c\x48\xaf\xb2\xeb\xe5\x53\x41\x13\x75\x0c\xf2\xee\x06\x7e\xf4\x47\x18\xaf\x68\x22\xda\x2d\xba\xa7\xc3\xcb\x4f\x40\x69\x20\x5e\x84\x32\x0a\xc3\xa4\xe4\xb9\x0f\x2a\xe1\x76\xe9\x9e\x9f\xd0\x0b\x35\xa5\x72\x22\x29\x50\x9e\xdb\x89\x01\x36\xd0\x40\x1a\x92\x53\xdd\x5b\xdd\xc2\x1c\xf4\x70\x50\x58\x3d\x47\xd9\xf0\xf3\xc8\x92\xc4\xfe\x0f\x01\xd4\x20\xb3\xf2\x11\x8d\x95\x7a\xb1\xcb\xca\xf5\x22\x0d\x56\xa6\x61\xf2\x83\x7f\x57\x2c\xda\xd1\x54\x2a\xde\xa6\xe3\xde\x83\xd1\x6b\xff\xb5\x61\x8e\xe6\xb3\x49\xb2\x52\x51\xc4\x09\xe7\xd7\x3a\xad\xe4\x42\xfd\xbe\x35\x9e\x34\x0e\xb6\x4f\xf0\x84\xa5\x6e\xd7\xd5\x1d\x0c\xdb\xd3\xbc\xa8\xcd\xc7\x7b\x76\xa6\x64\x8b\xde\xec\x46\xca\xa6\xb1\x46\xb6\xcc\x8d\x54\xe8\xf4\x79\x37\x1f\xaf\xc3\x70\xa2\xa8\xc7\x74\x4e\xac\x6e\xda\x87\x9e\xfd\xee\xc9\xbd\xac\xde\x37\x3b\xab\x17\xb6\x99\x75\x21\x5d\xb9\x3a\x6e\xa2\x9e\x3d\xbb\x72\x4b\x41\x1d\xb2\x05\x35\x43\xf3\xb5\xd1\x33\xab\x1a\x4f\x0c\xfc\xfe\xb8\xc8\x4b\x29\xa1\xc3\x7e\x74\x1e\x0f\x7b\xe4\x79\x9f\x7e\x7e\x74\x50\x70\xd7\x0a\xe4\xac\x45\x56\xa1\x1c\xa2\xa7\x9f\x7a\x3c\x5a\x0b\x96\xfa\xee\x93\x32\xa0\x46\xd5\x9b\x0c\x59\x92\x04\x52\x9b\x96\xdb\x57\xed\xbb\xc2\x4c\x81\x04\x69\xfc\xaf\x88\x75\x73\x6e\x89\x65\x6a\x2e\xc2\x62\x71\x79\x86\xd7\x16\x98\x63\x4f\xc2\x98\x31\xbd\xb2\x0a\x72\x7b\xd0\x1d\x9a\x31\x28\xf9\x9f\x84\xfd\xb1\xe4\x30\x12\xe9\xa1\x42\x9a\xd2\x4b\x4a\x6e\x99\x78\xca\x45\x92\x48\xd1\x48\x93\x20\xa6\x5c\xb0\xd5\xbd\xc0\xb8\x65\xd3\x8e\x4b\xfa\xde\xd2\xdf\x1f\xfa\x30\x9f\x14\x8e\x87\x2d\xc7\x44\xd1\x1c\xa2\x43\xe3\xd9\x3d\xdc\x03\x92\xbd\x70\xfd\x0a\x2b\x72\x0e\xf0\x38\x24\x74\x84\x92\xc0\x7e\x58\x86\xb4\xc8\xa1\x52\x32\xcc\xa9\xa2\x7e\x5d\x5b\xa6\x7f\x43\x55\xfd\xea\xdd\x74\xd1\xf0\x22\x0e\x86\xdf\x4a\x1b\x60\x27\x97\x6a\x61\xa9\xa6\xc5\x88\x19\x8f\xcd\xf7\xc1\x34\xfc\x2f\x2e\xc1\x0a\x64\xa9\x15\x56\x3b\x6d\x96\x65\xbf\x08\x4f\xe1\xa7\x9a\xad\x5b\x0c\x4d\xd7\xa2\xad\x0e\x51\x2b\x46\x8a\x97\x5a\x26\xcf\xf3\x28\x4f\xf5\xa7\x39\x99\x1d\x47\x13\xbd\xeb\x89\x9a\xd2\x27\x6d\x17\x53\xb9\xc2\x54\xf5\x11\x4c\xf2\x78\x7f\x79\x1b\x80\x09\xdc\x8b\xc9\x32\x85\xb3\xd2\xeb\x66\x59\xa6\x79\x77\x02\xd2\x8d\x2b\x86\xef\xd8\xb7\x88\x71\x6a\x1a\xd7\x83\xb6\xca\x82\x8e\xc4\xa2\x8a\x16\xb9\xa9\x3e\xb9\x68\x5a\x95\x04\xcf\x10\x96\x77\x95\x6d\x69\xa6\xee\xcc\x41\x3e\x84\xc8\x32\x3f\xa6\x95\xc4\x84\xe9\xad\x33\x3f\x98\xa7\x20\x80\xbd\x4e\xe4\x91\x2f\x93\x2d\x5a\x04\x55\x1a\xf1\x9c\x7f\x49\x17\x65\x92\x8c\x85\x2c\x8d\xa1\xf7\x60\x8b\xff\x2c\x2a\xec\x9b\x8f\x07\x99\x2f\x93\xff\x01\x8a\x67\xc4\xfb\x91\x2a\x42\x9b\xef\x76\x93\x4a\x1f\x66\x2e\xff\x29\x27\x84\xb9\x1e\xd2\x51\xa1\x54\xde\x16\xb1\x4f\xb0\x52\x0f\x3a\xc6\x80\x9a\x0d\x53\x4c\xdc\x57\xf2\x23\x57\xe2\xd4\x81\xde\xa5\x07\x62\xc8\xef\xe7\x95\x04\xab\x2c\x11\x56\xe3\x13\x4e\x03\x44\x55\x89\x00\x20\x06\xce\x59\xc8\xfa\xea\xae\x7d\xbd\x2e\xa7\xf9\xbe\x1b\xbc\x10\x68\x8c\x2f\xf4\x3d\x9e\x4f\x59\x1c\x7d\x97\xa3\x7f\x9c\x1d\x12\xfd\xc4\x29\x4f\x9c\xd5\x0a\xc1\x4f\xe9\xc7\xd6\x26\x32\x6e\xc2\xfc\x0e\x34\x98\xaa\xc0\x43\x96\xcf\xdc\xc0\x43\x06\x31\x45\xa0\xc7\x34\x42\x15\xdd\xd8\x03\xf9\x2b\x23\x84\xed\xf2\x48\x7a\xaa\xee\xfd\xe4\x61\x14\xef\xf2\x3f\x26\x40\xc2\xae\xf9\x55\x9c\x56\xb9\xea\xbe\xca\x2f\x90\xe7\x8f\x8e\x74\x4e\x5c\x04\x02\x67\x43\xd3\x53\xc9\x24\xf7\x98\x81\xf5\x06\x77\x80\x70\x4c\x80\x49\xa0\xb1\xfb\x13\xdc\xaa\x73\x1c\x09\xf9\x35\xa2\xa6\x86\xa3\x50\xe0\x38\x77\x22\xbd\xc1\xe3\x38\x63\x1a\xe1\xfc\xb8\xdd\x19\x23\xc5\x11\x1d\xf6\x96\x02\x0c\x76\x5a\x52\xcf\xb4\x34\x35\xfc\xc1\x42\x27\x3f\x59\xb9\x3d\x9c\xd8\xb7\x1a\x3d\x4e\xd1\x8a\xbf\x8f\x2d\x3b\x7e\x11\xaf\x7a\xda\xda\xcf\x0b\x6a\xc4\xaa\x4c\xdd\x59\xbc\xed\x6d\x41\xbc\x9f\x62\xf8\x1c\x33\x53\xb2\xb3\xbc\x8e\x32\x72\xb7\x9b\x2b\x57\x3d\xcf\x0f\x73\x7d\x5e\x27\x26\x52\x39\x33\x5e\x78\x7d\x16\x55\xdb\x78\xca\x47\xae\xf9\x06\x7e\x6c\x2c\xe1\x22\xcd\x28\x20\xe6\x14\xeb\x5e\x86\x56\xfb\x81\xa9\x2c\x68\x83\xe5\xc3\xb0\x35\x75\x4b\xff\xc9\x68\xd1\xc4\xf5\xa3\x0e\x63\x22\x09\x12\x62\xac\xd0\x20\x2b\xcc\x80\x61\xdb\x1b\x09\x32\xf7\x19\x50\x1f\xd0\xfb\xda\x89\x72\x36\x3f\x77\x7e\xea\xf8\xf2\xf2\x65\xb5\xa8\x2d\x0a\xae\x63\x08\x25\x5e\x73\xd9\xe0\x63\x71\xf4\x34\x5b\x5b\x24\xf8\xac\xc7\x5f\x41\xb3\x3d\x99\x64\x81\x8e\x82\x57\xd8\x22\x67\x78\x00\xd8\xa2\x14\x80\x29\x13\x23\xa0\x66\x32\x8e\xe0\xd6\xf6\x8f\xc7\x9c\xba\x18\xf0\x6a\x63\x62\x97\x29\x32\x46\x19\x6b\x31\x0c\xdd\x03\xb7\xf9\x15\xc0\xa0\x53\xd8\x34\x19\x9c\x13\xc1\x03\x0e\xc4\x39\x4d\x6f\x7a\x0a\x96\xac\x80\xe6\xd2\x69\xc5\xec\x9b\x36\x87\xb2\x52\x57\xac\x53\x77\x58\xc6\xd2\xe0\x90\x44\x9e\x10\x12\x42\x7d\x9e\xe2\xdc\x8e\xef\x9d\xcf\x7b\x05\x9e\x6f\xbd\xee\xfa\x3c\x04\xfb\xac\x92\xbe\x1f\xce\xa0\x26\x93\x63\xbf\x1f\x57\x4f\x51\x72\x4b\x58\x01\xd7\xe4\x7e\x2f\x34\x6a\x2d\x7f\xff\x42\xa9\x98\x82\x3d\x70\xf9\x7f\x71\xf2\x10\xf5\xc2\x27\xee\x0a\xaf\x44\xea\xe7\xf2\x0e\xd6\x0b\xb4\x83\x93\xf1\x61\xb2\xee\x4c\x04\x1c\x99\xf1\xa7\x71\x50\x4e\x9a\xeb\xd5\x7b\xe0\x01\x05\x66\x25\x66\xc7\xfe\xc4\x21\x80\x5d\x78\x41\x8d\xce\x83\x3b\x8d\xf6\xf7\xae\x67\x43\x39\xd5\x50\xe6\xb9\x35\x6b\x7c\x1f\xcd\x90\x37\x0a\x52\x4e\x7e\x58\xcb\x46\x90\xc1\x68\xf6\xf4\x10\xb7\x3a\x6e\xfb\xf9\x5c\x48\x6b\xb0\x3d\x33\x7e\x83\xcb\x20\xd7\xea\x80\x79\xa8\x82\xba\xfb\xc2\xba\x2d\x42\x41\x16\x6f\xe9\xb4\x8e\xd2\x71\x5f\x97\x59\x19\x6c\xad\xde\x24\x0c\x73\x50\x97\xe9\xa9\x26\x34\xe6\x9c\x64\xea\x2d\x48\x73\x16\xdc\xd3\x02\x92\x3b\xf6\xdb\xc7\x23\x86\xf1\xfb\xa3\xfe\x5e\x1d\x4a\x14\x52\x67\x58\x8e\x6e\x59\xcc\x3f\xee\x20\x9e\xa4\x34\x68\xd7\x2d\xf1\xba\xe0\x62\x35\xd2\xbe\x75\x53\x74\xad\x2a\x65\x59\xb6\xd8\x53\x95\xe6\xdc\x31\xce\x0e\x86\xa5\x9c\x57\xd9\xde\x4b\x24\x6b\xe4\xc7\xa5\x43\x7f\x1b\xae\x3f\x77\x56\x0d\xc3\x05\xe2\xf4\x74\x34\xe4\x1b\xee\x76\x5b\xd6\xbe\xbd\xf7\xc9\x57\x6b\x50\x25\xbc\xf5\x36\x71\xab\x45\x64\xd0\x5e\x73\x89\xb0\xe1\x6b\x5f\x89\xdf\xba\x3f\x65\x5c\xca\xf8\x7e\x9e\x46\x49\x98\x2a\xad\x33\xeb\x4f\x4e\x38\xd7\x78\xb1\xde\x46\x54\xad\x35\xb5\x1a\x9e\x75\x48\xd3\x66\xae\xf0\x44\xa0\x72\x06\x72\x6f\x5a\x86\x1b\x65\xf7\x28\xd4\x2f\x63\xb4\x9f\x25\x68\x5f\xc3\xf4\xf6\x94\xba\x32\xd7\x47\xca\xef\x5d\x67\xf6\x69\x52\x2e\x4b\x24\x93\x36\x3a\x5a\xe3\x26\xf6\xeb\x33\x90\x73\x4c\x47\xf6\x83\x46\x92\xae\x81\x46\x02\xb1\x27\x93\x1a\x78\x51\xf6\x63\xed\xa4\x63\x62\xdd\x5a\x0b\xa7\x8b\x56\xbe\x7e\xc9\x24\xf9\xbe\x1f\xcf\xea\xa2\x1d\x8f\xbf\x22\x08\x66\xa9\xfa\xdf\xbe\xca\x7b\x2b\xad\x0b\x43\xd5\xd4\x85\x2c\x4e\xad\xed\xbf\x85\xf7\x51\xf8\xef\x31\x40\x97\xa2\xa2\xae\x40\x9f\xd0\xfb\xa1\xc0\x48\x18\xec\x73\xa0\x4c\x5e\x6a\x09\xe8\x23\x68\x56\x3a\xc7\x35\x38\x83\xe9\x35\x5a\xd1\x86\xe0\xfd\x20\x20\x21\x4b\x16\x8d\xa5\x69\x68\x58\x10\x48\xe3\xf8\x2e\xda\xbf\x07\x6a\xba\xf0\xb4\xb5\xfa\xe9\x18\x45\x44\x85\x11\xc9\x98\x49\x6c\x37\x5a\xca\x0b\x3a\xb9\xb9\xd2\x27\xe6\x7a\x5d\xdf\xa1\xa8\xb6\xbe\x78\xb5\x4b\x9d\x58\x80\x6a\x48\x25\x74\x27\xbf\x60\xd3\x52\x64\x04\xa9\x18\x19\x82\x99\x84\xeb\x85\x88\x31\x2c\xac\x41\xc4\xf3\xa0\x07\x91\x0a\x05\x04\xfb\x27\xc4\x8d\x0f\xe0\x36\x42\xfe\x10\x30\xfc\x20\x95\x57\x10\xa8\xb4\x3a\xe8\x45\x22\x30\x8d\xf2\x61\xec\x33\x2a\x31\x88\xa0\x8d\xc8\xe9\xa7\x2b\xe9\x4b\x27\x18\x07\xeb\x93\xac\x77\xc0\x08\x5c\x7c\x30\xa0\xc5\x43\xa7\x3a\xdb\x13\xe3\xd1\x13\xc5\x98\x19\x68\x91\x25\x8f\x1d\xa0\xb5\xcb\xb5\x12\xca\xaa\x18\x09\x00\xa5\x96\xb0\x62\xc8\xa8\x1f\x09\xd1\xe4\x79\xea\x90\xd5\x72\xc0\x46\xb4\xd1\xf7\xeb\x19\xa6\x82\xfd\x9a\x02\x4b\xa0\xca\x7d\x4f\xee\x69\x93\xdf\x4c\xf4\xba\xcb\x1e\xef\x8b\xfe\x8b\x25\x93\x9d\xdf\x4b\x4b\xdf\x99\x15\x8e\xb2\x7a\x40\xe1\x5e\x65\x9f\x7a\x96\x05\xe5\x0b\xb6\xd4\xa0\x47\x69\xca\x41\x31\x65\xb4\x21\x6e\x0b\x2b\xad\xe7\x43\x8e\xaf\x9d\x9d\x18\x6f\x9d\x8c\x47\x40\x24\xd0\x50\xf6\x7e\x6a\x74\xdd\xf9\x28\xfb\x00\xde\x50\xa9\xfe\xb9\x69\x7d\x9a\x7e\xfa\xb9\xf0\x78\xda\x5b\xb2\x56\x84\x98\x2b\xbf\x20\xee\xa7\xbf\xd4\x8f\x9a\xd5\x83\xc5\x22\xb4\x24\x5a\xe5\x92\x76\x7c\x77\xaa\x50\xf5\xcf\xae\x6f\x0a\xe1\xa7\x30\xcf\x9e\xe2\x95\x32\x41\xe4\xe2\x29\x88\x73\x3a\x48\xbc\x08\xf7\x85\xb8\xe5\x12\x8f\x24\xe3\xab\xa4\x9a\x23\x1f\x78\x8d\x5d\x3e\x20\x81\x4b\xb1\x0d\xa0\x2f\xd2\x03\xb9\x13\x16\xae\xce\xcb\x10\xb2\x3f\xf8\x72\x07\xdf\xb4\xb0\x46\xfe\xd4\x8a\x48\x85\xe6\x42\x43\x14\xeb\x6b\x04\xad\xa5\x8e\xf5\x62\x87\x13\x7a\xa9\x1a\x39\xcb\x29\xf7\x35\xf8\x28\xd5\xe1\xef\x65\xe3\x92\x22\xdb\x9e\x9e\xfa\x43\xbf\xcb\xcd\x31\x42\x81\xba\xb0\x0b\x6d\xf8\x73\x3f\x25\x60\x12\xeb\xf6\xf7\x4c\x09\x9b\x1b\x18\x1f\xc5\x36\x33\x2c\x01\xd1\x3f\x71\x0a\xf9\xa4\x1e\xf3\xf6\x44\xc1\x39\xf9\x80\x24\x3d\x83\x4a\xdd\xc2\x7f\x8c\xe0\xdc\xb2\xc2\x72\x5e\x50\x56\xe2\x69\xd6\xa7\xe7\x58\x7c\xdf\xb3\x35\xd7\xdd\xaf\x5d\xb6\x0b\xff\xd6\x17\x1b\x5a\xac\xc3\x3b\x8b\x97\x89\xae\x64\xc5\xd7\x65\x16\x7a\xff\x1b\x85\xa1\xa6\x82\xb7\xa6\x4e\x05\x33\x55\xdc\xa0\x4c\x72\x44\xf8\x9f\x0c\x26\x86\xf8\xc5\xe6\x1a\xae\x32\x01\x1b\x4c\xa0\x00\xe2\x3e\x97\x3f\x7e\x95\x4d\x51\x6d\x06\x27\xd9\xc7\x4b\x63\xae\x0f\x89\xd7\xed\xf7\xd3\xe0\x14\x95\x5a\x68\x10\xb4\x5c\x33\x0d\xc8\x7a\x7a\x88\x1b\xb4\x25\xf8\x4a\xe0\xba\x67\x14\x45\x64\x91\x84\x13\x1f\xb6\x46\x90\x00\x02\xdf\x03\xf7\x37\x14\x6d\xe6\x87\x11\xe5\x86\x52\x77\xee\xd0\xba\xf9\x49\x31\x33\xc1\x20\xf6\x55\x33\x07\x13\x93\x3f\x41\x63\x4b\x26\xed\xbf\x40\xe4\xc7\xe6\xf1\x4a\xa7\xd9\xfd\xfb\xdf\xa1\xab\xfc\x5b\x64\x02\x08\xf5\x7b\x85\x3c\x62\x34\x16\x45\x0c\xfe\xec\x9a\xb1\xa6\x24\x60\xd4\x3e\x0a\xb5\x02\xe0\x9a\x48\x60\x18\xa2\x23\xbf\x3f\xbe\x15\x4e\x99\x8d\x32\xb2\xa8\xea\x81\x70\x1e\x96\x25\xce\xfc\x4a\x59\x04\x5c\xe9\x96\xae\x1e\xd0\xf2\xaa\x4b\x25\x4a\x68\xb5\x3b\xd2\x5f\x6f\x0d\xcc\xb7\xcc\xa3\xe9\xab\x94\x18\x6f\xf7\xde\x4a\xeb\x41\xa4\xf3\x21\xa5\x18\x7e\x79\x1a\x81\x8d\x81\x0e\x8c\x41\xc9\xd2\xac\x70\xf0\xd4\xc5\x8b\x39\xdb\x70\xfa\xc5\x9a\x0c\x1a\x09\x6e\xe0\x06\xb8\xcd\x7b\x3b\xdb\x6a\xd4\x49\x6b\xab\xe9\x6b\x11\x5a\x86\x30\x2c\xf1\x59\xac\xe3\x49\x19\x91\x59\x59\xc3\x11\x15\xfd\x3b\xf4\xc9\x74\x7e\x86\x14\xf1\xdd\x46\xe6\x45\xee\x36\xd0\x15\x37\xc7\xe2\xd9\xa1\x04\xbc\x79\xf9\xa9\xce\x3e\xe6\x5f\x13\x82\x4f\x6b\x17\xd4\x08\xda\xf6\xa3\xe7\x7f\x77\xb7\x16\xbe\x5c\x1e\xb3\x05\x0d\x57\x69\xa2\xbf\x56\x70\x67\x3a\x12\x04\x69\xf5\xdb\xa5\x58\x4b\x14\x68\x27\x9a\x5e\xd6\x2a\x22\x6b\xda\xd9\x1b\x4d\x17\xe3\x3b\x7b\xb7\x9b\xee\x67\xac\x15\x65\x6b\xc7\x5a\x48\x43\x5a\x5f\x34\x0c\xf1\x03\x6b\x29\x0b\x57\x53\x90\x9b\x04\x92\x29\x90\xb1\xad\x78\x1e\x71\xc2\xec\x5b\x15\xdc\x30\xde\x16\xb0\x47\x98\xe2\x95\x20\xeb\xc4\xc2\xcd\x11\x51\xa0\xb8\xfa\x08\xc5\x98\xd4\xda\x78\x06\x17\x35\x14\xfc\xc3\x06\xb5\xf0\xd6\xec\x1a\x60\xa2\x82\xa6\x77\x09\xe1\xe4\x44\xcc\x1f\x86\xc6\x26\x78\x92\xe2\xfe\xc4\xec\x57\x91\x96\x2e\x25\x66\x53\xdc\xbd\x0d\x25\xcd\xee\xd8\xc2\x88\x16\x85\x98\x5b\xa1\xd4\xb8\x4f\x54\x87\xa5\x8c\xa3\x51\xd8\x0b\x6f\x9e\x5d\x7f\x76\x40\xd4\xb4\x19\xba\xed\xc3\x51\xca\xd6\xf2\x2c\x63\xbc\xd2\x5f\x84\x09\x09\xcc\xcc\x28\x49\xfa\x0a\x51\xef\x54\x2c\x50\x28\x47\x58\x98\x92\xed\xba\x3c\xbf\x2d\xb3\x75\x79\x09\xca\x9a\x6e\x6a\xb0\xd8\xdf\xef\x93\xf2\xdf\x0e\x50\xab\x56\xb5\xf7\xf4\x1f\x8a\xc7\x5e\x13\x39\xf0\x38\x9c\x68\x97\xc0\x72\xc7\xea\x7b\xca\x3a\xf0\xd2\xd5\xc1\x91\xa0\x59\xc5\x49\x9f\x7a\x55\x4d\x68\xcc\x8c\x06\x1b\x3e\xfc\x8b\x67\xae\x33\x96\x38\x1f\xd5\xef\x54\x13\x2b\x94\x4a\x85\x98\x9a\xfd\x01\xec\x5a\x9c\xe7\xc6\xff\xd4\x46\xdd\xda\x74\x5a\x3d\x32\xbd\x42\xb5\x4b\x0d\x31\xcc\xe0\x0d\xb6\x37\x77\xc3\xe5\x83\x5d\x46\xcc\xbc\xc4\xb0\xae\x46\x17\xd2\x5f\xed\xdc\x1f\x5a\x42\xcc\x65\x76\xe6\x70\xf6\x0c\x6d\x2c\xa5\xba\x25\xa9\x58\xa8\xb9\x57\x50\x33\x7a\xac\x07\xec\x80\x50\x2b\x58\xb8\x72\xda\xed\x66\x90\x0e\xb2\xf1\x88\xbb\x2d\xc3\x77\x51\x81\xd4\x02\x2b\x01\x79\x22\x67\xa5\x53\x7b\x52\x00\xad\x43\x4a\x8e\x45\xec\x11\x4b\xd2\x44\x21\x63\x54\x35\x41\xa6\x2b\x92\x8e\x67\x19\x44\x5a\x58\x02\xbb\x1b\xeb\x3b\x53\x35\xa4\xcf\x62\x30\x72\xc2\x01\xcf\x0e\xe5\x98\xa1\x0b\x62\xa1\xdb\xe2\x29\x78\xa1\xd6\xf1\x99\xd2\x3b\xa8\xa3\x0b\x66\xbf\x5b\xd6\xd8\xcf\x99\xb5\x80\x66\xc8\x71\x65\x74\xbf\x32\x35\xfa\x52\x98\xdf\xb6\x5f\x0d\x95\x35\x56\x27\xb1\x41\x45\x29\x8d\xf9\x14\xa7\x9c\x3f\xe0\xc1\x70\x1b\xba\x5e\x5d\xfe\x10\x2e\x30\x62\x86\xbd\x16\xe3\x75\x84\xf8\x0b\x54\x2c\x72\x44\xf9\xb8\x9f\xb5\xe3\x7c\xfc\x6d\xc9\x83\xfa\x2e\x55\x28\x54\x98\xe4\xd3\x35\xa3\x76\x3f\xe2\x8f\x9e\x5c\x3e\x5b\x69\xd6\x7d\x5c\x9a\x47\x53\xa5\x7b\x02\x4f\xc5\xed\x69\xb3\x9e\x55\xdb\x38\xc4\x22\x65\xc1\x02\xf7\xe1\x95\x72\x6a\xf3\xdf\x10\x87\xba\xb0\x8c\x5b\x1a\x43\x4a\x92\x51\xda\xc2\xc6\x91\x21\xe9\xac\xff\x10\x09\x66\x07\xaa\xa4\x0f\x47\xb9\x70\x77\x89\x9a\xe7\x41\x74\x4e\x1e\x06\xc7\x39\xa9\x0f\xa0\xad\x64\x64\x19\xf5\x1c\x53\x73\xa7\xc5\x84\x31\x40\x73\xc9\xc5\x03\x13\x2f\xe2\x05\x7e\x13\x7b\x46\x95\xeb\x57\x1d\x3c\x19\xec\x0e\xf5\xa9\x3b\x2f\xe0\x7a\x71\x0e\x3f\x2b\xd7\x34\x2a\xdf\x39\xbe\xbf\x19\x0c\xff\xd3\xfa\x6d\xb1\x19\x1b\x4b\xf3\xc5\xf3\xd1\xf1\x87\x67\x0e\x13\x67\xec\x73\xee\x12\x22\xb7\x5b\x3f\xef\x7a\x82\x80\xa0\xae\x98\xc6\x3b\xb3\x93\xa7\xf8\x20\x5e\xd4\xb3\xf7\x61\xe9\x16\xb9\xf0\x9a\xdf\xf6\xb2\x61\x63\xa7\x6c\xec\x0f\x2f\xa4\x25\x28\xc9\xcd\x10\x6f\xba\x84\x43\x0b\x4d\xda\x2e\xd4\x4c\x02\x50\xe2\xd8\xa4\xde\x30\xb8\x42\xaa\x3e\xa1\x97\x2b\x39\x07\x39\xa5\x92\x43\xd9\xfd\x8f\xfd\xfa\xfe\xd0\x2d\x87\x15\xe0\x28\x0b\xde\xeb\x7c\xe8\x1f\xfc\xaa\xcf\x3d\x93\x20\x2d\xa3\x19\x00\x55\x5c\xc5\x38\x3e\x41\x0f\xc4\xed\x4c\x00\x78\x84\xeb\x65\x72\x66\xbb\x35\x86\xd7\xd5\xa8\x5b\x86\x52\x3e\x78\xe1\xfa\x07\xcd\x90\x42\xc9\xfb\x53\xfb\x23\x5a\xb1\x9b\x8b\x60\x2d\xf9\xf7\x25\x51\x24\xb2\xa7\xdf\xf6\x7d\xa2\xfe\xa9\xbc\x1c\xf4\x1b\x5c\xed\x23\xe7\xe2\x7b\xea\x73\xaa\x16\x00\x54\x53\xe0\xa2\x38\x1b\xe0\x3c\x0c\xbb\x0e\x1f\xb2\xec\x4f\x9f\x35\x05\x7a\x3a\x69\xb7\x2d\xee\x23\xc6\xd9\xaf\x9d\x74\xe4\x88\xac\x65\x39\x59\x3b\xfa\xc9\xe0\x99\x90\x75\xc5\x52\x3a\xb9\x57\xa0\x7e\x73\x00\x9b\xba\x62\xff\xcd\x9e\x2b\x55\x3e\xa6\x23\xcd\xc7\x5d\xec\xfc\x65\xa2\xa7\x81\x39\x70\xd2\x7d\xb7\x45\x3f\x18\x26\x05\x45\xf4\x78\xc2\x52\x79\x9b\x30\x2a\x1d\x7c\x93\x7f\x4c\xbd\x62\x3b\x4a\x8c\x67\x42\x9d\xd2\x97\x50\x5c\x38\x44\xa2\xcd\x02\x6a\x65\x53\xf8\xc1\x98\xe9\x48\xb3\xd3\x15\x7d\xe9\xae\x8e\xad\x53\x6d\xea\x4e\xea\xe7\x36\x53\x5e\x7b\x06\xbc\x1f\xc9\x76\xe8\x7b\xa1\xc7\x81\x9b\xa0\x7e\xa1\x1c\x36\xbd\xe8\xd9\x96\x02\xaf\x24\x80\x2e\x45\x6a\x4e\x9b\x0c\x2d\xb4\xd8\x87\x36\x64\x39\x7d\xba\xa1\x42\xcf\x42\xb4\xff\x27\xc4\x9d\x5f\x2b\x76\x67\xf5\x08\x72\xcd\xb3\x21\x27\x49\x77\xb7\xe7\xf9\xe3\x67\xb0\x12\x79\x93\xcb\x63\x2b\x24\x0e\xe6\x4b\x53\xc0\x90\xc2\xa6\xc3\x67\x0c\x93\x99\xcb\xbb\x5a\xda\x5f\x7f\xb6\xb8\xb5\x2a\x0a\xf5\x25\x67\xcb\x75\x78\x3c\x3b\xfd\x17\xe9\x02\x5b\xb2\x24\xb5\xf9\xdd\xbc\xa4\xdd\x70\xbe\xb9\x3b\xff\xdf\x0c\xaa\xcd\x0b\x84\x06\xb1\x88\x61\x11\xe9\xde\x38\x9b\xda\xcb\xda\x43\xba\xc8\xca\x0a\x86\x98\x75\x04\x96\x46\xc7\x07\x08\x4c\xad\x76\xaa\xee\xde\x4b\xd7\x58\x98\x10\xcb\xa5\xf6\xde\x6d\xb7\x87\xb3\x0c\xc9\x5f\x50\x5a\x99\x40\x92\xad\xd6\x1e\xb5\x8d\x46\x62\x1c\x75\xbb\x7b\x64\xd5\xa1\x12\x23\x1e\x7b\x51\x76\xe1\xc8\x69\xd2\x0f\x0e\x5b\xc9\x29\x93\x41\x9c\x98\xea\x68\x17\xc7\xa6\xa0\xe3\x07\xec\x3e\xf5\x57\x7f\x1e\x07\x45\x18\xd3\x07\x89\x21\x53\xb5\x7a\xca\x67\x29\x2e\xc9\xf2\x3d\xe6\x3e\xd3\x8b\xfb\x1f\x40\x9b\x64\x96\xe9\xdc\xe2\x9a\xb6\x86\xb8\x14\x18\xe3\x6a\x7b\x16\xc8\x98\x4e\xb4\x04\xd9\x0b\x36\x49\x02\x25\x2a\x85\xa3\xe0\xed\x9e\xf2\x24\xf2\xaf\x05\xac\x09\x77\x1b\x4b\xa1\xcd\x77\xe2\xf4\x76\x74\xea\x56\xb7\xe5\x05\x56\x47\x69\x1d\x8b\xe5\xb3\x6b\xd5\x94\x74\x37\xe9\xd2\x69\x2f\xe8\xe3\x16\xc9\x8e\xcc\x38\x7f\x20\xeb\x32\x22\x24\xdd\x53\xa2\x89\xc9\x0b\xc0\x7a\x3c\x42\x85\x5f\x5d\x38\xe0\x61\xae\xf4\xfe\x44\x58\x5d\x22\x21\x50\x81\xa3\x0c\x8e\x96\x34\x9d\x1f\xfa\xb4\xda\xf9\xd0\x44\x23\x3f\x7c\x15\x5e\x1d\x91\x9a\x78\xd8\x72\x7e\x43\xac\x4d\x61\x12\xab\x41\x7d\xf1\xeb\x61\x37\x75\xc7\x17\x82\xe7\x57\xe4\x6f\x39\x02\x2b\x84\x76\x7b\xd8\x30\xf2\x78\xbb\xd6\x7b\x58\xb1\x54\x2d\x95\xec\x4f\x3b\x8d\xc7\x6c\x06\xac\xba\x94\x7f\xd2\x60\x3c\x34\x76\x74\x3f\xea\x54\xb7\x52\x77\xa4\x7d\xf8\xab\x20\x6a\x4e\x81\x0a\x30\xf2\x20\xeb\xae\x1f\x79\x35\x46\xfc\x22\x00\x71\xdb\x21\x7a\x3c\x42\xd7\xbf\x32\x4d\x1c\x5f\x83\xfc\x08\xdb\x99\xa4\xbf\x6c\x71\x30\xc8\x99\x41\x3f\x1b\x86\x0c\x17\x89\x2c\x8a\x79\x9e\x0c\x72\xd0\xdd\xf7\x4f\x7a\x5d\x31\x83\x62\xad\x10\x62\x3e\xe1\xcc\xa3\xa9\xee\x47\x88\x00\x55\x0a\x15\xea\x8d\xdc\xd6\x81\x79\xb8\x46\x25\x1a\xe7\x66\xcf\x21\x4e\x21\x4e\x6f\x30\x3c\xce\xc0\xbb\x1f\xf5\xae\x5e\x33\xeb\x91\xbe\x30\x5c\x8a\xaa\x2f\xb1\xc2\x99\x94\x46\xf4\x66\x4d\xa3\x91\x88\xc6\x59\x6b\x6e\x0e\x77\xdd\xa7\x66\x66\x62\x21\xf2\x46\x4a\x8c\x9a\x54\x7e\xd4\x62\x3c\x7c\xfa\x74\x3e\x4b\x4a\x21\x73\x6e\x98\x10\xa1\xe8\x09\x67\xc8\xf1\xd3\x7a\x03\xae\xbe\x9b\x19\x52\x82\xe2\x22\x53\x90\x23\x0c\x2a\xfd\xe8\x3f\x49\x13\x9a\x19\x64\x4c\x23\x3a\x22\x5c\xaf\xc3\x28\x23\x69\x85\xb9\x9e\xfe\x11\xae\xca\xd0\x86\xd4\xeb\xdd\xc4\x2a\x1f\xb9\xef\x75\x48\x74\xb4\x60\x09\xde\x64\xa1\xce\xb5\x8b\xfa\x97\xce\x5b\xae\xf9\x8a\x7f\xb2\x74\x15\x3b\x10\x8e\xec\xf0\x4c\x0e\x70\x53\xfc\x32\xcd\xd3\xf1\x88\xc0\x72\xc3\x03\x31\x03\xba\x89\x11\x1f\x39\xc0\x72\x08\x8f\x3b\xa6\x9c\x31\x24\xb9\x05\xae\xf1\xa0\x06\xd1\x0f\xa7\x83\xc7\x1e\x32\x77\x70\x27\x3c\x61\xbd\xad\xcb\x23\x0c\x9c\x8d\xeb\x4c\x03\xa6\x42\x4e\x62\x05\xe1\x8e\x19\x34\x23\x39\x59\xb4\x8a\xb2\x93\xc2\xfd\x2b\xf3\x58\x74\x54\x57\x55\x1c\xca\x46\xbe\x40\x20\xb2\x85\x12\x62\x0b\x1c\xf6\xfc\x1d\xa0\x9a\xbc\x7f\x64\xd6\x0e\x60\x61\xa0\xf7\x8c\xf2\x1b\x52\x6a\x59\xa0\x2a\x8c\xd2\x8b\xe5\xf7\xfd\x7c\x63\x4c\x9e\xbf\x68\xea\x4b\xfa\x11\x63\x43\x9a\xfd\xb3\xdf\x07\xf4\x0a\xf7\xa5\x43\x7d\x8f\xe0\x48\x2d\x15\xb0\xb9\x4d\xd0\x1e\x1d\x34\xa9\x4a\x9c\x58\x3c\x34\x35\x04\x03\x3d\xc1\x4b\x36\xce\x6d\xe9\xaf\x3d\x4d\x2e\x4c\x3e\x5a\xac\x4a\x75\x87\x45\x3e\x33\x4b\x6d\x50\x0d\xc0\x0d\x10\xfa\x30\x36\x4b\x1e\xab\xa9\xf4\x9d\x8d\xc7\x59\x7a\x2a\xac\xd1\x28\xc6\x1b\xac\x38\x71\x65\x1e\xa8\x9a\xeb\xf8\xf2\x5a\xe2\xd7\x60\x54\xf4\xca\x94\xdf\xa6\xa6\x7c\x6b\x28\xdd\x08\xaa\xfa\x06\x2a\x53\x66\xd5\x80\x4e\xd2\xa5\x4f\x57\x7f\x91\xf5\x82\x52\xf5\x74\xc0\xa9\x82\x1c\xf3\x8c\x76\xa7\xc8\x2a\xf4\x41\x09\x42\x5a\xf5\x99\xa8\xff\xac\x51\x14\xc2\xdf\xa6\x22\x29\x21\xf6\x1f\x0d\x27\xff\x1a\xd0\xae\x97\xd4\x67\x53\x43\x70\x4e\x8e\xb0\xad\xd2\x7a\x98\xdf\x6d\x10\xe8\x34\xdc\xf4\x0b\x7a\x77\x43\x10\x6c\xd4\xed\x87\x86\x42\xf0\x3e\x35\xd1\xcd\xda\x70\x9c\x59\x6a\xa6\x48\xc4\xa2\x77\x9f\x4d\xf3\xc8\xfa\x3a\xdb\xdf\xce\x9b\xc2\xe3\x7b\x9d\x74\xf4\x08\xb3\xf1\xb8\x2f\x17\x04\x1a\x4a\x23\xec\x70\x39\x3c\x3f\xb8\x79\xad\x27\x1b\xcd\x7c\x56\xc4\x32\xd0\x0f\x66\x4d\xfb\x59\xae\x2c\x3d\xb4\xc8\xe0\xfe\xd5\x77\x90\x80\x6a\x8b\xf7\xb7\x94\x45\x96\x33\x24\xa3\x9a\xfd\x23\x49\x16\x38\x09\xe1\x95\x56\xf2\x57\xed\x10\xa4\x7c\x4f\x9d\x52\xc7\x2f\x11\xac\x02\xfb\xb2\xb3\x56\x89\xc7\x56\x3f\x43\x1b\x1c\x3d\xa6\xce\x5f\x5d\x0c\xb7\xd6\x64\x97\x2b\x25\xa5\xc5\x65\x75\x2d\xdc\x5b\x9b\xe7\xd3\x86\xc0\xba\x93\xf3\x63\xc7\x13\x33\x10\x02\xbd\x59\xf4\xc5\x9a\xfe\x89\xcd\xcc\xff\x6d\x27\x48\x72\xdb\x7b\x5b\x92\x4d\xeb\xfb\x2d\x75\xa3\xf1\xfe\x82\xae\xa4\x3b\xa6\xa7\xf7\xd9\xce\xe3\x3d\x07\x9b\x40\x4f\x9a\x5c\x4f\x5a\xe5\xdf\xae\x65\x10\x0a\x41\x57\x26\xd2\x00\xac\x3f\x96\x3e\x83\x45\x86\x11\x5e\xb0\x21\x65\x3d\xd4\x38\x47\x30\x82\x5d\xa5\xc6\xbf\xe3\x2e\x70\x47\x01\xab\x21\x4b\x07\x1c\x71\x52\xd0\x37\xb7\x28\xc5\xe4\x47\x3b\x2a\xd6\xa1\xab\xac\x89\x3c\x73\x74\xe7\xab\x1e\xc7\xe2\xca\xce\xc2\x3c\xdf\x53\x1e\xc3\x9e\x25\xa0\xc9\xcd\xc5\x67\xff\x56\x63\x8a\x16\x8b\xc4\x3f\x9d\x0c\xf3\x0c\x73\x57\xfc\xb7\x37\xbe\x0f\x1d\x40\xd1\x3c\x66\x3a\x5f\xeb\xa2\x67\xf8\x92\x63\x35\xf8\x1f\x17\xcc\xa1\xe0\xb5\x3d\x14\xee\xbf\xaf\x29\xda\x7f\x51\xc3\x62\xae\xc8\x1d\x7c\xa1\x8f\x7e\x4a\xeb\xe8\x50\x6a\x3e\x90\x5e\x48\xee\x23\x8c\xdc\x84\x35\xb2\x08\xab\xad\xeb\x10\xf3\x47\x33\xa9\x51\x6b\x8b\x83\x68\x28\x0c\x4c\x2d\xa9\xfe\x14\x41\x07\x9b\x05\xf0\x3c\xe7\x17\x37\x9b\x32\x70\x7b\x14\xb4\x51\x37\xb6\x50\xf6\x96\xd0\x0f\x70\x37\x6e\xef\x1c\xb1\x19\x65\xee\x5e\x5f\x4a\xd0\xec\xa8\x54\x55\x58\x38\xd7\xdc\x32\xbd\xf6\xbd\x69\x2f\xfd\x4a\x26\x73\x8d\xe5\x60\x88\x45\xe0\x20\xec\x42\xfa\x55\xce\x47\x47\x2b\x15\x12\x80\x0c\xda\x68\x6d\x09\xda\x29\x67\x2c\xc9\xde\x09\xe7\x99\xc7\xda\x05\x5d\x21\xe4\x60\xf8\x90\x66\x61\x32\x9f\xb1\xbf\xb8\xf3\x8e\xfa\x4c\xa0\xe5\x84\x62\x1c\x7a\x80\x58\x86\x39\x72\x6c\xbb\xf1\xaa\x32\x0c\x8d\x66\xde\x1b\x62\xd5\x74\xeb\x3e\xfa\xd0\x12\x02\xed\x69\x1d\x65\x44\x1a\xbf\xa1\x6a\xc9\xc7\x36\x4e\x7b\x08\xd2\xd1\x67\xed\x09\x38\xea\xd8\x6b\xbb\x0c\x95\x32\xbe\xc6\x61\xc6\xa5\x44\xe0\xa5\x76\xe2\x70\x31\xcc\x51\x5d\xb8\xeb\xa6\xe1\x06\x5d\x20\x36\x54\x46\x5b\x61\xe9\xd3\xc4\x30\xb2\x9d\xa2\x28\x54\x9a\xb9\x58\xa0\x4d\xcf\xd4\x24\x1c\xca\x4e\x49\x79\x34\xc7\x8c\xb1\xe2\x2a\x95\x1f\x75\xb4\x08\x17\xe6\x1b\x57\x46\xdf\xff\x54\x35\xee\x59\xa9\x2f\xdf\xd0\xda\xb4\xbb\xbf\xe7\xe4\x46\x5d\x25\x8f\x0f\x13\x8b\xec\x6e\xf1\x60\x3e\x35\x0d\x59\xc7\x9c\x18\xd3\xfa\x7e\x76\xaf\x64\xbb\xd6\x72\x3d\x6d\xcc\xb7\x9a\x65\xae\xe7\xd8\xd4\x91\x25\xae\xe4\x8d\xe6\x27\x9f\x27\x95\x78\xcd\x3e\x58\xb9\x5c\x9a\xb9\x18\x2d\x8b\xb7\x6b\x50\x33\x8a\x6e\x7b\xb4\xcf\x5b\xd6\x43\x68\xb9\x58\x5f\xd4\x44\x6f\xab\x6a\x65\x69\x4a\xbd\xd9\x03\xde\xee\xe3\xce\x8c\x27\x64\xab\x2b\xaf\xa1\xb0\x8f\x50\x84\xc8\xd8\xd3\xe5\x64\x2a\x01\x20\x04\x62\x0e\x39\x8b\x5d\x32\x30\x35\x1b\x82\x5a\x7f\x79\xad\xf7\xe6\xe3\x05\x4d\xd6\xf2\xe3\xee\x36\x40\xcc\x92\x4d\xbe\x04\x28\x0c\x30\x04\x90\x22\x8e\xa7\x73\x0a\xfc\xd6\xb8\x90\x78\x4f\x21\x29\xf0\x04\x67\x39\x86\x21\x30\xab\xf0\xdd\x34\x15\x97\xc5\xa5\xc6\x54\xbd\x23\xe5\x25\x69\xef\xfd\x7e\x1b\xfc\x83\x0d\x77\x35\x1b\x9e\xfa\xe4\xfe\x95\x18\x9d\x95\xfe\x92\xda\xbc\x66\xe6\x7a\x78\xcc\x7f\x47\x8a\xd2\x5d\xbe\x26\x67\xfc\xd6\x54\x73\xd9\x8f\xe3\x6d\x7e\xe8\x7c\x77\xc4\x79\x7a\xc0\x5c\xbd\x33\x27\x85\x6a\xd0\x2c\x2d\xa7\xe2\xb9\x31\x22\xcb\x5b\x33\x56\xd0\x70\x14\x89\xc5\x5f\x38\xc6\x20\xbd\x78\x11\x95\x05\x01\x22\xd7\x08\x49\x67\x8a\x39\xc4\xae\x40\x1d\xfa\x25\x9f\x48\x10\x04\x1e\xda\xad\xaa\xd3\x42\xb4\xa6\x63\x88\x5b\x7f\x2f\xe5\x20\x58\xcf\x6e\xa9\x8d\x7f\xab\x12\xd2\x37\x3e\x20\xbe\x05\x55\x69\x23\x0b\xab\x9f\x22\xca\x45\x5f\x74\xb0\x01\x8d\x32\xad\xb2\xbc\xfa\xb6\xc3\xf1\xf9\x10\x82\x27\x23\x70\xaf\x7b\xde\x6a\x73\xfd\xa6\xfa\x35\x34\x6b\x92\x06\xb4\xe1\xc5\x47\x49\x0c\xc2\xde\x09\x8a\x39\x64\x32\x23\x7e\xca\xb1\x06\x96\x9f\xfc\xe0\x51\xb8\x52\xf0\x4b\xfe\xd0\xea\x70\x09\x4c\xfe\x34\x4c\xe1\xc3\x07\xba\xd5\x30\x2e\x67\xbb\x2d\xf0\x45\x3b\x5e\x21\xee\x22\xe5\xcb\x66\x68\x8a\xbb\x22\x19\x78\xb6\xd5\x5b\x2f\x37\xc6\x8a\xb9\xfa\x1d\x67\x7a\x55\xaf\xfa\x34\x18\xcf\x29\x71\xbb\x27\x57\xea\xfa\xec\x82\x29\x7d\xa2\xc7\xe7\x11\x12\x62\x07\x15\x4e\x6e\x72\x09\x44\x0f\x90\x1a\x2f\x8b\xb9\xdf\x9d\x48\x96\x58\xa6\xb6\x0b\x76\x31\xa7\xee\xcd\x3f\x8a\x48\xa5\x1e\x3f\xe7\x33\x7f\x7d\x7f\x20\x77\x43\xc3\x27\xd8\x9b\x65\x06\xcd\x73\x4f\xab\x17\x64\x39\x16\x1f\xef\x2c\xb4\x0a\x57\xb0\xef\xda\x5b\xec\x1b\x97\x41\xb1\xcd\xfa\x63\x8d\xdb\x38\x0a\xfd\x8d\xdb\x42\xd1\x90\x0a\x5e\xe9\xda\x25\xae\xe7\xcc\xee\xfb\x27\xce\x0b\x93\xca\x24\x6b\x5a\x66\x7b\xc5\x9f\xe6\xc3\xb2\x69\x6b\xd4\x8b\xc7\xd6\x59\x8b\xe3\x98\x47\x8a\xec\x89\x23\x41\x8c\xe1\xf0\xa4\xb8\x26\x2c\x30\x29\x67\x08\x2e\x2b\x14\xd2\x93\x74\x9c\xef\x52\x0c\x39\x03\x13\xde\x93\x37\x70\x62\xd2\x75\x79\xbc\x96\x2f\xff\x51\x36\x0b\x94\x23\x52\x93\x2a\xc6\xce\xbd\x97\xaf\xb6\xfc\x6e\xbb\x22\x04\x73\xbe\xfe\x9c\x96\xfa\x6e\x48\xe3\x94\xf2\xa2\xde\x01\x9d\xcc\x67\xfe\x63\x9b\x76\xb2\x51\x4f\xa7\x65\x2e\x4b\x81\xa8\x35\x35\xc0\x82\xbd\x19\x1a\xd0\x21\x2f\x20\xe6\x4d\x03\x66\xba\xa4\xe5\x25\xe5\xa6\xaf\xf8\x71\x44\x9c\xa7\xe7\xfd\x16\x7f\x4e\x15\x9d\x88\xbf\x30\xad\xed\x0d\xda\x11\x44\x30\xae\xac\x2d\xf0\xfa\xeb\x7c\x01\xbb\x1c\xe5\x51\x39\xd0\xd3\x05\x66\xf7\x58\xc9\xa0\x12\x14\x11\x38\x3a\x6a\xc8\xde\xb8\x77\x62\xff\x17\x40\xd7\x4f\xd2\x9c\xd2\xd5\xa5\x62\x9f\x6f\xec\x6e\x34\x02\xa2\x61\xa2\x9c\x44\x4c\x8c\x1f\x22\x00\xf1\x27\x0c\x22\x45\x76\xf2\x98\x2a\x58\x88\x78\x59\x88\xe7\x24\x44\x6c\x4d\xae\x1b\x63\x5d\x08\x79\x3e\xd3\x12\x0e\xa8\x55\xf9\xa7\xc5\x5a\xfe\x00\xe1\x65\xa7\xd8\x72\xa1\x55\x49\x37\xc1\xec\x49\x24\x79\xba\xc2\x56\x6b\x6d\xca\x2e\x00\x95\x87\x35\x7d\xbb\xdb\xd1\xd1\x6b\x93\x2b\x55\x76\x7b\xa7\xb5\x7c\x90\xf4\x6a\x1a\x44\x1a\xdf\x04\x1f\x3c\x03\xf5\xe4\xb8\xc2\xbd\xd9\xa0\x80\x66\x40\x24\x4b\xbf\xc7\xae\xc0\x03\xed\xa3\x4d\x23\x8f\xbc\xd2\x84\xa5\xa6\x51\x63\x6a\x43\xf3\x1c\x8d\x7e\x87\xf3\x99\x41\x81\xc2\xf8\x36\xe1\x7e\x45\x25\xd7\x44\x25\xcc\x5a\x89\xab\x39\x1b\x39\xe6\xe1\x5c\x88\xe4\xc1\x26\x0e\x32\x38\xae\x79\x62\x28\x65\xb1\x8b\x1d\x86\x17\x23\x35\x0b\x47\x20\x5d\x6a\x7d\x33\x80\x36\x51\x15\xe4\x5e\x88\x45\x90\x0a\xa5\x9b\x56\xa8\x9b\xb2\x87\x08\x1e\x03\xca\x20\xad\x4b\xbd\x6e\x2d\xcc\xac\x3b\xe6\x18\x6d\x25\x23\x1d\x39\x8a\x35\xad\x08\x99\x09\xec\x0b\xd9\xaa\xc2\xee\x44\x68\x0d\x3c\x30\x2d\x7d\x8b\x4c\x05\x2f\xd3\xe9\xa0\x68\x35\xc6\xd9\x85\x10\xfb\xfb\x6a\x38\xb1\xf6\xc9\x69\x60\xf8\x40\x47\x96\xd5\x2a\x20\x52\x39\x75\xc7\xa3\xaf\xe9\x2b\xa1\xf9\x66\x06\x3e\xa3\xc4\xf9\x26\x08\x85\xc7\xc3\xe2\x5e\x42\x99\x69\x93\xc2\xf3\xe0\xbc\x34\x85\x76\x91\x44\x81\x71\x38\xc3\x96\x05\x5b\x52\x10\xc3\x34\x29\xd8\x40\xa1\xc9\x70\xfb\xd0\xa0\x7a\x30\xe1\xe3\x46\x45\xbb\xa7\x79\x38\xed\x3a\xfc\xec\x6e\xbd\x12\x65\x59\xf5\xdc\xfb\x00\x98\x03\x24\x98\x79\xfe\xaf\xa4\xc8\x4f\x50\x11\x0b\xf0\x67\x90\xcc\x57\xc7\x47\x85\xd1\x6b\xa9\x2b\xe2\x07\x0f\xf4\x13\x97\xf8\x59\x6b\x62\x85\x75\x26\xd0\x37\xb0\x38\x2f\xe4\xd3\x22\xa9\xbb\x73\xb4\x4f\xf8\xa2\x97\x20\xfe\x59\xa8\x20\x63\xfd\x40\x0e\x10\x34\x99\x98\x50\xca\xbf\x7f\xfd\x7e\xff\xf8\x15\x81\x21\x53\xfb\x9d\xb3\x00\xeb\xf6\xe5\xcc\x73\x53\x39\x00\xe8\x8a\x7b\x6b\x29\x59\xfb\x1e\x19\xfe\x47\x2b\x05\x28\x1f\x19\xf6\x79\x99\x88\x23\x8b\xa7\x6c\x5e\x9a\xf0\xfa\xcd\x42\x72\xdd\x2f\xac\xb9\xca\x42\x47\x2b\xb0\x99\x3c\xa0\x7a\x4e\xce\x6d\x4b\x7a\x75\x1b\x4e\xbb\xcb\xe2\xca\x3d\x38\x45\x8a\xd3\x73\x6d\x58\x8c\x6c\x9e\x02\x38\x59\x9e\xef\xa0\x2a\xc6\x4c\xa5\x6a\x2d\x2f\x09\x8c\xf3\x71\x6c\x4d\x8d\xc7\x8e\xea\x5d\x69\x75\x5c\x8d\xfb\xc3\x4b\x97\xb0\x84\xe1\x00\x26\xc7\x7b\xb9\xf1\xb5\xb7\xe8\xbf\x11\x6a\x54\xf9\xea\x2d\x52\x73\xe7\xc0\xde\x59\xee\xa1\xee\xb9\xd0\x72\x58\xd0\xb9\x49\x48\xd4\x77\x74\x77\x6d\x1a\x57\xc9\xc3\xee\xd4\x35\xf4\x90\x64\xef\x88\xe8\x5a\xf4\x3b\xaa\xc5\xc0\x88\xe5\x61\xcb\x47\x63\x73\x4e\xfd\x16\xda\x87\x34\x6a\xc3\x16\xe5\xe4\xe6\xfd\x8d\x46\x56\x34\x67\xe3\x64\x99\xb8\x33\xb8\xa0\xc3\xf9\x69\x87\x3a\xa6\xbb\x09\x91\xd8\xcc\x85\x74\x8a\xec\x98\xf5\x6e\xe0\x86\x51\x34\x8d\x55\x47\xca\x9a\xdf\x64\x89\xba\xa7\xb3\xa1\xb5\xe2\x34\xd6\x08\xa0\xd3\x1a\xb5\xd2\xab\xf3\xa2\xd9\xcb\x6c\xfa\x20\xca\xf0\x06\xb3\x7a\xa3\x27\xff\x32\xb9\x5d\x7f\x41\x77\x75\x2f\x73\xf5\xc8\xbf\x51\x70\x99\xbf\x51\x70\x5d\xbc\x8c\xd4\x70\x51\x2f\x72\xe7\xab\xaa\xf2\x84\xcc\xf2\x00\x93\x4c\x46\x70\x6a\x73\xf7\xfb\x12\xf9\xfe\x01\xad\x49\x75\x9a\xb4\xe3\x3a\x0b\xff\xf8\x69\x12\xe7\x66\x4a\x05\xc4\x88\xd1\x69\x6f\xce\x71\x90\xbb\x23\x1a\x59\x53\xcc\x76\xae\x27\x36\x90\x57\xd4\x1e\x4f\x7f\x4d\x6c\x6e\x6f\x9a\x16\xc2\xcb\xd9\x68\xaa\xad\xc1\x06\x5f\x9a\xdb\x56\xb2\x34\x3c\x4c\x78\x06\xc3\x2b\x10\xe7\x59\xe4\x09\xe4\x8c\xa1\x76\xfe\x3d\x92\x88\x17\xe0\x17\xb1\xc3\xca\x31\xd3\x28\x39\x16\x85\x6d\xee\x0f\xe8\x9d\xf3\xec\x94\xa8\xfa\x21\xe4\x94\xa8\x8a\x8d\xfa\x59\xfb\xaa\x87\xe1\xc5\xa4\x3d\x5e\xb0\x8f\x3f\x62\xcf\x14\x1e\xa2\xce\x0e\x46\xda\xd7\xab\x02\xcf\x8c\x14\xe2\xa8\x7a\xa0\xee\x59\x4d\x1d\xcd\x0b\xe0\x6f\xbf\x21\xf9\x8e\x84\xf2\x31\xe3\x93\xc6\x32\x7e\xa9\x85\x70\x35\xde\xe9\x35\x8d\x0d\x47\x64\xb5\xa9\x85\xf8\xfa\xeb\x6a\xd6\x99\x1e\x24\xad\x71\x84\xa3\x49\x34\x0e\x5f\x47\x8e\x98\x70\x90\x07\xab\x39\xac\x68\x1f\xe4\x00\x58\x01\xe0\x07\x7f\x5f\x3c\xb6\x96\xc3\x69\x30\x1f\x96\x5a\x97\xfe\x44\xd9\x21\xaa\x45\x12\x83\x69\x11\xea\xb7\x60\xb2\x4c\x2d\xc4\x4c\xde\xee\xee\x79\x88\x52\x32\x13\x68\xda\x47\x1d\xed\x34\xdb\x9f\xda\x5d\x2c\x94\xe0\x84\x52\x65\xe2\xd5\xb2\x7f\xd0\x11\x48\x4b\x19\x3d\xc0\x10\x67\x47\xab\x6c\xb4\xbe\xd7\x67\xaa\x50\xec\x32\xd7\xb3\x4e\x82\xf4\x07\xc6\x2e\x4a\xd0\x52\xb7\x8e\x34\x29\xc6\x4e\x6a\x44\xbe\x6a\x37\x29\x7d\x65\x5c\x3b\x7f\x66\xd0\x6f\xb7\xdb\x3f\x85\x80\xe2\xcd\xa1\x86\xac\x20\xb5\xd3\xe7\xb8\x87\xba\x4b\xd2\x14\x86\xc8\x73\x29\xdf\x0c\x9f\x74\xd8\xb2\x67\x1e\x6f\x1e\xa1\x68\x51\x0e\x36\x9f\xb7\x05\xbc\xb2\x4c\x36\x1b\xbd\xf3\xd7\xc1\xc0\x30\x0f\x8c\x93\x86\xfd\xa5\xd6\x90\xae\x55\xc6\x3b\x3d\x50\xd7\x81\xb9\x15\x62\x3e\x9c\xd1\xa1\xe6\xf5\x6c\x61\x1f\xc7\x12\x5b\x60\x86\x5d\x21\xcf\x00\xf1\xd4\x87\x4c\x0c\xa2\x6b\x69\xd3\xc7\x4b\x25\x39\xad\x5c\x3e\xf2\x72\x56\xe0\x91\x97\x49\x70\xb2\x65\x82\x17\xb3\x17\xfa\x87\x4e\xf0\xfd\x0d\x63\x09\xd5\xa0\xb6\x36\x94\x9c\xd1\x16\xcc\xd9\x33\xfc\x46\xa9\xba\x70\xef\x3d\x22\x9b\xfb\x63\xf7\x18\x89\xe9\x42\xd1\x8e\xbe\xed\x56\x5f\x0c\xaa\x65\x39\x1c\x7b\x57\x7e\xff\x13\xec\x7d\xe7\x00\xe0\x4b\xd9\xaf\x56\x97\xb2\xa2\x4d\xd9\x67\xed\xb9\xa0\x57\x38\x1c\x5e\xf9\x01\x1a\xa8\x26\xd7\x88\xa8\x2e\xee\xf9\xf1\x0f\x76\xb4\x03\x15\x27\xa9\x14\xa7\x60\x0d\x8b\xb5\xb9\x8b\x06\x8b\xd2\x80\x09\x54\xbb\xf6\x14\xe3\x10\x56\x4f\xb9\x1a\x09\xbd\xcc\xd6\x68\x33\x85\x34\x4c\x31\x78\xa5\x52\x2a\x13\x05\x7e\xb7\xfa\x3e\x02\xec\xd7\xe8\x9d\x4c\xa5\x54\x51\xca\x6d\xfe\xd8\xce\xe8\x5d\x23\x5b\x81\xcd\xd3\x5b\x51\x44\xc4\x0b\x8c\x91\xd8\x77\x98\xc5\x2b\x79\x1d\x6a\x30\x2a\x6e\x7c\x34\x17\x5b\xda\xdc\x72\xdc\xb8\xac\x15\xd8\xcb\xd6\xcf\xcf\x84\xe9\x7a\xca\x91\xa1\x55\x56\x7b\xb4\x4b\x5e\x62\x61\x9e\xb1\x5c\x7a\xf5\xb7\x79\x0f\x47\x43\x7c\x5f\xb2\xd6\x3e\x7f\x20\x54\x73\xe7\x3b\xab\x4d\x4f\x94\x78\x5b\x6f\x88\x11\x9b\xf3\x1a\x47\x62\xd3\x77\x38\xe3\x54\xbd\x20\x29\xd3\x9c\xd4\x1b\x87\x36\x5a\x05\x9e\x2a\x59\x55\xaf\xae\xcf\xcf\x1b\x14\x48\xab\x24\x0e\x1c\xfd\xb5\xf7\xc4\xd5\x11\x65\x02\xea\x68\x43\x39\x4e\xef\x14\x32\x34\xd2\x3d\x81\x86\x5e\x42\x54\x6d\x76\x54\xb7\x03\x77\x5b\xcc\x0f\xce\x9a\xad\x52\xae\x3d\x4c\x44\x31\x59\x06\x5d\x77\x85\x8a\x50\xfb\x3e\x14\xa3\x52\x8d\x0b\x30\xa8\x09\x3f\xe6\x69\xe3\xde\xae\xf2\xd5\x1a\xc5\xb6\x82\x27\x1f\x57\x15\xb5\x9f\xaf\x9f\x96\xe1\xf8\x7e\x63\x56\x0f\x8b\x28\x3a\x21\xbe\x47\x44\x4b\x17\x28\x65\x83\x24\x15\x6c\x3e\x72\x2a\xd2\x43\x82\x77\x47\xa3\x21\xa1\xa6\x8d\x3f\x18\xbc\x37\xdb\xf9\xc9\x40\x04\xba\xdd\xb2\x6d\xc1\xb4\xfe\xb4\xdd\xc0\xe9\xa0\x40\xc7\x81\xbb\xee\x36\xef\xdd\x36\x0a\x59\xed\x1c\x2c\xbc\x2f\x31\xde\xdf\x56\xd5\x2c\xa0\xd5\xf1\xa2\x6b\xfd\x89\xc2\xe7\x42\xc4\x8f\x1c\x4e\x1d\x79\x21\xd8\x30\x65\xc0\x81\xf3\x84\xbf\x8e\x8e\x19\x46\x99\xc4\x79\xc1\xdb\x30\x34\x81\x3b\xf1\x3e\xc3\xf1\x6f\x09\xda\xce\x31\x83\xd9\x3b\xd4\x7b\x29\x71\xa9\x22\x07\xea\x63\xbb\x8d\xf3\x78\xa8\x2c\x6f\x30\x59\xd1\xf1\x15\x1e\xb5\xa0\x90\x03\x75\x47\x5f\x65\x38\x7c\x24\x13\x41\x69\x27\x9a\x79\x10\x09\x97\x2b\x31\x27\x4a\x4e\xf4\x60\x8e\xf9\xae\x97\x4d\xf1\x57\x29\x13\x87\x2b\xee\x50\xa9\x2b\x97\x4f\x64\x92\xf8\x33\xe3\x60\x22\xb6\x1f\xaf\xa1\x58\x8b\xc5\x20\x9d\x6a\xa2\x07\x09\xa5\x60\x34\xe0\xeb\xdf\x25\xfb\xa6\x9b\xf7\x61\xfb\xfb\x65\xbb\x0c\x41\xbe\xdf\xeb\x5a\x99\x4b\x88\xf5\x35\x5f\x30\x5e\x01\xf3\xed\x62\x71\xa5\x24\x7a\xbc\x1f\x4a\x8d\x57\x0a\x4a\xc0\x14\x88\x52\xe4\xf7\x6e\xd9\xf9\x9e\x45\x21\x38\x80\x2f\x1e\x82\x7a\x33\x5e\x7a\x0f\xfc\x47\x2f\x44\x17\xc4\x22\xef\xd7\x50\x62\xda\xca\x00\x35\xd1\x97\xec\x3d\x96\xc7\xd4\xc6\xc4\x25\xc2\x55\x61\xb2\x5c\xb2\xfc\x92\xc2\x06\x75\x8e\x62\x28\xf8\x41\x5e\xc1\x3f\x42\x9f\x9f\x77\x5c\x94\x81\x77\x5b\xc2\x22\x71\xa4\x2f\x2c\xf6\xbc\x4d\xa5\xea\xcd\xa7\xed\x85\xfc\x5d\xc5\x01\xc6\x54\xa8\xcd\x19\xcb\x07\x53\xe7\xd9\xf4\x4d\xe7\x1a\x74\x35\x6d\xbf\x75\x7f\x0a\xf2\x6d\x4d\x71\x0c\x6d\xdc\x35\xc6\x66\xe8\x81\x69\x2a\x86\x7c\x41\x3b\x50\x28\xe1\xc1\xc1\x2d\xf6\x81\x8d\x2c\x44\xd5\x96\x44\x61\x31\xfc\x9f\x82\x49\x4c\xf9\xca\xc1\xb9\x7a\xe9\x92\x1d\x95\x81\x8c\x1a\x2d\x0b\x46\x7a\x4c\x8d\x7d\x2a\x18\xe4\x84\xb8\x6f\x3c\xc9\x90\xad\xa7\xcd\x3c\x55\x71\x82\x9d\x63\x2c\xdf\x1a\x32\x53\x5d\x74\x60\xf0\xfc\x24\x86\x07\xbf\xcf\xd7\x0c\x59\x2e\x6f\xeb\x4f\x47\xfc\x41\x8b\x72\x64\x96\xaf\xa1\x5c\xd8\x50\x8c\xd8\x8a\xb9\xed\xd3\xf9\x75\x30\x5a\xf1\x5a\x85\x3f\x99\x21\xe1\xb1\x15\xdd\x5f\x5b\xce\x96\xab\x06\x8c\x1c\xdd\x0e\xa9\x7d\x78\xb3\xa6\x48\xfa\x8b\x14\x4b\xb4\x03\x34\xf2\xbf\xe0\x8a\x15\xfd\x36\x4f\xc3\xb4\x2d\x6a\x73\xa3\x1b\x9c\xe0\xf4\x12\xed\x1d\x12\xe6\xd1\x74\xca\x66\xae\xcd\xba\x3d\xc4\xa7\xb4\x31\x25\xb2\x61\x51\xf8\x9a\x03\xb6\x4c\x6e\x87\xe8\xaa\x8a\x82\x6b\x45\xd2\x08\x55\x74\x6e\x9b\x99\x87\x17\x6b\x35\x2d\xfe\xf4\xd5\x33\x36\x85\xb9\xe2\xb4\xcd\xcc\x0a\xc9\x54\x86\xb2\xd1\x1d\x53\x06\x85\xd3\x60\x5e\xee\x0a\x4d\xe1\x58\xe0\x3d\x98\x63\x50\xfc\x5a\x59\x58\x63\x06\x76\x7a\x60\xa5\xb6\x93\x4b\x35\x16\x10\xad\x0c\x52\x7d\x63\xff\xf8\x2f\x2e\xa9\x6d\x88\x0a\xf1\xab\x9d\xe5\xd3\x32\xd1\xb3\x7c\x13\x2e\xc5\x1d\x49\x4e\x1d\x8c\x70\xac\x48\x6e\x73\x23\xd3\xe6\x89\x1c\x49\x2e\x1b\x06\xf1\xbe\xe0\x79\x9b\x49\x3d\x66\xe3\xa1\xd3\x61\xfd\x9b\x36\xe3\x61\x33\xa4\xfa\x8b\x06\xd3\xa1\x65\x7a\x47\x34\x81\x09\x83\xa1\xa9\x86\xbc\xc8\xa8\x12\xde\x63\xe4\x74\x0b\x26\x80\x82\x64\x33\xc4\x29\xb3\xc3\xf6\xb0\x33\xed\x9a\x29\xc6\xe9\x01\x5c\x4a\x12\x0f\x50\x56\xa1\x29\x71\xe7\x38\xc1\x6d\x4b\x65\x83\x77\x60\xae\x62\xe5\xcd\x02\xf6\x83\xd4\x60\xee\xb1\xba\x11\x92\x58\x1d\x6a\xdf\x28\x1a\xf5\xb4\x71\x63\xb0\x34\xc4\x07\x8a\x1a\x7e\x6c\x2b\xa8\x22\x15\x44\x87\x33\x2f\x08\x53\xd4\xca\x49\x33\xb4\xda\x65\x38\x58\x93\xed\x2e\xe3\xd3\x8d\x0d\xa8\x11\xc5\xa3\xb9\x6b\x3d\xcf\xe1\xb5\xd1\x3b\xcd\x77\xe3\xd9\x9b\x04\xbd\xe6\xf7\xd7\xb4\x38\xb6\x98\x1a\x4e\xdf\x27\x06\x93\x25\x38\x21\x21\x36\x6b\x6b\x0b\xeb\x2c\x0d\xd5\xcd\x96\x93\x72\x12\xcf\x7e\x52\x53\x84\x22\x50\x2b\xbc\x17\x6c\xcd\xce\x64\x9a\xd1\xbb\x56\x5d\xd6\xca\xb7\x3d\xf1\x98\xd9\x5b\xdf\x57\x6c\x29\xb4\x9f\x23\x8d\x9d\xbf\xe7\x3d\xfb\xc5\x93\xbd\xf7\x57\x35\xf5\x9b\xaf\x2e\x2e\xb7\x5c\xf5\x56\xeb\x78\x9f\x1d\x9d\x2f\x3b\xed\x46\xfd\xfe\xf5\x49\xbd\xde\xee\x15\x62\x95\x4e\x1e\xed\xad\xfc\x38\x66\xd1\xd1\x56\xe3\xc6\xab\x31\x55\x33\xba\x5e\x68\x73\x4f\xe8\xa8\x06\xf0\xfe\xd9\x06\x90\x09\xdb\xb2\xc9\xd1\x6b\xfa\x81\x40\xe4\xfc\x48\xdc\xfe\xca\xb1\xfd\x8a\x4c\xea\xf1\xab\x1a\x33\x46\xe1\xfa\x08\xfe\xfa\x08\xe7\x6e\x38\x32\x0a\x64\xfd\x72\xea\xca\x02\xb6\xfe\x88\x36\xeb\xf9\x86\xfd\x4a\x9b\x6b\xf6\xcd\xf5\x2a\x48\x48\x83\x7a\x23\xd0\x7a\x21\x92\x0d\x59\x65\x63\x95\xf6\xfd\x29\x35\x2e\x29\x68\xfe\x50\x10\x9f\xd1\x8b\x35\xcd\x82\x07\x26\x0a\x68\x02\xc8\x7f\xa6\x9f\x1f\x02\xba\x74\x03\x6d\xf2\xf9\xb2\x2c\x7a\xdf\xa9\x87\x8f\x77\x4e\xac\x3c\x8c\x17\x7f\x7a\xb8\x54\x7c\xbf\xb9\x7e\xf3\xa2\x8b\x99\x4e\x0e\x46\xfc\xc7\x2e\x25\x22\x67\x8d\x26\x87\xb3\xbb\x2d\x33\xe4\xcf\xfc\x21\xe6\x66\xe9\x78\x8a\x30\x0a\x67\x56\xa4\x6e\x46\x7e\x66\x32\x7b\x35\xac\x27\x2e\x70\xc1\x83\x7b\x0d\xad\xca\xb5\xad\xd9\x2a\xfe\xee\xd7\x44\x0d\x48\x59\x2d\x11\x59\x80\x3c\x52\x34\x46\x24\xc8\x59\x38\x64\xcc\x10\xff\x15\x53\xdf\x3f\x47\xd4\xf0\xf8\x86\xf0\xe5\x8c\x11\xb1\xf9\xda\xce\x8d\xc9\x5f\xc5\xc8\xdb\x39\xbc\x55\xf9\x75\x80\xbd\xae\xd5\xd5\xf7\xf4\x45\x4e\x4e\xa3\x7d\x12\x4d\x4a\x93\x80\xf2\x26\xb5\x63\xa1\x76\x5a\x44\xdc\x07\x2d\x2a\xda\xa9\xce\xa3\x31\x18\xbb\xb7\xcf\xba\x48\x90\x71\x9d\x82\x3c\x92\x5d\x98\xed\x11\x1e\xd5\xad\xa2\xfb\x49\x9b\x32\x2d\x91\x0d\x0e\x7b\x98\xba\x56\x22\x92\x39\x00\x6e\xdf\x70\xd7\x93\x8f\x0e\xe9\xb9\xc4\xb2\x90\x30\xd3\xf0\x8f\x95\x9a\x9e\x4f\x06\x5e\x06\xdb\xb5\xc3\xb7\x36\x97\x51\xd1\x18\x53\x6e\x4f\x17\xea\x98\x86\xd3\x8b\xeb\x4c\x48\xc6\x6c\x17\x67\x2a\x35\x2d\x97\xe5\x77\x5b\x4e\xd8\x87\xe6\xec\x81\xb3\x21\x09\xfe\x11\x1c\xe7\xf8\x58\x0a\x94\x85\xc6\xe8\x8b\xb6\x1c\xf6\xef\x82\xcb\x3c\x26\x99\x34\x75\x10\xb0\x60\x86\x11\x98\x8f\x62\x2e\x50\xf7\x2a\x0c\xae\xf6\x0b\x31\xde\x7a\x13\xd4\xf6\xa0\x7b\x17\x76\x9a\xea\x5b\x11\x84\xb7\x7b\x01\x42\x91\x0c\xe8\xb7\xc3\xd5\x56\x6b\xbe\xf1\xaa\xb1\x35\x0c\x6d\x8c\xe3\x70\x5b\x3d\xa6\xa5\x3d\x77\x53\xa4\x73\xe4\x17\xae\xd8\x11\x77\xdd\x40\xd6\x86\x4b\x3f\x4e\x79\xa5\x25\xe8\x8a\x14\xe9\x96\xc9\x44\x79\xfc\xc6\x9b\xe7\x1d\x21\x82\x07\xe4\x7e\x29\x5d\xff\x2b\xb6\x2b\x53\x48\x3a\xa2\xcc\x03\x2b\x1c\x7e\xd6\x6c\xd4\x88\xec\x12\x74\x0d\x7b\x51\xa6\x4a\x1b\xbd\x65\xc2\x2e\xa1\xc0\x07\xc1\x7f\xb7\xcb\x6e\x0d\x3e\x9a\x06\x4b\xfe\xa3\xac\x2a\xd0\x5e\x26\x2f\xec\x62\x7a\xa5\x36\xaf\x24\x50\x5e\x86\x77\x3b\x63\x36\x8c\x69\xe2\x41\x73\x6a\x3d\xa5\x44\x88\x5e\xaa\x92\xf2\x60\xe3\xf1\x9e\xd3\x32\xd3\x5d\x38\x7e\x74\xb6\x23\xf3\xf5\x65\x60\x49\xb5\x5c\xe3\xf8\x57\x4d\xb1\xba\xc0\xe9\xb3\x26\x5e\xc8\xe1\x7c\x66\x65\x25\x5b\x32\x31\x9c\x94\x8b\x4b\x13\x1c\x5c\x23\x4b\xbc\xd7\x3e\x6e\xec\x00\xf2\xd8\x90\xaa\xc0\x56\x51\x02\x12\x92\x3e\x5f\x8c\xb1\xc8\xaa\x60\x87\x5d\xe4\x65\x15\x7b\xf4\x6c\x66\x9b\x5d\x44\xb2\x02\x70\xd9\x6d\xa8\x24\x60\x8d\xef\xa9\xf2\x89\xe9\x85\xea\x0c\x1a\xdd\x15\xde\x51\x39\xdb\xad\x5e\xed\xe7\xb3\xfd\x4a\x23\xe3\xc4\xa3\xf9\x4d\xb7\xc1\xee\x7c\xf5\x7e\xea\xff\xc3\x57\x8c\x37\x45\x6c\x1f\x1f\x31\x48\x73\xdf\x53\x87\x7f\x86\xb0\xcf\x86\x21\xf1\x00\x5b\xa2\x5f\x38\x37\x20\xf8\x57\xfe\x76\x57\x1f\xa2\x5b\x72\xe9\xd3\x35\xcd\x4e\xbf\x25\xbb\xc8\xf1\x2d\x0e\xcd\x55\x7a\x6e\x7c\xeb\xde\xfd\x9b\xeb\x2e\x7f\xe1\x1c\x1d\x5f\xc0\x96\xa7\x5f\xc9\x3c\xee\xa9\x54\xd8\xc6\x77\xf2\xa5\x98\x52\xf1\xe7\x40\xa7\x51\xbd\x74\x91\x28\x58\xa0\x72\xd9\xb2\x44\x86\xc5\xd7\xb8\xaa\x9d\x28\x29\xa6\x48\x24\x1a\x39\x5c\xa1\xc9\x71\x31\x67\x2e\xe0\x99\x76\xbe\xa6\xa6\x1f\xb6\x32\x50\x0d\x86\xf2\xa8\x21\x97\x00\xaf\xab\x85\xf9\xc2\xbc\xd5\x23\x21\x3c\x68\xa4\xc4\xff\xd9\xae\x29\xf8\xdc\xff\xb9\x49\x3e\x93\xe2\x6a\xe0\xc8\x0f\xa9\x59\xdc\x0b\x3f\x89\xd9\x98\x01\x35\x22\x2c\x18\xe4\xa4\x62\xd1\x8b\x19\x71\x39\x58\x5e\xa1\x50\x82\x5d\x73\x27\xec\x53\xb6\xe8\xde\x46\xc0\x9c\xac\x3f\x34\xb3\x72\xbd\xff\xed\x40\x03\x81\x6f\x12\x02\x67\x9f\xa3\xe0\x54\x00\x94\x6f\xf6\x8a\x76\x0f\x5c\xac\x2e\xaf\x2b\x73\x46\x4a\x52\xba\x5b\xc8\xf6\xa5\xdc\xfb\x86\x2e\x59\x84\xcc\xf5\x8d\xb8\xa4\x45\x38\x9b\x16\xb9\x98\xe3\xac\xa5\xfd\xd9\x41\x9e\xb2\xb0\xfe\x23\x7a\x72\x15\xb7\xbb\x67\xab\xc7\xd2\x5c\xc0\xda\xfe\x92\x96\x31\x37\xbf\xee\xe5\xe2\xa6\xf4\x4c\x31\xd6\xcc\xcb\x23\x7b\xb3\x42\x1c\xa2\x0b\x48\xa8\x90\x69\x70\xce\xa7\x73\xc3\x44\x49\xd7\xe5\xbb\x75\x60\x9b\x7a\xf1\xc4\x6c\xac\x5a\xee\x03\x85\x83\xdc\xe6\x45\x98\xc8\x29\x96\xe2\xdf\xaf\x88\x17\xf4\xd3\x84\xa4\x3d\x6c\x79\xa0\x52\xc4\x41\xb3\x95\x72\x30\x59\x7a\xb8\x47\xc3\x84\x9e\xfe\x1c\xcf\x2e\xdf\x7b\x8a\x19\xb5\x86\x87\xbb\xf2\xd8\x2b\x56\x25\x3d\x23\x01\x13\x82\x22\x94\x45\xea\xdc\xab\x5f\xa4\x89\x7b\x29\x28\xb9\xf9\x04\x90\x02\x1a\x2a\x00\x46\xaa\x65\x4f\x4c\xdd\x0b\x25\x45\x29\xaa\x85\x03\x5a\x91\x05\xa8\x48\xf9\x72\xcc\x9f\xb0\x53\xc3\xac\x4e\x5f\x3e\xf1\xd0\x22\x2b\xfb\x78\xc0\x4d\x95\xb1\xef\x62\xb2\x87\x81\x63\xa1\xc4\xc8\xbd\xbc\xb5\x26\xa0\x6d\x14\x46\xe6\xf6\xb0\xdb\x74\x1f\xfa\x0c\x6a\xbe\x53\x88\x22\x90\xc8\x33\x5a\x44\x83\x06\x89\x51\x21\xfc\xcc\x5a\x92\xfd\xb0\xce\x14\xdb\xca\x96\x43\x89\x4e\xdd\x67\xb4\xa4\x32\x93\xbe\x81\xbc\x86\x8a\x54\x05\xbc\x92\x1e\x0b\xdd\x76\x23\xdb\x7c\xdd\xf7\x3c\x2d\x30\x45\xaa\x7b\xbb\x93\xd8\xd4\x64\xe8\xe6\x64\x9e\x18\x2f\x5b\xa3\x79\x65\xd2\xc6\x7b\xff\x44\x88\x65\xc5\xac\x59\x89\xa0\x66\x75\x0a\x5f\x0f\x1f\xd4\x73\xc0\xc0\xb3\x96\xb0\xb4\x7a\x12\xfa\xbe\x29\x66\x7f\x4c\x40\x16\x54\xb4\x7c\x60\xf9\x94\xbd\xf7\xcf\x9f\x77\x3c\xad\x08\x3a\x14\x8b\x9a\x71\x1d\xfe\xe9\x14\x3d\xbc\xa1\x5f\x4b\x83\x96\xd3\x9a\x9f\x75\x36\xf9\xcb\x4a\x49\x5d\x9c\xaf\x87\x0b\x9a\xc7\xfb\xbd\xf9\xe8\xe1\x59\xee\x83\x37\x53\x5b\x26\x13\xe3\xd7\x10\x41\x01\xd9\x52\xe1\xa6\x68\xde\x99\xa4\xbe\x9c\xbf\xf2\xcd\xdc\x89\x2a\x4e\x31\x64\xe2\x16\xf9\xe2\x09\x1e\x1d\xe2\x0b\x5f\x11\x30\x4d\x63\x3b\x6a\x4e\x9e\x12\x50\xa1\xd5\xf5\x47\xaf\x68\x87\x2a\x1f\x48\xae\xbc\x06\xf5\x7f\x8f\xb2\xde\xd6\x71\xc7\x0f\xef\x89\x97\x2d\xd3\x48\xa2\xac\x4a\x43\x82\x30\x61\x4c\x89\xec\x99\x29\xc5\xe1\xca\xd9\xed\x70\x95\xe7\xa1\xb2\x6f\xee\x5e\x5a\xe0\x31\x3a\xc5\x8f\x54\x1a\x6a\x49\xea\xa1\x25\x0a\xc8\x78\x30\x58\x3c\xf0\xcf\x19\x10\xe4\xf3\x6b\x90\xec\x95\xc6\x66\xf2\x7c\x50\xb1\x5c\x4e\x99\xcc\x3b\x27\xaf\x9a\x6c\xeb\x79\x48\x08\xd4\x4f\xae\x77\xfe\x1f\x00\x81\x2b\x7e\xd4\xb4\xa0\xfb\xfa\xea\xaf\x8e\xda\x7c\x06\xa9\x55\xa9\x34\x9f\xea\x94\x8d\xb4\x79\xbb\xb3\xde\x38\xe1\xc7\xb3\xb4\x83\x3e\x20\x4e\x03\xa6\x70\x50\xe7\xeb\x57\x34\xdd\xa7\xe8\x59\x14\xb8\xfd\xad\x07\x45\xb7\x3e\x38\xf9\x3b\x3a\x12\x25\x3d\x9e\x8e\xa3\x2c\x73\x48\xec\x22\x79\xda\x38\x35\x48\x95\xe5\x18\x9b\xd5\x13\xd6\x60\x18\x0c\x49\xde\x2d\x9a\xa8\x37\x0d\xc5\x0d\x32\x6d\x3a\xe2\x20\x70\xb7\x31\x6c\xe4\x02\xd8\xc3\xca\x0d\x78\xb5\x0d\x6e\x5c\xba\xae\x29\x4e\x63\xae\xb9\x24\x9f\x81\x59\x82\x7b\x45\xc7\xe9\x8f\xa7\xf2\x85\x75\x5f\xea\xe9\x3d\xb8\x2a\x5b\x58\x7b\xa8\xa7\xef\xe0\xc5\xd9\x5f\x1a\xfd\x8d\x36\x5b\x22\x60\x34\xfa\x13\x56\x7b\xc2\x8f\xb2\x1c\x47\x6f\x58\x75\xdb\xf6\x62\x66\xc3\x37\xd6\xac\xbd\x75\x4b\xae\x79\xd3\xf1\xaf\xa7\x92\x83\x69\xbb\x2d\xbd\x30\x99\x1a\xce\x3b\x1c\xb9\xb3\xf1\x55\xc1\x10\x29\x20\x13\xaa\x3d\x1d\xfa\xd3\xef\x6e\x44\x23\xd5\x47\x5e\xfb\xd3\x07\xd7\xa3\xa5\xd5\x47\xde\x47\xf2\x77\x8f\x57\x9f\x59\x50\xbd\xf5\xd8\xf4\x15\xc1\x34\xd4\x99\xfd\xcc\xc7\x10\xaf\x48\x00\xdd\x98\x28\x2b\x75\x13\xc5\x99\x92\x1c\x9b\xad\x98\x6b\xa0\x26\x53\x36\x99\xc9\x49\x43\x88\x8b\xcb\x66\x92\x76\x36\xab\xe5\x42\x57\x31\xd1\xe9\x0a\x23\xa0\x7e\x86\x84\x30\x9c\x25\x53\x31\x08\xb0\x45\x93\x29\x1b\x8c\x24\xe7\xc4\xc2\xbf\x33\x1a\xf0\xa5\xb1\xd6\x77\x8c\x30\x8a\x47\x0a\xd0\x72\x23\x29\x85\x34\xe8\x79\x19\x39\xbe\x6a\x36\xb1\x42\x49\x33\x5b\x20\x0c\x34\x20\x0b\x2a\xd4\x1a\xfd\x40\xb4\x1d\xc9\xe6\x3f\x3e\xfc\xd4\x8d\x3d\xf4\x35\xe5\xa9\x63\x0f\xa1\xbe\xa3\x1b\x37\x72\x9b\xb6\x88\x26\x8e\x4e\x5d\x87\x5e\x08\x7c\xbe\x8b\xb4\xf2\xda\xbe\x16\xdd\x5f\xbd\xf1\xc8\xdd\x77\x5f\x73\x04\x57\xba\x9f\xd9\xc9\x54\x6b\xeb\xcb\xc2\xea\xc8\xb6\x63\xc5\x27\xb4\x85\x74\xf8\x48\x29\xa3\x07\x66\x88\x8f\x0e\x70\x89\x64\x45\x53\x13\xf3\xdc\xbc\xd5\xc5\x00\x77\x18\xc8\xab\x72\x8c\x2c\x26\xe6\x83\xc5\xe4\xe7\x2c\x26\xc6\x56\x64\x4a\x0d\x6e\xc4\x8a\x97\xc4\xc9\x71\x0f\x12\x1f\x86\x12\x7e\x78\x33\xc1\x8e\x2b\x0d\x91\x2c\xf1\x83\xb3\x56\x37\xc7\x25\x22\x69\x16\x5e\x12\x97\x48\xba\x5a\xd5\x3d\x22\x5e\x74\x9c\x2c\xfa\x7f\x65\x6e\xda\x94\x5a\xd6\x1e\xd0\xc5\x06\x5b\x4c\x0d\xec\xbf\xa8\xcd\xc6\xaa\x28\x76\x45\x49\x1b\x70\x19\xf2\x01\x7f\x5c\xc9\x48\xe4\xf3\xe8\x01\xd1\xda\x4a\x7f\xeb\x50\x83\x3f\x97\x2f\x35\x68\x7d\x5a\xc6\xf4\xf0\x8e\xf4\xbe\xbc\xc6\xe5\xf6\xea\x02\xd1\xb0\x5f\x6e\x55\xd5\xe4\xe0\x8f\xe2\xa3\x54\x91\x6a\xa7\x16\x82\xee\xbf\x4e\x71\x0b\x93\x5c\x6f\xb6\x32\x28\xc8\x41\x4f\xa6\xbc\x70\x10\xaf\x7b\xe1\x00\x50\x6b\x70\x21\xbe\x1c\xec\x02\x0b\x58\xa8\x07\x31\x38\xd6\x35\x66\x2b\x56\xe1\x85\x3b\x59\x09\xd5\x48\x39\x8c\xed\x63\x25\x23\xc8\x85\x03\x3c\x41\x25\x26\x5c\x67\x74\xfc\x00\x08\xcd\xa2\x4c\xa5\x5f\xb8\xd1\x9d\x29\xf7\x0f\xe0\x6f\xee\xef\x85\x41\x06\xfa\xf1\xe5\x40\x07\xd0\x79\x31\x3e\xf0\x86\x1d\x71\xb2\xc8\x0f\x64\xe0\x79\x10\x77\x3d\xe5\x4b\x5d\xf5\xac\x20\x37\x44\x6a\xe2\xb1\x7b\x06\x66\x64\x84\x8e\xbe\x49\x8c\x8a\xcb\x26\x5f\x8c\x9c\x7f\x66\xcf\xe5\x98\x51\xed\xe5\xfc\x4e\x5a\xd3\x69\x89\xb3\x04\xf0\x4a\xad\x52\x2a\x32\x3a\x43\xa6\x86\xd6\x44\x5e\x2c\xd3\x3a\x2c\x06\x97\x3d\x16\x8c\x06\xfc\x7d\xe1\xf5\xd9\xab\x16\x66\x56\x76\x85\x94\x46\x87\x2e\xd6\xda\x38\xb4\xb1\x79\xe8\xcb\x0b\x09\xdf\xee\xa8\x0b\x2b\x73\xe5\x51\xb5\x4b\x23\x37\xb1\x2a\xb7\xdf\xeb\x41\x0c\x7d\xb7\x4c\xe2\xd1\x5b\xa2\x0d\xa9\xad\x1d\x9d\x9e\xfc\x40\x83\xce\xef\xb1\x4b\xcd\x83\xb1\xa6\xe1\x82\xbb\x6b\xf2\x85\xb3\x44\x7a\x4e\x3f\x90\x0e\x9c\x09\x23\xbd\x9f\xec\x12\xa1\xf6\x85\x2b\x26\x6b\xbd\x41\x10\xd7\x39\x5d\x2a\x62\x12\x2a\xb6\xd5\xc4\x03\x8f\x9b\xd4\x39\x4d\xbc\x12\x13\x5a\x84\xc4\x92\xb5\x66\x21\x7c\x57\xad\x93\x0e\x27\x2e\xf2\x0a\x13\xd9\x11\x04\x3b\x5e\x31\xd8\x43\xa4\x5f\x88\x70\xae\xb8\x4c\x79\xbc\xc5\x59\x6e\xb9\x1d\xe4\x55\x90\xdd\x59\x25\xeb\x4c\x7d\xbf\x62\x76\x31\x50\x13\xda\x1f\x6e\x1b\x0a\xce\xe9\x0c\xd2\x1a\x08\xf5\x77\x95\xec\xf7\x06\xd7\xee\x3c\xd8\x75\xf1\x2d\x9b\xf2\xef\xe0\xde\x20\x1e\xa1\x3c\xd4\xe3\x68\xb6\x58\xac\x68\x6c\xc1\xd6\x91\x76\xa7\x3e\xdc\x98\x76\xed\xdb\x17\x1f\xe8\x5f\x9c\xe9\xd8\x9a\xc6\xcd\x41\x9c\xb9\xc1\xc4\x6d\x05\xd2\x41\xe4\x18\xf3\x0b\x7c\xf4\xdc\x1c\x4e\x3b\x5d\xd9\xb0\xc5\x64\xb4\xa7\xb0\x4c\xe3\x3e\x17\x92\x63\x94\x94\x92\x51\x2a\x70\xcc\x2d\x33\xbd\x2e\x64\xf5\x93\x6a\x15\x89\x7a\xa6\xe1\x85\x6e\xba\xe1\x05\x4b\x82\x41\x35\x29\x08\x9a\x69\x78\x11\x40\x05\xb1\x14\xcd\xee\x7a\xf1\x21\x32\xef\x45\xad\x2d\xd5\x3f\xcc\xea\x7e\x21\x7e\xe6\xd5\xf7\x2f\x9d\x7c\x0c\x3d\x4c\xfd\xdf\x99\x03\xee\x4e\x39\x77\x0e\x39\x54\xdc\x57\xbd\x55\x36\x7b\x0e\x0f\xbc\xff\xea\xd1\xb9\x73\xd8\x4a\xe6\xa0\xa5\xf4\xf5\x6e\x07\xf3\xe6\xa0\x9b\x99\x83\x61\x7a\x0e\xb8\xef\x03\xd9\x25\xc6\xc6\x0c\xe9\x48\x43\xa5\x59\x73\x01\x3f\x2b\x96\x46\xa4\x73\xa7\xf3\x12\x62\x3b\x11\x3d\xf2\xd6\xfb\xdb\x67\x4f\xe8\xf8\x3b\xbf\x5a\x7b\xec\xe8\x64\x19\x4f\x69\x7a\x4e\x37\x92\x39\x45\xa9\x46\x6a\xfd\x39\xe7\x14\xab\xcf\x09\x6f\xb7\x2b\xc5\x13\xe3\x06\x65\x58\x16\xe7\xdd\x64\xb7\x83\xb4\x17\xaa\xcd\xb3\x69\xce\x3c\x63\xa4\x49\x0b\x6f\xc0\xee\x59\x6e\x2b\xce\x99\x31\xee\x42\x5e\xcb\x54\xce\xdd\x24\x9c\xbb\x88\x93\x87\x6f\x8c\x0f\xb8\x64\x7a\x93\x45\xa5\x75\x3a\x1c\x9a\xcb\x7c\x85\x4c\xda\x19\xee\x71\xc9\x2d\x0e\xb7\xd6\x93\xf2\x77\xcd\x5e\xdc\x93\xaf\xc5\x9c\x32\x83\x5e\x65\xf4\xc6\x2c\x47\x62\x5d\x71\x8b\xd7\x26\xb3\xdb\xf5\x0b\x7a\x26\xef\x26\xeb\x15\xd7\xd6\x7b\x84\xac\xd7\x49\x4e\xfb\x1e\x3f\xe7\x8a\x5d\xd3\x2b\xb6\x26\xb9\x64\xb6\xa2\x11\x52\x87\xa1\x0c\x71\x49\xf2\xd3\x15\x03\xc9\x12\x8e\x4b\x0d\x72\x20\x04\xa5\x25\xb8\x05\x28\xc0\x19\xc8\x16\x1d\xd6\x6a\x9c\x44\xc4\x8e\xc9\x20\x85\xe0\x0b\x49\x34\x56\x97\xd0\xda\x8d\xf3\x80\x8b\xd2\x8f\xd3\x22\xb1\x9b\xa8\x33\xc2\xad\x54\x3c\x73\x88\x33\xbf\x0d\xb1\x8f\x99\x7f\x6b\x16\x89\x1e\x32\x87\x73\x2e\x4f\x3e\x62\xb2\x44\xf2\x2e\x57\x2e\x6c\xfe\x25\x90\x24\x81\x6f\x7a\x73\x21\x23\x7e\xc6\x37\xa7\x69\xf4\x19\xce\x46\x5a\x42\x29\x5b\xbd\x79\xb0\x02\x3d\x4c\xef\xc0\x29\x49\x4b\x38\x65\xc5\x37\x8d\xa4\x61\x30\x53\xa3\xd5\x61\xc0\xa0\x2e\x90\x8d\x2b\x6b\x74\x32\x67\x01\x72\xf0\x0e\xa0\x4c\x24\x59\x51\xd6\x32\x29\xb1\x7a\x5b\x15\xdc\xaa\x5c\x82\x93\xa8\x42\x1a\xc5\x4d\x8e\x14\xd5\x61\x2a\x2e\x6e\x75\x4b\xc0\x78\x21\x9b\x03\xc7\x16\x41\x96\x77\x29\xe1\x59\x07\xde\xc1\xea\x24\xc0\x35\xe2\x60\xf5\x8f\x4b\x74\x26\xe4\xf2\x11\x17\x9d\x46\xf3\x3a\xac\xd5\x3a\xde\x28\x51\x2d\x03\x80\x7d\x06\x7a\xc0\x9d\x09\x19\xfd\xc5\xe1\x78\xe3\x48\x29\x60\x0a\x66\x5c\xe8\x95\xe9\x66\x38\xfd\x61\xa7\x23\x1c\x76\x38\xc3\xa2\x3f\x2a\xc3\x99\x36\x1f\x6e\xc4\xe8\x6d\x19\x8c\x79\x4b\x99\xb0\xf2\x73\x55\xad\x4f\xce\x7d\x74\xda\xdb\xd8\xe8\xf5\x36\x35\x91\xfd\x81\x33\x93\x40\x80\x4f\x48\x5f\x16\x3d\x75\x79\xed\x84\x27\x95\x9d\xdb\x10\x45\xa3\x53\x61\x21\xd1\x88\x70\x9f\x12\xd5\x74\x6f\x14\x41\x6b\xb5\x6a\xd2\xe6\x1e\x8c\x07\xa7\xca\x90\x26\xca\xa2\x4c\x59\xc6\x92\xfe\x07\x34\xee\x5a\x22\xc3\x5d\x4b\x8c\xa4\xb7\x0e\x2b\xe0\x73\x8a\x17\x89\x6b\x9a\x1d\x40\x33\x8d\x53\x20\x54\x61\x0c\x59\x56\x04\xb0\xf5\x40\xf5\x59\xa4\xad\xfe\x3b\xea\x98\xfa\xc3\x63\xab\x6f\x39\x8c\x5b\x9b\xbc\x88\xfb\xa8\xa0\xfe\xea\xd3\x34\x8d\x6a\xfd\x32\x4a\x10\x3b\xe0\x1e\x38\xbd\xb8\x56\xad\xde\xfa\x06\x67\x39\x5b\x04\x4c\xd0\x91\xac\x78\x14\x38\x44\x41\x5c\xdf\x74\x3b\x1c\xdc\xd0\xdc\x4e\xd5\x6a\x17\x5a\x92\xe4\x82\xeb\x60\xf1\x8e\xaf\x47\x3f\x1e\x8e\x64\xbb\xb0\xf4\x9a\xd8\x2f\xdc\x2d\x47\x8b\x66\x0e\x51\xcc\x0e\x3b\x9a\x98\x0b\xf6\xd0\xe9\xf8\xc1\x46\x51\x3d\x04\xe9\x98\x15\x99\x98\x36\x7c\xef\x40\xf7\x05\x3a\xeb\xec\xb8\x9a\xf5\xd7\x23\x95\xec\x74\xf4\x72\xb7\xf6\x92\x1f\xfc\x0e\xcb\x34\xe9\x71\x03\x7e\x40\x09\x5e\x40\x47\x8d\xcd\xea\x73\xa3\x3a\x67\xe3\x19\xcc\x50\xf6\x42\xcd\x6e\xf0\x09\x08\x5c\xbf\x8e\x1b\xa0\xcc\x6d\x7a\xe3\x33\x80\xa7\x9a\xd5\xf9\x66\xf2\xa5\xef\x63\x3f\x35\xdd\x00\x87\xf8\xa8\xb3\xe7\x35\xfc\xdf\x36\xaf\xb3\xe6\x03\x5e\x6b\xce\x7c\x7e\x43\x7c\xd6\xcc\x84\xb0\xc3\x9a\x9e\xcf\x56\x32\x1f\x03\xb5\xe2\x0b\xcd\xc7\x78\xa1\xf9\x98\x6a\x74\xe2\xd5\x86\xe2\xd9\x94\x12\x7c\xd8\x9c\xc9\x6d\xae\xbb\xb0\x99\xf9\x09\xfe\x8b\xf8\x2e\x61\x8e\x47\xc8\x1c\xbd\x54\x8e\xfa\xca\x17\x98\x25\xee\x2b\x91\xca\x56\xf4\x82\x39\x0f\x83\x39\xcf\x9f\x77\xd6\x1c\xa5\xe3\xd4\x18\x27\x5b\x84\xfd\x21\x39\x29\xc3\xae\xc4\x85\x57\x92\x0c\xdf\x8c\xd7\xa3\xc6\x3d\x0f\x9d\xe7\x58\xcf\x05\x76\x8e\xe6\x2c\xb4\x7d\xbe\x0d\x47\x87\xe6\x1b\xf0\x19\x12\xcc\xb7\xe0\x8e\xb3\x8c\x37\x23\xf4\xcc\x99\x96\xa7\xc1\xb9\x7d\x73\x08\x71\xe6\x34\xcf\x61\x2f\xdc\x3c\x47\x7f\x56\xf3\x1c\x22\xdc\xf5\x0e\x3a\x53\xbe\xaf\x60\xc9\xae\x37\xd2\x11\x04\xfb\xff\xaf\x79\x80\x50\xcf\xcc\xe3\x59\x22\xd1\xd3\x13\x21\x02\x4d\xcd\xd0\xa4\x2e\xd3\x17\x5d\x68\x2e\xc6\x0b\xcf\x85\x08\x34\x0d\x0e\x4d\xa3\xd5\x17\x67\x1f\x14\xaa\xcf\x8b\x88\xf4\xcc\xd4\x12\x75\x79\x9e\x9e\xdd\xb4\x38\x83\x3c\x0b\xf3\x9b\x91\xe7\xdb\xfe\xfa\x0c\xcf\x29\xca\x17\x98\xf1\xb8\x45\x4e\xcb\xe2\xb8\xd1\x0a\x16\x61\x75\xb2\x26\xda\xe3\x3e\x72\x5b\x90\x6c\x22\xd6\x74\x5d\xac\xf9\xb8\x1c\xae\xc2\xa9\x73\xac\xee\x02\x02\x3e\xb3\x6c\xe3\x85\xa5\x7b\x9a\x20\x17\x14\x6e\x9a\x52\xd4\x7a\x01\x18\x28\x3f\x3e\x75\x43\xce\x51\x18\xc5\x13\x42\x07\x00\xb7\x6c\xa2\x82\x28\x56\xa4\x8e\x73\xbe\x2c\xde\x54\xe2\x3c\x42\x61\xb6\x9e\x24\xeb\x8d\x6a\x7c\x50\xb4\x6c\xd4\x93\x44\x88\x0f\xc2\x5b\x3d\x49\x8f\xe8\xf1\x29\x30\xa3\xd0\xe7\x04\x9f\xb3\x08\xd6\x77\xa1\x78\x55\xbd\xe0\x71\x4e\x93\x35\x1f\x6b\x98\x6e\xb3\x86\x83\x52\xc5\xd2\x39\xbd\xd6\xaa\xbf\x7c\xb7\xde\x6d\xed\xa7\x3f\xa5\x7b\x9f\x41\xb3\x5b\xae\xd1\xbd\xd5\xcb\x84\xae\x6b\xd5\x17\x9f\xc1\xe7\x2a\x71\x5f\x21\xc0\xe0\x1a\x40\x1b\x29\xea\xeb\x33\x75\xb4\xda\xba\x11\xe3\x44\x59\x00\xd9\x78\x03\x60\xdc\xae\x4f\x00\xe0\x0c\x01\xf2\x4e\x65\xea\x3d\xca\xce\xd1\x74\x08\x9f\x07\xd3\x50\x64\x23\x92\x63\xd8\xc7\x69\x95\xde\x1e\x12\x5a\x28\xea\x79\x1c\x39\xe2\xd6\x2d\x73\xba\x10\xf1\x89\x90\xf0\x69\x3b\x8b\xab\x16\xf5\x02\x24\x9d\xd7\x99\xe8\xaf\xc0\xf6\xd9\x4d\x8b\x7e\xb1\xf7\x42\xa8\xfd\xac\xb6\x46\xe7\x87\xee\x82\x6e\x90\x9e\x47\x60\x47\x28\xca\x4c\xc5\xa8\x26\x6a\x49\xad\x2b\xbc\x53\x21\x54\xd6\x92\x6a\x39\x3e\xac\x98\x3e\xd7\x6e\xd1\x92\xd6\xf0\xa4\x66\x5d\x2b\x1c\x68\xf7\xe1\xd6\xf0\x12\x7d\x3c\x41\x60\x77\xd8\x09\xaf\xcc\x48\x19\x23\x58\x26\xcb\x5e\xa0\x07\x12\xb6\x75\x5f\xa4\x0f\x92\x04\x5b\xc1\x2f\xd0\x0c\x89\xfe\x11\xf1\xfc\xe7\x5a\xdb\x8a\xff\xcd\xb5\x55\x60\x6d\x8d\x4d\x42\x9f\x4c\x2e\xf1\xbf\xb1\x44\x30\xa3\x5f\x64\x89\xbd\xc4\xc0\x7e\x91\x35\xde\x56\xb3\xbd\xf5\x35\x6e\x25\x6b\x74\x51\x69\x6a\x6d\x6d\x8d\x81\x39\x6b\x4c\xe0\x35\x66\xc8\x1a\xdd\xc2\xe1\xd2\x86\xda\x1a\xb3\x38\x74\x40\xc2\x61\x89\x06\xb6\x22\xb1\xda\x1c\x7a\x41\x9c\x39\x3b\xac\x34\x11\x20\x2b\x4d\x2b\xcf\xbd\xd2\x9a\x21\x66\x2e\xdc\xd7\xea\xc9\xba\x85\x66\xbf\x40\x83\x2b\xe6\x5b\xc4\x7a\x4f\xad\x98\xdf\x6b\xa9\xbe\xde\x1b\xc9\x7a\x0b\xd4\x10\xf5\xe5\xda\x7a\xdb\xe7\xac\x77\x40\x31\x01\xe1\x24\x6f\x03\xbd\xf6\xd9\x72\xa0\xd7\x8d\xa0\xd7\x85\x0c\xc9\xd5\x01\x0d\x5a\x80\x06\x2d\x3a\xb2\xd9\x8c\x69\x80\xb3\x6f\x2d\x35\x1a\xf4\x00\x0d\x6c\xbe\xc6\x1a\x0d\xf8\x70\x04\x87\x0f\x03\xed\x84\x0a\x43\x98\x0a\xa4\x05\x21\x6f\x89\x14\xcf\x49\x8f\xf3\xaa\xf1\x17\x20\xd1\x2d\x17\x52\xee\xc4\x17\x21\xdd\x3f\x9c\x4f\xdf\xa7\x4a\x67\xb5\x0d\x83\xb8\x5d\xa0\xe7\x91\x9a\x8e\x74\x50\xcb\xa8\x5b\x6a\x14\x4d\xcd\xa1\x68\xab\x02\xe7\x28\xb8\x91\x6c\xc5\x29\xf8\xc5\xde\x0c\xf9\x51\x1b\xa0\x66\x5c\x3b\x31\x6e\x89\x23\xf0\x73\x3e\xc1\xfd\xc5\x75\x24\x3e\x07\xd2\x8e\x0f\x2a\xf3\x70\xbf\x53\xb8\xdf\x99\xac\x0c\x0a\x9e\x10\xff\xca\x4d\xa7\x8f\x58\x8d\x54\x2b\xb1\x1a\xf8\x47\x6d\xb0\x4a\xe1\x13\x4e\xbc\x33\x0c\x24\x8e\x2d\x3b\x37\x89\xe7\xc7\xf0\x17\xf8\x19\xa1\x73\x11\x7a\xbe\xdb\xdc\x30\x9f\xb0\xc8\x36\xdf\x8f\x9e\x83\xd4\x22\xd5\xfc\x88\xff\xb1\xf9\x7a\xfa\xfb\xb3\xc3\x7f\x88\x23\x6f\x41\x3e\xe6\x56\x51\x3b\xe0\x11\xca\x80\xeb\x10\x0b\x16\x5c\x8e\x20\xbd\xe5\xa3\x8f\xee\x9a\xf8\xdd\xbd\xff\xf1\x87\x13\x1f\xfd\x1e\x3d\xfd\xe7\xc9\xdb\xfe\xf3\x3f\x6e\xae\x4e\xde\x39\xf9\x47\x8c\xb1\x02\x67\x0e\x30\xbf\x15\x5f\x49\x7a\x37\xe4\xa8\xab\x84\x0e\x2c\x7c\x63\xbd\x3b\x5d\x10\x2e\x14\xa4\x4b\x1f\x81\xdd\xb8\xf3\x48\x4d\xd1\xd3\xd8\x61\x69\xf1\x31\x2a\x82\x3f\x48\xdf\x15\x9c\x25\xe0\xd2\xec\xe3\x32\xb1\xd5\xe4\xc7\xfd\x90\xf1\x4e\x96\x5c\x89\x45\xbd\x11\x9f\x81\xb4\x3a\x48\x12\xa1\xa2\xa4\x34\xbe\x1c\x7e\x5b\xac\xaf\x35\xc6\x17\x0a\x4e\x6b\x25\x93\x98\x21\xe1\x88\x34\x52\x68\x42\xb8\x98\x18\x85\xe7\xfc\xd8\x47\x38\x42\x48\x5f\xdc\x95\x1e\x79\xe6\xb2\x74\x51\x20\x7f\x69\x5b\x72\xac\xb2\xbf\xd4\xf6\x07\x95\x1c\x8d\x64\x5b\x31\xad\xbf\x66\x69\x76\x61\xda\x4b\x25\x02\x8d\x3d\xae\x3b\x36\xfe\xe3\xb2\x7f\xbd\x4d\xa0\xb3\xcb\xfa\x9d\xf5\x6f\xae\xfe\xe3\xb7\xba\xf7\xa6\xe8\x2b\x13\x40\xd3\xa9\x17\x0c\x7a\x4c\xe2\xcc\xaa\x30\xa6\x0b\xe9\x9f\x45\x6c\xbc\x9f\x0a\xe3\xb8\xd3\x8d\xe9\xc2\xd6\x7a\xe6\x08\x3d\xd8\xc4\x16\xdc\x48\x2b\x42\x84\x15\x63\x10\x89\x96\xb4\x30\x34\xe3\x1e\x1f\xe0\xd2\xb1\x29\x54\x21\xa1\x77\x89\x84\xe5\x18\x5c\x56\x5a\x61\xdd\xc1\x50\x18\x4b\x26\x88\xa0\x0d\xfd\x95\x9e\x5a\xd8\x7f\x9d\xb7\xaf\xd6\xdf\x63\xa7\x75\xc1\xe6\x5a\xa2\x1d\x02\xa6\xff\x6f\x5a\x8b\x44\x45\x4e\x04\x73\x66\x16\x56\x11\x08\xe2\x55\x70\x36\xbc\x79\x7f\xc1\xb5\xe0\xd4\xeb\xf9\x7b\x84\xc9\x88\x7b\xba\xf0\x6a\x16\x0b\xce\xa9\xbe\x9e\xad\x64\x3d\x51\x9c\x01\x3d\xef\x7a\x62\xe7\x5b\x4f\xbc\xc6\x1b\x3e\x10\x2d\xce\xe3\x4e\x03\x59\x17\x2b\x98\xe8\x0b\x72\x49\x70\x54\xe7\x5d\xdc\xad\x75\xf7\x74\xe1\xe5\x35\xd7\x22\x0b\x51\x6d\x7d\x47\xc8\xfa\x9a\xa9\x45\x38\xe3\x79\x9e\x15\x62\xdf\xdb\x9f\xad\x34\x08\xa6\xb3\x0d\x4c\xe7\xd0\x9c\x15\x07\x70\x34\x9c\x10\xac\xe4\xcc\xea\x39\x9b\x8e\xeb\xc6\xef\x14\x84\x77\x0a\xc9\x4a\xb7\x60\x3f\x87\x67\xd8\xcc\x17\x12\x40\x1e\x37\x69\x3d\xd9\x80\xb7\x8e\x16\x15\x2f\x48\x8c\x0b\x04\x18\xe7\xa5\xd2\x95\x17\x8e\x37\x2e\x4c\xbf\x1f\x5e\x30\xca\xc6\xb2\x43\xfa\x9e\x11\x5d\x90\x53\x6a\x7c\xde\x8b\xe4\x90\xa9\x59\xc0\x9d\xfc\xc8\x8a\x4c\x48\x8f\xe3\x1f\x52\x91\xca\x6a\x47\xf9\x6b\x9d\xbc\x99\x1a\xcc\x16\x7a\xa0\xe1\xdf\xbc\x9a\xe9\x83\xb6\xb0\x96\x9c\x99\xe9\x86\xc6\x3c\x8c\xa5\x76\xa6\x8f\xa6\x85\x0a\xe2\x1e\x12\xd3\x03\x56\xcc\x42\x0f\x5f\x33\x33\x51\x51\x04\x85\x76\xbe\x18\x54\x85\x84\xa6\xde\x30\x07\xb9\x35\x23\x34\xf4\xb5\x90\x8a\x36\x7c\x5a\x95\x0f\xe3\x4e\x78\x96\x5a\x91\x75\xd0\x5a\xab\x5f\x9c\x6e\x0d\x6b\xca\x9e\xbb\xc9\xa6\xd0\x25\xf6\xa5\xb3\x3b\x6d\x3e\x3f\xdd\x2a\xf6\x44\xbd\xe3\x66\xf5\x2d\xf4\x21\xee\xb8\x19\x5c\x90\xf3\x90\x9e\x4d\xbf\x61\x4e\x89\xb7\x52\xed\xb8\x2e\x93\xcc\x9e\x1c\xaa\xf5\x32\xe4\xe0\x1a\x81\x41\x49\x7c\x2a\x95\x1c\xbc\x82\x99\xb7\x83\x98\xb5\xeb\xf0\xa9\x23\xfc\x6b\x05\x9c\x49\xc7\x29\x71\x2d\x4b\x06\xae\x33\x49\x5e\xa9\x16\x1a\xeb\x67\x00\x00\x55\xec\x12\x6f\x9c\xa4\xda\x43\xb8\x45\x15\xb8\x0a\x3b\xae\xda\x74\x83\x5e\x16\x70\xb7\xae\xb9\xbe\x7a\xd6\xaf\xf5\x44\x0a\xe6\x73\x34\x29\x17\xce\x6d\x8f\xe4\xb7\xde\x79\xc9\xaa\x6f\x6e\x29\x98\xc3\x59\x67\x76\xac\xd5\x9b\xd9\x7c\xc7\xa6\xe2\x96\x96\x03\xb9\xe6\x60\x7b\xc2\xee\xed\x5c\xdf\xb9\xf5\x80\xaf\x10\x35\x9b\x00\xca\x40\xa4\x67\x64\x56\x5c\xfb\xb3\x63\x03\x3d\x7b\x6e\x1e\x6c\x18\x5e\x50\xd0\x9b\xfa\xd6\x5e\xde\xb5\xf6\xee\xdd\x25\x9f\xa7\x92\x76\xe5\x17\x36\xb6\x6e\xea\x8f\x9c\xb2\xa4\x87\xf3\xc1\xde\x9c\x37\xb3\xfa\xf0\xd0\xe4\x49\x82\x93\x49\xff\x32\x31\x2e\x52\x77\x03\x4a\xce\xe3\x7d\x45\xf3\x34\x75\x82\xe2\x9a\xc2\xe2\xc3\x8f\xbc\x42\x3c\x51\x91\x24\xec\xda\xfa\x6e\x51\x33\x51\x55\x8f\x12\x22\x5e\x41\x35\xa5\x8d\xf8\xb0\x1a\x90\xa6\x80\x7b\x21\x61\xeb\xa4\x22\x87\x11\xd8\x53\x0a\xad\x3d\x98\xc9\xe5\x09\xa2\x91\x60\xf2\x58\xd2\xa4\x45\x12\x3e\xbe\xae\xd5\x93\xdf\xf5\x21\x8d\x83\xbe\x48\x37\xb3\x30\x8e\x8d\x0c\xd2\x2f\xd8\xce\x6c\xf5\x15\x3d\xb6\xe4\xc9\x87\x0e\x7c\x81\x7e\x66\xb4\xad\xb1\x28\x72\x5f\x5e\xe5\x16\x9c\x83\x2e\x87\xff\x6f\xd0\xe5\x71\x42\x17\xd2\x33\xcb\xa4\xe7\x72\xff\x3d\xc4\x71\x20\x0b\xf3\x5f\x20\xce\xe6\xef\x9f\x7c\xeb\x0b\x12\x87\xe9\xaa\xd7\x84\xd5\xe9\x73\x82\xd0\x27\x44\xb5\xe0\x5c\xe8\x0c\x7d\xe2\x67\xd3\x27\x37\x43\x9f\x22\xa1\x4f\xed\x78\x19\xa1\x4f\xb6\x46\x9f\x56\xdc\x8e\x09\xe8\x53\x56\xa9\x3d\xc5\x69\xc9\xf1\xfa\x02\xf1\x1a\x89\xfc\x75\x12\xb9\x2d\xff\x15\x12\xe1\x13\xc8\xb3\xc2\xb1\x3a\xa5\xce\x4f\xa5\xa7\x7f\xdf\xf3\xe1\xc1\x6f\x3f\x54\x9c\x4f\xac\x73\x13\x8a\x79\x08\x45\xab\x6f\xae\x7a\x7c\x7c\xf2\x93\xf9\x24\x9b\x45\xab\x5b\x08\xad\x3a\x21\x92\xf8\xdb\xd9\xb4\xea\xab\xd3\x2a\x8a\x9d\x22\x6e\x61\xd5\x99\x19\x6f\x8b\xe2\xe0\xcc\x07\x6f\x25\xe9\x39\x64\x1c\x99\x21\xa3\x10\x64\x74\x01\x19\xbb\x6a\x64\x5c\x2c\x90\x91\x4b\x66\x48\x20\xd1\x75\x16\x25\x7d\xd1\x5c\x5f\x8d\x92\x4d\x40\xc9\x11\x33\xc4\x16\x6e\x64\x59\x86\x63\x0b\x85\x44\xe8\x26\xa1\xc5\x3f\xb3\xc5\x47\x73\xb5\x3d\xc2\xbf\x46\xd6\x0b\x47\x75\x17\xa6\xf4\x65\x87\x6f\x6c\x1c\x70\x49\x0d\xc6\x5a\x70\xb7\x1f\x82\xbb\x8c\x23\xd2\xed\x92\x5b\x85\xe0\xce\xfe\x05\x79\xf0\xf9\xcf\xa3\x4e\x99\x11\xe2\x3b\x5f\xcc\x7c\x24\xda\xd5\x68\xf1\x59\x6b\x5b\xb1\xdc\xd9\x4c\x11\xd7\x78\xb2\x93\xf0\x24\x43\xf5\x51\x17\x53\xa7\x66\x73\xa5\xe5\x6c\x09\xee\xae\x93\x1e\xd7\x37\x5e\x94\xad\x04\x05\xd0\x32\x04\xa0\x65\x35\x6e\xc3\x50\x89\x0a\xa9\xcd\x6c\xd4\x03\xbc\x43\xc0\x17\x94\xe4\xb3\xf0\x14\xad\xb1\xa7\xab\xc6\x1e\xf0\x25\x4b\x31\x7a\xe9\x17\xd0\x4b\x7f\xb2\xb2\x54\x40\x2f\x6b\x70\xcf\x7f\xdc\xad\x41\x65\x6f\xc1\x4c\xeb\x67\x79\x05\x69\x1b\xd3\x5d\x63\x54\xdf\x59\x8c\xba\x00\x83\xce\x13\x13\xd6\xd9\x32\x3f\x26\x3c\x3f\x9b\x8e\xcc\x3f\x76\xb2\x65\x3e\x5b\x90\x69\xfe\x39\x94\x73\x33\x4a\xe4\x99\x77\x3a\x65\xb2\xeb\x2c\x3b\xf3\xdc\xfc\x03\x2b\x75\x7e\x71\xd3\xfc\x1a\xc5\xfd\xe0\xbe\x30\xbf\x70\x35\x13\xde\x89\x5c\x92\xac\x04\x6b\x3b\xc8\xcb\x88\xfa\x00\x7f\xc6\x3d\x59\x1c\xa3\xf7\x0b\x1b\xc8\xd9\xb9\xcc\x1a\x8f\x9a\xcc\xf0\xe6\xb0\xf0\xe6\x70\xb2\x12\x15\xea\xf1\x97\xe3\x86\x71\x1e\xa1\xbf\xe1\x30\x5b\xd1\x2a\x9a\x5a\x82\xc4\xbb\x9d\x9f\x55\xfc\x92\x41\x78\xcb\x13\x1d\x15\x7e\x1b\xf2\xff\x84\x6f\x86\x59\x7b\xd1\xe7\xe7\xd9\xaf\xfc\xc5\xc5\x78\x83\xda\xef\x2f\x8d\x34\xc6\x17\x17\xfd\x8a\xf9\x3c\x3b\x1e\x76\x3a\xc3\xf8\xef\x7c\xac\xaa\xef\x5d\xc7\x16\xe1\xe7\x45\x93\x4b\xce\x62\xd5\x4f\xbd\xf1\xb8\xb0\x8b\xcd\x50\xa2\x33\xef\x8b\x28\xe6\x97\xe0\x0d\xfa\xc1\xca\x3d\x21\xfc\xde\x05\x97\xcb\xf2\x61\x60\x42\x47\x46\x68\xa1\x60\xcb\xf2\x32\x78\x39\x92\xa9\x88\x7b\x1a\x81\x43\x9c\x37\x8b\x2b\xf4\xb9\x81\x0c\x27\xd6\xe1\x5f\xf0\xa9\xff\x26\x70\x51\x35\xc1\x15\x75\xb8\x9d\x36\x27\xce\x54\x7c\x42\x45\x1e\x7c\xca\xa7\xe3\x17\x0a\x1b\xfe\xde\x5a\xc6\xa4\x38\xdd\x33\xb5\x9b\x2d\xcb\xb4\x39\xac\x3b\x3e\x3d\x6f\x4c\xc2\xf3\x42\xb6\x6c\x13\x0a\x8b\xdd\x7a\xae\x01\x18\xd4\x83\x73\x28\x54\x43\xb1\xc8\x7b\x1a\x49\x61\x19\x27\x23\x3d\x55\xb5\xe0\x95\x8d\xd3\x05\x4e\x73\x4a\xc3\x2c\xc2\x11\x73\x17\x12\x0b\xdb\xcd\xc2\xc1\xa3\xf0\xdc\x9f\x0c\xc6\xcd\x47\xd0\xf4\x8f\x86\x89\x5a\x77\xdf\x7b\x49\x67\x4b\x78\x38\x7c\x59\xee\x96\x51\x4f\x57\x29\xc3\xea\xe2\x99\x82\x6b\x68\x6f\xbf\xbf\xba\xd3\x1c\x6b\x0b\x8f\x76\xec\x6f\x3e\xb6\x78\xe0\x50\x4c\x9f\x29\x75\xfb\x7a\xf7\x0c\xc7\x5e\xd6\x39\x83\xc6\x9e\x42\xc7\x58\xce\x82\x4e\xbc\xa3\x76\x44\x6c\xae\xb8\x5b\x8b\x64\x83\x5f\x5a\x95\x63\x36\xef\xcd\x76\x7c\xb3\xb7\x1b\x9f\x4b\xb3\xc6\x3d\x86\xb6\xbd\xdf\xba\x64\x0b\x3b\x98\x19\x2d\x79\x77\xdc\xdc\xdd\xb7\xa0\x15\x9f\x8e\x4b\x8d\x6e\x6f\x31\x45\xbd\xc6\x35\x6b\x36\x31\xce\xc6\x56\x54\x90\x28\x1b\xfa\xd2\x4e\x5f\xa1\xd6\x33\x79\xa4\x7a\x0d\xe9\x5b\xda\x4b\x6d\xa4\xa6\xdb\x95\xce\xdd\xa7\x77\x29\x28\xd5\xcc\x3e\x3d\x6e\x61\x8a\xf7\xe9\xad\xe7\xde\xa7\x77\xe9\xc7\x03\xb5\x7d\xfa\xff\x6a\x6f\xd3\xf3\x6f\xd6\x5f\xb0\xe3\x69\xdb\x2d\x23\xe7\xde\xac\x5f\x77\xdf\xde\xf6\x0b\xf4\x41\xed\x5b\xac\x69\x38\x7b\xb3\xfe\x5e\xc5\xf2\xeb\x7f\x44\xe2\xd6\x77\x99\x87\x6b\x98\x2f\x4a\x25\xa8\x6b\x6a\x9d\x77\x8c\x92\x7a\xc6\x0f\xd3\x2c\x24\x9d\xa8\x78\xb4\x76\x89\x3a\x2e\x48\x6b\x13\x31\x24\x5a\x0c\xf7\x32\xb8\x02\x03\x1f\x98\x57\xd6\x7e\x48\xd2\xab\x65\xf5\xa7\x24\x46\x7b\x34\xd6\x98\x10\xf2\xe4\x65\x8d\x45\xa8\x98\x36\xda\x85\xbe\xb6\x5a\x56\x00\x33\x1e\x3d\xf8\x8c\x22\x09\x22\xa2\x73\x63\x86\xf3\x75\x07\xc5\x28\xf8\x0b\x76\x08\x8d\x00\x02\xbe\x50\x97\x50\xfa\x55\x02\x7d\xcf\x41\x87\x2f\xff\x37\xd2\x21\x5e\xa3\xc3\x38\xd0\xa1\x91\x58\xcc\xff\x73\x42\x60\xc4\xfb\x05\x09\xb1\x06\xd0\xee\x85\x08\x81\xfe\x50\x87\xb9\xd3\xb4\xa8\xe3\xdc\xd4\xff\xd7\xdc\xb9\xc7\xb6\x59\x5d\x01\xfc\x7e\xdf\xe7\xb7\x13\x3f\xe2\xf7\x2b\x7e\x24\xb6\xe3\xd8\xb1\x63\x3b\x71\xea\xa4\x69\x5a\xda\x24\x4d\x93\xa6\x69\x28\x08\x26\xca\x8a\xe8\xda\xae\x0c\x5a\x28\x5d\x4b\x59\xd7\x41\x91\x3a\x56\xca\xd8\xba\xc1\x18\x93\x40\x8c\x55\xd0\x3f\x26\xbf\x36\x75\xc0\x2a\x06\xab\x50\x85\xb6\x81\xa6\x75\x7f\x74\x48\x30\xb4\xa1\x76\x93\x90\x18\x02\xad\x6b\xdd\xdd\x73\xee\xf7\xd9\x89\x1f\x71\xa6\xf1\x07\x7f\x40\x92\xcf\x49\xbf\x7b\xce\xbd\xe7\xde\x73\xef\x3d\xe7\x77\xc8\xc3\x0d\x75\x11\xa3\xba\x08\x31\x5d\x84\x94\xac\x94\x8f\xa8\x8b\x10\xea\x22\x2c\xea\x02\x6e\xc9\xf4\x1c\xba\x56\xb9\xb0\x11\x34\x42\x9d\x5b\xf1\x9a\x0c\x34\x12\x68\xa8\x91\x90\xa8\x91\x98\x31\xd7\xbf\xa4\x46\x24\x3f\x77\x39\xfc\xd8\x02\x73\x71\x23\xad\x31\xb2\x82\x4e\x74\x6f\xcb\x03\x12\x50\x56\x2e\xea\x45\xf2\x9f\x46\xe9\x7a\x7c\xaa\xa1\x66\xb2\x54\x33\x69\xa6\x99\x34\x73\x9d\x36\x56\x5c\xa7\xb5\x29\x69\x19\x06\x4d\xa5\x53\x39\x2f\xb8\x45\xcc\x8d\x02\xad\xad\xa2\xd3\xfc\x7a\xf6\xd3\x7a\x71\xff\x3d\xa0\xc5\x0b\x0c\xd0\xe5\x8d\xa2\xb7\x94\x1b\x85\xf9\xa8\x68\x76\x2a\xb0\xba\xdd\x7a\xb8\xae\x20\x58\x1f\x88\x69\x2f\x6d\x64\xda\xcb\xc2\x6f\x2e\xa5\xbd\xfa\x28\x38\xc9\xd0\x6a\xcf\x81\x96\x50\xeb\x3d\xb5\x8e\xd2\xe1\xaa\x82\x3f\xad\xf5\x90\x9a\x6a\xfc\xd1\x1a\x1f\xe9\xda\x37\x24\x23\xfd\x5a\x83\x5c\x5e\x60\xc7\xcd\x53\x7b\x55\x13\x0d\xd1\xc1\x4d\x25\x63\x4f\xca\x90\x4e\xaa\x21\x12\x18\x4f\x26\x43\x04\xd0\xd2\x08\x4a\x83\x08\x22\xa5\x1b\x07\x5d\xb6\x06\x45\xea\x87\x19\xe7\x97\x7f\xbf\xc8\xbd\xf6\xce\xb5\xed\x53\x74\x4a\x39\xc3\xcf\x9c\xb9\x7a\xf5\x8c\x7c\x1d\x9b\x39\xea\xdb\xb2\xf1\x73\x69\x4b\xbe\x4d\x57\xdb\x12\x30\x79\xa9\x25\x7f\xa4\x36\x2d\xb6\x44\xca\x5a\x92\xda\x71\x12\xdb\x61\x24\x73\x4b\xb6\xa3\xa3\x45\x3b\x4c\x62\x3b\x8a\x6d\xed\x7a\x83\x78\xf6\xbd\xb0\x29\x68\x74\x52\x6b\x7c\xcc\xae\xa4\x06\xed\x16\x6d\x07\xe6\x92\x97\xb0\x4d\x60\x33\x66\xb4\x9a\xa7\xc4\xdb\x0a\x2b\x6d\x95\x3b\x25\x9e\x4a\x71\x0c\x2c\x09\xf1\xc0\xf1\x34\x00\xf3\xc1\x52\xba\x53\x98\x2a\x6c\xbb\x90\x77\xd3\x56\xba\x6d\x88\x5f\xee\xa4\xad\xb4\x61\xfa\x95\xcd\xa1\x8e\x16\xb5\x6e\x1b\xf5\x54\x39\x66\x2f\x5c\xa2\xa4\x65\xdb\x11\x2f\x3e\x66\x46\x85\x49\xc5\x36\xd8\x16\x2a\x0c\x16\x80\x68\x44\xdc\x54\xbb\xdd\x71\xcc\xe0\x01\x98\xab\x39\x55\x7b\xb7\xc4\x2c\xa1\x29\x8d\xf6\xa5\xda\xe1\xde\x8e\x6a\x28\xbf\xdd\x32\x29\xfd\x3f\x19\x49\x45\x7f\xab\x1b\xd2\x22\x93\xfb\x0d\xf9\x03\x24\x44\x86\xc9\x87\xa4\x10\xc0\x5b\x1d\x89\xb2\x9e\x51\x01\xe2\x31\x67\x4f\x70\xb9\x91\x44\x4e\x7f\xa1\xa8\xd3\x13\x5d\x34\x1f\xd6\x5f\x82\x1c\xea\xa2\xce\xe1\xa1\x3f\x25\xf5\x97\xe8\x3c\x9c\xf7\xd0\x87\x2b\xab\xfc\x1a\x9d\x1e\xf8\x35\x7a\x5d\xfc\x3c\x97\xb7\x3b\xe0\x7b\x87\x9d\xb1\x6c\x8c\xc7\x5e\xdf\x87\x74\x13\x9d\xa1\xd8\xae\x73\x98\x60\x0a\x2a\x1a\xf4\x76\xe0\xd6\xc0\xff\xe1\xb9\x13\x9e\x17\xe8\xc3\x05\x80\x13\x5b\xb6\xd0\x0e\x34\xc9\x2c\x5c\x0c\x17\xdb\x0d\x36\x27\x02\x4e\x2a\xdf\x21\xd8\x24\x4c\x10\x57\x94\x4b\x1a\x8b\x72\x8d\x99\x4d\xf3\x19\xb8\x30\xf5\x90\x2c\xd6\x57\x5e\xe4\x33\xc5\x39\x76\x7b\x14\x86\xd4\x85\x21\x9b\x72\x71\xf9\xf8\x85\x27\x85\x33\xa3\x7b\x9e\xd9\x6a\xcf\x0c\x24\x4d\xe6\xa1\x54\x79\xf4\x74\xef\xb6\x91\x4f\xa3\x73\xc1\x7f\x0c\xbf\x70\xc7\xae\xa1\x3d\x3f\xbb\x67\xdb\x4f\x0f\xae\xfd\xa8\x73\x68\x53\x32\xba\x21\xd3\x19\xc8\x6e\xe8\x89\x6d\x5c\xe1\xe3\xce\xef\x38\xf3\xd8\xbc\xd6\xe4\xee\xe8\xbd\x33\x3b\xf9\x7c\xd4\xbb\xca\x37\xe4\x1e\xf1\x8d\x3e\x1d\xfd\x56\xf9\xdc\xd9\x43\xe7\x9f\x98\x9b\x3e\x5a\x7c\x70\xdd\xfd\x5b\x12\xe1\xd9\xaf\xcf\x6d\xbe\x77\xbd\x3f\x3c\xb3\x97\xda\x14\x63\x35\x9f\x20\x0e\xe2\x24\x23\x50\x7d\x53\xe2\xb3\xc2\xbc\x5f\x08\x62\x6d\x47\x05\xb0\x6b\x8a\x2b\x82\xfd\x74\x0f\xec\xa1\x9b\xb2\x28\x2f\xa1\x2c\xab\xfc\xd6\x95\x4d\xf8\xad\xa3\x70\xbc\x0f\xbe\xbc\x6b\x24\x8b\x29\x08\x0a\x4f\xb0\x1f\x8b\xe3\xb4\x75\xe4\x7b\xa3\x38\x4a\x19\xd5\x35\x1f\xec\xc7\x44\xd3\xa6\x74\xd7\x25\x02\x47\xea\xc1\xaf\x1f\xc6\x5b\x1d\x42\x34\x41\xc3\xca\x7e\xd3\xec\xd0\x01\x7d\x07\x64\xc6\xa2\x1f\x65\xa6\xe3\xb8\x17\x66\x21\x03\xe6\x6c\xc8\x16\xae\x90\x01\xb1\x4c\x24\xc7\xca\xa7\x59\x18\xa6\x57\x2b\x72\x4a\x3d\x16\x88\xb3\x30\x84\x23\x2c\xf7\x3f\x40\x5d\x83\xa2\x99\xd3\x86\xea\xe2\x0e\x1a\x41\x64\x61\xbe\x6e\x05\x92\x1d\x05\xd7\x70\x69\x98\xac\xe0\x91\xe6\xf7\x2f\x80\x4c\x30\xf3\xb7\x92\xe9\x5e\xf0\xf2\x96\x96\x89\x1f\xab\x9e\x65\x32\x99\x4e\xa2\x4c\x2e\xea\xef\xde\x26\xca\xe4\x5f\x24\x53\x44\x56\x71\x72\x17\xd4\x68\x94\x3c\x5c\x37\x87\x29\xd0\x70\x3b\xac\xb0\xda\x1c\x06\x31\x56\xc4\x0e\xf8\x1d\x3f\x93\xaf\xaf\xb1\x7c\x8b\x0e\x27\x9b\xf3\x7f\xdf\x10\x8f\x24\x5b\x60\x80\x05\x41\x5c\x70\xae\xbd\x55\x03\x04\x96\xe4\x3c\x81\x72\x0e\x92\x49\xf2\x90\x28\xe7\x88\x24\xa7\x17\x4c\xb8\x97\x9a\xf0\x60\xaa\x98\xf2\xf6\x52\x13\xb6\x51\x13\x06\xc3\x66\x2a\x58\x0b\x2a\x58\x8f\x2a\xc8\x50\x15\x64\xd0\x45\x43\x15\x4c\x71\x10\xc6\xc7\x54\xb0\x8a\xaa\xc0\xe6\xed\x15\x55\x90\xef\xc6\x8a\x57\x6b\x47\x50\x09\x93\x18\x2a\xe2\xed\xc5\xdf\x6c\xb4\xd2\xb4\x38\x52\x6c\xae\x9f\xfd\xad\x6c\xd8\xda\x4a\x73\x5f\x6a\x66\xcc\xd7\x8e\xd6\xb2\x95\xe5\xa2\x2e\xd9\x5a\xde\x43\xd7\xa8\x59\x88\x0f\x41\x6d\xc6\x17\x8d\x9a\x0c\x5d\xca\xbb\x13\xb9\x0d\xe9\x92\x93\x2d\xe5\xab\x53\x88\x51\xa1\x2a\x8c\xe8\x2f\x15\x2d\x11\x38\x7b\xf2\xb2\x45\x3b\xc2\xa2\x12\xa8\x3e\x8b\xe3\xda\x24\x7d\x3e\xc2\x9e\x8f\x24\x4a\xe3\x6c\xfd\x06\xac\xca\x88\x17\xe2\x43\x0c\xf1\x0c\x5b\x44\xe2\x6c\x70\x41\xb4\x48\xde\xd9\x4d\x27\xcf\x9e\xd9\xc6\x6b\x78\xc3\x33\xa5\x4c\xb3\xf0\x90\x3a\xfd\x1e\xae\x5d\xe9\xf7\xd4\xe8\x53\x53\xe7\xdd\xd6\x69\xf8\x9b\xb5\x6e\xad\x69\xb1\x4d\x9e\xad\xf5\x04\x04\x72\x84\x7c\x2a\x1c\x95\x25\xc4\xbc\xdd\x21\x92\x33\x25\x4a\x6a\x0d\x71\x62\xae\x75\x9e\xd3\x60\x56\x88\x47\x43\x1c\x70\x6a\x81\xb9\xbb\x39\x7b\xaa\x44\xfd\x01\x2f\xfd\x8d\x40\x0a\x32\x77\x45\x58\x84\xbc\x85\x42\x8e\x08\xb2\x32\x0f\xf7\xaf\xbe\xa4\xdf\x08\xf7\xaf\xce\xfe\xa0\x95\xb7\x76\x27\x9c\x40\x88\x45\xa2\x3e\x6d\x15\x9f\x78\xeb\xad\xd7\x5c\x7d\xbe\x0e\x7b\x30\xda\xe1\x8c\xf9\x4c\x26\x5f\x8c\xdf\xea\x88\x07\xcc\x8e\x60\xcc\x64\x8f\xf9\xcd\x66\x7f\x8c\xb6\x76\xe4\xfa\x7e\xe1\x1c\x6d\xb7\x13\xe9\x7a\x77\x91\x82\x89\xb0\x39\xa4\x42\x0c\x2f\x68\x90\x4e\xcf\x60\x7b\x2e\x6a\x4e\x2e\x03\x23\x53\x8b\xe5\x70\x5c\x84\x95\xfc\x89\x19\x7f\xa1\x96\x5b\x4c\xde\x90\x18\x8f\xa2\xc1\xab\xdc\x88\x89\xed\x11\xfd\xc6\x22\xd1\x75\xc6\xc5\x60\x14\x6d\x83\x60\x14\x2a\x5c\x35\x16\xc5\x54\x8d\x45\xa1\x5d\x1f\xc6\x5e\xee\x9a\xf0\xad\x2e\x4c\x8c\x4d\x41\x4f\xcf\xcd\x4c\xe6\xe6\xd7\x4c\xfd\x53\xad\xbd\x62\xf5\x40\xb7\x3e\xa7\xf7\x1a\xb7\x1f\xb0\xb3\xbe\xd4\x6a\xf6\x6d\x3b\xb2\xe6\xd5\x43\xd0\x9f\x9e\x63\xb7\x3d\xb5\xf6\x57\x0f\x44\x67\x02\xdc\xef\x95\xb4\xf3\xca\x0f\xca\x85\xe7\x9f\xde\x3a\x49\x65\x47\xe6\x2f\xae\x11\x3e\xd2\x4d\x6e\x65\xb2\x63\xd1\x11\x28\x2c\x25\x86\x00\x70\x58\x0c\x10\x2f\x8a\xa9\x2d\xc8\x20\x1c\x9e\x55\xe3\xb6\xa6\x60\x3b\x88\x57\xc4\x6d\x32\x3a\xb8\xdd\xfe\x00\x1c\xad\xc2\x6e\xd8\xd4\x05\xa2\x2b\x4d\x18\x92\xc6\x6e\xf3\x9b\x42\x80\x61\xed\x6b\x02\x02\xbe\x0a\x4b\xde\x92\x30\x60\xd9\x14\x5b\xf1\xbe\x20\xb2\x00\x95\xa1\x19\xd4\xb8\x1f\xd6\xba\x25\x85\x11\xee\xaa\x9c\x67\x48\xf2\x9c\x44\x79\xc2\x40\xb3\x5c\x4a\x9e\x9e\x26\xf2\x44\xe0\xfa\x1e\x66\x7b\x3f\x00\xb8\x4b\xee\x40\x57\x30\x8c\x62\x75\xe4\x4d\xdd\xcb\x17\x4b\x5c\xf9\x9a\x48\xf6\x24\x5b\xf0\x5a\xc8\xb6\x67\xc1\xfe\x8a\xc9\xb6\x1b\x65\x1b\x20\xeb\xc9\xc9\xa5\xa4\xcb\xf5\x63\x9a\x73\x88\xcd\xca\xc3\x74\x56\x9e\xaa\x48\xeb\x87\x73\x08\x31\xed\x62\x91\xe4\x74\x4b\x90\x1b\x83\x0f\x07\xd9\x87\x83\x09\x31\x86\x2f\xbf\x81\xaa\x24\x0a\x49\xdf\x4a\x88\x61\x1f\x1b\x44\x77\xbf\xa2\x88\x7c\x08\xfc\xd5\xf5\x2d\xc7\x6c\x8b\x00\x94\x26\x9a\x9a\x6b\xcd\x04\x6b\xa1\xc5\xcb\x2d\x89\x61\x30\x76\x90\x87\x8c\xb6\xd0\x43\x62\xc0\x44\x36\x80\x2a\x3d\x69\x3a\x05\xe7\x35\xe0\x1a\xf4\x25\x20\x21\x93\xe4\x35\x61\x04\x32\x00\x8a\x96\xb7\xe1\x6a\x64\x69\x01\x45\x86\x11\xbe\x5c\x30\x32\x67\x84\x2b\xeb\xe5\xd0\x91\xe5\x6f\x8b\x23\x9f\x27\x3b\xca\xa7\xb1\x46\x99\x8b\xf4\x93\x1d\xe2\xbe\xdb\x2f\x95\x27\x8b\xc9\x10\xc1\xc3\x25\xa4\x93\x3b\x15\x1d\xe4\x4e\x77\xaa\x52\xa6\x2c\x24\x96\x29\x83\xf3\xbb\x10\x2b\x4f\xe6\x67\xa7\x97\x50\x1b\x01\x2e\x81\x62\xd5\xf2\x64\x39\xce\x88\x50\x65\x53\x83\x22\x65\x71\x3e\x6c\x14\x5a\x54\x29\x5b\xbb\xf7\x89\x59\xe7\xca\x91\x21\x8b\xac\xae\x4c\x59\xf9\xb4\xe2\xd5\xba\x42\x65\x6d\xf6\x2e\x5b\xf9\x2e\x61\xac\x41\xad\x32\x99\xd8\x67\xbb\xb1\xcf\x56\x52\x6f\x7d\x7f\x6d\xaf\x01\x5b\x72\x26\x5d\x8a\x33\x3b\xb8\x81\xda\xc1\xe6\x44\x2e\x72\xa1\x94\x66\x23\x3c\x6d\x80\x6d\x59\x69\x92\x8d\xf2\x79\x2a\x7f\x3a\x42\xbd\x77\x8d\xd1\x1a\xc6\x02\xb4\xa3\x50\xdd\x28\x37\xd9\x91\xf3\x64\xeb\xfa\x3d\x1f\x07\xba\xf3\xdc\x72\xfa\xbf\xd5\xc8\x5f\xee\xd8\x48\xb6\x36\x85\x65\x8d\x1c\xc5\xa6\x96\x16\xc1\x13\xc5\xf5\x8f\x85\x8f\xe5\x3a\xba\xc6\x47\xc8\x77\xc4\xe8\x60\xbd\x70\x09\xaf\x25\xb1\x28\x05\xe6\x42\x6a\xe8\x37\x02\x56\x4a\x56\x5d\x2a\x69\x75\x56\xa1\x9d\xba\x78\xea\x4a\xd1\x64\xa8\xae\xe5\x62\xb1\xf5\x90\xc2\xa9\x49\x15\xf4\x48\xa7\xd0\xb7\xab\x59\x02\xab\x1f\xea\x26\x0b\xd6\x2c\xac\x1a\x45\xa5\x02\x71\x9d\x24\xaf\xef\xc0\x19\x26\xaf\x85\x42\xcf\xc4\x05\x85\x9e\x35\x22\xcc\xdb\x64\xe8\x80\xf5\x7f\x70\x41\x6e\x58\x25\x54\x04\xb9\x79\x46\x36\xea\x14\xbf\xfe\xb9\xfb\x06\x27\xaf\x2e\xbf\xce\xb5\x97\xff\xc5\x0d\x5f\xfb\xb7\x6b\xdc\xb3\xf9\xe8\xd6\xf4\xc5\x8d\x37\x86\xfa\x15\xda\x81\x3e\x2f\x55\x20\x7f\x84\x1b\xe7\x36\xd8\x6d\xde\x73\xe5\x37\xde\x2c\x3f\x71\xce\x6f\x75\xcc\x3e\xf7\xd9\xe9\xbf\x7c\xb4\x72\x90\x3f\x9d\x99\xea\xdb\x5d\xc4\xb9\x41\x71\xfd\x7d\x99\x4a\xf8\x1d\xb5\xae\x0d\xec\x2c\x18\x28\xc9\xb9\x58\x3a\xef\x52\x5d\xca\x0d\xb0\x22\x49\x39\x7d\x3a\x3f\x41\x7f\xdc\x94\x2a\x4d\x5b\xbb\xa1\xa2\xda\x34\x90\xae\xe7\x51\x0f\x62\x3d\x09\x38\x03\x98\x6e\x83\x82\x63\xb9\x69\x03\xc6\xf3\x41\x95\x1a\x38\xeb\x1d\x4d\x42\x89\xb9\xd8\xc0\x04\x0c\xbb\x69\x63\x49\x13\x19\x5a\xb3\x16\x01\x95\x1d\x05\x57\xb7\x3e\xcb\xa8\x22\x3e\x80\x6f\x80\x1b\xec\x8f\x60\xd8\x43\x1e\xa8\x05\xb9\xe9\x8e\x02\x49\x8e\xb2\x3b\xf5\xdc\xea\xfa\x4b\x2a\xe9\x82\xcf\x5f\xd9\x79\xa0\xbe\xc2\x0b\xd5\xc6\xcc\x15\x10\xa9\x99\x01\xb1\xac\x49\x30\x0d\x9a\x54\x28\xb2\xb7\x1f\x5a\xe3\x4a\x27\x7a\xf4\x86\xde\xe4\xa0\x6b\x62\xef\x6c\xa4\x3c\xcf\xd9\x7a\x86\x02\xae\x58\xa4\xd7\x7e\xe0\x86\x13\x5b\x3c\xab\x47\x07\x8c\x5d\x77\x64\x46\xee\xdf\x3a\xfc\x87\x89\x35\x36\xa7\x20\x68\x95\x6a\x39\x6f\x75\x38\xe3\xdd\x16\x6e\xdf\xbb\xfc\x8a\x91\x54\x9a\xbb\x78\xec\xec\x81\x8c\xde\xee\x33\x1a\x7c\x0e\xfd\xc0\x57\xbe\x7f\xfb\x4f\x66\x77\x8c\x3a\x74\xae\xb0\xf3\x87\xeb\x66\x75\xb6\x4e\x63\x57\xa2\x7f\xdf\xeb\x2f\x3e\x7f\xda\x6e\x14\x8c\xa6\x35\x47\x33\x37\xdd\xe3\x54\x2b\x79\x93\xcf\x3f\x71\x77\x60\xe7\xcd\x3b\xd9\x1e\x9d\xc5\x08\x1e\xc1\x18\x41\xc8\x7d\x78\xb4\x41\x94\x20\x60\x5c\xfa\xd2\x62\xbd\xaa\x5c\x57\x0a\xd3\x20\x58\xd4\x60\xd1\xac\x54\xa9\xa2\x15\x48\x65\x42\x04\x59\x17\x3b\xf1\x71\x0f\x9b\x09\x20\x3f\x42\xa5\x81\xca\x12\x50\xb1\x2a\xcb\x8a\xa8\x08\xd9\x7c\x8f\x92\x3e\x93\x75\xf5\x65\x17\xc4\x1b\xe6\xf5\x0e\x64\x69\x2d\x8a\x3b\x6c\x61\xf0\xd5\x98\xc4\xcb\xcb\x49\x55\xac\x06\x2c\xca\xf8\x65\xc4\x51\x72\xa4\x2c\x33\x08\x36\xea\x07\x29\xe8\x3a\x06\x20\x2c\x45\xba\xc4\x8b\x58\x2c\xac\xd9\x2b\xc1\xe6\xb0\x46\x29\x2f\x13\x6b\x94\x8a\x1e\x4b\x99\xb9\x26\xd5\xc3\x5d\x8e\xfe\x1b\xb7\x08\xfb\xe8\xde\xda\x07\x31\x99\x1a\xcc\x81\xa6\xfb\x68\x5f\xaa\xe8\xd1\x58\xe8\x3e\x9a\xa7\xfb\x68\x03\xc6\xa1\xfb\x13\xf9\x00\x56\x85\xb4\x20\x31\x29\xcf\x6b\x44\xd0\x43\xf3\xad\x6f\xae\xd5\xd6\x76\xc9\x73\x28\x6e\x01\xff\x90\xc0\x46\xe8\xa8\x50\x61\x1b\xfe\x5f\x9f\xc9\x16\x7e\x26\x5b\xfc\x99\x6a\xe1\x67\xaa\xea\x67\xdc\x1c\x7f\x91\x2f\xc9\x13\xc4\x4e\xd7\xa3\x9c\x39\x51\x12\xb0\x22\x2c\x52\x85\x58\x56\x2c\x4b\x89\x25\xc0\xb5\x03\x66\x10\x12\xad\x20\xbf\x5b\xb0\x20\x29\xb6\xc2\x23\x98\x3b\x78\xe8\x3e\x4f\x7f\xb7\xb9\xa3\xdd\x19\xb1\xf6\x64\x03\xbe\xd1\x84\x5b\xf8\xd1\xe6\xf3\x87\x77\xb9\xb2\x99\x84\x41\x6b\xd2\x5a\x93\xdd\x9d\x74\x02\x73\xa7\xc6\xe9\x7b\x13\xf4\xbd\x27\xa5\xf7\xda\x13\x25\x43\xf5\xbd\xf2\x0b\x10\xe9\x51\x90\x03\xe3\x88\xc8\xb5\xd5\xf7\x22\x8a\x27\x2c\xf1\xa4\xd9\x8d\x11\x97\x70\x27\xe9\x4b\xdb\x9c\xbd\xf4\xa5\x5d\xbe\x95\x09\xf7\x81\x43\xc2\x3a\x57\x76\x90\xbd\x32\xd5\x25\xbe\x32\x32\x7f\xfe\x30\xc8\x9b\x2c\x9f\xe2\x9f\x24\x57\xfe\x97\xf7\xca\x1b\xbe\x37\xb9\xe8\xbd\x54\xd8\x83\x87\x3e\xae\x4a\x0a\xaf\xb5\xd1\xd7\xf6\x6e\x86\xd7\x22\xf3\xf2\xa2\x70\x02\xe5\x4d\x02\xcd\xcf\x8c\xd6\xce\x94\x9d\x73\x33\x6b\xaf\xd3\x37\x24\x1c\x03\x83\x34\x40\x9f\x06\x1c\xf0\x34\xd0\xa3\x66\xa6\xee\x80\xa4\x4c\x41\xc6\x4a\x69\x37\xea\x8f\x60\xa3\x87\x47\x69\x1f\x41\xb3\x4d\xd0\xec\x08\xeb\x23\xee\x54\xf5\x61\xcb\x8e\xeb\x6d\xd2\x9f\x3c\xd9\x4e\xe5\xdb\x53\x95\xcf\x9e\xc8\x25\xd3\xa2\x72\x11\x11\x92\x6a\xa0\x5f\x38\x87\x84\x08\xe4\x38\x7d\xda\x19\x87\xa7\x9d\xdd\xa2\x7c\x9d\x90\xde\xe1\x48\x32\xf9\x1a\xe9\x3f\xd8\xe8\xe1\xf6\x4a\x9f\x44\x56\x88\x7d\xc2\xa5\xeb\xfb\xa9\xd9\xf8\xf8\x6a\xb3\x61\x03\xf2\x95\x4f\x09\x7b\x70\xdc\x7c\xee\xf2\xd9\x3e\x6f\xf9\x9a\x8c\xc3\x5d\x4d\x87\x27\xb5\x8b\x2c\x77\x8a\xff\xb3\x10\x5d\xc8\xb7\xd3\x32\xbe\x9d\x76\x11\xdf\x4e\xc3\xf8\x76\x9a\xe6\x7c\xbb\xac\x7f\xc5\x74\x34\x3a\x03\x01\x4a\x33\xd1\xe8\xf4\x0a\x3f\xbf\xab\x67\x72\xd0\x0b\x4c\xa5\x9e\x09\xf8\x3a\x81\xbc\xe3\xeb\x1f\x08\xef\x50\x7d\x32\x3e\xf3\xcd\x62\x05\xb7\xae\xa1\xb4\x44\x69\xce\x3b\xfa\x52\x29\xf1\x6e\xa2\x21\xa0\x59\xcc\x0e\x2c\xa5\xd8\x02\x38\x0a\x93\xb8\x5c\x0f\xbe\xb0\xb9\xb3\x87\xc5\x74\x0d\xb5\x58\xd4\x6a\x7f\xd6\x58\xc2\x03\x3e\x6f\x06\x00\x46\x19\xaf\x6f\x20\x6c\xe1\xb6\xd4\x3d\x99\xb7\x84\xa8\x10\x99\xb0\xd5\x1a\xce\x50\x61\x42\x96\x3d\x9e\x34\x14\x3d\x4c\x53\x67\x16\x7e\x0d\xbe\x2e\xf9\x33\x9b\x93\xaf\x90\x5b\xa8\xc5\x6c\xa1\xeb\x9d\x95\x48\x4b\x9c\x5c\x4f\xd4\xe2\x12\x07\x47\x64\x08\xe8\xbd\xc2\xcd\x1d\xbb\xfc\xc9\x71\xee\xfc\x38\x37\x71\xfc\xbd\xf2\x95\xe3\xb4\xaf\x08\xfd\xdb\xf7\xf1\x6f\x3b\x1b\xfc\x6d\x5e\xce\xd8\xb9\xf4\xdf\x08\x32\x08\x1d\x47\x3e\xb9\x7c\x0c\xe8\x73\x1f\x70\x8a\xf7\x8e\x97\x5f\x1e\x47\xe6\x1c\x47\xc2\xd7\xdf\x17\xfe\x44\xb5\x9d\x22\x5f\x26\x85\x3e\xd0\x7f\x88\xee\xc0\x74\xb0\x58\x5a\x15\x97\x4a\x84\xeb\xd3\xb1\x78\x30\x28\x87\x12\x48\x95\x54\x4a\x7c\xe0\x4a\xe7\x55\x32\x28\x68\x58\x34\xf6\xe9\x54\x0c\x9a\xcc\x5f\xc8\xfb\xda\x19\x24\xd9\x07\x37\xc4\xea\x14\xf8\x1b\x24\x84\x58\x49\x2a\xcc\x18\x3a\x6a\xb4\x7b\xc1\xb3\x63\x85\x00\x14\x4a\xbf\xd2\xaf\xe3\xa8\x93\xa7\xf4\xe3\xf9\x57\xc5\xcb\x0b\x47\xd7\x70\xfc\xdd\xd1\x6d\x8e\x3b\x1f\x7a\x7a\xee\xec\xe1\x99\x8e\x70\x66\xd3\xf0\xad\x8f\x7b\xb9\xbf\x4e\x94\x27\x78\x8e\x7b\x6e\xb2\xfc\xaa\xe7\xb1\x9d\xab\x76\xad\xb8\x7d\xea\x99\x6d\x5b\x9f\x3d\x7c\x93\x89\xfb\xf1\x19\x59\x9f\xd6\xdc\xf6\xf2\xbd\xcf\x6e\x8f\x3f\xfa\xa6\x3d\x13\xef\x3c\xb0\xff\x65\xa3\xaf\xcd\x7b\xe6\xd0\xc3\xc3\x03\x2f\x8e\xad\x5b\x79\xdf\x0b\x3b\xa9\x1d\x07\xf9\xef\x0a\xef\xca\x6d\x44\x49\xcc\x10\x23\x8d\x84\x08\x75\x1b\x1d\x75\x84\xc5\x5c\x09\x15\xde\xab\x82\x9a\xaa\x4a\x07\x63\xd0\x42\xdd\x11\xaa\x61\x64\xd8\x14\xe4\x0a\xa9\xd8\x7b\x41\x81\xfc\x49\x05\x64\x8e\xcb\x11\x32\xb9\x00\x25\xac\xa7\x3f\xe9\x58\x6c\x22\xc4\x2f\x9a\x55\x58\x91\x17\x22\x0f\xa5\x7a\xe1\xe2\x31\x28\x40\x28\x39\x23\xe0\xec\x01\x45\xd7\x15\x36\x06\xb9\xdf\x3e\xf5\x03\x6e\xe2\xc0\xfe\xc3\x7b\xbf\xb7\x6e\x74\x58\x76\xf2\x91\x47\xc0\x9b\xa2\xff\x7d\xbb\xfc\x19\xa7\xbe\x76\x90\xbb\xe3\xf1\x63\xe5\x53\xb4\xff\xc0\xd1\x7f\x45\x78\x85\x5a\x53\x78\x41\x8d\x3a\x89\x23\x4a\x1d\x26\x3a\x39\x89\x5f\x44\x9c\x68\xd2\xe8\x37\xc2\x9f\x5c\x1d\x27\xff\x05\xd1\x23\xd8\x54\x78\xda\x63\x60\x64\x60\x60\x00\xe2\x82\x69\xcd\x1d\xf1\xfc\x36\x5f\x19\xe4\x39\x18\x40\xe0\x7c\xfd\x9c\x93\x30\xfa\xff\x9f\x7f\xd5\x1c\xcd\x6c\xed\x40\x75\x1c\x0c\x4c\x20\x51\x00\x6e\x3e\x0d\xd7\x00\x00\x00\x78\xda\x63\x60\x64\x60\x60\xbb\xff\x2f\x98\x81\x81\x93\xe1\xff\x9f\xff\x0f\x39\x9a\x19\x80\x22\x28\xe0\x19\x00\xa6\x58\x07\x8e\x78\xda\x75\xd3\xc1\x2b\x44\x51\x14\xc7\xf1\xfb\xcc\x50\x26\x0b\x4d\x62\x61\x35\x49\x92\x24\x59\x48\x93\x0d\xb2\xd0\x34\x69\xd2\x24\xcd\x62\x16\xd2\x34\x25\x69\x56\x93\x64\x31\x69\x92\xac\xd4\x24\x0b\x65\xa3\x94\x85\xd5\xa4\x94\xb2\xb0\xf7\x0f\xc8\x3f\x60\x21\x59\x49\xf8\x9e\xf7\x7e\xd3\x3c\x2f\x16\x9f\xce\x9b\x3b\xf7\xde\x73\xee\xb9\xdd\x8e\x17\xb7\x10\x77\xce\xb5\x79\x19\x62\x13\x23\x58\xc7\x20\x66\x19\xdf\x22\xbe\x62\x1f\x8b\x58\x61\x6c\x92\x58\x23\xe6\x89\x65\x8d\x9f\xc2\xe6\x16\xb1\x8a\x4d\x94\x50\x47\x3e\xe0\x31\xcf\x4b\xf1\x3d\x17\xec\xe3\x2c\xe7\x36\xa6\x54\x47\x0e\x69\xac\xa1\x82\x43\xa4\xb4\x5f\x43\xf3\xec\x7b\x37\xa8\xcd\xdf\x67\x08\x1b\x8a\x96\x7b\x06\xa3\xda\xbb\x0f\x3d\x18\x43\x52\x39\xdf\x54\xd7\x31\xce\x94\xef\x5d\xb9\x6d\x9f\xac\xf6\xce\xa8\x76\xcb\xb1\x83\x07\xcd\xb5\xef\x83\xd0\x78\x5a\xe7\x4e\xab\x7f\x45\xd5\x5e\x52\xbd\xbd\x8a\x03\xaa\xbd\x40\x0f\x2c\xf7\x15\xa6\x43\xbd\x5f\x56\xed\xe5\xe0\x2c\xfe\x1c\xeb\xe1\x0d\x12\x38\x42\x15\x17\x41\xef\xfd\xb1\x27\x3c\xab\xe6\x7b\x5c\xb3\xee\x44\xe7\x26\xbf\xb7\x04\xbb\xcf\x3b\xd5\x5c\xfd\x7d\xe7\x7e\xef\xdd\xdf\xbe\x3f\x75\xa6\x4a\x44\x23\x22\x11\xba\x87\xa8\x23\xc5\x4c\x44\x32\xd4\xeb\xdc\x3f\xe2\xfa\x3f\xba\xb6\x19\x72\xa9\xb1\xd6\x3d\x44\xed\x29\x96\x22\x06\x94\xdf\x62\x97\x58\x4d\x5f\xd6\xc3\xd8\x3c\x03\x75\xe7\x5a\xb1\x63\xdc\x39\xef\x1c\xfd\x01\xf7\x48\xcc\x12\x0b\x7e\xaf\x6a\x2d\x9d\xe8\x0e\xde\x05\x77\xe9\x4d\xb4\xdf\x89\xff\x9e\xe0\xd9\xfd\x26\x6c\x2d\xf1\x83\xdf\xfe\xbe\x7a\x73\xc3\xb1\x5b\xe7\x7e\x00\x27\x4b\x55\x86\x00\x00\x78\xda\x63\x60\x60\xd0\x81\xc2\x29\x0c\xbf\x18\xef\x30\x4d\x62\x4e\x61\x91\x60\xf1\x61\x69\x63\xd9\xc2\x72\x8d\x55\x82\x35\x84\x35\x87\x75\x05\xeb\x0e\x36\x2d\xb6\x30\xb6\x63\xec\x11\xec\x4b\x38\xf8\x38\xe6\x70\x9c\xe2\x2c\xe0\xfc\xc7\x15\xc2\xb5\x8b\xeb\x1c\xd7\x07\x6e\x16\xee\x3e\x1e\x1d\x9e\x04\x9e\x6b\xbc\x7a\xbc\x25\xbc\x1b\x78\x9f\xf1\xa5\xf1\x1d\xe0\xfb\xc1\xef\xc5\x3f\x89\xff\x98\x00\x8b\x80\x87\xc0\x32\x81\x4f\x82\x29\x82\x07\x84\x82\x84\x9a\x84\x6e\x08\x73\x09\x27\x08\x4f\x12\x3e\x24\xfc\x47\x44\x43\xc4\x42\x24\x45\xa4\x4b\x64\x89\xc8\x35\xd1\x08\xd1\x0b\x62\x7a\x62\x3b\xc4\xb5\xc4\x5b\x24\xca\x24\x4e\x49\x6a\x48\xce\x92\xbc\x23\xc5\x27\x55\x27\x75\x4a\x5a\x45\xba\x4f\xfa\x97\x8c\x95\x2c\x93\x6c\x9a\xec\x1e\xd9\x4f\x72\x7d\x72\x47\xe4\x25\xe4\x03\xe4\xaf\xc9\x7f\x50\xa8\x50\x38\xa1\x70\x42\xd1\x44\xf1\x8b\xd2\x2f\xe5\x0e\xe5\x57\x2a\x7c\x2a\xb7\x54\x8d\x54\xef\xa8\x25\xa8\x35\xa8\xad\x50\x3b\xa1\x5e\xa3\x3e\x4b\xfd\x9d\x86\x8d\xc6\x12\x4d\x0d\x4d\x0f\xcd\x43\x5a\x4c\x5a\x56\x5a\x5d\x5a\xab\xb4\x05\xb4\x8d\xb4\x17\xe9\x98\xe9\xf2\xe8\x2e\xd0\x7d\xa4\xa7\xa2\x97\xa7\xf7\x4c\xbf\x46\xff\x97\x41\x84\xc1\x33\x43\x23\xc3\x2a\xc3\x33\x46\x51\x46\xf3\x8c\x9e\x18\x9b\x18\x9f\x30\x31\x30\x39\x64\x6a\x60\xba\xc8\x4c\xca\xec\x90\x79\x8d\xf9\x34\x0b\x25\x8b\x0e\x8b\x0f\x96\x09\x56\x7c\x56\x5e\x56\xab\xac\xcd\xac\x0f\xd9\x04\xd9\xbc\xb0\xdd\x64\xd7\x65\x1f\xe3\xa0\xe3\xb0\xc7\xd1\xc1\xf1\x98\x53\x90\xb3\x84\x73\x9c\xf3\x22\xe7\x37\x2e\x4d\xae\x3e\xae\x4f\xdc\xfc\xdc\x76\xb8\xeb\xb8\x5f\xf2\x68\xf3\x78\xe4\x99\xe0\x79\xcc\x4b\xcf\x6b\x8e\xb7\x8f\xf7\x2a\x1f\x35\x9f\x2b\xbe\x51\x7e\x0a\x7e\x9b\xfc\x6e\xf9\x6b\xe0\x80\x66\xfe\x2e\xfe\x41\xfe\x09\xfe\x79\xfe\xab\xfc\x9f\x05\x28\x05\x4c\x0a\x64\x0a\x2c\x0a\x5c\x15\xa4\x05\x84\x1e\x41\x39\x40\xf8\x2c\xd8\x27\x38\x07\x00\x2b\x8a\x94\x93\x00\x01\x00\x00\x00\xe6\x00\x6d\x00\x05\x00\x00\x00\x00\x00\x02\x00\x01\x00\x02\x00\x16\x00\x00\x01\x00\x01\x52\x00\x00\x00\x00\x78\xda\xb5\x55\xcd\x4e\x13\x51\x14\x3e\x2d\x28\x60\x52\x16\x2c\x58\x4f\xba\x82\xa4\x14\x68\x80\x28\xac\x10\x41\x89\x4d\x49\xa0\x4a\xdc\x98\x0c\x65\xfa\x13\xfb\x33\xce\x4c\x29\x6c\x5d\xba\x76\xe5\x23\xb8\xf0\x19\x5c\xea\x9b\xf8\x00\x3e\x80\xdf\xf9\xee\x99\x22\x95\x09\x2c\x34\x37\xbd\xfd\xee\x3d\xff\x3f\xf7\x8c\x88\xcc\xcb\x57\x99\x92\xdc\xf4\x9c\x88\xfc\xc2\xcf\xe1\x9c\x2c\xe2\xe4\x70\x5e\x66\x73\x8f\x0c\x4f\xc9\x65\x6e\xc1\xf0\xb4\x78\xb9\x8f\x86\x1f\xc8\x87\xdc\x17\xc3\x0f\xc5\xcb\x97\x0c\xcf\x4a\x2d\x5f\x35\x3c\x07\xfc\xd9\x70\x61\xba\x96\xff\x69\x78\x5e\xde\xce\x6c\x19\x5e\x90\xc5\x99\x4f\x86\xbf\x03\xa7\x3a\x7f\xc8\xda\xcc\x37\xd9\x93\x48\x02\xf1\x25\xc1\x7e\x2e\x9e\x9c\xc9\x15\xf6\x63\xdc\x84\xd2\x06\xaa\xe2\xfe\x42\x3a\xd8\xfb\x38\x0d\x25\x06\xee\x4b\x0b\xb8\x0d\x14\xe3\x7f\x20\x23\xd2\x12\xa0\x81\x74\x79\xe7\xe3\x46\xb5\x1d\xe0\xa6\x0f\x8a\xfe\x47\x90\x0a\xa4\x8c\xdb\x3d\x9c\x42\xd8\x89\xa0\xa1\x05\x3d\x09\xee\x2a\xb2\x86\xb5\x95\x69\xbb\x4c\x4a\x00\xfd\xea\x6d\x6c\xde\x0e\x69\x27\x80\x26\xb5\xdf\x06\xf2\x64\x17\xd2\xbe\x34\xec\x54\xc1\xaf\x0b\x1d\x0d\x6a\x89\xe9\xc1\x21\x50\x83\x9e\xc5\xf4\x58\xa3\xf7\xe5\x29\xf1\xf9\xd8\xfe\x9f\xd6\x4b\xf2\x12\x48\xfd\xed\x62\xd5\xe5\xdd\xd8\xc2\x85\x2c\x01\x5d\x59\x16\xbb\xd0\xee\x22\x5d\x96\x6d\x58\xbe\xdd\x92\x37\xb6\xb5\x6d\x91\xaf\x63\xdd\xc5\xfb\x9a\x71\x6a\xfe\x07\xcc\xf7\x3a\x6c\xa9\xe4\x86\xec\x30\xfa\x44\x9a\xe0\x1f\xb2\x0e\x6d\x56\x49\xf3\xba\x04\x0f\xd7\xc0\xf9\x04\x76\x96\x71\x5e\x81\x2e\x4f\x1e\x13\x69\xd6\x36\x41\x55\xfc\x7c\x5c\x03\x3d\x5d\x52\xff\x06\xf1\x08\x7b\x11\xf4\x62\x86\x87\x2b\x7f\x65\xce\x9b\xc8\x9d\x77\x23\x7b\xde\x3d\xf3\xf7\x6f\xb5\x65\xf5\x9c\x66\x3e\xab\xe7\x0a\x58\xd5\x1b\xbd\x73\xbf\x9e\xbb\x29\xa3\x1e\x4f\xd6\xae\xc2\xda\x69\x75\x52\x0d\xc5\x09\xa9\x22\x7c\xde\x81\xfd\x2b\x48\x0c\x41\xef\x41\xbf\xbe\xcc\x3e\xce\x89\xbd\xc4\xc0\x3c\x70\xef\xb0\xc9\x8c\xe8\x5d\x80\xfa\xa9\xa6\x90\x9c\x1d\x5a\xd4\xba\xf5\x70\xa3\x6f\xc1\x67\x1d\x95\x73\x84\x53\xc2\xb8\x93\x5b\x7d\x2f\xc3\x83\x37\x13\x1e\x0c\x30\x23\xb4\xee\x4e\xaf\x6f\xba\x43\xa3\x35\x33\x75\x79\xec\x17\xcd\xa9\x67\xab\xcd\xae\x0d\xf1\x0a\x56\xb1\x46\x5c\x65\x56\x22\xcd\x65\x5a\xbf\xd5\x89\x37\x1c\xe3\xa6\x8a\x7e\xdc\x93\x7d\xa9\xc9\x09\xf6\x15\xcb\xa9\xea\x7f\x05\xae\x2e\xb9\x34\x2f\xda\x0b\xef\x11\x41\x87\xe8\x7a\xc6\xa9\x9d\xd0\xf4\xfa\xb8\x73\xb9\xd3\xae\x1e\x31\x92\x88\x3c\x2d\x4a\x39\x39\x7d\x59\x69\x3e\x47\xec\xa4\xc4\xa6\xa1\xd6\x38\x66\xf4\x09\x28\x3e\x65\x0a\x90\xd1\xca\x24\xe4\x3c\xe3\xcb\xcc\xee\xa0\xc9\x5c\xb9\x9a\x66\x69\x18\x58\xee\xfb\xec\x9c\x5d\x64\x40\x67\xcd\x09\xb0\xce\x0b\x3d\xeb\xa9\x04\x1f\x4e\x81\xea\xf2\x42\x8e\x90\x95\x3a\xa8\xa7\xa0\x1e\x63\xed\x22\x6f\x75\xd0\xf6\x29\x7b\x84\x1b\x9d\xcb\x47\xb8\x7d\x46\x89\x43\x62\x47\x3b\x60\x87\xd7\xd0\x09\xfa\xf6\x0e\xc9\x53\x62\x9f\x75\xcc\xff\xc8\xba\x2e\x64\xe4\xb1\x7d\x17\x22\xc6\x91\x76\x9d\x7a\xae\xfd\x74\xc2\x7c\x66\x47\xde\x34\xc9\x94\x1e\x43\x3e\x00\x47\x87\x1d\xde\xb0\x1a\x69\xd6\x87\xac\x8f\xf2\xb4\x20\x73\x41\x3f\xfa\xe3\xef\x53\xc8\x73\x8f\x19\x4c\x5f\xde\xf5\xb7\xa9\x40\x9f\x7a\x8c\xc0\x67\x1d\x53\xfa\xdd\xd5\x29\xff\x97\xce\x75\x5a\x7b\xe0\xbf\x7d\xce\x9e\x42\xfa\x8c\xd9\x71\x93\xdd\xcd\xff\x03\xf6\x86\x9b\x40\x11\x27\xcb\x26\x76\x9d\x6b\xdb\xd8\x2b\xdc\xd7\xc7\xb3\x6e\xe3\x37\xb2\xb4\x66\xc0\x00\x00\x78\xda\x6d\xd0\x47\x4c\x54\x61\x14\x86\xe1\xf7\xc0\x30\x03\x43\xef\x55\xc5\xde\xf5\xde\x3b\x5c\x8a\x7d\x28\x63\xc1\xde\xb0\x2b\x0a\xcc\x8c\x22\xe0\xe0\x88\xd8\x8d\x05\x7b\x34\x26\x26\x2e\x34\x16\x36\x6a\xec\x35\x1a\x75\x21\x04\x7b\x89\x25\xea\xc2\xa5\xb1\x41\x5c\xa8\x4b\x23\x32\xbf\x3b\xbf\xcd\x93\xef\x24\xe7\x2c\x0e\x41\x74\xe4\xf7\x61\x2a\xf8\x5f\x3e\x82\x04\x49\x30\xc1\x58\x08\xc1\x8a\x8d\x50\xc2\xb0\x13\x4e\x04\x91\x44\x11\x4d\x0c\xb1\xc4\x11\x4f\x02\x89\x24\x91\x4c\x0a\xa9\xa4\x91\x4e\x06\x9d\xe8\x4c\x17\x32\xe9\x4a\x37\xba\xd3\x83\x9e\xf4\xa2\x37\x7d\xe8\x4b\x3f\xfa\x33\x80\x81\x0c\x62\x30\x1a\x3a\x06\x0e\xb2\x30\xc9\x26\x87\x5c\xf2\x18\xc2\x50\x86\x31\x9c\x11\x8c\x64\x14\x4e\xf2\x29\xa0\x90\x22\x5c\x8c\x66\x0c\x63\x19\x47\x31\xe3\x99\xc0\x44\x26\x31\x99\x29\x4c\x65\x1a\xd3\x99\xc1\x4c\x4a\x98\xc5\x6c\xe6\x30\x97\x79\xcc\x67\x01\x0b\x59\x44\xa9\x58\x38\xc9\x56\xb6\x71\x9b\x43\x7c\x62\x3b\xfb\xd8\xcd\x11\x4e\xd1\x28\x21\xec\xe2\x3d\x5b\x38\x28\x56\xb1\xb1\x57\x42\xd9\xc1\x3d\x3e\x48\x18\x47\x39\xcd\x4f\x7e\xf0\x8b\x13\x9c\xe5\x01\x2d\x9c\x63\x31\x4b\xd8\x4f\x19\x8f\x28\xe7\x3e\x0f\x79\xc6\x63\x9e\xf0\x94\xcf\xed\xdf\x7b\xc9\x73\x5e\x70\x1e\x37\xdf\x39\xc0\x1b\x5e\xf1\x1a\x0f\x5f\x69\x65\x27\x4b\xf1\xb2\x8c\xe5\x54\x52\xc5\x31\xaa\x59\x41\x0d\x3e\x6a\xf1\xb3\x92\x55\xd4\xf1\x85\xd5\xac\xa1\x9e\xb5\xac\x67\x1d\x37\x38\xce\x46\x36\xb0\x89\xcd\x7c\xa3\x8d\x9b\x5c\xe0\x22\xb7\x78\xcb\x3b\xb1\x4b\xb8\x44\x48\xa4\x44\x49\xb4\xc4\x48\xac\xc4\x49\xbc\x24\x48\xa2\x24\x49\x32\x97\xb8\xcc\x35\xae\xd3\xc4\x15\xae\xd2\x4c\x03\x67\x24\x85\x3b\xdc\x95\x54\x49\x63\x8f\xa4\x5b\xdd\x95\xf5\x35\x1e\xdd\xe6\xaf\xf2\x6a\x9a\x56\x18\xd0\xa9\x29\x55\xcf\x37\x94\x0e\xa5\xa9\xcc\xfb\xab\xd1\xbe\xa8\xd4\x95\x86\xd2\xa1\xcc\x52\x9a\xca\x6c\x65\x8e\x32\x57\xf9\xef\x9e\x33\xa0\xae\xee\xea\xba\xbd\xc2\xeb\xf6\xfb\xca\xcb\x4a\x6b\x3d\x81\x91\xe1\x0a\x68\xba\x2c\x45\x7e\x5f\x75\x47\x31\x5d\x05\x7f\x00\xeb\xee\x95\xa0\x00\x00\x00\x78\xda\xdb\xc1\xf8\xbf\x75\x03\x63\x2f\x83\xf7\x06\x8e\x80\x88\x8d\x8c\x8c\x7d\x91\x1b\xdd\xd8\xb4\x23\x14\x37\x08\x44\x7a\x6f\x10\x09\x02\x32\x1a\x22\x65\x37\xb0\x69\xc7\x44\x30\x6c\x60\x56\x70\xdd\xc0\xac\xed\xb2\x81\x43\xc1\x75\x17\x03\x33\x23\x0f\x03\x93\x36\x98\xcf\xae\xe0\xba\x89\xc3\x00\xca\x61\x03\x72\xd8\xfd\xa1\x1c\x56\x90\x4a\x36\x46\x11\x98\x4a\x16\xa0\x24\xab\x13\x94\xc3\x09\x31\x46\x0c\x26\xc9\x05\x94\xe4\x9c\x01\xe1\x30\x6e\xe0\x86\x5a\xc6\x0b\x14\xe5\x9e\xcc\xa4\xbd\x91\xd9\xad\x0c\xc8\xe5\x01\x72\x79\x0d\xe1\x5c\x3e\x90\x19\xdc\xf5\xff\x19\xe0\x22\xfc\x40\x05\x7c\xfb\x61\xdc\xc8\x0d\x22\xda\x00\x4c\x6c\x3e\xaf\x00\x00\x01\x53\x59\xec\x49\x00\x00\x01\x00\x00\xff\xff\x95\x31\x48\x34\xd4\x6b\x00\x00") func fontsInconsolataBoldWebfontWoffBytes() ([]byte, error) { return bindataRead( _fontsInconsolataBoldWebfontWoff, "fonts/inconsolata-bold-webfont.woff", ) } func fontsInconsolataBoldWebfontWoff() (*asset, error) { bytes, err := fontsInconsolataBoldWebfontWoffBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "fonts/inconsolata-bold-webfont.woff", size: 27604, mode: os.FileMode(509), modTime: time.Unix(1492020681, 0)} a := &asset{bytes: bytes, info: info} return a, nil } var _fontsInconsolataRegularWebfontEot = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x74\xae\x55\x4c\x1c\x0c\xc0\xac\xbd\xcb\x2e\xee\xee\xbe\xb8\x2d\xee\xee\x5a\xdc\xdd\xdd\xa1\xd0\x02\x2f\xee\xee\xee\xee\xee\xa5\xb8\xbb\xbb\x7b\xf1\x02\x05\x0a\xe5\x4f\xbe\xfc\x39\x17\xe7\xcb\x79\x6e\x26\x99\x4c\x9e\x0c\x9d\x0e\x00\xa0\xa8\x0d\x00\xc0\x00\x60\x00\x60\x00\x00\x00\x83\x0c\x87\x08\x02\x80\x00\x00\x00\x10\x90\x08\x04\x00\xc0\x00\x25\x55\x36\x00\x20\xd0\x01\x08\xf8\x3f\x60\xff\xff\x19\xb9\x90\x92\x00\xf8\x5f\xe0\x01\xe4\x01\xce\x00\x0b\x80\x0b\xc0\x19\xe0\x01\x70\x01\x38\x02\xcc\x00\x9e\x00\x33\x00\x00\x80\x06\x50\x07\x58\x01\x6c\x00\x5e\xff\xd3\xb9\x03\x00\x00\x22\x80\x36\xc0\x0a\xe0\x0e\xf0\x00\xd8\xfd\xcf\x9e\x02\xc0\x0e\x60\x05\x40\x01\xec\x00\x4e\x00\x00\x40\xfb\xff\x30\x51\xfc\x2f\x0f\x00\x20\xa1\x21\xab\xfa\x7f\x3f\x01\x01\xbc\x63\x01\xdc\xe4\x00\x6e\x1a\x00\x8b\x0c\xd6\xcc\x45\xf4\xb8\xe9\xba\xce\x84\xad\xa2\x9b\xc2\x7f\x3e\x54\x5a\x02\xee\xcc\x6c\xe9\x5c\x86\x39\xdb\xb8\x68\x28\x8e\x76\x8b\x5b\x4b\xf7\x91\x93\xd9\xe8\x70\x79\xd2\x63\x4a\x32\xca\xad\xa4\xa3\xcb\xb0\xba\x45\x05\x6a\x86\xa6\x9a\x3f\x1d\x89\x21\xda\xc7\xe9\x26\xd8\xab\x21\x0c\xe3\x9c\x2c\x5f\x44\x82\x25\x7f\xb9\xf0\x0c\x64\x94\x5a\x79\xe9\xcb\x73\x35\x22\xf0\x64\xca\x7f\x95\xaf\xbc\xdf\x2a\xdf\x1d\x0d\x59\x40\x7f\x5b\xfb\x5d\xd4\xd8\x7d\x15\x18\xeb\x23\x43\x0a\xbb\x22\x50\x8d\x42\x16\xfe\x06\x09\x14\x5b\xf2\xda\x6d\xec\x1a\x23\xd2\x0a\xdf\x81\x36\xa4\x2f\x7f\xd7\x56\x64\xff\x3e\x5a\x65\x7b\x9e\xbf\x90\xe5\x08\x1f\x4c\x8a\x84\xbd\x81\x38\xc4\xa3\x12\x74\xf2\x2c\x6c\xfc\x3a\xda\xb6\x6b\xc2\xd5\x5e\xbb\xb2\x86\xb3\xa3\xa7\xe7\xd4\x6d\x0f\xdc\xe4\x51\xae\xea\x6a\xf5\x2f\xe0\xa3\x0f\x56\x89\x9b\xed\x36\x5a\x0f\xce\x7b\xa6\x51\x3e\xc3\xff\xe7\x4e\xd7\xc9\x6c\x18\x5b\x90\x8c\xc6\xd5\xcc\xb6\x8e\xf6\x49\x92\x18\xe7\x90\x24\x6d\x14\x22\xe0\xa8\x50\x98\xe4\xb6\x8f\xc3\x6e\x05\x4a\x81\xf1\xde\x22\x2a\xe6\x68\x3b\xf0\xf3\xe9\xc9\x42\x99\x08\x13\x53\x34\x6e\x40\x48\x91\x7a\xf0\x7c\xa7\x49\x54\x1e\x16\x7a\x4c\x9c\xde\x43\x21\xf3\x11\xdb\x1d\xd4\xfd\x35\x81\xa3\xd6\x12\x25\xd6\x15\x72\xf3\xcf\x93\x6b\x61\xf4\x73\xfa\xa8\x92\xbd\xe2\x5f\x61\x44\x41\xbe\x1f\xb0\xe8\x30\x3f\x9a\x8c\xfa\xc0\x2d\xcc\x1c\x27\xc3\x9b\xe2\x9c\xea\x6b\xba\xa3\x9d\x59\x3e\x32\xb7\x5d\x64\x4b\x48\xa3\xc2\xe6\x47\xec\x48\xae\x90\x2f\x21\x23\x53\x80\x99\x7c\xc9\xd5\x41\xc8\xc1\x1d\x69\x88\xeb\xb0\xaa\xd9\x91\x53\x8e\x7a\x73\x98\x99\x5e\x1b\x4a\xba\x42\x8b\x6d\x08\x5e\xaf\x41\x98\x84\xbe\x34\x46\x30\x4c\x82\xa0\x91\x61\x64\x50\x6b\x32\x2c\x31\x9a\x14\xa6\xce\x64\xbb\xf0\xc0\xf9\x35\x88\xc7\x53\x89\x77\xe0\x6e\x9e\x3c\xf8\x15\x6e\xe3\x3f\x6f\xe9\x20\x43\x12\xa1\xb8\x48\x8a\xf7\x25\x2a\x6f\x0c\x07\xf1\x63\xc9\xeb\xe5\xd7\x20\xb8\x81\xba\x4e\x05\x2a\x2a\xf8\x8f\x87\xab\xec\x7a\x2c\x19\xd7\x7d\xf9\x82\x27\x58\x77\x8b\x31\x5e\x78\xa7\x10\xc6\x46\x33\x8c\x44\xd2\xf7\x3b\x68\xbf\x58\x68\xe2\x56\x09\xe1\x6c\x9a\xd0\x53\x18\xc6\x58\x42\xa3\x02\x9f\x1d\xc8\x5c\xcd\x21\xe3\xa0\x56\x73\xcd\x56\xe6\x5e\x8c\x7c\x0d\x1f\x9d\x62\x3e\x58\x06\x17\x3e\xd1\x4f\x89\x06\x75\xaf\xab\x68\xdf\x81\x04\x3c\x5f\x1b\x73\x2a\x94\x38\x02\x81\xb8\x06\x6a\x0c\x4c\xcb\x81\xb1\xf2\xff\x86\x9a\x8a\x4f\xa9\xea\x33\x8f\xf0\x7d\x06\x47\x07\xd5\xfd\x22\x69\x01\x20\xf7\x1f\x88\xa5\x92\x61\x38\x12\x83\x23\x07\x21\xfa\x34\x94\xb2\x49\x73\x24\xa4\x78\x88\x62\x7f\x29\xc6\xd9\x4c\x05\xc9\x13\x6f\xb0\x19\x13\x28\x7b\x07\xc5\xef\x49\x4c\x28\x25\xab\x55\xaf\x62\xb1\x23\xa0\xd4\x82\x45\xfb\x31\x30\xb4\xd1\x11\xe9\x4c\xf1\xba\xd1\xa7\xe3\xbf\xea\x58\x45\x90\x67\x8a\x43\x59\x02\xbe\xa5\xc0\x39\xf0\x22\xee\x3f\x9d\x7d\x31\x42\x60\x30\x0c\xfb\x4a\x3a\xff\x8b\x66\xa3\xdd\x07\xb5\xcb\x9b\xcf\xaf\x48\xe0\xde\x49\x95\xab\xb0\x48\x4b\x35\x70\xd4\xcb\x6b\xa0\x63\x79\x58\x2e\xbc\xe5\x56\xae\x7d\x39\x06\x4a\xcd\x5f\xc8\x23\x42\x32\x1a\xaf\xc6\xb4\xfe\xb4\x71\x92\x89\x20\x0f\x09\xf9\xe4\x73\x9a\x46\x15\x04\x83\x0e\xe1\x34\x83\xd1\xb1\xe0\x90\x40\xe3\x99\x49\xc7\xb5\x2c\x76\x27\x94\xcc\x61\x1d\x50\xc6\xbc\x9a\xa2\xfe\x67\x58\x0f\x72\x4a\xa6\xa2\x50\x5a\x44\x0c\xd5\xd8\xab\xa3\xb9\x11\xd3\xe0\xc3\x96\x2d\xcc\xd4\xf7\xd8\x55\xee\x04\x89\xe2\xaf\x65\xa6\xe6\x92\x04\x4c\x38\x27\xaa\x6a\x2f\x5e\xb8\xeb\x14\x54\x9c\x0c\x96\xf3\x04\xee\x7c\xef\x7f\xf0\xa7\xcd\xed\x84\x10\xec\xe1\x0f\xeb\x92\x39\x5c\xa4\x7c\x2d\x4f\xac\x8f\x2b\x8d\x13\xc1\x7f\x8d\x9d\xf2\x4a\xd8\xb6\x5b\xcc\x97\xe6\x77\x4e\x70\x28\x51\xdd\x7a\x3d\x7e\xa9\xa9\x3c\xa0\x5a\x9a\x2b\xe4\x1e\x73\x93\x3a\x4e\xa7\x1e\x70\x44\x0a\x85\x3a\x42\x7c\xec\xac\xc2\x20\x30\x5f\x29\xab\xa3\x29\xf7\x51\x39\x64\x99\xa3\x5d\x8c\x18\x7c\xab\xb0\xfa\xb7\xd3\x12\x98\x85\x70\x1e\x6f\xd2\x35\x19\x46\xed\x8d\xbd\x3d\x30\x1d\x59\x87\x37\x8c\x5a\x88\xe3\xf5\xf9\xf0\xce\x62\x66\x11\xf1\x05\x8c\x27\xb9\xb2\xb1\x44\x2d\x87\x79\x23\x20\x2c\x71\xed\xb2\xe0\x4f\xaa\x73\x78\x29\x4a\xef\xa8\xf3\xb1\xb1\xb1\xfc\xe3\xa8\x86\x58\x14\x01\xa7\xd8\x07\x62\xf1\x50\xc6\xf9\xf6\xd1\x0d\x14\x65\xeb\x35\x25\x18\x20\x71\xa9\x44\x35\x60\xaa\x6e\x38\x14\x82\x91\x31\x37\x34\x00\x36\xa1\x41\xfe\x71\x17\xa4\xf1\x88\xc5\x2a\xe0\x7f\x8d\x77\xde\x46\x5c\x2b\x76\x4e\x8c\xc0\x09\xb3\x8f\x25\xb2\xb6\x55\x70\x2a\xf0\x78\x61\xfe\xfd\xdb\xeb\xde\xf5\xc7\x7f\xf0\x84\x8d\xb8\xd8\x9e\x48\x09\xf2\xb4\x20\x49\x93\x42\xdb\x61\xa9\x4a\xd7\xd1\x02\xe5\x77\xd9\x80\x65\x93\x01\xbe\xf1\x4a\x02\x02\x2c\xf1\xdf\xd4\xad\xdc\xc0\xe4\xad\x73\x42\x61\x52\x5e\xf8\x9e\x68\x34\xac\xfc\x91\x68\xaf\xba\xaf\x91\x65\x06\xd2\x63\x6b\x87\xbf\x4a\x64\x36\xfb\xd7\x16\x89\x38\xab\x3d\xc8\xec\xcb\x92\x8d\x11\x8a\x48\x48\xf7\x59\xa6\x59\xe3\xdc\x2d\xa7\x35\xce\x7c\xee\x74\xaf\xea\x90\x23\xc2\x8a\xf6\x57\x62\x27\xdc\xf7\xf2\xa6\x7b\x92\x75\x75\x97\x46\xcf\x58\xe7\xd8\xed\x69\xa0\xf3\x28\xfe\x1a\x4d\x7c\xfc\xa7\x1d\x09\x21\x67\xe3\xeb\x59\xb6\xc1\xff\xcd\xa9\xa4\x73\x23\x37\xb4\x66\x08\xf2\xc9\xef\xae\xc0\xc1\x47\x6b\x68\x90\xcb\x49\xc0\x75\x93\xe4\x79\x5e\xe0\xae\x95\xe3\xf5\xe0\xe0\x34\x86\x7c\x8b\x3f\x3a\x74\x55\x5f\xd2\x6c\xe1\x29\xc1\xf3\x7e\x7e\xdd\x9f\xcb\x2b\x6d\x42\x1d\x32\xd8\x2c\x14\x66\x1a\x95\xd7\xca\x7c\xc4\x1c\xd9\xa0\xf2\x6f\xa3\x9d\xb0\x2e\xd6\x9e\x10\x8d\xf3\x1f\xfb\x0b\x01\xbb\x51\x47\x71\x9f\x80\xf3\x15\x25\x69\xfb\x2d\xf7\xe5\xfe\xe5\xf7\x9f\xe7\xd5\xf6\xcd\xca\x48\xbe\x03\x0d\x71\xa7\x6b\xd8\x4a\x2c\xeb\xa2\xb0\x71\xdd\xc9\x17\x41\x17\x25\x48\x1e\x98\x3f\x45\x1c\x42\x50\x24\x3a\x7b\x2c\xe0\xcc\x51\xb9\xca\x7a\x70\x5e\xa5\x97\xbd\xfd\xf5\xcd\xd8\xb9\x8e\xac\xba\xc2\x24\xf8\x50\xeb\x48\xa6\xb9\xa2\xa3\x2a\x38\x62\x09\xaa\x1b\x5a\x7c\xba\xe5\x4b\x07\xf5\x45\xa9\xc3\x28\x7b\x9a\x8e\xf6\x8d\xcf\x99\xe5\x57\x34\x97\xb0\x7f\xf8\xa8\xb1\xfe\xa0\x49\x44\x39\x47\xf6\xeb\xda\x29\x8b\x1a\x8a\xca\xee\x96\x98\x40\x64\x4a\xa0\x4a\x15\x90\x20\xb6\x3d\x3f\xbe\x24\xa1\xe5\x65\xa1\x17\x08\xb7\x59\xab\x49\x65\x77\x92\xa2\x37\x6a\xb6\x5e\xc3\xdc\xd9\xa6\xd2\x17\x4e\x25\xff\x92\x56\x0a\x5a\xfe\xfd\x50\x60\x31\xb0\x2e\x59\xaf\x14\x61\xc7\x3d\xb7\xbd\x49\x44\xa5\x15\x33\xef\x79\x7e\xa6\x67\x43\xfc\x85\x6e\x24\xb6\x29\x54\xc8\x06\x05\xd1\x20\xb0\xdf\x68\x4a\xd1\x88\x2c\xe1\xc7\xd3\x82\xa7\x35\x44\xf2\xa4\x55\x87\xb0\x3c\x66\xb3\x0f\x37\xc8\xcb\x3d\x5a\xda\x07\x24\x95\x7d\xf0\xb3\x9f\xfe\xe2\xbf\x8b\x13\xb6\xd3\xa0\x49\x29\x62\xfe\xc3\x55\xab\xf8\xd4\x71\x95\xb7\x96\x9a\xa4\xdc\x6d\xf5\x54\xf4\x66\x2d\xda\xe8\xa6\x97\xf4\x7d\x21\x2b\x20\xda\xe5\xd7\x55\x74\x09\xdd\xe7\x6c\xcb\x0c\x98\x8b\x03\x1e\x38\x50\x6c\xff\x93\x37\xbe\x6e\x0e\x8a\xe9\x7b\xa1\xd9\x50\x02\xdc\x12\x68\x25\xda\xa5\x54\x7d\x70\x0e\x0e\x47\x89\x49\xdb\x69\xb7\x00\x9f\xb4\x60\x71\xc9\x16\x65\x18\x51\x35\x9c\xb8\xc2\x2b\xe2\x75\xbb\xe7\xb4\x0a\x13\xcb\x74\xce\xfa\x50\x53\xad\x3d\x65\x4d\x9a\x26\x79\x60\x50\xcb\xb7\x2b\x6f\x86\x7a\x67\x18\xa6\x4b\x39\x3c\x4b\xe2\x3d\x40\xe9\x40\xb6\x48\xb5\x14\xaa\x12\x9f\x5e\x18\xde\x49\xa8\xe5\xd8\x48\xf0\xfc\xe1\x08\x10\x6d\x09\x3f\x00\x33\x47\x01\x00\x38\x65\x3a\x2d\x69\x3a\x2b\xe0\xf2\x9f\x88\xf3\xd9\x96\xa5\x26\xc3\xb1\x6d\xc8\xa1\x14\x70\x6a\x79\x96\xfd\x78\xbc\x77\x7f\xf4\x81\x8e\x92\x3b\xe0\x81\xe2\x33\x78\x68\xce\x4f\xe6\xec\x98\x32\x06\x75\xc2\xf3\x21\x12\x3b\xdb\xb3\x0c\x8b\x74\x78\x7d\xc2\xca\xa5\x36\x4d\x00\xbc\x7a\x76\x94\xe9\x4b\xbd\x55\x7e\xe9\x10\x95\x0a\x6b\x63\xb4\x68\x35\xfb\x22\xae\x7f\xe9\x1f\x76\x7a\x3a\x2f\x91\x5c\x39\x43\x27\x3c\xac\x3c\x3b\xa7\x2a\xcd\x96\x10\xc7\x2d\xa7\x26\xf1\x06\x82\x05\x58\xfa\x48\x52\x67\xab\x62\xe9\xe3\xbc\xbb\xf8\x32\xdf\xd7\xb2\x86\x79\x6f\xaf\x90\xe1\x82\x42\x8f\x86\xec\xd2\x2a\xd6\x54\xf6\xca\x52\xfd\xaa\xa5\xbd\x87\x67\x31\x65\xb2\xf2\xd7\xb0\x5a\xf0\xac\x11\x5d\x43\xbc\x4c\xc9\x9e\x3c\x3d\x99\x7e\x59\xcb\x02\x75\xe4\x9d\xcd\xcb\x74\x41\xf8\xf9\xab\x0b\x76\xcf\x97\x3e\x29\x53\xb5\x2e\x59\x85\xef\xe3\x51\xeb\x88\xeb\x22\x25\x9c\xf8\x89\x98\x81\xe3\x18\x21\xa8\x1d\x97\xbe\xbe\x53\xed\x39\x40\x17\x9a\xb6\xb4\x12\xee\x64\xd2\x5b\x02\xef\x74\x9a\x2c\xd4\xdf\x36\xe4\x11\x78\x2c\xbd\x66\xfe\x36\x27\x36\x47\x55\xcd\x6f\x30\x2c\xe7\xd3\x11\x03\xa9\xf2\xdf\x3e\xab\xda\xe1\x2a\x25\x60\x5d\xcd\xbe\xd9\x58\x24\x2a\xf7\xd4\x1c\xa6\x83\x63\x28\x7e\x05\x2a\x81\x9b\x12\x40\x23\x04\x1b\x0d\x40\x00\xc2\x36\x56\x72\xba\xf0\x39\x4c\x6d\x71\x2d\x8d\x98\xe5\x6f\xc7\xf9\x1e\xad\xda\xee\x70\xc9\xbc\x02\x89\x25\x5c\xfb\x2f\x60\xec\x84\x68\x31\x2a\x5d\xc7\x28\xc3\x2e\x16\xb7\x2e\x9a\xf2\xbe\x99\xe3\xfc\xea\x4f\xe7\x9b\xa5\xc2\x3d\x5f\xf1\x58\xf5\x5f\x69\x98\x8d\xe7\x5e\xf4\x89\x22\xe5\x97\xd2\x33\x88\xb3\xc5\x18\xf1\x10\x71\xde\x1e\x4a\x27\x9c\x6f\xa9\x7b\xbf\xe8\xeb\x17\x87\xf2\x68\xe1\x2e\x6b\xbd\xd5\xe6\xcf\x38\xc4\x3d\x2c\x1c\xbc\x04\x23\x8c\x50\x82\xf8\x3f\x84\xff\x38\x62\x2b\xc0\x00\x2e\x52\x82\x4f\x74\x1f\x46\xc3\x52\xcb\x9b\x6b\x93\xac\x6c\x6a\x49\x18\x91\xd5\x5a\x19\x06\xb8\xf1\x6c\x8d\x28\xd1\x2c\xcb\x79\xed\x19\x60\x96\x65\xbc\x87\xd1\x91\xbe\xfe\xe2\x6f\x26\xfc\x44\x22\x41\xb8\x41\xa2\xf2\x1a\x27\x1f\xa6\x9b\x49\xec\x7f\xf5\x71\xf7\x5b\x21\x25\x2e\x99\x89\xea\x27\xef\xaf\xfc\x87\xf5\x0f\xc6\x5c\xbc\x80\x21\x09\xfb\x25\xcd\x10\x58\xeb\x60\xa2\x2a\x66\x63\x2f\x1e\xe9\x81\xd1\xa9\x8b\x99\x3d\x69\x27\x50\x7e\xd3\x33\x2d\x41\xbe\xf7\x87\x49\x7f\x7a\x3a\x73\x91\x36\x37\x09\x13\x30\x88\x01\x7f\x94\x8d\xd6\x86\xb1\xf6\xc7\xe1\xe8\x00\x15\xa4\x52\x27\x73\x29\x26\xe8\x98\x02\xad\xac\xe4\xed\x5f\x74\xfb\x38\xd5\x59\xb1\x42\x1f\xac\x1a\x01\x22\xf2\x69\xd6\x84\xa2\x7c\x1e\xcc\x04\xc6\xdc\xe7\x2b\x33\xa5\xfe\x89\x99\x61\xa5\x22\x6a\xb6\x9c\xcb\xfd\x6d\x22\x05\xe1\x44\x56\x8d\xfe\x68\xac\xce\x35\xf2\xae\x85\x43\x4a\x60\x51\xce\x5b\x35\xe8\x23\x45\x1a\x44\x32\xae\xff\xf6\x64\xb6\x1f\x42\xd4\x96\x54\x29\x9e\xdd\xf1\x4f\x46\xa3\xe5\x30\x0c\xe1\x0d\x36\xe2\x54\x65\x7e\xc8\xe4\x4e\xef\xde\x38\x1b\xe0\x6d\x6b\xe4\x3e\xac\x15\x9d\x3b\xf3\xcc\x9c\x9c\x1f\xcc\x38\x3c\x1f\xd8\x4c\x88\x53\x11\x7d\xfb\xef\xe8\xfb\xd3\x0f\xd9\x53\x27\x62\x92\xbd\xea\x9d\xea\x60\x05\xed\xf7\xec\x7f\xaa\x4d\x03\x1b\x0c\xb6\xab\x14\xb1\xd8\x5b\x08\x8b\x8f\xcf\xe8\x79\x5c\xad\x8f\x16\x40\x3b\x57\xb4\x8a\xa2\x45\x5c\xf0\xe4\x86\x00\x3c\x4b\x8c\x70\xdb\xa4\x80\xf5\x37\x80\xba\x9e\xde\x31\xeb\xac\xfe\xc0\xd4\x3e\x56\xdc\x13\x22\x3d\xf6\x10\xe4\x90\x99\xa6\xe8\xa7\x45\xf0\xcf\x4c\x36\xcd\x7b\x63\x06\x3c\x6f\xd3\x31\x2e\x2d\x11\x2c\x93\x71\xa1\x77\x6b\x16\x7d\x9a\xdc\xa3\x7a\x80\x1d\x83\x45\xbf\x7e\x28\x03\x86\xa1\x73\x8e\x87\x3e\xd2\xde\xed\xa4\xf1\xd2\xe8\xf8\x1b\xe1\x62\x66\xa0\x01\x2f\x89\x99\xc9\xb7\xd5\x2b\xc1\x42\x14\x97\x59\x69\x58\x74\x17\x83\x7f\x98\xe4\x1d\xaa\x37\x2d\x5e\x65\xc7\x74\xde\x53\xc1\x3c\x0f\xf7\xa8\xb3\xb5\x8e\x39\xb4\x4d\x5d\xac\x74\x0f\xe2\x3f\xc3\xf3\x78\x84\xa2\x06\x62\x4f\x9f\x8b\x2e\x46\xfe\x63\x92\x13\x93\xde\x95\x0d\xa5\xe7\x4a\xe3\x4c\xe4\xe2\xa3\x7f\xee\x8b\x20\x5e\x1f\x30\x91\x49\x6b\x46\xd9\xb3\x0f\xab\x17\x5b\xb4\xcb\x39\xc5\xb0\x8b\x15\x19\x40\x33\x4b\x8b\x15\x64\x10\x75\x1c\x52\xcc\x0d\x82\x4c\x6a\xb6\x16\x30\xa2\x0a\x5e\x3d\x1b\x73\x65\xf5\xeb\x19\xe0\xcf\x1b\x37\xcf\xc7\x86\x0e\xe4\x9f\xd2\xbf\x10\x6e\x31\x34\x97\xa6\x12\xa1\xd4\x4e\xe2\xf6\x27\x86\x0f\xa4\x10\x0c\xa8\x57\xe3\xd0\xf5\x3a\xa3\x9c\x36\x1c\xdb\x45\x03\xb3\xc4\x0a\xfd\x0e\x0e\xfd\xfe\x20\x63\x5d\x10\xd6\x54\x8f\x84\x37\xe3\xc0\x18\xb4\xea\x7a\xbe\xde\xf7\x77\x39\x3b\xa0\xc2\xe1\x52\x4f\xfc\xc5\x3c\x2f\x06\xc0\x64\xf3\x3a\x27\x6a\x88\xfd\xa7\x08\xfb\x5a\xae\x56\x19\x17\x99\x9e\xb2\x71\x80\x57\xa6\xd8\x43\x5a\x44\x91\x6e\x8f\xc2\xa3\xef\x80\xc7\xe6\x4f\x93\x76\xf6\xc8\x74\xf1\x1c\xde\xe2\xef\xf2\x94\x98\xa4\xee\x1a\x96\x55\xfc\x11\x4a\x58\x14\x5b\x8d\x96\x19\x3b\x3e\x2d\x55\xa8\x98\x28\xb3\x24\x3e\x1a\x26\x37\x6e\xc1\x25\x79\x76\x44\x8d\x78\x93\x4c\x08\xb2\x82\x4b\x29\xb8\x8b\xd2\x4b\x94\x1d\x48\xb3\x3d\xf6\x00\x02\x7f\x10\x8c\x54\x17\x6e\x77\xec\x32\x16\x9f\x82\x27\x15\xc5\x32\xa3\x6d\x59\xd0\x12\x5e\x7a\x03\x85\xfa\xd2\x82\x65\x73\xcd\x4a\x4a\xbe\x4e\x1f\x50\x36\xcb\xf6\x23\xed\xd2\xbb\x5a\x46\xd3\xdf\x1f\x5b\x2f\x45\x5c\x05\x05\x99\x12\x1e\x14\x1d\x67\x1f\x45\x78\x0c\xd0\x93\x75\xdb\x79\x0e\xab\x73\xd3\x87\x40\xf9\xe3\xf3\x4a\x0c\x9f\x1a\xa8\xff\xe9\x9d\xa2\x8e\xb9\xf1\x5a\xb3\xde\x85\x8b\x3b\x92\x18\x29\xfa\xea\x75\xae\xa4\xa5\xb2\xfc\x79\x84\x6d\xaa\x34\x53\x8d\xfc\xd9\x43\x35\xdc\xd3\xf9\x3d\x33\x24\xb4\x82\xe0\x93\x85\x14\x31\x4e\xab\xf5\xfc\x97\x5a\xaa\xc8\x34\x37\x9e\x95\xc2\xb3\x29\x4e\xa0\x34\xb9\xb7\xbf\x32\x7f\xc5\xc3\x00\x2e\xea\xa9\x2e\x5a\xc0\x30\x02\xdc\xb0\x5e\x49\x03\x0a\xc5\xdd\x68\xfc\xda\x37\x0e\x2e\x3b\x7c\xeb\xf8\xe8\x2a\x09\x2a\x72\x45\x0d\x08\x44\x4b\xa1\x7c\x65\x68\x56\x30\x62\x24\xca\x25\xce\x1e\xf1\x37\xbd\xf5\xbf\x5d\x17\x2e\xcc\xc6\xb4\xa3\xf9\xf2\x2f\x33\xca\x53\x32\xc1\xb9\xa9\xa7\x18\xe5\x69\x13\xff\x46\xf9\xea\xec\xc1\x32\x7c\x1b\x63\x55\x2e\x5a\xbb\x16\x5d\x70\x77\x64\xc9\x72\xc7\x22\xf2\x64\xf0\xa8\xad\x9c\xf8\x94\x16\x8e\xd1\x86\xd8\x90\xa8\xad\xc6\xfb\x45\xe5\x16\x6e\xf7\x1e\x90\xfb\x8f\x32\x73\x91\xda\xbc\x63\x84\xdd\x03\x80\x0c\x89\xe8\xc8\x92\xdd\xef\xb1\x43\xcd\x3a\xae\x2d\xb1\xb8\xc0\xf3\xa0\x62\x1b\x9c\x95\x5b\x59\xc7\x06\xc9\x4f\xcd\xd5\x8b\x26\x83\x76\x9d\x52\x3d\x30\xbb\x74\x9f\x1b\xb5\x10\xbe\xdc\x5b\xd5\x8c\x8b\xdd\x79\x77\x1e\x4e\xc8\xdf\xc3\xe9\x05\x4c\x11\x61\xfa\xfc\xd2\xc7\x47\xdd\x17\xf0\xac\xfa\xf8\x77\xaf\x32\x4a\x58\xc6\xa2\x6a\xe6\xa1\x1a\x5c\x05\x72\xda\xb5\x9f\x6d\xc3\x46\x92\x4e\x41\x8b\x1d\x57\xf6\xfb\x3d\xea\x6a\xb5\xf7\x14\x99\x3c\xd7\xb5\x25\x65\x42\xfd\xc9\x32\xc9\xc1\x0a\xfd\xbc\x5c\xdd\x15\x51\xe2\x13\xa3\xd7\x8a\xb8\x09\x54\x0a\xea\xa9\x7c\x36\x0e\xae\xa3\x74\x60\x92\xfb\xa6\x6f\x29\xbd\xc1\xaa\xe8\x66\x81\x30\x57\x30\xf4\xd1\xb1\x05\x6a\x02\xe6\x39\xe9\xc5\x16\x14\xb0\x4f\xc9\x16\xd4\x13\xf4\x0f\xb7\x2a\xc9\x2c\xa7\x43\xb1\xa6\xe0\xb4\x88\xf7\x4f\xa6\xe8\xcd\x77\x6d\xf4\x68\x9e\x75\x72\xac\x8b\x61\x6f\x62\x15\x98\x5a\x6b\x1e\xf6\x92\xdc\xd8\xcb\xa8\x99\x54\x50\xdb\xf4\x19\xc7\x69\x86\x79\xb2\x81\xe9\xaa\x9b\x70\xf3\x99\x51\xe1\xc9\x39\xb8\x2d\x38\xf8\x37\xc1\x60\xcf\xe8\x7f\x86\xb5\xa2\x9c\xb4\xa4\xa1\x37\xad\xa0\x90\x7f\xc5\xb7\x78\xa7\xc8\x90\x31\x7b\xb6\x3f\x89\x51\x9a\xee\xda\x8d\xe9\x9c\xa2\xcf\x51\x9a\x6e\x61\x1e\x68\x64\x2f\xe2\x31\xcc\xa2\xa5\x8b\x28\x79\x60\x44\xab\x59\xcb\x96\xcf\x7f\xa4\x0e\x98\x4e\x3f\x6a\x10\x1e\xea\x91\x7d\x68\x9f\xc5\xf1\x77\x9b\xc3\x05\x7f\xc9\x26\xcd\x48\x51\x23\xb7\xe1\x97\x44\x2b\xc8\x96\x9e\x7f\x29\x36\x92\x7f\xb5\x81\x6b\x11\x74\xde\x71\xe5\xda\xc4\x68\xb6\x49\xb6\x74\xc1\xfc\xd1\x07\xc3\x32\x47\xee\xa8\x2c\xb1\xc2\x37\xe6\xbb\x97\x9d\xcd\xba\x69\xf8\xad\x99\xca\x48\xb3\xa7\x2b\x20\x8c\xac\xf0\x14\x51\xd2\x3b\xc5\x28\xf5\x7e\x70\x79\xbb\xb6\x12\x0c\xc3\xc8\x06\xc8\xb2\xda\xf1\xed\x68\xae\xa7\xbf\xc1\xfd\xee\x50\x1d\xd6\xf2\xcf\xda\x11\x7e\xaf\xb0\x8a\x69\xcb\x9b\xd0\x73\xf9\xdd\x24\x2d\x6b\x2a\x14\x83\x03\x75\xff\xf8\x47\x59\x1d\x6c\xd4\xee\x73\x20\x1e\x02\xc1\x44\x0d\x7f\xe2\x1f\x9a\x0d\x3f\xda\x66\xc7\xe1\x9d\x2e\x96\xbf\xac\xc7\x84\xf2\x30\xcc\x54\x7f\xf0\x29\xe7\xd8\x33\x28\x1e\xc6\x9f\x28\xba\x32\x6f\xae\x2d\x37\xec\xb5\xfb\x5e\x43\xa7\x45\xb1\xa6\x39\xc1\xf2\x53\x93\xa8\x5d\x0e\x8e\xb2\x5e\xbb\x5c\x99\x9d\xb0\xb0\xea\x7d\x23\x51\x57\x1b\x4e\x7d\x21\xb3\x71\x87\x5d\x8b\x30\x9c\xd0\x7c\x11\x62\xb2\x2b\x96\x9f\x49\xa9\x18\xc1\xc4\x5d\x29\x67\x78\x7b\x6c\xb9\x3a\xcb\x1d\x2c\x80\xae\x1c\xf0\x65\x82\x6f\x60\x79\x59\xa1\xb0\xc8\xe6\x83\x98\xa3\x71\xaa\xd1\x17\x01\xb8\xfd\x50\x0f\x1e\x55\xe9\xea\xb2\xa9\xee\x64\x03\xef\x7e\x03\x79\x2f\x21\x85\xd8\x99\x18\x2f\xe1\x1e\x4a\x77\xa2\xf8\x62\xde\x55\x84\x51\xdf\x22\xff\xdf\xb8\x77\xaa\xd7\x51\xea\x5f\x5b\x2e\x2b\x35\xee\x88\x10\x62\x62\xf4\xd0\x3d\xc4\x5e\x1b\x41\x93\x8c\x79\xac\x34\xc3\x00\xdf\x12\xb8\x4b\xd1\x7d\xbc\x4a\x7d\x4e\x63\x73\x9e\x21\x75\x4c\x6d\xec\x01\xfd\xa5\xda\xb3\x0d\xec\xc4\x88\x6f\xc7\x3d\xb9\x1d\x12\x30\x0d\x40\xef\x91\x14\x02\x92\xe3\x6c\x4c\x16\xca\xe8\xde\xf8\xfc\x8e\xfa\xfa\x9f\xcb\x47\x7f\xfa\x0a\x64\xe6\x86\x21\xe6\xcb\x77\xe2\x16\x0b\x4d\x8a\x92\xb0\xd6\x8e\xf3\x12\xab\x23\x25\x1e\x6f\xab\x35\x50\xec\x56\xc6\x2d\x4b\xca\xe1\x7f\xdb\x1e\x2b\x3e\x68\xd2\x9d\x1e\x0d\x91\x8c\x59\xc4\x2c\xca\xfe\x6a\xc1\xdd\x48\x4c\x63\xe1\xd3\xb8\xb6\x7a\xd1\x87\xa7\x8c\x9c\xb9\x9b\x25\x04\xcf\x31\xfb\xc5\x12\xe4\xc6\x70\x83\x95\xd4\xaa\x41\x50\x3f\x74\x7f\xd4\x1f\x2b\x03\x14\xb1\x0a\x31\x4e\x06\xc3\xa0\x34\x76\xee\x68\x19\xcc\x99\x42\xf9\x1f\x0b\x18\x2d\xfb\xba\xf1\xb8\x8e\x8c\xbf\x9c\x70\x75\xe1\x9c\x7b\xa1\xec\xb9\xb6\x7d\x72\x5b\xf5\x23\xb8\x10\xb3\xc1\x4e\x4c\x7b\xe3\xc7\x0d\xd7\x7c\x51\x19\xa0\x77\xce\x29\x26\x9a\x98\x48\xea\xa1\x02\x43\xd8\x59\x43\xe7\x0f\xfd\xe3\x5c\x07\xcd\x92\x98\xb4\x95\xa2\x84\x1e\x9f\x3b\xea\xe1\x2f\xf3\x2f\xe5\xdd\x0e\xf8\x44\x86\x52\x18\x56\x02\x6d\xda\x52\x84\xba\xab\x1f\xb8\x94\x49\xa3\x21\xb7\x30\x38\xbe\xbb\x88\x83\x32\xe4\xc3\x98\x84\xe6\x13\x39\x4e\xa6\x71\x8b\x59\x8b\x03\xd5\x90\xc2\x7d\x46\x18\x61\x87\xa9\xfa\x3e\xcb\x7e\xd9\x45\x44\xce\xca\x08\x06\x16\xff\x32\x5d\x94\xe5\x04\xbe\x09\x13\xe1\x2c\x07\x05\xe6\xb7\x29\x1c\x13\x51\x4c\x8b\x34\x61\xcb\x20\xbd\x7a\x8c\x45\xfa\x93\xea\x5a\xcf\x5e\x42\x12\x2e\x23\x86\x65\xcc\xbb\x44\x65\x3a\x29\xee\x1f\xf6\xde\x4e\x63\x67\x8e\x05\x5c\x7d\xd8\x38\x43\x0e\xe3\xf6\x19\x50\xc2\x78\x71\xa4\x4d\x14\xa0\x8b\xd9\x36\xcd\x57\x59\x83\x27\x28\xa7\x67\xa0\xb6\xd1\x6f\x39\x85\xd6\x99\xbd\x62\x2f\x12\x0e\x84\x8a\xfe\x6e\x11\x1e\x2f\x64\x6f\xf3\xff\x8a\x7d\x42\x1e\x22\x5d\xe0\x1a\xd4\xef\x54\x02\xcb\x3b\xd8\xdc\x0b\x9a\x72\x77\x7e\x9b\xa4\xba\x85\x4b\xce\xe9\xbd\xd4\xea\x3e\xd0\x6d\x58\x48\x62\x5a\xfa\xf5\x3a\x6b\xc8\x35\x95\x4f\x2d\xd5\xc6\xd9\x86\x72\xb0\x3e\xf7\xc8\xa8\x7e\x9f\x88\x30\x2c\xc5\x0c\x19\xce\xd5\x20\x42\x1c\x17\xfb\x85\x8f\xcb\xb4\xcb\x39\x6d\xdc\xfe\x8e\xd2\xb7\xa5\x5f\x2c\xfd\x19\xf8\x4b\xa9\x7f\xa3\xde\x5e\x2b\xce\x10\x42\x2c\x14\xda\x4b\xff\xb9\x53\xa2\xb1\x81\xd9\x4c\x00\x94\x8d\x69\x34\x9e\x6f\x16\x87\x55\x2c\x61\xce\x66\x80\x61\x8c\x74\x8d\x5c\x99\x88\x80\xa1\xe4\xac\x8c\x7b\x9c\x62\xab\xb2\x96\xfb\xcd\xdd\x71\xc0\xbc\x24\x18\xe8\xe7\xd6\xb1\x9a\xd1\x18\x72\x2d\x4a\x91\x89\xf1\x53\x8e\xcd\x27\xcb\x5e\xba\xa7\xc7\x07\x36\xe3\x7a\x67\x83\xfa\x3f\xd1\xb9\x05\x93\x2f\x04\xb2\x1f\x79\x74\x8d\xf6\xa1\x5f\x29\x3b\x61\xe9\x57\xf6\x5f\x6d\x96\x64\xa2\x49\xcc\xb5\x49\xa6\x84\x2e\xe6\xa4\x4a\x8b\x96\x4b\xce\xe9\xc8\x72\xe7\x9a\x7b\xda\x5c\xfd\xd9\x8d\xc6\xd2\xf9\xf7\x3d\xe9\x83\xf7\xb1\xae\x65\xa4\x83\x1d\x8e\x39\x13\x71\x79\x39\xf0\x93\x08\xa7\x89\x83\x76\xc1\x32\xed\x75\x94\x7f\x12\x6a\x87\x4e\xe5\x24\x2d\x28\x5e\xb7\x83\xab\x73\x2d\x20\xf7\x20\x48\x0a\x21\x7d\x89\x47\xb9\x59\x8e\x2f\x37\xb5\x89\x46\x90\x2b\xbf\xf8\xc9\x10\x67\x62\xa3\x99\xa5\x3a\x6e\x95\x45\x69\xf3\xc6\x7a\xfc\xef\x35\x74\xec\xe9\xd6\xee\x09\x86\x24\x74\x47\xcf\xd5\xa9\xb8\xeb\x7c\x24\x03\x82\xfa\xa7\x4a\x7f\xcb\x6f\xae\xa6\x57\x4c\xf9\xb5\x67\x62\x40\x2e\xa9\x7b\x56\x7a\xad\xe1\x7d\x9a\x54\xcb\x7d\x4e\xa1\xa8\x3b\xb2\xa8\xa9\xcf\x31\xe8\x31\x52\x75\x64\x81\x37\xe6\x83\xa3\xdd\x41\x74\xf2\xd0\xa8\x11\x0c\x60\xf0\x43\x28\x52\xb8\xd6\xce\x3f\x36\xe5\x1c\xee\x1c\x29\xf6\x8b\xc8\xd4\x4a\x93\x64\x0e\x84\x3f\x47\x7e\x40\x51\x5e\xda\xae\xb1\xef\x30\xf4\x70\x61\x69\x7c\x8b\x7f\x6b\x2e\xa4\x71\xa2\x24\xb4\x80\x17\xe3\x2c\xf5\x72\x6c\xf8\x92\xeb\x07\x36\xfc\x92\x6f\x5c\x32\x11\x79\x60\x53\x68\x3f\x82\x1c\xd6\xc9\xae\x75\xb8\x80\xda\x98\x4f\xc8\x14\xec\x20\xfd\x42\xc4\x14\xc7\x08\x6e\xf0\xa6\xe0\x9a\x05\x5e\xac\x22\x6a\x10\xe2\x05\xc3\x58\x85\xda\x3b\xf9\xdd\x23\x05\x78\x17\x51\x36\xf4\x0e\x75\x1d\x2c\x62\x4c\xcb\x5c\x38\xcb\x37\xe9\x0e\x16\x57\x7d\xbe\x72\x94\x1b\x82\xfc\x2a\x4e\xa9\xe6\xb8\xd3\x57\x7d\x0c\x60\xcf\x0a\x6e\xe5\xf0\xea\xf8\xcf\x76\x5a\x3d\xff\x5d\xb3\x78\x41\x18\xe1\xcb\x61\xa2\xb7\xbe\xec\x13\x05\xb1\x70\x3c\x8b\xc7\x05\xc4\x10\xe4\xd1\x6b\xc1\xde\xae\x4b\xe5\xdb\x9d\x1b\xb8\x0c\x27\xf1\x81\x28\xa7\xbb\x79\xc6\x35\x22\x2a\x26\x4b\x52\x12\x37\xd3\x15\x24\x97\x24\xa1\x0e\x32\x84\xc2\x3c\xe2\x9c\x2d\x7a\xf6\xd9\x5d\x15\xd5\x0d\xd2\x2b\x27\x2e\xd8\x93\x95\xd6\x45\x9f\x8e\xa0\x3e\x65\x0f\x76\x04\x72\xca\x7e\xe9\x18\xff\x31\x02\xbb\x90\xab\xfe\x03\xc5\x59\x02\xd4\x48\xe3\x07\xb9\x23\x8f\x90\xeb\x06\x83\x74\x86\xb1\x4d\xdd\x2a\x5c\x68\x51\x42\xc9\x00\x4f\x3c\x04\xf7\xdf\xa3\x24\x46\x5c\x5d\x93\x93\x02\xb6\x4c\x5b\xe4\xae\xa7\x71\xd8\x7a\x93\x4a\xc3\xc3\x35\xc3\xfa\xcb\x74\x88\xd0\x7d\xc0\xf2\xc1\x8a\x93\xbf\x3a\x35\xe0\x85\x62\xa3\x29\x4c\x3e\xe1\x9d\x53\x4c\x7d\xe1\x0a\xf2\xb6\x11\xad\x49\x03\x75\x84\x7f\xe3\x68\x69\x3e\x53\x52\x16\x44\xa1\x18\xdb\xf6\x29\x1d\x51\x54\xa8\x49\x69\x10\xc3\xdf\x30\x35\x97\xd6\x1e\x4f\xb9\xc2\xf2\xed\xbf\x5a\x91\x17\x7a\x66\x86\x23\x18\xa2\x8d\xce\xae\x0d\x16\x09\x6b\xf2\xb2\x50\x4d\xe7\x38\x50\xc8\xcd\xc0\x32\x91\x24\x77\x36\x33\xed\xe6\xac\x26\xc0\x77\x81\xaa\xf6\x7b\x59\x2a\x22\x56\xae\x77\xbe\xc2\x50\x34\xff\x37\x19\x73\xa0\x66\x53\x53\xe6\xaf\xfc\x09\xab\x4b\x21\x1d\x28\x37\x1c\xe6\xa5\x1d\x67\xb9\xdb\x94\x28\xeb\x2a\xf7\x3d\x88\x4a\xc8\xd2\x46\x27\x14\x03\x66\xf5\x04\xc6\x50\xea\xd9\x47\x5a\x2d\xf6\xf7\x46\x42\x8b\x19\x44\x81\x82\x82\xb2\x75\x66\xc6\xe6\xaf\x72\x7d\x68\x0b\xc4\x26\x3e\xb9\x5f\xab\x6a\x04\x45\x54\x9a\xb1\x0c\x30\x87\x17\xe0\xab\x25\x23\xba\x20\xe7\x71\x13\xfa\x4e\x83\x00\x7d\xa8\x15\x5d\x03\x12\x2f\xbc\xe6\x15\xd8\xda\xe1\xfb\xb6\x4e\x7e\x88\x5b\x2e\xd8\xd2\x3f\xb1\xfe\xf9\x89\xdd\xea\x13\xb9\x3c\xa4\x73\x57\x02\x62\x63\x69\xe9\x54\xd5\xe4\x1d\x5b\x1d\x3a\x44\x2e\xae\x26\x55\x08\x5c\x52\x56\xbb\x43\x66\x98\x3b\x3c\x8f\x95\xf5\x69\xd4\xac\xcc\xcb\x98\x9c\x61\xf0\x74\x84\x2c\x5e\xd9\x11\xae\x65\x6b\x1b\x0e\xf7\x6c\xa4\x37\xa4\xeb\x20\x42\x12\x65\xca\x69\xee\x92\x30\xe5\xb2\x89\xbb\x25\x50\x59\xb2\x44\x11\x20\x2c\xb9\x02\xe3\x02\xa9\xd3\x7e\xcc\x82\xc7\x89\x7c\xf9\x7b\xf6\x7e\x1c\xd4\xf9\x7f\xc2\xef\xa5\xc7\x94\xaa\x0b\x65\x8a\x9d\xb9\x3f\x61\x8b\x23\x74\x83\x73\x65\x73\x13\xae\x2e\xcd\x1c\xc0\xe7\x2a\x62\xa3\x03\x4f\x5a\xba\xb1\xc7\x7f\x7d\x25\x4a\xa8\x8f\x53\xa8\xaf\xea\xbc\x08\x33\xad\x1b\x81\x87\xe4\x0b\x01\xaa\xc2\x1f\xdd\xcf\x19\x2c\xf8\x2b\xa2\xa5\xd7\x47\x35\xea\xd3\x8b\x83\x93\x12\xb9\xf0\xaf\x22\xf2\x11\x49\xa5\x95\x38\x5e\x7d\x9d\x1f\x72\x4b\xee\x56\x58\xec\x70\xf1\xd1\xd6\xe6\x5f\xd9\x01\x7f\x61\xf1\xa1\x5e\x88\x87\x1a\xa7\x3a\xf4\x56\x31\x26\x1b\x9d\x72\x01\x87\x3c\xda\x17\x48\x89\x81\x8f\xc7\x3f\x58\x44\x89\x11\x1a\x62\x31\x45\xc5\x91\x4c\x87\x6e\x9d\xdd\x10\x3a\x9d\x12\xe9\xdd\xe0\x8f\x0f\x41\x84\x93\xa3\xff\x12\xe6\x33\x42\x8d\x70\x08\xd1\xb9\x36\x66\x3f\x54\x2c\x4a\xa9\xea\xd4\x1b\x2a\xd4\x07\xa2\xd2\x12\x1e\x7a\xab\x91\x2d\xdc\xf6\x23\x93\xb9\xf6\x99\xd5\x70\x7f\xf2\x52\x92\x36\xa6\xd3\xf6\xd4\x54\xf5\xdf\x21\x41\x24\x51\x0c\x08\x53\x59\x63\xef\xd8\x3c\x34\x69\xe0\x16\xf0\x3a\x1e\x84\x2e\x90\xbc\xff\x85\x34\xcd\xc1\xc6\xe4\x34\x6b\x6f\x51\x6f\x63\x8c\x37\x62\x0e\x7b\x16\x52\xd6\xd3\x71\xfe\x37\xb4\x3a\xf5\x1c\x59\x06\x53\x47\x33\x75\x66\x43\x5e\x54\x26\xdd\xa3\xb5\xab\x5d\xff\x73\x17\x49\xa9\x8e\x04\xd4\xc4\xcb\x31\x2b\xa0\xae\xf4\x3b\x5c\x57\xdb\x18\xb6\x60\xa9\x72\xfb\xb6\x5b\x8b\xfa\xab\xc1\x0f\x26\x9e\x24\x9c\x61\xf4\x56\x54\x29\x7a\x04\x8f\x21\xda\x61\x46\xf5\x8c\xd6\xdd\x3f\xb9\x85\xea\xa1\x45\xc8\x99\x86\x0a\xba\x97\x8b\x9a\xa2\x9e\xa0\x29\x53\xdb\xc1\x5f\x2e\xb5\xd8\xf2\x16\x7b\x41\x51\x94\xe9\xf1\x6d\xfc\x74\x42\xca\x78\x15\x04\x58\x9c\x63\xcb\x49\x03\x53\xe8\x08\xd8\xa7\x93\x36\x6b\xed\x25\xce\xdf\x9e\x85\x15\xbc\x4c\xf4\xd7\x8c\x04\x81\x78\x54\x6f\x83\xe7\x3c\xc1\x67\x07\x29\x33\x42\x9b\xa3\x2f\xca\x9e\x93\x75\xd7\xf4\x1d\x5d\x50\x55\x2b\xae\xca\xad\x11\x0a\x8e\xff\x64\xbe\xb4\xca\x02\x41\x28\x1e\xa9\xfc\x04\xc7\x2a\xd7\x43\x44\x39\x16\x9a\x59\xd7\xd2\x15\x6c\xd4\xdb\x4d\x64\xf4\x57\x02\xd9\xb6\xd7\xca\xc8\x57\x8f\xa2\x83\x82\xdf\xbb\x66\x1b\x09\xe0\x01\x84\x47\x98\xd0\xcd\xef\xc4\x8a\x3e\xa3\x4b\x12\xc5\x44\x10\xc4\xcf\x85\x66\xa0\xa2\xc1\x94\x99\x2e\x7c\xf2\xd8\x57\x67\x83\x49\x37\xfd\x38\x36\x03\xa8\x3a\xc6\x6f\x25\x8d\xe2\x45\x66\x2c\x90\xa9\x36\xc2\x48\x2d\x68\xf2\x4a\x96\x36\x9e\x85\x78\x0c\xad\xab\x0b\x5d\xc4\xce\x57\x28\x1f\xd6\xda\xdb\x54\xc0\x54\x4b\x25\x0d\x6e\x81\x6b\xe0\x7a\xdc\xac\x4c\xac\x57\xfa\xf7\x73\xeb\x3f\xbd\x41\x0c\x0b\x0b\x5a\xc9\xa0\xc2\x72\xd5\x98\x05\xdf\x62\x58\x21\xaa\x4c\xe1\x49\xfb\x96\xba\x01\x3a\xea\x87\x71\xa9\x31\xa9\x22\xc1\xa0\x22\x9b\x29\xeb\x3c\xbd\x75\xe6\x76\x3e\x84\x9a\x98\x33\x40\x9c\x04\x0c\xc7\x97\xa8\xed\x72\xe5\x14\x15\xa9\xc9\xaf\xdc\x80\x17\x77\x12\x34\x07\x67\x22\x91\xab\x44\x5f\xdf\xa9\xa9\x8e\xda\x17\x00\x62\x9c\xe3\xfb\x54\x77\x92\x0c\xa9\x8a\x8e\x63\x88\xaa\x8f\xe7\x65\xc8\xe0\xa1\x6f\xfe\xd6\xf6\x15\x06\x48\xc5\xf7\x4b\xfc\x8e\x85\x59\x51\x3a\x29\x80\x2b\x24\x96\x98\xd3\xda\x55\x9a\x16\xc4\xae\x9e\x07\x65\x25\x25\xd8\x5e\x58\xb0\xab\x8c\xeb\x13\xdc\xc6\x22\x9d\x87\x77\x56\x58\xa2\xfc\xb7\x23\x23\x2e\xf9\x1c\xb2\x1c\x19\x5f\x36\xb0\xbc\x30\xa2\x2e\x6b\x75\xa9\x87\x8d\xe4\x29\x65\xad\x0f\x2d\xfc\x3b\xf5\x44\x78\xbd\x8d\x7a\x73\xec\x48\x14\x2b\x9b\xde\x8a\x1a\xad\xb8\xb0\x29\x32\x36\x8e\x0c\x92\x6a\x6a\x40\xee\x2f\x6c\x3a\xf4\xfb\xfa\x25\x9d\x92\x4a\x8c\x0b\x6f\x0c\x2a\xab\xdf\xe7\x37\x08\xdb\x5c\x6a\x5c\xf8\x6a\x6a\x5a\xc3\x46\xfc\x03\x43\xf9\xee\x5b\x68\xdf\xec\x31\xa2\x08\x15\xe1\x87\x33\x3b\xb4\xfb\x30\x2a\xd0\x34\x04\x42\xdc\x46\xe6\x1e\xe8\x32\x54\xa8\x21\x8b\x71\x28\xc2\x33\xef\x9d\x87\x97\x4f\x38\x62\xa2\xb1\x02\x43\x68\xd4\x75\x7b\xd7\x9c\xf9\xe5\x49\x3b\x37\x49\xf2\x43\x5c\x59\x74\x1c\xdc\x8c\x60\x9a\xa4\x94\x4b\x65\x13\x1b\x28\x87\xaf\x64\xa6\xd7\xcf\xb0\xaa\xc8\xa6\x46\x83\xc5\x7a\x0b\x2e\x9c\xcc\xc4\xc9\xa2\xf6\xf9\xbc\x67\x05\x88\x86\x7d\xba\x16\x13\x2d\x8e\x8f\x5c\x02\x5c\xee\xf4\x18\x4e\xcd\xa4\x52\xd1\xbc\x64\xcd\xa7\xf2\x09\x69\x44\xf0\x7d\xef\xf2\xcd\x61\xdc\x68\x6a\x30\x80\x19\x6f\x98\x65\x21\xe2\xf1\x31\x0d\xbb\xb1\x5f\x77\xda\x43\x04\xb0\xdb\x7d\xbd\x7f\x8c\x17\x09\xa2\x98\xa4\xdc\xa0\x16\xe9\x8d\x7d\x22\xb7\x28\x09\x83\xec\xf3\xf4\xe3\xca\xe1\x34\x94\xdd\xf8\x8d\x18\x8e\xcc\x2e\xd4\xf2\x80\xea\x36\xa5\x9c\x7e\x85\x51\x93\xa0\x6a\x4d\x16\x6a\x5c\xa5\x46\x17\xbe\xdc\xaf\x27\xfc\xfb\x0e\x13\x0c\x75\xa4\x57\xc4\x99\x95\x58\x50\x4b\x75\x6a\xea\x4a\xc1\x55\x64\x70\xba\x1e\x6e\x2a\xd9\xfc\x4f\xb0\x7e\xd8\xbe\x17\x19\xd2\xb8\xba\x4b\x8b\x86\xed\xa7\xc3\xf7\xa4\xc4\x18\x7f\x67\xfa\x51\xbc\x19\x8e\x70\x0d\x77\x00\x66\xa5\x83\xcc\x35\x99\x18\xc0\x92\xaa\x22\x7a\xfb\x51\x7e\x26\x8e\xae\xbf\x86\xc8\xf3\x71\xe7\x63\x03\xc1\xba\xeb\xbf\xd0\x3d\x27\x9d\xaf\x78\x4f\xdb\x6a\x22\xe9\xee\xa5\x5f\xc5\xba\x6d\xe1\x4a\x0f\xbe\x57\xaa\x31\x0b\xf0\x40\xe9\x4c\xc3\x3b\x2f\xc4\xc7\x60\x9e\x9c\xa6\xcc\x71\xb5\x68\xcd\xb8\x55\x8d\x9a\x53\xee\x75\x58\x03\x89\x13\x49\x6d\x32\x5c\xb2\xf6\x6b\x21\x4e\xb6\xc8\xef\xa9\x29\xae\x9b\xee\x6e\x42\xdc\xd2\x2b\x49\xf3\x1c\x9b\xd2\xce\x01\x92\xdf\xe5\xef\xc9\xd2\xa5\x5a\x62\x70\x2a\xc5\x24\x62\xdb\xb2\xfd\x7d\x66\x32\xf1\x54\x97\x99\xda\x86\x58\x7e\x12\x78\x75\x29\x16\x8f\x21\x65\xff\xf7\xbd\xe5\x82\xd8\x5d\x2c\x6f\xd0\x54\x8e\x9e\x79\x19\x03\x47\xe6\xcf\xba\xea\xd8\x5f\xc9\xcf\x18\xbc\xe0\x4f\x0f\x40\xf8\x8c\x05\x58\xb9\xb3\x39\x30\x6c\x1c\x03\xe1\x02\xdb\xc5\xf1\xed\xbc\xf7\x5c\x0e\x1a\x94\xc2\xb5\x9b\x74\x83\xd0\x46\x69\x91\xac\x30\x71\x04\x56\xc2\x02\xf9\xf2\x94\x43\x46\x41\x7d\x2c\x68\x0c\xe8\x7f\x6f\x3a\x80\x64\x94\x24\x0e\x92\x8c\x19\x04\x42\x1b\xe0\x85\x04\x37\xc9\x2c\xa4\x0d\x6e\x49\x7c\xc6\xf7\x90\xc5\x21\x61\xbd\x6d\xcc\x71\xc6\xb9\x72\x8d\x0a\x2c\x67\x94\x7f\x3f\x25\xec\x6f\x13\x31\x1b\x27\x89\x04\x9e\xdb\x56\x55\xb2\xf2\xf7\x46\x5e\xaf\x06\xec\x65\xb7\x08\x3f\x3e\x10\xba\x2d\x0d\x24\xd2\x25\xa2\xec\xc1\xd2\x21\xe6\x08\x91\x21\x94\xd9\x4a\x4c\xab\xa5\x31\xa6\x30\x54\xbe\xda\x57\xd3\x02\xaf\x3a\xf4\x0f\xf8\x42\xc3\x23\xba\x08\xab\x63\xf8\x42\xef\x39\x30\xfc\x13\xcb\xc8\x3e\x95\x6e\xce\x2e\x0f\x20\xbe\x3c\xdc\xc1\xfb\xea\xc0\x39\x6c\xca\x8b\xc4\x5a\x41\xdc\x73\xd6\xb3\x37\x7b\x5e\x4a\x7a\x06\x24\xd5\x60\xbe\xb6\x4c\x2c\x34\x07\xfa\x69\xd0\xde\x68\x3b\x4f\x64\x40\xe0\x17\x4a\x87\x9c\x34\x30\x2e\x33\x06\x43\xab\xa6\x6c\x69\xab\x3e\x1f\x26\xe0\x2b\x1d\xe5\x4b\x22\x3a\x67\x65\x6d\x77\x7c\x2d\x0d\x8b\x23\x62\x17\x20\x40\x71\x63\x1c\xa0\xc7\x1e\xbe\xd2\x74\x8d\x5d\x6b\xaf\x69\x18\x2f\xcf\x9a\xc4\x60\x36\x85\x60\x2b\xb3\xf4\x42\x0e\xa0\x0e\xbc\x6f\x13\x01\x88\xc7\x0c\x87\x90\x01\xbb\x37\x3c\x72\x0d\xf5\x30\x4d\xc0\x7f\xae\xcb\xcd\x47\x5e\x07\xc9\x1e\x4c\xa9\x26\x5d\x99\x52\x77\xb0\xa7\x92\x7d\xc8\x98\xdf\xa8\x0c\x8d\xc5\x41\xfb\x1f\xd2\x30\x14\xa3\x99\xb7\x68\x6c\xe0\xdc\x88\x63\x85\xd1\x2d\x32\x23\x12\x32\x71\x94\x5e\x30\xeb\x3f\xd3\xe9\xa6\x58\x04\x3a\xd0\x1a\xa2\x3a\xa8\x09\x85\x28\x32\x5e\x6c\x33\x85\x9b\xca\x57\x38\x0a\x67\x25\x4a\xb7\x13\x4c\xfc\x0c\xd0\xb8\x2c\x99\xdb\xbe\xb2\x4f\x1c\x37\x7b\x3d\xe1\xa3\xb2\x18\x7c\xef\x6c\x79\x2a\x8d\x2a\x65\x06\x51\xd2\xa0\x42\xb8\x53\x60\x29\x17\x8e\xee\x73\x7c\x20\x0d\x9e\x8f\x77\x4c\xb9\x2d\xa6\x6e\x4e\x71\x83\x21\x14\x84\x70\x4e\xdf\x99\xc9\x4e\xf8\x2e\x16\x17\x28\xa8\x43\x61\x30\xeb\x10\x69\x5b\xdb\xde\x61\xd8\x4b\x8e\xa1\x49\x86\x31\xf2\xc1\x32\xce\x0f\xd1\x3b\xf3\x02\x75\xaa\x88\xef\xc4\x3c\xf8\xda\x8d\x5b\x4b\x59\x44\xc4\x02\xd5\xeb\x2d\x55\x1f\x2c\x96\xfb\x8d\x11\x5d\x81\x98\x60\x68\x48\x2f\x0c\xd0\xa5\xaf\x3a\xf8\x55\xe9\x9f\x7f\x11\xfb\x63\xad\xf7\x3b\xd3\x5d\x75\x3d\xae\x67\x07\x73\x80\x1d\x94\x98\x68\xb5\xe9\x27\xe1\xc7\x9d\x0f\x43\x02\xbb\x71\x14\xdd\xf8\xf3\x09\x70\x3c\x05\xce\x11\x41\x5d\x14\x01\x9b\x75\xe1\x59\x1a\x66\x0a\xde\x9e\x37\x45\x8c\x93\x44\xb6\x89\x3b\x0c\x68\xa9\x3f\x4b\x11\x67\xe6\x06\xc7\xf6\x9f\x45\xc0\x0c\xe9\xcd\x8a\xf8\x90\xd3\x73\x20\xa1\x1c\x89\xb5\xec\x29\x45\x1e\xcd\xf1\xcb\x75\x89\xf4\x41\xce\x96\x28\x1a\xfc\x98\xa8\x86\x18\x53\x11\x71\x8b\x17\x05\x03\x7c\x10\xc2\x50\x51\xb7\xa7\xd1\x5f\xbe\xad\xf1\x42\x5c\x66\xb5\x4a\xdb\x1e\x8b\xb5\x6b\xbf\x5b\x80\xe3\x38\x95\x57\x24\xcb\xf0\x5c\xc0\xbb\x6e\xa6\x7b\x95\x5b\xa3\xbb\x12\x0b\x0a\x5c\x62\xf4\xae\x36\x6e\x10\x05\xe9\xea\xc5\x77\x20\x95\x4a\x07\x1c\x86\x2b\xd0\x7b\x1f\xf9\x0d\xee\x83\xe6\x1c\x83\x18\x30\xb8\x37\x86\x7d\x09\x1b\x95\x36\x59\xe6\x2d\x14\x63\xc3\xf2\x6a\x20\xba\x98\x9c\xf0\xfb\xa1\xe0\x06\x8c\x15\xfa\xa0\x1a\x05\xb2\x52\x50\x56\x25\x53\x12\x09\xb8\x67\xb8\xbe\xea\x82\x1b\xea\x36\xe7\xb3\xf4\xe4\x4f\x86\xdb\xd4\x3e\x77\x42\xf6\xd7\xcc\xf4\xb1\x59\xe3\x4b\xff\x6a\xa6\x64\x07\x50\x4a\x67\xce\xda\x9c\x67\x09\x1c\x93\x97\xad\x4b\x74\x69\xf5\xad\xab\x95\x1a\xff\x25\xa0\xd4\xfa\x27\x0c\x9b\x8b\x55\xa9\x84\x79\xd2\x26\xa5\x30\xff\x3e\xab\x61\x06\xcd\x5d\x82\x72\x0b\x77\x24\x04\x8e\xb0\x96\x54\x60\xd1\xb9\xba\x76\x06\xc4\xea\x8b\xaf\x28\xa7\x62\xc7\x27\xa9\x60\x11\xa5\xc4\xce\x46\xa5\xce\xed\x56\xb0\x51\xa6\xab\xc7\x9d\x29\x62\x8e\x26\xd5\xe9\x5c\x6d\x87\xbd\x21\xed\x2c\xb5\x1a\x04\xc7\x87\xf5\x65\x78\xca\x85\xe1\xd2\x22\x8b\x57\x85\x2b\x73\x53\x75\xab\x66\x69\xe3\xe7\x76\xd1\x60\x8c\x77\x04\x2d\xb0\x50\x08\xaf\xec\xea\x15\xe3\x4a\x65\x96\x27\xe0\xaa\xd3\x2a\x59\x4f\x57\xd8\x12\xe7\x44\x5a\x46\x6c\x26\x7b\xd4\xee\x5c\x8c\x10\x9a\x45\x7e\x0d\x6f\x68\xce\xc7\xc6\xf1\x7a\xce\x70\x4b\x7b\xe7\x48\x16\xa4\x85\xc2\x22\x3b\x1b\x34\xdc\x3f\x68\x41\xdc\xb8\xb3\x7a\xdb\x4e\x94\x48\x77\x88\x38\x93\xb1\x82\xd1\xfc\x5f\xdf\x38\x9f\x19\x90\x6e\x43\x98\x46\x84\x16\x6d\x6e\x38\xf7\xbf\x53\x30\x13\x0c\x09\xe8\xe0\xbf\x2f\xbf\x2b\x9f\x0e\xdd\x74\xd4\x07\x6c\xc9\x81\x8c\xc4\xda\x62\x8e\x3e\xb6\xc4\x3a\x80\x4d\xce\xc0\x70\xa3\x6f\x70\x17\xfa\x19\x1b\xa1\x84\xe0\x22\xd5\x67\x97\x4a\xaa\x66\xb2\xb2\xd9\x95\xad\x17\x57\x8a\x23\xa4\x2a\x21\x18\xf5\x42\xec\x30\x8b\x7f\x13\x57\x35\x19\x62\xc0\x50\x2a\xb2\x50\x8a\x76\x19\xc3\x51\x6b\xa5\x48\x0e\x84\xc8\x1e\x25\x6c\x8c\xe0\xb2\x8c\x11\xdb\x50\xfc\x88\xc4\x60\x53\xb9\x3b\x0e\x9b\x98\x6a\x76\x0c\x1c\x3a\x00\xac\x73\x56\x67\x46\x38\x25\xb4\x04\x68\x36\x73\x7c\x60\xd7\x6a\x8a\xe1\xd2\xcc\x5e\xde\x9c\xca\xde\x3e\x0a\xc0\xf4\x22\x29\x80\x18\x64\x7d\xab\x5e\x53\xff\x45\xec\x38\xed\x63\x19\x5e\x02\x7b\x0c\x7e\xe6\x54\x1a\x95\xa8\x83\x2c\x7e\xcb\x36\x26\x05\x15\xf9\xaf\xb3\xb6\x8f\x62\xdc\x88\xb4\x04\x97\x94\xef\xf5\x0a\x99\x9b\x13\xcb\xee\x92\xe7\x49\x41\x06\x8e\x28\x70\x46\xe1\x6f\x99\xdf\x4f\x74\x4d\xcf\x4b\x61\x36\x85\xf0\xd7\x35\x75\xca\x96\x25\x23\x87\x27\xc8\x4a\x4b\x2c\xf0\x78\xe6\x85\xd4\x67\x9a\x84\x12\x69\xa9\xd2\xb5\xc5\x34\x97\xf7\x0e\x45\x66\x63\xe3\xe5\x2f\x5f\xc4\x51\x2a\x26\x87\x03\x66\x01\x9b\x48\xb0\xb8\x7c\xcb\x22\x47\x5f\x07\xa4\x8a\xf9\x58\x52\xef\x09\x55\x1a\x79\x98\x05\xe4\x9b\x3d\x34\xcc\x05\x1f\x04\x0e\xd8\x20\x46\x44\xae\x53\xa8\xae\x2a\x67\xf7\xf5\x14\x2f\x0c\x48\x79\x52\x88\xc4\xb6\x73\xc8\x27\x2e\x18\xd3\x78\xbe\xaa\xee\xfe\x8a\x0c\xa1\x68\x1d\x18\x6e\x42\x41\x0d\x94\x41\xba\xc4\x2b\x5d\xe8\x61\x06\x3a\x97\xad\x76\x42\x76\x12\xe6\xa3\xa9\xb1\x32\x07\xe6\xf6\x11\x2c\x58\x2d\x39\x98\xd8\xad\x2e\x98\x11\xd3\x3c\x12\xed\xeb\x9f\x81\xb6\x3c\x60\xc9\x2b\x39\x61\x1c\xd5\x79\xa2\x69\xc2\x14\x95\x22\x88\xbb\x95\x8c\xd9\xf6\x0f\x62\x63\xe8\x9a\x79\xe0\x3f\xb4\xe2\xef\x3f\xb5\x05\x56\xca\xcc\x30\xff\xba\x6d\x8c\x3b\x46\xab\x8f\x5a\x58\x25\x5c\xc0\xe4\x2d\x66\xfa\x32\x98\x29\x66\xce\xfe\x0e\xc6\x92\x59\x98\x06\x4a\x50\xa0\x34\x56\x64\x3c\x15\x28\xf2\x35\x68\xe5\x4b\x42\xb0\x51\x51\xfd\x0e\x02\x29\x51\x2d\x49\x08\x70\x30\x95\x5e\xd0\x2e\x8f\x47\x50\xe5\x0a\x6c\xae\xf0\xef\x53\xed\xaa\xc4\x59\x7c\xf1\x3c\x0e\xe9\xe4\xac\xe8\x89\x4a\x25\x30\xc4\xc6\x2b\x80\xac\x6b\xa6\x52\x32\x74\x12\xc6\x08\xb7\x01\x81\x32\x02\x42\x6b\x89\xca\x08\xef\xf1\xb8\x6d\x29\x13\x31\x1e\xac\x89\x5b\xc0\xea\x7c\xca\x0a\x6b\xea\x1c\x33\xb9\x55\xaa\x30\xfa\xd9\x50\xba\x0f\xa8\xf1\x42\x50\x0b\xdb\x74\x12\xed\xc3\x99\xec\x9d\xe5\x28\x1a\xc9\xe2\x59\x9f\x4b\xa7\xdb\x58\x19\x98\xc4\x54\xc2\x5c\x74\x22\x19\xa6\xc4\xd9\x4d\x8c\x8e\x97\x51\x9a\x78\x79\x39\x03\x0e\x4b\x28\x6c\x4d\x16\xe1\xb5\xf0\x71\x39\x91\x9f\x5b\xbc\xb0\x1f\x2b\x4f\x81\x54\x92\x72\xfa\x54\xa9\x49\x9d\x59\x1e\xe5\x56\x93\x46\x22\x82\x77\x5a\xcd\x2c\x57\x27\x20\x68\xed\xd4\x12\xeb\xb7\x12\xad\x10\x38\x1c\x2c\xc2\x07\x2d\x33\x81\x5a\x7c\x81\xe2\x67\xd1\x1e\xa5\x6a\x5b\x70\xdf\x16\x40\x5f\xa3\x92\x22\x5b\x8e\x5f\xb7\x94\xc5\x99\x79\xc4\xfb\x15\xd7\x42\x0b\x13\xa3\x93\x68\x6b\x40\x48\x87\x04\xda\x5a\x82\x3b\x8e\xdd\x9a\x9f\x6a\x88\xdc\x03\x81\x17\xfa\xb1\x21\x44\x7c\x83\xb9\x21\x25\x96\xa9\xbe\x3a\xf3\x10\x95\x7d\xd9\x08\x40\x4b\xf1\x4f\xe7\xe5\xc5\xe0\xf9\xf8\xa9\x5f\x81\x1b\x12\xfe\xda\xad\x6a\x16\x7d\x2d\x04\x64\xfd\xb2\xcc\x03\xde\xc9\xf7\x0d\xd3\x54\xc8\xb3\x62\xa8\xb3\xe5\x72\x12\x43\xa6\x76\x82\xe9\xf7\x5c\xe9\xdb\xb6\x23\xe4\x08\xa7\x0c\x34\x52\x3f\x43\xec\x7b\x54\x5d\x23\x95\x7f\x90\x66\xa3\x08\x0d\xff\xc8\x9d\xf1\xc8\x62\x11\xac\xbd\xfa\x8c\x87\x11\xde\x6b\x66\xe1\x60\x46\x5f\x2e\xc2\xb0\x91\x49\x94\xa4\xfb\xcf\xd4\x8f\x0d\x12\x8b\x82\xe0\x6f\xba\xa2\x6a\xc8\xf1\x17\x2d\x9c\x00\x90\x21\x60\x34\xb9\x31\xa3\x6e\xe0\xeb\x7f\x9e\x99\xa2\x9b\xa1\x0a\x3f\xbc\x1c\x42\x62\x48\xce\x4a\x28\x79\x1b\x13\xed\xeb\xc9\xaf\xe6\xda\x94\x7c\x46\xdd\x69\x86\x3d\x91\xef\xce\xe5\x0d\x11\x16\x58\x3f\xb5\xe6\x43\x6c\xaf\x0d\x22\x8f\x88\xd5\x3d\x09\xfc\x1d\x30\x6e\x4d\x94\x65\x29\xc1\x9b\x0b\x67\x70\x21\x91\x1e\xbc\x98\x24\xe3\xf6\xe2\xaa\x3d\xf0\xaf\xf5\xe3\x5d\xec\x9b\xed\x17\xef\x30\xaf\x1d\x40\x1e\x1c\x7e\x3d\x62\x04\xfb\xf4\x53\xfa\x2a\x3c\xbb\x06\xe9\x20\x72\x68\x58\x39\x8d\x32\x57\x2a\xb8\xdf\xbd\x6c\x8e\xe4\xed\xf6\x88\x83\x05\x89\x0f\x59\x2a\xee\x0b\x96\xde\xf1\x89\x31\xe5\x3b\x7d\x3b\x45\xca\xd9\xc2\xf1\xb5\xfe\x7e\xd7\xdb\x6c\x54\xa4\xac\x0e\x1b\x24\x7b\x72\xbd\xfc\xc2\x5c\x62\x14\xda\xa6\xd6\x06\x54\xbb\x68\x70\xe7\xf8\x9b\x66\x76\xf0\xf8\xd7\x27\xfd\x63\xc5\x6e\xbb\xd2\x6a\x36\xca\x91\x30\xc6\x98\xc0\xee\x56\x3d\xbb\x5b\x2c\xd8\x59\xea\x1a\xab\x89\x3c\x50\x3d\x64\x74\xbe\x5a\xc1\x5a\xd4\xe7\x28\xbd\x98\x4b\xb9\x7d\x23\x5d\xea\x89\x48\x65\x4b\xab\x68\x45\xd9\x96\x99\x4e\x80\xd1\x91\x99\xda\x75\xf3\x34\x28\xeb\xd3\xad\x71\x06\x45\xd6\x43\xa0\x79\x2e\x68\xbe\xca\x1e\x26\x83\x4e\x5a\xf2\x3f\x46\x42\x29\xbc\xd1\xb8\x3c\x79\xaa\x4f\x73\x54\xcc\xda\xf3\x44\x3b\xfe\x8b\x11\x94\x40\xe6\xb2\x88\x1e\x68\x0b\x90\x36\x4a\x66\x30\x17\x11\xab\xe1\x02\x77\x2e\xdd\xee\x78\x94\xf7\x23\xc7\x9b\xbc\x0c\xd3\x7b\x58\x51\xc5\xee\xfa\x82\x1d\x4c\x3e\xfa\xf5\xc7\xfb\xf5\x6d\xd9\x37\x1f\xd8\x12\xf1\x53\x4d\xb5\x44\x1a\x16\xf3\xde\x39\xaf\xbb\xb0\xdc\x2c\x78\xd8\xe3\x65\x78\x37\x65\xe0\x66\xc7\x6f\xcc\xc8\x09\x83\xf9\x6d\x58\x29\x23\x18\x13\x23\x84\xdd\x14\x82\xa4\xe6\x3a\xb9\xd4\x5e\x80\x19\x16\x3b\xca\x30\x5e\x4d\xfc\xa2\x19\xab\xb9\x86\x3b\x32\xb5\xcd\xd3\x07\x66\x5e\x24\x37\x5f\x9a\x14\x74\x62\xe3\x2e\xce\xac\x1f\x09\x9d\x9f\xbe\x04\x1a\x23\x30\x9e\x18\x0d\x32\x62\xf6\x3a\x21\x12\xc3\xf3\x08\x8b\xc4\x7b\xe5\x77\xf9\x76\x48\x46\x5d\xf3\x78\x6e\x76\xad\x12\xdc\x75\x99\xdc\x72\xa1\x01\x1d\x49\x16\x87\xdf\xd0\x9c\xe6\x6d\x25\xa9\xfb\xce\x98\x1f\x5b\x71\xc4\xa5\x1b\x56\x82\x21\x53\x6e\xb3\x4f\xa8\x90\xc5\xd5\xb7\x9f\xbe\x5f\xd6\xf9\x48\x88\x87\x7b\xa1\x69\xce\xf4\xc8\xe8\xd5\x8c\x94\x84\xe9\x55\x33\x98\x55\xf7\x13\x67\x94\x9b\x92\xf1\xf9\x2d\x42\xcb\xe9\x4b\x79\xb6\xf5\x25\xe6\xf8\xc4\xba\xd2\x9d\xaa\xd0\xab\xcc\x44\xea\x49\x00\xd2\x4f\xaa\x71\x14\x91\xa7\x4a\x67\xef\xf1\xf6\x2a\x6b\xf4\xa1\xd3\x0d\xed\x70\xc4\x5f\x6f\x28\x01\x58\x14\x6c\x15\xc0\x3e\x44\xf3\xb7\xf9\xdf\x7d\x5a\xf1\x15\x14\xd8\xe2\xff\xe5\x23\x1b\xac\x94\x5e\x32\x72\x4d\x34\x11\x49\x64\xc1\x0b\xd8\x42\x5b\xe9\xf1\x6a\x3c\x7a\xbe\x9d\x04\x3f\xb8\x62\x39\xc7\xdb\x2d\x39\xa4\x7c\x06\x07\x07\x8a\x44\x6a\xf5\xbe\x2c\x9b\x15\xba\x4a\xce\xf4\xae\xbc\x5d\xc0\x11\x24\x38\xa7\x44\xcb\x5d\x76\x52\x78\x73\x88\x4a\x0b\xb3\x06\x4d\x55\x64\x71\x6e\x9e\x7b\x9a\xe5\xd3\xcf\xa7\xe2\x5d\x1e\x84\x3d\xc4\xeb\xe3\x4b\x7d\xa1\x2a\x00\x53\xbf\x78\x20\xfe\xd4\x50\x0d\x2b\xe9\x13\x06\xa2\xe6\xc2\x5d\x65\x55\x82\xee\x8b\x78\x45\xa1\xff\xa6\x99\x04\x4b\xcd\x4b\xca\x7e\x49\x3a\x77\x95\x64\xc2\x29\x90\xaf\xc2\xf7\xa7\xe2\x0d\x07\xfd\x0e\x60\x83\x41\x31\x18\x39\xcb\x62\xdc\x9c\x67\x88\xb9\x12\x73\xfc\xb8\x94\x39\xc9\x94\xe4\x84\xa6\x4f\x11\xfd\xe5\x21\x94\x86\x03\xf5\xe3\xb3\xc7\xf6\xa6\x4f\x02\xbe\x9a\x61\xd7\x01\x8a\xab\x4c\x60\xcc\xe8\xe0\x81\x56\x33\xc8\xc6\xe6\xdc\xca\x3e\x4d\x16\x0f\xc9\xf1\xfb\x35\xf5\xbf\x28\x5e\x04\x71\x4a\x8a\xb3\xf9\xc8\x10\x73\x4b\xc6\x2e\x4e\xfd\x82\x47\x78\xc7\x19\x4f\xe0\xde\x4c\xeb\x77\x9c\xe6\xb7\xc5\xd2\x75\x13\x2a\x1a\x8b\x44\xf9\xdb\x04\x12\x2d\xc1\x12\x77\x96\x90\x4a\x0e\xc4\xf1\x78\xb1\x50\x47\xe5\x58\x26\x53\xf5\xab\x51\x33\xe5\xad\xf4\x7d\x49\x05\xa2\x8a\x7e\x0b\x52\x31\xe8\xa8\x51\x6f\x0e\x16\x85\x1b\x0e\x9f\xf7\xb6\x9c\xb3\xc9\x61\x7b\x07\xad\x9f\x9c\xec\xb9\xc2\xb6\x7f\xf7\x41\xcc\x78\xc2\x6f\xb8\x33\xbf\x93\x99\x3b\x44\x94\xda\x36\x40\x6d\x6b\x14\x05\x83\xb2\x9b\x91\x94\x1c\xda\x37\x73\x81\x8d\xb6\x6f\xb9\x1a\x18\xb4\x2d\x34\x6b\x92\xe3\xde\x23\x9b\xf8\x06\x30\xcc\xe2\xd5\x2e\x5c\x0c\xf0\x40\x1e\x80\xb6\xbc\x94\x85\x97\x14\x99\xcc\x68\x1a\xf1\xb7\xde\x00\xdd\x94\x50\x57\x15\xdf\x81\x40\xda\x1b\x81\x33\x06\x56\xb7\x6c\xe5\x50\x79\x01\x29\xf9\x98\x6e\x79\x9f\x43\xe9\xdb\xe8\x06\xb4\x05\x47\xfe\xca\x84\xd2\x89\xb7\x08\x7f\xd2\xcc\x99\xd5\x0f\x1a\x6c\x77\xe5\x45\xbb\x98\x85\xd1\x86\xb6\x34\x40\xb1\x92\x7b\xec\x20\x13\xae\x66\xe5\xc1\x51\x2a\x51\x1a\x31\x66\xfa\x40\x19\x9b\x83\x52\x18\x95\x19\x6f\x60\x5e\x6d\x92\x6a\xb9\xbd\xc0\xd7\x78\x5c\x97\xcc\xe5\x2f\x14\x02\x77\x18\xdc\x7d\x72\x79\x82\x1c\x3e\x77\x37\x6a\xe9\xe8\xbc\x4b\x25\x5f\x0f\x2e\x29\x0a\x36\xf3\x80\x44\x9f\x82\x30\xad\x8d\x45\x44\x64\xd2\xac\x16\x0e\x3c\x1c\x8e\x99\x97\xf4\x72\xbb\x40\x86\xce\x6c\x0f\xcc\x2e\x64\x52\xbd\xe1\xf1\xbd\x57\xcc\xb2\x50\x04\x37\xcb\x82\x1e\x1c\x47\xa2\xda\xa8\x24\x1b\xe2\xe6\xe0\x80\x6b\xfb\xd5\xe1\xbd\x32\xc8\x08\x02\x34\x1a\x3f\x92\x02\x9a\xe1\x46\x89\x2c\xe1\x17\xc5\xe2\xaa\xae\x2d\xcb\xda\xd4\xf6\x1a\x2a\x1f\x0f\xed\xa8\xaa\x79\xe2\x38\x71\x3e\x24\xe0\x62\x29\xe0\x7c\xa0\xfa\x25\x44\x8b\x8e\x4d\x6f\xd8\xa5\x38\x36\x88\x8c\x44\x9d\xd1\xe0\x09\x04\x64\x5c\xf3\x17\x0a\x45\x48\xa7\xdb\x88\x37\x17\x4b\x4c\xdb\x12\xc0\x54\x04\xb5\x3a\xc1\x48\x87\x5a\x9a\x88\xfb\xdc\xd2\x2f\xa6\x6d\xba\x15\x76\xaf\x07\xa4\x1c\x44\x45\x56\x77\x1d\x26\xca\x95\xf4\x1f\x52\xa8\x55\x44\x2b\xdb\x00\xd6\x0e\x76\x05\xef\xa4\x89\x22\x85\x2e\xb5\x21\x32\x35\x19\x32\xd2\x86\x99\x03\x8c\xba\x27\xb4\xd7\xb0\x04\x39\xbd\x3f\x03\xab\x64\x61\x4d\x43\x2c\xf2\xc4\x32\x3b\xaa\xd5\xa7\x9b\x71\x43\xa5\xa8\xf3\xea\x3e\xf9\x5b\x89\xdc\xc5\x35\x9b\x87\x35\xa8\x9d\xa6\xd0\xf3\xab\x1e\x69\xd1\x08\x0f\x39\xc3\x67\x60\xa3\x72\xa7\x16\xbc\x9f\x97\x87\x07\xbf\xd6\x2a\x67\x20\xeb\xa9\xaf\x1b\xc1\x0a\xbb\x2b\xc6\xb2\x46\x56\x67\xf3\x48\xbf\xc3\x20\xed\xd3\xba\x62\x6e\x28\xa2\xe7\x14\x08\x15\x72\xc3\x22\xb4\x9c\xe7\x06\x8e\x24\xd2\xa2\x7c\xaa\x72\xe9\x96\x3c\xc3\x14\x38\x9e\xc5\xac\xf3\x3b\xb0\xb4\xbe\xec\x1f\xe5\x21\x08\x07\xa4\x91\x4c\x30\xeb\xf7\xa2\x84\xad\x18\xac\x80\x62\x74\x1f\xe8\x5a\xf9\xb6\xd8\x11\x56\xe6\x5f\x44\xfa\xbd\x38\x28\x66\xb8\xe4\xb7\x2a\x57\x2e\x10\x5a\x74\xc6\x90\x0e\xb1\x20\xd5\x10\xe3\xcc\xd0\x1c\x4e\xbd\x2f\x13\x97\xe1\xd1\x27\x04\xed\x57\x87\x54\x2a\x19\x0f\x47\x46\xb8\xc2\xfb\xdf\xda\x99\x2a\x8d\xa9\x72\xff\x48\x33\x87\xd0\xb2\x75\xfa\xec\x70\x09\xe7\x34\x18\x5e\x9e\x7e\xa3\xea\xfd\x25\xf1\xbd\x45\x8e\xaa\x93\x7d\x5c\x48\x30\x25\x18\xe3\xa3\xda\xea\x6a\xe7\xa5\x6b\xa3\xad\x68\xa2\x4c\x8b\xff\x5e\x8b\x25\xa3\x7c\xe0\xd1\x8d\xb5\x43\x99\x92\xd8\xfd\x6e\x3c\x46\x50\x36\x9a\x37\x86\x66\x1c\x89\x3b\x7e\x79\x12\x1e\x3f\x22\x2f\x4d\x2d\x9d\x82\x32\xf5\xa7\x17\x2a\x00\x11\x84\xa7\xaa\x8f\xcd\x1f\x38\xfd\x24\x35\x2a\xa5\x7c\x38\xde\x29\x4c\x6f\x34\x53\xb4\xbc\xf6\x6a\x74\xd3\xd9\x54\x68\x1a\x79\x0c\x1f\x2c\x7e\xda\xb1\x45\x48\xd6\xe3\x64\x34\x01\x11\xdb\x3f\x64\x4b\x90\x60\x89\x15\x99\xa1\x40\xcf\x9b\xe2\x60\x77\x5c\xfe\x01\x0f\x69\x0d\x09\x6d\x44\x40\xdf\x99\x8d\x1d\xe4\x07\xc6\x57\x8e\xc3\x83\x07\x69\x25\xc4\x85\xbf\xef\xa5\xd6\x21\x13\x46\x5e\x8a\x01\x0d\x23\x15\x90\xfb\x41\x64\x4b\x71\x2e\xe6\xd4\x14\xef\x00\x08\x2b\xba\xf9\xb7\x60\x5d\x1d\x1f\x80\x96\x3c\xde\xee\x9d\x86\xce\xda\xdb\x9d\x0b\x97\x75\xe3\x39\x58\x20\xab\x5f\x92\x8f\xc7\x11\xde\xba\xf2\x77\xbf\x02\xcc\x28\x63\xaa\xa9\x91\x7d\xc8\x69\xff\xb2\xd4\x61\x33\x89\xd4\x24\x6b\x75\x52\x32\xb7\xcb\x5a\xad\x86\x59\xe8\xdf\x93\x80\x7d\x55\xb3\xfb\x9f\x9d\xe6\x5e\xca\x48\x8d\xb2\x7b\xd4\xda\x40\x57\x95\xe9\x98\xd2\x5b\x1f\x0a\x6d\x2a\xd3\xa1\x53\xb3\x18\x9c\x7a\x4c\xea\x63\xbb\xe3\x84\xd7\xf6\x0c\x06\x0f\xbb\x5c\x0a\xa8\x39\x20\x99\x0a\x62\x92\x45\xf7\x02\x87\x65\x9e\x41\x68\xa7\xdd\x6e\xae\x52\x2e\x35\x12\x68\x9f\x7b\x76\x3c\x4a\x14\xa4\x72\x11\xcb\x22\x1f\xb9\x49\x12\x2b\x21\xdd\x39\x16\x83\x06\xb1\x1b\x90\xf0\xb6\xbf\x3c\x4d\x8d\x65\x50\xc3\x92\xc7\xdb\xe8\x35\xc5\x79\x61\xe8\x48\x5b\x24\x84\xbf\x63\xb6\x71\x56\xa5\x69\xa4\x8c\xfe\x3a\x22\x41\x4a\x71\xc7\x40\x28\xda\x46\x91\xe7\x6f\x63\xde\x77\x76\x8a\x17\xd1\x55\x61\x41\xd5\xbb\xcc\x29\xd0\x8f\x13\x93\xfe\x93\xad\x06\x31\x9a\xaa\xc4\x79\xf5\x12\xb8\xa9\x4e\xd2\x20\xc5\xce\xee\x2a\x3e\x8c\x67\x3f\x46\x0a\xfc\xed\x64\xec\x9a\x1c\x75\xc8\xfa\x38\xe1\xa9\xcf\xfe\x54\xf0\x86\xd3\xa4\x7d\xfe\x29\x03\xe3\xd0\xc2\x26\xa0\x68\xea\x7e\x96\x59\x8a\x88\x43\x51\xd6\x6d\xf9\x62\x78\x8c\x1a\x6d\x92\x49\xd2\x4c\x35\x29\xeb\xe9\xed\xdf\xe3\x42\x9f\x21\xd6\xef\x10\xb7\x16\xe7\xdb\x8c\x13\x07\xd2\x04\xa0\x11\xa8\x3f\x6c\xfe\x9a\x0e\xe2\x71\x00\x62\xcf\x84\x27\x97\x1a\x5a\x7d\xe5\xa4\x38\x29\x08\xcf\x36\xd4\xb4\xa5\xfa\x0f\xc7\x03\xc8\xd4\xb9\x24\xe5\x32\x24\x0b\x43\x8d\x28\xfe\x2a\x36\xae\x75\xad\x25\x59\xa0\xb6\x2d\x26\x42\xdf\x81\x46\x70\x44\xb1\xc0\xbb\x97\x2f\x45\x2b\xa2\xbb\xc3\x23\xff\x39\xc3\x5b\xc5\xb5\x78\x69\xcb\x6f\x57\x32\x1a\x35\x6b\x66\xf6\x29\xb2\x7d\x51\xcc\xcd\xb7\x8f\x5e\x93\xe4\x55\xeb\xc4\x10\x8e\xc1\x47\x94\xf2\x93\x6a\x78\x48\xe8\xe1\x69\x23\x41\x4c\x7d\x46\x84\xda\x86\x11\x29\x3c\x50\xdb\x6b\x32\x83\xaa\x01\x85\xf5\x47\x08\x37\x61\x15\x53\xf3\x54\xdc\x19\x96\x29\xfc\x52\x57\x7e\xd3\x23\xa3\x12\xdc\x88\x0a\x22\x91\x99\x57\xd4\x97\x42\xf1\x39\xb9\x2d\xb4\x64\xa4\x26\xb9\x92\x86\x63\x79\xe2\x1c\xc5\x7c\x57\x1c\x0b\x6c\xaf\xe9\x40\x84\xf2\x90\x01\x9f\xee\x31\x9f\x5b\x67\xab\xac\x4f\x95\xc0\xfb\xa7\x26\x6e\x2c\xa7\x20\x06\xd4\x7e\x25\x78\xdd\xa2\x15\xb6\x9d\x26\x55\xf3\xc5\x16\xd1\xaf\x75\x03\x18\xd9\x46\xe3\x25\x14\x83\xbd\xfd\x13\x66\x8d\x9d\x88\x99\xd3\xb1\x8c\x05\xbf\x38\x92\x2e\x3c\xf0\x2b\x8d\x87\x91\x45\xef\xc6\x74\xab\x27\x45\xa3\xfd\x84\xfb\x4d\x69\x64\xaa\x75\x45\xe0\x14\xe0\x8a\xed\xfb\x55\xeb\x7c\x5e\xff\xa3\xe0\x53\x4c\xc4\xbb\x8b\xfc\xd4\xa4\xed\x64\x6f\xab\xc2\x7d\x5c\xdf\x98\x2e\x6c\x70\xb3\xe3\x07\x39\x4b\xde\xe9\xa9\xf3\x40\xe0\x5a\x52\xae\x17\x6c\xd6\xd8\x13\x9c\x3d\xd3\x6b\x62\x3d\xe8\xe9\xcb\xe2\x3b\xdd\xa7\x04\x24\xe5\x41\xd4\xda\x4f\x23\x58\x12\x12\x99\xbf\xb7\xfb\x57\x40\xc2\xcc\xec\x51\x9b\xad\x1f\x9e\x25\x6d\xb5\x83\x10\x04\x07\xdb\x2d\x6b\x8c\x75\x31\xa2\x8e\x2d\x79\x96\x5c\x18\x26\x70\x6c\x48\x7a\x3a\xd2\xeb\x56\x2a\xac\x2f\xbe\x4e\x10\x93\x04\x8c\xbe\xd0\x9f\x68\xdb\x42\xa2\x75\x38\x60\x8c\xc1\x83\xea\x6d\x80\x48\xd9\xa8\xc1\x3c\x5d\x29\xf7\xcd\xad\xf2\x81\x88\xef\xd6\x48\xb7\xf0\x48\x37\xfe\x59\xd0\xb7\x15\xe8\xe8\x99\x18\x85\x1e\xe3\xdf\xdd\x70\xe3\xbb\x7d\x18\x66\x75\x04\xf5\x2c\x12\x0e\xc9\x4e\x35\x1c\x39\x5d\xd7\x3f\x45\x64\xf4\x91\x08\x80\x3d\xbc\x24\x22\xe8\x53\xbe\x6f\x44\xea\x4c\x06\x8d\x24\x93\x59\xe1\x63\x24\x42\x7d\x49\x5f\x85\x4a\x85\x5e\x14\x39\x7c\xb5\x8a\x22\xc9\x8b\xa8\x41\x91\x18\xa9\xc8\xd4\x72\xf1\x7d\x6d\xd8\xfa\x1b\x62\x5c\xed\x1a\x6c\x9a\xb0\x9b\x34\x7f\xa1\x61\x9c\x45\x1f\xc7\x09\x5f\x5a\xcf\x02\x21\xd4\x71\x2b\xd7\xce\x36\xa2\x7e\x00\x11\x82\x1e\x79\x2c\x61\xf7\x05\xf2\x5e\xd7\x6a\x5c\xc9\x1d\xf0\x9f\x7a\x71\x79\x59\x72\x25\x7c\x7a\x66\x5d\x17\x86\x59\x53\x8b\x40\x6a\x15\xda\x4a\xd7\xdf\x63\xea\x3c\xf8\x3b\x99\xb7\xc0\x63\xed\xef\xf7\xe7\x9b\x9c\x42\x93\x56\x76\xbe\x89\x60\x6f\x47\xa3\xbd\x18\x3c\xf2\x46\xdb\xfc\x41\xf7\xfe\x1b\x25\x80\xb7\x0a\xc1\x92\xbf\x75\xbe\x65\x5e\x11\x23\x35\x54\x98\x5b\xa0\x2a\x97\xb8\xf2\xbf\x65\xb9\x0e\x87\xa4\x1f\xe6\x06\xb8\x90\x1a\x23\xde\xf4\x07\x9e\xda\xc7\x76\xff\xab\x40\x69\x18\x3a\xae\x6c\x65\xcf\x84\x3e\xe6\xa8\x0f\x23\xab\xd5\x7d\xff\x5f\x38\x54\xfd\x57\x18\x00\x8c\xe8\x6a\xc7\x61\xaf\xd0\xc0\xab\x5a\x49\x1c\x3a\x3f\xdc\x0f\xe1\xc8\x5c\x78\xdc\x70\x67\x7a\x1b\x46\x73\x09\xf4\xdd\xc3\xac\x87\x3b\x9c\x77\x53\x04\x30\xc4\xf1\x9b\xc5\x77\x75\x76\x5b\x6a\xba\x28\x47\x55\xba\xd9\x43\x82\xfb\x22\x3c\xdd\xba\xaa\x9e\xcb\xfe\x1a\x86\x6a\xe7\x87\x1e\x5c\xc4\x29\x35\x4e\xa0\x07\x9a\x37\x12\x01\x61\x83\x39\x92\x32\xef\x07\x37\x9e\xba\x75\x1b\xa1\xfd\xe6\x6b\x9a\xbc\x4b\x09\x4e\xfa\x78\x5d\x05\xf1\x92\x9f\xa1\x42\x83\xaf\x00\x18\xc2\x40\xa5\x4d\x2a\x5b\x42\x00\x50\x0b\x01\x26\x8d\x0b\x19\x71\xa0\x3e\x7a\xfd\x68\x8b\xc1\x9b\x9e\x30\x2c\x82\x4e\xb4\xe5\xd4\x28\x40\x98\xd4\xd8\x4d\xdd\xac\x96\x6a\x3c\x43\x16\x47\xfe\x82\xa3\x53\x89\xa6\xf9\x0e\x5c\x34\x0f\xad\x33\x3b\x04\xdf\x0d\x6c\x61\xa1\x8a\x23\x37\xed\xce\xd5\x30\x87\x59\xe9\x57\x0e\xa9\x2e\x3e\x26\xfe\x49\x6f\xd8\x35\x12\x88\x7e\x71\xc6\x71\x47\x8d\x78\xbd\x01\x4a\xa9\x75\x15\x09\x67\xdd\x2c\x45\xdd\xd8\x42\xf1\x9e\x24\xcd\xfd\xcc\x84\x91\xbc\xe3\xab\x08\xcc\x6f\x2f\x51\x85\xdd\x1d\xf5\x97\x25\xb6\x80\xb3\x59\xfd\x44\x07\x7c\xb5\xad\x0b\x12\x4d\xf7\x8a\xcf\xdf\xf9\xb1\x9a\x27\x87\x77\xb3\xa3\xec\xdf\x47\x06\xea\x6a\x72\x32\x33\x20\xb8\xfc\x22\x74\xde\x52\xa6\xcc\x84\x98\xc6\xc4\x11\x0f\xaf\xea\x8b\x88\xfb\x49\x58\x0d\x6f\xc8\xae\x01\x57\x1f\x73\xb5\xe3\x8d\xbd\x11\xb7\xb9\x7c\xf8\xf3\x1f\x2b\x54\x27\x3f\xd9\x62\x42\x07\xc0\x72\xf2\xe5\x7c\xf0\x5d\x5e\x0b\xd2\x76\xb9\xde\xa6\x6d\xab\x10\x83\xc9\x1b\xb1\xb2\x85\x35\xb2\x61\x6e\x1b\x1c\x1f\x0f\xd8\xd6\xe0\x3b\xce\xd5\x56\x16\x8f\x11\xbf\x7c\xd7\xe3\x1a\x8e\x9f\x76\xa9\x89\xc4\x2d\x4c\xa5\xb9\x61\xa7\x64\x4f\xc8\x48\xa2\x2e\xa0\xdf\x88\x10\x3d\xfe\xe7\x17\xae\x2f\xf2\x2b\x1f\x31\xcd\xfe\x98\xb0\xbc\x77\x8e\xc1\x17\xef\x75\x76\x0f\xf6\xd9\xfd\x12\x32\x8f\xf1\xa8\x18\xed\xd8\xbd\xfc\x04\xda\xff\x4e\xb1\x44\x32\x03\xfd\xf9\x11\xf3\x18\xee\xf1\xee\x4a\xbe\xa1\xbe\xd4\xe3\x05\x5b\xa6\x6a\x10\xb6\xef\x74\x38\x98\x5d\x9a\xcf\x8f\x98\x4a\xf0\xff\x86\xdc\x88\x58\x22\xd0\x53\x50\xcd\x09\x3e\x50\xc3\x47\x61\xbb\x38\x28\x7b\x58\xbe\xcd\xe9\xd2\xe7\xfb\x99\x5f\xac\x86\x4a\xa1\x66\xc1\x8d\x8a\x5f\x21\x46\xb9\xeb\x0a\x92\x92\x22\x52\xb8\x05\x21\x69\x83\x56\xf8\xdb\x11\x4a\x2c\xfe\xf8\x0b\xac\xa4\xdd\x28\x87\xbb\xf0\x63\xa2\x81\x1c\x97\x9a\x87\x08\x32\x8b\x53\x81\xe6\x6d\x39\x7d\x5f\xa3\x01\x2c\xad\x09\x88\xb8\x6e\x39\x04\x59\x77\x1b\x3e\x03\xd0\x2a\xcc\x3b\xf6\xa6\x4b\x41\x7b\x07\xea\xaf\x50\x1c\x6d\x2a\x20\x38\x77\xe0\xc6\x3f\xd4\x5e\x6d\x8a\x51\xdb\xcc\xba\x5c\xe1\xb6\x0a\xff\x55\xb4\x9a\xd5\xd4\x58\xcd\xb6\x02\xb4\x02\xd2\x71\x1f\x23\x7b\x04\x62\x05\xa6\x39\x36\xcd\x10\x88\x76\x38\x51\x54\xbe\xcc\x11\x8f\x36\x8e\x81\x04\xa3\x76\x3b\xa1\x06\x44\xf4\xf0\x2d\xc2\x06\xb9\x1d\xd1\x8e\xcc\x5a\x0a\x48\x72\x95\xa3\x2e\xee\x63\x0d\x42\xee\xdd\x6b\xe6\xb6\xdb\xb5\x17\x7b\x5c\x8f\xd8\x98\xac\xb2\xfe\x5b\xd6\x45\x32\x97\x95\xec\x6b\x28\xaa\xcf\x71\x66\x18\x5f\x30\x24\x3b\x57\xf9\xe8\x0a\x6c\x9f\x3a\xe4\xc6\xff\x05\x97\x5c\xc5\xfd\x30\xbf\x7e\xa9\xa3\x6f\xdc\x0b\xf8\x16\x60\x4f\x01\xcf\xad\x49\x02\x72\x24\x79\x07\xe0\xd6\x04\xff\x56\x24\x30\x1d\xe3\x19\x9d\xca\x66\xff\x91\x1f\xe2\x05\xde\xe0\x24\xd8\x35\xaa\xbf\x86\x89\xe4\x36\x18\xcc\x60\x8f\x78\x40\x56\x98\xbc\xfe\x1a\xd8\x8f\xbb\x10\x47\xe1\xa8\xdc\x01\x5f\x77\x92\x86\x6c\x65\x81\xe3\xcb\x5f\x4d\x08\xb0\x46\xe3\xca\x72\xa9\xe9\x1a\x2d\x5c\x56\xc2\xa1\x45\xc0\x5c\x00\x14\x92\x7c\x49\x0c\x48\x70\x24\x8f\x41\x30\xe9\x65\xff\x33\xbb\xb8\x74\x63\xf5\x1b\xd2\x70\x8f\x1f\x49\x68\xb6\x4b\x16\xb1\x4e\xb2\xe3\x25\xae\x7a\x50\x1f\x30\xc2\x29\xf2\xb5\xfb\x37\x84\x89\xfd\xd0\x60\x42\x34\x52\xc5\xbc\x75\x51\x3e\xa3\xdf\xdc\xf6\xf4\xf0\x88\x9f\x14\xd3\x42\x8b\xc1\xfa\x27\x2b\x84\x68\x24\x61\x6b\x35\x1a\x29\x32\xe0\x2d\x39\x3c\x80\x9f\x51\x97\x09\x61\x0e\x0e\x45\xf2\x7b\xc6\x9d\x04\x1d\x4a\x05\xcc\xb0\x6d\x26\x15\x06\x11\x11\x1a\x5c\x0a\x98\x00\xec\xd7\x5d\x19\x64\x19\x97\xc2\x54\x55\xdd\xc7\x36\xcf\x2e\x7d\xa5\xf4\x57\xa2\x7f\x23\xd9\x8b\x39\x0f\x3b\x82\x97\xca\xc2\xad\x4a\x63\x7b\x64\xd5\xc2\x2d\x7a\x18\xaf\x28\xeb\xe2\x4b\x02\x42\xcb\xea\x97\xa4\x9e\x5b\xb8\xd7\xfb\x66\xcf\x89\xe4\x5d\xbc\x8b\xef\x2c\xce\xce\xa7\x34\xea\xaf\x1e\x93\xcf\x5c\xff\x2c\x38\xe4\x93\x05\xa9\xd2\x38\xe0\x08\xf9\x03\x08\x90\xf6\x12\x1f\x91\x9b\x53\xea\x16\xb8\x13\x47\xcc\xbd\x0d\xa3\x17\xbd\xaf\xed\x37\x41\x59\xcf\x71\x14\xd1\xef\x08\x5b\x58\x2e\xa5\xb4\x33\x61\x02\xfc\x68\x2b\xf3\xd5\x7b\x87\xf8\x2d\xea\xe8\x7b\xa5\xc5\xac\xff\xbc\xd2\x6b\x0b\xd9\xef\xf2\x8a\x3e\x24\x37\xb6\x3a\xc7\xd3\xad\x30\xa0\xed\xc1\x7b\x6d\xa8\x54\x33\xae\x1b\xc2\x9c\xfb\x15\xe7\x02\xe2\x17\x78\xbf\x0f\x08\x98\x39\x8b\xdc\x74\x7f\x95\x0b\x45\x4b\xad\x46\x35\x61\xd3\xf7\x84\x58\x11\xc3\xa3\xf5\x24\xc2\xcf\x33\x60\xeb\x76\x05\x45\x4b\xad\xf1\x08\xa2\x5c\xf4\x0f\xdc\x90\x7a\x1f\x0d\x88\xd9\x4e\x2e\x4e\xe2\xda\xf2\x81\xb3\xfc\x35\x70\x58\x36\x52\xbb\x8b\x48\x3c\xb1\x49\xe5\x65\x81\x24\xef\x53\x2f\x3e\xc1\xbd\x66\x8f\x54\x0a\x16\x2a\x8a\x4b\x68\x90\x1e\x8e\x8f\xb7\xf0\x9d\xb9\xc4\x94\xd1\x2c\x62\x61\xd9\x13\xa5\xc3\x81\x9c\x30\x8a\x89\xdb\xe7\xea\xbb\xc8\x35\xd4\xea\x15\x71\x7f\x33\x4d\x80\xa7\xac\x07\x27\x9b\x57\x7e\x8a\x84\x4e\x99\x04\x92\x48\x79\x77\xb3\x4e\xa5\xfb\x77\x8a\xa2\x11\x4b\x82\x56\x27\x8d\x37\x51\xd5\x6f\x4c\x8c\x77\xdf\x6c\xd5\x15\xb4\xbf\xa1\xda\x25\x42\x55\x71\xfa\xf5\x41\x66\x5a\x38\x95\x0e\x9b\x88\xea\x52\x03\x2d\x04\x81\xd2\xc6\x1c\xd3\x11\x0d\xdf\x0a\x94\x48\x7e\xc8\x9d\x6b\x30\x2c\x0b\x3a\x6c\xaa\x32\xe2\x3a\x5e\x54\xc2\xa3\xa3\x65\xba\xa5\x1e\xb1\x4b\x9d\xe1\x45\xbf\x2b\xfb\xe5\xdc\xca\x14\x7d\xfb\xca\xc0\xf7\xea\x98\x79\xc1\x03\x64\x9e\x20\xd3\x5c\x34\x4e\x7e\x2c\xb6\x3a\x60\x92\xd7\x4d\xd5\x18\xee\x61\xdc\xa2\xc3\x1a\xdf\xd2\x8a\x78\xa4\x82\xa5\x26\xbd\x8d\xa6\x84\x47\x48\xdf\x49\xf2\x93\x3c\x5c\xd5\x67\xec\xa7\x96\x90\x21\x60\x2a\xf5\xe9\xaf\x8a\x17\xa6\x43\x30\x14\x2d\x5b\xdf\x11\x60\xd0\x44\xea\xce\x24\x88\x74\xae\x82\x73\x37\x52\x86\x21\x42\x52\x21\x0a\x5e\xf7\xc0\x5a\xaa\x2e\x38\x88\xba\xf2\xa9\x64\x61\x11\xe4\x2a\xc5\x11\x46\xaa\x46\xb2\x19\xa7\x11\x93\xf5\xbd\xb1\xa1\x50\xce\xf9\x6b\x6d\x33\x80\xb4\xb8\xcd\xbe\xb8\x6c\x48\xb4\x24\x80\x46\x82\xd6\x95\x2d\x96\x20\x7f\xc6\xf1\x0e\x97\x35\x90\xd0\x68\x2b\x3f\x39\xaf\x41\xf1\x51\x57\x44\xf0\x4c\x5c\xf5\xf1\x9d\x19\x15\x81\xd5\x5d\x6a\xe8\xd4\x1b\x78\xaa\x5b\xc0\xd1\x07\x3b\x8f\x21\xcf\x2d\xa1\x84\x0b\x9f\xa6\x07\x8f\x71\xbd\x0f\x42\x1c\x2f\x35\xf2\x50\x31\x35\xe4\x69\x91\x8d\xb6\xe8\x00\xda\xd2\x18\x22\xf3\xe8\x3c\xc8\x49\x87\x54\x3c\xc7\x8e\x74\x96\x50\x5b\x2a\xec\x56\x29\x47\x09\x41\xc5\xd7\x63\x92\xb2\x2c\x6e\x22\x6b\x99\x6a\x6b\xa2\x47\x17\x65\x22\x09\x95\xcf\x62\xa5\xd0\x48\x2f\xf7\x5a\xdc\xdf\xa5\xdd\x1d\xe8\x08\x1b\xe5\x28\x53\xe6\xbf\x17\x73\x48\xc2\x69\xa3\xb7\xca\xe1\xd7\x86\xd8\x2b\x62\x31\x68\x91\x95\x00\xf8\x4a\x69\x69\xc2\x24\x25\x73\x67\xf4\x6e\x76\x14\xa9\x36\x14\xe9\x70\xc8\x7f\x3b\x1c\x29\xb9\x05\x42\x31\xc3\x82\x49\x42\x19\x60\xaf\xdc\x4a\x07\x93\xf4\x9b\xbc\x45\x37\x52\x97\x79\x56\x5f\x18\xd0\x41\xce\xba\x82\x41\x2f\xf1\x46\x62\xa1\x11\xb4\x3f\x52\x8d\x1d\x5a\x2e\x02\x30\xde\x14\xdc\x37\xe3\xaa\xd4\x62\xd1\x5f\xfb\x8a\x16\xdf\xf5\x12\x6d\xcf\x8c\xd9\xb9\xaa\x0a\x78\x84\xec\x5e\x24\x21\xd9\x1b\x11\x21\x04\xdb\x09\x25\x6f\xf5\x82\xbd\x3e\xad\x9c\x36\xea\x6c\x78\x55\xde\x76\x71\xd5\x83\xc6\xc1\xd3\x59\x4c\x0b\x6f\xb5\x54\x23\x30\xab\x23\x87\x91\xa1\x17\xfa\x47\xd4\x62\x74\x25\x9a\xc9\x3a\xee\x6d\xbe\x51\xe8\x45\x0a\x93\xd4\x67\x22\x82\x5b\x60\x83\x25\xae\x80\xc8\x1d\x26\xe3\xdc\x78\x79\x88\x69\xd6\x3d\x8d\x5f\xd8\x26\xce\x6b\xf4\xdc\x3e\xf5\xe9\xe4\x6a\x96\xe5\x1b\x6b\x28\xc9\x8b\x92\xab\xc2\x83\x38\xbf\xed\x9c\x3c\x49\xe7\x82\x85\x68\x70\x36\x0a\x16\x29\xc6\xa2\x84\x37\x0e\xbd\xb0\xa9\x49\x2f\x9d\x00\xdd\x66\xc1\xe8\xfd\x00\x82\x23\x22\x9f\x05\xae\x21\xbb\x31\xac\xe8\xc2\x10\xd1\x99\x43\xff\x9f\xcd\x39\xd2\xd9\xcd\x1d\x72\xf7\x34\x6a\x68\xa6\xac\xf7\x50\x29\x77\x9e\xa3\xb4\xc7\x75\x5e\x97\x77\xde\x96\x07\xe4\x14\xb8\x1a\x29\xad\xe3\x28\x53\x21\x26\x19\x2e\x33\x9e\x1d\x07\x4f\x0a\x58\x92\x77\xa2\xe1\x3d\x69\x3a\x12\x2e\xb6\x71\x5e\x5e\x9a\xd2\x9a\xda\xf3\xc7\x1b\xa9\x2a\x5e\xeb\xc4\x70\x67\xda\x3f\xce\x09\xa0\xe3\x65\xc5\xbc\xf8\x68\x85\xe3\x36\xaa\x0c\xfd\xef\x3f\xe2\xf7\xe9\x70\xa4\x58\xe0\x86\x82\xcd\x6f\x76\xf6\xaa\xf0\x1a\xfc\x67\x93\x71\x44\x95\xd4\x7e\xf1\x8c\x67\x6a\xd9\x7f\x28\x08\x48\x06\xeb\x36\x96\x24\x3f\x82\xff\x20\xd3\xe0\x83\x8d\x18\x2c\xc2\x92\x7c\x4a\x9c\x13\x6a\x77\x12\xc2\x95\xb0\x8b\xea\x4b\xd9\x74\x32\x2d\xbd\xcc\x74\x30\x9c\x84\xf2\x1a\x2a\x74\x87\xcb\xf2\x59\xa5\x62\xa3\x09\x4d\x23\x29\x32\x61\xbc\xbf\xd3\x8e\x43\xa1\x9a\x54\xee\x34\xde\x87\x72\xf6\x14\xe9\xea\x24\x66\x74\xb8\x30\x1c\x12\x34\x1e\xc5\x2b\x9c\xac\x69\x84\x13\x46\xa5\x8f\x86\xe1\x5f\x09\xd4\xdd\xb4\x5a\xef\xf8\x72\x09\x4f\x74\x47\x93\xc7\xa2\x58\x7a\x5d\x54\x9f\xfc\x24\x8e\xce\x2f\x77\x07\xf1\x8a\xb0\x31\xf2\x95\xe0\x3b\x29\x4c\x5c\x89\x51\x83\x0c\x67\xff\xde\xaf\x1d\x5a\x98\x3f\xdd\xff\xf7\xdf\x6e\xd9\xe4\x5f\x46\x64\xd8\x44\xd2\xd6\x96\xef\xb4\x2c\x4a\x28\x47\x29\xbe\x98\x31\x5e\xca\x8c\x76\xae\x20\x30\xb4\x04\x5e\x03\xbe\x00\x1b\x39\x5b\x2e\x96\xea\xf2\x2b\xcc\xf6\xb1\x69\x2b\xa5\xda\xf1\xd3\x78\xb0\x4a\x95\xd9\xb3\xac\xc4\x60\x85\x6d\x68\x70\xff\x68\x91\x8f\xfc\xa1\x9a\xd1\xf6\x6d\x31\x1c\xb9\xa4\xf3\xc9\xf5\xc3\xbb\xf2\x3f\x4d\xc0\xc2\x3e\x4a\x31\xc6\x10\x88\x0c\xe0\x04\xd8\x66\xc5\x58\x03\x24\x63\x8c\xfd\x43\xda\x32\x03\x12\x3c\x8b\x9b\x38\x63\x20\x63\x29\xe1\xde\x73\xab\x2d\x27\x68\x0b\x3b\x03\xd8\xa5\x7d\xba\x85\xd8\x50\x50\x9c\xb5\x03\x1c\x76\x42\x50\x07\xa7\x3d\x49\xd6\x01\x86\x2c\x06\x26\x13\xb8\x7a\xc7\xef\x53\xd0\xfa\x05\xcd\x2a\xa6\xcc\x40\x00\x00\x08\x02\x9a\x02\xa8\xb4\xeb\x38\x6f\x72\xf0\x62\x07\xc2\x76\x66\x56\x5d\xf9\xa6\x83\x8b\x94\x6c\x11\x6a\x3f\x30\x49\x09\xa5\x30\xab\x23\xdd\x28\xa8\xa4\xae\x60\xf0\x50\x93\xf8\x51\x38\x54\x3f\xfa\xfa\xeb\xd2\xd0\x56\x52\xbc\x17\xc2\x7f\xd9\x07\x32\x9e\x19\x44\x11\x7c\xe3\x12\x31\x7e\xb7\xfe\xf4\x0a\x64\x20\x4a\x40\xc6\x7d\x0c\x09\x7a\xe0\xb2\x04\x46\xbf\xc5\xea\xad\x46\x7b\xd4\x7e\x51\x56\x13\x88\x62\x12\x24\xe2\x39\x5b\x54\x9b\x51\xc3\x61\x07\x31\xc7\xbf\xb7\xff\x61\xd4\xfc\xc0\xdd\x98\x3c\x6c\x9f\xd9\xc9\x96\xe5\x53\x08\x31\xab\x47\xee\xbb\xde\x40\xf8\xc1\xd4\xf8\xc7\xdd\xf9\xde\x64\x9e\xec\x23\x59\x71\x3c\x36\x14\x58\x64\x92\x19\xa3\x76\x8a\xb6\x0d\x4f\x8a\xcc\x54\x41\x45\x27\x54\xac\xfb\x9c\xc8\x86\x0c\xe4\x43\x1c\xf4\x93\x47\xd9\x01\x34\xa3\x83\x25\xf4\x9c\xb5\x36\x2d\xd6\xd7\xda\xb6\x51\x4e\xc4\x3a\xd3\x5a\x9a\xd6\xa4\x8e\x01\xff\x5c\xa4\x9f\x48\xbb\x73\x91\x93\x04\x34\x41\x63\x9e\x3c\xda\xbe\x7e\x73\x32\xcc\xb2\x16\xd8\x06\x6f\x21\xe0\xbe\x06\xe4\xd6\x22\xc9\xe9\x4f\x19\xf3\xb2\x06\xdd\xd5\xa1\x89\x60\xcc\xe7\x2e\xaa\xec\xd5\x71\xac\xcf\x54\x04\x75\xc7\x6e\xb9\xf7\xef\x9c\x49\xb5\xc1\x88\x38\x8c\xfd\x96\xa1\x77\x9b\xba\xca\x89\x52\x52\x37\xb3\x4c\x55\x22\x61\xec\x06\xb0\x53\x05\x21\xf4\xe1\x10\x2d\x91\x51\xf5\x18\x08\xf1\xfe\xbe\x97\x86\xba\x9c\x2b\x0e\x72\xa5\x90\x6a\x38\x1a\x61\xb2\x55\x14\xb7\x84\xd2\x2c\x79\x6a\xd7\x94\x68\x60\x3c\xf9\x97\x30\xdb\x0a\x32\x73\x88\x12\x6e\xc1\x0c\x2d\xa6\xff\xf4\xc9\xe1\x65\x71\x60\x25\x28\x81\x89\x12\x88\x65\x6e\x1e\x5c\x16\x1b\xdb\x77\x40\x93\x51\x1a\xab\x55\xd8\x71\xb2\x17\xe8\xe2\xfc\x4e\xd6\x88\x58\xaf\x1b\xfd\x1e\x64\xd1\x83\x3b\xb3\x57\xc4\xb3\x5e\xb8\x4e\x17\x61\xed\x96\x42\x42\x70\x2a\x99\x60\xc0\x60\x66\xb9\x1d\x4e\x84\xac\x18\xf5\xe6\x58\x31\x79\x64\x47\x00\xa3\x8c\x01\x67\xcd\xd5\x60\xf7\x38\xb6\xae\xcf\x4b\x9d\x92\x84\x5c\x0c\x8b\xa8\x24\x28\x06\xd3\x18\x28\x24\xb4\x58\x05\xb1\xb6\xf2\x8a\x55\x2d\xc9\x54\xd3\x18\x95\xfe\xc2\xd8\xe2\x1e\xb2\x3d\xd9\x9a\x25\x90\x17\x7f\xaf\x2b\xfa\xb5\x75\x29\x75\xc2\x3e\x8f\x06\x4b\x82\x24\x0c\xe6\xb7\x72\xec\x7e\x26\x3f\x99\xda\x47\xda\x9a\x3c\xf3\xc1\xe3\x27\x7b\x52\x4d\x6f\x52\x0c\xff\xa9\x9b\x07\x15\xa6\x93\xfb\x90\x4d\x7d\xf5\x1e\xaa\xae\x9d\xe0\xb7\x9b\xa1\x41\xe5\x1c\xdf\x91\x6f\x0a\x92\x03\x6d\xf0\x1b\x82\xe7\x4f\xc8\xd4\xbe\x09\x6b\xb5\xb9\x38\x50\xb2\xa8\x01\xca\xfc\x0d\x98\x76\xa9\xa3\x37\xf4\x94\xa5\xb4\x5f\x74\x21\x2a\x6d\x06\x62\xcf\xe7\x43\xb6\x5b\xa8\x7e\xbc\xcb\xcc\x1d\xab\x33\xee\xd4\xb4\x83\x10\xba\x92\xb5\x41\x28\x54\xf0\xe2\xb1\x21\x31\xf0\x35\x65\x62\x56\x2c\xcb\x2d\x5a\xe8\xdb\x83\xd3\x59\xc9\x79\xd5\x40\xd6\xfd\x0d\x98\x2e\xfc\x23\x5e\x86\x49\xfd\xe1\x57\x54\xcc\x2f\x14\xef\xf0\xbf\xec\xd8\xad\x33\x45\xc1\x16\x3f\x93\x19\xf2\x2e\xeb\x12\xb0\x13\xeb\x11\xbc\xdf\xbf\x9a\x0f\x06\x47\x49\x86\x36\xef\xf6\x79\x24\x4a\x82\xbe\x60\x4c\x76\xb0\xf2\x24\xd1\x2b\x97\x4a\xbc\xaf\x0b\xf2\xd3\x73\xb5\xbb\xb8\xd5\x1c\x03\xbc\x46\x6b\x4d\x3c\x71\xb7\x27\x7d\x5d\x0a\x1b\x42\x2f\xe5\xd9\x73\x88\xa7\xb2\x63\x7e\x39\x1d\x71\x32\x5c\xa8\xac\x1e\xcb\x1a\x02\xee\x5c\x5a\xf9\xa3\xcc\xb8\x83\xdc\x42\xff\x2d\x63\x95\xc1\x52\x15\xbc\xc9\x2c\x15\x81\x9c\xb4\xbb\xf4\xcb\x8a\xbc\xe9\xb2\xd5\x2b\x6f\x2d\x7f\xa9\xa2\x80\x79\x6c\x24\x82\x2b\xe7\x48\x69\x34\x58\x5f\x60\x96\xb0\xdd\x7e\xec\x32\xe9\x70\x33\xa3\xa1\xa2\xfc\xe1\x4a\xc9\x20\xa0\x00\xdc\xf3\x07\xda\x48\x99\x0f\xbb\xd5\xd1\xfd\xed\x11\x44\x00\x02\xbf\x75\x4f\x93\x12\xaf\xbd\x8c\x2e\x62\xbf\xb0\x64\x07\xb6\x1a\xde\x98\xf8\x95\x40\xa3\x75\xb2\x2d\x15\x45\xdd\xb6\xc8\xfb\xb0\xfc\x5c\xdd\x88\x15\x50\x70\x99\x12\x79\x42\x87\x40\x7c\x7f\x39\xf2\xc7\x5d\x58\xe9\xe7\xed\xa5\x88\x51\x44\x45\x78\xea\xde\x01\x5d\xb1\x9e\xd2\x99\x54\xe0\xfe\xc9\x53\x94\xcc\x27\xc1\xa8\x60\x99\x3f\x6f\x5c\x14\xe6\xab\x58\xd7\x58\x1c\xe2\xf2\xe5\x94\x70\xc3\x07\x11\x23\x21\x39\xb1\xe9\x78\x1f\x91\x68\x58\xa1\x6c\x14\xd8\xef\xba\x4a\x84\x71\x74\x9b\x18\xe2\x56\x9b\x36\x56\x1b\xa9\xba\xbf\x08\x87\xe0\x79\xf0\xc2\x2e\x85\x86\x06\x02\x69\x88\x51\xb8\x12\x65\xcf\x7a\x92\x18\x2c\xf3\x65\x34\xbd\xc5\xa8\x38\x2a\x5d\xd8\x3f\xa8\x25\x12\xa3\x12\xd0\x73\x21\x95\xc3\x3c\x3f\xf9\xf4\x80\x52\xf3\x73\xa5\xf2\xd8\x17\x6f\x0e\xec\x81\xab\xfd\x72\x2d\xc1\x84\x8d\xf8\xdf\x87\x96\xaa\x36\x49\x54\x03\x9a\x57\x43\x3c\x2c\x6e\x8f\x4d\xe6\x0d\x8a\x03\x63\xb4\xf6\x87\xbf\xb8\x33\x6d\x6e\x32\x21\x59\x72\x60\x93\x50\x4e\x64\x61\xb3\x24\x6a\x2d\x06\x67\x0f\x5c\x38\x26\x50\xd0\x14\x2e\xf9\x92\x39\x86\xd2\xc4\xc3\x9b\x7a\xf2\xf0\xd0\x52\xbf\x2b\x7f\x46\x2e\xb9\x28\xc4\x75\x81\xd2\x88\x74\x23\x49\x28\x2d\xda\x87\x5b\xd6\xef\xcf\xb9\x8f\xa9\x9c\xfc\x5c\x53\x9a\x8b\x65\xa0\x05\xb3\x1d\xe6\x1d\x02\x5a\xc5\x54\xe5\x65\xfb\xf1\x4d\x62\xa6\x3f\x87\x2d\xb5\xc9\xc2\xdb\xca\x4a\xdf\xe4\x7c\xf4\xf0\x75\x69\x9c\x76\xc4\x8c\x86\x81\x08\xe6\x72\x3a\x88\xd9\x2e\x43\xff\xa4\x3e\x3b\x31\x55\xeb\x2c\x5d\xbf\x53\x42\x83\x6e\x63\x18\x63\x75\x24\x46\xd2\x4d\x91\x5e\x85\xe0\x2c\x90\x30\xfe\x8e\xde\xec\xa8\x57\xa6\xd8\x17\xb1\x04\xc1\xbe\xe6\x61\x3e\x52\xa7\xae\x7b\x79\x92\xc7\x3b\xef\x0d\x7c\x2d\x3f\x66\xb5\x96\x20\xf1\x5e\x65\x2d\x3d\x68\x8b\x30\x01\x3d\x75\xc1\x7f\x57\x5e\x27\xd1\x6c\x05\xd2\xbd\xb7\xad\x1b\x74\x30\x63\xda\x07\x4f\x01\x87\xbb\xca\x68\x65\xe0\x79\x33\x29\xfa\x0c\x44\x54\x4c\x16\xad\x09\xa9\x6e\xf8\xaf\xe9\x96\xa8\x0d\x5b\xf6\xc9\xc4\x4f\xdc\x78\x55\x17\x0d\x22\xe3\xb7\x2d\xba\x32\xb7\xeb\x1d\x13\x4b\xc2\x73\x7e\xbc\xef\xa6\xff\x1a\x63\xbc\xfa\xa0\xe7\x40\xa3\x95\x4a\x1b\x0d\x8b\x34\x2b\x8c\x65\x6e\xd6\xf6\x1c\x75\x13\x46\x8f\x61\xd9\x8d\x01\xfc\x57\x32\x6b\xff\xe4\x67\x1f\x5b\x30\xe7\xf8\x12\x24\x74\x83\x23\xb5\x3e\x1e\x30\x84\xca\x27\x8b\x41\x7a\x89\x2c\xdf\x84\x4f\x9e\xb5\xe4\x81\x11\xa8\x94\x8c\x3b\xc2\x50\x06\xb6\x71\xdf\x0b\xa4\xf4\xbe\x9e\x64\x19\xf5\xc1\x4c\x44\x9a\x8a\xd7\xd5\x25\x40\xac\xa3\xdb\x85\x48\xe6\x2e\x15\x0e\xc6\xd0\x70\x8b\x5a\x2d\xa6\x5b\x2d\x9a\xef\x41\x74\x95\xa5\x2e\x70\xfb\x15\x03\x2c\x38\x0f\xd3\x8d\x34\x7c\x88\x19\x1c\x53\x4f\xe0\x59\xa8\xdf\x1c\xb7\xf4\x21\xd2\x6a\xd2\x7f\xfd\xcd\xcf\x67\xea\x86\xd7\xe5\x2d\x86\x5e\xfc\x7b\x42\xf7\x91\x6a\xf6\x10\xbe\x32\x4e\x7a\x78\xa9\x79\xd5\xcb\x4c\x56\x58\xce\xdf\xb0\xb9\x79\x18\x99\xd0\x0c\xc5\x68\xb4\xb7\xcf\xa9\xfd\x11\xaf\xe8\x17\x38\xfd\x8f\x55\xd2\x00\x33\xd6\x6b\x07\x02\x05\x09\x1a\x87\xc5\x77\x8c\x30\x35\xc2\x4b\x37\x64\x0e\xf4\x94\x95\x9a\x26\xe1\x39\xe5\xd5\x37\x77\x57\x3f\x72\x47\xda\xf4\xf5\xf7\x5d\xd1\xc4\x41\x5f\x11\x4c\x52\x8d\x02\x42\x03\x43\x63\xac\x49\xf1\x71\x26\x97\x76\x4b\x0c\x8a\x74\x3c\xa1\x43\x47\xaa\xe0\xbd\xdf\xfd\x41\xcc\x9e\x95\x3c\x77\x71\x39\xa1\x72\xa1\x2e\x89\x69\x68\x13\x85\x78\x54\xa8\xc3\xa3\xeb\xec\xab\x63\x6a\x15\xf3\xf1\x2d\x2f\x7f\xb0\x92\xc2\x32\x87\xbf\xc1\x77\x96\x33\xea\x13\x26\xeb\xa0\xf8\x05\xdc\xd3\xdf\x71\xb7\x26\x60\x59\x42\x4f\xda\xc5\x7f\xc8\xf3\xe5\x42\x98\xeb\x15\x1e\x69\x7e\x99\xe5\x7d\x04\xe1\x1b\x6a\xd5\xe0\xa6\x3e\xae\x23\x1f\xe5\x22\xee\x41\x5b\x74\xa3\xed\x74\x5a\x04\xe0\x65\x6f\x0f\x51\xc3\x0a\xe1\x93\x4f\x9f\x33\x6f\x8a\x97\xb7\x23\x8e\xff\xdb\x78\x58\x54\xcf\x30\xa4\xa1\x57\x16\x40\x8a\x36\x55\x13\xb2\xcd\x43\xaf\xed\xff\x7d\x8c\x52\x81\x3e\x63\xff\xbc\xfb\x42\xb5\xff\x9a\xa5\x2c\x57\xa6\xa5\x29\x06\xfe\x49\xc1\x72\x53\xbc\x03\xc4\xde\x37\x0c\xfb\x5d\x69\x1b\x21\x64\x8c\x5a\xa6\xd7\xbb\xeb\xaa\xfb\xeb\xfa\xb6\xba\xfb\x87\xe7\x96\x72\xd0\xcb\x16\xf9\x7f\xf8\x24\xa1\x2a\x9b\xe7\x5f\x7e\x49\x84\x7c\xd6\x53\xf6\x91\x02\xea\x5d\x52\xb3\xb8\x74\x3d\x2a\x87\x48\x0a\x5d\x11\xbe\x13\x62\xa7\x50\x55\x4f\x1d\xfa\xc5\xe8\x9f\x76\x82\x27\x23\xcd\x6a\x75\x72\x5a\xf4\xcb\xf6\x13\xf3\xf6\xcb\x1e\xf7\xd7\x32\x05\x99\x74\xd8\x2d\x50\x70\x77\xfe\x03\x33\xd5\xc5\x87\xd1\x26\x32\xd0\x2c\x71\x33\x10\x17\x5f\x91\xdf\x43\xb5\x5a\xfe\x84\xcd\x68\x82\x0b\x72\x90\x5c\xb5\xab\x57\x08\x4c\x04\x4a\x02\xa0\xd1\x14\x61\x64\xe1\xa0\x20\x32\x69\xdd\x7d\xf2\xfd\x0f\xa0\x44\xe1\x2a\x44\xfd\x70\xc2\x5d\x0e\x0d\x49\x2c\x5d\xd8\xc1\x47\xdb\x92\xbb\xf6\xc2\xac\x9d\x84\x83\x9b\xe6\x67\x74\x36\x09\xef\x9f\xb8\xc9\x1e\xc9\x46\x42\xc6\xcf\x64\x99\x72\x96\xf2\x20\x67\xa5\xd9\xb2\xb3\x57\x48\x4a\x98\x56\xa0\x62\xaa\x6b\xe3\x5a\xb6\x1e\x69\x34\x67\x39\x52\x1c\x4d\x3e\xc5\xa5\x59\xcc\x3f\x00\xde\x64\x13\xcd\x07\xc4\xab\x1f\x78\xb3\xf5\x62\x62\x1a\x36\x64\x92\x9c\x42\x28\x7b\xfe\xfb\xaf\x01\x21\x48\xb9\x31\xc8\x44\x6c\x71\xc9\x50\x04\xb4\x1a\xb8\x8d\x98\xea\x1c\x59\x27\x15\xb9\xd3\xc9\x1f\xb1\x9c\x10\xd0\xe5\xf7\xcd\x71\xb4\xc6\x99\x11\x28\x50\xf2\xe9\x25\x99\xc5\xc7\xe2\x1b\xba\x28\x70\x22\x6b\xb2\x93\xcc\xd8\x5b\x86\x69\x9b\x62\x78\x6f\xd3\x2f\x2d\x48\xc2\x38\x5a\xec\x1d\xe1\xc3\xf0\xf3\x4a\xe7\xc8\x01\xdb\x93\xb4\xd5\xfe\xae\x1a\x88\x5b\x86\x63\xf2\x68\x5c\xb4\x56\x05\xd0\x34\x46\x32\xd3\xbc\xca\xde\xbc\xc5\x1d\x42\xd3\x03\x71\x60\x23\x53\xbf\x06\x79\x19\x3f\xbd\x28\x15\x44\x23\xc3\xfd\xa9\xb0\x47\xee\xed\xef\x81\x8e\xeb\xfc\xa1\xa7\xde\x43\xc5\xa4\x7d\x7e\xc4\x99\x46\x4e\x85\x2a\xe5\x9e\x3a\x1f\x10\x6d\x27\xbd\x42\x01\x16\x03\xb1\xe7\x9a\xa3\x40\x9a\xb1\x6e\x28\x0f\x1d\xa7\x12\x0f\xa6\x9c\x4c\x86\x12\x03\x96\x86\xa5\x05\x94\x23\x95\x12\x2f\xee\x46\xb5\xca\xe1\x52\x4a\x6e\x94\xc2\x97\x8a\x5f\x9f\x8b\x4f\x7a\xd4\x9c\xef\x28\x24\x86\x51\x25\x32\x38\x2b\x28\xa1\xbc\x7d\x15\x22\x44\x9a\x31\xe3\x46\x02\xcf\x19\x8f\x90\xd6\xce\xaf\x7b\x8b\x4d\xf1\x2b\xa1\x65\xc9\xdc\xf5\x00\xb6\xfe\xf9\xa8\xb4\x0a\x2d\x0b\x65\x25\xa4\x06\xaf\xd4\x8f\x95\x98\xd0\xfb\x0d\x8d\x0a\xfc\x15\x3c\xb1\x99\xec\x0b\x93\xfe\x17\xb3\xb1\x90\xb8\x96\xc4\x15\x43\x39\xb5\xff\xdd\xc4\x43\x1d\xb4\x88\x7f\x18\xf3\x0a\xdd\xb2\x0d\x8a\x44\x59\xc7\x7b\x38\x71\x90\xcf\x4a\x41\x1e\x95\x12\x52\x60\x93\x1c\x9c\xdc\x95\x81\x09\x9e\xf6\x16\x87\x45\x36\xb5\x75\x3f\xfa\xd7\xfc\x37\xa6\x59\x1f\xb0\xf3\x2a\xbc\xd8\x32\x30\x38\x73\xeb\xba\xaf\xaa\x07\xaa\x1d\xce\xbb\x8a\xbd\xc5\x2c\x64\xa5\xbd\x38\x79\xdc\x95\xe3\x1c\x68\x4f\xb4\xd4\xe4\x89\xb8\xa7\x11\xdd\x1a\x16\x77\xd4\x3e\x9e\xb2\xf5\xb8\xca\x62\x80\xe0\x24\x97\xed\xf1\x7f\x84\xfc\x58\x0d\x8b\xfd\x43\x06\x3f\x91\x55\xdc\x7f\x23\x5c\x91\xb9\x2c\x70\x78\xa0\xeb\x8e\xf4\xcb\x60\x66\xc3\x26\x3a\x74\x7e\x06\xe9\xe7\x9a\x6b\x42\x7c\x19\x79\xd6\x7e\x14\x69\xd0\x84\xdd\x8b\xa0\xa1\x0c\x98\x44\x29\x1f\xf7\x49\x48\x0e\x2c\xe1\xf5\xd7\xb1\xae\xf5\x18\x23\x43\xc2\x59\xc2\x4e\xc3\xba\xb9\x88\xda\x0a\xae\x2b\x3c\x2b\xd1\x1b\xc0\x4c\x4e\xbd\xed\x37\x0c\x84\x81\x77\x30\x55\x69\xf0\x57\x75\x46\x99\x2d\x95\x8a\xa5\xbc\xff\xa3\x6e\x7e\x2c\xd4\x22\x26\x22\x88\x56\x6b\xd3\x1b\xd9\x88\x8c\x6b\x11\x84\xb7\x3a\x88\x97\x25\x82\xbb\x3d\xaf\xf8\x14\x01\x7f\x71\x34\x32\x86\x04\x4a\x28\x83\x04\x9d\x89\x0d\xe5\x41\x52\xf9\x2b\xff\xa6\xcd\x98\xdc\x62\xb8\x3b\xc3\xe3\xf3\xe2\x59\x99\xca\xdd\x1c\xf9\x9f\x3e\xa0\xe4\xa2\xa0\x94\x40\x4c\x5e\x81\x24\x6f\xb1\x61\xb0\xf5\xb3\x4c\x41\x42\xe0\xc6\xfe\x84\x88\xe2\xb7\x94\xf6\x34\x65\xdd\x7e\xd1\x0b\x1c\x94\x54\xe9\xd5\x51\xb0\x9a\x28\x44\xe6\xff\x03\xcc\x16\x33\xe9\x92\x41\xc7\x13\xf8\xc5\xa8\x4c\xfc\xfe\x0d\x9e\x78\xc7\x93\x0b\x84\x7f\xa7\x67\xa6\x9b\xb6\x0c\x64\x10\xf6\xd0\x41\xf3\xf6\x40\x80\xad\xc3\xde\x8b\x30\x37\x39\xb2\x05\x5d\x2f\xa9\xb5\xe5\x10\x84\x4c\x5c\x57\x82\x81\x0b\x14\x12\x88\x2b\xae\x2b\x33\x68\x2d\xe9\x16\xae\xdd\x56\x56\xe2\x6b\x09\xf6\x25\x06\xdd\x03\x04\x99\x54\xdc\x65\xb6\xa3\x75\x26\xf0\xcf\xa6\xc4\xc0\x87\x3d\x60\xc4\xc0\x30\x71\x9c\x43\x90\xe4\x86\xf8\x1c\x2b\xfd\xc2\x0a\x01\x73\x96\x33\x98\x48\xee\xbc\x99\x8b\xc0\x72\xc9\x37\x92\xf1\xdb\x06\xda\x98\x4c\xb2\x59\x23\x06\x60\x05\x87\x22\xf6\x1a\x0d\x0c\xb0\xa6\x18\x0c\xf7\x90\xa5\x79\x08\x0f\x60\x4b\x92\x37\x7b\xa4\xe3\x98\x55\x65\x8f\x4c\x95\xad\x58\xa9\x63\xa5\xf7\xbb\x82\x6f\x97\xc2\x58\x19\xe1\xe1\xb0\xe1\xf9\xc5\x31\xfa\xf7\x48\x8d\xec\x80\x9c\xf8\xe5\x17\x44\x39\x4e\x20\x6d\x29\x7e\x52\x22\xd8\x3e\x35\x9e\xc2\x06\x95\x2d\xb9\x16\x98\xe2\xf1\xfa\x0b\x4d\xfe\xda\x52\xb9\x8b\x63\xcd\x42\xef\x30\x68\x23\x8e\x39\x1c\x5d\x6e\xb7\xce\xd1\xc1\xa6\x0b\x5e\xc1\x08\x77\xaa\x1d\xaa\x7f\xeb\x06\xe4\x58\x41\x21\xf2\x24\xa8\x03\x99\x82\x71\xa1\x01\x13\x20\x12\x22\x4f\xb4\x68\x06\x4f\x30\x38\x51\xb9\xcc\xe0\xdc\x66\xa1\xf1\x74\x7a\xc2\x1f\xb1\x27\x23\x51\x2f\x21\x3d\xd0\xb5\x2a\xba\x17\xd9\xa5\x9a\x57\x74\x9c\x12\x04\x36\xfe\x5b\x14\xac\x85\x4d\x0f\x45\xfb\xa6\xcd\x91\x9f\xd2\x65\x66\xd2\x0e\xe4\x00\x28\x02\x11\x74\xbd\xc6\x47\xda\x47\x78\x67\xd4\x5d\x52\xeb\xcd\x41\x4f\x17\x7a\xfd\xb3\x33\xc9\x65\xad\x3e\x7f\x0a\xc4\x58\x0d\x32\xa2\x80\x50\xf6\x5d\xd6\xa3\x27\xac\x78\x9b\xe9\xc5\x65\x6d\x50\x86\xab\x99\x98\x59\x46\xdb\xd5\x0f\x38\x4d\x76\x4f\x2c\x4f\xd2\xb2\x28\x53\x3a\x15\xdd\x08\x60\x0f\x9d\x9b\x91\xe2\x5d\x86\xd2\xa6\x20\x65\x4d\x59\xea\xf1\xcf\x78\x4d\x20\xab\xea\x08\x90\xae\xc7\xe2\xb8\x83\x18\x2e\x72\x0a\xda\x92\x01\x98\x98\x16\x9c\x8b\xe9\xf0\xac\x2a\xcb\x01\x7f\x03\xe5\x32\xa0\xd9\x3a\xfa\xb3\xc7\x80\x53\x75\xc6\x21\x34\x0c\x4e\xd8\x6f\x6c\xaf\x93\x65\x33\x2b\xb0\xad\x08\x35\xeb\x30\x05\xe5\x27\xf4\x9d\x03\xa0\xf7\x35\xe0\x86\x4d\x8a\x20\x61\x97\x8e\x43\xa4\x8a\x08\x99\x36\x46\x8b\xe3\x34\xd8\xea\xc0\x48\xfa\x84\x51\x33\xe7\x45\x18\x87\x7a\x12\x41\x81\x16\xc4\x07\x8e\x75\xc3\xa1\x69\x49\x8c\x20\x27\x21\x3c\xa3\x3b\xb7\x50\x2d\x93\x96\xe8\x92\xcc\xab\x45\xe0\x07\x30\x26\x2b\x75\x0a\x62\x75\x87\xb5\x09\x58\xe6\xec\x98\x9f\xe2\x01\xe5\xea\xbf\x2d\xa2\x01\x23\x9b\x47\x62\x47\xe3\xad\xeb\x73\x66\x24\xa4\x05\x12\x52\x39\x92\x96\x5d\x8f\x77\xa9\xab\xf0\x95\x99\xc4\xab\xee\xa0\xda\x12\x23\x92\xae\x36\x76\x3f\xb6\xd7\x1f\x9b\x68\xc4\x96\x13\xed\x92\xa2\x4f\x2d\x2e\xa6\xf0\x08\x34\xac\x91\xa5\x80\x41\x79\xe1\x25\x64\x8d\x38\xc2\x65\xde\xc2\xd0\x6d\x03\x2f\x1b\x99\x02\xf8\x90\xc1\xb2\x37\x74\xdc\x5a\xb7\xbe\x62\xc0\x9f\x8c\x4e\x91\xcb\x1d\xdc\xbe\x31\x6a\x07\x13\xcd\x80\x49\x10\x87\x05\x14\x9c\x71\x89\x8b\x67\x40\x46\x70\x7b\xc6\xf1\xf0\x42\xf9\x6e\x7c\x79\x58\x8e\x89\x44\x94\x82\xe4\x15\x41\xd0\x45\x10\x14\x9d\x17\x21\x42\x07\xc3\x37\x13\xbb\x7b\x42\xd8\x3e\x52\x9c\x9e\x9a\x37\x26\x7e\xbb\x70\x55\xb9\x63\x76\x63\xb4\x96\xe6\x91\x61\x1a\xfd\x1c\xab\x44\x2b\xd8\x6c\x48\x30\x50\x43\x23\xc9\x75\xb4\x39\x90\x05\x1c\x41\xfb\x86\x76\x14\x11\x5a\x9d\x2e\x17\x46\xfe\x1d\x7a\xbb\xfb\xac\xe3\x4d\x89\x4a\x7d\xbe\x2a\x6b\x24\xc9\xbf\xd9\x29\xea\xe6\x5e\x0f\xed\x51\x25\x82\x4c\x10\xd0\x9c\x0f\x8b\x6d\xfc\x99\x5f\x96\x16\x9a\x62\x24\xfe\x0a\xa7\xaa\xe4\x01\xb5\xb1\x04\x49\x85\x4a\x0c\xc0\xfc\x4d\x0b\x0f\x98\x6f\x1d\x4e\x5f\x53\x70\x2d\x91\x9e\xcc\x7c\xd7\xa7\x94\xef\xfd\x57\xdc\x56\xc4\xa8\x46\xb8\xfd\x85\xf3\x75\xba\x38\xa0\x0a\x23\x02\x64\xbb\xbc\x10\x14\x20\x2f\x6d\x6d\x6e\x06\xc7\x13\x7f\x68\xf0\xae\x4f\x99\xd3\xb6\x17\xd3\xb7\xa6\x0f\xd1\x9c\x98\x53\xd1\x98\x0a\xd4\xf7\x91\x0b\x5c\x8a\xc4\x14\xe3\x81\xa3\x9c\x1a\x60\x3c\x44\x11\xde\xb0\x70\xe5\x5d\x2f\xac\x01\x55\xa4\x2d\xad\x0a\xc1\x0d\x22\x98\xe8\x47\xd6\x7d\x86\xa8\x9d\x7e\x91\x54\xed\x74\x97\x9a\x71\x1b\x15\x08\x6d\x73\x59\x15\x5e\x01\x94\x2e\xf4\x23\xec\x21\xaa\x3b\x88\x0b\xa9\x05\xa3\x6e\x6e\xcc\xd2\xd0\x48\x5e\x8d\x23\x06\x45\x03\x78\x7e\x15\x11\x41\xdc\xc6\xde\xf3\x11\x86\x13\xc4\xbe\x01\x4b\x41\x08\x29\x6c\x43\x40\xcd\x5d\xeb\xd2\xfc\xd0\x08\x51\xc4\xbd\x9b\xdd\x0d\x91\xd1\xc0\x46\x6e\xb5\xdf\x3c\xf0\xe8\x6e\x83\x16\xab\x4b\xa1\xdb\x32\x82\xb5\xe2\x7e\xc0\xcd\x15\x3c\xc3\x83\x31\x5b\x27\x42\xca\x2c\x31\x06\x1d\x6b\xef\x70\xbc\x61\x62\xe8\x9c\x4d\x9f\xcb\x0a\x4c\xb0\xf2\x04\xf6\x95\xf8\x7f\x08\x80\x49\x32\xc3\x00\xd3\x2a\xe4\x86\x7a\x7b\x5b\xeb\xb2\x06\xb3\xd0\x4c\x0d\x95\x4c\x31\x3c\xb1\x81\x22\x48\x9d\x8d\x2d\x5c\x11\xd0\xb9\x6f\x35\x5d\xbc\xac\x88\xa2\x2e\x93\x3d\xac\x47\x75\x68\xf2\x93\xaa\x65\x4f\xc1\xc9\x43\xd4\x68\xac\xbb\x94\x50\x0a\x90\x96\xa5\x4d\x46\x4b\x5f\xe6\x47\x7a\x78\x36\x27\x9d\xd8\x2d\xf9\x09\x93\xad\x52\xc6\x66\xd1\x05\xb1\xd6\x66\xde\x0c\xac\x00\x79\xd1\x32\x30\xe0\x7f\x71\xfb\xdb\xe9\x5a\xde\xea\x96\x99\xe4\xd8\x9e\xf0\x4a\xe9\xa8\xec\x9b\x18\x5c\x47\x46\xf0\xbd\xc1\x0b\x08\xed\x0a\xd8\xaa\xeb\x88\xc5\x29\x20\x50\x26\xce\x1d\x77\x6c\x60\x29\x05\x60\xbd\x83\x74\xaf\x1e\x40\x38\x29\x01\xae\x31\x86\xd3\xbc\xad\x12\xb9\x94\xf8\x2b\x13\x2f\x62\x38\x21\x2c\x85\x07\x41\xd9\x71\xc3\x6b\x3e\x85\x15\x1b\xbe\x29\x75\x46\xb3\xdb\x2b\x92\x21\x39\xea\xee\xb1\x24\x33\x9b\x83\x95\x36\x3d\xfd\xc3\x96\x76\xe4\xd4\xf7\x4c\x4f\x43\xe1\x0a\x9f\x3c\x2d\xbf\xf2\xad\xd6\x83\xc7\x0a\xfc\xc2\x7e\xa4\xe9\xc4\x19\x20\xa1\x7a\xda\xb9\x0a\xcc\x4a\x0f\xa7\x26\x63\x02\xd3\xa8\x34\x38\xe0\x06\x4e\x0e\x48\x1d\x0c\xeb\xae\x5d\xb4\x93\x84\x7d\x21\xae\x92\x1e\x19\x1c\x89\x5b\x52\xa7\x91\xe9\x96\xa0\xcb\x84\x63\xf4\x41\xc9\x23\xa7\x90\xbf\x6d\xd8\xdc\x0f\x98\x84\x64\x0e\x42\x2d\x84\x8e\x08\xc7\xe4\xa0\x53\x6e\x4b\xdc\x5b\x03\x9f\xf8\xeb\x13\xd4\x15\x8c\xbe\x4a\x2c\x15\xfa\xca\x4a\x98\x55\x46\x67\x37\xa5\x4e\x30\x85\x94\x18\xc9\xf3\x32\x75\x79\x3b\xba\x11\x1a\xe2\x34\xe0\x61\x98\x94\x26\x90\x88\xb3\xde\xfa\xd9\xea\x8c\x45\xc4\xdb\xb2\x5c\x2d\xb0\x64\x53\xf3\xb5\x86\x28\x4b\x12\xca\xc8\x95\x18\xc1\xce\xb5\x40\xf0\x52\x90\x57\x26\xb9\x3d\xc7\x36\x7a\xf6\xfe\xe4\x93\x3f\xfb\xed\xc6\xc8\xf4\x0b\x52\x3c\x62\x62\x80\xa9\x14\xa0\x07\x60\xa2\xe0\xbb\xa1\x73\xfe\xc2\x8c\x6e\x7a\x09\x30\x17\xc6\x4b\x1b\x82\x2a\x91\xd2\x14\xd5\x6d\x29\xba\x9a\x94\x8b\x07\xcd\xe8\xa9\x8f\x9e\xf4\x62\xdc\x67\xc6\x9d\x7b\x26\x22\x37\x5d\xe6\x64\xfe\xdd\x15\x64\x34\x91\x91\x0e\xf3\xd7\x4d\x26\x90\xfe\x1d\xb0\xc3\x73\x91\x57\xa4\x7e\x76\x86\x66\x04\xaa\x43\x72\x07\x64\x51\x06\x59\x46\x87\x9a\x2b\x5d\x05\x48\x2b\x75\xca\x29\xe7\xc2\xe1\x81\x89\x4c\xfc\x68\xe0\x32\x31\xbe\x5a\x53\x0a\x2a\x02\x68\xae\x52\xcf\x07\x6e\xef\x4f\x15\x94\x43\x1c\x10\x2e\x58\x02\xb6\x70\xe9\xa1\x56\xba\x67\x97\x1c\x30\x88\x3c\xf1\x8f\xdb\xa7\xf0\xdd\xa7\x47\x0c\x01\xc5\x6f\x46\xa7\x9a\xfa\x35\xba\x2b\x43\xc5\x94\x9e\xdd\x31\x86\xf7\x5f\x2b\x88\x0b\x33\x19\x87\x14\x32\x6d\x98\x84\x4e\x3d\xd0\xe3\x89\xf0\x19\x96\x87\x65\xd1\x64\x00\x18\x70\xb4\x30\x6c\x78\x10\xd0\x61\x12\x2f\x68\x65\xe6\x8f\xd6\x40\x61\x26\x7a\xdc\x2a\xf8\xc8\x89\xc9\x5e\xbe\xce\x2e\x68\x42\x94\xf1\x99\x1a\x0b\xa6\x53\xda\x58\x4e\x1f\xf3\x7e\x7e\x7e\x2c\xdd\xac\x9a\xae\x8c\x00\xf9\xe2\x10\x72\x30\x7d\xf7\xf6\x4a\xf1\x41\x91\x12\xde\x0e\xca\xa4\xcc\xfe\xd0\x43\x44\xcc\x1c\x73\x64\x38\x14\x86\x96\x42\x83\x85\xca\x2c\xf1\x12\xa5\x59\x51\xe8\x66\x77\xd4\xac\x5f\x3a\xb9\x8b\x96\x21\xc0\xa3\x11\x8e\xaf\xdc\xc3\x7a\xdd\x3b\xdf\x68\x22\x00\x32\x7b\xca\x04\xff\x1c\xdd\xe2\xcf\xfc\x2d\xad\x01\x3f\xce\x43\x01\x7e\x03\xaa\x58\x53\x53\xc6\x7f\x0f\xa8\x13\x08\xff\xc8\x58\xd5\xfc\xdc\x7b\x4f\x34\x0a\x49\x07\x09\x87\x60\xcc\x0b\x44\x78\x0e\xe3\x48\xc4\xa0\xae\x27\x50\xa3\x9a\xe9\x9c\xe6\x4a\xfb\xeb\x05\x4d\x01\x17\x23\x10\xae\x89\x85\x2c\x4d\x40\xa4\x9c\x22\x83\x02\x3b\x7c\xee\x10\xb3\x40\x2d\x47\xb3\xb4\xd1\x92\xe5\x05\x4e\x2c\xd5\x89\x9e\x6c\x70\xaa\x65\xa6\x41\x2c\xee\xe3\x97\x22\x95\x24\x07\xa0\x04\xb8\x2d\x40\x7c\xea\xec\xbf\xc5\xd4\xea\xb2\x9e\x30\x44\x09\x07\x39\x7b\x39\xc5\x48\x15\x07\xf6\x52\xe1\xde\xf9\x9d\x90\x1d\x2b\xb0\xbe\x59\xa4\xe2\x65\xc4\x92\x58\xb1\x46\x63\x02\x56\x12\xa8\xdc\x2e\x8d\xfd\xe0\x37\x2b\x5c\xcc\xdc\xe0\x56\x29\x20\x4d\xa9\x6c\x5c\x5b\x61\x7d\x94\x1c\x7d\x7c\xd3\x99\x5b\x1a\x21\x5c\x11\x2c\x38\x29\xd4\x72\xfa\xee\x45\x4a\x3f\x18\xb1\xe6\xef\x8b\xf2\xe0\x5d\xd6\xc6\xc1\x38\x3a\xda\x46\x80\xd6\xf0\x22\x6f\xbd\x43\xc4\x29\x71\x22\xab\x83\x49\x6d\x2a\x05\x5c\x26\x22\xba\x54\xaa\x8e\x22\xeb\x5d\x53\x06\x6c\x87\x34\x7a\xb9\xd1\x0e\x88\x29\xef\xf4\x59\x91\x40\x46\x8b\x5e\x06\x1a\x74\x0c\x3d\x1a\xb9\x86\x61\x11\xf1\x93\x14\x26\x94\x84\xf3\x41\xb6\x68\x1a\xac\xad\x50\xd5\x15\x69\x1d\xce\x22\x04\x51\xb5\xa6\xf7\x7c\xb9\xad\x52\x75\xc8\xf5\x00\xcd\x66\x39\x62\xcd\x05\xa6\x31\xbf\xc5\x4b\xff\x8a\x99\x36\x7c\xf8\x5a\x7b\xfc\xfe\x09\x9f\xc4\x0b\x92\x14\xa4\x6e\x43\x39\xb9\xad\x87\xf7\xb4\x1f\x6a\xef\xd4\x9d\xb8\x07\xb2\x53\xad\xce\x01\x55\xdf\x21\x46\x26\xa3\xd5\x87\xcf\xa4\xde\xf7\xa9\xaa\x07\x9f\xa8\x72\xda\x0f\x70\xd2\x03\xd5\x7e\xf4\x9f\x12\x90\x96\x62\x3d\x2f\x1c\x8b\xc7\x61\x3e\x96\x91\xa0\x3c\x5c\x2c\x8b\x14\xd0\x44\x49\x32\x36\x41\x4d\x9b\xa0\x48\x40\x8a\xa6\x18\xe3\x3a\xa0\x69\x1f\x87\xd9\x7a\x9b\x9a\xd7\x18\x66\x41\xdf\x0a\x66\xf6\x67\x51\x7f\x2c\xf6\x63\xd6\x19\x68\x5a\x10\x3c\x66\x64\x7e\xb9\x64\x41\xde\x6e\x3a\x8a\xea\xb8\xc5\x33\xd8\x24\x13\xfe\x5d\x36\xf2\x51\x50\x44\x1f\x19\x7d\x61\x76\xe5\x40\xbb\x30\x9d\x37\x31\xd4\x00\xa8\x5b\x84\x16\x29\x18\xa9\x1d\x80\x46\x3f\xe2\x58\x1e\x72\xdb\x3e\x80\x20\x55\x78\xa1\x77\xca\xeb\xe3\xfb\x78\xd0\x11\x88\xf0\xe3\x08\x80\xf0\xe7\xd4\x6d\xe0\x45\x05\xbb\x38\x2d\x27\x5b\xb9\xc1\x22\xea\x8b\xfe\x38\x63\xc1\xb9\xd1\x2e\x25\xe8\xe7\x16\x0c\x13\xbe\x52\x1d\x47\x92\xee\xa3\x2b\xd0\x21\x55\x27\xc0\x38\xfc\xb9\xbf\x6c\x1e\x88\x2a\x08\x55\x77\x3c\x6a\x0f\x4d\xa6\x39\x4f\x0b\xd1\x58\xed\x48\x63\x61\x90\xcb\x67\xa8\x46\x9f\x6b\x17\x29\x94\xd6\x01\xab\x4b\xb8\xae\x0c\x6b\xc6\xdb\xd1\x0c\x46\x2b\xc0\x43\x3a\x28\x06\x7e\x0b\xff\xa5\x76\x71\xe3\xa2\x82\x46\x7e\x3b\x3f\x9d\x15\xc8\xdf\x6c\x41\x09\xde\xa9\xe9\xd4\x0c\xf7\x4a\x83\xdf\x16\x6e\x20\x04\x96\xa2\xbf\x52\x6b\x30\x12\x3a\xce\xe0\x19\xb7\xc8\xb8\xf0\xa0\x77\xd2\xdf\x0d\xf1\xba\x6f\x0c\x1d\x94\x42\xb3\x4e\x8d\x1c\x7f\x0f\xb0\xc3\x99\x2c\xc7\xb3\xd4\xb9\x2a\x79\x34\x85\xf7\x05\x5e\x08\xbe\xf8\xc7\xa0\x38\xb0\x85\x7a\x97\xe6\x96\x13\x40\xf6\x86\xae\x40\x31\xcf\x71\x31\xc1\x24\x0b\x1f\x8f\x5b\x16\xda\x8d\x04\x31\x0b\x95\x61\xc8\xf1\xe2\xad\xab\xae\xa4\x34\x33\xc2\xc0\x6c\xcf\x0b\x26\xda\x3f\x1c\x44\x57\xc0\xc1\x13\x3f\x1a\x23\xa3\x81\xcf\xb2\xfe\x18\x27\xfc\xa3\x83\x06\x84\x42\xf8\x67\x35\x8e\x1a\x40\xcb\x71\x16\x14\xcd\xb9\x29\x12\xbb\xf2\x18\xb9\x7d\x57\x4f\xaf\xa2\x47\xe4\xbe\xa9\x1a\x12\x98\x30\x19\xcd\xb8\x24\x88\x40\xf7\xe2\xb5\x0b\x7c\x04\x34\xd2\xf7\xc0\x65\xc5\x89\x20\x92\x52\x00\xfa\xa3\x7f\xbe\x59\x24\xd8\xca\xe5\x00\x86\x53\x20\xd1\x58\x2a\x85\xfe\x77\x19\x2a\xf6\xac\xba\x00\x0b\x2d\x28\x1a\x0e\x23\x4b\x7c\xe9\x3c\xc0\xe9\x83\xfb\xb5\x38\x25\x1a\x4e\x1f\x66\xe8\x27\xeb\x60\x82\x9a\x25\x0d\xed\x7f\xc3\x9f\xe4\x2c\x82\x11\x47\x1a\x34\x04\x65\x32\x36\x29\x59\x33\x78\xf5\x30\x09\x17\x4f\x8a\xe6\xac\x7c\x85\xa3\x64\x82\x8c\xc0\xd8\x64\xca\xff\x21\x4b\x6e\x96\xd5\xa9\x52\x27\x8d\x70\x54\x04\x1a\xb3\x87\xbb\x51\x85\x5a\x2e\x8f\x2d\x84\xde\x3d\x80\x08\x0c\x9b\x4e\x2a\x88\xa6\xc3\xb6\x44\xa8\xe2\x18\x90\x51\x6e\x21\x58\xb5\xed\x4c\xff\x9f\x58\xd0\x81\xe2\xf8\xf4\x03\xd2\x32\xc1\x2f\x7f\xac\xb9\x99\xe0\x60\xbd\x67\xf2\xd0\xd6\x6f\x51\xb9\x90\x08\xff\x84\x42\xac\x40\x51\xd1\xf2\x80\x0f\x5b\xc5\xbe\xb9\xd6\x02\x75\x98\xd4\x20\x58\x99\xc9\xc0\x5e\x19\x2a\xcd\xfa\x80\x45\x11\x06\x8d\xd0\x85\x4b\xf4\x6a\xa9\x21\xef\x30\xc5\x59\x51\x84\xf5\xa3\x49\x37\x2f\xde\xa2\x86\x06\xc2\x3b\x83\xee\x0e\xc1\x0e\x84\xbe\xe0\x1e\xc4\xe2\xcd\xab\x64\x1c\x55\xeb\x8b\x20\x78\x71\x79\x24\x2e\xc0\x61\xb4\x92\xf7\xb1\x07\x0c\xa1\xc3\xdd\x04\x6b\xa2\x9a\xa4\x4b\xa5\x54\xd3\x7a\xc9\x0e\x0b\x76\x1c\x92\x07\x09\x3d\x2f\xc5\x5e\x59\xcc\xe7\x73\x95\xdf\x94\xc8\x09\xd6\x88\x97\xc4\x60\xdc\x5a\x40\xf9\xfb\x89\xca\x72\xc1\x7d\xf6\x9e\x00\x13\xf9\xa6\x71\x7f\x63\xcf\x06\x69\x9c\x1e\xe1\x31\x2d\x42\xf8\x6e\xa1\x92\x91\x12\x83\xfa\x3e\xc1\x3c\x6c\x3e\x2f\x3a\x81\x22\x99\x84\xf3\xbc\x21\x8f\x65\x8e\x8a\x64\x23\xdf\xcd\x55\x0e\xf5\x05\x3f\x6f\x50\xec\x0a\xbd\xa4\x41\x29\x92\xdc\xc0\x43\x45\x45\xf5\x38\x88\x70\xc0\xbf\x07\x03\xc6\x56\xba\x48\xda\xce\x6c\x17\x19\x1c\x20\x38\x20\xf1\x91\xe3\x8e\x9e\xd4\x49\x84\x10\xfd\xa9\x03\x41\xec\x2e\xed\x0c\x48\xdb\xe7\xe7\x75\x73\xeb\xd0\x83\x82\x7c\x83\x9d\x23\x6c\xe2\x59\xdd\xab\xa8\x75\x92\xba\xd1\xff\xfd\x96\x69\x58\x7f\xa7\x21\x5b\x80\xa6\xb2\xa4\xd6\x1f\xd4\x7f\xca\x70\x3a\xd3\x50\x02\x32\xde\x00\x8a\xdb\x01\x9b\x98\xf7\x20\xb8\x44\xba\x7b\xcd\xee\x3b\xc6\xa0\x5e\x6b\x14\x77\xc3\xd5\x91\x98\x74\x24\xaa\x05\x5e\x17\xb8\x60\x57\xbb\xaa\x81\xbe\x3b\x28\xd8\xe7\x00\x7a\x82\xdb\xb7\xc1\xb2\x41\x9b\xb4\x02\x06\x07\x82\x9f\x99\x7f\xe3\x5a\x4d\xa0\x35\x12\x11\x9f\xef\xf3\x89\x73\xdf\xcd\xd9\x83\xc3\x3c\x88\xce\x53\x86\xba\xa5\x4c\x84\xbb\xfd\x6c\xb7\x01\x06\x66\x40\xdf\x18\x5d\xb3\x1f\xd9\xe0\x25\xfa\x89\x53\x9b\x95\x5c\x62\x5c\x0d\xf1\x69\x81\x38\x19\x2d\x33\x16\x33\xa1\x23\xf3\x24\xd1\xbd\x12\x26\x9e\x73\x6c\x17\x1c\xca\x04\x23\x5c\x7e\xee\xe2\xfc\x65\xcc\xd1\x0e\xe1\xe6\x41\xf1\xf7\x8f\xb1\x1f\x44\x05\xdb\x90\x15\x1e\x52\x48\x5e\x52\x57\xd4\xd7\xc1\x03\xe5\x99\x12\x7d\xf8\x52\x33\xf0\xb1\x8e\x41\xda\xc8\xf2\xd0\x30\x11\x3c\x22\xe8\x0e\x35\x2d\x70\xa7\x5e\xca\xa2\x58\x01\xa2\x34\x12\xb4\xfc\x07\xa5\x8a\x62\xac\x9d\x73\xa1\x46\x27\x06\x8e\x70\x13\x80\xcb\x07\x9b\xde\x36\xd1\xbd\xee\xb4\xe9\x90\xa9\x80\x34\x27\xe3\x4c\xa6\x0b\xd2\xa6\x37\x76\x33\xb7\xa0\x9c\xd9\x48\x99\xe6\xf2\xa6\xac\xbd\x36\x45\xdc\x1f\xec\x47\xa7\xf5\x7c\x34\xa8\x73\x59\xc2\x14\xdb\xce\xb8\xc5\xd0\x71\x52\xe1\x00\x0e\x53\x98\x94\x02\x01\x15\xcb\x02\x47\x28\xc2\x27\x50\x21\x2e\x25\xfd\x69\xac\x25\x4a\xdb\xed\xc5\x71\xf4\x5a\xf0\xbe\xc6\xe3\xe0\x0d\x90\x7f\x16\x6c\x45\x4a\x9f\x2a\x7b\x6d\xd8\x44\x2c\x39\x49\xdd\xb2\xdc\x25\x1e\xba\x1f\xa7\xb1\xe1\xb0\x88\x17\x65\x88\x27\x32\x3d\x8b\x74\x93\x75\x2e\x40\x62\xdf\x03\x6c\x0b\x05\x64\x87\x04\x88\xc1\xd2\x48\x4b\x54\xea\x9a\x90\x05\xe2\xc8\xa3\x6b\xc5\xa4\x50\x44\x59\x41\xd8\x04\xef\x52\x02\x1c\xf8\xd5\x18\x40\x88\xe3\x10\x2e\xbc\xe0\xf8\x56\xa4\x28\x55\x1a\xee\xf9\x91\xc9\xf1\x2d\x9e\xbc\xde\x65\x03\x3c\xa5\x8f\x65\xd3\x53\x2f\x7d\x19\xbd\x44\x86\xd8\xa4\x26\x65\x1e\x49\xdd\xc3\x8c\xac\xda\x6a\x80\xd2\x65\x86\x96\xc2\x00\x8d\x06\xc1\x6d\xfb\x4b\x27\xbb\x2f\xa6\xd9\x67\xa0\xa6\x08\x30\x14\xdb\x68\x70\x6d\x85\xa6\x63\x04\xe7\x81\x44\x87\x2e\x9c\x29\x90\x4b\xb8\x02\xcb\xbd\x0d\x38\xc3\x47\x01\xf6\xc6\x8b\x74\x47\xb0\x3b\x02\x67\x3a\x46\x9c\x24\x88\x12\x48\xf9\x92\xd8\x01\xf1\x3d\x8e\x7d\xf1\x25\xb0\x04\x96\x93\x35\x32\x7f\x55\xff\xa2\x36\x72\x2c\x0d\xfc\x9e\xbb\x55\x6e\x96\xed\x9f\x25\x2c\x45\x53\xf9\x46\x97\xb7\xf1\x01\xf6\xe6\xcd\x25\xda\xcb\x5f\x86\x1c\xf3\xc0\x65\xd0\x73\xd4\x2e\xab\x93\x54\x64\x43\xb3\x65\xc6\x99\x1d\x38\x17\x55\x93\x80\x87\x80\x63\xa0\x9a\xc4\x76\x1b\xfd\xe8\xa0\xc7\x4a\x6e\x3a\x08\xe9\x32\xa2\x09\x78\x07\x94\xfc\x8c\x37\xb8\xcf\x48\xe8\x6d\x24\xb3\x77\x26\x0a\x1a\x55\x5a\x0a\x32\xab\x17\x60\x63\xd8\x1b\x98\x35\x6b\x8d\x07\xa4\xde\xb6\x17\x16\xf2\xa2\x5c\xae\xc5\xee\xcd\x6a\x26\xf9\x96\xa6\xdd\xfe\x0e\x80\xbd\x12\x97\x7b\x87\x84\xef\x14\x19\xae\xf0\x80\x94\x0d\x27\x99\x3e\xd6\x7c\xd2\x9c\x16\x4d\x90\x7e\x67\x67\xa2\x96\x30\xf3\x2a\x7b\x88\x35\x5b\x5a\x4a\xf6\x6d\x65\xc1\xa7\x89\x65\x73\xc0\x75\x59\xe9\xf3\xdc\x78\x1b\x4a\x07\x5c\xdb\xc1\x28\xa5\x31\xa3\xa9\x4f\x13\x51\xb5\x97\xf3\x6c\x21\x2b\xa7\xee\x5a\xc9\x7d\xb5\x8d\x8c\x41\x7f\x52\x66\x32\x41\x97\x86\x30\x16\x87\xb2\xb1\x84\x1c\x68\x43\x18\x09\x89\x54\x80\x51\x72\x2b\x15\x4e\x09\x36\x76\x7b\xc3\xeb\x57\x3a\xe8\x8c\x16\x6b\x0b\xe7\x10\x5f\x1c\x26\x80\x05\x12\xf3\x70\x99\xd6\xb8\xc7\xaf\xe8\x5e\xfc\xac\x98\xe3\xa0\x49\xfb\xd3\xf3\x4b\xe6\x0f\x88\x73\xe5\xee\x0c\xf9\x7d\x4d\xb9\x54\x90\xea\xbc\x58\x85\xf9\x42\x20\xe4\x1c\x61\x3f\xbc\x45\x9a\x62\x81\x1c\x9e\x9c\x34\x34\xff\xb9\x21\x94\xb6\x2f\x6a\x89\x90\xc3\x3a\x4c\x2a\xc5\xe1\xc9\x27\xad\xcf\x64\x92\x0f\xfc\x8b\x83\xad\x1d\xb8\x15\x11\x38\x2a\x48\x77\xe4\x64\xe6\x9a\xc7\x9f\x93\x36\x9d\xf0\x9a\x04\x03\x22\x9f\x24\x23\x20\x8c\x28\x9f\xde\xfd\x69\xb2\x85\x61\x08\x7c\x16\xc8\xe6\x95\xa4\x08\xd7\x05\x69\x71\x52\x90\xe8\xa9\x7d\x19\x68\x6d\xd2\x0a\x2e\x61\x84\x2b\xef\x61\x8b\xfc\xce\x93\xf3\x0e\x74\x8b\xa8\x4d\x92\x5d\xae\xa7\x52\xd8\xa7\xa4\x23\xb6\x02\x29\x49\xdb\x61\x9c\x50\x21\x11\x16\x6a\x87\xc8\xad\x83\x0f\x92\x48\x97\xd6\xa1\x7c\x24\xb0\x2c\xb4\xc4\xf2\x4c\x4a\xe9\x1a\x2b\x4e\x89\x79\x4a\x4a\x94\x84\x69\xa7\xc4\xd4\xd0\xdc\x80\x7a\x47\x80\xca\x61\x38\x1f\x97\x0b\x35\x28\x50\xde\x12\x04\x08\xd9\x8a\x2d\x80\x64\x6b\x5c\x64\x0b\x19\x33\xbd\x05\x9f\x4c\x02\x15\xb2\xae\x8a\x79\xcc\xae\xb0\x05\x07\x47\x3f\x6b\x7a\x88\xb2\x90\x08\xd0\x8e\xe6\x55\xd7\x13\x2f\x51\xf5\xf0\x75\x18\x00\x51\x95\xd6\xe6\xdb\x79\x43\x78\x38\x0a\x6f\x1a\xa6\xec\x1e\xa1\x95\xf7\xb1\xf2\xb7\xc9\x89\xe9\xf5\xa4\x16\x01\x3d\x3b\xaf\xf1\xf9\x0c\x26\x8f\x24\xec\x13\x31\x78\x67\x50\xd5\xe8\x95\x21\x98\x90\x83\x22\x89\xe4\x18\xa5\xc3\x29\x0f\xd1\xca\x18\x28\xac\x2c\xb9\x53\xb2\xcf\x4f\x0f\xe3\xb5\x6e\x4f\x96\xc2\x00\xc3\x6a\xd0\x40\x20\x10\xd8\x1c\xa6\x60\x8a\xc4\xf4\x89\x90\x87\x16\x54\x43\xdd\x08\x21\xf9\x1b\x21\xec\xb4\x54\x19\x8b\x26\xfd\xce\x95\x99\x44\xd4\x31\x6a\x64\xf5\x52\xce\x1e\x89\x2d\x51\x46\x36\x99\x9c\x02\x52\xb8\x97\x5c\x5c\x4a\xdb\xe0\x08\xa0\xb7\x96\x1f\x15\x26\x14\x12\xc9\x70\x0f\x36\x79\xc7\x11\x23\x9a\x1d\x01\xb1\xf2\xea\x6c\x9e\xd4\xbe\x74\x16\x98\x2e\xb6\xda\x25\xad\x3c\x5f\xb3\x8e\xa6\x69\xf0\xd4\x9f\x6d\x40\xfa\x49\x07\xbe\x61\xa7\xb1\xea\xcf\x87\xf2\xca\xe7\x72\x01\xb0\xe8\x61\x99\x4d\x93\x17\x08\x3d\xde\x61\x14\x9e\xa4\x46\xde\x31\x89\xbc\xb1\x7b\x57\x7a\xdc\xaf\x83\x42\x69\x81\x60\x57\x9f\x46\x2c\xad\x71\x05\xa4\x08\xe2\xcc\x6d\x90\x43\x13\x38\xb3\x1a\xee\x1a\x31\x33\x3f\x95\x54\xe3\xb2\xbb\x3b\x2b\xd6\x02\xf8\x62\xe0\x66\x49\x28\xcd\x12\x2d\x42\x01\x60\xc6\xf1\x90\x61\x2b\x1e\xb7\x83\xaf\x18\x89\x20\xe9\x20\xe5\x8e\x38\x18\x83\x5a\x0d\xb0\xda\xed\x52\xa8\xa0\x4e\x92\xb8\x8c\x92\x6a\x72\x05\x63\x2b\x1d\xf8\xc0\x41\xaa\x61\x9a\x53\xac\x92\x19\x82\x35\xd1\x73\x3d\xc8\x80\xf5\xba\xb1\x22\x5e\xa5\xa8\x33\x35\x88\x28\x2b\x90\x44\xa1\x58\x42\x3d\xa0\xa4\x55\xa1\xf4\xf5\xd4\xb4\xa8\xf3\x89\x5d\xf2\x08\x8b\x70\x81\x34\x24\x09\xa5\xdb\xce\x1d\x37\xe1\x28\x65\xec\x06\x10\x76\xee\x56\x5a\x55\x32\x38\xea\xe5\x75\xab\x9c\x2c\x4f\x30\x09\xd9\x77\xaa\x86\xeb\x18\x2a\xe5\x4f\x35\x29\x89\x6f\xcc\x49\x0a\xbe\x76\x18\x62\x64\xe8\x28\x28\xcd\x4e\x2a\xc0\xc5\x5c\xf1\xb0\x0c\xcc\x28\xd2\x54\x2c\x73\x61\xd4\x4e\x66\x15\x0b\x99\x83\x06\x70\xa9\x42\x19\x84\x44\xbb\x85\x98\x31\x4b\x81\x7f\x44\x54\x39\x4a\x07\x10\x2f\xb8\xe2\x20\x12\x8e\x46\xbd\x79\xd1\xae\xb7\x0d\xfc\xf3\x90\xaf\x93\xbe\x02\x50\x2f\xfb\x13\xa6\x38\x52\x1a\x0c\x14\x33\xd7\x61\x92\x5a\xcf\xf9\xa3\x31\x77\x31\x44\xf2\x29\xe5\x61\x40\x90\x86\x78\xab\xf2\x8a\x2f\xba\x93\x9f\x41\x25\x2c\x92\x32\x4f\x49\xd7\x3c\x96\x6b\x13\x20\x11\xd9\x59\x78\xad\x93\xb6\x1d\xec\x99\x00\x1e\x13\x7c\x62\x15\x2c\xcd\x0d\x54\x80\x48\x44\x17\x54\x14\xcc\x82\x59\xb1\xba\xeb\xad\x81\x82\x5d\x61\x07\x9d\x24\xf8\xf4\xbe\xe4\x2b\xb9\xe2\xdc\x04\x96\x2e\x11\x66\x20\x46\xeb\x62\x37\x10\xf2\x9d\xe0\x74\x77\xc4\x7b\x86\x17\x99\x21\xb4\x55\xba\x65\x77\x39\x21\x32\xd8\xf9\x37\x72\x82\x24\xf5\xe5\x46\xec\x3f\x63\x5c\x7d\xb1\x23\xa7\x0f\x2b\xca\x94\x43\x14\xa7\xf9\x79\xf5\x68\x52\x1f\xdc\xd4\x72\x02\x03\x90\xc6\xfc\x6f\x43\xe0\x6c\x2a\x82\xca\x36\x83\xbe\xaa\x43\x7d\x9b\x90\x1b\x09\x58\xd2\x4b\x4d\xb6\x86\x09\x08\x99\xa7\x95\x42\x38\x90\x40\x6f\x82\xf0\x92\x5b\x2e\xb9\xfe\x98\x12\x4a\xc3\xc4\x18\x2a\x68\x18\xd8\xdf\xb5\x12\x9e\x37\xfa\xce\xf9\xf5\x8a\x6e\x12\x7d\x84\x63\xdd\x2a\x27\xd7\x76\x77\xdf\xfa\x10\xd3\x21\x6b\x62\x4f\x62\x2c\x16\x4f\x43\xd0\xeb\x3a\x17\xa2\x37\x11\x7d\x3c\x49\x09\x63\xf1\x85\x67\xb9\x2b\x02\xac\xe8\x58\x09\x3d\x0f\x9e\x16\x85\x51\xd0\xb8\x3c\x4c\x45\xa2\x49\x64\xba\x7e\x10\x02\x8e\x14\xb2\x01\x24\x8d\xe2\x04\x78\xc8\x90\x7a\x06\x28\x9e\x1f\x8e\x87\x15\xfe\x5d\xec\x29\x7f\xd5\xd6\x0a\x24\xcb\xb5\x02\x51\x1f\xbf\x49\x97\x0b\xdc\x3b\x9d\x42\x16\x55\x4f\x4c\x71\xd4\x98\xac\x84\x95\xf2\x19\x98\x76\x14\xc4\xd5\x4e\x1e\x4b\x1a\xe1\xef\x3c\xae\xe8\xd0\x5e\x4f\x88\xdc\x67\xf1\x31\x91\x26\x5b\xf1\xbb\x31\xe8\x5c\x29\x67\xa0\xaf\x73\xb2\x52\xa8\x7a\xe1\xd8\x60\x94\xa9\x9c\xbe\x8c\xda\x5c\x1c\xb4\x91\xe0\x20\x70\xec\x4e\x9c\x48\x7b\x50\x62\x99\xdf\xe9\x84\x53\x45\x96\x86\x63\xe3\x90\x32\x54\xda\xbd\xe2\x6a\x6e\x82\xaf\xda\xa3\x26\x6b\x99\x07\x16\xcc\x45\x33\x3c\xf2\xf6\x12\xc2\x36\xfd\x6c\x96\x86\xd9\x02\x0c\x09\x19\x46\xfa\x14\x2d\x92\x30\x05\x3e\x21\x0b\xdb\xa7\xe0\x9d\xba\x4f\x06\x1d\xcb\xc1\xba\x09\x2e\x27\xc0\x83\x97\xc9\xc1\xc0\x79\xb1\x77\xdc\x0a\xdc\x8d\x69\x7d\x3b\x70\x68\x35\xc9\xd5\x0a\xe0\x98\xa2\xf8\x10\x72\x94\x56\xe0\x6f\x31\x43\x5d\x12\x9e\x08\x21\xb0\x75\x91\x68\xdb\xa1\x31\x59\x46\xcd\x68\x0d\x05\xe3\xfd\xf4\x5b\xa5\xf5\x9d\x4c\x39\xe1\x92\xa0\xd6\xcb\xcf\xcc\x0c\x43\x4d\x26\x1b\x27\xa0\x57\x1e\x25\x55\x90\x07\x2c\x32\x01\xb7\x00\x99\x30\x6c\x79\xef\x2e\x10\x82\x5c\x92\xfd\x64\x97\x9a\x60\x05\x82\x59\xde\x2c\x13\xbc\x7e\x9f\x27\x2c\xe0\xdc\x0e\x60\xc9\x1c\x9e\x12\xbe\xa7\x2e\xf1\x85\xc4\x49\x21\x05\x5e\x45\xc7\x61\x34\xeb\xd6\x10\x23\xe2\x60\xd7\x10\x81\x95\x05\x2e\x8a\x18\x83\x92\xb5\x59\x47\xc2\x8d\x2c\xbc\x23\xd2\x7d\x50\x0b\x7d\xe1\xcf\xdb\xd1\x65\xd5\x7f\x14\x39\x65\xd0\x91\x8b\xb1\x8d\xad\x11\xc8\x04\xca\x04\x09\x6d\x7a\xf3\x60\x47\x8b\x69\x92\x66\xf0\xbf\xd4\x16\xfd\xe1\x4d\x76\x12\x28\x99\xfe\x21\x5c\x5a\x63\xc0\x4f\xda\x0b\x1b\xdf\x2d\x73\x94\xc1\x01\xc3\x3d\xcd\xfb\x58\x8b\x9c\x8c\x2d\x5a\x52\x10\xb0\x54\x24\x25\x2f\x94\x6d\x59\x80\x9f\xe1\xd4\x3f\x24\x69\x7a\x8b\x84\x0c\xd1\x20\xdb\x26\x03\x12\x2d\x60\x22\x1e\x9f\x44\x6d\xc7\xfc\xb7\x33\x63\xc9\x6e\x51\x0d\x2c\xa0\x03\x4b\x24\x47\x78\xb1\xd8\x0a\x41\x12\x18\x24\xcd\xb0\xe2\xa4\x7a\x38\x56\x8a\x8f\xaa\x4e\x81\x51\x99\x4a\xca\xa1\x7e\x31\x6a\xdc\x94\xe9\x76\x8e\x8b\xa3\x7b\xd0\xaa\x3f\x50\x52\x4b\xef\xa6\x1c\x14\xb2\xf2\x81\x6c\x16\x33\x27\xdf\xbb\x30\xbf\xd3\xb4\xc5\xba\x76\x22\xe0\x88\xa3\xc1\xa3\xeb\xab\x38\xbf\x11\x49\xee\x7d\x1f\x45\x08\x1d\x87\xe2\x5d\x84\x1f\x4c\x8f\xad\x60\xa3\xbf\xef\x8a\x2e\x1d\xbe\x11\x1e\xd6\x89\xe7\xd1\x7f\xcd\xbb\x7f\x45\xb3\x76\x2f\x9e\x34\x0c\xd7\xb1\x9d\xf0\x30\xec\xee\x70\xa0\xd1\xdd\xde\xc6\x84\x47\x76\x2f\x2c\xf4\xd8\xa8\xec\x2b\x44\xb1\x02\x00\x9f\x64\x8e\x63\xc7\x06\x3f\x27\x72\x4b\x51\x2a\x75\x85\xc3\x84\x09\xe7\x60\xa3\xb8\x82\x4f\xa5\x6c\x09\x41\x58\x5c\xc9\xf1\x4a\x6b\xf3\x7d\x21\x02\xea\x7d\x05\x31\xb5\x0d\x92\x5e\xc3\x8d\xae\xab\xdb\x3f\x56\xdb\x14\x27\x46\xa5\x84\x4d\xd1\x04\x93\x96\x41\x18\x49\x52\x42\x31\xd5\xce\x9c\xbb\x40\xdd\x39\x61\x34\xe8\x9d\x06\xcc\xba\x42\xe6\x47\x24\x67\xb0\xce\x12\x37\x5b\xfb\x22\x52\xd5\x48\xdf\x95\x38\x15\x63\x15\x1f\x24\x48\x16\x11\x7c\x3c\x9a\x1d\xfd\x66\x9e\xfe\x5f\xe7\xcb\x79\xb0\xb6\x6e\x72\xd1\x56\x6d\x3d\x27\xe0\x60\xfe\x1e\xb4\xf7\x39\x30\xbe\x63\x7a\xf9\xa2\xba\x53\x48\xdd\xd3\x6c\xba\xaa\xea\x3a\x31\x75\x2c\xc5\x26\x29\xac\x68\x77\x6f\x0d\x0f\x10\xd1\x2b\x58\x48\x7d\xc5\xdc\x48\x63\xc8\x80\xdb\xb7\xef\x46\x12\x65\x01\x7e\x1b\x3e\xcc\x18\x11\xaa\x3f\x33\x0a\x14\x54\xe0\x7b\x6a\xe9\x0a\xba\xe5\x45\x69\x5a\x03\xdc\x38\xa9\x6e\x60\x62\x96\x68\xf6\x3b\x0c\x59\x7b\xa0\x66\xbe\xcc\x1f\xbc\xd8\xdb\xf3\x8c\xb2\x27\x08\xc0\x00\x34\x3a\xa7\x7a\xa7\x33\x09\x8b\xcf\x09\x62\x09\x7d\x06\xf6\x5c\x4a\xfb\xf0\xd7\xd2\x78\x80\xab\x74\x88\xe8\x8e\x40\x13\xa5\x4b\x22\x6e\xb2\xe6\x50\xc3\xc3\x04\xb1\x15\xd7\x6c\xbe\x6c\x19\xed\xb6\xc7\xa7\x81\x7a\xd7\xad\xb5\x00\x6e\x5c\x1c\xa1\x31\xa8\xc0\x9b\x85\xd4\x6a\x2a\x72\x97\x79\x4b\x98\xc7\xd1\x14\xb8\x6b\x90\x88\x3b\x51\xce\xb2\x61\xd4\x37\x90\x01\x00\x00\xff\xff\xa2\x34\x0d\x45\x27\x57\x00\x00") func fontsInconsolataRegularWebfontEotBytes() ([]byte, error) { return bindataRead( _fontsInconsolataRegularWebfontEot, "fonts/inconsolata-regular-webfont.eot", ) } func fontsInconsolataRegularWebfontEot() (*asset, error) { bytes, err := fontsInconsolataRegularWebfontEotBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "fonts/inconsolata-regular-webfont.eot", size: 22311, mode: os.FileMode(509), modTime: time.Unix(1492020681, 0)} a := &asset{bytes: bytes, info: info} return a, nil } var _fontsInconsolataRegularWebfontSvg = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\xbd\x79\x9f\x26\x47\x6e\x26\xf6\xff\x7c\x8a\xd8\xa6\x3d\x3e\xa3\x3a\x00\xc4\xb9\x4d\x8e\xec\xd5\xc8\xf2\xda\x5b\xbb\xb2\xa5\xd5\x7a\x7d\x37\xd9\xdd\x4c\xda\x39\xe4\x24\x99\xca\xa1\xca\xc7\x67\xdf\x1f\x1e\x20\xf2\xad\x6e\xd6\x5b\x9a\x3e\x78\x68\xd4\x7f\x90\xf5\x76\xd5\x9b\x99\x91\x71\x00\x0f\x80\x07\xc0\xa7\x7f\xf6\xfd\xef\xd6\x70\xbc\xfc\xf6\xbb\xaf\xbe\xf9\xfa\xb3\x27\x74\x93\x9e\x84\xef\xf6\xe7\x5f\xbf\x78\xbe\x7e\xf3\xf5\xcb\xcf\x9e\x7c\xfd\xcd\x93\x3f\xfb\xcd\xaf\x3e\xfd\x67\xbf\xfd\x37\x7f\xfe\x37\xff\xfe\xaf\xfe\x22\x7c\x77\x7c\x19\xfe\xea\xdf\xfe\x8b\x7f\xf5\x2f\xff\x3c\x3c\x89\x4f\x9f\xfe\x3b\xf9\xf3\xa7\x4f\x7f\xfb\x37\xbf\x0d\x7f\xfd\xb7\x7f\x19\xe8\x86\x9e\x3e\xfd\x8b\x7f\xfd\x24\x3c\x59\xf6\xfd\xf7\xff\xfc\xe9\xd3\x3f\xfc\xe1\x0f\x37\x7f\x90\x9b\x6f\xbe\xfd\xf2\xe9\x5f\x7e\xfb\xfc\xf7\xcb\x57\x5f\x7c\xf7\xf4\xaf\xff\xf6\x2f\x9f\xea\x17\x7f\xfb\x37\xbf\x7d\xfa\xdd\xf1\x25\xd1\xcd\x8b\xfd\xc5\x93\xf0\x9b\x5f\x7d\xaa\xb7\xfe\xfe\x77\xeb\xd7\xdf\x7d\xf6\xc0\xf5\x9c\x52\xd2\xef\x3f\xf9\xcd\xaf\x3e\xfd\xdd\xcb\xfd\xf9\x8b\xe7\xfb\xf3\xdf\x7c\xfa\xf4\xfc\xf8\xab\x4f\x5f\xbc\x7c\xf5\xdd\x6f\x7e\xf5\xe9\xab\x6f\xbe\xde\xc3\x57\x2f\x3e\x7b\xf2\xd5\xd7\x5f\x7c\xf3\xf5\x77\xdf\xac\xcf\xf7\xe7\xdf\xbe\xfc\xf2\xef\xd6\xe7\xdf\x3e\x09\xcb\x37\xdf\x7e\x75\x17\x9f\xbf\x38\xe2\xf7\x9f\x3d\xa1\xc4\x19\x0f\xd6\x4b\xe2\xab\xe7\x5f\xbc\x0c\x7f\xf7\xf5\x57\xfb\x77\xf1\xf7\x2f\xbf\x8d\x2f\x7f\xf7\xd9\x13\x4e\xb9\x3f\x09\xcf\xbf\xfb\xe2\xe5\xd7\xfb\x67\x4f\xa8\x4a\x7f\x12\x5e\xbc\xf4\x7f\xc6\x4c\xe9\x49\x78\xaa\xc3\xf9\xea\xbb\xef\xbe\xfa\xfa\xcb\xf8\xe5\xfa\xf7\xbf\x5f\x5e\x7f\x44\x49\xfe\x1d\xfb\xdb\x43\x9f\xfe\xee\xeb\xaf\xbe\xf8\xe6\xc5\xcb\xcf\x9e\xfc\xfa\x93\xef\x5f\x3c\x7b\x63\x88\xb5\xd3\x93\x87\xbe\x1b\x1e\xfc\xed\x3f\x7b\x12\x5e\x7c\xf6\xe4\x56\xea\x08\xa3\x6e\x29\xe4\x11\xa4\xdc\x94\xd0\xeb\xde\xf3\x4d\x09\xd2\xf6\x5e\x43\x94\xb6\x4b\x0b\xb1\xeb\x57\x62\x6e\x21\x4a\xbd\x29\x21\x76\xd9\x63\xc7\x27\xa9\x5b\xcc\x23\xa4\x10\xed\xb2\xb2\x47\xbb\x4f\xbe\xbb\x95\x3e\x02\x31\xb5\x2d\x85\xc6\x81\x7b\x20\xa2\x9b\xb2\xb7\x16\x64\xdc\x94\x2d\xb7\x90\x42\xd3\x2f\xc7\x9c\x76\xee\xfa\x81\x84\xf5\x49\x2c\x21\x72\x88\x25\xdf\x94\x3d\xd6\x10\x1b\xdf\x94\x35\x52\x0a\x91\x52\x5d\xa3\x0e\xa9\xd4\xba\x44\x4a\xb2\x46\x49\xa1\xd4\xba\x45\x0e\x22\x21\xea\xfd\x6a\xc7\x75\xfa\x69\xd8\x1d\x2a\xee\x24\xa1\xd0\x4d\xb9\x7b\x70\x42\x7e\xfd\xc9\xf7\xcc\xcf\x6c\x56\x98\x5b\xe8\x2d\xad\xb9\x04\xca\x69\xa3\x14\x84\x02\xe9\x9d\x4b\xdf\xf1\x23\xaf\x91\x72\x20\x1e\x5b\x0a\xa5\x05\xd6\x67\xf5\xb2\x57\xba\x29\x81\xfb\x5e\x05\x73\x93\x6e\x8a\xbf\xd7\xe8\x37\x45\x5f\xac\xa5\x10\x6b\x0f\x91\x4b\x5d\x75\xde\x22\x49\xb9\xbb\x2d\x9d\x5f\x7b\x5e\x0f\x95\x02\xe9\x7c\xf1\x1a\x89\xdf\xe1\x39\x55\xec\x59\xaf\x3d\xe7\xc1\xf7\xfe\xc4\x5e\xb9\x50\x90\x41\x6b\x0f\x83\x17\x4e\xb2\x66\x0a\x52\x68\x89\xcc\xb2\xd6\x30\xf2\xc2\xdc\xec\x97\x69\x25\x2e\x21\xaf\x31\x4b\x88\x52\xd2\xc2\x5c\xd7\x9c\x82\x64\x5e\x89\x5b\xe0\x35\x66\x0a\x51\x72\x5a\xa8\x37\x8c\x3f\x0e\x5d\x2b\xfd\x07\xae\xc9\x15\x8f\xc0\x7a\x0e\x59\x22\xfe\x91\xf5\x45\x1a\xde\x57\xdf\x43\xe7\x42\x5a\xd1\x01\xcc\xcb\x6a\xd5\x3f\x52\x88\xbc\x66\x09\x52\xf3\x12\x69\x0c\xdd\x66\x12\x72\x6f\x0b\x73\xc1\x1f\xf2\xc0\x55\x0f\xbf\xee\x7f\x64\xaf\x4b\x2c\x81\x86\xac\xbd\x07\x62\xde\x7a\x88\x35\xe8\xb2\xa4\xbd\xea\xee\xdb\x28\x71\x88\x44\x14\xb8\xd4\xa0\x43\x3a\x72\xa1\x2d\x52\x4d\xa1\xe8\xde\xd4\x0d\x1c\x88\xfb\x1e\x1b\x3e\x75\xdd\xe4\xa5\x04\xd6\x05\xa1\x54\x6e\xca\x5e\x71\x0c\x74\xff\x51\x4a\xba\x15\xf5\x97\xc4\xfa\x75\x3d\x44\x07\xb1\x2c\x24\xb4\xb1\x6e\x75\x0e\xb1\x62\xa7\x93\x9e\xac\x10\x39\x1f\xb1\xf5\x8d\x06\x1e\x16\x24\xe9\xd9\x28\x6d\x8d\xbd\x63\x5c\x9b\x4e\x5e\xd6\x8f\x81\xb0\xd9\x75\xa8\xf9\xa6\x6c\xb1\x71\xe8\xfa\x87\x81\x71\x1c\x51\x46\x0d\x9b\x5e\xc5\x23\x50\x61\xdd\x24\xc5\x06\x85\xf3\x8b\xa3\x52\xf1\xeb\x5e\x77\x4e\x38\x84\x44\xba\x87\xca\xd0\x67\xdb\x2f\xec\x20\x36\xfc\x23\x11\x1e\x98\xf0\xaf\x36\xf6\x48\x19\xdf\xca\x72\x44\xe2\xb1\x44\xa2\x71\x10\x97\x2d\x32\x53\x20\x95\x22\xa5\x07\xaa\xf9\xee\x96\x47\x0b\x43\x92\xde\x9d\xa8\x05\xb2\x91\xd2\x21\xa5\x6c\x71\xe8\x94\xeb\x5f\xa4\x87\x58\x9a\x3e\x24\x57\x9c\xf8\x9b\x72\x77\x5b\x53\xd2\xf1\x6f\xa3\xe3\x64\x14\x7d\x64\xd3\xc1\x17\x9d\x67\x12\xc2\xc6\x6f\x39\xe8\x76\x27\xea\x3b\x16\xab\x8d\x70\xc4\x9c\xae\x6c\x86\xff\xd8\xf7\x7e\x0b\x94\x20\x78\x4a\xc1\x74\x06\x4a\xfa\xc2\x79\xd8\x69\x6b\x12\x4a\xdd\xfb\x08\x3a\x3d\xfa\x33\xe2\x43\xb3\xc9\x6c\xbb\x9e\xaf\x5e\x77\x32\x09\xa6\x97\xce\x17\x8c\xd8\x04\xfa\x8a\x98\x32\x3b\xae\x0d\xeb\x04\xe9\x17\xe7\x4d\x23\x9e\x81\x57\xf6\x87\x46\x1f\x48\xbd\xbb\x1d\x39\xa4\xb5\xa5\x16\x88\x5b\x5d\x48\xda\x1a\x1b\x89\x6e\xcb\xa6\xe7\x4a\xe8\xee\x96\x3a\xcf\x77\x88\xbd\x42\x10\x12\xcb\xde\x18\x22\xbc\xda\xa6\xdb\x55\x50\x04\xe2\x1c\xf6\x28\x6c\x1f\xf7\xd8\x08\x7f\xdc\x54\xaa\xaa\xe4\x18\x7a\xd4\xf4\x0b\x7a\x8b\x7c\x77\x5b\x24\x05\xce\xf9\xf5\xd9\x79\x7d\x6e\x6c\x56\x1e\x9e\x1d\x9d\xc7\x1e\x62\x2f\x3b\xf9\xf6\x11\x7f\x37\x9b\xaa\x1d\xe2\xa9\xe3\x13\x86\x12\x4b\xd9\xb1\xcd\x39\xed\x36\x3f\x36\x3b\xe7\xdc\xe4\x73\x6e\x74\x5b\x14\xdd\xf8\x50\x4f\xbd\x07\xd1\xbb\x72\xdd\x9b\x6e\xba\x6e\x63\x90\xb1\xeb\xe6\x50\x4d\x14\xb6\x84\xc3\x21\xfa\xaf\xb2\xe9\x4f\x19\x41\xef\x2e\x63\x53\xa9\xa5\x12\x3a\x63\xca\xa2\x4f\xe1\x75\x65\x51\x5d\x59\xb4\x1c\xb8\xab\x7c\x26\x1e\xa1\xe9\x0c\xb3\xe8\xbe\xa4\xae\xef\x4b\xb6\xda\xa4\xa2\x5d\x47\x45\xb9\x06\xa1\xee\xe2\x9c\x6d\x89\xf5\x08\x26\x9b\x4f\x15\x18\xba\xdb\x28\xe9\x2b\xea\x4c\x6e\x55\xc7\x45\x84\xf9\xd4\x2b\xf6\x8e\xd9\xd3\x2b\x76\x95\x4e\xba\xf5\x46\x88\x43\x4f\x22\xce\x0b\xcf\xa3\x33\x70\x88\x1a\x94\x33\xe6\x32\xd6\xb4\xb2\xa4\x10\x85\x79\x63\x55\xf9\xa1\x74\x68\xfd\x9b\xb2\x43\x6f\x8f\xaa\x9a\x96\x03\x67\xbc\x51\xe8\x81\x69\x25\x9d\x8c\x21\x61\xc3\xbd\x54\x76\x46\x2a\x10\x94\x6d\xa5\xac\x67\xb8\x4f\xd9\x3c\x68\x8d\x44\x12\xa8\xd3\x06\x2d\xd4\xf5\x8a\xa2\xdf\x51\x69\x49\x7a\xc8\x73\xc7\x8d\x70\xab\x0e\xb1\xa5\xe2\x84\x42\xc5\x01\xd0\xff\x87\xd1\x77\x93\x3d\xc4\xe9\xee\x96\x75\xa8\x26\x94\xb2\x04\x15\x46\x21\xe2\xec\xeb\xea\xe9\xa1\xda\x4b\x35\x09\xb4\xeb\xf6\xa5\xb2\x89\x84\x14\x20\xaf\x28\xed\x35\x07\x56\xe1\x5b\xb2\xe2\x13\x88\x6e\x7d\xd7\x55\x54\x9d\xad\x91\xab\xfe\xcc\x5b\xec\x0a\x39\xc8\x46\x15\x49\xc4\xe5\x4f\xe5\xbb\x70\x2b\x0a\x5f\x12\x16\x2e\xaa\x08\x52\x25\xc5\x25\x6f\x4d\xef\x19\x20\x20\x5d\xee\x67\x1c\x32\x6c\x81\x98\x39\x10\xe9\xf8\xe2\x68\x21\x17\xdd\x09\x05\xa7\x6c\x0c\x05\x3d\xfe\x95\x88\xc5\x7e\x78\xa7\xfd\x27\xb6\xc9\x32\xf3\x43\x88\x04\x78\xe4\x1d\xd1\x88\x02\x2c\x9c\x97\x66\xbf\xd8\x63\xc1\x52\x35\xdd\x00\x98\x86\x6b\x90\xe1\x3f\x75\x94\xd4\x4b\x28\xac\x33\x42\xe2\xe8\x91\x75\xca\x77\x4a\x62\xa7\x60\xa7\x0a\x35\xab\x0f\xa6\x1a\x54\x72\x55\xcc\xaf\x9e\x08\xdd\x08\x01\x3b\x36\xaf\xaa\xe3\x78\x8b\x15\x7b\x42\x95\xf1\x16\xa9\x1b\xda\x0b\x91\x3b\xb4\x12\x43\x97\x46\x53\xa6\x31\xab\x34\x31\x31\x5b\x82\xd8\x17\x18\x82\x48\x25\x87\x1e\x96\x9d\xb2\x69\x33\x88\x66\xfd\x90\xcb\x1a\x2b\xe4\x4e\xdf\xb0\x8b\x75\x7f\x32\x41\x81\x9b\xf0\xd5\xf1\x72\xd2\x7d\x9a\xf4\x08\xe0\x77\xf6\x62\x8d\x1e\x9e\x8b\xff\xcc\xf1\x84\x62\x63\x16\x05\x0e\xd9\xe4\x24\xf6\x9e\xe4\x9d\x74\xc7\xb6\xba\x0f\x0a\x8c\xfd\x01\x61\xc4\x8c\x5d\x71\xff\x33\x44\x1d\x8e\x2e\x19\xba\x68\xbc\x63\x16\x48\x68\x15\x45\xd2\x6d\xc3\xd1\x83\xe0\xc0\xfb\xe8\xf8\xa8\xe9\x4b\x24\xda\x29\x0d\xcc\x82\x5e\xbc\x0b\xd6\x99\xab\x60\x8a\x14\x2f\x8b\xfd\xb5\x36\xc5\x0a\x26\x4b\xb2\x4a\xd2\x86\x93\xc3\xa9\xea\x81\xb3\x09\x2b\x57\xde\xf5\x3f\xb7\x77\xed\x39\x34\x96\xb5\x48\x20\x91\x55\xa0\x28\x14\x66\x8a\x82\x32\x59\xc8\xb0\x38\x16\x58\x57\xaf\x39\x86\x67\x6c\x2c\x51\x68\x98\xfa\x2a\x5c\x03\xe5\xae\x77\xd1\xfd\xb0\x2a\x92\xd4\x95\x69\x2b\x97\xae\x5f\x19\x26\x47\x62\xef\x2b\x70\x84\xe4\xa4\x1f\x54\x3b\x65\x45\x89\x44\x61\xa4\x95\x6b\x0d\x72\x4d\xbd\xff\x17\x36\xde\xc1\xa1\x8c\xaa\x88\x64\x91\x2a\x87\x42\x56\xe2\x71\x00\xbb\x4a\x49\x0a\x5a\xca\x12\xf1\x49\xba\x2c\x8a\x61\x0e\x7c\x90\x7a\x45\xfc\xff\x97\x6e\x3c\x29\x50\xe1\x2e\x5b\x69\x8a\x0a\x15\x71\x91\x4e\x7d\xa0\xa4\x10\x87\xf5\x85\x74\x76\xa5\xef\x51\x6a\x90\xec\x9b\x49\x9a\xed\xb5\x90\x0d\xad\x2b\xf6\x16\xb7\xbd\xaa\x19\x51\xc3\xe4\x59\xdb\x0d\x5a\x11\xdb\x42\x56\xc6\x86\x55\xe5\x76\xe5\x6c\xc6\xb9\x1f\x4b\x28\xad\x1c\x24\x7d\x69\xd2\x0f\x05\x55\x4b\x6c\xd2\x1f\xbe\xea\x66\x5a\x83\x2d\x8c\xec\xd6\x60\x35\x5d\xdb\xc5\x46\x04\x6b\xb0\x6c\xd8\x4a\x2d\xc0\x28\x9c\xef\x13\x3b\xef\x11\x1b\x5e\xbf\xa1\xb2\x43\x35\x0e\xde\x54\xbf\xa2\xa2\xb1\x5f\x99\xc9\xa7\x3e\x5c\xdd\x16\xdc\xd6\x9a\x49\x45\xe7\x58\xb1\xd1\x6b\x5e\x63\x55\xe8\x4f\xd2\xf3\xc3\xd7\x27\xbf\x3e\x71\xa8\xac\x18\x5c\x5f\x5c\x72\xe0\xaa\x27\x0e\x1a\xb4\xef\x7a\x77\x92\xb2\x93\x5a\x7f\x21\xf7\x4d\x91\x61\x0a\xdc\x55\x16\xb5\xb4\x29\xd0\xed\x49\xd7\x2f\x72\x1a\xbb\x40\xe6\x8c\x73\xc2\xed\xdf\x40\x70\x23\x1b\x9c\x33\x49\x84\x9d\x4f\x00\xc0\x38\x5c\x0a\x22\x5a\x87\x0c\xb3\x27\xd9\x3a\xe3\xe9\x38\xd8\x3e\x22\xb3\x45\x75\x90\x45\x91\x2d\x4b\x0d\xb5\xd8\x02\xab\xfd\x04\xf8\x4f\x6b\x2e\x14\x8a\x6a\xd1\x4c\x41\x35\x13\x9e\x0d\xc4\x66\xd8\x20\x73\x98\x73\x0d\x48\x6e\xb0\x45\x95\xbc\x23\x80\x8a\x83\x89\xa1\x1a\x8c\xe7\xd4\xee\x6e\x45\x2d\x85\x2e\x9b\xa2\xae\x01\xd0\x68\x76\xb7\xec\x8e\xe8\x33\x6d\xa5\x28\xe2\xc0\x5f\x74\x63\xee\x3d\x87\xd1\x76\x85\xc9\xb0\xc8\xd9\x5e\xa3\x9a\x5d\x1f\x55\xb0\x17\x3c\x45\x11\x43\xba\xa6\xc9\xc8\x97\x4a\x25\x1a\xa5\xbc\x8a\x64\x45\x47\xcb\xd0\xdd\xc9\xad\x2f\x91\x32\x1d\x44\x49\xcf\xb9\xca\x80\x56\x1f\xbe\x11\xfb\x8d\x4a\x0a\xe9\x18\x69\x6b\x35\xe8\x67\x43\xd7\x5c\x80\xbd\xaa\x59\x65\x74\x53\xd6\x31\xc2\xa0\xad\x50\xc8\x2d\x74\x15\x7c\xbd\xed\x25\x05\x95\x7b\xbb\x62\x0f\x60\xb6\xbd\x86\xaa\x2b\x9e\xa1\x30\xf4\x2b\xb1\x30\x9c\x13\x7b\x6c\x35\x14\xb5\xca\x5a\x50\x55\xb1\xc5\x22\xd0\xe0\x90\x94\xf8\xbb\x23\xc6\x62\x8a\x09\x13\x61\x13\x09\x9c\x6f\x1a\x0d\x36\xbf\x9a\xbc\x39\x74\xd6\x09\x56\x10\x81\x2b\x60\x94\xed\xd0\x0d\x41\xa7\x57\xdf\x47\xf7\xb1\x2d\x19\xf4\xa9\xc1\xe5\xd6\xc2\xde\x4d\xe3\xed\x0c\x93\xde\x8d\x7d\xdd\xbf\x0e\xae\x89\x2f\x66\x13\x9d\x68\x2a\x0e\xfc\xba\x61\x9f\xc3\x93\x02\x08\x47\x0a\x02\x54\x6f\xb9\x4d\x18\x62\x31\xc7\x89\x01\x2c\xdf\x44\xf3\x80\xc3\xe2\x8a\xbd\x2e\x45\x8a\x02\x90\x14\xb0\x0f\x86\x6d\x87\xb1\xd4\x43\x0d\xc1\x25\xb6\x3c\x1e\x5e\x37\x99\xa2\x89\x02\xb1\xac\x94\x06\x20\x0b\x26\x47\x95\x85\xbd\xab\x4e\xa6\x2e\x9b\xbe\xa1\x6a\x3c\x20\xb0\x50\xdd\xd9\x74\xa2\x0b\xcc\xf1\xdc\xa8\xec\x50\x79\xef\xac\xd8\xb9\xe4\xa0\x52\x6b\x37\xcd\x9e\xd4\x28\x52\x75\x11\xbb\x6a\x62\x5d\x1e\xea\xa1\x66\xb5\xe6\x75\x21\xa1\x83\x23\xb9\x32\x8e\x72\xe8\xbc\xa8\xc9\x15\x80\x85\xb0\xe8\xfe\xd0\xc2\x3b\x7e\xd5\x4c\xf1\x02\x2e\x6f\x09\xc2\x10\x82\xbe\x19\xa2\xc3\x4a\x0e\x00\xef\xcc\x7b\x1c\xba\x37\x6f\x4a\xd8\x20\x0a\x92\x4b\xf0\xd1\x57\x15\x3a\xbd\x6f\x8a\x25\x55\x45\xab\x91\x4f\xd2\x14\x52\x26\x03\x90\xba\x34\x58\x7f\x8c\x0c\x77\x6f\x66\x42\x01\xca\xc1\x40\xb3\x2d\xa0\xb0\xda\x8c\x7b\xaa\x2e\x75\xdc\xc4\xd2\x3d\x32\xba\xd9\x3c\xc5\x7e\xc7\x6e\x6e\x44\x4e\xe6\x94\x72\xed\x1c\xcc\x92\x77\x9f\x46\x24\xf7\x2c\xe8\x83\x3a\x29\x54\x50\x61\x98\x14\x9a\x41\xc8\x09\x73\xa0\x7c\xe5\x90\x66\xd7\xbd\x6a\x93\xe5\x83\x52\x59\x4b\x96\xd0\x69\x2c\xc4\x74\xc4\x36\xc6\x42\x35\xe3\xe4\x2f\x11\x9f\xa4\xf0\x12\xa9\xa4\x43\x4a\x5e\x62\xa1\x7c\x77\xcb\x39\x85\xdc\xc6\x22\x2d\x1f\xa5\xf1\xc3\x4f\x2a\x17\x15\x42\x2d\xc3\x05\x35\xb2\x6e\x50\x15\x4c\xaa\x56\x54\x64\x89\x99\x4e\xba\xd9\x28\x07\x43\x11\x6a\x11\xb0\xc9\xed\xbd\x19\x44\x66\x85\x69\x11\x88\x7d\x64\xec\xef\xbd\x8d\x60\x96\x96\x1e\x8a\x51\x70\x54\xcd\xf7\x73\x33\x4f\x3a\x2c\x1b\x58\x20\x43\x71\x9c\x84\xe2\x48\x95\xcd\x80\x8b\xd5\x80\x2d\x0f\x7f\x48\x24\xc2\xfc\xf7\xb1\xea\xee\x90\xb6\x66\x09\x35\x8f\xa5\xe6\xe6\x3e\x94\xc2\x75\x8d\x6a\x50\x49\x6d\x1b\x25\xa8\x64\x4e\x23\xe4\xb1\x75\xc6\xde\xd4\x57\xd2\x1b\xee\x38\xcc\x8a\x1d\x0c\xbd\xc9\x44\xf9\xd4\x1c\x22\x63\xf9\x93\xff\x6a\x8f\xc0\xc2\xaa\x99\x75\xaa\xa0\xc5\x7d\x63\xf0\xd8\xe0\xb5\xc0\x16\xad\xf0\x95\x1a\x24\x26\xdd\xd2\x0f\xcf\x7e\x9d\xb3\xdf\x42\xe9\x38\x69\x8d\x83\x70\x90\x94\x01\x79\x99\x77\xca\x30\x73\x05\x30\x5c\x15\x57\x3d\x15\x30\xa4\x99\x9a\x8e\x09\x5a\x4c\x9f\xdf\xe1\x31\xe2\xec\x46\xda\x1e\xf1\x32\xba\x3d\x37\x05\x8f\x0a\xaa\x20\x93\x1c\x57\xea\x6b\xe1\x6f\x66\xbd\x0f\xf7\xb7\xb8\x49\x79\x91\x63\x3e\x39\x25\x9d\x90\x3e\xb2\xfe\x63\xcb\xa2\x4a\x8c\xe0\xdd\x35\xf1\x09\x25\x17\xd4\x78\xd8\x1a\xa6\xda\xbf\x3e\x2e\x47\xb1\x97\xb0\x9b\xe7\x9a\x84\x77\x3f\x3b\x76\xfa\xe7\xdc\xcb\xae\x58\x20\xba\x6a\x24\x7d\x29\xd5\x2a\x94\x69\x1a\x63\x5b\x1c\xb6\x2f\x54\x4e\xd8\x5c\xe3\xb5\xc9\x86\xdf\x5a\x20\x33\x79\x60\xcf\x31\x5c\xd7\x30\xba\x72\x6b\xf0\x77\x24\xc8\x26\xdd\xd1\xcd\xac\x5b\x7d\x8c\x4a\x41\x7b\xef\xbe\xab\x51\xad\xab\x8a\xf3\xea\x2e\xb3\x6a\x8e\x49\x66\x35\xa7\x5b\x0f\xbe\x85\xa1\xe7\x4d\x84\x98\xb3\xaa\x31\xb4\x5e\xeb\x81\xda\x16\x21\x93\xe6\xe0\x4b\x0a\x13\x84\x44\x62\x3e\xd1\x3e\xdb\xba\x1d\xf8\xff\xc3\xdb\xa5\xf9\x76\xa9\x3a\xe5\xaa\xee\xa5\x2c\x8d\xe5\x88\x5d\xe5\x0a\x64\x3e\x60\x58\x26\x55\x49\xac\x07\xac\x86\x58\x53\x56\x21\x01\xe7\x1f\x0f\x35\xd1\x80\x6e\xf5\x2c\x72\x0d\x45\x5f\x68\x89\x25\x5f\x79\x66\xbf\xb8\x7c\x85\xa7\x32\x00\x40\xe0\xd4\x76\x02\xe4\xa6\x3c\xb6\xd8\xbb\xe9\xff\x6c\xee\xa2\xea\x3a\x8f\x9a\x62\xb3\x5a\x03\xb7\x00\xa7\x5a\x56\x80\xef\x1e\x1a\x33\x78\xe1\x4d\x83\x2c\xf6\x1d\x63\x2a\x0a\x4a\x08\x8a\x1d\x8e\x40\xf3\xc3\x99\x57\x86\x6d\xf7\xe8\x7a\x9d\xf2\x1b\xfb\x46\xb7\x41\xee\x16\x09\x81\xd6\x2a\x2a\xd7\x6c\xae\x61\xf0\x99\x17\x16\x78\x61\x9b\xfe\x2a\x3f\xf9\x10\x49\x1d\xaa\x5d\x5f\x01\x1b\x2a\xc4\x86\xa5\xb5\xe5\xc7\x5e\x9a\xff\xf0\xcf\xac\xf6\x1c\xae\x54\x38\x68\x62\x6d\x98\xf5\x8a\x1d\xd7\x52\x10\x99\x01\x20\xdb\x71\xbd\xef\x76\xbb\xc6\xbb\xee\xa1\x3c\x76\xe0\xa1\xae\x3f\xa8\xed\xad\x85\xdc\x76\x80\xe0\x96\xcc\x31\x0a\x0f\xf9\xc8\x18\x30\x4e\x07\x0d\xf8\x69\xcd\xef\x2b\x70\xdb\xb8\xb3\xb9\xee\xb1\x9a\x52\xae\xe3\xee\x56\xd5\xcc\x18\xb4\x45\x0a\xb1\xaa\x1d\x08\x98\xb3\x31\x10\x56\x50\x7b\xbe\x11\xc4\x76\xa9\x2b\xfc\x19\x23\x28\x84\x02\xca\xd0\xc3\x94\xe0\xc9\x0d\x58\xd5\xa9\xac\xcb\x19\x1a\xca\x53\x5a\x03\xf4\xa8\xba\xd6\x63\xe5\x60\x89\x4e\x00\x24\xf6\xe5\x74\xfa\x34\x55\x8d\xc4\x7a\xc5\x9c\x1a\x53\x28\x8e\xd0\x6b\xd7\xf7\x4e\xaa\x73\xa8\x36\x55\x27\x76\xd6\xb0\xf4\xa1\x77\x17\x8f\xf0\x5f\x53\xaf\x10\x8b\x26\x4f\xa0\x76\x5c\x88\x15\xf2\xe5\xbe\x67\x91\x24\xf3\x2b\x99\xc0\x33\x29\xe3\xd6\xa2\xe1\x52\x82\x33\x1c\x82\x86\x2a\xce\x2f\xeb\x0a\x53\x5d\x55\xdc\xaa\xb4\x75\x25\x69\x1b\x2a\x43\xf4\xcd\x8f\x30\x8a\x74\xbd\x33\xec\xd0\x8d\x8a\xde\x81\x6d\x63\xe0\xfe\x1e\x26\x84\x53\x4b\xbf\x54\x0d\x52\x06\x08\x73\xdd\x62\x0a\x11\x1a\x02\x12\xf0\x41\x94\xc0\x26\x96\x89\x42\x17\xc0\x6a\x28\x4e\x46\x6c\xc0\x76\xda\x08\xbd\x21\x3a\x50\x6b\x20\x44\x3a\xba\x79\x8f\x11\xa5\xe8\xba\xc6\x3b\x16\x46\x81\xb8\xe9\xc1\x5c\x4d\x78\x52\x6a\xe6\x6b\xdb\x58\x35\x08\xe6\x94\xf7\x84\x1f\x5b\x0a\x50\x35\x18\x7c\x2e\xa7\xa4\xb3\x78\xa4\x8e\xa4\xe1\x43\xef\x70\x14\x6e\x80\xe9\x98\x6c\x07\xde\x17\x54\xcc\xfa\x88\x87\x57\xfd\x9f\xff\x04\x46\x34\xee\xde\x72\xbf\x7f\x7b\x58\x68\x78\x80\x2e\xe1\x03\x8f\x90\x37\x82\xb7\x7c\x06\x6f\x2f\x71\x88\xf3\x7a\xfb\x92\x1a\x4a\x0f\xbf\xe5\xb3\x5f\x84\xef\xe3\xe7\x9f\x87\x5f\x7f\xf2\xbd\x7c\x31\x43\x00\x1c\x6a\xaa\xc7\x18\x6b\xaf\x35\xe4\x02\x53\xa8\xac\xb1\x11\x00\x9c\xac\x8d\x9a\x1e\x45\x3a\x22\x95\x2b\x80\xf9\xb3\xd3\x59\x25\xb9\xc3\x59\xd5\x33\xbb\x6f\xaa\x67\xbe\xd3\xbf\xb4\xc6\x0f\xfc\xe5\xea\xf0\x5e\xfa\xf0\x3a\x87\x51\x0f\x2a\x75\x6d\xa4\xc0\x86\x6c\x64\x52\xe5\xd0\x61\x76\x3d\x58\x18\xf4\xb8\x62\xb9\xfd\xd9\x3d\x88\xad\x9a\x52\x4f\x67\x02\xd4\x3b\x5d\xa7\x8c\x58\x86\x7e\x9c\xe7\xd2\x20\x25\xac\x71\x95\x95\xad\xab\xe2\x34\xe3\xb5\x9a\xba\x1a\x6e\xbe\xaa\x44\xce\x1e\x5a\xc4\x6e\x41\x54\x51\xe5\x47\xc5\xb1\x84\xcd\x05\xf3\x7a\x86\x89\xb7\xe8\xe2\x29\x1a\x70\x9f\xe2\xcf\xa4\x9f\x28\x06\xe9\x0a\x19\xa4\x1c\x1d\x47\x51\x82\x04\x1c\x63\x6c\x4a\x04\x3d\x33\x05\xd5\x5e\xd5\x74\x53\x63\x85\x81\xc3\xc2\xba\xc3\x20\x9d\x4a\xb3\xe9\x13\x70\x97\xba\x3e\xdf\x39\x05\x15\x50\x76\x8f\x9d\x60\xde\x6d\xb1\x1b\x9a\x33\xd3\x2a\x77\xd5\xac\xa6\xc5\x24\xdd\xdd\x66\xca\x61\xe8\xc9\xc8\xcd\x89\x16\xb2\xdb\xe9\xae\x46\x84\x98\xfb\x15\xca\x06\x5a\x0e\x23\xb7\xfd\x7a\x11\x10\xd9\xf6\x2b\x50\x3c\xc8\x16\x35\xf4\x2b\x5b\xe0\xbf\xb2\x55\xab\x6a\x5a\x10\x90\x79\x0a\x59\xaf\xe7\x91\x77\x7d\x37\x4e\x79\x77\x1b\x17\xa6\x1e\x35\x3d\xaf\xba\x82\xf0\x40\x4c\xa3\x00\x61\xeb\x1a\xe2\x90\x1d\xd8\xa2\xca\xce\xee\x6a\xae\x3a\xd3\x99\xea\xa2\xa7\xf4\x68\x7d\x43\xb8\x67\x20\xaa\xdb\xf5\x03\x16\x2a\xb9\x1d\x6a\x06\x95\x9d\x39\x53\xa2\x78\xb8\xda\x96\x00\xa1\x90\x9a\x70\xe5\x78\x00\x41\xbf\x2e\x30\xcb\x15\xd2\x2e\x08\x1c\xeb\x6e\xc1\xbc\xc2\x5d\xb5\xeb\xfd\x7b\x77\xe1\x0d\x27\x86\x42\xd3\xe2\x0f\x3b\x4d\x2f\xb7\xed\x61\x7a\xb5\x13\x84\x99\x29\x54\xbb\x45\xfb\x38\x4f\x1d\xab\x0b\x00\x2f\x9c\xc2\xa2\x61\x18\xbb\xd1\x6e\x7e\x79\xf7\xac\x90\x0e\x44\xf2\x66\x06\x13\x73\x0a\xb5\xaf\xc5\xfe\xac\x96\xbe\xda\x64\x59\x0f\x00\x84\xfc\x06\x6b\x10\x3a\x08\xbe\xbb\xa4\xea\x59\x02\xb1\xda\xd5\xac\x88\xb6\xee\x31\x03\xe7\x8f\x76\x77\x9b\x7b\x09\x95\x0d\xdf\x75\xf8\x11\x61\xeb\xef\x88\x98\x86\xa8\x16\x14\x1e\x6b\xa6\x0a\xf6\xf0\xae\x92\x35\xd8\x92\xc8\x58\x74\x68\xd1\xcc\xac\xc8\x02\x04\xb1\x47\x38\x0f\xe4\x8a\x77\xff\xbf\x76\xc1\x4e\x21\xad\xb9\x20\x9c\xd9\x17\x6a\x6b\x86\x49\xac\xff\x50\x43\x63\x8d\x94\x39\x48\x93\x25\xe6\x34\x3d\x49\xf8\x27\x65\x52\xb0\x96\x43\xee\xb2\x48\xce\x6b\xa4\x4e\x21\xf7\x2b\x18\xe9\x5f\x9c\x0e\x82\x74\x20\x90\x2d\x55\x00\x78\xd5\xaa\x21\x53\xb5\x27\x61\x02\xca\x17\x51\x5d\xb8\x5e\xd5\x6e\x25\x45\xd7\x80\xce\x7a\x48\x7c\x8d\xd2\x0c\x9e\xa8\x14\xd8\x10\x5b\xe8\xc1\x20\x52\x61\x45\xa5\xb1\x59\xb8\x7e\x88\x49\x02\xd5\xf4\xa7\x76\xb1\x28\x5e\xe4\x9a\xf4\x5c\xb1\x45\xca\x96\x28\x95\xcc\x15\xa1\x12\x97\xb3\x6c\x86\xa6\x18\x96\x1e\x44\x89\xc9\x41\x15\x45\x5b\xcc\xb6\x43\xd9\xe3\xe4\xb1\x54\xa0\x1d\x5d\x7e\x2c\x96\x22\x23\x58\x79\x5d\x8d\x16\x4e\xe3\x88\x25\xb1\x3d\xa0\xe5\xbe\x70\x4a\x7e\xfe\xcc\x0c\xf1\x90\x30\x30\x4e\x49\x46\x64\xe2\x14\xe0\x18\x0e\x70\x8e\x8f\xd0\xd3\x1e\x73\x77\x92\x53\xcf\x21\xbb\x71\xaf\xaf\x08\x0a\xcf\x23\x1c\x88\x3f\x3f\x83\x3a\x55\x20\x25\xcc\x0a\x12\x52\x19\x81\x90\xd4\x0e\x09\xef\xe7\xcd\xc4\x1b\xd0\x6a\x15\x1d\x25\xc3\xc1\x09\x29\x2f\xd8\x65\x43\x3c\x38\x5b\xe1\x85\xd4\x7d\xa0\x87\xa9\xb6\x2d\xf6\xa0\x56\x70\x60\x20\x04\x5d\xd5\xa0\xa2\x5c\x51\x7c\x77\x9e\xc7\x3c\xd5\xb6\x8a\xd0\x10\x33\x54\x8c\xc8\x91\xc9\xf9\x34\xe9\x03\xe6\x7c\x55\x5c\x6d\x46\x72\xe4\xb9\x2b\x88\x29\xcc\x5f\x25\xf3\x9a\xa9\x25\x02\xda\x04\xa5\x9d\xc4\x90\x96\xd9\x0a\x3a\xd9\x4d\xc1\xbf\x6a\x2a\xa2\xbc\x22\xee\xd8\x12\x3c\x0e\x88\x85\xea\x63\x46\xda\xa3\x9e\x05\x98\x72\x6a\xbb\xbb\x55\x30\x74\x37\xca\x16\x6d\xf3\x46\x1a\x75\xa2\x1c\xa3\xa6\x90\xfd\x23\x99\xc5\x29\xbb\x3e\x95\xc7\x95\x80\xc8\x6f\x5d\xd5\xc2\x73\x75\xc0\x2f\xce\xa3\xcd\x2d\x57\xcc\xc1\x6c\x3b\x48\x0f\xe5\xae\xb2\x56\x6f\xea\x21\x50\x58\x1b\x11\xd1\x48\x85\x3c\x5c\xf3\xe9\x07\xe1\xa4\xa7\xc3\x1c\xa9\x30\x6e\xb9\xa8\x7d\x20\x4b\xe4\x86\xfd\x57\x15\x0f\x1b\x25\x89\x54\x68\x8b\x7b\x06\xd8\x8d\x10\x51\x1b\x9d\x03\x17\xd0\xb6\xb0\x3c\xaa\xae\x6d\xd9\x32\x2d\x6a\xc0\x1d\xba\x2a\x57\x62\x35\x7f\x31\xed\x70\xb2\x23\xdf\x97\xd6\xd9\x3d\x80\x70\x7c\x65\x4e\x4b\x91\x72\xe8\x5a\x2f\x11\x9f\x72\x93\xa5\x66\xf2\x6f\xb5\x6b\x21\x81\xff\x66\xba\x15\xd2\x79\x6b\xdc\x47\x21\x52\x19\xac\xdb\x9f\x96\xdc\x9a\xff\x0a\x9f\x2a\x3c\x8f\xf9\xca\x3a\xfc\xe5\x49\xee\xa8\xc0\x9f\x9c\x28\x14\x18\xc2\x3b\x49\xf2\x50\x2e\x55\x09\xa3\xed\xaa\xb2\x74\xaf\x4d\x5d\x60\x1a\xc6\x02\x11\x6e\xd3\xea\x82\x9d\x6e\x2e\x46\xf4\x5b\x15\x4c\x03\xf1\x44\xec\x00\xc0\x77\x85\x6d\xb2\x9b\xa3\x2a\x58\x04\xc1\x35\xa8\x81\x09\x67\x4b\x90\x39\xe3\xb3\x9b\xfb\x16\xbd\x16\x38\x60\x5c\x85\xc9\xdc\xfe\x38\x33\x06\x93\xa0\xc4\x88\x27\xf3\x86\x72\x02\x81\x93\xc0\x96\xe0\xcc\xa1\xf5\x43\x92\xee\x08\xa1\xe0\x01\xd3\x7c\xc4\x3c\xe0\x98\x63\xbb\x6d\x14\x53\x23\xd8\xf1\x05\xfa\x25\x55\x20\x21\xdf\xef\xa2\xe7\xa4\xcf\x60\xb6\x98\xa7\xe1\xaa\x47\xe8\xbf\xbd\x6c\x78\x57\x04\x54\xc6\x85\x14\x07\x63\x30\x44\x87\x60\x7b\x6c\xe6\xc2\xd0\x41\xf5\xa5\xa4\x74\x94\xdc\x16\x2a\xc5\xae\x10\xbf\x42\xe5\x8d\xbd\x30\x24\xe2\xd4\x26\xba\xfc\x02\x55\x55\x8e\x4a\x69\xd1\x9b\x1c\xb1\x26\xa8\xb6\x2b\xd8\xf7\x5f\xce\xad\x55\xed\x40\xd2\xc2\x85\x0f\x4a\x52\x75\x9a\x3a\x7e\x53\x05\xd4\x37\x5a\xa2\xfe\x2d\x52\x92\xbe\x30\xbc\xdb\x34\x96\x58\xcb\x95\x5b\xff\x77\x33\x78\x99\x02\xd1\x58\x87\x1a\xb0\x6d\xab\xfa\xc2\xcd\x9d\x98\x0e\x76\x56\xa3\x9b\xc0\x7d\x9d\xe6\xc2\xaa\x46\xc8\xec\x74\x2b\xb8\x8c\x2a\x3e\xc0\x64\xd5\xdd\x98\x0c\x88\xab\xdc\x69\xbc\x03\x45\x70\x49\x47\xe3\xb1\x44\xce\x15\x43\x2f\x3d\xfb\xd0\x69\xb4\x23\x36\x04\x51\x8d\x83\x39\x83\x86\x63\x07\x65\x0d\xb8\xe8\x74\x5d\x83\xf7\xe7\x30\x30\xdb\xee\xd0\xcd\x94\x28\xd0\x35\x93\xe4\xbf\x77\x4d\x53\xe7\x19\xa5\xc6\xf6\xb0\x10\x87\x87\x3a\xf0\xa1\xe9\x4a\x15\x69\x6b\x11\x0e\x65\xf4\x0d\x08\x5c\x61\xa1\x4e\x8b\xca\x88\x35\x66\xdd\xf7\xa5\xd0\x5a\x08\xfc\x60\x3d\x5d\x8a\xe6\xfa\x1a\x73\x56\x35\xd9\xe6\x71\x23\x3a\x62\x61\x5d\xe2\x72\x45\x30\xfd\xab\x69\xde\x94\x73\x0b\x4e\x39\x8a\x91\x79\xf0\x56\x77\x3e\xf6\x50\xea\xb4\x54\xca\x2e\x4c\x5a\xbd\x72\xdb\xdb\x53\xb3\xce\xbb\x92\xac\x42\xaa\xf7\xb8\xac\xc2\x08\x59\x2f\x94\x2e\xf1\x4f\x29\xc7\xa8\xb2\x46\x56\xa4\x52\x28\x2f\xb1\x14\x0b\x86\x96\xd4\x8e\x38\x0a\xe8\x7e\x57\x24\xd6\xbf\xbe\x84\xc2\xe7\xf3\x72\x5a\x8b\x9a\x53\x23\xd7\x63\xe4\xbe\x50\x39\x27\xbc\x5d\x9c\x81\x6d\x1a\x6a\x3a\x0e\xd6\xe3\x41\xbc\xc6\x52\x45\x8d\x3c\x7d\xcb\x04\xf7\xeb\x35\xee\xc0\xbf\x71\x12\xe5\x98\x66\x86\x5a\x38\x39\x70\xed\x3b\x24\x1a\x27\x95\x34\xcd\x25\x03\xe0\x45\xdd\x86\xea\x74\x52\xa9\x27\xc3\x3d\x60\x86\xcc\xf7\xe1\xee\x4d\xc3\xfe\x6a\x7f\x98\xf9\x0f\xde\x9e\xae\x01\xa5\xdd\x22\xdc\xfa\x2d\x55\x6f\xf3\x6a\x0f\x57\x28\x4c\x90\xfb\x4e\x9c\x3e\x02\xac\xb1\x6c\xd2\x49\x97\x12\x32\x49\x37\x36\xc4\xe4\xb8\xbb\x55\xf1\x3e\x63\xf0\x99\xc2\xdc\xd8\x38\x82\xf5\x0c\xab\x6d\xaa\xf4\x61\x39\x91\x3b\xbb\x66\x04\x12\xd6\x8d\xcc\xe1\x77\x31\x57\xaf\x45\xdf\xe1\xea\xe5\x52\x61\xdc\x70\xf0\x80\x46\xd6\x63\x65\xf6\x33\x44\xfa\x60\xc7\x89\x46\x56\x5b\xe2\xd8\xcc\x32\x06\x2b\x06\xa4\xe4\xa8\x0a\x1b\x78\x2b\x29\x24\xb1\x28\x81\x8d\xce\x62\x35\x73\xd8\x57\x56\xea\xaf\xde\x50\xc0\x75\xc9\x70\x02\x02\x00\x75\x9a\x11\x58\x3b\xf7\x6a\xaf\xb3\x79\x63\x3d\xbe\x61\x68\xcc\x3c\xb8\x33\x5e\x28\x7d\x8f\x75\xdc\x9f\x7f\x1a\x21\xc2\x89\xad\x7b\x58\xbf\xa5\xf8\x42\x0e\xdd\x4f\x30\x20\xee\x6e\xb9\xf6\x50\x47\x5a\x74\x4a\xd4\xd4\x52\xc0\xaf\x77\x83\xbf\x13\x5e\x36\x80\x4c\xe0\xdb\x66\xf8\x76\x20\xa6\x8d\x98\xca\x08\x79\xcc\x88\x8a\x63\xe8\xd2\x8f\x98\xaf\x91\x96\xfe\x87\xcb\xf6\x34\x7c\x3b\x24\xe4\x1c\xc4\xc2\xba\xc4\x81\x13\xfc\xac\xb6\x43\xc1\xc5\x34\xf6\x86\x20\x5e\x88\xc8\x89\x71\x62\xcf\x6f\xf9\x4e\x75\x26\x9a\x22\x64\x35\xd7\x15\xa6\xc1\xc7\x2a\x33\x0c\x95\x8d\x40\xc6\xdd\xf1\x57\xbe\x29\x1b\xbc\xc6\xf0\x30\x61\xca\xdc\x0d\x1c\xd5\xaa\xd0\x23\xa1\xfb\xd1\xb8\xb5\xa2\x68\x5f\x76\x53\x9f\x2b\x68\x04\x6a\xd6\x21\x4e\x92\xd2\xc5\x3b\x09\xff\xb6\x4b\xe5\xdc\x3c\x22\x36\x28\x4c\x92\xac\x18\x2b\xbc\x07\x50\xab\x71\xeb\x02\xf3\x60\x18\x99\x04\xb6\x96\xfb\x8f\xf5\xd8\x36\x84\x99\x68\x8c\x50\xab\x4b\x0b\x09\x8e\x3d\xb0\xc3\xab\x43\x09\x9e\xd6\xa8\x47\xcd\xcc\x49\x91\x41\xb5\x48\xc1\x6d\xf0\x32\x0d\xe8\x9e\xf7\x66\xf6\x8c\x6e\x13\x8b\x68\x19\x77\xb0\x9d\x47\xc2\x3c\xda\x88\x75\x98\x29\x07\x37\x40\x2f\xf3\xbc\x03\xdb\xc7\x6a\x28\xdb\x6c\x35\x49\x17\x5a\x4e\x6b\x16\x64\x4f\xd5\xe0\xbf\x7d\x92\x71\x65\x63\xfc\x8f\x13\x78\x9c\x52\x5f\x5a\xdb\x98\x0b\xa0\x2f\x4e\x59\xc2\xe8\x01\xa3\xdd\x55\x65\xf4\x10\x05\xf3\x20\x88\x4c\x96\x85\x62\xa3\xce\xb0\x4c\xcc\x18\x5d\x11\xc6\x2a\x75\xa8\xda\x19\x2b\x76\x05\x4e\x00\xe7\x7e\x9e\x85\xa2\x67\x21\xd9\x59\xc8\x7d\x23\x10\xb0\xcd\x41\x60\x67\x81\xce\xb3\x00\x37\xa7\x79\xa1\xd4\x0c\xd1\xc3\xc0\x3e\x55\xf3\x38\x8c\x79\x1c\xf2\x63\xc7\xe1\xaf\xa7\x96\xa8\x81\xb2\xac\x3d\x07\xd2\x47\x5b\x20\xc0\xf7\xb3\x3e\xfa\xc6\xc9\xc6\x9b\x1e\xc1\x02\xf6\x21\x28\xc6\x46\xe0\x4d\x1b\x68\xac\xb6\xc8\x34\xcc\xed\x5a\xc8\xb8\xf8\xcd\xf3\x08\x20\xb8\x11\xd8\x41\xe0\x91\xf6\x08\xef\x93\x85\x5b\x7a\x03\xa3\x9b\xdc\x6c\xb5\x4d\x8d\x2f\xd7\x16\x00\x2e\x52\x87\x67\xc8\xf8\xc9\x2a\xbf\xdb\xc9\xe6\x68\x29\x48\x32\xce\xff\x8e\xa0\x95\xc9\xad\x6c\x6e\x7c\x2a\x26\x42\x37\x53\x00\x6a\x8f\xc5\xcc\x61\xa7\x62\x11\x05\xc4\xdc\xe1\x56\x3e\x93\x28\xb0\xe3\xe0\x4d\x72\xc2\xc7\xa6\xba\x06\xe2\x17\xaf\x38\x74\x6d\xab\xc5\xa4\xb7\x38\x4c\xaf\x18\xe7\xb8\x9c\x31\x22\x12\x63\x28\x17\x4b\x15\x52\x09\xaa\x93\x07\x7e\xb2\x1a\xc5\xd5\x82\xcb\x90\x96\x2d\x6d\xc3\x14\x9a\x81\xe6\xd8\xda\x8e\x85\x8f\x9d\x9c\x95\x30\xc8\xc3\x31\x94\xba\x87\x44\x2c\x2c\x8e\x98\x73\x54\xf1\x3a\x19\x1a\x62\x24\x9d\xe2\xfc\x6a\x48\x2e\xdd\x07\x3a\xcc\x9c\x40\x8d\x0a\x0f\x6f\x87\xbf\x39\x7d\x84\x44\x79\x1c\xc4\x63\xe9\xbd\x38\x07\x41\x60\x30\x51\x1e\x86\x98\xed\xd3\x55\x52\xe4\xbf\xbd\xe0\x8f\x9c\xd3\xd1\x45\x61\x14\x6f\x8a\x0b\x75\xcb\x38\x2c\xf7\x9c\x12\x1d\x74\x88\x02\xd0\xd1\x1c\x06\xa6\x1a\x3c\xff\x04\x8e\x0c\x9d\xfd\x81\x70\x36\xb2\xbd\x2c\xc4\x73\x6e\xcb\xd2\x42\xb6\x85\x77\xe6\x4f\x77\xf7\xf3\x8e\x09\x36\x37\x91\x9d\x9f\x71\x53\x8e\x2e\xbc\x90\xb4\x23\x76\xcf\x3e\x01\xc0\x05\x55\x38\x9d\x8e\xc0\xac\xfa\x17\x8e\x3b\x0b\x8c\x22\x81\x6a\x20\x40\x69\xe2\x36\xb0\x6e\x4c\x49\xc8\x41\xd0\xa3\x03\x0f\xac\x5a\x7c\xe5\xee\xe1\x34\xbb\xbf\x3d\xb3\xab\x0c\xf1\x96\xb4\x0a\x4e\x52\xa7\x55\x28\x85\xd1\xc6\x42\x99\xd6\x98\x8d\xce\xd3\xf3\x12\xeb\x15\x23\xf7\xdf\xb9\x83\xae\xcc\x3c\x10\x59\xc9\x92\xf3\x78\xe5\xa4\xe7\xae\x2f\xb9\xac\x9c\xe0\xe6\xe2\x55\xad\xd1\x5e\xeb\x42\x9c\x56\xd5\x52\xf3\xfe\x05\xcc\x92\x11\x7a\xe6\x55\x65\xba\xda\x91\xac\x76\xf2\xc3\x8f\xfd\x9f\x2e\x30\x76\x15\x3d\xae\x85\xd6\x28\xd9\xd1\x6b\xc9\x2b\x23\x7e\xd0\xcb\xca\x35\x87\xdc\xcb\x42\x39\xaf\x11\x22\x14\x40\xb7\xaa\x1d\x57\x54\xe2\x55\x72\x49\x98\x74\x08\x0a\x23\x4a\x52\x48\x7b\x2d\x26\xf2\xef\x2f\xf9\x39\x86\xca\xf3\x2a\x88\xbb\xd2\x58\xb9\x73\xa8\x34\x14\xd3\xae\xba\x29\xf1\xce\x47\x2c\xc0\xaa\xa5\x1c\x25\x5d\x81\xe5\xff\xf3\x6b\x38\x39\xa5\xb5\x66\x45\xba\xb9\x2d\xb1\x52\xc7\x11\x68\xbd\x03\xf6\xae\xb1\x8a\x59\xcb\x63\xa9\x89\x37\xd2\x83\x0f\x57\x72\x35\x1a\x77\x3d\x5c\x2b\x5f\xa3\x41\xfd\x2f\x4e\x95\x87\x83\xab\xf3\x41\xa5\xe4\xa5\xf4\x0a\x4b\x74\x89\xb9\x98\xb7\xa3\x2c\xb9\xe0\xac\xd5\x25\x96\x6b\x1e\xd3\xff\xf5\x5e\x14\x86\x47\x5f\x55\xc7\xd5\xbc\x4e\x86\xec\xf0\x0c\x8c\x6b\xeb\xf8\xbf\xf9\xe5\x48\x41\xac\x78\x20\x9e\x8c\x41\xe8\x68\xcc\x14\x2c\x60\x5f\xf5\x7a\x10\x5d\x79\xa7\xff\xdd\x6f\x34\x52\x68\x85\xb1\x22\x85\x33\xb6\x5e\x53\x53\x9d\x79\x35\x45\xa8\x2b\xa3\x40\x42\xa0\x01\x19\x81\x8b\x2b\x83\xfb\x3f\xce\x40\x5a\x14\x15\x41\x67\x7c\xab\x23\xe2\xf5\xf0\x45\xff\xe7\x25\x0f\x81\x04\x8c\xc2\x1a\xd4\x22\xc4\x7c\x14\x30\x04\xaa\x84\x62\xb9\x31\x16\x96\x41\x40\x29\xeb\x28\x4f\x82\x60\xac\x70\x6b\x21\x69\x91\xc7\xe4\x40\x66\xe7\x54\x6e\x91\x41\xf7\xcc\x14\x1a\xf4\xae\x19\x83\x9e\x35\xe3\xe0\x97\xda\xd5\xb4\xd2\xe7\x17\x1b\x9f\x05\x78\x07\xc4\x04\x0e\xcc\xb2\x4b\xa1\x30\xd2\x42\xad\x1d\x52\x3c\x8f\xc2\x6e\x4d\xc3\xfc\x3c\x80\x8e\xc5\x62\xd2\x05\x62\x88\x0d\x76\x94\x35\x36\x06\xd1\x0d\xec\x41\x0a\xa0\xd3\x0a\x6d\x84\x78\x3b\x5b\x2a\x55\x6f\x1e\xbe\xe0\x3e\x8e\x58\x7a\x52\x3b\x6e\x1c\xe6\x82\x2a\x53\x0e\x8a\x54\x4f\xca\x70\x9a\x8f\xd1\x59\x64\x87\xb7\x7d\xf2\x23\x78\xc6\x58\x2d\xfc\x32\x14\xbd\xe4\x1e\xb8\xcc\x80\x3d\xd4\x25\xc9\xae\x6f\x18\x73\x0b\x33\x71\x29\x4d\x12\x25\x02\x3f\xb9\x99\x84\x46\x00\x08\x0f\x2a\xbc\x71\x0a\x6a\x75\x51\x50\x6b\xbd\xd2\x82\x88\x2c\xc3\xef\x65\xce\x72\x67\xd7\xd2\x86\xa4\x00\xb3\x07\xcd\xf0\x41\x3a\x83\x2a\x78\xb8\xda\x2d\x2b\x2a\xba\x02\xbe\x1a\xbc\xfd\xfc\x42\x09\x4a\x07\x49\xe5\x85\x54\x78\x58\x28\x20\x39\x22\x98\x34\x32\xba\xb8\x8f\x0a\xe7\x2d\xab\xa4\xc5\x12\x82\xec\x8c\x40\x50\x06\xf5\xa7\x9b\x23\xf9\x5e\xd4\xcc\x14\x79\xda\x91\xe7\x08\xee\x19\x88\xee\x96\xca\x04\x48\x05\xcb\xc1\x33\xdd\xcc\x81\xb6\x7b\x06\xac\x38\xa3\x43\x4d\xde\x33\xb8\x58\x7a\x30\x27\xcc\x50\xe5\xe7\x79\x3a\x2a\x49\x46\xbe\xbb\xe5\xc6\x21\x8f\xea\x39\x80\x36\x3f\xb9\xcc\xa0\xa7\x2d\xa6\x4d\x79\xac\xc5\x09\x3c\x59\x36\x41\xca\x9e\x31\xa2\x22\x37\xa3\xb8\xc6\xb6\x81\x51\x37\xc0\x86\x19\xa4\x46\x83\xed\x75\xb8\x0e\x2d\x3e\x5a\x8d\xbd\x44\xbd\xaa\xcd\x07\x08\x9f\x77\xcf\xa8\x19\xfd\xc2\x4e\xef\x6e\x3e\x21\x22\xe6\xc9\x47\x38\x8c\xc6\x3d\xe6\x94\x1e\x5e\xa6\x2f\x2e\x10\x3d\x57\xb0\xfb\x53\x36\xdb\xc9\xce\xc7\x68\x0a\x9f\x76\xb3\x6a\x28\xd1\xae\x32\x49\xcc\x13\xab\x8f\x86\xd2\xcb\x75\x37\x42\x15\x77\x95\x4b\xf0\x7e\x5b\xfe\x6c\x55\x38\x62\xe9\x59\x8c\x34\x43\x4f\x25\xc2\xe9\xcf\x03\x91\x07\x6c\x6a\x7d\xfd\x76\x3a\x62\xcd\xf7\x6a\x8e\x58\x33\xf4\x8c\xf9\xe7\xb9\x9e\x06\x28\x1c\xa9\xe5\x3c\x59\xe6\xce\xd2\xf3\x1c\x5a\x32\x3c\x83\xb5\x30\x36\xb1\x45\x28\x31\xaf\x1b\x61\xea\x39\x5b\x30\xa2\x23\x8e\xa2\x76\x1f\xf0\x31\x7c\xfb\xc8\x1a\xcb\xfd\x62\x0b\x5a\x2c\xb9\x19\xa2\xf6\x04\x80\x31\x09\xfb\xd1\xe7\xec\x8a\x40\x7f\x71\x52\x0f\x8c\x59\x48\x96\x19\xa8\xdb\x72\x90\x39\x10\x11\x01\xee\x66\x02\x53\xe0\xbe\x8d\xd3\x30\xce\x79\x37\x93\x8b\xfa\xa1\x86\x0d\x95\x3e\x9d\x4c\x6e\x50\x78\xfc\x63\x9e\x8b\x15\x48\x84\x90\x60\x91\x07\xec\xd2\x5e\xe1\x1b\xd8\x62\x47\x5c\xa8\x87\x96\x0e\xb5\x74\x33\x60\xf4\x4c\x39\x64\xa3\xaa\x22\xfe\x39\x13\x2d\x10\x33\xb5\x45\x23\xb3\x3a\x18\x3e\xf1\xf9\xe2\xa4\xaf\x61\x39\x16\x25\x19\xf4\x6b\x35\x38\x87\x0e\x66\xcb\x6e\x16\x97\x25\x34\x6f\x60\x68\x57\x8b\xdb\x18\x53\x12\x6c\x2d\x80\x74\xe8\x0c\xb1\xb2\x02\x1b\x4b\x68\x39\x20\x8d\xbc\x39\x93\xb2\x4e\xef\x37\x0e\x40\x1f\xee\xfc\x36\x91\x64\x19\x21\x40\xe6\xd2\x02\xd2\x5b\xba\x93\x7b\xa0\x9a\x88\x2e\xb1\x72\x9a\xde\x6e\x38\x39\x61\xf5\xf6\x6e\xa9\x94\x48\x6f\x6b\x57\xce\xcb\xcb\x8b\xb2\xc9\x15\x27\x93\x40\x25\x60\xa2\x7d\x5c\x7c\x4d\x24\x35\x0c\x95\x0a\x6d\xba\x39\x8c\x72\x9e\x2f\x0c\x41\x15\x6f\xe0\xcc\x9a\xe8\x92\xbe\x3b\x4d\x7e\x78\x5e\x0c\x1c\x53\x46\x1a\x15\x23\x53\x2b\x70\x85\x7f\x63\x74\xa3\xf4\x38\x8e\x77\xdf\x71\xba\xe7\x32\xb1\xd0\x08\xa5\xe9\xa2\xdf\x28\x17\x8f\x40\xa8\x66\x83\x35\xad\xfb\x9d\xb0\xdf\xf5\xfe\x40\xc7\x59\x2e\x61\xf4\xde\x00\xc4\x76\x3b\x62\x61\x48\xd8\xa3\xbf\xa2\x87\x1d\x02\xa7\x6e\x2a\xaa\x54\x5a\x0a\xa9\x70\xef\xc1\xea\x38\xec\x14\x3c\x7f\x10\x02\x14\xf2\xaa\x39\x29\xac\x27\x18\x57\xee\x95\xf3\x1c\xdc\x93\xaa\xab\xe8\x73\x20\xbe\x11\xf9\x1a\x40\x7a\x35\xb5\xcb\x08\xad\xe6\x83\xa8\x2d\x9c\xe4\x18\xe0\x9e\xa6\x11\x4c\x78\x76\x90\xe8\xf4\xb4\xc9\x99\xe3\x01\x6a\x09\xe5\x8c\xcc\xe0\x8d\xb0\xc7\xc1\x20\x20\x1e\x6b\xac\xcd\x80\x8d\x27\x2e\x40\xaa\xdb\x3e\xc9\x93\x7e\xaa\xef\xad\x02\xa2\x37\x4b\x52\xd0\x53\x09\x6f\xe6\x99\xb6\xc2\x4e\x6b\xb4\x7c\x8f\xe4\x89\xc2\xf9\xa2\x35\xa1\x32\x8e\xd8\x68\x91\x04\x4c\xda\x96\x88\x4f\x0d\x15\x17\x32\x1d\xf8\xc0\xe9\x8a\x1d\xf8\xa5\x43\xb9\x3e\x2d\x62\x95\xc5\x54\x74\x3d\xda\x16\x41\x31\x51\x6d\x81\x7c\x46\xd3\x2f\xa9\x06\x6a\x1d\x5c\x0d\x60\xd9\x64\xdc\xbc\x74\xb2\xb0\xb0\x33\xcd\xee\xe7\xee\x87\xac\x59\xb4\x78\xee\xa3\x46\x3b\x99\x17\xa9\xba\x23\x85\x61\x67\x25\x95\x54\x5d\x0f\x6a\x0e\x3d\x2f\x5c\x57\x6c\x2a\x68\x80\x1c\x3c\xeb\x24\xc8\x6e\x3f\x69\x8b\xc3\x7d\x6b\xaa\x39\xcc\xfb\xa1\x5a\x15\xa4\xd1\x8b\x19\x5e\x27\x21\x23\x36\x1b\xf0\xa5\x1e\x02\xb8\x8f\xd0\xf2\x75\x26\xfb\x22\x8e\x2e\x1b\x72\x4f\xcd\x18\x02\x82\xdb\x10\x7d\x0b\xc6\x57\x80\xe6\xf7\x14\x4e\x38\x20\xe0\x18\x6d\x23\xc8\xae\x53\xb6\x0d\xbe\x50\x72\xdc\xfb\x68\xd9\x5a\xc3\xdc\x44\x08\xd1\x78\xfd\x06\xf3\x98\x97\x72\x0e\x34\xb5\xdd\x88\x39\x3a\x4e\xf3\x3d\x56\x83\x17\xdd\xed\xf1\x0b\xae\x1a\xd9\x5d\x21\x6a\xe7\xe6\xee\xb1\x1f\xe7\xb6\x83\xb8\xa4\xc0\x4f\xad\xf7\x61\xfc\x24\xb2\xa2\x17\x26\xce\xdc\x3b\x98\xcb\x3e\x9c\x4b\xb1\xcf\x58\xa5\x6e\x68\x38\xd7\xd4\x40\xcd\xe6\xb8\x61\xb0\x18\x10\xd5\xae\x80\xd3\x6a\x7e\x8b\x69\x67\x04\x16\x91\x98\x83\x1f\xa7\xc4\x37\x66\xc0\x64\x01\xb4\xcd\x0b\x2d\x54\xaf\xb8\x40\x59\xee\x6e\xb9\xf4\x50\xb3\xf8\xf8\x0c\xfe\xb4\xb1\xe7\x3c\x89\xd8\xee\x9f\x35\x32\x69\xb5\x34\x00\x90\x44\x71\x9e\xf0\xe7\x5c\xf6\x3c\xab\x76\x20\xb9\x07\x25\x25\xf4\xc3\x30\x1a\xd8\x25\x5b\x3d\x97\x00\xcf\xb4\xf3\xc0\x8a\x79\xed\xf5\x60\x55\x36\x0e\x81\xfe\x07\x92\xec\xc9\x1d\x6e\xed\x1a\x38\x5d\x66\x9e\xd4\x3d\x70\x0a\xcd\xc5\x41\xb7\xd5\xae\xff\xf3\xb0\xe8\x98\x21\x4e\x5d\x0f\x8f\x9b\x65\xd9\x8a\xda\x26\x81\xa4\x07\x92\xb6\xab\x96\x2e\xe4\x74\x0d\x67\xf8\xaa\xe8\x34\x96\x0d\x08\x2c\xe6\x94\x32\x3c\xeb\x3e\x18\x15\xfe\x47\x2c\x15\x41\xf2\xaa\x9a\xdd\x63\x3b\xb1\xe8\x12\x3a\x75\x9c\x61\x1d\x4c\xf6\xa4\x91\x11\x20\x37\x09\x95\x31\xbc\x64\xc8\x48\x33\x05\x11\x90\xf8\x88\x45\xe0\x18\xbd\xa2\xc6\xbe\x72\xbb\x2e\xc1\x33\x4b\x63\x61\x19\x47\x1d\x1d\x65\x5d\xf0\x0b\x69\xe5\x88\x5d\xe5\x2a\x8d\x19\x65\x4d\xf5\xee\x36\x93\x22\xf3\x9c\x9c\xf2\x97\x42\x93\xbd\x51\x90\xb4\x88\xad\x70\x2b\x96\xf0\xb5\xab\x5d\xdf\xf2\x8c\x9a\x1b\x45\xbe\x9d\x0e\x65\x84\xcb\xed\x23\x88\x15\x2a\x6c\x1e\x1e\xeb\xff\x75\xd2\x98\xd4\xc2\x45\x0c\x97\xdb\x66\x95\x8a\x2c\xfd\x28\x79\x18\x57\x1c\x07\x02\x0e\xd9\x99\x95\xae\xa3\x8a\xcc\x41\xc5\x32\xf3\x92\xe7\x39\x87\x73\x81\xe7\xca\x70\x92\x9b\x72\xb4\xd6\x97\x68\xe4\x50\x5a\x10\xb9\xee\x83\xb6\x33\x4b\x5e\xf7\x42\x27\x27\xae\xf3\x85\xe9\x66\x47\xd7\xa2\x5f\xd1\xf2\x68\xa8\xdb\xf1\xea\x2d\xa0\x7a\x48\x81\x38\x96\x66\x64\x47\xa1\xd0\xea\x26\xc9\xe6\xef\xfe\xe4\x5d\x5c\xee\x86\x06\x80\xf9\xbd\x2a\x83\xa7\xcf\xf9\x4c\xde\x73\xce\xb7\x73\x26\x39\xb4\xab\xe4\xe9\xff\xfb\xb5\x18\x2c\x36\x7d\xed\xf7\xa3\xc3\x75\x46\x87\x11\xfd\xef\x49\xd6\x5c\x47\xc8\x92\x21\xa3\x11\x1d\xee\x67\x74\x58\x06\x78\x0a\xb4\x66\xb5\xfe\x4b\x19\x6b\x54\xd3\x20\xf6\x35\xa2\x5a\x50\x6b\x97\x1c\xc8\x23\x22\xe1\xec\xea\x6e\x5c\x2f\x29\x2b\xbe\x1b\x5b\x3d\x88\x58\x75\x20\xb4\xfb\x58\xb2\x05\x83\xb3\x2c\xdc\x66\xd4\xbf\x5d\x33\x6a\x7e\x77\xea\xc7\x74\x0c\xa9\x0b\x49\x39\xe2\xe0\x4d\x44\xc1\x48\xcf\xe0\x1c\xab\x2a\x30\x96\x15\x30\x21\xcc\x16\xa4\x77\x28\xfc\x85\x05\xc5\x2d\x54\xfd\x3a\x9c\x9d\xbb\x65\x0e\x49\xdf\x86\xb1\x99\x54\xcb\xf4\x0d\x3f\x44\x4d\x6b\xb8\xc4\x22\x55\xd5\xeb\x7a\xf4\xa4\x1e\xb5\xaa\xfc\xae\x62\x9e\xff\xe4\x1c\xcc\x52\x2f\x39\x57\x76\x3c\x5a\xb0\x34\xd1\x14\x3c\x05\xd4\x58\x9c\x90\x04\x7e\x80\x6c\x2f\xec\x58\xab\x4e\x47\xac\x84\x68\x76\x3b\x6a\x31\x00\x70\x72\x36\x4b\x55\x49\x09\x58\x3d\x66\xe1\xb0\x71\x26\x9e\x7a\xb9\x0d\x5d\xe0\xca\x65\xb9\x5e\x81\xe2\xeb\x4b\x82\x85\x4f\x22\x78\x17\xb5\x6e\x45\x4c\xf4\xd5\xd7\x44\x9f\x39\x22\xf2\x45\xf4\xf1\x29\xfa\xcc\x2f\xe4\xa2\x8f\xde\x5d\xf4\xd5\x29\xfa\x3a\x7c\x38\xd3\x1c\x1c\xe4\x6a\xd3\x1e\x71\x8a\xbe\x2b\x1c\x89\x6f\x4e\xc6\x76\xb6\xa7\xaa\xc1\x5b\xd5\x74\xd3\x51\xd7\x40\xa5\x81\xb6\xa3\x90\x83\xaa\x13\xcd\x48\x17\xd1\x92\x4a\x44\xf1\x77\xb3\x2c\x46\xac\x0e\xfc\x0b\xce\x71\xa4\x12\x7c\xb1\x38\x95\xdd\xa2\x20\xb6\x84\x1e\xbc\xb3\x32\x20\xa0\xba\x48\xbe\x40\xa1\x61\x86\x25\xc8\xfd\x9e\x06\x7f\xda\x57\x88\x1d\xaa\x7d\xd5\x43\x6e\x90\x46\x9d\xad\xae\x8d\x05\x1b\xf7\x9a\xce\xb4\xb4\xa1\xb6\xae\xe7\x4d\x45\x6e\x0e\x61\x38\x9b\xf3\x5e\x91\x53\xb1\xf4\x12\x39\x9d\xf7\xc5\x80\x1f\xac\x1e\xb9\xd4\xe9\xa8\x7c\xa6\xa1\x44\xd0\x23\x9b\xd7\xa4\x2a\xe7\xbe\xf5\xbc\x2b\xfb\x87\x5e\x6f\x5f\xa9\xd3\x82\xdf\xa3\x8f\xb2\x5c\xcd\x58\xff\xfd\xc5\x4b\xa4\x16\xb7\x93\x56\xf2\x40\xa2\xb3\x8a\x1d\xf8\x81\xaa\x27\xec\x51\x51\x71\x74\xf1\x03\xdd\x67\x4f\x23\xd7\x13\x29\x09\x36\x29\x6e\xec\x93\xb8\x89\x18\x99\x66\xee\xbe\x17\x22\xe1\x0b\x2a\xcf\x26\x4c\xf9\xe2\x04\x32\x6e\xe4\x24\x98\x53\x1a\x47\xcc\x55\xcf\x4b\x21\xf3\x02\x49\x1f\x1b\x5c\x4e\x1c\x10\xc4\x30\xc4\x68\xd8\x53\x65\x8a\x45\x68\xd9\xd0\xce\xc8\x76\xea\xeb\xf0\x0a\x36\xfa\x4a\x08\x76\xc1\xb7\x93\x80\xd6\x59\x51\x0f\x43\xcc\xca\x4c\xb6\x84\x69\x98\x2d\x14\x95\xc7\x1e\x2d\x92\x35\x2e\x3e\x42\x1b\xfb\x01\x6a\xf0\x83\x33\xbc\x9d\x94\xa0\xdc\x50\x42\x89\x04\x21\xf0\xc4\xba\x5b\x2c\x56\xac\x60\x1a\xe1\x69\x9d\x60\x91\xe9\xe0\x2c\x66\x97\x6e\x84\x0d\x1e\xf0\x23\x1f\x24\x6d\x21\x19\x97\x8a\x02\xed\xc8\x83\x37\x28\x28\x73\x24\xd0\x74\x24\xe8\x2e\xcf\x15\x8c\xf5\xe4\xdb\xc0\x33\x4e\x51\x1c\x2e\x91\x25\xc4\xe9\x51\xe6\x31\xeb\x36\x98\x27\x21\x5b\x75\x88\xe1\x29\xf0\x9e\xaa\x65\xe1\x45\x38\x3a\x27\x1e\x9f\xb9\xea\xe5\x24\x07\x12\x7c\x0e\xbd\x87\x1d\xc8\x91\x41\xf2\x67\xb5\xf8\x2d\x23\x51\xad\x4f\x4b\x49\x6c\x63\xda\x6c\x93\x68\x40\xd3\x25\x60\x44\x5f\x0b\x4f\x8e\x7b\xb3\x5d\xae\xa6\xe9\x7e\x3b\x21\x95\xc2\x8d\x63\x48\x5f\x08\x2c\x2a\x48\x3b\xd5\xee\x43\xb1\x22\x4c\xaa\x92\x76\x32\xbf\x2f\x6f\xe6\x73\x66\x2b\xcd\xc2\x2b\x4a\x17\x52\x26\x38\xc5\x01\x69\x29\x14\xda\xad\xb6\x8c\x65\xcd\x64\xab\x6a\x35\xfd\xc5\x9b\x5e\x72\xfa\x3a\xfd\x90\x8a\xe5\xd9\xec\xb1\x61\x31\x54\xf5\x00\xb8\xd3\x11\x73\x69\x8f\x70\xf1\xbe\x9b\xfe\x40\xa0\x2c\x0b\x5e\x3b\x61\x4e\x07\x36\x76\x27\x05\xc0\xc9\x5f\xe0\x14\x9e\x1e\x07\x36\xdf\x8e\x42\x6f\x77\x74\x02\x97\x01\x21\x01\xff\xeb\x8e\xee\x62\x74\x8a\x56\x83\x24\xcb\xf8\xce\xcd\x00\xb1\xbe\xce\x66\xc5\xff\xe0\x6d\x1c\x58\x27\xc3\x86\x90\x94\x78\x05\x1a\x60\x34\x37\x4b\x31\x37\x46\xb3\xda\xd8\x65\x60\x9e\xb2\x84\x3a\xad\x08\x64\x23\xe5\x61\x64\xbe\x91\xd5\xca\x6b\x46\x49\xb1\xfa\x5f\x96\xa9\xa1\xeb\xba\x31\x68\x96\x02\x27\x66\x6e\x6b\x84\x1c\x41\xb2\x36\x42\xab\xe6\x60\xbf\xf8\x01\x92\xfb\x98\x0c\x17\x65\xab\x78\xe1\xd9\x95\x39\x21\xb2\x9d\x82\x43\x34\x73\xed\x9f\x9b\x74\x8f\x6a\x22\x65\xb6\x4a\x62\x66\xf0\x72\x41\x75\x06\x78\x32\x41\xc0\xea\xa0\x53\xab\x76\x55\x21\x85\x04\x43\x94\x36\xd3\xa5\x37\xa9\xe7\x75\x3e\x5d\xbe\xce\x92\x94\x74\xda\xa3\x4e\xe5\xec\x1e\xe0\x8d\x5e\xed\xc5\xf9\x5b\x37\x93\x7b\xa8\xdb\xcc\x4a\x34\x8c\xa2\x2b\xfd\xf0\xa6\xd8\x2f\xe6\x52\xa7\x62\x0c\x4d\x35\xf3\xab\xee\xdb\x55\x85\x1e\xd7\xcd\xeb\x4a\x95\x49\xe6\x73\x8a\xfe\x6a\xfe\x67\x9e\xbe\x0e\x26\xf8\x3a\x36\x23\x79\x80\xf1\xda\x21\xfb\x3d\x8d\x1e\x64\xf3\x72\x41\x0a\xc0\x02\x48\x54\x82\xab\xac\xcd\x63\x6a\xf5\x23\x38\x8d\xd0\xf3\x9a\x8d\x31\xb4\x81\x59\x06\x82\x57\xe4\x61\x9f\x36\x58\x89\x90\xd0\x39\xf4\xb1\xc5\xca\xa8\xf5\xa2\x83\x2e\xed\x40\xe6\x62\xcb\x21\x07\xea\x63\xd7\x37\xaa\x75\x89\x4c\x57\x8e\xc7\xdf\x4d\x7d\xd5\x42\xa6\xbc\x72\x28\xcc\x8b\x8a\xc0\x58\x98\x5d\x60\x79\xd6\x03\x62\x11\xd9\xc2\x02\x17\xb7\x34\x1c\x9c\xdd\xcb\x48\xe8\xa1\x18\x21\x87\x31\x9d\x4b\x7b\x27\x54\x8b\xdb\x4b\x0d\x96\xc3\x9c\xa6\x6f\xe6\x28\xa4\x18\x2c\x1d\xb1\x1b\xc5\x30\x37\xf3\xeb\x02\x58\xa3\x1e\x94\x0a\xe8\x6c\x3e\xbb\x84\xe4\xfa\x95\x43\xa3\xfb\x2e\x5e\x72\x03\x71\x9f\x79\x97\x39\x9f\xd9\xa3\x26\x81\xeb\xe4\x04\xa9\x32\xb2\x68\x84\xcc\xea\x36\x34\xda\x95\x18\xfc\x71\xc9\x82\x53\xa4\xd8\xea\xa4\x76\xca\xdc\xf4\xe2\x3e\x17\x1d\x38\x58\xc7\x2b\x5b\xa1\xd6\xbc\xaa\x04\x94\xdc\x37\x14\x95\x14\x1c\x51\x30\x07\x8d\x2e\xa6\x78\x40\x4c\x1f\x5a\x79\x0c\x8b\x7d\x11\x4a\x55\xe9\x7e\x13\x5e\x22\x51\x5e\xa3\x28\xb6\xbf\x46\x45\xfa\xc3\xcc\xa9\xb4\x11\x2a\xc2\x38\x6d\x9f\x3c\x1d\xe8\x9e\xe7\x6d\x3c\x0a\xb8\xd0\x2d\xfc\x5f\x5b\x5e\xa9\xa6\x50\x6b\x5e\x46\x5a\x69\x8c\x10\x6b\x65\x35\x10\x54\x79\x67\x95\x45\xcd\x18\x57\x34\xf2\x4e\x56\xf8\xb1\xed\xd0\x71\x87\xd0\x42\x2a\xb2\xe0\xb1\x42\x9e\x06\xa4\x63\x6e\x97\x54\xad\x98\x2b\xf2\x48\x48\xd4\x8c\xb2\x5c\xc7\x15\x29\xc5\x6a\x74\x3f\xc2\x48\xfd\xde\x6d\xe3\x1a\xd2\x2a\x92\x42\x6e\xc5\x78\x01\xb9\xd2\x42\x95\x57\x56\x69\x23\xb9\xae\x2c\x12\x24\x57\x0f\xe6\xab\x82\xc8\xa5\xac\x02\x61\xd4\x69\xd1\x0d\x61\x3c\x58\xa9\x7a\x66\x71\x19\x00\xcf\xb5\x0c\xec\xbf\xf7\xb2\x79\x00\x9a\x75\x6d\x1d\xb1\xd1\x6a\xb6\x8e\x47\xf6\xaa\x39\x4f\x56\x48\xea\x0d\xdc\x14\xa0\x83\xbe\xbb\xfb\x1a\xb5\x2b\xcb\x74\x5e\x9d\x86\x98\x00\x5f\x93\xc8\x8a\x82\x8f\xba\xb6\x1c\x7a\x05\xa5\x21\xd4\xba\x50\xe7\xe9\x23\xbf\xbf\x78\x4c\x73\xf1\x80\x5c\x56\x6e\x30\x41\xfa\x4a\xad\x87\x92\xb0\x60\x8d\x43\x16\xe3\xec\xed\xec\xf9\xcc\xaa\xa9\x4d\x20\xa9\xf2\x91\x7b\x9e\x9a\x59\xf1\x05\x84\x33\x4b\xe7\xa8\x2d\x85\xd5\xb2\xe9\x13\x6f\x5e\xf9\x17\xfe\x63\x7d\x5b\x8f\x29\x36\x27\xd4\x58\x9a\x1a\xa4\x4f\x09\xfd\x8a\xb9\x7a\xf7\x26\x5d\xa2\xf4\x14\x5a\x6a\x4b\x2c\xd2\x8c\x2d\xc1\xcd\xd9\x12\xa5\x2a\xc4\x4f\x63\x29\xa5\xbc\x4e\x96\xe0\xfb\x64\x09\xbe\xf2\xa8\xff\x67\x3e\x6a\x84\x5c\xdb\x41\x54\x16\xb5\x68\x2d\x36\xc1\xc6\x30\x83\x82\xc1\x76\x30\xe5\x9f\x82\x14\x35\x83\x24\x48\x69\x56\xd7\x0d\x1e\x6b\xaa\x7d\x83\xcd\x9f\x2c\x7e\xa7\x18\x78\x05\x5e\x85\x2d\x04\xe7\xb0\x4e\xbc\xee\xb6\x0d\x6e\xfd\xd2\x02\x7e\x0a\xb5\x15\x95\x78\x9d\x96\x24\x56\x00\x46\x6f\x03\xc3\x7c\x9c\xa2\x72\x41\x81\x5d\x1d\x66\x6c\x6a\x2e\x19\xd2\x69\x2d\xb4\x19\xba\x2d\x46\x6d\x43\xee\x27\x38\x8b\x7a\x16\xd7\x1e\xac\xf0\x0e\x09\x12\x45\x83\x2a\x1a\xb5\xaf\x14\x05\x2f\xf1\x1a\x56\xfe\x7f\x7d\x4b\x63\xf3\xa7\x71\x50\xcd\x79\x21\xd4\x76\xd3\x4f\xd7\x09\xda\xff\xdf\x2c\xbc\xd5\x03\x51\xef\x88\x47\xd4\xbc\x21\xad\xca\xc3\xd5\x80\xd7\x8a\x91\x11\xcc\x6b\x97\x38\x26\xe2\x8c\xc3\x27\x24\xb7\x59\xd7\xd6\xc8\x88\xa8\x5d\x10\x62\xa1\x05\x19\x3a\xe0\x92\x64\x84\xaa\x3c\xe1\x3f\xe6\x66\x8e\x02\xea\xbc\xd6\xb3\xde\x10\x14\xab\x93\x62\xa7\x63\xd9\xb8\x6f\x20\x30\x52\xed\x58\x7b\x22\xd9\x10\x17\x02\x90\x60\x45\x74\x6d\x67\x95\xc3\xa7\x79\xa8\xd3\xdb\x73\x28\x03\x2e\x7e\xa2\x15\xe5\x0c\x18\xe9\x65\xdd\x4a\xd1\x50\x0b\x1b\x56\x1a\xd5\x57\x5b\x0f\x92\x64\xad\xc1\xf6\x01\x3c\x13\xc5\x68\x62\x6d\x26\xb0\x94\xf4\x48\xae\xc0\xff\x7f\xa9\x81\x58\xa1\x15\xba\xe5\xc0\x91\x10\x02\x37\x85\xbc\x04\x08\xb3\x33\xdd\x3a\x39\xfc\xec\xc8\x82\x36\x92\x47\x6b\xc6\xa0\x1c\x4e\x28\x51\x81\xa2\x48\x75\x45\x85\x8c\x6e\xf1\x71\x94\x39\x37\x1f\x1e\x4f\x57\xaa\x05\x13\x1b\xcf\xf2\xa1\x88\x3f\x5c\x92\xe4\x68\x18\xe7\x56\x1f\x64\xb4\x91\x56\x81\x28\x54\x8f\x75\x3e\xb9\x6c\x56\xc7\xf5\x0a\xa2\xfa\xf5\x27\xdf\x3f\x4f\xcf\xae\xfe\x89\x9e\x5d\x6a\xc7\x93\xe5\x1b\x9d\x39\xf8\xd5\x33\xf0\x1b\x6c\x20\x69\xbb\xaa\x94\xc7\xab\xc7\x7b\xa5\x83\x0a\x6a\xa5\x14\xd4\x2e\x46\xb0\xc6\x2a\x7b\xdb\xae\x63\x09\x96\x3f\xb9\x57\x6c\x87\xd5\xd2\x41\x56\x69\xa1\xd4\xb6\x50\x92\x55\x92\x4a\xb5\xb6\x31\xbc\xed\xf7\x8a\xae\x9c\x4e\x50\x15\xff\x7d\x17\x5d\x0e\x64\xd6\xb2\x7b\x4d\x29\xa1\x06\x84\x22\x5b\xf3\x4d\x65\x72\x17\x18\xf1\x15\xa8\xa5\xf3\x30\xab\xc5\x8f\x1e\x0a\x4a\xc4\xe8\x62\x2a\x54\x03\x6d\x58\xac\xaa\xcc\x6e\x51\x55\x4a\xb2\x93\x9a\xb9\x62\xa5\xcd\x98\x87\x69\x6f\xca\x53\xd1\xf7\x33\x52\x4e\xa6\xe9\x57\x0b\x7c\xd4\xbe\x21\xe8\x2d\x84\x00\xa9\x95\x01\x37\x71\x72\xa6\x54\x4e\xaa\x75\xbc\xd4\x4a\x2a\x03\xc5\xf9\xa8\x50\x18\x7d\x85\x93\xad\x51\x9d\x75\x3c\x74\xe9\x28\xaf\x16\xbd\x4a\x9e\xaf\x8c\x5a\x1f\x50\xba\x94\x71\x0e\x57\x87\x05\x69\x35\xba\x7d\x59\xb9\x07\x16\xd2\x13\x55\x2c\xfb\x94\xb3\x93\xb5\x07\x05\xa1\x71\x77\xab\xca\xb9\x0c\x8b\xb4\x67\x2b\x0e\x8d\x42\xc1\x30\xe0\xbd\x4e\x0d\xdd\x94\xb5\xf7\xd0\xd2\x40\xd0\x0f\x66\x28\x2a\x3b\xd0\x1e\x91\x3e\xca\x67\x05\x98\x74\xb1\x6e\xe5\x7a\xa9\x83\xe7\x32\x4b\x1d\x24\x14\xa0\xc8\x88\xb0\x9b\x17\xbf\x5a\xae\x3f\xdf\xab\x5c\xb8\x93\x22\xda\x0d\x75\x9f\x50\xfe\xc9\x48\x4c\xd8\x03\x14\x38\xb1\xe5\xe2\xa8\xa0\x24\x58\x03\x19\x6e\x14\x02\xd3\xca\x6a\x48\xcf\x6a\xea\xbb\x9e\x68\x6a\xbb\x79\x17\x5b\xf1\x24\x71\x4b\x07\x44\x70\x59\x41\xbb\x33\xb6\x6c\xd5\x18\x01\x5c\x54\xb9\x9a\x79\x06\xd3\xc5\x00\x6a\x8c\x1e\x26\x8b\x51\x9a\x93\x54\xac\x30\x85\x15\x49\xf0\xa4\x11\x94\x19\x2c\x6c\x99\xb6\xc1\x19\x07\xaa\x60\x10\xf9\xb3\xaa\xeb\x24\xb2\xb0\x69\x28\x55\x88\xad\x6e\x66\xa3\xea\xe8\x90\x88\xbe\x25\xaf\xe3\x8c\x12\xb2\x0d\x2a\x9b\x31\x9e\x20\xbb\x15\xed\xda\x58\xe5\x8a\xaf\x85\x78\xe5\x69\x14\x75\x40\xac\x67\x58\x41\x42\xb9\x54\x2d\x2c\xa1\xf4\x15\xbe\x19\x4c\x5c\x42\x69\x74\xb8\xba\x20\x07\x9c\xd4\xd5\x6a\xa0\x59\xf6\xd9\x0a\xb5\x78\xfc\xd4\x5c\x04\x43\xff\x3c\xfd\x8f\x8c\x82\x10\x8f\x88\xaa\xfc\xec\xe2\x0d\xce\xa9\xaf\xfa\x86\x44\xf6\x2c\xc0\x71\x31\xfe\x78\x0e\xc3\x65\x95\x7e\xac\xaa\x4f\x7a\x5f\xad\x10\x3d\xb5\xb5\xe5\xd0\x68\xb5\x0a\x36\x94\x5d\xad\xe8\x99\x2d\xc3\xbd\xea\xa8\x0f\xdd\xfc\xfe\xac\x17\xc4\x86\x72\xd7\x9e\x6f\xae\x16\x6e\xaf\x01\x25\x8e\xf5\x89\xa8\xcb\xd8\xf5\x02\x44\x1a\x78\x45\xe6\x0c\x7a\x1c\x90\xe8\xd6\x33\xc3\x41\xcf\x58\x47\x09\x0e\x7f\x77\x2c\xf4\x3d\xaa\x43\x0f\xd5\xaf\xd1\x67\xdd\xdd\x4a\x6a\x8a\xc0\xc2\x07\x0e\x6f\x6e\x11\xe1\x07\x35\x3e\x29\x5b\xc8\x28\x54\x3a\xeb\xa2\x23\xc1\x70\xba\xb5\xb3\x95\xc2\xf0\x5c\xe8\x39\x82\x47\x6a\xa5\x3c\x2f\x97\x72\xe9\x4e\x85\x1e\x2b\x0f\xd5\x70\x52\x56\x6e\x12\x8a\xc8\x42\xe0\x16\x83\xc7\x07\x3e\xde\x19\x50\x69\x4b\xb4\x4f\x3c\xe6\xaf\xb2\xff\x8a\x13\x19\xab\x11\x1f\xb8\x2b\x70\xcc\x0b\x7e\x22\xd1\x11\xbf\x68\xf8\xc5\xb5\x64\x5f\x1d\xdf\x2c\xe7\x7e\xe2\xab\x46\xc9\xe0\x95\x7e\x00\xba\xc2\xdf\x6a\xca\x47\x83\xd5\xa4\x7f\x12\x7a\x04\x78\xe9\x6d\xdb\xb9\x39\x25\x54\x59\x51\xa5\x88\xcb\x66\x96\x1d\xe1\x9c\xec\xb0\x35\xdc\x77\x05\x87\xb1\x95\x59\x53\x68\xb6\x55\xb1\xf4\x0b\xb5\xb6\xca\xd8\x8c\xee\x65\x38\x25\x37\xef\x7d\x80\x53\x8f\xd2\x57\x64\x41\xc3\x28\xdd\xab\xf7\xb5\x0c\x6e\xa2\xa5\x4b\x79\x2d\xa8\xd2\xc1\x7a\x61\x33\x9b\xe9\xc2\x5d\x83\xbf\x75\x4b\xa1\xf6\x90\x11\x47\x05\x0d\xa8\xab\xf5\x21\xcd\x50\x04\xa8\x4b\x2a\x02\x8b\x01\x8d\xd9\xd2\xc5\x98\x57\x67\x5b\x89\x6a\xc4\x2a\x49\x33\x6b\xc7\xc7\xdd\x6d\xf3\xf4\xdd\x59\x08\x24\x79\xf5\xb0\x3d\x28\xa9\xc9\xac\x33\x0e\xac\xc6\x8b\xf9\xd4\xcc\x15\x79\x63\xa5\xd2\xf3\xac\xf9\x67\x82\xa2\x51\x20\xde\xa1\xdd\xf5\xb2\x3d\x42\x51\x1a\x2b\x69\x58\xc9\x98\x59\x16\xa6\xd2\xe4\x9b\x59\x82\x6c\xdf\x0d\x73\x7a\x66\x01\xcd\x81\x39\x20\x06\x2b\x49\x4f\xe5\xb0\x92\x08\x28\xee\xed\x5e\x2c\x68\x61\xaf\xb1\x05\x01\x87\xda\x5d\x7e\x8c\x8d\xfb\xc1\x76\x3a\xab\x25\x79\x47\x72\x50\x26\x21\x8e\x7e\xe6\xd0\xba\xc7\xcb\x2b\x7d\xe6\x4b\xc6\xe2\x68\x56\xc2\x41\x4d\x12\x49\x56\xb3\xb7\xf6\xee\x77\x74\x2d\x4a\xbc\x53\x75\x02\x21\xca\xc6\xd0\x29\xa8\x61\xb8\x7a\xe2\xb9\xb1\xbb\x64\x84\x26\xae\xbd\x50\x47\x0b\x4c\xa4\xd9\x23\x63\x8d\x7d\x80\x76\x91\xcd\x43\xea\x55\x63\xf3\x98\xb1\xab\x6b\xc6\xa1\xee\xf0\x7e\x36\xcd\x51\x38\x58\x10\x44\x26\x04\x91\x51\x2a\x4f\xd8\x7c\xab\xa0\x76\xd3\x2e\x70\x3d\xba\xe4\xf2\xc2\x75\xcd\xd7\xf2\xe6\x2c\x8c\x68\x3a\x4f\xaf\x46\x5d\xd6\xd0\xe8\xee\xb6\xa8\x56\xf0\xfb\x8b\x65\x68\xb6\xec\x2d\x1e\xe8\xf5\x67\xd0\x6b\xcf\xa0\xf3\x09\xfc\xc6\xfd\x61\x57\x8c\x53\xfd\x5e\xe7\x0b\xeb\x7b\x8e\xf9\x9e\x23\x14\x6c\x26\x84\x68\xad\x4b\x43\xf6\x7d\xaf\x56\x84\x9e\x2f\x4f\x89\x1b\x6c\x67\xce\x77\xff\xb0\xca\x40\x46\x1a\xee\x67\xe2\x9c\xdb\x5b\xb5\xed\x39\x59\xb0\x2e\x9a\xbd\x1a\xac\x12\xa0\x34\xb2\x06\x12\x00\xf1\x5e\x28\x1d\xdd\x68\x66\x49\x19\x06\x62\xc5\x76\xb1\x02\xc0\x9e\x98\x55\xeb\x1e\x7d\x84\x8c\xac\x3e\x26\x1f\x3b\xca\x8e\xfa\x66\x49\xc8\xb0\x21\xe9\x3b\x0a\x30\x0e\xf6\xa2\x40\x51\xf2\xac\x35\xaa\xe0\x3c\xe0\xcf\x23\xef\xd8\xe4\x7d\x17\x09\x54\x07\xc2\xfa\xf8\x09\x32\x81\x57\x8c\xc5\xf7\x8c\xad\xec\xcc\x32\xbb\xa1\xcc\x3f\xc7\x61\x15\x95\x8d\xce\x33\x6b\xef\x12\x0a\x51\x08\x4a\x3a\x5a\x6c\xfa\x5e\x41\xcc\x3a\xdb\x53\xa8\xb1\x54\xad\xb4\xa2\xb8\x74\xb1\xb2\x31\xd0\xcf\xb3\x84\x2b\xc8\xbe\xcd\x8a\x72\x77\x48\xda\xe6\x91\x41\xf6\x3a\x44\x74\x3a\x36\x2d\x31\x4d\x60\x2f\x49\x41\xf1\xb2\x0e\x3a\xfa\xc4\x2b\xd5\xdd\xec\x2e\x7c\xa2\x64\x0b\x56\x97\x31\x7b\x99\x74\xaf\xb5\x7a\x66\x7f\xa1\xa3\x49\xf6\xb8\x8e\x47\x99\xc1\x00\x6e\xee\x77\xda\x10\xfd\x1e\x6a\xaa\xee\x55\x42\xed\xeb\x48\x96\x8c\xa0\xb8\xda\xf8\x4c\x76\xd2\xbd\x2b\x80\x55\x1f\x04\xbd\x39\x56\x0b\x0c\x51\x77\xdc\x0f\x27\xad\xb7\xbd\x12\x33\x25\x2f\x0d\x34\x1e\xdb\xd5\xcf\xa7\x7e\xd2\x35\x26\x3a\x88\x68\x69\xa0\x33\x10\x2d\xb1\xa1\x0a\x6f\x1a\xa1\x21\xb5\xbb\x5b\x23\x2d\xf3\x1a\xec\x04\x5b\x49\x01\xe8\x56\x6b\xa8\xce\xf4\x6f\x16\x54\xa1\x85\xc7\x61\x4d\x44\xf0\x2a\x45\x77\x49\xdd\x10\x08\xf2\x3d\x1b\x47\x5a\xd5\x6e\xed\x19\xa5\x0a\x00\x4c\x15\x1d\x90\xaa\xc7\x01\x57\x6c\x4a\x4e\x99\x42\xa4\x68\x80\x19\xc0\x74\xc4\x9c\xab\xd5\xe9\xaf\x0d\xe9\x78\xde\x2f\x46\x65\x71\xbf\x97\x22\x40\xae\x8a\x76\x23\xa7\x91\x95\x50\x15\x54\xda\x11\x08\x68\x2f\xb5\xd5\xd8\x33\x3d\x91\x39\x8e\x21\x5a\xf2\x65\x72\x0e\x30\xa8\x38\x34\x93\x21\x9c\x68\x7c\x48\x5b\xa2\xc8\x19\x97\xf5\x36\x48\xbb\x91\x2c\x87\x13\xc9\x23\x22\xb5\xa6\x83\x1e\x15\x30\x9f\x3f\xbb\xd4\xd2\xcd\x8d\x8e\xdc\x56\x21\x0e\x92\x68\x45\xe5\xee\xbc\x46\x46\x9b\x89\x4c\x2b\xa3\x1a\x5e\x6f\xab\xa7\x9e\xde\xdd\x16\x4a\xe7\x55\x2a\x98\x12\xad\xe0\x0b\xe3\xaa\x7e\xe5\xaa\xab\x63\x99\x95\xed\x80\x7f\x91\x83\x33\x96\x5a\xf9\x88\xd2\x41\x1f\xa1\x83\x6b\x5a\x62\xb9\x56\x4c\x4a\xef\xf1\xe2\xd9\x3b\xf5\x22\xd0\x4b\x5f\x7e\x94\xb5\x3f\x89\xac\x15\x6a\x81\x1b\x1f\x65\xf4\x85\x86\x78\x25\x18\x94\x1d\x86\xfa\x2f\x4e\x74\x2d\x6e\x56\x46\x01\xd5\xc5\x6e\x57\x69\x35\xb0\x53\xea\x6a\x66\x0b\xea\x81\xb5\xc0\x56\xa7\x42\xcf\x6a\xe1\x25\x8e\x72\x77\x9b\x09\x61\x83\x85\x52\x75\xb2\x37\xe5\x6a\x05\xf1\x8c\x86\xc2\x61\x28\xca\x4e\x29\x1c\x91\x1e\x83\x1b\xaf\xe6\xd6\x28\x10\x19\xe6\x26\x2e\x9c\xdc\x01\x59\xae\x39\x97\x7f\xfd\xc9\xf7\x9f\xa7\x79\x2d\x72\x24\xac\xe3\xd7\xd9\x85\xe9\x24\x03\xa1\x9c\x5c\xef\x16\xeb\xa2\xe4\x95\xe4\xac\xd6\x0d\x0d\x14\xe2\xdb\x8c\xa2\x6e\x98\x78\x9c\xa9\xe1\x7c\xf1\x59\x18\xa3\xb2\x37\xe3\x9e\xcc\x82\xe0\xdd\xb3\x57\x27\x31\x38\xb5\x59\x13\x4f\x1f\xe7\x57\xe9\x45\x97\x0a\x77\x77\xb7\xa2\xc8\x2d\x49\x76\xf6\x71\xf6\x2a\x8a\xd0\x6e\x56\x8c\x11\x59\x56\x96\x08\x6e\x39\x23\x06\xe3\xab\xa9\x23\x78\x40\xb3\x98\xd3\x36\x35\x64\xb6\x58\x21\x7a\xa7\x7d\x8a\xcb\xa9\x36\xb9\x5c\xc5\xf7\xce\x3f\x20\xb1\x3e\x9f\x9e\xc0\xc1\xa1\x25\xbe\xd7\x61\x85\x66\x87\x15\xfa\x61\x87\x95\x32\x3b\xac\x14\x4b\x26\xbe\x1d\x39\x48\xb1\xd4\x63\xab\x6b\x39\x1e\xaf\x6b\xf9\xf9\xfd\x36\x8d\x44\x02\x96\x36\xdc\xb0\xb0\xad\x76\xea\x2d\x64\x27\xb9\x8c\xee\x70\xb8\x23\x94\x04\x96\x06\x20\x67\xf6\x10\xee\x49\x62\xf6\x04\x15\x43\x8a\x32\x53\x05\x3d\x1c\x56\x9d\x4b\x3f\x15\x3d\x42\x31\x7a\x91\x1a\xb0\x28\x76\x06\xda\x65\xab\x37\x65\x91\x26\xd7\xda\x23\xa0\xb0\x7b\xa3\x63\xa4\xad\x28\x7a\x9d\x65\xc7\x8d\xbb\x65\x25\x69\xb9\xdf\x94\xb5\xd8\x1b\x80\xba\xd7\x46\xe8\xb2\x73\x0d\x0d\x36\x45\x31\xda\x05\x3c\x1a\x08\x46\x6d\xf0\x14\xb9\xa3\x00\x3e\x16\x14\x59\x83\x1b\xd1\x36\xd7\xb0\x0f\xd7\x27\x54\xee\x41\xf8\x9a\x1b\x58\xac\xa9\x79\xb5\x21\x92\x49\x63\x72\xd7\xcf\xa6\x06\x44\xed\x10\x55\xb1\x36\xaf\x91\x01\x9b\x55\x86\xa5\x95\x61\x56\x31\x47\xdd\x8b\xa8\xce\x2c\x75\xcb\x45\xf0\xce\x0b\x06\x6f\x9c\x63\x1b\xe5\xa0\x84\xce\x12\x91\x3d\x11\x9c\x17\x90\x19\x8c\x13\x2b\x64\x3c\x52\x35\x65\x8c\xaa\x20\xc1\x6a\x2e\x18\xe9\xc2\x2b\xd7\x1b\xb2\xc8\xf0\xb5\xb4\xba\xe9\x99\x83\x4c\x6a\x0c\x66\xae\xd7\x6b\xc9\xd3\x4e\x0a\xbb\xc7\x38\xb1\x37\xcc\xd9\x4e\xce\x81\xee\xe7\xc1\x46\xff\xb3\x61\xf9\x6b\x35\x6d\xe6\xd0\xf3\xb2\x2f\xe6\x92\x9f\x45\x68\xbc\x84\x64\xf6\x82\x46\x21\x5a\x35\x75\x73\xde\xb7\x62\x99\x23\x85\x2c\x31\x03\xd8\x71\x43\x46\x12\x52\xcd\xd1\x51\xe9\xfa\x32\x4d\x47\x57\x46\x6b\x50\x49\x2b\xf5\x14\x24\xf1\x0a\x29\xdf\xeb\x1a\x91\xfb\xcd\x8f\x38\xcb\x3e\x9f\x6e\x98\x3c\x26\xaf\x81\x47\x10\x38\xee\xbd\xf4\xa9\xd1\x49\xe0\x3e\x18\x46\xc0\xdb\x9b\x71\x83\x76\x41\x5e\xfd\x01\x5a\x81\x8a\xf7\x52\x8a\x27\x1b\x3a\xad\x00\xfa\x56\x05\x54\x6f\x33\x13\xa0\x59\xf1\xbd\x6e\x29\x0d\xba\x26\x26\xf2\x60\x62\xe2\x29\x7a\x7a\x9b\xb5\xd3\x20\x6e\x07\xf5\xa3\x64\xb4\xc6\x3c\x62\x75\x27\xa5\xb7\xc0\xa1\x8c\xae\x75\xc9\x9a\xd6\x71\x9e\xae\x12\xbd\xcd\x4a\x1c\xb8\xac\xc5\x7c\xad\x88\x7b\xb8\xcb\x0c\x6d\x7e\x88\xc3\x59\x0c\x14\x21\xf0\x5c\x77\xcf\x2d\x25\x02\xea\x8f\x67\xc3\xb1\x59\x56\x21\x57\x23\xdd\xe2\x66\xc9\x5f\xcf\x39\x62\xe6\xdf\x4f\xa0\xdc\xb3\xbb\x70\x83\x7d\x5a\x1e\x8d\xac\x7c\x5e\x9f\xdd\xcb\xe3\x4e\x54\x3d\xaf\xc5\x05\xc1\xde\xab\xfb\x54\x14\x62\xb4\xb2\xb3\xd5\xf5\x54\xc9\xc2\x28\x2c\x5c\xe0\xef\xa2\xa1\x78\xca\xe8\x15\x40\x54\xfa\x91\xd3\xd1\x46\x47\xa6\x44\x76\xf2\x1d\x8a\xc4\x12\x55\x50\x26\xe0\xab\xbe\x74\x29\xc0\x89\xbc\x3e\xd0\xf6\xec\x52\xd0\xba\xb6\xd7\x4b\x2d\xcf\x42\xcb\xaf\x95\x59\x2e\x56\x66\x99\xdf\xbf\x2d\x94\x3e\x7e\xfa\x15\x84\x1d\xb4\x16\x0a\xbd\xa2\x95\x69\xcb\x96\xda\xd9\x50\xe3\x13\x14\x19\x32\x56\x8e\x19\x71\x56\x2d\x65\xa8\xaa\x5b\x14\xa6\xb0\x58\xa7\xa1\xb4\x22\x51\x62\x58\xa1\x78\xde\x2c\xa1\xd2\xf3\xae\x89\x64\x56\x23\x06\x60\x44\x6d\xa9\x36\x2c\x88\xa9\xaa\xa6\x3d\x32\x57\xa7\x73\xa0\x80\x68\x5c\x56\xc8\x9b\x42\xcb\x48\x47\x6c\x56\xdc\x8b\x8e\x0a\x84\x04\x09\xf0\x88\x7a\xfb\x23\x4c\x32\x1a\x2d\x74\x90\x10\x7b\xf5\xad\x63\x14\x4e\x3b\xc4\xe4\xb4\xb7\x36\x3c\xaf\xcc\xc4\xb6\x25\x80\xf4\x93\x16\x6b\x85\xb6\x1b\x5b\xd1\x25\x2b\xf5\x24\xaf\x71\xb6\x60\x56\x95\xf3\x57\x6e\x47\x19\x67\xcf\x12\xcb\x41\xfb\xf6\x0a\xf2\xe5\x35\xcb\x14\x91\x28\x2f\x50\xdf\x4e\x17\xa3\xb9\xfd\xcd\x32\x55\x99\xab\x18\x74\x84\x3e\xcc\x5f\x46\x2c\xc1\x58\xa4\x04\x14\x36\xab\xbf\x96\x33\xc0\x20\x64\x65\x4e\x67\x8f\x3d\xa4\xab\x2a\x64\xc9\x67\xce\xbc\x24\x2f\xd1\xec\x39\xb5\xf6\x0f\xbf\xed\x78\x74\xcb\xdf\x37\xc1\x38\x35\x18\x4c\xb0\x97\x18\xe4\x36\x18\x62\x3d\xc3\x2c\x8b\x92\xd4\x10\x6d\x5e\xe9\x42\x72\x35\x1b\xcc\x2e\x4b\xf3\xb2\x8e\xcb\x14\x2a\xea\x65\xf4\xda\x65\xd6\x0b\xf9\xfa\x68\x4e\x23\x4c\xdf\xb1\xf6\x95\x09\x1d\x13\x96\x96\x8e\x58\x19\x70\x39\x1f\x19\x1d\x37\x91\x15\x9b\xee\xb0\x67\xa2\x88\x37\x52\x1b\x65\xc5\x66\x2b\x67\x1f\xb5\x21\x77\xb7\xb9\xab\x35\x71\xd4\xb4\x0a\xf7\x90\x39\x2d\x15\x05\x62\xf3\x42\x49\x8e\xd8\xac\xaf\xb6\x4a\x9a\xb1\xc4\x91\x0f\xfc\x44\x59\xe2\x32\x52\x18\xbc\xd0\xe0\x83\xaf\x55\xf9\xd4\x81\xbf\xf8\x71\x06\x5e\x60\xad\x67\xd5\x23\xa8\x40\x6e\x22\x98\xce\x96\x2d\x38\xfb\x96\xa9\x62\xdb\x74\x16\xab\xca\xbc\xc3\xa7\x92\x1c\xc5\x34\xe7\x51\xa9\x5a\x6f\xb3\xa1\x03\x9f\x3e\x4f\xdb\x2a\x06\x82\x11\x8e\x4c\x88\x45\x99\x4f\x06\x50\x91\x79\xe1\x31\x36\x00\x9f\x1e\x9a\x0a\x1e\x70\x60\x50\x4d\x63\x1c\x8d\x83\x4a\xc4\x3c\x2c\xbd\x51\x9c\x03\x0e\x75\xb1\xa2\x00\xf8\x86\x26\x8a\xa1\x2b\x04\x1c\x8e\xea\x24\x87\x3e\x33\x08\x0c\x26\x79\xa1\x21\x04\x5a\x06\x70\x5d\x05\x65\x73\x66\x7d\xb5\xf9\xf1\xfa\x52\x9c\x96\xb4\x84\xde\x78\x6d\x4d\x65\x28\x00\xa2\x27\x64\xcb\x3e\xbb\x41\x6e\xd6\x7e\xc5\x9d\xc8\x99\x66\xae\x3a\xdf\xa3\x3e\xa5\x3d\xd7\x50\x5d\x17\x18\x77\xbd\xe5\xdd\xfb\x8d\x30\xaa\x4f\xdd\x9c\xd9\xef\x7c\x74\x06\x9e\xcb\x9e\x11\x20\xbb\xd9\x5a\x66\xb3\x8c\xb3\x42\x18\x4e\xb9\xcb\x1c\x31\xb8\x65\x88\xdb\x2d\xe7\x93\xb6\x60\x11\xcf\x35\x16\x1d\xe5\xd6\xb1\x09\x82\x5a\xef\x94\x9c\x2b\x62\x9c\xf4\x93\xd1\x28\x3d\x80\x09\x5c\x66\x11\x84\xda\x4f\x3f\xdd\xe9\xdb\xde\x4f\x7f\x37\x4a\x46\xf7\xa0\xd6\x6d\xee\xc8\x9d\x18\x3c\xed\x03\xc3\x84\x96\x33\x66\xf5\x77\x6b\x32\xd8\x9f\x69\xb7\x9a\xe7\x16\xb6\x33\x7e\x2d\xab\xcd\x9e\xea\x9d\x55\x0e\xfd\xd9\x8f\xe4\xab\x7b\x92\x4d\x60\x4b\x2a\xd4\x51\x3b\xb8\x21\x85\x36\x10\x27\xeb\xb9\x8e\xd2\x4a\xcd\x82\xe7\x23\xdb\xb4\x11\xf1\xd1\x51\x72\xe8\xb8\xcf\xe6\xf0\x14\x71\x8f\xff\xd9\x92\xe9\x54\xb5\x34\x53\xc0\xd4\x1c\x69\xd9\xa3\x87\x69\xc6\xf1\xf7\x59\x3e\xd0\x54\x6e\x2e\xde\x83\xa4\x5b\x6d\x96\x3a\x76\x5f\x90\x6a\x0d\xb8\xcc\x5f\x6a\x55\xb1\x61\xa2\x67\x53\x0e\xd9\x72\x81\x41\x07\xd1\xb5\x72\x3a\x81\xd5\xfd\x9c\xf4\x63\x14\x47\x8f\xd6\x9f\xc0\x69\x6f\x33\x8f\x02\xb5\xf5\x86\x19\x76\xad\x23\x40\x30\x15\x94\xdd\x7a\x98\xfd\x4d\x3f\xe0\xb9\x88\xb7\x3f\xc9\x5e\xbc\x7f\x96\xe5\xb7\xb2\xd2\x6f\x40\x20\xef\x31\xb1\x5b\x67\x6e\x58\x97\xd7\xfa\x59\xfe\xfa\x93\xef\xbf\x98\x5e\x8a\xf7\xab\xc4\x0e\x6b\x22\xb7\xb6\x76\x46\xa5\x37\x31\x2c\xcc\x2b\x96\xae\xd7\xb7\xa9\xd5\xae\xa3\xa2\x0f\x32\x2a\x61\xd2\xd1\x74\xa8\x50\x1d\x8d\xc1\x7a\x59\xa3\x64\x8b\x93\xbd\xed\xb8\xf8\xc3\xcc\x16\xc1\x84\x55\xd5\x3d\x02\x27\x41\x35\x23\x14\xeb\x4c\x64\x69\x0f\x2a\x76\x98\x74\xf4\xd5\xfb\xd0\x92\x8c\xb7\x1d\xac\x7c\x90\xc1\x12\xe8\x13\x35\x6f\xa0\x11\xb4\x1e\x58\x18\x19\xf4\xc8\x7b\xf7\x86\xbe\xb0\xdb\x5c\x91\xb9\x1a\x2c\xce\xea\xb0\x8c\x6f\x6c\xdc\x76\xc6\x52\x71\x4e\xf4\x5a\xd5\x11\x11\xdd\xbb\xbd\xee\xb9\xdb\x44\xc9\xfc\xda\x52\x61\x06\x9b\x9c\xaf\xc3\x8a\x62\x58\xd1\x22\xff\x98\xce\x62\x04\x90\xc8\xc6\xb3\x82\xa9\x8d\xf6\xe1\xc3\x0e\xd5\x5b\xcd\x5b\xfe\x30\x8b\x9c\x9a\x62\x72\xf2\x08\x25\x10\xb2\x58\x59\x4a\xe1\x99\xe2\xfa\x78\x04\x31\x9f\x11\x44\x23\x45\xd0\x1b\x79\xc2\x74\xf5\xdd\x6e\x4b\x93\xf3\xe9\x96\x9b\x9c\x91\x9b\x4c\xaf\x3f\xf9\x4a\x7c\x34\x78\x52\xf2\x1b\x8f\xf7\xf0\xa5\xa4\xc7\x83\x97\x5f\x94\xcb\x04\x46\x5e\x33\x9a\x19\x28\xac\x69\xa8\x43\x4e\x9c\xd0\xb0\x52\xd5\x01\xaa\x9d\x4b\xb3\x2e\xeb\xd6\x28\x25\x85\x52\xcd\x35\x2a\x03\xdd\xcf\xf2\x25\xbb\x03\x58\xdc\x82\x1c\x19\x04\x3c\xe7\x31\x4c\x3d\x0b\xa6\x62\x9f\x39\x57\x6a\xca\x95\xbe\x66\x98\xe4\x5c\x1f\x5d\xb5\xf2\x58\x4b\x89\xdb\x9c\x7a\xa0\x8c\x06\x40\xa8\xa7\x7f\x8f\xef\xe7\x95\xf0\xcf\xe4\x69\x28\x00\x08\xf4\xea\xc6\xa1\x77\x85\xb4\xe6\x6d\xf1\xfc\xd6\x8c\xee\xd9\x67\xbf\xe5\x63\xe8\xea\x8b\x69\xcb\x77\xdd\x96\x89\x8d\xd9\x52\xfa\xac\x57\x0f\x8f\xa7\x6a\x73\x1e\xcd\xab\xda\xe3\x53\x6e\xfa\x3a\xd5\xbf\x95\x1b\x1d\x92\xeb\x12\xb9\x56\x6b\x6c\x1d\xf1\x4f\xa4\x66\x73\x1b\x21\xd7\xb2\xb0\xb4\xa3\x76\xfd\xd2\x75\xcb\xf1\x8b\x69\xb1\xf7\x1c\x2a\x5b\xb1\x5b\xe8\x72\xf1\x36\xa2\x6d\xe6\x92\xef\x5e\xaa\xdd\xab\xd8\xdb\x61\xf8\x39\x1b\x3a\xb4\x1f\xb4\x73\xe8\x1f\xbe\x99\x03\xc0\x5d\x9d\x8c\x78\xf4\x60\x41\xb2\x0d\x66\x1d\x12\xfe\xdd\xdc\x02\xef\xe3\x99\x40\x0f\x17\x20\x12\xf0\xab\x50\x4d\x02\xf1\xc2\x1c\xa6\x1b\x2a\xa5\x7b\x15\x7a\x5b\xe0\xf6\x88\xa0\x9c\x4e\x93\xf7\x6c\xb2\xf0\x0f\xa3\x87\xab\x23\x18\x1f\x68\x04\xa2\x16\xfd\xe3\x48\xe1\xea\x18\x9e\x7f\xa8\x59\xe0\xf6\x4e\xa8\xe0\xea\xc0\x3e\xff\x50\x03\xa3\xf1\x93\x68\xb2\xd2\xcb\x7b\xe8\xac\xfb\x2a\x2b\xbc\xbd\xce\x3a\xdd\x1f\xef\xd7\x7a\xe1\x3d\xf6\xf2\x8b\x0f\x34\x82\xf7\xd9\xcb\x2f\x3f\xd4\x2c\x40\x61\x7e\xc0\xbd\xfc\xea\x43\x0d\x8c\xe4\xa7\xd9\xcb\x6d\xfc\x6c\x7b\xf9\xc5\xb4\xe9\x2a\x85\x4a\x15\x45\x43\x28\xd1\x51\x32\x2d\xdc\xb3\x97\xc1\x67\x23\x45\xe6\xb6\xc3\x1b\xa6\x86\x32\xea\x33\xa5\xd9\xd1\x99\xeb\xd9\x2c\x76\x56\xe9\x71\xf4\xed\xcd\xaf\xcc\x0b\x81\x9e\x62\xb8\x60\xc0\x25\xdb\x0d\x23\xa1\xab\x4b\x94\xa1\x40\x23\x1d\x56\xa3\x23\x4d\x4b\x91\xda\xa2\xd0\x4f\x01\x43\x0a\x3c\x46\x20\xc9\x3b\x25\xc5\x65\x6a\xef\x33\xaa\x84\x51\x10\x04\xa7\x7b\xf7\x86\x3f\xb9\x38\xbe\xa1\xe2\x4b\x8a\x4f\xf9\x5a\x23\x41\x9d\x0a\x7a\xf6\xe3\x37\xaa\x00\x6f\xe5\x97\x6a\x22\x85\x47\x6c\xa4\x7b\x26\xd2\xd5\x09\x9c\x16\xef\xc7\x8e\x1b\x1f\xb4\xe3\x06\x42\x17\xec\xd9\xe9\xc6\xd3\x98\xe0\x0b\x3e\xc2\x2b\x9d\x36\xde\x5d\xbd\xbc\x90\x8f\x0b\xf9\x4b\x5a\xc8\xf7\xd0\xd2\x2f\xf2\xc7\xa5\xfc\x25\x2d\x25\x9c\xef\x1f\x10\xec\xbc\x28\x7f\x12\xeb\xfb\xee\x5a\x31\xfc\xac\x9e\xc3\xfb\x8e\xc3\x77\xdc\xa3\xef\xb3\x45\xc3\x8f\xb1\x47\xaf\x6e\xb5\xfa\x27\xb1\xd5\xfe\x74\x44\xc9\x4f\x63\x6a\x87\x0f\x68\x6b\xbf\xbd\x79\x72\x66\xa9\x21\x55\x48\x65\x65\xd7\x65\xb4\x9a\x1b\xdc\x78\x1d\x35\x8c\xbc\xa2\xc4\x04\x02\xfa\xf8\x7b\x5f\xc7\x30\x16\x3f\x57\xf0\xce\x32\x98\x0f\x91\x5b\x59\x61\x8a\x8c\xac\x7f\x4a\xb8\x43\xe4\x82\xca\xb9\xd7\x03\x5f\x2f\xfa\x0f\x77\x3e\xd2\xc1\xb9\x7a\x3e\xb5\xed\xfc\x32\xbb\x92\xea\x3e\x6c\x5e\xdc\xcf\x3b\x54\x25\x6b\x37\x7e\xe3\xfc\xcd\x15\xd5\x6c\xfb\x0a\xa7\x2a\xaa\x40\x82\xc4\x48\xb4\x59\x6d\xe9\xca\x28\x91\x1d\x73\xb7\x42\x9a\xbd\xcf\x33\x21\xf7\xce\x04\xef\x93\xdb\x6f\x2c\x61\x64\x4d\x45\xb9\xdf\x9c\x13\x59\x6a\x34\x26\x17\x06\xf9\x9a\x09\x65\x65\xd2\x0a\x31\x58\x0a\xfa\x75\x30\xd7\x0d\xa5\x11\x50\x6a\x82\xac\x96\xd8\x3c\x2d\x23\x58\x69\x8a\x12\xac\xe1\x18\xaf\x99\x7a\x68\x3d\x83\xd1\x85\x0b\x1a\x87\x96\x2f\x75\xc1\xea\xcd\x59\xb8\x69\x16\x93\xef\x5e\x93\x10\xde\xce\xb9\xa9\xf3\xbd\x4d\x2d\x46\x2a\x2e\xc8\x6b\xdb\x5a\x75\x2e\xa7\x79\x74\x3d\x3d\x5c\x2c\x73\xa4\xef\xcd\xbc\xb6\x56\xa4\x0c\x1d\x17\x83\xf0\x23\x4b\x38\x9e\xfd\x13\xef\x02\x74\xcb\x28\x99\xff\x2e\xe6\xc0\xf3\x7f\xf2\x73\xf7\x3e\x08\xfc\xf3\x7f\xf2\xb3\xf7\xc1\x41\xef\x17\x1f\xa7\x54\xea\x4f\xe2\x9b\xac\x89\x7f\x36\xdd\x3f\x9d\xdc\xef\xdc\x65\xeb\xbd\x8e\xed\xcb\x37\x23\x22\x3a\x80\xb4\xa1\x58\x5c\xbe\xf4\x7f\x36\x3e\x9f\xb1\x3a\x8d\x4a\x66\xed\x9c\xbb\x2c\x5c\xeb\x6b\x3d\x4c\xfb\xbd\x1e\xa6\x48\x1d\x9c\x9d\xfd\x1f\xef\x63\x7a\x49\xf6\x78\xad\x93\xa9\x51\x4a\xef\xf7\x32\x6d\x47\x14\xce\x8b\x17\x9a\xaf\x39\xe4\x3c\x16\x6e\xed\x4c\xc4\x41\x61\x38\x6b\x7b\x91\xdb\x9e\x05\xbd\x09\x5a\xe8\xfd\x81\x8e\xa6\x7c\xe3\xa5\xe3\x11\xf4\xbb\xb4\x34\xad\x7c\xc4\xfc\x08\x49\xf8\xc5\xe9\x7d\x27\x09\xe9\xe8\x15\x4e\x5a\x5d\x07\xb8\x6c\xc7\x8e\x4c\x4a\x3e\xcb\x72\x58\x85\x47\xab\x2f\xd9\x51\x2c\xa2\x5b\x45\x60\xe3\xde\x45\xf0\xfb\x27\xe3\x17\xbc\xb4\xca\x3e\x05\x44\xb2\xa1\xd4\x68\x9f\x79\x13\x45\x70\x75\x47\x8b\x52\x2f\x82\x48\xce\x15\x9c\x45\xce\xb2\xc3\x72\xdd\x25\x3b\x4a\x43\x4c\x0e\x80\xde\xd3\x33\x42\x90\x97\x68\x09\x21\x64\xa4\x39\x42\x95\x04\xf0\xb0\x0a\xea\x69\x64\x45\xdf\x48\xa8\xf0\x1a\x16\x5e\x14\xd3\xe6\xb7\x94\xbd\x70\xc0\x32\x5b\x13\x0f\xf4\x13\xc0\x21\x37\x04\x63\x01\xfe\xea\xfd\x3d\x46\x09\xd5\x53\x7f\x53\x60\x5e\x62\xe5\x83\xa8\x2e\x2d\xbb\x05\x6c\x25\xa5\x8c\x3b\x98\xd1\x54\xbb\xb5\xdd\xfa\xa8\x92\xbd\x19\xe6\xa6\x59\x43\x53\x1d\x5c\xb3\x72\x92\xd9\x0b\x7d\x8e\x12\x2c\xa7\x03\x66\x8c\xb5\x09\x69\x97\x13\xda\xac\x18\x5c\x75\x0a\xb5\x37\xdc\x28\xf5\x88\xbd\x59\x6f\xae\xab\x2b\xfe\x32\x3d\xfb\xd8\x4a\xec\xe7\x6d\x25\x66\x15\xaf\x24\x57\x24\xdc\xf4\x8a\xfc\x9b\x28\x69\x82\xfd\x7a\x3d\x19\xf6\x25\x7d\x5c\xbd\x9f\x7b\xf5\xde\x23\x6d\xea\x25\x7f\x5c\xbe\x9f\x7b\xf9\x10\x75\x24\xaa\x2b\x73\x0f\xdc\x1b\xe0\xad\x61\xbe\x61\xee\x06\x54\x56\xaa\xc9\x0a\x01\x5a\x58\x3a\x3d\x22\x50\xe5\x4f\x7b\x4d\x93\x02\x80\x54\x51\x1c\xe3\x9e\xaf\x37\xb8\xaa\x9b\xa8\xbd\x4d\x95\x5e\xd3\x9b\xe1\x4f\x74\xeb\xc9\x1c\xfa\x7e\x16\xf2\x31\xdf\x9b\xa0\x8f\x61\xa6\x9b\xb2\xb6\x8a\x7c\xe8\x7b\x2e\x5f\xef\x59\x8c\x81\x59\x8b\x19\x23\x79\xf5\x59\x6c\xc3\x32\xff\xcc\xe3\xdb\x2e\x1f\xe5\x9a\xeb\x97\x4f\xd7\xef\x63\xdb\xf4\x1f\xde\xa5\xe1\x67\x6b\x37\xa9\xbb\x2d\xff\x69\xef\xb6\x7f\x14\x12\xa4\xe4\x1f\xb5\x42\x51\xd5\x61\xbf\x59\xa1\x28\xfc\x74\x25\x8a\x5e\x96\x8f\x7b\xec\xe7\xde\x63\x22\xe0\x50\x0f\x27\x51\x97\xd9\xd4\x2f\x93\x8d\xa1\x0c\x90\xa8\xad\x72\xfa\xcc\x69\x44\x97\xc7\xad\x20\x4f\x29\x80\xfa\x83\xde\x78\x28\x00\x6b\x37\xb7\x1c\xc6\x4c\x33\x59\xcd\xcb\x10\x0d\xdb\x31\x94\x83\x17\x41\xa3\x8c\xb2\x83\xfa\x87\xf9\xc4\x78\x0e\xe2\xee\x36\x67\x0e\xc4\xf0\xad\x1b\x6b\xda\xb3\x76\xca\xf0\xd6\x50\xa2\xc2\x17\x37\x87\xf0\x85\xb4\xaf\x17\x3a\x74\xbd\xb0\xa4\xf9\xc2\x9d\x76\x41\x6d\x49\x5f\xf5\x6a\xab\x2c\xdd\xa1\x33\xb8\xc5\x6a\xad\xf2\xdc\xa0\x30\x2b\x99\xeb\xce\xd8\x81\x83\xd6\xdc\x02\x1f\xc5\xd2\x94\x92\x95\x46\x0c\x9e\x82\x6a\x01\x1c\x64\x8b\x9d\x69\x61\xaa\x84\xba\xed\xd1\xb4\x01\x27\x88\x1e\x80\x40\xc4\xde\xdb\xd2\xa8\x55\x28\xb4\x60\xcd\x7f\x86\xd8\xeb\x96\x11\x10\x5b\x18\xb2\x9b\x17\x5f\x4e\x3a\x16\xfa\x70\x5a\x5d\x10\x94\x8a\x35\xd7\x56\x5f\x63\x46\x01\xcd\x7c\x44\xef\x86\x49\xc3\xfb\xc4\x5a\x82\x61\xb5\xd3\x3c\x2b\x57\x8f\xd0\xaa\x9a\xb4\xb1\xd7\x60\x89\x84\xa8\x1a\xc7\x02\x75\x39\xde\x68\x65\x8a\xba\x0e\xde\x68\xd7\xf2\xd2\x15\xc8\x8c\x3a\xa9\xc7\x62\x7d\xc3\xce\x5e\xa1\x20\xaf\xcf\x52\xed\x56\xec\x08\xdc\x6e\x14\x88\xb0\x46\xbc\x28\x47\x53\x66\x95\xd3\x88\x3a\x6d\xde\xbc\xc9\xea\x7d\xe4\x86\xbc\x2b\xc9\xbb\x57\x14\x47\xb9\xe2\xee\x6c\x70\xfb\x62\x0d\x16\xb1\x4b\xb8\x98\x70\x60\x29\x70\x3e\x30\x21\x3a\x28\xcb\xb9\xcf\x5e\xed\x0e\xfd\x38\x3c\x3d\x2e\xec\xd1\x8a\x57\xf9\x79\x21\x6b\x1d\x76\x77\x5b\x5a\x0f\xa5\xd1\x2a\xa9\x05\xa2\x23\xcb\x5c\x70\xe9\xe7\x72\xa7\xea\x8b\xed\xe2\xc2\x12\x98\x8d\xba\x6f\xad\x71\xd0\x2e\xe0\x88\xd7\x9a\x45\xe9\xbe\x3b\x03\x5c\xa4\x32\x61\x3e\xc6\xda\xe2\x22\xd3\xd8\x7a\xe5\x9e\xad\x84\xf9\xed\x5b\x09\x2b\xcc\x12\x74\x37\x80\x69\x2f\xee\xe5\x2b\xf4\x8b\x6c\x25\x6c\x7d\x70\x90\xf0\x89\x26\xab\xc5\x39\xf0\xef\x9a\x1a\xff\x01\x38\xf0\x23\xdd\xe3\xc0\x77\x14\x0c\xf1\x6e\xd3\xa8\x77\x64\x91\x59\xbc\x1b\xf5\x47\x60\x7d\x7f\xf6\xb1\x0b\xee\x4f\xdc\x05\xf7\x7d\x1c\x23\xe3\xe3\x72\xfd\xe4\xcb\xf5\x3e\x9e\x90\xe7\x1f\xd7\xeb\x27\x5f\x2f\x2b\x8b\xf8\x01\x5d\x1f\x9f\x7f\x5c\xc4\x1f\x2e\xa2\xd0\x8f\x6a\x1d\xfe\xd8\x9b\xa4\x8c\x7e\xbd\x3e\x6e\xf8\x09\xac\xcf\x2f\x9e\xbd\x73\xdf\x5e\xae\xed\x5d\xf5\xc7\x8b\x77\x7f\x2a\x32\x36\xdf\x51\x0c\xbe\x7c\x8f\x97\x15\xf9\xb0\xa7\xf9\xd5\x7b\x8c\x85\xe4\xc7\x2d\xda\x8c\xba\x7c\x3f\x7a\xd1\xe6\x87\x1b\x7f\xfd\xfa\x93\xef\x5f\xcd\xa8\x59\xe7\x90\x31\x0c\x04\x48\x4b\xa0\x21\xfb\x90\x40\x65\xec\x84\x4a\x1d\xd6\xa0\x42\x2c\x45\x55\x27\x3f\x05\x90\xd9\x28\x55\x74\xd5\x6f\xdd\xdb\x16\xcc\xa4\xcc\x60\x7d\x2c\x22\x23\x2a\x2e\x6b\x54\x59\xd9\x57\x9d\x51\x45\xf8\x83\x71\x09\x27\x45\x46\xb4\xa2\x59\x2b\xda\xb8\xa3\x3d\x83\x75\x3c\x6b\x2b\x33\x85\x9a\x80\xb9\xc1\x14\x43\x23\x22\xde\xd8\x1a\xc8\x33\x9a\x6d\xc4\x9a\xc7\x2c\x8e\xe4\xf1\x6a\x56\xeb\x0b\x11\xdc\x46\xde\x6e\x1e\x34\x5b\xb2\x40\xab\x8c\x70\x76\x6f\x6d\x6a\xc6\x58\xc4\xd3\xcb\x02\xa3\x8d\xac\x89\xbe\xaa\xf3\xa0\xa2\x09\xcd\xb9\x3c\x70\x3b\xfb\xa2\xf2\xd9\xbd\x15\x34\xd2\x64\xdd\x5b\xc9\x8d\x0b\xaf\xaf\x38\xbc\x4b\xa1\xb9\x5b\x6a\xb7\xf4\x6b\x94\x92\x62\x2b\xd2\x6a\xce\x03\x6b\xb0\x53\xbd\xe0\x1a\x0a\x5e\xd6\xe4\xd5\xa1\xa8\xef\x51\xad\x10\xe3\x64\x8e\x59\xf3\x37\xce\xb2\x54\x74\xcf\x0a\x52\x61\x78\xf5\x24\xbc\xa2\x67\x7f\x02\x8d\x81\x6f\x75\x77\x3c\xe4\xba\x7f\xdc\x73\x1f\x7e\xc1\xae\xfb\xab\x0b\xc6\xcf\x3e\x36\x3c\xfe\x59\x1a\x1e\xbf\x87\xc9\xf6\x4a\x3e\x2e\xda\xcf\xb4\x68\xef\x61\xb8\xbd\xca\x1f\x57\xed\x67\x5a\xb5\x0f\x6d\xbe\xbd\x2a\xff\x58\x97\x12\x09\x48\x6f\xad\xd9\xee\x29\xb6\xf0\x4b\xd3\x6c\x1f\x66\x77\xfe\x91\x9b\x33\xfc\x54\x9d\xef\x75\x93\xd5\x7f\xac\x9b\xec\xfd\x1a\xd1\x84\x3f\xc2\x92\xff\x09\x97\xfc\xc7\x90\x47\x0f\x76\xd2\xf9\x09\xe3\xd4\xaf\xda\x3f\xd8\x19\xe2\x36\x4b\x0a\x82\xfe\x21\x33\x7b\x0c\x36\x01\x4c\x02\xf8\x9d\x2a\xfa\xcf\x6d\xd6\x57\x1e\x1d\xed\xac\x38\x82\xb4\xd9\x66\xbc\xe6\xb3\xb5\x79\x73\xd4\xcd\xd5\x4b\x1f\x57\x55\xa6\xc2\x61\x20\xc6\x28\x03\xe1\xcc\x50\xdb\x8e\xd9\x66\x17\x48\x10\xc4\xaf\x3f\xa3\xbe\xf1\x0c\xb9\x84\x6b\xd0\xf3\x2f\xe2\x42\x7b\xae\x3e\x96\x2d\x2c\x77\x7d\x2e\xfa\x7d\x03\x15\xc7\x8c\x48\x8f\x19\x27\xb1\x43\x06\x0f\x98\x45\x49\x77\x6a\x84\x63\xb6\x75\x4b\xf7\xd3\xb1\xe4\x15\x66\x29\xad\x68\x2f\x50\xc6\x8a\xa0\x1b\x95\x84\xee\xfd\x28\x47\x89\x46\x84\xd2\xda\x0c\x56\xce\x93\x47\x3c\x4f\x9e\xd7\x68\xca\xf7\x4f\x9e\xd8\xc9\x3b\x3b\x5f\xa4\x90\x8b\x75\x0e\x41\x9b\x36\x4a\x2d\x94\xb2\xa2\xa7\x78\x35\xc2\x80\x37\xce\xd0\xf1\x8b\x1f\x13\x4f\xac\x2a\x15\x39\x4d\x5c\xea\x2a\x54\x43\xe9\x29\x6c\xb1\xb0\x75\x22\x4c\xcd\x5b\x7b\xdb\x34\x96\x69\x2c\xf9\x2e\xa6\x4b\x24\xcc\x8f\x9a\x45\xda\x47\x53\x53\x6e\x43\xf5\xb1\x62\x55\x80\xa5\xdc\x2f\xf0\xce\xde\x92\xbd\xd1\x3c\x6c\xf7\x3a\xc7\x7a\x2c\xb3\x9a\x59\xcf\xd7\x1a\x49\xeb\x12\x5d\x4a\x1a\xfd\x93\x6d\xac\xfe\x3e\xe6\xc2\xf3\x8f\xd3\xf7\x5e\xc0\xfd\xf3\x8f\xf3\xf7\xe1\x21\xf4\x17\x1f\x27\xf5\x4f\xbd\x63\xdf\xab\x19\x1a\x40\xad\xe7\x56\x57\x34\xdf\xa6\x0d\x65\xb4\xd1\x67\x72\x58\x53\x68\x6a\x37\x65\x05\xdd\x61\x43\x3a\x1b\xb8\x11\x7d\xf7\xd0\x14\x9a\x29\x5a\x31\xdf\x9b\x72\xaf\x14\x36\x90\x2d\x89\xac\x3c\x42\x4b\x6b\x94\xc2\xa1\x57\x3d\xd1\x2d\xd4\xba\x50\xe7\x19\xff\xca\xd3\x6a\xc8\xe6\x65\xb4\xbc\x39\x44\xcb\x56\x6e\xf0\x37\xf6\x55\xad\xa1\x92\x58\xc1\x46\x63\x9d\x2f\x68\xe3\xdd\x5a\xdc\xdc\x94\x85\x8a\x6c\x91\xba\xe5\xf5\xca\xb8\xf8\x26\x63\xb9\x00\xd0\x35\x22\x45\xbb\xb6\x14\xd6\x68\x0c\x0e\x46\x43\x61\xaf\x79\x68\x8d\x7f\x2d\x59\xaf\xb5\x59\x0e\xd9\xba\x3e\x45\xa6\x12\x7a\x7a\x3f\x27\xc3\x25\x9d\x0b\xe8\x81\x0f\x6a\x29\x2f\x54\x0d\xf4\x67\x2f\xe7\x64\xfd\x32\xda\x34\xc3\x8e\x58\x12\x6d\xb9\x05\x05\x32\x5c\xbd\xdf\x1f\x95\x81\x76\xd9\x5b\xb3\xfe\x32\x06\xa4\x87\xd7\x52\x8f\x7d\xa0\xf7\x84\xe1\x6e\x67\xbc\x90\xec\x56\x93\x3c\x32\x35\xc3\x10\x0e\xa2\xf1\xe6\xce\x72\x34\xd2\x90\xf0\xa5\x0e\xb4\x25\x39\xef\x7e\xac\x28\x8d\x23\xe6\x5a\xf4\x34\xa2\x02\x27\x07\xe9\x63\xcb\x56\x7f\x1c\xc9\x45\x64\xa6\x0e\x5b\xc9\xd1\x60\xbe\x70\x34\xb1\x83\x6d\x64\x6d\xaf\x77\x55\x99\xa8\xb0\xa9\x8b\x58\xad\x29\x13\xf4\x66\x53\x88\x49\x7b\x44\xd5\xe1\x74\xb6\xd8\xb5\xda\xe5\x88\xf9\xdd\xab\x43\x3f\x2e\x2c\x48\x1b\xfb\x81\xba\xa8\x57\x97\xe0\xd5\xc7\x5d\xff\x2e\xbb\xfe\x1f\xb1\x30\x0c\x7f\x8c\x34\xa4\x72\xe6\xb0\xf4\x50\x8d\xa0\xca\x15\xcd\xce\x42\x06\x71\x91\xad\xa6\x08\x36\xea\xcc\xb5\x8b\xd4\x50\x80\xbd\xf4\xa3\x8c\x25\x37\x99\x95\x6d\x73\x9d\x95\x6d\xe5\xac\x6c\x2b\xb3\xb2\x2d\xdf\xab\x6c\x5b\xc5\x58\x8c\xa8\x0b\xef\x2d\x33\x3b\x5a\x1f\x59\x13\x79\x5d\x82\x9c\x27\xdb\x4f\x8d\x0c\x3d\xa6\x77\xb7\x54\x92\x57\x81\x00\x09\x19\xed\x21\x06\xa1\x58\xad\xda\x34\x46\x2d\x1b\x39\x64\x41\x2f\x10\x4a\x47\xe3\xb1\x45\x42\x74\xcf\xc2\x64\xb5\x23\xc4\x55\xac\x45\x7a\xae\xe8\xdc\x07\x3f\x0a\xda\x34\xcd\x4c\x59\x37\xde\x66\xbc\xa9\xdb\xa6\x85\x5a\xb7\x3d\x03\xa3\xe4\xba\x7d\x40\xe5\xcc\x24\xe1\x90\x2b\x82\x8c\x62\x9d\x0d\x02\x73\xdf\xd1\x09\x26\x19\x49\x2f\x74\x99\x2d\x59\x74\x08\x2a\x26\x53\xf0\x96\x55\x6a\xd4\x8d\x1c\x54\xc8\x82\x69\x3d\x26\xed\x70\xe4\x1d\x1d\xda\x7b\x9a\xf3\x5a\xdb\x86\xac\x56\x0a\x34\xe3\x52\xbb\xf5\x30\x83\xdc\x91\x0b\x3e\xa9\x27\x3e\x21\xb6\x06\x76\x2d\xb4\x6e\x74\xd4\xee\x0d\xda\x51\x1d\x83\x41\xd0\x26\x95\x4a\x39\x87\x6e\x2e\x17\x58\x7b\x28\xfc\xd0\x79\x76\xf0\x41\x41\x15\x73\xbd\x40\x62\xa3\xad\xb1\x89\xe1\xc8\x23\x70\x96\xbb\x5b\x7d\xff\xdc\x2d\x6a\x39\x9a\x55\xbd\x8b\x3c\xd8\xab\x77\xc4\x51\x7c\xc7\xd3\x0c\x1f\xe2\x28\x79\x0b\x08\x88\xaa\x8c\xc6\x66\x38\x13\x84\x98\x9d\x89\x12\x9c\x7e\xe7\xab\x8c\x80\x78\xe7\x3e\x42\x33\xe1\x8a\x22\x87\x30\xef\xbd\xc6\xd0\x9c\x67\xb7\xca\x9b\x89\x38\x73\xa9\x60\x27\x62\x99\xd3\xbd\x26\xe6\x50\x06\xd6\x6a\xa4\xd4\xb1\x48\xce\x07\x1a\x74\x20\xca\x97\x2d\x37\x3d\x59\xcb\x7d\x48\x4a\x38\x6d\x66\x7f\x28\x3a\xbb\xd5\xec\xd1\x0b\x86\x74\x2b\x57\x78\x1d\x89\x52\xeb\xef\x9d\x80\xcd\x4c\x3f\x51\x39\xd8\xf6\xb3\x95\xd0\xe4\xb3\xd8\xf6\x87\xb6\x05\xf8\xc5\xfd\x6e\xa7\xef\xe5\x9e\xfe\xa5\x79\xa7\xaf\xbe\x72\x4a\xe9\xd9\x93\xb0\x7c\xf3\xed\x57\x77\xf1\xf9\x8b\x23\x7e\xff\xd9\x93\xce\xf4\xc8\xd7\xe9\xcd\xaf\x53\xcd\xfc\xc8\xf7\xf9\xed\x6e\x2f\x6f\x79\xfb\xfc\xe6\xf7\x4b\x6e\x8f\x7c\xbd\xbc\xf9\xf5\x4c\xe9\x91\xaf\xd7\x37\xbf\xce\x4d\x1e\xf9\x7a\x7b\xbb\xaf\xf7\x1f\x7c\x3d\x95\x47\xbe\x3e\xde\xfc\xba\x70\x7f\xe4\xeb\xcf\xdf\xfc\xfa\x78\x64\xde\x29\xbd\x73\x8f\x5e\x4e\x44\xef\x73\x31\xbf\xcf\xc5\x3f\xdc\x2e\xa2\x0b\xfa\xe6\xfd\x28\x71\xf6\x1b\xea\xc7\xc7\xee\xf8\x83\x0d\xc5\x22\xf9\x87\x77\xe4\x94\xe7\x10\xf5\xe3\x63\x77\x3c\xfb\xd7\x35\x09\x03\x2e\x05\x95\x44\x4c\x2d\x48\x2f\x50\xc0\x35\x6f\xc6\xa9\xa7\xe0\xec\x7f\xf7\xd6\x8b\x55\x4e\x48\x8e\x9a\x79\x7a\x22\xa0\x04\xc5\x32\x35\xf0\xa3\x7b\x57\xa3\xdc\x2f\x6d\x27\x25\x87\x68\x99\x53\xbd\x19\xdf\x12\x94\x9f\xdc\xd0\x31\x93\xf8\xba\x2f\x9a\x13\x4d\x57\xa7\x48\x0f\xdd\x0a\x3f\x14\x09\x63\x36\x6e\x43\xd8\xc5\x14\x30\x27\xc3\x15\xc1\x4a\x67\x48\x43\xa7\x41\xc4\x6e\x10\xa1\x29\x21\x9f\xbc\x46\x68\xca\x5e\x0d\x8d\xc8\x6c\x3c\x87\xe2\x18\x86\xe8\xad\x4e\x1c\xb2\x6c\xe0\x9e\xee\x8f\x89\x2e\x7a\x7e\x6f\x90\x91\xfb\x6b\xa3\x9c\x63\x7c\x7d\x84\xc0\x81\xe8\x3a\x68\xe3\x33\x7d\x1f\x7c\xda\x3e\xfc\x08\x2f\xa5\xcb\xf9\xa1\xb5\x4f\xef\xb2\xf6\xd5\xe6\x1f\x6b\xdf\xac\xcc\x5f\xf9\xc1\xda\x97\x73\xed\xfb\xb9\xf6\xc5\xd6\x9e\xb1\xf6\xb7\xa5\xd7\x07\x86\x54\xc7\x9b\x43\xba\x37\xa0\xb7\x1e\x4e\xf8\xe3\xc7\xf3\xc8\x24\x9e\xd5\xd7\xb9\xd8\x5e\x1c\x58\xe5\x3a\xf7\x62\x7b\x7d\x2f\xb6\xcb\x5e\xac\xa0\xbc\x21\x9a\x81\xbd\x58\x43\xae\x57\x56\xda\xe2\x05\x56\x23\x51\x97\x9b\x5f\x5b\xee\xea\xbd\xc1\x75\xb9\x6f\x4b\x1e\x7f\xcc\x38\xca\x0f\xc6\x51\xdf\x7a\x1c\xe1\xb1\x81\x3c\x32\x65\x2f\xef\x4d\x99\x9d\x8c\xcb\x58\xe7\x48\x1f\x3a\x19\xf5\xa6\xfc\xe0\x6c\xd4\x0f\x31\x5f\x6f\x33\x88\x3f\xfe\x78\x5e\x1b\x44\x78\x9b\xc9\xe2\xb3\x73\x94\x5a\x9a\x09\x7d\x58\x39\x78\x13\x66\xde\xcd\x17\x54\xd2\x56\x2d\x0f\x0e\xbd\x50\x36\x3d\x1b\x85\x8c\xab\xcd\x84\xec\x2e\x2f\xe5\x82\x2f\xf8\x87\x32\x33\xbf\x60\x11\x3c\x36\x86\xb3\x19\x6c\xb6\x9e\xc9\xb9\x05\xa9\x68\x2f\x56\x82\x54\x6f\x2e\xe6\x2d\x56\x8d\xd8\x89\x23\x95\xcf\x16\x6c\x67\x8f\x31\x6f\xb2\x0a\xcf\x40\x77\x61\x9c\x43\xe7\x3b\xf4\x6f\xb5\x9b\xcf\xee\x65\xd9\xdb\xb7\x96\xd7\xda\xb7\x36\x6b\xdf\x9a\xdf\xaa\x7d\xeb\x6d\x63\xba\xdc\xbd\xe1\xde\xf9\xfe\x9d\xaf\x8f\x3a\xcc\x61\x5b\x63\xb4\x6c\x8d\xd1\x1e\x13\x09\xfc\xea\xad\xb0\x90\x9c\x5d\x59\xd1\x06\x87\x8e\xdc\xd0\x83\x53\x12\x3a\x72\xc6\x9e\xad\x43\x67\xe4\x4c\x68\xf5\x89\x36\xb3\xb1\x93\x8e\xee\x91\x61\xc8\xf3\x7b\xf7\x7d\xa3\x4d\xe8\x7b\xf4\xfb\xe4\x54\x7e\xf0\x7e\x8f\xe2\xd4\xe7\x53\xcd\xd4\x1e\x72\xae\xab\xb9\x4e\x17\xb8\xe0\xe0\xe9\x73\x3b\x9d\x82\x37\xd2\x29\x23\xd8\x57\x50\x39\xdf\xbf\x4e\x09\x66\x8b\x1a\xd4\x0d\xed\x81\x76\x4b\x4b\x24\xa9\x3b\x49\xb7\x66\xdb\xe6\x7e\xc5\x6d\xa8\xb6\x40\x81\xad\xbf\x72\x5a\xed\x08\xe4\xb4\xa9\xcd\x1e\x22\x89\xb5\x74\xd4\xcd\x97\xf3\xae\xf6\x1d\x6a\xb0\xd1\x4c\x5f\xb0\x3e\xfa\x56\xa4\x6d\x16\x44\xa2\x59\x6f\x55\x6e\xca\x52\x52\xb1\x84\x52\x0c\x34\xb7\x81\x5a\x5d\x70\x21\x59\x5c\xfd\x88\x05\xc5\xbf\xf2\x08\x4b\x66\x2f\xac\x88\x2f\x4b\x15\x34\xb1\xa4\x06\xd6\xb9\x45\x93\xfb\xce\x76\xfb\xde\xdd\x07\xa2\x1a\xbc\xe7\xb5\x4c\x4f\xa1\x25\x43\x26\x94\xac\x9a\xed\xa3\xef\xb1\xa7\xd3\x2c\x89\xdb\xc7\x85\x6c\x81\x6c\x5d\x74\x5e\xe0\x84\x4e\x04\x8f\x60\x41\xba\x88\x1a\x35\xf1\x69\x1c\x9d\x96\x5c\xf8\x88\x9d\x96\x48\x3d\x1f\xb1\xd4\xbc\xc4\xc1\x07\x7e\x52\xab\x26\x3d\x6b\x29\x47\xcd\x65\x69\xbc\xc2\xff\xc0\xa3\xae\x54\x72\xe0\x51\x97\xda\x8e\xa8\x7f\x8b\xbd\x1e\x39\x93\xb7\xcd\x62\x9d\x0f\xe1\x20\x2b\x52\xd7\xc1\xf6\xcf\x99\x96\xc7\x0a\x4f\x72\x41\x34\xec\x75\xa3\x41\xc8\x46\x9c\xc0\xa3\xe6\x65\x08\x1f\x51\x3f\xe8\xff\xfc\x56\x4f\x5f\x7d\xf3\xf5\xae\x3f\x5f\xbc\x7c\xf5\xdd\x6f\x3e\x7d\xfa\xdd\xf1\xe5\x6f\xc2\x7f\x08\x00\x00\xff\xff\xce\x62\x9a\x93\x25\xf4\x00\x00") func fontsInconsolataRegularWebfontSvgBytes() ([]byte, error) { return bindataRead( _fontsInconsolataRegularWebfontSvg, "fonts/inconsolata-regular-webfont.svg", ) } func fontsInconsolataRegularWebfontSvg() (*asset, error) { bytes, err := fontsInconsolataRegularWebfontSvgBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "fonts/inconsolata-regular-webfont.svg", size: 62501, mode: os.FileMode(509), modTime: time.Unix(1492020681, 0)} a := &asset{bytes: bytes, info: info} return a, nil } var _fontsInconsolataRegularWebfontTtf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xac\xfc\x0b\x78\x1b\xd7\x79\x27\x8c\xbf\x67\x66\x70\xbf\xce\xe0\x46\x12\x04\x01\x10\x04\x21\x68\x04\x8e\x80\x21\x08\x8d\x28\x5e\x44\x51\x14\x45\xd1\x34\x4d\x33\x2c\xc5\x30\x34\x45\x51\x94\x2c\x59\x96\x64\x9a\x56\x18\x2e\xab\xb2\xac\xca\x48\x8a\x2c\x2b\xb2\x15\xd9\x51\x1d\x55\x75\x55\xad\xe3\xbf\x7b\x06\xa4\x15\x57\x71\x5d\xd9\x69\x92\xba\xae\xff\xfe\xb2\xd9\x28\xeb\x7a\xfd\xd9\xae\xeb\x75\xa7\x75\xd2\x6e\xbf\x6c\xea\xd8\x24\xf8\x3d\xe7\x0c\x48\x49\x4e\xb6\xbb\xfb\x3c\x9f\x65\x00\x83\x01\x88\x73\x7b\x2f\xbf\xf7\xf7\xbe\xe7\x00\x02\x00\x1e\x01\x70\xe0\x6e\x6b\xeb\xbd\x6b\xf4\x1a\xff\x6f\x00\xa8\x1c\x00\xca\xb7\xb5\x6e\x6d\x43\x1e\xe0\x00\xd0\x06\x00\x88\xdc\x7d\xaf\x94\x39\xe8\xf6\xff\x0b\x00\xea\x07\x80\xe1\xdd\x07\x77\x1d\xe6\xf8\xcd\x00\x80\x5e\x04\x40\x7f\xbb\xfb\x91\x87\x23\xee\x82\xb5\x0a\x80\x7d\x1c\x00\x36\x8e\x1d\xde\x7b\xf0\xde\x05\xe9\x4f\x00\xd8\xff\x0b\x80\xd9\xb3\x77\xd7\xf8\x61\x00\x70\x03\x18\xc9\xef\x99\xf7\x3e\x30\x39\x76\xc2\xe8\xd8\x00\x60\x6c\x06\x78\xf2\xf0\xbe\x3d\xbb\x46\x8d\xdf\xfb\xfd\x11\x80\x6f\x61\x00\xa8\xdb\xb7\x6f\xcf\x2e\x97\xcb\xfc\x10\xc0\xb7\xfe\x01\x00\xaa\xf6\x1d\x7c\xf8\xcb\xc7\x3f\x78\xb0\x03\xe0\x92\x1d\x80\xbd\xf0\xc0\xa1\xdd\xbb\x7e\xfb\xb5\x9d\x7f\x07\xf0\x47\xcf\x00\xa0\xff\xff\xc1\x5d\x5f\x3e\xcc\xb0\x68\x01\xe0\x8f\x1f\x26\xfd\x7d\x70\xd7\xc1\x3d\xe7\x9f\x9f\xff\x02\xc0\x1f\x3f\x0e\x60\xb8\x7e\xf8\xd0\xf8\xc3\x57\xb3\xf7\xfc\x12\xe0\xdb\xdd\x00\xcc\x9f\x1f\x7e\x68\xcf\xe1\x6f\xdf\xb3\xfb\xfb\x00\xcf\xbb\x01\xd0\x17\x8e\xee\x19\x19\xfb\x78\xc7\xbd\x3b\x01\xfe\x74\x1f\x00\x18\xc9\xc0\x00\x00\xfe\xa6\xe1\xf2\x9b\xe4\xf5\xaf\x3e\xf9\x4f\x5f\x22\xaf\x6f\x1e\xbb\xf8\xd7\xf4\x13\x27\x00\x94\x90\x3b\xc0\x00\x02\x04\x1f\x02\x22\xb3\x05\x0c\x00\xb0\xec\xc7\xe8\x31\x30\x00\x67\x90\x0d\x4f\x01\xa0\xb0\xfe\xca\xfe\x14\x46\x19\x37\x00\x63\x33\x5a\x58\x60\x01\xe0\x77\x00\x24\x00\x74\x00\x8a\xff\x75\x8f\x6d\x1d\x85\x66\x70\xc4\x17\x8d\x63\x85\x31\x00\xe3\x14\xfa\x3a\x00\x78\xc8\x67\xec\x55\x6e\x91\x8c\x8c\xb6\xce\x16\x1f\xe5\x7a\x2f\xe1\x3f\x03\x4b\xaf\xca\x81\x83\x17\x01\x60\x2d\x44\x80\x03\x2b\x00\x38\xe0\xb7\x61\x19\xdd\x8b\xbe\xcc\xfc\x80\xf9\xaf\x11\x6b\xc4\x1b\x29\x8b\x54\x44\x2a\x23\xd5\x11\x29\xb2\x31\x72\x5f\xe4\xb9\x68\x65\x7c\x71\x79\x99\xfe\x8a\x03\x22\x70\x09\xf5\x14\xbf\x0b\x11\x77\xa4\x24\x52\x5e\xfc\xae\x72\xdb\x77\xd1\xf2\xff\x58\xfe\x60\xf9\xd5\xe5\xc3\xcb\x9d\x4b\xcb\x4b\xff\xf8\xde\x0f\xdf\x7b\xf5\xbd\xbf\x78\xef\xe5\xf7\xbe\xfb\xde\x8b\xef\xe1\xf7\xfe\xe4\xbd\xd9\xf7\x72\xef\xbe\xfa\xb7\x5a\xb1\x6f\xff\x9b\xff\x21\x23\xac\xfe\x01\x62\x8a\x33\x79\xc7\x17\x00\x58\xce\x60\x34\x99\x2d\x56\x9b\xdd\xe1\x74\xb9\x79\xc1\xe3\xf5\xf9\x03\x25\xa5\x65\xc1\xf2\x50\x45\x38\x12\xad\x8c\x55\xc5\xab\x13\x6b\x92\x6b\xc5\x75\xa9\x1a\x69\x7d\x3a\x23\xd7\x66\xeb\x72\x1b\x94\x8d\xf5\x9b\x1a\x1a\x9b\x9a\x37\xb7\x6c\x69\xdd\xda\xb6\xad\x7d\x7b\xc7\x8e\xce\xbb\xba\xee\xee\xbe\xa7\xe7\xde\xde\x2f\xf4\xfd\x56\xff\xce\x81\x2f\x0e\x7e\x69\xe8\xbe\xe1\x5d\xf0\xfb\x73\x27\x4e\x9d\xbb\xf0\xf4\x1f\x5d\x7e\xe6\xca\x1f\xff\xc9\x7f\xfc\xf6\xb3\xcf\xfd\xff\xfe\xf4\x79\xac\xce\xbf\xb0\x70\xed\xc5\xef\xbc\xf4\xdd\x3f\x7f\x19\x1e\x1a\xdd\x73\xff\x3b\x5f\xfe\xc3\xc3\x07\xfe\xfe\x91\xfd\xf0\xd5\xa7\x60\x1c\x60\xef\x51\xda\xbb\x07\xfe\x03\x5c\xbd\x3e\xb3\xfb\x41\x72\x7d\x70\xfa\xff\x1e\xf9\xdd\xe3\xdf\x78\xf5\x7b\x3f\xb9\xf9\xb7\x6f\xff\xf4\xbf\xfc\x19\xbc\xf2\x97\xf0\xc1\x7b\xef\x03\xc0\xe4\x5b\xff\x15\x7e\xef\x6b\xb3\xa7\x4f\x9e\x79\xec\xec\xa3\x4f\x9c\x87\xc7\x2f\xfe\xc1\x37\xe1\xfb\x3f\x38\x02\x00\x5f\x29\x0e\x93\xae\xf3\x31\x98\x85\x09\x98\x84\x23\x30\x07\xa7\xe1\x3f\xc1\x79\xf8\x09\xfc\x07\x7a\x7d\x16\xce\xc3\x53\xf0\x34\x3c\x03\x57\xe1\x39\xf8\x32\xec\x85\x7b\x61\x08\x5a\x0d\x3c\x00\x86\x75\x18\x3c\x3b\x70\x67\x77\x3f\xee\x78\x64\x27\x86\x58\x53\x09\x36\x8a\xfd\x0d\x3b\xe9\xbd\xe9\x9d\x91\xff\x8c\x91\xa7\xa6\x24\x85\xd1\xba\xc8\xdf\x62\xbb\x98\xc2\xcc\xba\x1d\x3d\xfd\x5b\x63\x3b\xa3\x29\xcc\xae\xbb\xbf\x24\x82\x9b\xbb\xfb\xa3\xb8\x79\x67\x0a\x73\xeb\xc8\x9f\x46\x63\xd1\xaf\xf4\xbf\x13\x7c\x63\x67\x70\x47\x4f\x7f\xff\x52\xf0\x67\x3b\x83\xb1\x28\x36\x88\xfd\xb8\xed\x91\x9d\xf4\x83\x9d\x3b\x4b\x52\xd8\xb0\xce\x31\x38\x90\xc2\xc6\x75\x6a\x25\xfa\x6a\x77\x3f\x8e\x7c\x75\x70\x30\x88\x61\x67\x0a\x9b\xd6\xa9\x55\xf4\x56\xf3\xea\x2d\xf3\x3a\x81\x8f\x28\x52\x0a\x5b\xd6\x45\xa6\x49\x23\x7f\x19\x7c\x63\x67\x04\xb3\xf1\xed\xb1\x08\xe6\xaa\x3b\x30\x74\xf7\x9f\xdc\x73\x72\x57\x84\x5c\x6c\x08\x46\xa3\x3b\x83\x27\xe9\xbb\x1e\xfd\x1d\x69\xd0\xaa\xf7\xce\x1d\x74\x47\x77\xa6\xb0\x6d\x5d\xe4\x3f\xd1\xe1\xd8\xd7\x45\x24\x6c\x12\x07\xfb\x23\x91\x6d\xb1\xb6\x5d\xfb\x23\xfd\x91\xd1\x11\xfd\x27\xc8\xf7\x1c\xa4\xe5\x88\x22\x45\x4e\x46\xb6\x9d\x6c\xdb\x15\x3b\x19\x39\x19\xa3\xcd\xc5\xc8\x8f\xe3\xe6\x0d\xc1\xe8\xce\x60\x8c\xdc\xc0\xcd\x7b\xc8\x9b\x9d\x29\xec\xa4\x2d\x35\xdc\x2c\x89\x46\x83\x91\x9b\x27\x77\xf4\xf4\x47\x4e\xc6\xb6\x47\x30\x7c\xa1\xd8\xb7\x28\xfd\x9a\x6b\x5d\x2c\x72\xb3\xd8\x78\x2c\xd2\xbf\xe3\xde\x60\x14\xa3\x9d\xfd\x27\x31\x57\xbd\x3d\x76\x32\x16\x39\xb9\xfd\x64\x6c\x17\xf9\x03\xfd\x4f\xc8\x4b\x0a\xbb\xc9\x32\x08\x62\x0a\xf3\x64\x00\xe4\x42\xf8\xdc\x00\x4e\x92\x97\xd8\xae\xfd\xc3\xb7\x8f\x84\xfc\xa9\x67\x5d\xe4\x64\xe4\xe4\x1c\x99\xb6\x8e\xd1\xd8\x49\x13\x8e\x74\xf7\x6f\x0a\xde\xd8\x99\xc2\xde\x75\xf3\xd0\x8c\x9a\x5b\x5a\xd0\x8e\x17\xdd\xb0\x1b\xe8\x33\xf9\xf2\x17\xfa\xc9\x73\x4f\x7f\x6c\x24\x82\x21\xd6\x12\x1c\x89\x60\x14\x6b\xd9\x19\xc1\xcd\x3d\xfd\x79\x88\xc0\x96\xdd\x2d\x79\x14\x41\x5b\x76\xb7\xe0\xc8\x6e\x5c\xba\xa7\x7c\xa5\x2d\xdf\x3a\x8c\xb6\xec\x8e\x61\xd8\xb2\x3b\x96\xd2\x35\x11\x2d\x2f\x83\x0b\x18\x68\x05\x60\x46\x0d\x5f\x00\x16\x4c\x50\xa3\x22\x90\x36\xe5\x4d\x5c\xf0\x67\x19\xd5\x68\xf8\xaf\x9b\xf2\x2c\x13\xfc\x59\x06\x54\x96\xdc\x36\x90\xdb\x79\x93\xb1\x7c\x71\x53\x1e\x91\xfb\x32\x1f\xe5\xe3\x51\x3e\xda\xca\x44\x0a\x55\xe8\x42\x61\x9f\xe1\x0b\x9f\x7e\xbb\x95\x7b\x83\x68\x3e\x3a\xb2\xac\x31\xa3\x86\x7e\xb0\x43\x05\xb4\x41\xde\x0a\x20\x2e\xb0\x56\xe0\x39\x11\xe1\xb0\x84\xe1\xe6\x82\xc9\x4e\xde\x61\x4f\x06\x9b\xdc\xaa\xc3\xae\x61\x87\x84\x4d\xee\x05\xd0\x6f\x83\xa4\x46\x90\xa8\x9a\x1c\xbc\xa0\xb2\x56\x45\x81\xf5\xe9\x78\x6d\x9d\x9c\x09\xf8\x7d\x5e\x63\xac\xb2\xda\x43\xde\x90\x6b\x17\x62\x63\x6c\x0d\x8b\x8e\x6c\x4b\xa7\xe3\xf1\xed\x99\xf4\x36\xef\x86\xb4\xa4\x70\x9c\x35\xbe\xb7\x82\x31\x19\x8d\xc3\xe9\x8e\x78\x3c\x2d\xb5\xb7\x71\x5f\x6f\xbf\xbb\x7b\x30\xd0\x94\xdc\xbf\xf4\xd7\x4c\x5d\x74\x5b\x6b\x03\x30\xf0\x01\xdb\xc9\xa6\x0c\xbd\xe0\x84\x72\x68\x03\xec\x94\x70\xb9\xbc\x60\xb6\x82\x99\x13\xb1\x3f\x83\x70\x48\xc2\xdc\x4d\xd5\xe6\xd5\xb0\xcd\xad\x0a\x48\x54\x4b\x7d\x9a\x5a\x81\x44\xd5\xc6\xf1\x82\x6a\x76\x2a\x0a\x16\x78\xec\x52\x70\xa9\xa0\xfa\xcb\x69\x3f\x3d\xb9\x46\x94\x4d\x14\xfb\xe7\x42\x4d\xa8\xee\xb6\x77\x1f\xa4\xac\x36\x67\x36\x16\x53\x5a\xd3\xff\x92\x12\xec\xe4\xaa\x2d\xcd\x8e\x7d\x2d\x5c\x17\x9c\x51\x36\x34\xb4\xb6\x5d\x9f\x2b\xfb\x5a\x83\x4c\xaf\x9b\x5e\x99\xa3\x56\x54\x06\x2f\xfb\xa6\x81\x81\x20\x84\x51\x37\xe4\xcd\x0c\x88\xaa\xc9\x2e\xcb\xb8\x44\xca\x7b\x03\x41\x59\x96\x17\xca\x4d\x90\xe4\xc4\x3c\xc3\x87\x32\x99\x4c\xbe\xa4\xdc\x2a\xce\x37\x97\x94\x5a\x44\xcc\x49\xf3\xac\xbb\x22\x5c\x15\x90\x17\x0c\xf4\x3b\xf3\x46\x8b\xd5\x51\x15\xc8\x20\x1c\x91\x70\xd9\x4d\xb5\x34\xa0\xe1\x52\xb7\x6a\x42\xa2\x6a\x76\x68\xd8\xec\x56\x6d\x48\x54\xed\x0e\x4d\x8d\x22\x11\xd7\x95\x5d\x6f\x3a\xfb\xc9\x39\xf0\x89\x56\x0e\x9b\xdc\xb8\xec\x06\x79\x7f\x96\xbc\x77\x62\xbb\x1b\xfb\x6e\x70\xaa\xcd\xf1\x2b\x27\xf6\xdf\x30\xe0\x32\xf7\x3c\x53\x66\xf2\x88\xf3\x2c\x7d\x36\x92\x67\x5c\xea\x9e\xb7\x94\x9a\x3d\x22\xf6\xbb\xe7\xad\x7e\x9b\x47\xc4\x3e\xf7\xbc\xc3\x67\xf7\x88\xf3\x6e\xfa\xcc\xd3\x67\x2f\x79\x26\xdf\x09\xd0\xef\x94\xba\xe7\x4b\xe8\x5f\x95\xb9\xe7\x83\x2b\xbf\x53\xbe\xf2\x3b\x21\xf2\x9d\xf9\x8a\x95\x6f\x86\xc9\x7d\x16\xe6\x6d\x3e\x7f\x59\x4d\x4d\x4d\x0d\x6a\x16\x18\x96\x0c\xd3\xcd\x53\xf7\x42\x9d\x4b\xcd\xaf\xfd\x87\x9b\xcb\xe8\x6a\xc9\x9e\x58\x4e\xf6\xe4\x58\xfa\x30\xc5\xe8\xc3\xe4\x21\x0f\xf2\x91\x6c\x7e\x3d\xf9\xae\xf1\x83\xe4\xb4\xf8\x77\x6b\x8e\x25\xbf\x6b\xff\xae\xf8\xba\xf5\xf5\xd4\x74\xea\x03\x71\x52\x3c\xfe\xbe\xf8\x01\x9a\x1b\x44\xf7\x0d\xa1\x21\xae\x70\x19\xf5\x31\x85\xe7\x86\x0b\x57\xbe\x54\xf8\x9a\x05\x1d\x2d\x7c\x9d\x41\x0f\x0c\x23\x0a\x3a\x58\x98\x5a\xbe\xc4\x3e\x6f\xc8\x42\x0d\xd4\x42\x3d\x5c\x01\x9c\x92\xf0\x5a\x59\x35\x1a\x34\x9c\xcd\xe4\x53\x46\xb2\x60\xa9\x75\x16\x11\x97\x49\x38\x23\xe1\xb0\xac\xba\x0c\x1a\x0e\x64\xf2\xae\x0c\xf9\xc8\xe5\xb6\x88\x08\x6f\x92\xb0\xf5\xa6\x2a\x39\x35\x2c\xb9\xd5\x75\x48\xcc\x1b\x5d\xe9\x4c\x26\xa3\x8a\x01\x6d\xde\xe3\x0f\x67\xab\x02\x19\x2c\xba\xd5\x0d\x48\x54\xe3\x4e\x4d\x6d\x40\xa2\x2a\x59\x79\x21\x8f\x18\x56\x51\x14\x75\x83\xc8\x0b\x2a\x1f\x54\x14\x1c\xe7\xd5\xb2\x52\x45\x01\xd5\x98\xe2\x05\x5c\xa3\xe0\x32\xfe\x3b\x80\xac\x91\xb8\x94\xae\xaf\x0a\x28\x38\x23\xe0\x52\x65\x7d\xba\x09\xf9\xbd\x01\x7f\x80\xaf\x41\xd9\xda\x46\x26\x97\x95\x89\xc2\x99\x7c\xfe\x80\xa9\x06\x25\xaa\x13\x7c\x05\xeb\xf3\x3a\x19\x93\x2f\x96\xad\xf6\x78\x03\xbc\x13\xa1\x46\x94\xad\xad\x4e\x4c\xf5\x9b\x8d\x63\x4f\x5d\xfa\x96\xd4\x3b\xb1\x6d\x96\xb1\x33\xaf\x1c\xee\xb7\x32\xd6\xf6\xa9\xfe\x99\xde\xa4\xd4\x7f\xac\xfb\xe8\x3b\xf1\x17\x07\x07\x91\x34\x72\x68\xe4\xd0\x2b\x5f\x31\x96\x5b\x0e\x39\xd1\xf7\xb2\xe7\x0f\xe7\xf6\x74\x65\xad\x53\x0c\xc7\x09\xae\xae\xc0\xef\x1f\xe2\x42\xd6\x5e\x5f\xe1\xe1\x50\x43\xe7\x70\x53\xfd\xa1\xc1\x16\xeb\xcc\xb4\x9b\x9d\x98\xe8\x40\xbb\xad\xf7\x2d\x7e\x57\x98\xdc\xd6\xd1\x1f\x03\x30\x80\xb2\xfc\x31\xfb\xb6\x41\x00\x1e\x7c\x10\x85\x2c\xb4\xc0\xd7\x21\x2f\x00\x88\xf9\x34\x80\xa8\x2a\x26\x2d\xef\x61\x40\xcc\x1b\x88\xe2\x84\x4d\xda\x42\x73\x22\x6d\x70\x88\x6a\xb3\x49\x5b\x28\x75\xd0\xcb\x52\x93\x86\xf0\x16\x62\x97\x54\xbf\x43\xc3\x7e\xb7\x5a\x8e\x44\xd5\xea\xd0\xb0\xd5\xad\x56\x22\x51\xad\x0b\x68\xb8\xce\xad\x6e\x42\xa2\xba\x2e\xa0\xa9\xad\x48\x54\xcb\xfd\xbc\x90\x77\xf8\x0c\x64\x6a\x37\xd5\xf1\x42\xde\x93\x4e\x28\x64\x52\x9b\x05\x5e\x50\x2b\xd7\x29\x8a\x1a\x2e\xe5\x05\xd5\x0a\x8a\xb2\x3e\xed\xa9\x6d\x64\xe4\x4c\x05\x43\xcd\x57\x0d\xe3\x41\x32\x62\xbd\x7e\x39\x53\x97\xad\xad\x8e\x55\x1a\xd1\xea\xc7\x4e\x86\x7c\x9e\x2b\x7e\x96\x20\x1f\x2a\xf1\xc6\x5e\x49\xea\x6d\x88\xcf\x8e\x48\xbd\x8d\xf1\x38\xf3\xbd\x13\x4b\x39\xb1\x25\x91\x68\xd8\x9c\x88\x37\xa3\xc1\xe2\xc7\xb1\x78\x43\x8f\x44\xbe\x30\xd9\x96\x4c\x36\xc5\x62\xd5\xc9\x16\xce\x9c\xdb\xbd\x2d\x99\xdc\xbe\x3b\x37\xf1\x44\xb2\x7d\x64\x31\xcd\x2d\x7e\xc6\x71\xe6\xbe\x8e\xf6\xfe\xfe\xf6\xf6\xc5\xc7\x73\x23\xed\xc9\x64\xc7\x70\x2e\xb7\xbb\x6d\xcd\x9a\xb6\x91\x8d\xfd\x9d\x5d\x3d\xbd\xc9\x44\x07\x95\xd9\x8e\xe5\x8f\xd8\xb7\x0c\x66\x58\x03\x39\x68\x81\xfd\x90\xaf\x02\x10\x71\x44\x56\x6b\x38\x2d\x6f\x25\x93\xd9\x6c\x5c\x9d\xb6\xa4\xa0\xcd\x1b\x92\x60\x16\xd5\x0d\x2e\x0d\x27\xdd\x54\xfa\x5c\x4e\x7d\xaa\x1a\x36\xf0\xc2\x0b\x56\xb6\xaa\x26\xeb\x25\xe2\xe5\xe2\xd5\x68\x2d\x99\xa9\x9a\x2a\x5e\xc0\x61\x05\x37\xf3\xd7\xc0\xc5\x56\x44\xb3\x1b\xab\x02\x74\xae\xea\x72\xd5\x89\xdb\x66\xc4\xe4\x69\x44\xb9\x44\x6d\x2e\x60\x34\x05\x4c\x09\x27\xd2\x67\xa8\x82\x91\x33\x8d\x4c\x13\x42\x4e\xe4\xf1\x06\xa8\xe8\xc5\x2a\x8d\x1d\xa7\x27\xce\xa2\x54\xe7\x5e\xa5\x61\x6f\x47\x75\x64\x53\x77\xfa\xbf\x85\xea\x8d\x8c\xf9\x78\x5b\xdf\x63\x93\x47\x9a\xae\xed\x69\x7b\xb8\x4f\xfa\x66\x28\xdd\x1c\x8f\x6e\xad\x4f\xbb\xc2\x85\xcf\x7a\x06\x77\x4f\x77\xdc\xd3\x9b\x53\x7a\x51\x74\xe6\xed\xcd\xf8\x51\x65\xf7\xb6\x64\xaa\x73\x58\x96\xf7\x0e\x76\xfa\x0b\x2f\xc7\xf6\xa6\x4a\xec\x96\x2f\x4d\x3d\x74\xfd\x8b\x2f\x74\x0f\xa7\x7b\x0f\xf7\x89\xdb\x36\x54\x78\xc3\x09\x77\x0c\x8d\xc8\xcf\x30\xe3\x23\x17\x63\xa7\x5b\x5b\xbf\x78\x0f\x00\x42\x57\xd8\x4e\xe6\xb4\xa1\x17\x5c\x90\x00\xec\x92\x8a\xae\x04\x61\xb7\x84\x0d\x37\x55\x9b\x5f\x53\x79\xe2\x3c\x0c\xc4\x79\xb8\xa8\xbb\x40\xb7\xb9\x0b\x27\x72\x21\x74\x25\x65\xb5\x52\x17\xc1\x54\xc4\xe4\xdb\x5c\x43\xec\xd8\x10\xf1\x07\x08\x85\x0a\x4f\xb3\x63\x86\x5e\x28\x01\x0f\x20\x5c\x4a\xa7\xdf\xe9\xd2\xd4\x32\x24\x92\xdf\xab\x15\x1a\x51\x2e\x60\x8c\x25\x2a\x4d\x46\xc6\xe7\xad\x60\x02\xa6\x1a\x86\x41\xa1\x6d\x5f\x7d\x79\xb2\xc1\xce\x05\x8c\xf6\x85\xd7\x1a\xc6\xaf\x8c\x6d\x9e\x7a\xe5\xf8\x36\xc6\x7d\x0a\xa1\xb7\xaf\x66\xa7\x39\xc6\xb8\xbf\x70\xf6\x1f\xc7\xdf\xfd\xeb\x67\x37\x3d\xd0\xf4\xdd\x0f\x91\x99\xe2\x84\x73\x85\x8b\x8c\x66\xe8\x01\x1f\xf8\x01\xdb\x24\x84\xfd\x74\x20\x6e\xb7\xa6\x06\x68\x73\x81\x46\x36\x5b\x5b\xc3\x24\x72\x15\x8c\xe0\xf3\x32\x4e\x64\x3a\xb7\xef\x4f\x8e\x36\x35\x8d\x3f\x33\x92\x98\xfa\x9b\x47\xef\xba\xfb\xeb\x6f\x1e\xd3\x72\x4f\xbf\xfa\xd6\xf8\xf8\x5b\x2f\x5d\xcc\x1e\x53\xe6\xdf\x5d\x86\xb9\x13\x85\xc5\xbf\x7f\xb1\x1e\x10\xf4\xc2\x5b\xec\xb3\x5c\x02\x78\x00\x4f\xce\xc0\xca\x4e\x64\x62\xe3\x01\x03\x32\xd9\x50\x02\xf5\x66\x51\x67\xf4\x0a\x63\x66\xc2\xa8\x2d\x5b\xb8\x8c\x98\x23\xef\x7c\x78\x08\x59\x99\x1f\x1f\xbf\x88\x0e\xd8\xc3\xf6\xc2\xdf\x3c\x3e\x7d\xa0\xf0\x7a\x3f\xea\x2d\x3c\x3b\x80\x64\xd2\xdf\x41\xf8\x09\x7b\x85\x93\xc0\x06\x3d\x80\x41\xc2\x26\x59\x45\xac\x86\x0d\x99\x3c\x20\x62\x48\xc1\x6a\x11\xf3\x08\xc8\x25\x62\x89\x4d\xb5\x13\x9b\x8a\x99\x8c\x6a\x71\x68\x98\xcb\xe4\x2d\x56\xf2\x99\xc5\x64\x11\xf3\x56\x0b\xb9\xb4\x82\x45\x54\x1d\x74\xac\x9e\x6c\x94\x97\xf9\xa8\x2f\xca\xc7\xf8\x41\x74\x60\x06\x0d\x15\x2e\xcf\x30\xbd\xd3\xe4\x75\xba\x30\x83\x8e\x51\x6c\x85\x7a\x0a\x57\x99\x71\xf8\x31\xb8\x61\x0d\x60\xb7\xb4\x60\x2b\xca\x00\x2f\x61\xf6\xa6\xea\x14\xb4\x3c\xeb\xb4\x8a\xf3\xc0\x9a\x2d\x22\xc1\x14\x64\xd1\x88\xf4\xd6\x30\xd9\x22\x4e\x30\xa1\x1e\xa5\x33\x9a\x88\x6c\xc9\x66\x7f\xeb\xed\xc2\x87\xd9\xff\x50\xed\xad\x8a\x88\x41\xb9\x6d\xa8\xf3\xf2\xbb\x74\x5d\xce\x32\x4d\xec\x38\xf3\x1a\xb0\x10\x20\xe3\x54\x91\x59\x23\x0f\x84\x39\x49\x35\xac\x74\xd6\x77\x96\xf9\x3b\xa6\xe9\xe4\x49\x40\xe8\xd0\xb2\xc6\x8c\xc0\x4f\xc0\x0e\xd9\x5b\x68\x4c\xe0\xc4\xdb\xaf\x11\x81\x60\xab\xc8\xac\xf8\xa2\x3a\xe9\xaf\xdd\x01\xbe\xd0\xa1\xed\x92\x94\x88\x6f\xab\x95\xb7\x0e\xa5\xdb\x62\x71\x49\x6a\x6b\x05\x04\xb3\xcb\xcf\xb2\xc7\x0c\x3d\x24\xae\x0d\xa0\x00\x9a\x65\x66\xa6\x96\xa6\x83\x86\x83\xcd\x9f\x5e\xa0\xf6\x64\x6c\x59\x63\x9f\x32\x70\xe0\x81\x0a\x58\x0b\x1d\x90\x77\x11\xf3\x5c\xc9\x69\xba\x65\x2e\x63\x35\x84\x45\x2a\xcd\x5e\xa7\x86\xbd\x6e\x35\x41\x6c\xb0\x53\x23\xae\x4e\x4d\x78\x79\x61\xde\x65\x08\x84\xab\x02\x0a\xa8\x65\x95\xbc\x30\x6f\x05\xff\xda\xa2\xbd\x20\xa6\x22\xe0\x17\x6e\x59\xcf\x00\xaa\x41\xb1\x4a\x27\xe3\xa9\x40\xc4\x48\x10\xaf\x34\xd6\x3a\x7e\xae\xeb\xd2\x64\x7d\x7b\xfb\xc4\xb9\xce\xae\x73\xe3\xad\xbf\x5f\x8e\xbe\x97\x3c\x90\x93\xf7\xdc\x25\xed\x48\x1f\xcc\xe6\x76\x6d\x13\xed\x4e\x66\xfc\xec\xbf\x3e\x3f\xfc\x6c\x77\xa1\x70\xe9\xf2\x3f\x5f\xea\xba\xef\xd9\x7f\x7e\xee\xd8\x43\xcc\xd6\x9e\xde\x8e\xd9\x97\x0a\xa1\xc1\x9e\x2d\xc7\xae\x8d\xb7\x1f\x53\xc8\x1a\x2c\x10\xec\xcc\x15\xc0\x08\x71\xc8\x73\xc4\xdf\x20\x06\x44\x84\x4d\x14\x33\xb2\x2e\x4d\x35\x23\x51\x65\x39\x5e\xc0\x88\x02\xc3\xb8\xcc\xc7\x78\xc3\x02\xea\x1a\x39\x5d\x28\x70\xdd\xcf\x7f\xc6\x70\x9d\x9d\x3a\x1e\x3f\x0f\xc0\xce\x1a\x38\x58\x0f\x77\x43\x1e\xc8\xbc\xac\x65\x35\xfd\xa2\xc6\xa2\xe5\xcb\xc8\x04\xb9\xc8\x04\xa5\x29\x06\x08\xbb\xb4\xbc\x35\xbc\x2a\x9e\x19\x24\x82\xba\x16\x68\x43\xaa\xab\x86\x17\x16\x38\x7f\x20\x5c\x4d\x27\x47\xce\x36\xa2\x26\xa4\x6b\x29\x99\x11\x93\xd1\x94\x68\x44\x2b\x96\xd5\x85\x9c\xac\x29\x9a\xa9\xab\x47\xbe\xf3\x9d\x7f\xda\xb3\x5b\x6e\x8a\xdb\xab\x5a\x7b\x53\xd9\xde\xe6\x38\xc3\x71\xfb\x72\x7f\xf1\x60\xe7\xdc\xd8\xc6\x98\xd2\x99\x9c\x0a\x6e\x6e\x6e\x08\x30\x01\x6b\xc0\x6a\x1c\x38\xff\xd6\xf6\x2f\x4a\xdd\xdb\x5b\x63\xa9\xde\x2d\x89\xb0\x28\x09\x82\xa9\x67\xe4\x60\x6e\xf7\xec\xf6\xfa\x03\xc3\x3b\xab\xc6\x4b\xb7\x74\xf5\x89\xc2\x19\x3a\xb6\xd3\xcb\x1a\x3b\x66\x00\xa8\x85\x2f\x40\x5e\x26\x43\x32\x73\x5a\x3e\x46\x86\x54\xc1\x6a\x0b\x5e\xb7\x1c\x73\x88\xaa\x97\xb8\xe0\xac\x84\x4b\x6f\xaa\x6b\x9c\x1a\x76\x44\x6e\xf2\x6a\x8d\x53\x53\xeb\xc8\xd8\xdc\x66\x5e\xc8\x03\xaa\x51\x14\x05\x7b\x79\x2c\x2a\xb8\x42\xc8\x47\xa2\x6b\x14\x85\xc2\x94\x0a\x14\x46\xab\x0b\x1d\xab\x34\x9a\xb2\xf4\x92\x0c\xd8\x94\xa8\x2b\xba\x5d\x53\x05\xd2\xe5\xe3\xf4\x41\xb3\xd9\x1a\x72\xef\xc9\xe6\xee\xdb\x9a\xb8\x32\xe7\x0e\xbb\x87\x8e\x75\xc7\xa2\x1b\x7b\xd2\xb3\xfd\xdd\xd3\x0b\x1d\x33\x43\x1b\xee\xef\x1b\x99\xcc\xed\xbb\x30\xfc\xd2\xd4\x8c\x39\x61\x0f\xba\x93\xc9\x6d\xc3\x75\x87\x7e\x87\x61\xc6\x13\x9b\xfb\x6b\xe3\x5b\xe4\xe8\x48\xff\x09\x79\x60\xa2\x65\xf0\x1b\xd1\xd8\xc2\x78\xe7\xdc\xd8\x26\x9d\x49\x1a\x01\x60\x9f\xe6\x0a\x60\x05\x07\x0c\x43\xde\x42\xa4\x82\x61\x40\x5c\x00\x9b\x85\x71\x88\x98\x93\x55\x60\x35\x6c\xcc\x20\x12\x6b\xd8\x6f\x62\x4b\x46\xe5\x6c\x1a\x36\x65\xf2\x9c\x9d\xac\x27\x67\xb4\x88\x79\x3b\x47\x2e\xed\x64\x69\x5d\x48\x54\x39\x3b\x2f\x60\x46\x01\xd5\xa6\x2f\x31\x66\x78\xec\x20\x72\x9f\x45\x32\x2f\xfb\x62\x7c\x8c\x04\x62\x23\x4c\x78\xf2\x99\x67\xce\x17\xbe\x86\x1e\x41\x23\xf7\xb3\xf2\xe2\xfb\xc7\x0a\x97\xd0\xc8\x34\xb3\x89\xea\xa6\xc6\x9e\xe1\x16\x61\x2d\x1c\x85\xfc\x1a\xb2\x06\x16\x56\xcb\x97\x90\x35\x08\xb2\xda\x42\x85\x67\x4d\x89\x43\x54\x2b\x0c\xba\x0a\x3a\x6f\xaa\x31\x37\xd5\x3b\x1a\x01\x7c\xb8\xd8\x4f\x10\x3f\x2e\xa9\x71\xe2\xc0\x0d\x83\x1a\x64\x7f\xe5\xc4\xe5\x37\x40\x0d\x94\xd7\xd4\xa0\x79\x82\xb0\x8b\x80\x1a\xa9\x31\x27\x2f\xa8\xa5\x65\xc4\xbb\x7b\x2c\xbc\x30\x0f\xc8\x1f\xa3\x72\x48\x56\x29\x50\xc1\xca\xab\x2b\x63\x34\x25\x3c\x51\x5f\x94\xad\xbb\x85\x7b\xaa\x67\x8f\x59\x19\xc6\xbc\xb6\xa9\x37\x9d\x1e\x68\x4d\x26\xdb\x87\x72\x2d\xc7\xa4\x01\x91\x99\x5b\xfa\x57\xdf\xe8\xc1\x9e\x47\xf7\x29\x0d\x07\xcf\xf6\x4d\xfc\xe0\xf9\x21\x63\x9c\x73\x26\xe3\x41\xb1\xeb\x48\x7b\xfb\xe1\xae\x64\xb3\x12\x67\x4e\xcc\x14\xce\xa6\xeb\x8f\xfc\xc1\xee\x91\xa7\x1f\xdc\xb8\x57\x5f\x8f\x13\xcb\x1f\xb3\xb3\x06\x2b\x54\x41\x0e\x1e\x84\x7c\x64\x45\xb3\xa8\xc5\x71\xb2\xda\x82\x3f\x13\x21\x00\xd0\x4f\x74\x6b\x03\x35\x3e\x71\x9b\x46\xa2\xd2\xb8\x5b\x4d\x21\x51\x0d\xba\x34\x55\x41\xa2\x9a\x8a\xf3\xc2\x82\xd5\x69\xf0\x47\x08\x82\x09\xf2\xaa\xd9\x44\xc6\x98\x59\x4b\x04\x33\xe8\x21\x20\xd0\xe9\xe7\x05\x6c\x56\xb0\x81\xc7\x26\x6a\x95\x04\xa2\x67\x14\x2c\xeb\xc6\xc8\x74\x4b\xef\x6e\x21\x98\xba\x95\xd9\x30\x7a\x4f\x34\x3f\xf2\x27\x63\x97\xbe\x3c\x2a\x38\xfc\xe1\xa6\x50\xf2\xe0\xd0\x16\x46\x3c\xdb\xd3\x7e\x6c\x38\xa7\xec\x3e\xbe\x63\xf8\xf1\x3d\xd9\xc7\x13\x5b\x87\xea\xfa\x67\x93\xcd\xdd\xd5\x1d\x73\x49\x86\x69\x7b\x0e\x99\x17\x06\x1f\x3e\xe8\x4e\x98\xbd\xae\xc4\xfe\xef\x3d\xd9\x7e\x4f\xfd\xa1\x27\x87\x86\x9e\x3e\xd2\x70\xef\xc5\x77\x63\xdd\x73\x23\x1b\x2f\x9c\xed\x3a\xd4\x5e\x39\xda\x6e\x2f\x25\xba\x78\x19\x80\x9d\xe0\x16\xc1\x0a\x49\xc8\x9b\x56\x6c\x96\x0a\xc4\x75\xd8\x24\x6c\xba\xa9\x1a\xbd\x9a\x6a\x27\x3a\x87\x88\xb0\xb1\x8a\xee\x49\xac\x88\x8d\x95\x21\xcf\x65\xe6\xc7\x33\xef\x0d\x5d\x1e\xb9\x79\x94\x9b\x98\xeb\x2e\xbc\xb5\xf4\x7c\xe1\x0d\x14\x67\xb2\x28\x48\x63\x9c\x8f\xd9\x39\x83\x1d\xc2\x20\x41\x0b\x1c\x80\x7c\x90\xcc\x76\x9c\xd5\xf2\x36\xd2\x46\xe3\x2d\xb0\x18\x71\x6b\x38\xe2\xc6\xeb\x89\x8e\x1b\x9d\x1a\x36\x4a\xea\x7a\x27\xb9\xa5\xae\x45\xa2\xea\x77\x6b\x58\x21\x1f\xb9\x5d\x3a\x7c\x54\xd6\xf3\xc2\x35\x1b\x1b\x8c\xa7\x3c\x75\xd4\xfc\x37\xc6\x79\xe1\x05\x30\xba\xfd\xa9\xba\x55\xc0\xa8\x07\x29\x9f\xd7\xf5\x5b\x38\x91\xb8\x00\x27\xf2\x18\x03\xc4\x58\xe8\xee\x96\xac\xc9\xd4\xa9\x89\xfe\x03\x75\x43\x53\xdb\xda\xa7\xfa\xe5\x07\xbf\x74\x68\xae\xe1\xfe\x33\x3d\x3d\x67\xee\xaf\x3f\x97\x68\xed\x97\xe5\xfe\x96\xf8\xe3\xd3\x83\x53\xb5\x28\x56\xda\x2d\xc7\x3a\x47\xc2\xb9\x0e\x51\x6c\xcf\x96\xa3\x96\x43\x37\xb2\xa9\xcb\x83\x2d\x0f\xf5\xa5\xa5\xde\x43\x0d\x83\x57\xd2\xf2\x5f\x3c\xd8\x31\x33\x94\xcd\x0e\x4e\xf7\x49\x3d\x8d\x55\x95\x9b\xba\xa5\xa1\xa7\x13\x89\xa7\x18\xb9\x41\x4e\x6e\x2a\xf3\x24\x4f\xb5\xc7\x37\xd7\x55\x54\xa4\x5b\x80\x81\x53\xcb\x1f\xb3\xc7\x0c\x66\x08\x43\x06\x0e\x42\xde\x41\x66\xca\xb7\x22\x97\xeb\x59\x6d\x21\x18\x77\x10\xb9\x0c\x12\xb9\x94\xf5\x49\x73\xd1\x19\x12\x91\x88\x4b\x32\xaa\xd9\xad\xa9\xb5\x48\x54\x23\xc0\x0b\xaa\xcb\xad\x28\x58\xe4\xe7\x1d\x42\xd0\x40\x27\xc8\xe7\xe0\x05\xec\x22\x72\x8a\xdd\x8a\xba\x3e\xce\x0b\x79\x33\x94\x28\xb7\x02\x11\x81\x27\xb0\xba\x32\x91\xab\x40\x01\x12\x69\x78\x6e\x07\xd5\x75\xb9\x95\xf9\x31\x9e\xda\x38\x7a\xbc\xf3\xfa\xeb\xed\x53\xcf\x0c\x3e\xf3\xc8\xa8\xd5\x65\xae\xef\x7b\xea\x1b\x96\xd4\xd7\xba\xdb\x7f\x7b\x78\xc3\xd7\xaa\x36\x75\x26\x7b\x7e\x47\x64\x50\xa2\xa5\x2f\xb5\x6f\x86\x1d\x1d\x78\xea\x48\x53\xe1\x2f\x0a\x7f\x70\xf9\x67\x4f\xdd\xc5\x3c\x7c\xd0\x18\x37\x4a\x1f\x21\xae\xa9\xa3\xfe\xc0\x13\x83\x2d\xfb\xb6\x27\xee\x6d\x77\x47\xdc\xdd\xb3\x83\xf2\x37\x81\xd1\x31\x09\x3b\x02\x76\x28\x05\xe5\x0e\x54\x82\x03\xd2\x82\xbb\x88\x49\xca\xc8\xe0\xb1\x23\xb3\x42\x18\x79\x57\xae\xd4\xe0\xaf\x23\x13\xfe\x7f\x02\x53\xe8\xc5\xf6\x8c\xb4\x7d\x15\xaf\x30\x7f\x91\xde\x1a\x8b\xd7\x48\x6d\x5b\x29\x5f\x45\x31\x1b\x3b\x02\x6e\x08\xc1\x0e\xc0\x41\x69\xc1\x5b\x6c\xbf\x62\x05\xb5\x61\xa7\x1b\x97\x44\x6e\xf2\x0b\xbc\xde\x11\x5e\xc2\x66\x79\xa1\x44\xef\x4b\x98\x78\x7a\x9e\x17\xb0\x5b\xc1\x25\x7c\xde\xe6\x0d\x2a\x3a\xba\xff\x1c\xb0\x63\xef\xe8\xe0\x6d\x28\x2f\xb9\xda\xc5\xcf\xe3\x3d\xae\x75\xb5\xa7\x08\xda\x61\x98\xc5\xdc\x09\x30\x02\x78\xb2\xc8\x67\x41\xbe\x76\x76\x64\x49\x61\xde\x60\x86\x76\xa3\xbf\x3a\x5b\x78\xa2\x70\xe8\x22\xb1\x7b\x83\x68\x90\xbd\xc2\xce\x50\x5e\xaf\x4c\x47\x88\xac\x46\xc1\x21\x11\x28\xb3\xa4\x5a\x56\x41\x22\xca\x46\x7d\x83\x6c\xc7\xe2\x35\xb6\x03\x0d\x4e\x4f\xa3\xab\xd3\xd3\x3a\x26\xe9\x81\x61\xf6\xba\xde\x56\x2e\x6b\x41\x59\xe4\xeb\x61\x5e\x5f\x52\xd8\xd1\xe1\x8b\xe8\x2c\x3a\x70\xb6\xb0\x61\x37\xb5\xb1\xb3\xcb\x1f\xb2\x93\x86\x1e\xa8\x82\x34\x1c\x04\x2c\x49\x0b\x6b\xf4\x55\x8c\x4a\x2a\xcb\x69\x08\x67\x24\xec\xb9\xa9\x0a\x4e\x6d\x9e\xf7\xc4\x9d\xe2\xc2\x3a\x7d\x02\x05\x3d\xca\x36\x7b\x35\x55\x46\xa2\x2a\x78\x78\x61\x81\xf5\x47\xd7\x48\xc4\xc2\xae\xe3\x55\x57\xa9\xa2\xe0\x72\x41\x2d\x73\x2a\x0a\x36\x13\x97\x07\x6a\x74\x0d\xf1\x29\x66\xa1\x4a\xd7\xfb\x3b\x80\x0c\x0a\xa1\x18\x25\x2a\x56\xa5\xd7\xe4\xd1\xa7\xdb\x44\xa7\x7b\xb6\xe5\x27\x0f\xf7\x1c\xbf\x2f\x1b\x12\x95\x50\xaa\x3e\x34\x67\x0c\xe6\xd2\xed\xb9\xa8\xd2\x29\xf6\x3d\x21\xe5\xb7\x65\xa4\x44\x0c\x6d\x4b\xa7\xdb\xb9\xe9\xd1\x23\xca\xee\xd9\x0e\xa5\xbf\x2d\x5b\x12\x97\x76\x6d\xee\xed\x15\xb7\xb6\x76\xa6\xdb\x1f\xda\x98\xea\xae\x8f\x0e\xf7\x2c\x36\x49\xed\xb1\x44\x4a\x6a\x6b\xa3\xe3\x6f\x5a\xd6\xd8\x17\x0d\x6e\x58\x0f\xf5\xf0\xfb\x90\x5f\x47\x74\x39\x61\x28\xea\x72\xc8\xa4\x2d\xb8\x6a\xd7\x11\x5d\x76\x99\xb4\x85\x80\x42\x2f\x03\x04\xec\x6c\xa2\x6a\x5d\x19\xd0\x70\xa5\x5b\xf5\x22\x51\x4d\x3b\x34\x9c\x76\x13\xeb\xab\x96\xe4\x32\x19\xd5\xe6\xd0\x49\x1c\x7b\x9a\x17\x16\x0c\xae\x50\x62\x1d\x99\x19\x1b\xaf\x26\xd7\x12\xdf\xe3\x4a\xf0\x02\x4e\x2a\xb8\x96\x57\x6d\x0e\x45\xc1\x8a\x90\xf7\x56\x82\x72\x07\xdb\xc0\xc7\xb2\x94\x6f\xc8\xd6\xd6\xd5\xa3\xa2\xc9\xf3\x51\x25\x27\x21\x62\x65\x0d\x13\xa7\x44\x43\x03\x8a\x55\x1a\x9b\x76\x9e\x7e\xbe\xbf\xef\xec\x81\xfa\xa9\xee\x47\xea\x77\x77\x24\xdf\xfc\xfb\x0a\x71\xc7\x9e\x5c\xcb\xec\xbe\x96\xce\xa9\x8b\x77\x4f\xec\xcd\x1d\x7f\x6a\xec\x95\x27\xbf\x84\xae\xdc\xa7\x4c\xec\xa8\xbc\x74\x9e\x99\x79\xf6\x93\x4b\x77\xd5\x1f\xfb\xe1\x89\xc2\x70\xd7\x90\xd8\x3e\x90\x3e\xff\x47\xca\x9e\x4e\xb1\x79\xf6\x8d\x33\xa7\xde\x9c\x6b\x6d\xdd\xd3\xdb\x7d\xf9\xd3\x8b\x5d\x83\x4f\x5e\x4a\x8c\xe9\xfe\x38\x0c\xc0\xbe\x63\x10\xc0\x04\x56\x58\xa7\x23\x5d\xcc\xca\xd4\x09\x2d\x18\xcd\x80\x1c\xa2\x6a\x34\x51\x5f\x54\x74\x42\x66\x5e\xc0\x56\x02\x63\x91\x8c\x62\x6c\x94\xf5\x44\xd9\x30\x7a\x95\x47\xff\x74\xee\xd1\xc2\x81\xa9\x0b\xa8\xff\x05\x83\xf0\xe9\xcf\xd1\x44\xe1\x14\xfa\x00\xfd\x03\x8d\x33\x46\x8a\x39\x18\x01\x42\xb0\x16\xfa\x8b\x78\xda\xc3\x6a\xba\xaf\x5b\x6b\xd4\x16\x2a\x42\xb4\xa9\x0a\xe3\x6a\xc8\xe1\x71\x69\xb8\x22\x93\xf7\xd0\xd0\xd0\x63\xb2\x90\x67\x97\x45\x24\x18\x08\xd4\x90\x47\x37\xa7\x15\x3c\xb6\x2a\x78\xad\x40\xfd\xbb\xcc\x47\x57\x9c\x0d\x4b\xf4\x39\x41\x0c\x67\x0d\x2b\xa2\x2c\x71\x37\xf4\x6a\x04\x1d\x38\xf4\x87\x23\x75\xbb\x07\xb2\x3b\x37\x47\x3f\xfc\xe4\xed\xff\xe7\x99\x19\x33\x17\xdf\x31\x33\xf0\xa3\xbf\xea\x3b\xd4\x1a\xe1\xb8\x8a\x96\xb1\xce\x77\xb9\x45\xb1\xef\xc8\x96\x81\x4b\x51\xa1\xb5\x6f\xb4\xee\xf2\x5f\x4e\x9f\xb8\x5f\x19\x6a\x8f\x4f\x56\x64\x3b\x45\xb1\x23\x17\x25\xba\xd8\xbb\xfc\x31\xfb\x8a\xc1\x08\x49\x68\x84\x7c\x9c\x8c\xa7\xdc\x58\x94\x30\xc1\xa0\xcd\xdb\xe2\x06\xb3\x88\xf0\x5a\x3a\x94\x80\x4b\x23\x5e\x02\x54\x5b\x39\x51\x96\x40\x98\x42\x16\x81\xa7\xf3\xb8\x22\x19\x01\x53\x75\xb6\xb6\x88\x4b\x7c\x45\xab\x1f\x70\xb2\x44\x24\x7a\x07\x1e\xff\xe3\xae\xa6\xaf\xec\xeb\x29\x3d\x69\x36\x26\x67\x3b\xda\xbe\x72\x5f\x36\xbb\x6b\x66\x7b\xe7\xa3\xe2\xfe\x70\xdf\xf0\x70\xfa\xd0\xb3\xa7\xbb\x98\xa3\x2f\x2d\x5e\x68\x8a\x6f\x1e\xdc\xb8\xc5\xe8\x2c\xb5\xb7\xde\xbd\xed\xc4\xf7\xa7\x27\x7f\xf0\x68\x57\x6f\x7b\x9b\xdc\x95\x2d\xdb\x71\xe9\x97\x64\xbd\x0f\x2d\x17\xd8\xe7\xb9\x45\xb0\x83\x0f\x36\x14\x57\xc2\x61\x2a\xae\x84\x8f\x4c\xbf\x9f\xf6\xd9\x41\x20\xbf\x9b\x92\x23\x26\x97\xce\x2d\xe8\x4e\x8c\xcc\x74\xa0\x38\xd3\x4e\x86\x4c\xb2\x90\xad\x66\x44\x74\x08\x25\x9f\xb9\x76\xac\xa1\x63\xe6\x6f\x2e\x9c\x98\x7d\xfb\x75\xe6\x3b\x3f\x7d\x92\xe1\x0a\x03\x57\x7f\xfe\xc4\xb9\x7f\xbc\xd2\x77\x04\x99\x3f\xf9\x14\x95\xe9\x76\x6c\x12\x80\x9d\xe3\x0a\x60\x83\x6d\xc5\x1e\x58\x56\x64\x81\x63\xb5\x05\x83\x2e\x76\x06\x62\xa9\xec\xb4\x33\x16\xa7\x4e\x05\x50\x59\xb0\xd8\x2c\x22\x66\x32\x3a\x27\x50\x24\x02\x74\x12\x40\x7f\x4c\xb2\xce\xa5\x49\x26\xb0\xa4\x31\x33\x5c\xe1\x58\x61\x70\xb6\x90\xd0\x79\x00\xb8\x04\xc0\x1e\xe3\x0a\x60\x81\x66\xbd\xdd\x5f\x6f\x93\x18\x63\xab\xde\xa6\xeb\xf6\x36\x59\x4b\x91\x84\x50\x6d\x9f\x6b\xf0\x12\xf3\xee\x12\x46\xef\x14\x62\x5c\x61\xba\x70\x68\x7a\xe9\xb4\xde\x56\xc7\xf2\xc7\xec\xf3\x06\x33\xc4\xe1\x30\xe4\xa3\x64\x8c\x25\xb7\xa3\xdc\xf2\x50\x94\x98\x9d\x72\xd2\x5e\xf5\xaa\xbc\x7b\xdc\x6a\x19\x12\xd5\xb0\x53\xc3\xe6\x4c\xbe\x8c\xc6\x93\x65\xe5\x16\x91\x06\xde\x65\x1e\x5e\xc8\xdb\x0d\x51\x12\x72\x85\x79\x6c\x53\x40\x2d\x2f\xa1\x74\x9d\xea\x0c\x51\x23\x6c\xf1\x14\xc1\x17\xc5\xb9\xfe\x80\xa9\xfa\x0e\x79\xca\xf1\xb1\x6c\x94\xa7\x46\xa6\x63\xf4\xd2\x95\x2d\x13\xaf\x65\x47\xed\xae\xf0\x4c\x5f\xfd\xf4\x58\x73\x76\xe8\x77\x77\x1c\x3f\xf8\x11\x7a\xe0\xda\x2b\xe3\xd7\x66\xb6\x30\x87\x5e\x43\xce\xd3\xd9\x89\xe1\x31\x73\xb8\xf5\xde\xf4\xd1\x57\x1f\x3f\xfe\xc6\x89\xf6\x2e\x24\x4d\x17\x1c\xc7\x07\xaf\xfe\x8c\x8e\x91\xc8\xd2\x79\x6e\x11\x7c\xf0\xa5\xa2\xe5\xe0\x75\xcb\x81\xad\xf2\x82\xd9\xcb\x93\x19\x35\xdf\x12\x29\x9f\x4d\x53\x39\x53\x26\x83\x7d\x34\x73\x43\x22\x2d\xde\xad\xa9\x0e\x0f\x15\x2f\x55\xf0\xd1\xa0\x4a\x75\x10\xaf\x4d\x46\x47\x4d\x8d\x8b\x2a\xb6\x4e\x74\xf3\x51\x5e\xf6\x07\xc8\x45\x8c\x8f\xf2\x87\xbe\xc5\x58\x19\xf4\x8b\x6f\x32\xc8\xc1\x9c\x2d\x38\xb9\x45\x86\x33\xfa\xdc\x05\x27\x13\x63\x38\xb3\xc7\xfe\x99\xc4\x8c\x2c\x5d\xa2\xfd\xbc\xb2\x5c\x60\x15\x6e\x51\x97\x37\x1b\x95\x37\x83\x86\x51\x46\x5f\x0e\xce\x48\xa2\x3d\x2a\x6a\x0c\x5d\xf6\xbc\x85\x59\x95\x33\x63\x26\xcf\x50\xd6\x89\x01\x8b\x88\xb9\x4c\x51\xde\x02\x59\x99\x4c\xa6\x2f\xc6\x47\x7d\x57\x16\x7f\xce\x4c\x2e\x22\x33\x33\xc9\xd9\x27\x27\x3f\xfb\xd7\xa3\xb4\xcd\xd1\x65\x8d\xda\xbc\x32\x68\x87\x7c\x29\x69\xd3\xca\x6a\x79\x37\xa5\x0d\x8c\x1a\x16\x32\x08\x07\x25\xec\xb8\xa9\x7a\x5d\x5a\xde\xeb\x20\x4d\x78\x05\x8b\x98\x77\x78\xc9\xa5\x83\x58\xba\x72\xa2\x73\x2e\x2b\x2f\xa8\x80\x6e\x0b\xab\x59\x12\xa2\x14\x5b\xa7\x90\x7a\x74\x97\x91\x31\x96\x9a\xe3\x52\xba\x64\xec\xbe\x5f\x32\xed\xdf\x97\xc6\x8e\xb6\x5d\x3b\x3a\x61\x0c\x9a\x4b\xad\x01\xc1\xf5\x58\x9e\x79\x6b\x72\x72\x29\x39\x7d\xf5\xc1\xf5\xb4\x6f\x7d\xcb\x9f\xb0\xdf\x37\x18\xc1\x0d\xb5\xc5\x75\xb3\x17\xd7\xcd\x24\x53\x56\x0c\x6e\xaa\x6e\x41\xc3\x86\x8c\xca\xf8\x35\xca\x88\xd1\xe0\x43\x35\x3a\x15\x7d\x39\xbc\x46\x1f\x8f\xfc\xf5\xc8\x82\x4c\xc8\xc4\xf7\x3d\x27\x30\xde\x54\x63\xb6\x10\x62\xb8\x3f\x2b\xb4\x8f\x72\x05\x7b\xd0\xb9\xf4\x11\xd3\x67\x5d\x7a\x6b\x49\x34\x33\x73\x87\x96\xfe\x85\xb4\x3b\x07\xc0\xce\x72\x8b\x60\x06\xb9\xa8\xf7\xc6\xa2\xde\x23\x6c\xa1\xad\x1a\x6d\x5a\xde\x48\x35\xce\x68\xb6\x88\x18\xdc\x2a\xe3\xd3\x54\x6b\x51\xe5\x68\xb3\x51\xdf\xdc\x55\x81\x19\xe3\x16\x9d\x71\xcf\x67\x3f\x9c\xa6\xb6\x18\x80\x7d\x9e\x2b\x80\x1d\x3a\x8b\xe3\x31\x16\xc7\xc3\xc9\x45\x0e\x4d\xb5\x3b\x35\x6c\xd7\xd3\x6a\x46\xa7\xa6\x3a\x89\x17\x07\x2a\x70\xd8\xc4\x63\x56\xc1\x46\x01\x73\x4a\x71\x9c\xac\xb9\x38\x4e\x0b\x92\xf9\x18\x8f\x62\x88\xef\x3d\x82\xea\x51\xcb\x03\x73\x85\x7f\xca\x15\x0a\xdc\xe2\xd2\x19\x66\xfc\x33\x86\xfd\xde\x52\x01\x7d\xb6\xd8\x0a\x08\xc6\x00\xd8\xcb\xb4\x0f\x45\xbe\x08\x5b\xe4\x3c\x47\xfa\x80\xf4\xd7\xcf\x75\x84\x45\x22\x31\x6b\xaa\xc1\xa6\x77\x86\xd5\x29\x05\x6c\x21\x5e\x01\x54\x8e\x76\xc3\x56\xec\x06\xd2\x87\x1e\x43\xfc\xd8\xd7\x98\x92\x0b\xae\xc3\x4b\x6f\x70\x8b\x8b\x5d\xec\x82\x3d\xe4\xfc\x4c\x61\x3f\x5e\xf4\x52\x5f\x5e\xbf\xfc\x31\xfb\x7d\x83\x15\x3c\xb0\x16\x5a\x8b\x6c\x5e\xa9\xa5\x68\x75\xe2\xe6\x5b\x6c\x9e\x8b\xb2\x79\x15\x48\x54\xad\x3a\xab\xa0\x56\x78\x79\x41\x35\xb8\x08\x8a\x89\x97\x12\x89\xb3\xde\x99\x23\x59\x4d\x82\x90\xe0\x64\x85\x30\x88\x19\x4d\x4e\xa6\xbe\x75\xea\xb9\xb1\x81\x8b\x33\x2d\x5d\xc7\x9e\xee\xd9\xf7\xec\x64\xcb\xa3\xf5\xd2\xf0\x44\xee\x40\xbf\xac\xf4\x0f\x6f\x30\x70\x4a\xa6\x6e\xa8\x9e\x99\x39\xf7\xaf\x57\x07\xbb\xfe\xe0\x97\xcf\xbe\xb8\x78\x71\xcb\xf0\xf3\xbf\xf8\xd6\xe9\xb7\xea\xc7\xa5\xa3\x7f\x75\xf1\xc2\xab\xe3\x32\xf2\x97\x1c\xba\x01\x0c\xf5\x0b\x57\xb8\x45\x70\x42\x29\x48\xb7\x5b\xe8\x52\xb3\xb6\xe0\x70\x51\x0b\xed\x20\x16\xb3\x4c\xa7\xd8\xdd\x1a\x76\x65\x8a\x51\x87\xee\xfc\x89\xc3\x8c\x96\xa2\x28\x75\xfc\xb1\xe8\x24\x7a\x72\xff\xf9\x5d\x12\xc7\x49\x83\x5f\xdf\x57\xf8\x67\x04\xa7\x26\x8c\x5c\x45\xe3\x70\x2b\x59\xc2\xdc\x9e\xd9\x8e\x8e\xdf\xb9\x2f\xb7\xf4\x06\x93\x9f\x1c\x95\x7a\x1b\xe3\x74\x0e\x0b\x3f\xa5\x73\x18\xd1\xd9\xb1\x95\xf0\x0f\x07\x24\xd5\xcd\x6a\xd8\x97\xa1\x9c\x18\xdc\x54\xa3\x2e\x0d\x47\x69\xf4\x47\x29\xd1\x3a\x24\xaa\x62\x94\x17\xe6\x0d\x42\xb9\x83\xb8\x77\x2b\x9f\xf7\xf8\xfc\x34\xff\xb4\xde\x4d\xc9\xd1\xf2\xea\xdb\xc8\xd1\x0a\xc6\xe7\x66\x4c\x3a\x47\x26\x9b\x28\x22\xac\x61\x6f\x85\xc6\x45\x06\xa2\xbe\xff\xab\xdf\x6a\xef\xbf\x7c\xbc\xf5\x2f\xae\x73\x0d\x7d\xd6\x9a\xac\x64\xe5\xba\x47\x4f\xf4\xc6\xbb\xce\x8c\xb7\x7e\x4d\xec\x9d\xde\x2e\x1f\x1c\xc8\x2a\xa3\x07\xd2\x0d\x07\x92\xfb\x99\xa3\xaf\x2c\x3d\xbe\x79\xfb\xe5\x7f\xc5\x85\x0f\x0b\x7f\x96\x6c\xed\xe3\x18\xee\x94\x6f\xfb\xc1\x6e\x6b\xff\xa5\x8f\xbe\x3b\xf5\xda\x99\x1e\x79\xe2\xfa\xdc\x73\x6f\x4d\x49\x0d\xd2\x24\x30\x30\x0e\xc0\x5e\xe3\x16\xc1\x05\x65\xf0\xc5\xa2\xd4\xda\x74\xcd\x51\xcb\xcc\xda\x82\xd3\x4d\xa7\xdc\x49\xa6\x3c\x48\x07\xed\x72\x6b\xd8\x9d\xc1\x2e\x1d\x1e\x1b\xdc\x1a\x0d\x18\xbc\x2e\x5e\x50\x1d\x56\x85\x32\x2d\x76\x05\x54\xb7\x93\x82\x44\x5c\xc6\x63\x43\x11\x98\xf9\x69\xda\x08\xc5\x50\xac\x14\x15\x39\x16\x11\x8d\xa3\xc9\xf7\x7f\x50\xd5\x3a\xbc\x09\x25\xbe\x55\xf8\xf0\x93\x4f\x4e\x4c\x45\xeb\x47\xda\x3e\xe1\x16\x5f\x7b\x26\xf7\xc0\x7d\x5b\x5d\x4b\x3f\x64\x64\x7d\x79\xd2\x3d\x64\x79\x00\xc1\xfe\xe5\x8f\xd9\x67\x0c\x1c\x6c\x80\x21\xc8\xe7\x88\x84\x9b\x58\x2d\x1f\xa4\x12\x6e\xd0\x10\x56\x24\xec\xbf\xa9\xae\xb1\x69\x78\x8d\x0e\xdc\x33\x2e\x4d\xdd\x88\x44\x75\x8d\x9f\x68\x14\x52\x14\x6c\xe7\x5f\x30\x09\xc1\x68\x4d\x4e\xcf\xac\xaa\x15\x61\x2a\xf6\x26\x5e\x78\x01\x90\xbf\x22\x9c\xb9\x8d\x1e\x43\x2b\xcb\x91\xa8\x61\x75\x3a\xc3\xbf\xca\x1f\x19\x69\x2e\x47\xcf\xb9\xc6\x2a\xf7\xf7\x5a\x91\x51\xba\x74\x58\xd9\xd5\x96\x0c\x36\x1e\x1e\x1c\xfd\xfd\x9e\xd8\xa6\x7d\x8f\xf5\xec\x7b\xb1\x65\xc0\xca\x72\x89\xe3\x23\x43\xd3\xe1\xa6\xa9\x91\xa1\xa9\x8e\x70\xfa\xfe\x4b\x87\x3f\x39\xf3\xb8\x31\x64\xae\xef\xae\x6e\xee\x4f\x27\x9a\x73\xb9\x78\xa2\xbb\x67\x28\xd7\x36\x35\x28\xf7\x76\x4e\x71\x41\xa3\xd2\xf6\x60\x67\xaa\xa5\xa1\xb9\x3a\xd1\xd9\x37\xbc\xa9\xe5\xf7\xee\xa7\xa5\x81\xd0\x04\xc0\x2e\x70\x05\x30\xc1\x46\xc8\x1b\x6f\xf1\x45\xac\x86\xd9\x0c\x09\x24\xb1\xf1\x26\x59\x98\xbc\x81\xa6\xb0\x0d\xac\x45\xcc\x1b\x0d\xd4\xa2\x82\x45\xbc\x2d\xca\x8c\xf2\x31\xbe\x89\x9d\x28\xcc\x9d\xe5\xa6\x67\x66\x3e\x9b\xe5\xa6\xe9\xef\x8f\x2d\x6b\xec\x65\x6e\x11\x2a\xa0\x09\xf2\x65\x2b\xbf\x8f\x3d\x72\xb1\x4c\x44\x35\xbb\x34\x95\xf3\xd2\xc2\x04\x01\x89\xaa\xcf\xa9\xd1\xc2\x10\x81\xe3\x05\x5c\x46\x0c\x68\x19\x2f\xe8\x64\x28\x2f\x67\xa8\xd7\x26\xb3\xd4\xc8\x66\x79\x99\x2f\x9a\x91\xb1\xcb\x8c\xc0\x25\xb7\xef\x51\x48\x6c\x72\x62\xc3\x43\x17\x86\x06\x2f\x3c\xb0\x09\xbd\xc8\xb6\x72\xe6\x70\x60\x71\x71\xff\x44\x67\x9c\xe3\xa2\xdd\x47\x1f\x64\x9b\x17\x5f\x9d\xfe\xf6\xf8\xc6\x8d\x0f\x5e\x02\x04\xf2\xf2\x27\xec\x8f\x29\xbf\x7f\x97\x3e\x76\x6c\x90\xf3\x40\x86\xcf\x72\xb2\x4c\x79\x7e\xf6\xa6\xca\xe9\x3c\x3f\xae\x2b\xbb\xde\xc0\x7d\xfc\xbc\x5e\x1a\xc1\xba\x31\x73\xc3\x80\x39\x37\x36\xdc\x60\x01\x33\x35\x48\x65\x0c\xab\x25\x07\xc4\xce\xa3\x98\x7c\x1e\x6d\x43\x75\xa7\x0b\xbd\x2d\x5c\x61\x51\x64\x7f\xfc\xe9\x22\x20\x88\x2d\x7f\xc2\x7e\x44\xf1\xf2\xf3\x90\xb7\x53\xec\x60\x93\x8b\xad\x22\xa3\xbc\xea\x5f\x90\x53\xc3\xc8\xad\x1a\x09\x5e\x0e\x50\x93\x4e\x3a\x70\xe3\xf5\xff\xf1\x0b\xca\xd4\x82\x1b\xdb\x6f\x38\x31\x22\xdd\xb8\xde\x70\xf3\x9f\x8f\x91\xbb\x06\x6c\xab\x71\x62\xeb\x0d\x15\x31\x66\x95\x29\xf9\x95\x13\xb3\x37\xae\xbf\x2a\xfd\xf3\x41\xfd\x43\x4b\x8d\x6a\xb3\x9a\xb1\xf5\x86\x53\x35\xb0\xbf\xc2\xdc\x0d\x58\x60\x58\xce\x60\xa5\xc5\x12\xe8\x3b\xe4\xda\x62\xb5\xd9\x6f\x2b\x9f\x40\xaa\x11\x51\xca\x93\x0e\x2a\x88\xc8\xff\x6c\xcc\x86\x62\xb1\xe3\x27\xde\x48\xbd\x39\xf1\xe5\xbf\xde\xf0\xf6\xbb\xf5\xdc\xe2\xe2\x65\x16\x16\x17\xd9\x91\x4f\x17\xd9\x8e\xc5\x6b\xb0\xe2\x43\x5f\xa6\x98\xbc\xba\x68\x09\xcc\x32\x25\xca\xb1\x41\x26\xd8\x88\x02\x1f\x95\x21\x6e\x89\xa3\xbe\x81\xcc\x19\xfd\x3f\x66\x41\xbd\x68\xb0\xf0\xec\x53\xc8\x8e\xcc\x8f\x15\x5e\x42\xfb\xff\xb0\xf0\x61\xe1\xe7\xcc\x29\x66\xbc\x10\x44\x1f\x2e\x9d\x59\x1a\x47\x9f\x16\x8c\x80\x40\x01\x60\x5f\xa3\xfe\x7f\x7d\x91\xeb\x24\xd3\x88\x59\x99\xba\x7f\xd3\x4d\xd5\x28\x50\x67\xaf\x1a\x4d\x45\x7e\x1d\xf4\x8b\x95\x25\xe2\x63\xbc\xf2\x0c\xda\x88\xca\x2e\x14\x9e\xf8\x26\xb7\xb8\xf4\x04\x73\x60\x71\xb1\x60\x46\x9f\xe8\x98\x7b\x8c\xea\x06\x59\xab\x74\x11\x5f\x98\x58\x0d\xdb\x32\xd4\xff\xaa\x2c\x31\x63\x0e\x89\xe6\xcf\x54\x53\x31\x37\xc3\xb1\xbc\x80\x8d\x34\x2b\x83\xa2\xd9\xa8\x8f\xb8\x0e\xd9\x37\xc6\xcc\x2e\x9d\x67\xbd\x4b\x5f\x65\x06\x9c\x31\xe7\x28\x17\x98\x19\xfd\xec\x23\xfb\x29\x00\x84\xec\xcb\x1d\x6c\xbf\x61\x10\x4c\x20\x51\x16\xc7\x60\xa0\x2c\x0e\x32\x52\x16\x87\x48\x82\xc1\xa9\xe5\x0d\xb0\xa2\x7c\xd8\x98\x29\x2a\x9d\xa1\x18\x32\x20\x3b\xd3\x51\x50\xd0\x6b\xd7\x8c\xc2\xd4\xa7\xef\x3c\x7c\x47\x9e\xce\x05\x18\x49\xb7\xe7\x0c\x73\xc8\x34\x3b\xc9\xcc\x4e\x1a\x84\xe6\x4f\xcf\xd5\x03\x82\x67\x97\x3b\x98\x5f\xac\xb4\x6f\x92\x54\x30\x68\x98\x95\x08\x88\xa5\xed\xa3\x9b\xaa\xd1\xa1\xe5\x91\x71\x25\xa1\x8a\x61\xa5\xfd\x40\x94\x8f\x66\xa3\x7c\xf4\x59\xf4\x5a\x41\x61\xda\x97\xae\xb5\x18\x62\x53\xbf\xfa\x39\x20\x78\x99\x79\x99\xe2\x63\x23\xa4\xa0\x18\xf9\xeb\x05\x57\x5c\x86\x2a\x15\xdc\x5c\x60\xed\x60\xe2\x44\xa2\x57\xa0\x22\x23\x2f\x50\xbb\xee\x41\x32\x32\xd9\xd0\xcb\x68\x63\x0a\x79\x1f\xf8\xe1\xfb\xcc\xbf\x30\xf6\xa5\x5f\xd6\xa2\xbd\x85\x27\xe9\x7a\xb4\x2f\x0f\xb2\xd7\x97\xdf\xd2\x73\xa2\xac\x44\x8c\x14\x79\xdc\x36\xbe\x40\xd4\x17\x6d\x67\x1f\x5a\x7c\x34\x31\x0d\x08\x85\xd8\x49\x66\xc2\x30\x04\x2e\x88\x00\xb6\x4a\x0b\xc8\x0a\x96\x62\xae\x5e\xcf\x82\xda\x39\x91\x44\xa4\x34\x49\x4f\x0c\xaf\xce\x91\x26\x50\x68\x7f\xb6\xb4\x35\x9b\x60\xea\xfc\x81\xaa\x0d\x0d\x09\x83\x28\xcf\x35\xb5\xcb\x1b\x22\xc9\x98\x53\x9e\x3c\x44\xb1\x11\xc1\xe3\x53\xec\x4b\x50\x0a\x29\xb8\xbf\x58\x8d\xe2\x03\x9d\x0f\xca\x3b\x10\xd0\x48\x65\x81\xab\xf6\x39\x1c\xa2\xca\x99\x34\x84\x6b\xe8\x6a\x96\xd9\x34\x5c\xa6\x9b\x3a\xae\x2a\x93\x51\x79\x97\xa6\x4a\x24\x1a\x03\x1a\xa5\x60\x81\x5f\xb0\x3a\x7c\xa1\x24\x65\x79\x39\x12\xc2\x78\x14\x6c\xe6\x55\x2b\xc5\x6e\xb9\xda\xba\x9c\x4c\x53\x60\x34\xed\xe5\x5f\xa5\x7f\x68\x39\x49\x23\x93\xab\xcb\x65\x63\x95\xd5\x24\x46\x1b\xfd\xc5\x87\xea\xc4\xd4\x85\xd1\xf6\xe9\x1f\x3d\xf7\xc3\x53\xe7\xaf\x77\x4c\xf4\x88\x8f\x3f\xd4\xdb\xb0\xbb\x23\x65\xf5\xa2\x58\x48\x2e\x3d\x72\xe6\x9e\xf0\xcf\x4f\x3f\x63\x8e\x9d\x3a\x74\xff\xd0\xec\xf3\x7f\xbd\xf4\xd2\xd8\x74\xcd\xf6\xa1\x4d\x2d\x43\x89\xdc\x26\x7f\xb2\xad\x81\xa9\xa8\xdb\x42\xc6\x3a\x45\x62\x0f\x43\x0f\x94\x40\x0a\x76\x15\x71\x94\x97\x8c\x35\xca\x69\x79\x2b\x19\x6b\x92\x5d\x1d\x60\xa9\x4d\x23\x32\xca\xfa\x69\xd9\x59\x35\x12\x55\x97\x4d\x1f\x62\x29\x19\x62\x40\xc1\x2c\x8f\x83\x0a\xae\x16\xe6\xad\xde\xa8\x3e\xce\x64\x94\x17\xf2\xae\x80\x49\x29\xe2\x53\x1f\x41\xa7\xb7\xe7\x52\xaa\x13\x26\x0f\x75\x8e\xb7\xe7\x00\x8d\x53\xcf\x05\x52\x4f\x75\x77\x9d\xda\xdf\xd8\xfa\xe0\xd7\xb6\xf7\x3d\x26\xc9\x39\x4b\x49\x32\x9a\x68\x08\x26\x47\x7a\x73\xdf\x78\x4c\x7e\x28\x58\x6a\xe8\xe1\xac\x1e\xfb\xd2\x2f\x3a\x77\xd6\x4f\x2e\x4c\x1e\xbb\x3e\xdd\xd8\xd5\x3a\x85\xfe\xa5\xef\x68\x77\x46\xf0\x3a\x2b\xba\x66\xf7\x5c\xff\xcb\xed\x8d\x0d\x54\xbe\xc6\xc9\x38\xd9\xeb\x10\x23\xf1\x44\x18\x74\xd4\x92\x37\x90\x01\xba\xc9\x00\xab\x56\xc3\xce\x38\xcd\x59\x96\xf1\xc2\x82\x19\x2c\xe5\xa1\xdb\x70\x18\x89\x92\xeb\x6a\x50\xa2\xfa\x0e\x22\xce\x54\x59\xc3\x8c\x6f\x9d\x7e\x7e\xef\xa1\x6b\xca\xfd\x56\xc6\x58\x12\x6f\x9b\xac\x3f\xd8\x93\x4e\xf7\x1d\x6d\x3f\xbd\xb7\xef\xd4\xeb\xa3\xdf\x9e\xde\x8a\x7e\xbc\xef\x85\x99\xed\x83\x3d\x93\x46\x57\x69\x55\x58\x49\x0f\xce\x74\x77\xcf\x8d\xe4\x1e\x1a\x3d\x87\x3a\x66\x89\x69\x1b\x5c\xfe\x98\x3d\x6f\xe8\x81\x20\x64\x60\x04\xf2\x3c\x59\x87\x00\xe9\x66\x98\x2d\x76\xb3\xc6\xa8\xe5\x0d\x35\xd4\x56\x58\x2c\xe2\x4a\x62\xa1\xdc\xad\xe1\x72\x37\x4d\x56\xf3\xd5\x99\x8c\xea\x70\x6a\xaa\xd5\x43\x90\x17\xcd\x30\x98\xcb\x09\x56\x0f\xd0\x7a\x9d\x30\x2f\xe4\xc1\x6b\xbe\x8d\x63\xf4\x07\x68\xb0\xe0\xf1\x06\x62\xd5\x0d\x68\x25\x8b\x50\x94\x36\x1d\xc9\x20\xba\x1a\x83\x6d\x87\xbf\xb6\x6d\xe4\xd1\xd8\xd3\x3e\xc6\x7a\xce\x9c\xba\xd8\xdd\x75\x62\x5f\xe3\x63\x73\xb3\xe1\xad\x8d\x69\x7b\xc0\x51\x96\x0c\xc7\x9b\x42\xf5\xbd\xc9\x7e\xf4\xce\xcc\xb5\x89\x0d\xfd\x1d\x8c\x6c\x0f\x3b\x3f\x6b\x48\xc7\x4b\x53\xdd\x5d\x83\x0d\x53\xd7\xcf\xe3\x9f\xfa\x53\x8d\xd5\x1d\x53\x5d\xfb\x3a\x24\x4f\xc0\x1f\x8d\x77\x17\x75\xed\x63\xf6\x0c\xfb\x32\x94\xc3\x1a\x18\x85\x7c\x09\x65\xfb\x0c\xc5\x21\x57\x9b\xb4\x85\x90\xb3\xc4\xe0\x10\xd5\x10\x01\x6c\xc9\x95\x72\x19\x1c\xca\x60\xa7\x5b\x8d\x16\xa3\x92\xb5\x48\x54\xa3\x4e\x5e\xc8\x1b\x3c\x25\x8a\x42\xf0\xb4\x4a\xe0\x34\xa8\x4e\x0f\x2f\xd0\x4b\x1c\xe2\x7f\x2d\x4e\x31\x9a\xa2\x24\x40\x2e\x72\xa9\xb9\x68\xed\x4a\x36\x6f\xb4\x75\xe2\x9b\x03\x1d\xa7\xee\x6f\x62\x98\xa5\xbd\x5c\xfd\xc0\xa1\xdc\xd9\x5d\x3d\x47\x7f\x34\xf6\xec\xd1\x96\xc7\x19\x86\x49\xb4\xf4\xcb\xc3\x17\xd1\x8f\x8e\xbe\x38\xbd\x39\xfb\xc0\xd5\x71\x77\x8c\x1f\x39\xde\x13\xbb\xbf\xfb\x4c\xd3\xd4\xb5\x9f\x98\x5d\x56\x79\xb0\x35\x79\x12\x10\xcc\x50\xbe\x74\x08\x42\x04\x31\x97\x13\x3f\x09\x12\x2e\x95\x55\x44\xab\x03\x31\x2f\xa9\x66\x83\x96\xe7\xcd\x64\x4d\x79\x9b\x45\xcf\x57\x94\xd3\x82\x96\xa0\x4b\xc3\xfe\x4c\x3e\x48\x8b\x41\x83\xa5\x16\x31\x5f\x1e\x24\x97\xe5\x04\x98\x85\x89\x84\xf2\xa8\x48\xae\x7a\xb2\xb2\x8e\x36\x03\xa6\xca\x15\x12\x27\x84\x74\xd0\x36\xf3\x7a\xee\xfe\xdf\xeb\xca\x1f\xdc\xe2\x46\x5c\xf4\x81\xe6\x6c\x57\x43\x18\xc9\x85\x37\x4e\x33\x8b\x13\x83\x07\x9f\x1c\x4a\xcd\xcc\x45\xcd\x52\x7d\x45\xdb\xd1\xbe\x6d\x13\x4b\x1c\xb3\xa8\xd7\x3b\x76\x15\x2e\xb1\x6f\xb0\x3f\x84\x0d\xb0\x03\xee\x83\x3f\x87\xbc\x13\x81\x88\x05\x59\xfd\xa2\x41\x53\xbd\x81\x4c\x06\xd7\x4a\x6a\xa3\x49\xc3\xdb\x24\x75\x2d\xab\xe1\x88\xa4\xde\x43\x96\x67\x58\xc2\x96\x9b\x6a\xa7\x53\xc3\x10\xb9\xc9\xab\x8a\x53\xc3\x9d\x6e\x5c\x45\xae\x39\x07\x75\x7d\x55\x0e\x72\x4b\xed\x43\xa2\x1a\x74\x6a\xf3\x9b\x83\x7d\x66\x51\x95\x9c\x9a\xba\x0b\x89\x6a\xa7\x45\x27\x75\xaa\x38\xea\x67\x71\x1f\xff\x9d\x88\x73\x6d\x6d\x63\x6b\xc7\x3d\x34\x6d\x2b\xa8\x6e\x5a\xf7\xb8\xad\x91\x17\xf2\x12\x28\x64\xa5\xd7\xf2\x2a\xd3\xa1\x28\x38\x22\xa8\x5c\x95\xa2\xe0\x7b\x78\xd5\x58\xa9\x28\xf8\x8b\x82\x6a\x09\x92\xe5\x0e\xd4\xe6\xaa\xb3\xb5\xab\x09\xc6\x40\x5d\x3d\x0a\x90\x39\x32\xf9\x75\xeb\x93\x30\xfa\x28\x89\xfe\x9b\x72\xbb\x54\xf8\x89\x81\x32\x7a\x6e\x0f\xb6\x8c\x26\x27\xea\x7a\x72\xc7\xfe\x96\xed\xca\xf0\x74\xcb\x89\x81\x91\xaf\x96\x79\x9c\x41\xe7\x40\xbb\x94\xfd\xd2\x57\xda\x94\xc6\xcd\x77\xb7\x25\xba\x63\x83\xc7\x7b\x92\xd9\x03\x97\x1f\x38\x72\x79\x44\x9e\x93\xba\x0f\xd6\x4f\x3f\xc3\xf5\x7e\xd1\xea\xb5\x76\x4d\x49\x13\xa9\x68\xae\x33\x29\x76\x28\xd1\xa8\xd2\x99\xfc\x42\x43\xb8\x7c\xf6\xd0\x70\xf5\xce\x81\x7e\x71\xae\xb3\xed\xcb\x03\xb5\x03\xbd\x93\x0c\x93\x6a\xef\x6b\x79\xb8\xbf\x36\xd0\x28\x56\x25\x8c\xb1\xa6\xbe\x4c\x6e\x5f\xb7\x14\x6b\xe8\xee\x49\xe6\x62\xfc\x40\x67\xae\x91\x31\x72\x2d\xcc\xe3\xc9\xce\x5c\x34\xaa\x74\x24\x93\x9d\x4a\x14\x35\x84\xb7\x03\x82\x33\x00\xec\x51\x43\x0f\x84\x08\xf6\xa5\xf8\x4c\x90\xf3\x76\xa2\x50\x01\x62\xea\x2a\xa8\x16\x85\x6c\x94\x38\x0c\x51\xf4\x11\x32\x58\x44\x1c\x72\xab\x1e\x82\xce\xdd\x1a\xcd\x88\x79\x42\xbc\x40\x23\xb4\x00\xb1\xed\x96\x22\x99\xa3\xc3\xf4\xa2\xfd\xe6\x63\x7c\xad\x6e\x0c\xf9\x33\xcf\x32\x02\x97\xbb\xd2\xd7\x74\x7f\x57\xf2\xeb\xa3\xed\xd2\x50\xbf\x64\xe8\x61\x18\x63\xc0\xbd\xf4\x7e\xdf\x98\x38\x74\xee\xc0\xd2\x6b\x8c\x7c\xee\x68\x72\xfb\x81\xad\x4b\x1f\xea\xf9\x84\x37\x00\x58\xd1\xd0\x04\x16\x28\x21\x11\x1a\x45\x61\x44\x37\x4c\x19\x5d\xfd\x39\x83\x86\xfd\x92\xea\xb4\x6a\xb4\x52\x8e\xb9\xa9\x9a\x6c\x5a\xde\x44\x19\x37\x93\xc5\x22\xe6\x19\xd3\x2a\xdd\xc6\xb8\xe7\xbd\x8c\xd5\x29\xaa\x1e\x3b\x2d\xa6\x53\x4d\x0c\x2f\xe4\x9d\x6e\xbf\x9e\xca\x93\x75\x12\x8e\x97\x7d\xa8\x36\x57\x27\x67\xf4\xfa\xf3\x58\x65\xf5\x1b\xff\xfc\x01\x3a\xfa\x76\x61\xa2\xa2\x22\x89\x18\xb1\xb9\x59\x14\x1b\x8e\x32\xd7\x8f\x2e\xbe\x79\x94\xfb\x2f\x62\x45\x45\x93\x28\x36\x34\xd0\xda\x90\xc2\x45\xd6\x6b\x68\x82\x12\x48\x40\x1f\xe4\xdd\xa8\x48\xce\x05\x24\xd5\xcc\x6a\x38\x2e\xa9\x21\xd2\xcd\x35\x94\xa7\x13\x6c\x5a\xde\x21\xac\x90\x73\xd8\xe1\x9e\xf7\x3a\x4a\x9d\xa2\x5a\x69\xd7\xd4\x24\x99\x62\x07\x2f\xa8\xa1\x38\xcd\x03\x99\x57\x39\xbb\x40\xae\x82\x0d\xf8\x49\xdf\xea\xb2\x14\x7e\xd1\x2c\xef\xe7\xfa\x3b\xb2\xcb\xca\xd8\xe3\xa2\x98\x66\x98\xc1\xa3\x85\x67\xd0\xbf\x6e\x1c\x9d\xeb\x5a\x40\x0f\x85\x2b\x44\x06\x89\x4d\x4d\xa2\xd8\xfc\xfe\x31\xab\xaf\xb4\x22\xe0\x9f\x3e\xcd\x5a\x27\x17\x8f\xef\x3f\x3f\x24\x71\x46\x25\x15\xae\x68\x48\x91\xc1\x20\x98\x5b\xfe\x84\xfd\x89\xa1\x07\xdc\x2b\xd8\x17\xdb\xe5\xbc\x09\x81\xb8\x4a\xe8\xd9\x74\x42\xcf\x57\x24\xf4\x4c\xff\x0e\xa1\x37\x77\x55\x40\x3f\x91\x1a\xb2\x85\xa3\xe8\xf5\x97\x0b\x33\x53\x86\x1e\x7b\xc8\xbe\xf8\x0e\xca\x5b\x0b\xa7\x97\x7e\x64\x46\xef\x8c\x17\x9e\x2e\xd6\x2e\x0c\x19\x7a\xc0\x02\x9b\xee\x58\x69\x8a\xef\x0c\x3a\x93\xfe\xef\x2d\xf0\x0a\x97\x9e\x2d\x22\x53\xdf\x65\xe4\x2d\x7c\x82\x9e\x46\xc2\x51\x6e\xf4\xe8\x67\xf1\xa3\x80\xa0\x0b\x80\x7d\x85\x7d\x19\x92\xb0\x6f\x25\x6f\x14\x91\xe5\x3c\x42\x20\xe6\x8d\x88\x0e\x53\x8d\x9b\x34\x5c\x96\x59\xc9\xb6\x24\x9d\x1a\x66\x32\x38\xa9\xbb\x92\x88\x5e\xc6\xe0\x25\xc2\xef\xa4\x69\x18\x35\x9a\xd4\x6d\x51\x84\xc7\x16\x05\x7b\x75\x85\x88\x53\xc2\xcd\xb2\x02\x68\x74\x02\x9d\x96\x8b\xf8\x4d\x5e\xaa\x14\xc5\x5c\x5d\x51\x3f\x8c\x3e\xbe\x6b\x2e\x3a\xb6\xb1\x7e\xd0\x1e\x1c\xdf\x32\x5c\xb3\x16\x7d\xd5\x1e\x2a\x0f\x04\xb3\xc9\x92\x13\x62\x5d\x7a\x90\xbd\x3a\x28\x37\xdd\xb5\xa9\xa1\xb3\xb5\x69\xd0\x6c\x5e\x4a\x33\x17\x9a\x3a\x12\x56\xb1\xa5\x37\xb1\x74\x9e\x39\x35\xd1\x35\xb1\x6f\xe9\x0c\xc1\x30\xa7\x00\xd8\x09\xf6\x65\x08\xac\xe4\x42\x28\x17\xbb\x32\x3a\x95\x27\xca\x5d\xa2\x67\x91\x6c\x74\x5c\x01\x37\x09\xc5\x54\xbb\x5b\x53\x4b\x91\xa8\x3a\x02\x74\x30\xa0\xf2\x2b\xd5\x21\x2b\xdd\xbf\x53\x97\x4f\x5d\xc8\x5e\xe9\x6b\x38\xd0\x25\x12\x45\x1e\xe9\x96\xd9\xab\x57\xee\x50\xe1\x1d\x07\xb6\x2c\x7d\x08\x0c\xf4\x2c\x7f\xc4\x3e\xcf\xbe\x04\x1e\x48\xdc\xe2\x10\x57\xe0\x4a\x8c\xd5\xd5\x01\x6e\xaa\x5e\xe1\x0e\x0e\x31\x79\x27\x87\x18\xfb\xf7\x38\xc4\xdb\x39\x2e\x27\xd3\xd3\xfe\xe5\x4b\x7d\x7d\x4f\x3d\xd4\xba\x79\xfc\x62\xff\xc0\xd3\x8f\xb4\x5d\x4c\xed\xd8\x4b\x99\x01\xa9\x6b\x4f\x2e\xb7\x67\x47\x0a\xbd\xb9\xef\xcf\x66\x76\x6c\x39\x76\xed\xc8\xf8\xc2\x4c\x6b\xc7\xcc\xc2\x91\x9e\xb9\x91\xba\xf5\x83\x73\x7d\xfd\x27\x86\xd2\xe9\xa1\xe3\x14\xf3\x16\x9e\x65\x17\xd8\x97\xc0\x0b\x71\xb8\x17\xf2\x6e\x9a\x71\xe1\xb4\xdb\xa6\x32\xc2\x6a\x18\x24\x9a\x6e\x41\x3a\x2a\x64\x3c\x7a\x32\x22\x84\x44\xd5\x26\x68\x34\xcb\x12\xf2\x11\xb5\x70\x93\x41\x44\x4a\x78\x21\x6f\xf3\xb0\x3a\xb8\xba\x35\xab\x45\x84\xcb\xb3\xb7\x4a\x19\xc9\x14\x4f\x3d\x21\x3d\xdd\xdd\x75\xfa\x60\xd3\x96\x43\xa7\x3b\xfa\xce\xad\x67\xb8\xdf\x1b\x96\xc7\xfa\x6a\xcf\xcf\x25\xfb\x5a\xc5\xc2\xb3\x5c\xe1\x4c\xe7\x6f\xd5\x1f\x5d\x98\x9a\x7a\x69\xba\xb9\xab\xad\x20\x31\x6f\x5f\x98\x8d\x76\xcf\xee\x5e\xf8\x01\x57\xde\x36\xd1\xa7\xdb\xcf\xbe\xc2\xb3\xec\x09\xf6\x15\xf0\xe9\xe3\x20\x98\x51\x0d\xb2\x3a\x6c\xd7\x17\x21\x6a\xd4\xb0\x43\x5a\x49\x1b\xf9\x6d\xb4\x3a\x9e\x88\x84\xa5\x22\x93\xa1\x72\x41\xc6\xe1\xf0\x93\xc5\xe0\xc9\x38\xa2\x41\x02\x12\x2d\xce\xdb\x40\x62\xc0\xef\x23\xc6\x93\xbf\xa3\xc8\x24\xab\xcb\x4a\x5f\xcb\xe1\xf3\xbd\xcf\xf5\x38\x4f\x9d\x13\x2f\xf6\x77\x9f\xbe\xbf\xfe\xbc\xb8\x7d\x57\x6e\xe2\xf8\xa9\x89\xec\x7d\xdb\x44\xf4\xee\x91\xfc\x74\xcb\x49\x2f\x77\xe2\x33\x06\x7d\xdc\x35\xb8\x6d\xf6\xcf\xbe\x32\x70\x7a\x44\xc6\x7f\xf9\xda\xd3\x62\xdf\x71\x8a\xcb\x5f\x5f\x2e\xb0\xcf\xb2\x2f\x83\x17\x94\x15\x16\x77\x75\x15\x28\x99\xe8\xd3\x45\x88\x0a\xb4\xea\x27\xd6\xc8\xb9\xa2\x7e\x18\xf1\xd8\x4c\x53\x8c\xb2\xa9\x58\xad\xc5\xea\x12\xfc\xfa\x93\x9c\xf8\xdd\xfd\x17\x46\x5a\x03\x55\xa2\x1c\x6f\x7d\xa4\xbf\x8e\x61\x9f\x5d\x18\xd9\x37\x76\x3a\xbc\x26\xe4\x6e\xda\xf7\xd5\xed\x85\x9c\xce\x03\x4c\x2c\x7f\xcc\x1e\x67\x5f\x06\x05\x86\x21\xbf\x81\x72\x36\x46\x2d\x1f\x2a\xa2\x4f\x84\x37\x4a\xb8\xe4\xa6\x2a\xda\x34\x2c\xba\x29\xf9\x2e\xdb\x34\xb5\x1e\x89\xaa\x58\xb2\xc2\x11\x3a\xf9\x17\x2c\x42\xa8\x7a\xfd\x06\x82\x52\x64\x21\x1f\xae\x4c\x53\x2a\xb7\xda\x42\x59\xc2\x92\x70\x44\x5e\x61\x09\xd9\x5b\x51\x4e\xa2\x7a\x95\x26\xbc\xad\xca\x4c\xa7\x09\x8b\xf5\x4f\x13\xbd\x46\xae\x74\x73\x6b\xf8\xae\x44\xb2\xb7\x35\xb9\x7b\x76\x20\xd4\xb1\x39\x1b\xcd\xee\x3a\xde\xf5\xd3\xe3\x7d\x56\xc4\xc5\xe7\xfa\x12\xdb\x36\x44\x4a\xea\x86\xbb\xf0\xd9\xec\xde\x33\x03\x1f\x1f\x3b\x67\x2c\x8b\x4b\x21\xa7\xc3\x97\xc8\xc5\xb2\x1d\x89\xa0\x35\xb4\x76\x53\x67\x2a\x3d\xb0\x55\x3c\x37\xc3\x84\x8c\x52\xb7\x27\x52\x1b\x29\x4d\xc4\xe3\x7e\x69\x66\xa8\xe1\x50\x8f\x44\xe6\xe0\xcc\xf2\xcf\xd9\xd3\xdc\x4b\x10\x81\x8b\xa0\x07\x1d\x82\x59\xd7\x06\x95\x31\xcb\xb2\x0a\x46\x4d\xb5\x45\x32\x19\x84\xa3\x12\x0e\xea\x55\xd0\x4e\x0a\x47\x9d\x56\x8b\x98\x0f\x3a\x29\x48\x25\x46\xba\xb2\x58\x74\xf8\xee\x67\xff\x48\xa9\xac\x48\x8d\x13\xb3\x37\x0c\xaa\xcd\xf2\x2b\x27\x36\xdd\x30\xe0\x88\x7b\x9e\x89\xb0\x1e\x11\xdb\xdc\xf3\x66\x9b\xc9\x23\xb2\xa0\xb2\xa6\x9a\x1a\xf4\x02\xc3\x9a\xcc\xb6\xc8\xad\xdd\x3d\xaa\x40\xac\x95\x4f\xc1\xc0\xab\x5e\x0a\xe5\x3c\x59\xb9\x09\x79\x8d\x2e\x82\x6d\x8d\xb7\xd5\x41\x24\xaa\xb3\xb5\xd9\xda\xba\xdc\x99\xbf\x73\x5f\xb6\x32\xa5\x04\xe0\x0a\xe6\xd8\xe6\xdc\xd0\x78\xea\xf4\xf9\xaf\xb7\x36\x9a\xed\xac\x34\xf9\x69\x99\x10\x32\xbf\x33\x79\xed\xd2\xc8\x5c\x97\xd8\x3b\xb1\x6f\x67\xcf\x9f\xba\xdd\x1d\xff\xed\x1b\x64\xfc\xc7\x96\x35\xf6\x38\x7b\x15\x2a\x88\x5d\xf5\x10\x19\x2c\xa3\x85\xae\x06\x7d\x12\xb0\x73\x95\xd0\x64\x6d\x1a\x66\xdd\x44\x0c\xb1\x23\x43\xdc\x24\xe5\x33\xfd\xec\x0a\x9f\x69\xa6\x51\xf0\xfa\x74\x10\xc9\x3c\xe9\x60\x91\xca\x0c\xc4\x6a\x50\x53\x31\xbe\x3a\xc6\x9c\x8b\x6e\xda\x91\x4a\x7f\x71\x5b\xf2\xbc\xf5\x22\xc3\x31\x4c\xea\xc9\xc1\xf6\xf1\x41\x09\x3d\xcd\x58\x97\x7e\x39\x30\xd9\x11\xe5\x92\x9d\x47\x7b\x19\x6e\xf1\x39\x29\xee\x8c\x05\xb6\x75\xf5\xd7\xee\x7f\x86\xd6\xf4\x2c\x7f\xca\x5e\x65\xaf\x02\x0f\x51\xdd\x6a\xe5\x01\x51\x1a\x1e\x61\x41\x22\xd8\x0d\x54\x70\x17\xd3\xee\x1e\xe2\xa6\xbd\x01\xe4\x69\x44\x39\xd9\x68\x62\x63\xa8\x07\x1b\x19\xe4\xbc\x90\x6e\xe0\x8f\x27\x47\xff\xfe\xa1\xc2\x1f\xb2\x57\x9d\x01\x33\xc7\x2c\xf5\xa2\xc1\x23\x37\x7a\x9e\xfb\xf9\xd2\xc7\xec\x14\xd5\x89\xe8\x72\x81\x7d\x8b\xbd\x0a\xa5\xf0\xb1\x9e\x8f\xcc\xfb\xfc\x25\xb2\x2c\xeb\xcd\xf1\x32\x4d\xaa\xf0\x37\xb1\x33\xa3\x0a\x4e\x4d\x0d\xea\x8b\xde\xb8\xe1\xbf\x33\xb7\x55\x9a\xaa\xe6\xd2\x5f\x61\xcb\x8d\xeb\xaf\x5e\xfb\xd9\x39\x9d\xa3\xf4\xd7\xa8\x25\x01\x33\x0e\xdc\x70\xaa\x36\xc7\xaf\xb0\xf5\xc6\xf5\xa6\xce\x5f\x9e\xd6\xb7\xa7\x39\x6b\x54\xab\xcd\x8c\x6d\x37\x9c\xaa\xa7\xec\x57\x06\xec\xbb\x71\xbd\x69\xf8\xdf\x3c\xe0\x13\x6d\x44\x54\xec\x36\xa7\x47\x9c\x77\x90\x67\xec\x73\xcf\x7b\x7d\x1e\x8f\x98\xb7\xdb\x9c\x91\x93\x91\x93\x31\xa3\x93\x17\x14\xec\x50\xf2\x5e\x9f\x87\x17\x14\x68\xb6\x9a\x2d\x56\x5b\xc0\xee\x70\x7a\xbc\xb7\x76\x8c\xa1\x66\x3b\xb9\xed\xf3\x07\x4a\xec\x8e\xdb\x3f\xd0\xd9\x50\xca\x82\xfa\xe8\x9c\x05\x91\xec\x69\x64\x1b\x90\x6c\x64\x4c\x31\x1b\x8a\x45\x9f\x30\x33\x27\x2e\x0d\xfc\x30\x58\xe9\x31\x9e\x08\xdf\xb5\xfe\xd4\x73\xcf\x1c\x67\xaf\x9a\xed\x61\x97\x99\x5b\x1a\x62\x2e\x2c\xed\x5f\xf8\xc7\xa7\x46\xe5\xf0\xcf\x0b\x29\x8d\x19\x5a\xba\x4c\xe7\x70\x18\x80\xbd\xc2\x5e\xfd\x1c\x47\x8a\xfe\x7d\x8e\x34\x48\x39\x52\xc4\x0e\xa3\x8e\xc2\x4b\x97\x7f\xa1\x5d\x28\xfc\x08\xf5\x5f\x2d\x14\x7e\x81\xde\x46\x6f\x14\xae\xa0\x81\x82\x52\x08\xa3\x83\x85\x73\xba\xed\x4a\x15\x2e\xb2\x0b\xec\x55\x88\x13\x4c\x45\x10\x29\x0e\xca\xb8\x4a\x52\xad\x46\xbd\x52\x20\x78\x53\x2d\x2f\xba\xaa\xf2\x20\x2f\xe0\x0a\x05\x54\x6b\x15\x2f\x60\x50\xb0\x9b\xcf\xa3\x40\x85\x6e\xe6\x73\x15\x28\xb0\x3e\x40\xed\x7a\x13\x42\x89\xdb\x25\xc7\x89\x4c\xac\x89\x08\x6e\xaa\xcb\x68\x66\x2c\xe6\xb2\x64\x69\xfd\x60\x2a\x54\xb8\x14\xbc\x66\xe6\x90\x27\x1f\x8c\xd8\x9e\x14\xc4\x70\x21\x91\x7e\x6a\xf4\x78\xe1\xe3\x59\x63\x90\xb3\x5a\x04\xbe\x63\xb8\x8d\x1d\x69\x71\x07\xac\x66\xc3\x52\x37\xfa\x65\xfb\xb4\x9c\x9d\xeb\x59\x1a\x19\x3b\x71\x64\x85\x7b\x7d\x8a\xbd\xfa\x1b\xb8\x57\xf4\x7f\xca\xbd\xb6\x2e\x7d\xc4\xfc\x74\xe9\x87\x8c\xe8\x8c\xb9\x46\x99\xef\xcd\x8c\x2e\xd5\x53\xee\x15\x0e\x16\xae\xb3\xad\x86\x52\xa8\x84\xfb\x00\x97\x4a\xaa\xdf\xa0\xd1\x42\x3a\x83\x86\x6d\x34\xee\x46\x38\x26\xe1\xf0\x4d\x82\x73\x05\x97\x86\x1d\x99\xbc\x40\x6b\x28\x04\x8b\x45\xc4\x81\x4c\x3e\x4c\xf1\x7b\x98\x58\xb5\x2a\xaa\x59\xc4\x49\x0a\x15\xba\xd7\x71\x2b\xd8\xb6\x82\x88\x3d\x59\xe2\x0f\x13\xee\xb8\xec\x8b\x55\x9a\x02\x5e\x93\x9f\x37\x79\xfd\xf5\xc8\x47\x1c\x7f\x75\x36\x57\x5b\x1d\x3b\x58\x3d\xb4\x8b\x43\x13\x33\x57\x5f\x46\x5c\xfe\x79\xe3\xe4\x89\xfb\x3b\x46\x9e\x6e\x7e\xc8\x3c\xdc\x8f\x7e\x3c\x3e\x36\x71\x0e\x8d\xa2\x89\xb7\x1e\xfb\xa0\x53\x29\x2c\x3e\x77\xea\xc0\xb8\x4b\x1a\x78\xf3\x8d\xb9\x21\xba\x1f\xe5\xa5\xc2\xeb\x4c\x9b\x21\x47\x79\x51\x84\x39\xdd\x0a\x39\x35\xfa\xd0\x79\x51\xc4\xcb\x3c\x7a\xe9\x64\xe1\x75\xe3\x03\xbf\x7a\x9c\xca\xc5\x4b\x85\xeb\xec\x79\x43\x29\xac\x81\x01\x20\x01\x54\xc0\xa0\x61\xa7\xa4\xda\x56\xa7\x80\x32\x29\x91\x9b\xb8\x8a\x72\x94\x24\xde\x8a\xf0\x64\xb4\x11\x64\x11\xb1\x3f\xa3\xae\xa5\x6e\x36\x40\x06\x1c\x51\x14\x6c\xe3\x71\xa5\x82\x41\x50\x4d\x55\xfa\xf0\xb9\xe2\xb0\x2b\x18\xdf\xca\x50\x8d\xbe\x80\xd7\xb8\x52\x3e\x45\xa6\x23\xa7\x0f\xfd\xa5\xe6\xb6\x6f\xce\xf6\x1a\x47\xbe\x94\x5c\xd7\x3f\x64\xfc\x23\xf5\xea\x91\x54\x2e\x16\xb0\xf6\x1a\x9f\xcb\x1b\xf7\xee\xe3\x9e\x99\xb0\xdd\xf5\xd8\xf4\xb9\x89\xb1\xf1\xa1\xb9\x37\xae\xa9\xe3\x9c\xd5\x61\xae\xbf\xf0\x1c\x62\xea\x3b\x3f\x78\x6c\x62\x54\x97\xf3\x5e\xe6\x02\xfb\x26\x7b\x0d\x4a\xa0\x16\xf2\x2c\x91\x11\xbf\x51\xa3\xf4\x09\x47\x23\x43\xba\x79\x4a\x35\xf3\x94\xdf\x2a\x51\x14\x45\x65\xfd\xbc\x90\x37\xda\xec\xba\x7c\xeb\x00\xdd\x9f\x5b\xa9\x92\xaa\x4e\x54\xc7\x2a\x4d\xbd\xe9\xf3\x5b\xdb\x47\xc3\xbd\x39\xa5\xab\x76\xa8\x74\x73\x5b\x47\x55\xdb\x48\xa8\xb3\x73\xb0\x8b\x85\xee\x31\x29\xd4\x85\x36\xb7\x76\xc5\xdb\xe4\x0a\xb9\xa2\x87\xd6\x04\xdd\xb9\x2f\xba\x45\x67\x74\xf2\x02\x51\x3b\x8b\x74\xe7\xfe\x68\xec\xc8\x2c\x18\xf5\xda\xd2\x52\xbb\xb6\x72\x19\x29\xf2\xa4\x14\xbb\xd0\xcd\x5e\x75\x2b\x61\x5d\xa2\xda\x53\x5b\xd7\x84\x3c\xb2\x47\x2f\x47\xab\xac\x46\x47\xb6\x4b\x52\xe7\xf6\x8c\x1c\x8b\xb9\x6e\xed\x87\xde\x28\x49\x0a\xf7\x4e\xba\xa3\x23\x2d\xb5\xc7\xa2\x9f\x69\x81\xa6\xe4\x01\x26\xb7\xf4\x5a\x78\x6b\x7b\xb3\xb7\xbd\xb3\xa7\xb8\x8f\x61\x79\x88\xbd\xc8\x15\x20\x0c\x6b\x60\x09\xf2\x46\x86\x58\x06\x89\x84\xd0\x65\xb2\xea\xe5\x34\x62\x23\x0c\xb7\xf8\x34\xbd\xa0\x9b\x66\x67\xd7\x52\x53\x8e\xab\xcb\x90\x1a\x2c\xaf\x79\x0d\xd4\xf2\x60\xcd\x6b\xd4\xa3\x9f\xfe\xe4\x90\x6e\xc5\xcb\xdd\xd8\x78\xc3\x89\x83\x6e\x6c\xbd\x41\xde\xcd\x1b\xca\x8d\x1e\xf1\x7a\xd3\xc3\xff\xf6\x27\xd4\x5a\x07\xdd\xf3\xb6\xa0\xd5\x23\xce\x7b\xc8\xb3\x61\xde\x4b\xdf\x94\x91\xe7\xeb\x4d\xbf\xfb\x09\x4f\xbf\x54\xee\x9e\x0f\x91\x3f\x9b\x8f\x91\x67\xc3\x7c\x15\x79\xc9\x87\xca\x8d\xb7\x19\xf4\x98\x92\xf7\x04\xad\xe4\xca\xa6\xc0\x82\xd5\xe6\x09\xc5\x8a\x86\xdc\x6a\x30\x5a\x6d\x1e\x6f\x59\x28\x56\xf5\x39\x23\xae\x56\x79\x79\x61\xc1\x01\x4e\x7f\x60\x95\xb7\x6d\x42\x01\x02\x1a\x56\x36\xbe\xb2\x04\x34\x88\xc8\x94\xc8\xd5\xa0\x9c\xd7\x1f\xf0\x38\xd9\x91\xd6\xa3\x57\xc7\x42\x27\xdc\xac\xf7\xe9\xde\x01\x33\x32\xd7\x0f\xde\xf7\xd4\xf8\xf6\xe3\x3f\x76\x87\x1f\x2e\x7f\xea\xda\xd7\x8f\x0c\xf5\xb7\xec\xef\x16\x99\x86\xe1\xff\x38\x73\x97\xe1\x43\xa7\x3d\xec\xba\x1a\xfe\xed\x09\x63\xc2\xdc\x5e\xb6\x54\xfb\xd0\xe8\xd9\xff\xe6\xfa\x48\x2c\xfc\xe8\xcc\x9f\xc7\x99\xef\x73\x75\x03\x5f\xa6\x32\xdb\xbd\xfc\x3e\xfb\x3d\x6e\x11\x1a\x90\x0c\xf9\x06\x00\x71\xbe\xb4\xa1\xce\x29\xe2\x9c\xac\xa6\xcd\x1a\x5e\x9f\xa1\xdb\x5a\xd5\xa0\x41\x53\xeb\x1b\xdc\x91\x1b\x12\xde\x28\xab\xeb\x58\x0d\xa7\x32\x0b\x36\x6b\x83\xc7\x21\xe2\x2a\x99\xaa\x6c\x65\x06\xe1\x46\x9a\xf2\x4a\x38\xb5\x7c\x82\x46\xc4\x89\x2a\x8b\x38\x1f\x49\x98\xcc\xa2\xea\x74\x52\xe5\x26\xb1\x6b\x32\x93\x77\x46\x56\x60\x99\xda\xa4\xbb\xe5\x8f\xaf\xbc\xba\x4c\xdd\xf2\xc6\x1a\xbc\xbe\x06\x6f\x74\xab\x29\xee\x57\x78\xbd\x5b\xcd\x71\xbf\xba\xfe\x33\xc7\xab\xef\xd2\x05\x49\xb9\xe7\x6b\x52\xeb\x3d\xe2\xbc\x44\x9e\xf1\x46\xf7\xfc\x86\x8d\x39\x8f\x38\xaf\x90\xe7\x7c\x4d\x6a\xfd\x6d\x0b\x23\x29\x79\x65\x63\x8e\x5c\x6d\x50\x60\xbe\x46\xda\xa0\xe8\x49\xc6\x54\x8d\xb4\x3e\xb7\x41\xd9\x78\x47\x92\xd1\xe4\xe4\x05\xd5\x62\x57\x14\x35\x11\xe1\x85\x7c\x65\xbc\x9e\x62\xe3\xfa\x06\x5e\xc0\xb5\xb4\x52\x18\x64\x45\xc1\x56\x82\x5a\xd4\xa0\x8d\x17\xb0\x5f\x59\x9f\xce\x35\xb2\xb9\xba\x6c\x6d\x22\x96\x95\xf5\xbd\xa4\xc5\xd5\xd3\x21\x72\x40\xf6\xc5\xfc\x26\x6f\x71\x47\xc6\x2a\x83\x1b\xab\x34\x75\x4b\xd9\x90\xd3\xdc\x1e\x9e\x3b\xe0\x44\x1b\x47\x66\x3b\xbe\x31\x3e\xe0\xb6\x95\xa4\xdb\xc5\xee\xcd\x09\xf7\x1b\x38\x88\xb6\x3b\xe3\x25\xde\x7b\x87\x86\xa2\x9d\x5b\xeb\x0e\xee\x0b\x0d\x1d\xdc\x2f\x0e\x7c\x7d\x34\x10\xf4\x0b\xae\x23\x27\x3a\x7f\x7b\xa2\xad\xa1\xf7\xc4\xae\x2c\xda\x77\xd8\x1d\xb5\x27\x42\x0d\xc3\x2d\x72\xcf\xc4\xf8\xbd\x17\x8f\x32\x4c\x59\x38\xb8\xf1\x40\x5f\x28\x56\x7e\x17\xd5\xb1\x53\xa8\x9b\x9d\xe0\x72\x50\x01\x69\x78\x08\x70\x50\x52\xab\x4c\x1a\x4e\x49\xaa\xdd\xa4\x17\x4d\x73\x37\xd5\x70\x40\xc3\x61\x37\x8d\x77\x3d\x01\xbd\x4e\x3a\xcc\xf1\xc2\x3c\x32\x59\x2a\x48\xac\x90\xe4\xe7\xad\xce\x92\x10\xb9\xf4\x08\xf3\x2e\xde\x17\xa0\x19\x93\xaa\x20\x2f\xcc\xfb\x41\xff\x20\xc5\xcf\x23\x13\xef\x23\x97\x76\x61\xde\x6c\x75\xba\x75\xc1\xa6\x8c\x66\x5d\x2e\x91\x0b\xd4\xc9\x99\x40\x2e\x60\xf2\xfb\xbc\x2b\xfb\x6b\xf5\x84\x0a\x8d\x33\xaa\xf5\x39\x3b\x35\x1e\x2a\x2f\x0f\x4f\x74\x8c\xf7\x8e\x0d\xf7\x8d\x77\x8c\x37\xd4\x1f\xe9\x38\x92\x1c\x4a\x8f\xf5\x1d\x19\x5a\xa1\x22\x51\x43\x43\x6f\x92\xbc\x5e\x78\x38\x39\xb4\x3e\x3d\x94\x9c\xd8\xf6\x50\xbd\x72\x78\xdb\x91\xbe\xb1\xb1\x2f\x1c\x6e\x3f\x12\x0e\x35\x8e\xa3\xf1\x15\xba\xb1\xb7\xa1\x21\xb2\x71\x7b\xb1\x7e\x11\x80\xbd\xce\x15\xa0\x04\xbe\xac\xb3\x00\x2b\xb9\xda\x05\x5e\x70\x81\x43\xc4\x56\x59\xe5\x4d\x1a\xb6\x67\x16\x7c\x7e\x7a\xc3\x28\xab\x3e\x83\x86\xcd\x19\x4a\xec\xb9\x6e\xaa\x9e\x40\x26\x43\xf7\xc1\x1a\x2c\x99\x4c\xde\xe9\xa2\x52\x6c\xb6\x88\x04\x15\xb8\x68\x7c\xe1\xf2\x59\x44\xcc\x67\x28\xb7\xe7\x74\xad\xe4\x7c\xfd\x77\xe4\x7c\x7d\xd1\xe2\xbf\x58\x36\x5a\xfc\xd7\xf1\x2d\x94\x44\xfc\x37\x0a\x17\x91\x50\xf8\x39\x79\x9c\x2a\xbc\x8f\xc2\xe4\xc1\x15\x96\x34\xc6\xb7\x34\x2c\x4e\xcc\x3c\xf4\xda\x6b\x0f\xcd\x4c\x88\xc4\xc6\xdf\xf2\xb7\x26\x08\x41\x31\x4f\x8b\xb9\x0c\x71\xb8\xd8\x98\x51\x4d\x4e\xad\x98\x23\x25\x7e\x97\xd5\x7d\xef\xc9\x93\x85\xd7\x99\x1f\x2c\x6d\x64\xcf\x32\x6f\x2f\xc5\xa9\x7c\x1c\x5f\x3e\xcb\xf6\x1b\x86\xa1\x19\xee\x86\x07\x01\x37\x4a\xaa\xd9\xac\xe1\x35\x92\x1a\x22\xe0\xac\x9b\x46\x95\x29\x9b\x86\x3d\x91\x9b\xbc\xba\xd9\xa6\xe1\x14\x3d\xbc\x01\x6f\xcf\xa8\x8a\x5b\x53\x6b\x05\x4d\xbd\x07\x89\xaa\xcd\xc3\x0b\xdf\x41\xfe\xd0\x9a\x74\xe3\xb6\xbb\x88\x10\x28\x7c\x3e\x5a\x95\x53\x14\x05\xd7\x0a\x38\xa2\x80\xba\xc6\xcc\x0b\xdf\x01\x54\x12\x89\x2a\xf4\x1b\xc5\x38\xd3\x5f\x2c\x9c\x49\xe8\x72\x52\xbd\x5a\x90\x42\xc2\xce\xd5\x48\x93\x96\x4a\x16\x99\xf0\x6a\x8f\xd7\x1f\xa8\x40\x81\xba\x44\x6d\xb5\x84\x9c\xe8\xf8\x01\x3b\x67\x0c\x54\x34\xed\x19\x3d\xe4\xaf\x1b\xda\xfa\xf4\xec\x60\xe7\x09\x79\x60\x6a\xeb\xe8\xb7\xd3\x13\x56\x86\x0b\x67\x5b\xe3\xf1\x2d\xe9\x50\xbc\x7b\xaa\xef\xa5\xde\x2d\xb3\x75\x83\x33\x1d\xfb\xae\x3f\xb4\xe7\x70\x2c\xcb\x77\xa0\xd1\x07\x77\x26\xe5\xa6\x69\xce\xee\x8f\x87\xea\x87\xb6\xc4\x72\xeb\x93\x5e\xf9\xe8\x60\xeb\xe1\x60\xcf\x13\xf5\xf7\x77\x4b\xc3\x7d\x63\x56\x7b\x50\x4e\x94\x94\x88\x1b\x23\xe9\x8d\xb9\x64\x7c\xe0\x4c\xc3\xc1\x60\xff\xa9\xd6\xf1\x7b\xd6\xf7\x33\x3f\x6c\xed\x8f\x58\x5d\xe6\xc4\x60\x6b\x4f\x75\xd8\xd9\x06\x0c\x7c\xc8\xcd\xb2\x51\x43\x0f\xdd\x6f\x92\x03\x6c\x95\x70\x40\x56\x59\x2b\x4d\x74\xb1\xd6\xd5\x3a\x2f\x93\x5d\xa3\x47\x92\x20\x51\xf5\xda\x69\x68\xa2\x43\x48\x96\x96\x39\xdc\xbe\xa1\xe0\x8e\xad\x27\x1f\x36\x8a\xc9\x70\x18\x35\x24\xc5\x46\x74\xa8\x9e\x5c\x37\x26\xc5\x7a\x4e\x4b\x36\x87\xc3\x62\xb2\xa1\x71\x8d\xd8\x48\x2f\xea\x69\x7e\x24\x04\x09\x76\x91\x6b\x00\x01\xaa\xa1\x93\x68\xbf\x53\x5a\x28\xa1\x07\x74\xe0\x76\x49\xdd\x6c\xd2\x70\x4e\x52\xd7\x99\x34\x5c\x29\x15\x0f\xee\x40\xf8\x2e\x9a\x97\xf6\x04\xc0\xcb\x89\xd8\xa3\x6f\x8f\xdd\x14\xd0\xf0\x26\x4a\x29\x2d\x58\xe9\x07\x6a\x17\x12\xd5\xd0\x26\x5e\xb8\x66\x28\xa9\x5c\x27\x6d\x6d\xa7\xf6\x20\xb7\x99\x17\xbe\xe3\x09\x25\x24\x58\xdf\xba\xf5\xce\xb2\x30\xa3\xc9\x98\xf8\x0d\x3c\x59\xe0\xce\x74\x65\xe2\x8e\x32\x71\x1a\x85\x86\xee\xfa\xea\xc2\xd8\xe8\x0b\x73\xdd\xe8\xdc\xd9\x37\xc6\x16\x7e\xff\xae\xc1\xa6\x43\xe7\x7a\x7b\x1e\x7f\xb0\xa5\xf9\xc1\xc7\x7b\x7b\xcf\x1d\x6a\x1a\x4f\xf7\x8c\x66\x0f\x3d\xea\x3d\x60\x66\x8c\x81\x68\xac\x26\xd4\x92\x8b\x87\xe5\xb6\x64\xba\xc7\x3f\x20\xce\x6d\x6f\x7a\xf0\x6e\x89\x49\x1f\x7c\xf9\xb1\x7b\xee\x79\xec\xe5\x83\x6f\x3d\x75\x01\xf5\x9c\xf9\xf3\x07\x06\x2e\x3d\xdc\xda\xf6\xc8\xd3\x03\x03\x4f\x1f\xdd\xba\xe5\xe8\xa5\xfe\xa6\x23\xdd\xd2\xbe\xbe\x84\xd3\xe7\x0f\xfa\xbd\xc8\x27\x6d\xab\x4d\xdd\xbd\x29\x96\x11\x37\xb5\x6c\x97\xfb\xc6\xc9\x5c\x5e\x44\x39\x76\x8c\xfb\x14\x58\xa8\x80\x14\x1c\xd4\x77\xbb\x98\x34\x5c\x2e\xa9\x95\x26\x0d\x27\x25\xd5\x6a\xa2\x0e\xce\x53\xcc\xb3\x13\xbb\xea\xa4\x76\xb5\x94\xe8\x47\x22\x93\x51\x4b\x1c\x7a\x12\x9a\x18\x57\xd5\xcd\x2b\x0a\x2e\xe5\xf3\xce\xf2\x4a\xea\x69\x2a\xcb\x79\x41\x2d\x29\x53\x88\xb9\xc5\x9c\xa2\x3a\xad\xc5\x2f\x15\x37\xd0\xd4\xd6\xe5\x1a\x51\x3d\xca\xd6\xea\x79\xf7\x0a\x14\x42\x7a\xe2\xbd\xba\x98\x09\x6d\xa0\xc4\xcc\x45\xe6\xaf\x97\x0e\xcc\x1c\x6a\xd9\x19\x0d\x5d\x38\xb6\xb9\x6d\xec\xb9\x99\x47\x67\x86\xc6\x8f\x9c\x98\x6d\xdd\x1c\xdc\xda\x98\x8c\xf6\x8d\x6f\x0d\xa1\xdc\xa1\x43\xe8\xf9\xbe\x29\xde\xc8\x94\x5c\x19\xe8\x1d\xe7\x8e\xcd\xf8\x0a\x2d\x5b\xfa\x8f\x0d\x24\xb6\x78\x53\x1d\xb9\xb8\x39\x2c\xd1\x7d\x8d\x30\xcd\x9e\x65\x65\x30\x82\x83\xee\x04\x0a\x98\x90\xa9\xf8\x72\x02\x6d\xb8\xfb\xdf\x90\xb1\x27\x8d\xb2\xdd\x9f\x20\x63\x0f\xfa\xa9\x84\x52\xbd\xff\xbd\xf0\x7e\x0f\x1a\x58\xb9\xa2\x36\xf7\x3a\x6a\x61\xbb\x99\x1f\x82\x01\xd6\xaf\xec\x10\x5a\xd9\x25\xcf\x59\x44\x84\x8d\xfa\x3e\x66\xa7\x96\xe7\x58\xba\x35\x95\x04\x32\xa6\xd5\x9d\xf0\x31\xfe\x3a\x73\x7e\x96\x69\x9b\x29\x4c\x21\xee\xff\x7c\x4f\x3a\x77\x87\x0e\xd4\x42\x3d\x7c\xfb\x76\x2d\x90\xa5\x85\xac\x09\x4a\x39\x31\x2f\x67\x49\xe3\x72\xc2\x22\xe2\x7a\x69\x61\x8d\xfe\xf1\x6d\x6a\xb1\xe9\xd7\xd5\x62\xa1\x56\x7f\x97\xcd\xe0\x5a\x7a\x1e\xca\xc2\x3a\xfd\xc6\xba\x3b\x54\xa5\x01\x89\xea\x86\x5a\x5e\x58\x30\x54\x96\x64\x8a\xbb\x8e\x70\x5a\xc1\x21\x01\xaf\x57\x40\x95\x4b\x78\x41\x5d\x9f\x56\x14\x9c\xe5\xe7\x3d\x20\x51\x67\x5a\x2f\xe0\x75\xff\x1b\xea\xe3\xe1\x75\x5c\x6e\xf2\x98\xd8\x98\x8f\x97\x33\xb9\x5a\x11\xfd\xaf\x35\xe6\x2f\x5f\x39\x7e\x64\x93\x32\x3b\x7c\x6c\x6e\xff\x59\x74\x61\xf4\x7f\xa9\x1d\x85\x59\xa6\x6f\xa4\x53\x1e\x70\x2f\x83\x0b\xc1\x22\xea\x1a\x18\xd0\xfd\xe9\x22\x77\x9c\xe5\xb8\x4f\x80\x85\x4a\x28\x46\x6c\x7a\xd4\xc6\x49\x2a\x20\x71\x81\xb5\x83\x99\x13\x6f\x5b\x96\x45\xc6\xcc\x1d\x1f\x1f\x27\xb2\xf5\x09\xf3\x4b\x36\x6a\x08\x81\x00\x51\x68\x26\x6b\xa2\xfa\x4d\x1a\x0e\x49\xaa\x81\xe8\x4f\xa5\xbe\x7d\xc0\x41\xb7\x0f\x10\xfd\xb1\x38\x34\x35\x46\xe2\x12\x0f\x2f\xa8\x4e\x03\x51\x98\x10\x09\x74\x2d\x70\x07\x01\xfc\x1b\x0e\x36\x71\x32\x9f\xa4\x3a\x47\x73\xe3\xdd\x3d\x62\xe7\xe8\x46\x65\xb4\x53\x9c\xee\x6f\x6a\xe9\x4f\x89\xcd\x61\x25\x59\xc2\x99\x95\xbd\x1d\x62\x4f\xf7\x78\x6e\xb4\x23\x25\x6e\xdf\x53\xdf\x32\xb2\x7b\x73\x8b\x9c\x2e\x5b\x5f\xaf\xc7\x28\x83\x10\x63\xaf\x72\x4f\x81\x0d\x5c\x24\x42\xb7\x4b\xaa\x83\x72\xee\xff\xeb\x43\x1f\xdc\xbf\xf9\xd0\x07\x97\x5e\x81\x5f\x3c\xf7\xc1\xae\x57\x33\xf1\xbf\x76\xf4\x03\xdd\x30\xb7\x72\xfc\x43\xe1\x1b\x6c\x07\xf3\xf2\x34\xba\xaf\xf0\x87\xd3\x85\x63\x68\x66\x69\xcf\xcc\x0c\x20\xf8\x80\x31\xb2\xb2\xa1\x14\x12\xd0\x06\xb4\x98\xd7\xa4\xa9\x5e\x96\x98\x73\x95\x35\xe9\x59\x8d\xf0\x4d\xd5\xec\xd0\xf2\x61\x9a\xbb\x0f\x07\x2c\x22\x41\x79\xa0\xba\x03\xbc\x80\x4b\x14\xb5\x92\x84\x21\x60\x76\x06\x13\x9f\xdf\xea\x66\x72\xa2\xe2\x96\xfd\xa8\xbe\xb7\x5f\x3f\xf9\x84\xdc\xfe\x40\xba\x74\x40\x1e\xea\x10\x7d\xe9\x81\xb6\x6c\x7f\x0c\x4d\x58\x03\x56\xe3\xd2\xf7\x73\x93\x83\x4a\xb6\xb6\xa7\x79\x72\x8b\xd1\xca\x71\x87\xba\x07\x62\x8d\x7d\x72\xb2\xa1\x71\x5b\x6d\x72\x47\x42\x98\x19\xe8\x38\xba\x35\x95\xec\x8d\xc9\x1d\x7d\xe6\xa0\x7e\xee\xc7\x87\x0c\xc3\x36\x19\x82\x20\xc1\x4e\xc0\x35\x12\x3d\xa8\xc8\x2e\x2d\x78\x74\xed\x2b\x95\xd4\x0a\x32\x8a\xf5\x34\x5b\x9f\x74\x68\xd8\x4f\x30\x48\xcc\xa1\xa9\x69\x22\x11\x04\x52\x55\x2b\xa0\xda\x8d\xbc\x30\x0f\x2c\x4a\x52\x7c\xca\xe3\x6a\x05\x97\x0a\xf9\x60\x79\xec\x16\x69\x44\x42\xea\x95\x4d\xfb\xfe\xcc\x4a\x5a\xe0\x37\xec\xda\xff\x70\x97\xd9\x6a\x6d\xed\xef\x3f\xb0\xab\xd7\x1d\x72\x5b\x7d\xd6\xc1\xae\xbe\x96\x89\x1d\x1d\x0f\x3c\x93\xdb\xdd\x91\x6c\x91\x5b\xbe\x20\xf7\x1e\x6e\xc4\xcc\xdc\x01\x6b\xc2\xd2\x8a\xba\x72\xd9\x7a\x86\xb9\x9f\x69\x48\xa5\x3a\x86\x3a\x8f\xc5\x1a\xbb\x53\xb9\x7e\xb7\x75\xcf\xe6\xf4\x17\x36\xc7\xf5\x73\x3a\x2e\x73\x29\xe6\xa7\x86\x0b\xc0\x42\x04\x30\x4b\xeb\xbf\xec\xc4\xa0\x50\x86\x64\x81\xb1\x83\x73\x55\x43\x90\x27\xc0\xa2\xcb\x0b\x33\x6f\x72\xfb\x51\x4d\x5f\xe1\x9f\xe8\x1c\xa5\x0b\xcf\xb2\xbf\x60\xaf\x42\x0a\xf6\xe9\x7b\x6e\x70\x42\x56\xcb\x0c\x5a\xde\x4c\x02\x7a\xbf\x4c\xd3\x3f\x35\x34\xec\xb2\xae\x14\x34\xa4\xf4\x23\x85\xbc\x48\x54\x4b\x9c\xba\xcb\xf1\x5a\x79\x01\x27\x14\x5c\xc2\xe3\x2a\x05\xd4\x28\x0d\xef\xd7\x29\x0a\x2e\xe3\x55\x57\x58\x51\xb0\x59\xc8\x57\x54\xad\x5d\x49\xa7\x70\x94\x0e\xa6\x35\xae\x0d\x88\x32\xc3\x99\xba\x26\x14\x30\x26\x2a\xab\x29\x72\xaf\x4e\x94\x23\x53\xda\x68\xb3\x9a\x8d\x73\xd1\x5c\x7b\x22\xd1\x51\x1f\x9b\xed\x09\xd5\xdb\xed\x1b\x3a\xef\x6f\xf9\x92\x39\xf6\xe8\x8e\xce\x99\x10\x53\x78\x36\xf4\xd0\x63\xdf\x7a\x7c\x3a\xce\x58\x97\x7e\xd2\x77\x70\x73\x88\xe3\x62\xad\xfb\x3b\x04\x26\xbc\xd4\x76\x1a\xa5\x83\xa5\xf7\x1f\x41\x83\x9b\xbb\xef\xda\xd6\x3e\xf1\xd1\x84\x6e\x53\x66\x97\x27\xd8\x69\x43\x0f\xf0\xc4\x2a\x58\x69\xfc\x9f\xb7\x1a\x56\x75\xc5\x94\x41\x58\x90\xb0\xfd\xa6\x6a\x0b\x68\xd8\x46\x8f\x72\xb3\xd0\xa3\xdc\xb0\x4d\xaf\x2e\x32\x05\x34\x4a\x31\x17\xad\x02\xd1\x25\xf2\xaf\x86\x9d\x95\x27\x5f\x39\x8d\xe0\xe8\xc5\x2f\x77\x1d\xdf\xad\xb0\x9f\xb4\xfd\xf6\xae\xec\xa7\x31\xc3\xbe\x4f\x2f\xb0\x15\x5c\xe3\xb0\xbe\x1f\x15\x1d\x62\xd2\xcc\x08\x1b\x04\x3b\xd4\xd0\x7a\x3d\x7d\xaf\xf0\xff\xc6\xe1\x25\xe8\x7f\xb2\x2b\x98\xb9\x92\x6e\x8d\xc5\xe8\xe9\x25\xe4\xf7\x5b\x0a\xe7\x59\x81\x9e\xd6\xf9\x5b\xc5\xdd\xc8\x16\x0b\x94\x70\x22\x16\xa4\x05\xb6\xe8\x6c\xbc\xc4\x72\x2c\xd8\x74\x6f\x62\xd3\x0b\x70\x5d\x01\x4d\xf5\x11\x20\x41\x60\x81\x5d\x20\x06\x90\x15\x74\x8a\xd4\xc2\xab\xc8\xa5\xc7\xa6\x0e\x65\x7d\x1a\xe5\x74\x71\x17\x51\x4e\x36\x15\x3b\x84\x5a\xe4\xfe\x87\xb2\x6b\x77\x35\x04\x06\x1c\xb1\x53\x0f\x4f\x4e\x16\xde\xef\xeb\x40\x61\x6f\xfa\xf9\x61\xc6\xba\x57\x19\xd2\xe7\xfe\x53\xc6\xc8\x8c\x1a\xdc\x60\x84\x08\xdc\x79\xcc\x88\xf3\x37\x1f\x33\x62\xfa\x14\xb9\x07\x66\x7f\xc0\x4d\x7e\x63\xf1\x97\xcc\xde\xda\x3b\x71\x52\x00\x62\xb0\x6d\x15\x27\x79\x24\x35\x68\xd0\x70\x54\x52\x2d\x06\xbd\x8c\x8d\xbb\x49\x00\x11\x2e\xd1\x13\xae\x4e\x07\xad\x68\x53\x2b\x88\x3f\xb4\x78\x56\x72\x7c\x2a\xe7\xbc\x85\x80\x7e\xf3\xe9\x55\x44\xad\x09\xea\xb9\x4f\xee\x1b\x6f\x68\x3a\xd4\x23\xc9\x7d\x47\x1a\x9a\x0e\xf5\x4a\x5f\x39\xd4\xd1\xf9\xe0\x03\x9d\x9d\x87\x08\xde\x61\x5a\xfa\x4e\xef\x51\xd2\xf7\x9d\x18\xe8\x3f\xbd\x5b\xae\x1b\x3e\x3e\x30\x35\x3b\x33\x35\x7d\xea\xd4\xe7\x71\x4e\x0e\x25\x72\xc8\x87\xe2\xfa\xcb\x09\x64\xfc\xb7\xbb\xd1\x86\xc2\x4b\x28\x86\xb8\x4f\xba\x51\xae\xf0\xe7\x6f\xa2\xf0\x7f\xef\x2d\xfc\x58\x2a\x5c\xe9\x59\xbd\x22\xf3\xc7\x81\x75\xf9\x08\xfb\x23\xc3\x7e\x30\x82\x15\x7c\x50\x02\x8f\x03\xb6\x49\x98\x97\x17\xfc\x14\x64\x60\x57\x26\x6f\xf3\x13\x51\xb6\x79\x2d\x62\xde\x6f\x23\x97\x7e\x87\x45\xc4\x66\x89\xc6\x97\xdc\xcd\x05\x36\x00\x55\x9c\x88\x59\xb7\x1a\x40\x74\x1b\xba\x4b\x97\x02\x21\x93\x77\x05\x68\x78\xc9\x5b\xc4\x7c\x80\xc6\x9d\x01\x9b\x45\xa4\x61\x26\x59\x16\x15\x59\x15\x05\x07\x78\xec\x57\xb0\x4b\x50\xcd\x0e\x32\x83\x7e\x1b\x2d\x8d\xc1\x66\x7e\x1e\x58\x4b\x49\x31\x22\xa7\x2b\xe7\x41\x01\x94\x2b\x1e\xed\xe1\x8b\x65\x13\x72\xd6\xfa\x76\xdb\xbe\xa7\x8f\x32\x33\x23\x4b\xd3\x1f\xa1\xf6\xa6\xbd\x7b\x87\x5e\xbe\xc1\xfd\xe2\x91\xa5\xc7\xd1\x3f\xad\xf9\xac\xc2\x30\x9e\xfb\xf4\xcc\xd8\x26\xf4\x4c\xe1\x81\xce\x6f\x7d\xab\xf3\x17\x64\xad\xad\xcb\xfb\xd9\x5f\x14\xc7\x2b\xc1\xef\x02\x8e\x48\x0b\x65\xba\xf1\xae\xc8\xe0\xb5\xd2\x82\x53\x7f\x43\x86\xb7\xfe\x73\xc3\x23\x00\x4a\x87\x53\xf9\x84\x87\x52\x45\x11\x8b\x48\x0d\xfb\xad\xd1\x24\xf8\x17\xcc\x16\x9b\xb3\xa4\x4c\x3f\x8e\x27\xc2\x0b\xaa\x35\x4a\x8b\xa9\x16\x4c\x36\x4f\x15\x01\x53\xaa\xd9\xc9\x0b\x79\x60\x2d\x45\x63\xbf\x32\x36\x0b\xba\xcd\x95\x19\x4d\x94\x85\xd7\x1d\x59\xdd\xaa\x1f\xbb\x6d\xc0\x28\x9c\x98\x19\x10\xb7\x6d\xa8\x70\x26\xda\x95\x01\x19\x89\x66\xaf\xad\x90\x8d\xef\x6f\x97\x7a\x5b\x73\x43\xb2\xd1\xc4\x7d\x6e\x26\xd0\xf3\x2d\xdb\x2a\xea\xb6\xc4\xa3\xe9\xf4\xc6\x64\xcb\x06\xe7\xfd\xed\xe9\x83\xd9\x58\xbb\x24\xd7\x6f\x35\x06\x8c\xc0\x41\x80\xca\xc2\x24\xac\x87\x5a\x68\x82\x16\x78\x0f\xf4\x84\x31\xcd\x79\xaf\x25\xb6\x3b\x2b\xe1\x7a\x79\xa1\x59\x17\x0d\x25\x93\xcf\x36\x93\x69\xc8\x36\x5a\xc4\x7c\x33\x45\xa3\xcd\x39\x8b\x88\x25\x69\xc1\xa4\xcf\xa2\x8b\x7a\x46\xf2\xe5\x8c\x34\x5f\x9a\x09\x3b\xc5\xe2\x64\xd3\x03\x2f\xac\x37\x17\xd6\xea\xa2\x12\x88\xdc\xe4\x17\xaa\xf4\xeb\xb5\x6e\x75\x33\x12\x71\x63\x66\x41\xd1\x6f\x6c\xca\xe4\x95\xcd\xe4\xc7\x95\x7a\x8b\x98\xdf\xac\x90\xcb\xcd\x59\x8b\x48\x8f\xc0\xb0\x06\xa8\x93\x50\x37\xaf\xe5\x05\xdc\x4c\x62\x78\x35\x93\x23\x72\x24\x35\xf3\x02\x6e\x51\x54\x64\xa2\x16\x47\xf5\xb8\x74\x6f\x52\xc6\xcf\x97\x87\xaa\xe4\xa2\x5c\x15\xf7\x96\xd0\x09\x5e\x8b\x4c\x59\x7f\xdd\xbf\xe3\x69\x7f\x5d\xfe\x02\x77\x19\x2d\xe6\xd0\xe6\x58\xfd\xe0\x96\x2e\x7b\xa9\xdd\x5a\x6a\x6d\xa9\x6f\x51\x06\x37\xd5\xf7\xcd\xa6\xba\x94\xa8\x9c\xcc\xb6\x26\x5b\x07\xd2\xa7\xd2\x74\xc5\xde\x59\x11\x51\x76\x5f\x9f\xb9\xc2\x12\x2a\xd9\x54\x9d\xce\x30\x3d\x1c\x23\x47\x63\x4d\x5d\x0d\x7b\x43\x52\x53\x3c\xd5\xe6\x34\x77\xd7\x26\xb7\x64\x43\x8b\xef\xff\xba\xfc\x32\x70\x62\xf9\x43\x76\xc6\xd0\x03\x95\x20\xc1\x34\xe8\x1e\xb5\x42\x52\x03\x9c\x86\xd7\x49\x0b\xd5\x45\x93\xbf\x9e\x62\x51\xc1\xab\x61\x41\xdf\x6b\x47\xfc\xac\xd5\x3d\xcf\x5b\x93\x4e\x71\x21\xa6\x1f\x33\x10\x93\x16\x92\xba\x37\x20\x22\x2c\xe8\xa1\x3c\x8e\xf1\xaa\x9b\x53\x14\x6c\xd2\x6b\x48\xb0\x95\x9f\x0f\x54\x54\xaf\xa3\xe2\x6c\x0e\x10\xc1\x2d\x0b\x16\x5d\x6e\x1d\x81\x58\x0d\x48\x2e\x62\xaf\xcf\x85\xc1\x9e\xdb\x29\xf8\x13\xc3\x8d\x29\x25\x7a\xdc\x18\xcc\x49\x1d\xb9\x98\xd2\x99\xec\x7b\x22\xb3\xaf\xe5\x27\x0f\xf7\xcd\xdd\x97\xfe\xc7\xed\xeb\xa5\x1d\xdb\x64\x39\x16\x43\x5d\xfb\x4f\xca\x71\x69\x68\x73\x5f\x9f\xb4\xa5\xa5\x23\xdd\xf5\x40\x7d\xaa\x7b\x63\x6c\x57\xcf\xee\xd1\x23\x1b\x47\x66\xd9\xb7\xd2\xad\x6d\x92\xd4\x16\x8d\xea\xb5\x94\x74\xcf\xbc\xb1\x17\x4c\x60\x03\x27\xac\xd3\xcf\x9a\xc2\xb0\xb2\x6b\xde\xce\xad\xee\x9a\x77\x49\xaa\x9b\x96\xcc\xdb\x79\x01\x3b\x6f\xdf\x35\x9f\x33\x98\xd0\x1d\x3b\xe7\x27\x7b\x90\x22\x15\xbe\x77\xdb\xfe\x79\xc3\xf7\xcf\x5c\xeb\x5b\xfc\x26\xfa\x87\xff\xaf\xda\x8c\x07\x0c\xec\x1d\x6d\x3e\x81\x36\xf4\x14\xfe\x78\xdd\xed\x6d\x3e\x7d\xed\xcc\xf4\xaf\xb7\xe9\x04\xfe\xd7\xdb\x74\xdd\x6a\x73\x25\x55\x8d\x88\xb0\xf3\x77\xb4\x29\x07\x4c\x09\xd3\x9d\x87\x04\x54\x23\x47\x6a\xb1\xf5\xc7\x1f\x6e\xb8\xbd\xe1\x13\xaf\xbf\xd6\xf5\xf5\x53\x8b\xdf\x2a\x9e\x19\xa0\xb7\xbd\x1f\x4c\x50\x01\x51\xe8\xf8\x7c\xdb\xe1\x95\xb6\xb1\x5f\xa2\x27\x73\x06\x25\xd5\x6a\xa0\xd1\x10\x89\x7d\x40\x45\x61\x5e\xc0\x51\x45\x75\x91\xc8\xc7\x5c\xa1\xd0\xa3\x57\x3c\xb7\xf7\xac\x4e\x27\x9a\x57\xe5\x86\x1e\x4f\x71\x47\x3f\xb9\x23\x47\xe3\x77\xb7\xe7\x5c\x92\x14\xbd\xab\x61\x40\x92\x3a\x9a\xb3\x25\xa9\x3a\xf1\x8e\x6e\xbf\x98\x97\xea\xa5\xa6\xd4\x3d\x1d\xed\xe9\x8d\xe9\x5c\xfb\xe2\x03\xb4\xff\x5c\xb1\xff\xdd\x60\x02\x2f\x04\xa0\x0a\xee\xff\xfc\x08\x7c\xab\x23\x10\x24\x5c\x29\xab\x36\xab\x86\x83\x19\x84\xe3\x12\x36\xdf\x54\x5d\x76\x0d\xbb\xdc\x6a\x09\x12\xd5\xb0\x5d\xd3\xcb\xf2\xcd\xbc\xa0\x1a\x7d\x0a\x3d\xcf\x04\x31\x01\xba\x0f\x5c\xc8\x1b\xfc\xf4\x64\x13\x15\xf9\x8a\x75\x0a\xab\x03\xbc\xe3\x78\xde\xd5\xf7\x3a\x53\x76\xdb\x28\x63\x0d\x49\x31\x1c\x6e\x14\x93\x0d\x13\xa8\xff\x85\xbe\x4d\xe4\x1d\x6a\x10\x93\x9b\x56\xc7\xf8\x51\x91\x32\x6b\x58\x8c\xa3\x7f\x60\xca\xef\xe0\xcd\xc2\xcb\x05\xf6\x1d\xe3\x20\xf8\xa1\x14\xe2\xf0\xc8\x6a\x6d\x2a\xf6\x49\x6a\xc0\xa4\x11\x65\xb7\x14\x2d\x6f\xb1\x60\xc9\x45\x0b\x96\x38\x24\x2e\x94\xe9\x1e\xae\xcc\xad\x46\x90\xb8\xe0\xd4\x39\x80\x04\x12\x55\xce\xaf\x97\x89\x94\xf1\x38\xa0\xe0\x88\x30\x6f\x41\xa5\x3c\x09\x59\x9c\x3c\x2e\x51\x40\x8d\x05\x78\xe1\x05\xce\x89\xf8\x52\xbd\x94\x3f\x80\xee\x3c\x6c\xa8\x78\x30\x85\x0d\xdd\x06\x7b\xc2\xe8\xc5\xf6\xe1\x90\xdc\x96\x48\x6c\x91\x43\xc3\x1d\xe8\xfd\xd5\xf3\x2a\xee\x96\x63\xb1\x74\x3a\x16\x93\x19\xee\x97\xe6\xb1\xf6\x78\x53\x3a\x14\x4a\x37\xc5\xdb\xf7\x19\x3f\xb3\xa3\x89\xc2\x09\xf4\x21\xfa\x07\xf4\x4e\x22\x9b\x4d\x24\xb3\x59\x62\x0b\xcd\x00\xec\xbb\x5c\x01\x5c\xe0\x81\xff\x97\xba\x73\x01\x6f\xea\x3c\xf3\xfc\xff\xd3\x39\x92\x25\x59\x96\x74\x8e\x64\xc9\x77\x4b\x96\x65\x21\x64\x5b\xb6\x64\x59\x08\xdb\x18\x83\x6d\x8c\x71\x08\x75\x3d\x2e\xb8\xd4\x0d\x37\x63\x08\x60\x08\x26\x84\xba\x84\xf2\x90\x34\x69\x53\xd2\x32\x69\x69\x86\x49\x5b\xca\x64\xd8\x0c\xdb\x65\xcf\x91\x15\x9a\x65\x33\xf4\x96\xcc\xf4\x92\xa6\x4d\x2f\x69\x33\xe9\x5c\x9a\xc9\x66\x56\x1d\xda\xcd\xf6\x49\xf3\x64\xb2\x89\xd8\xe7\x7c\xe7\xd3\xc5\x42\xc2\xee\x64\x76\xba\x63\x1e\x71\xce\xd1\xe5\x9c\xf7\x7d\xbf\xf7\xfb\xbe\xf7\xbb\xfd\xbe\xb3\x6c\x55\x18\x2c\xe1\x70\x16\x63\x60\xa3\xcb\xf1\x12\x66\xab\x89\x2e\xa0\xd4\x26\x13\x5a\xbd\x29\x03\x35\xb0\xab\x6b\x29\xcd\x34\x89\x4d\x84\x76\x81\xa7\x1b\xbe\x94\x39\x66\xd0\x64\x70\x03\xe5\xea\x88\x4f\xf7\xff\xbe\x7e\x38\xbd\x90\x8c\x7c\x5d\xb2\x58\x25\xdb\xd7\xe7\xcd\x16\x9b\x2d\x30\x6f\x55\xfe\xe7\xe6\x89\xd9\x6a\xcb\x52\x74\xc3\x24\x0b\x44\x70\x0b\x6e\xce\x16\x16\x3c\x7a\xf2\xc7\x9a\x81\xd4\x05\xe2\x4f\xfd\x8c\x4c\xa4\xfc\xa9\x37\x67\x3e\xf5\x6b\x47\x06\x91\x40\x26\x52\x17\xc9\x0b\x9a\xcb\x20\x18\x4b\x9d\xa5\x6c\x8b\x95\xb8\x03\x19\xa4\x85\x12\xa3\x04\xd5\xda\xb5\x34\x48\xa4\xae\x34\xd9\x42\x72\x5a\xe5\x10\x09\xc8\x3e\x67\x92\xd2\x58\x43\x4e\x41\x5c\x6d\xd0\x8a\x35\x9e\xc6\xe5\xcd\x11\x15\x0f\x15\x54\x2a\xc9\xe6\x98\x54\x2a\xcc\xc3\xe9\x6b\xa1\xf4\x0b\x36\xd1\x5d\x65\x15\x14\xc3\x5f\x10\x0b\x61\x1e\xec\xcb\x46\xea\xad\xdc\xd8\xe4\xe9\x4b\x23\x0b\x80\x18\x5b\x57\xa4\x81\x18\x91\x27\xb6\x97\xd2\xb0\x7d\x2f\x0b\xe3\xed\xe3\x5f\x3e\x31\xac\xd9\xff\x2c\x21\x67\x7b\x0a\xe3\x31\xc6\xf7\x99\x36\xd2\xd0\x7e\x83\x1a\xe8\x9f\xd3\x8f\xfe\xe9\x75\xb6\x1e\xf9\x01\xdd\x18\xed\xcf\x58\x94\x54\x61\x5d\x8c\x54\x21\xdc\x44\xaa\x20\x51\x6d\x49\x0e\xad\xe2\xdd\xc7\x95\x2a\x20\x93\x20\xb4\xf8\xa7\xfd\x2a\xff\xcf\xe5\xf0\x3a\xb5\xb9\x72\xfc\x92\x56\x0b\x59\x41\x94\x3a\x61\xa1\x1c\x62\x86\x8a\x58\x54\x0e\xdb\x62\x72\x28\x4d\x6e\x03\xd4\xf9\xe8\xf9\xf2\xd0\x4a\x23\x57\xa4\xed\xac\xca\xc8\x0a\xa5\xd6\x17\xb4\x0c\x52\xe5\xda\x84\x52\x54\xc0\x8b\x7b\x6e\x2d\x99\xe4\x08\x4a\x9e\xb0\x6c\x31\x26\xa5\x9a\x50\xba\x50\x2a\x28\xa6\xc9\x00\x3d\x9d\x7b\x2e\x19\xd4\x8e\x35\x97\x89\x0e\x17\x29\x25\x94\xcd\x20\x88\xb2\xc5\x11\x8b\xc9\xae\x4a\x41\x94\x6a\x6e\x52\x21\xb7\xf0\xf5\xe6\x96\xbc\xb9\x5a\x4d\x64\x8a\x5e\x72\x20\x5b\xee\x66\x75\xcc\x14\xbc\xfe\x9c\x32\x57\xa3\xf2\x2c\xb2\xfe\x50\x94\x68\x61\x5d\x12\xd1\x42\xb8\x89\x68\xa1\xf8\x65\x9a\x6a\xf1\xee\x75\xc5\x29\x33\x6c\x0b\xed\x5f\x53\xa7\xfc\x77\x90\xc1\xeb\xd4\xa6\x65\x48\xf9\xa9\x43\x66\x85\x38\xaf\x38\x64\xae\x0c\x22\xde\x7f\x0b\x19\x6c\x4b\x92\x81\xfa\xa3\x46\x10\xe3\x65\x66\x41\x5d\x60\xb0\x50\x1e\xea\x93\x19\xb3\x7c\x9e\x39\x64\x56\xa8\x87\x98\x43\x72\x4c\xae\x1c\x7f\x2c\x22\xd9\xcd\xae\xb8\xb8\x98\xf3\x36\x83\x46\x1f\x90\x4d\xa6\xa4\x64\x0a\xe6\x39\x27\xf5\xcc\xac\x3f\x2e\x10\xbf\xa8\x3f\x66\x34\x7a\xac\xa0\x33\x66\xf5\x4b\x16\x70\x46\x0d\x7a\x6e\xa4\xb8\xab\x94\xed\x54\x8f\xdd\x6c\xde\xb5\x4d\x9b\x8c\x73\x74\x26\x84\x2e\x99\x20\xb0\x72\x65\x01\xa9\x4e\x5d\x22\x55\xa3\x72\xee\x05\xda\xd9\x6b\x33\x2b\x21\x4f\xdc\x46\xe7\x29\xd9\xea\x0c\x81\xb8\x40\x9b\xb7\x82\xa2\xaa\x8d\x36\xeb\x29\x23\xc3\x9d\x01\x90\x18\x9c\x6c\x76\x56\x06\x40\x54\xa2\xf3\xb8\x05\x5b\x38\x24\x46\x3a\x34\x01\xa2\xb4\x90\x7a\x76\x91\x9a\x87\xbe\x76\x2c\xe6\xdf\x70\x68\x68\xd3\xe7\x53\xef\x9c\x9a\x7b\xf6\xb9\x2b\xcf\x9e\xf9\xd9\xcf\x34\xd3\x47\x35\xb5\x93\x97\x5e\x3f\xb3\xf5\xab\x5f\x38\xee\xf6\x69\xf6\xa6\xca\x88\xe9\xb7\x6f\x92\xaa\xd4\xd6\xa3\x34\x5f\x51\x86\x87\x6e\x2f\x4c\xf0\xe0\x54\x61\x8a\x87\x12\x67\xda\xb5\x74\x79\x94\x45\x9b\x59\x62\x58\x80\xe9\xe1\x4d\x03\x46\xca\x62\x12\x27\x24\x34\x16\x7b\xb5\x47\xa9\xf7\x0c\x62\xdc\xe8\xac\xa0\x11\x5b\x86\xf1\x21\xdb\xab\x05\x51\x2e\xf3\xc4\xe8\x9a\x84\x8a\x98\x64\x61\x91\x5c\x2e\xf9\x83\x2b\x14\xaf\x66\x70\x20\x9d\x85\x43\xd5\x3c\x4a\x48\x7e\xb4\x0a\x4e\x65\x86\xe8\xc6\xe8\x7c\xff\x00\xd6\xe7\x53\x43\x3c\xfa\x24\x91\x9a\x0b\x51\x43\x5a\xd8\x8c\xff\x79\xad\x65\xd9\x72\x5a\xcb\x7b\x2a\xe9\x64\x2d\x63\x6c\x71\x74\x48\x93\x59\xa3\xb4\x80\x6e\xcd\x0e\xe9\xbd\x73\xb2\x6b\x2b\x2d\x7d\x6e\x49\x0f\xd1\xb4\xcf\x7c\x5d\x73\x5e\xad\x2b\xff\x90\xfa\x78\x9d\xda\xc5\xf5\xf9\x13\xb5\x24\x5b\x5c\xa1\x63\xb4\xce\x5d\xa8\x4f\x6b\x11\x7d\x82\x85\xf4\x69\xcb\xd1\x27\xf0\xaf\xd2\x87\x16\x78\x8b\xab\xe4\x4a\x97\x84\x8b\x2b\xb5\x33\x5b\x67\xab\x7a\xed\xa5\xac\x9a\x55\x38\xc2\xf4\x6a\x4b\xeb\xb5\x52\x4f\x87\x66\xaa\xb5\x49\xc9\x47\x27\x7a\x12\xa9\x97\x6a\x19\xb0\xd0\x59\xfb\x11\xa6\xe5\x6a\x12\x90\x03\x4a\x36\xb3\xc7\xa4\x88\xf0\xa4\xd6\x51\xd7\xb0\xdc\x42\xf1\x2b\xa2\x54\x1f\x83\xbc\xb2\x4d\xd1\x39\xa0\xe8\x2c\x57\x37\x08\xa2\x6c\x5f\x4e\x3b\xcb\xa4\xfa\x02\x36\x28\xd8\x24\xe4\xf2\x0d\x73\x93\x45\x4e\x14\xce\x7b\xb7\xe5\x1b\xea\x26\x03\x71\xdf\x5d\x98\x1d\xdf\x75\xe4\x5b\x4c\xed\x2b\x55\x6d\xb5\x89\xfa\x40\x07\xfa\x70\xa8\x80\x17\x48\xa1\xa0\xd4\x1b\x96\x03\xc6\xa4\xb4\x22\x44\xa4\x35\xb9\x2e\xb1\x8c\x04\xe4\xa0\x89\x6e\x52\xa1\xd8\xad\xdb\x44\xa7\x28\xa4\x1d\x65\x2d\x09\xc8\x91\xa0\x20\xc6\xb5\x95\x16\xa5\x4d\xd9\x2d\x48\x2b\x7e\x7f\x6f\x29\x5a\xbf\x2c\xee\x40\x62\xe1\x8a\x67\x71\x77\xfa\x66\xa1\xf0\x08\x04\x97\x89\x9f\x3b\xc4\xeb\x50\x0a\xd8\x0c\x24\x4a\xbb\x38\x4b\x0c\xe4\x32\xd1\xa4\x52\x77\xa4\x88\x66\x47\xea\x77\x84\x9f\x4c\xbd\x73\x03\xe4\x21\x52\x46\xac\x93\xa9\x37\x88\x69\x22\xf5\x9b\xd4\xaf\x27\x89\x35\xf5\x16\xf3\xcf\x13\xdc\xb3\xda\xbd\xa8\x44\x23\x9a\xb1\x5f\x25\x06\xc8\xbe\xb4\xc5\xeb\x95\x7c\xd7\xa2\x12\x02\x2c\x94\x10\xb0\x9c\x04\xe4\x32\x6b\x52\x32\x86\xe4\x56\xc6\x07\x90\x1d\x15\xb4\x07\xf6\x49\xbd\x58\xae\xad\xf5\x2a\x6e\x59\x26\xca\x86\x52\xa5\xf0\xf7\x89\x6a\x13\xb7\x5e\x78\xb2\xb4\xa2\xac\xc6\x4b\x49\x92\x5a\x91\xae\x7d\x49\x2f\xe4\x8e\x3a\x4b\x1c\x42\x7a\x3d\xbd\x2f\xda\x64\xb3\x3b\x09\x1d\x98\x33\x13\x9b\x23\x1a\x12\x85\x0e\x5f\xd7\x9a\x63\x97\xa6\x7b\x8e\x75\x4e\xce\x1c\x3e\xba\xf1\xc4\xf9\x4d\x5d\xc7\x62\xbb\xf7\x1e\x7b\xe0\xf4\x00\xb9\xb0\x71\x32\x72\x67\x7b\xb0\xeb\x73\x23\xa3\xe7\xbe\x14\xd5\x9c\x3c\xf3\xfa\xa5\x49\xbf\x3f\xde\xf5\xe3\x0b\xa9\x6f\x3c\xfd\xf6\xb9\xde\xa6\xc0\xb5\xe8\x2b\x97\xc9\x6d\xbf\xfc\x04\x67\x1d\x0e\x47\x22\xdf\x7b\xf7\xcb\xfd\x84\x80\x18\xbf\x77\x8c\xd6\x85\x37\x92\xdc\x05\xdd\x18\xea\xd0\x80\xb5\xf9\x24\x18\x4f\x31\x12\x4c\x23\x23\xc1\xc4\xab\xea\xdd\x6a\xaf\xc4\xe2\x34\x18\xa5\x22\x28\x4c\x84\xf9\x4b\xa5\xf0\x5f\x04\x0b\xc3\x7f\x56\x29\xf9\xff\x5d\xe5\xf5\x3a\xb5\x85\xe5\x7d\x87\x16\xee\x8b\x09\xbc\x9f\x96\xec\x0b\x6d\x4c\xd7\x7a\x2d\x94\xb9\xa9\x98\xcc\x4a\x90\xa7\x87\x0a\xfe\x53\x64\x4f\x54\xb9\xdc\x1e\xea\x5c\xe5\x82\xd4\xb0\x54\x1d\x68\xe1\x5e\x58\x8d\x53\xac\x40\x5f\x4c\x91\xcd\x6a\x69\xce\x31\x3d\x36\xa1\x0e\x01\xac\x50\xf2\x4a\xae\x26\x92\x3f\x28\x75\x86\xe5\x06\x63\x52\x0a\x86\x28\x9f\x29\xab\xd6\x7c\xbd\x5e\x69\x62\x35\x99\x72\x15\x9c\x0f\x97\x8b\xfa\x80\xdc\x6c\x4a\x4a\xcd\x41\x39\x6c\x52\xf1\x4d\xcd\x4d\x74\x3d\x8e\x14\x16\xa4\xe0\x12\x75\x2c\x5a\x24\x15\x56\xfb\xe3\x05\x8b\xa1\xc5\x8c\x70\xa5\x60\x19\xa4\x51\x59\x37\xba\x31\xe8\x61\xba\x99\x76\x53\x96\xa1\xdd\x98\x6f\x4d\xbb\xe1\xbc\x4e\x6d\x96\x78\xb3\x4d\x6d\x97\xe7\x70\x6f\xb8\x8b\xaa\x33\x65\xd9\x69\xe5\x68\x40\x7f\x0e\x3b\x2d\x61\x77\xd0\x96\xaf\x9d\x4b\x26\xf4\x0d\xf4\x54\xaf\x4f\xa6\xb3\x44\xb9\x25\x29\x97\x38\x42\x21\x25\x31\x68\x66\xe0\x55\x08\x23\xb2\xd0\xc5\xf2\x05\x5c\x35\xca\x51\xf5\xb8\x8f\x9d\xe7\x05\x9e\x18\x73\xe0\x6a\xff\x4c\xca\xd7\x6c\xe9\xae\xe2\x55\xbc\xda\xdb\xfc\x3b\xbc\x46\x57\x2d\x7e\x35\xb6\xfd\xd4\xf0\xf0\xc9\xc9\x68\xea\x69\xf2\x8d\x86\xee\x51\xba\x69\x0e\x2d\xa3\x0f\xdd\xb8\xce\x5d\xd1\x4e\x60\x05\xf6\x32\x69\x1d\x6c\xa9\xa3\xd4\x14\x94\x7d\x5a\xa5\x42\x93\x79\x46\xf4\xc2\x8b\x74\x13\x9b\x15\xb4\xa3\x50\x16\xcc\xc9\x79\x83\xe0\xd2\x07\xe4\x16\x0b\x9d\x9e\x6b\x60\x88\xaf\x96\x15\x82\xf8\x24\xef\x30\x55\x37\x55\xd0\x80\xc7\xe7\x10\x44\xd9\x54\x19\x8b\x49\x21\x81\x2d\x76\xef\xc8\x0e\xae\x30\x6e\x97\x2f\xaa\x56\x64\x19\x50\x6c\x24\xb3\xd2\xf7\xd0\x73\x5f\x19\x79\x60\x57\xd7\xf8\x48\xec\xc3\x7d\x9e\xd8\xd4\x83\x9b\x8e\x4e\x0e\xf5\x6c\x09\x8c\xf5\xf9\x78\xdf\xf0\xec\xe8\xaa\x61\xef\x48\x97\xd7\xd3\x3b\xde\x11\x1d\xef\xa9\xe7\xb6\xa7\xde\xee\xda\x71\x6a\xdd\xe6\xcf\xfa\xc4\xc1\x3b\x8e\xf4\x8e\x3d\xbc\xb7\xab\xf7\x70\x7b\x60\xed\xe6\xe0\xe0\xe1\xdb\x9b\x67\x6b\x7b\x3e\xd4\x17\x18\xed\xf5\x46\x77\x7e\x6a\xfc\x9d\x73\xb4\x8e\xa1\x4c\x1a\xed\xa3\x94\x49\xd3\x8e\x3b\x97\x44\xa5\x09\x15\xa5\xd2\x84\x17\x50\x69\xae\x50\x2a\x4d\x6b\xdb\x7b\xe6\xd2\xd8\xa2\xb6\x92\xa5\xb1\x69\x8e\x9d\x4c\xec\x5e\x94\x4f\xc3\xbb\xc7\x53\x3f\xea\xc1\x7f\x1c\xfd\xab\x89\x93\x5b\x9a\xfe\x97\x12\x27\x7f\xb0\xa8\xfe\xdc\xfa\xf4\x7c\x95\xb4\xfe\x73\x54\xff\x0e\xdc\xb5\x24\xfd\x23\x45\xf5\xef\x5c\xa0\xff\x57\x99\xfe\x21\xa5\x62\x10\x44\xa9\xfd\x3d\x9b\x21\x6c\x2b\xf1\x2d\xd1\x13\x96\xbd\xda\xf2\xcb\xc9\xf3\x17\x17\x37\x46\x17\xa9\x4f\xfd\xfd\xd0\x8f\x5f\xc8\xfa\xc3\x49\xed\x34\x2a\x11\xc2\x20\xfe\x3c\xd7\x1e\x9d\x0b\xec\xd1\x9b\xb6\x87\xb4\x3c\x28\xbb\xb5\x49\x29\x18\x94\x6b\x94\xb2\x62\x1d\xb5\x4e\xb8\x34\x29\x85\x99\x75\x7a\x54\xeb\x48\xbe\x90\x3c\x44\x02\x72\x58\x09\xcb\x4a\xab\xe8\x2e\x81\xab\x0d\xc6\xb2\xf2\x1a\xf7\xf2\x50\xe7\x1a\xd5\x48\xb2\xb7\x49\x89\x01\x7a\x45\x25\xf2\xb5\x85\x95\x60\x98\x17\x24\x4d\x4c\xd2\x8b\xd4\x60\xb2\x7b\xb9\x12\x2a\xb4\x84\x94\x4f\x82\x82\xe4\xbb\x95\x09\xd3\x8d\x89\x55\x9a\xbc\xd6\xc4\x12\xb8\x4f\xd3\x33\xc7\xbc\x63\x7d\x51\x4b\x65\x43\x75\x85\x6d\xa4\x67\x4b\x30\x38\x12\x5b\x59\xd1\xd2\xd9\xd2\xba\x14\x20\x14\xf7\x96\xd2\xac\xb0\xd6\xfb\x1c\xa3\xc3\xeb\xd4\x51\xa9\xfb\xf3\x18\x51\x3c\xf3\xbd\x51\xea\x7b\x2b\xb1\x0e\x5f\x5e\x82\xf7\x49\x2b\x82\xd2\x40\x58\x6e\x37\x26\xa5\x55\x21\x22\x0d\xe5\xba\xa2\x12\xf3\x46\x4c\x49\x29\xb2\xd0\x2b\x25\xc1\x2a\xad\x71\xbd\x28\xc8\x5d\xa6\xa4\xd4\x15\x94\xd7\x98\x92\xf2\x7a\xe5\xab\xad\x82\x38\x6f\xac\x2d\x6f\xa7\x53\x38\x85\xb8\xde\x5f\xa6\xae\xaf\x56\x6d\x5f\x75\x93\xed\x7f\xbf\x32\xab\xe8\xa4\xf0\xa5\xf9\xaf\xae\xe0\xd4\xf1\xc5\xdd\xf9\xdb\x85\xe6\x96\xa7\x6d\xfd\x10\xb5\xf5\x6a\x8c\xe0\xab\x4b\xb1\x75\x77\x30\xd1\xaf\x0e\xb7\x0c\x07\x13\xe1\xdc\x19\xe7\x39\x26\x4f\xf4\xa9\x43\x68\x7d\x56\x79\x1d\x09\x24\xa2\xea\xc4\x85\x68\x5e\xc9\xb0\x91\x04\xe4\xd6\x2a\x15\xc9\xd9\x27\x28\xad\x8e\x75\x62\x42\x5f\x5b\xd6\x1d\x56\xac\x1f\x15\x24\xff\xad\x2c\x2f\x0f\xf7\xd3\x3d\x09\x7f\xcf\x14\x50\x67\x99\x3a\x0b\x4c\x40\x5a\x5a\x1a\x4c\xd4\x87\xd7\x7a\x47\x62\x51\x52\x1f\x1e\xf4\x7a\xd7\x86\xeb\xa7\x43\x0d\x9e\x70\xd8\xe3\x69\x5f\x3c\x1d\xae\x78\xfb\x42\x35\x91\xe8\x90\x72\xa8\x09\xf5\xf9\x7c\xd1\xa8\xf2\x52\xca\x18\xfb\x8d\x24\xf7\x06\xf7\x34\x02\xe8\xc1\x20\x2e\x65\xe7\x09\xd6\x68\x93\x52\x7b\x88\x26\x85\x64\x0b\xcb\xfa\x92\xa4\xb4\x36\x94\xe8\x75\xba\x95\x04\xe9\x2d\x49\x4a\x5c\x48\xea\xb5\xca\x2b\x74\x99\x62\xa6\xd9\x9c\x94\x9a\xad\x72\x94\xd0\xee\xe3\xca\x32\x25\x57\x48\x95\x56\xb9\x97\x04\x64\x87\x33\x49\xcb\x9b\x66\xa5\xbc\x51\xac\x28\x45\x85\xb8\xde\xd7\xae\x58\xb7\x52\x94\xad\x8d\xb1\x98\xd4\x2b\xc4\x6d\x35\x14\xe7\xed\x50\xd7\xf1\xae\xa8\x51\x92\xa0\xae\x31\x16\x8b\xd1\x29\x0f\xb2\xd1\x1a\x8b\x49\x65\x82\x54\xaa\x1a\xbf\x97\xa4\x8d\xef\x64\x70\x12\x47\x2d\xd1\x52\xd6\x11\x5d\x2e\xd5\xe4\xcb\xe7\x39\xf4\x90\x12\x33\x47\xbc\xaa\xdd\xcb\xed\x2f\xc8\xc1\x0f\xae\xdb\xba\x7a\x68\xf3\xd9\xe1\x63\x2e\xcf\x91\x9e\x87\x3e\x9a\x1a\xbf\x6b\xc7\x64\x74\x68\xe2\x33\x1b\x3f\xe1\xf7\x7c\x64\xb8\x6b\xd7\x90\xef\xbe\x0a\x7f\xb8\x7a\xf3\x90\xa6\x65\x64\x47\x97\x83\x5c\x22\xe1\x91\xfe\xe1\x2d\xef\x9c\xbe\xa4\xd3\x74\xee\x3c\xb2\x79\xe2\x10\x59\xdb\xdd\xd5\xff\xd2\xb5\x8d\xe6\x1d\x47\x3f\x3d\x32\xbe\x7f\x64\xcd\x9a\x91\xd0\x6d\x3b\x82\xb5\xe1\x40\xe5\xfe\x43\x26\x47\xd9\x46\x8e\xaf\xeb\x18\x20\x15\xa5\x81\x9d\x47\x1e\xd8\x45\x39\x6d\xa9\xb3\x94\xd3\xd6\x89\x03\x88\x87\x14\x7b\xd7\x87\xe5\x2a\x3e\x8b\x6a\x93\x9a\x82\x89\x00\x73\xf1\x68\x1a\xda\x26\x95\xab\xa5\x8a\xc7\x99\xa4\x3b\x68\xb6\x96\xd3\x81\x45\x6b\x55\xbd\xab\x69\x59\x7b\x88\x56\xec\x01\xa5\x55\xb0\x4c\x89\xef\x64\x8f\x3f\x16\x2b\x8a\x78\x6b\x25\x9d\x4d\x79\x88\xb7\xc2\x23\x8b\x39\xd0\x37\x4d\xcd\x42\xe8\xdb\xb1\x78\xde\xb8\xe2\xc4\x9f\xcc\xf4\x92\x97\x76\xca\xa7\x0a\x31\xe0\x4e\x5a\x47\x16\x0e\x29\x6e\x3a\x79\x59\xad\xe3\xae\x73\x9f\xd6\x3e\x4a\xd9\x68\xcd\x98\x5a\x8c\x8e\xd6\x52\x84\x8e\xd6\xca\xe8\x68\x09\xad\xad\xc2\x1f\x50\x79\xc3\xef\x89\x8f\x46\xc3\xbc\xa5\x30\xd2\x76\x9d\x4c\xec\x5e\x8c\x93\xa6\xb9\x97\x05\x79\xff\xff\xea\x4b\xc3\xba\xa5\xe8\x7b\x36\x71\xf2\x07\x8b\xe9\x4b\x2e\xb2\xa0\x2e\xad\xef\x1c\xd5\x37\x88\x3d\x8b\xe9\xdb\x56\x44\xdf\x76\xa6\xef\x93\x54\xdf\x16\x06\x94\x2e\x77\x34\xc7\xde\x8b\xca\x6a\x08\xb7\x14\xad\x75\x6a\x04\xb7\xa8\xe2\x8f\x66\x03\x38\x9e\xe9\x3e\x8a\x1a\xf8\xe9\xae\xaf\x67\xf2\xb5\x0f\x97\x24\x13\xcb\x55\xed\x97\xd3\x9e\x5d\x69\x75\x58\x76\x19\x93\x52\x2c\x94\xde\x89\x4a\x31\xc5\xf2\xd0\x7c\xad\x19\xfa\x80\xdc\x68\x4a\x2a\x46\x69\x55\x8d\x32\xdf\x63\x6c\xd5\x07\xe4\x4e\x53\x52\xea\x0c\xca\x3d\x26\x75\x2f\xaa\xc6\x5a\x41\x94\x5c\x31\xa9\x53\x98\xb7\x55\x68\x69\x8d\xd6\x23\x4a\xe5\x0b\xac\xb4\x7c\x31\x2b\x2d\x08\x18\x6c\x59\x93\x2d\x18\x36\xbb\x85\xe1\x4e\x65\x03\x06\x21\x4b\x13\x1c\xce\x84\x0e\x45\xec\xc8\x9d\x4e\x07\x0c\xef\x1e\xcc\xe4\x1d\xef\x82\xb1\x5e\x95\xa7\xf6\x28\x0c\x28\xc3\x50\x61\x9e\x1a\xdd\xb9\xee\x96\x9c\x2d\x0b\x63\xa7\xc9\xa6\xb2\x7c\x72\x5a\xd4\x56\xa2\xe2\xd2\xde\xfd\x87\x93\x89\xdd\x0c\x93\xa6\x5d\xc3\xf2\xef\xbf\xf5\xf3\x4b\x6f\x7a\xbe\xcd\xc9\x31\x5c\xdb\xee\xc4\xc9\x1f\xa4\x31\x6d\xe9\x49\xfd\xe9\xe7\xcf\xc1\x00\x2b\x86\x8b\x3d\x5f\x58\xe4\xf9\x62\x9a\x1d\x57\x6a\xb2\xdc\xc4\x8e\xb3\xd1\x5c\xc1\x8c\x70\x4d\xf5\xfb\xb4\x1c\x5b\x17\xb4\x4f\x54\x59\x46\x61\x80\x03\x9e\x74\xbf\xc5\x4d\x74\x3b\x7b\x50\x72\x87\xe5\x32\xa3\xca\x24\x6b\xa4\x2b\x5b\xf8\x90\x2c\x98\x94\x60\x58\xd6\x28\xa2\x2c\x10\x74\xde\x59\xa2\xd1\x07\xe4\x3a\x93\x3a\x68\x28\x18\x69\xcf\x96\x5c\x57\x22\x88\x72\x95\xfb\x26\xd2\x5d\xb1\xc8\x96\x29\x70\xa9\x60\xe8\x9a\xd6\xa7\xd0\xe2\x47\xc6\xfc\xd2\xde\x41\x99\xf7\xaf\xa8\x0c\x04\xb9\x29\xcd\xfc\x6a\xe3\x92\x52\x69\x50\xb2\x05\x33\xe0\x7b\x1b\x05\xdf\x9b\x08\x9d\xc2\x31\x5f\x6e\x77\x9a\x03\x2a\x4c\x29\x28\x3b\x4b\x69\x3b\x34\xcd\x1b\x28\x35\xb5\x7e\x07\xb2\xa9\xb4\xf5\x3b\x44\xb6\xd9\x95\x73\xbb\x4d\x65\x0f\x08\x0f\x7f\x73\x36\x0d\x82\x31\x96\xda\x6d\x01\xc9\x64\x9d\x2f\x33\xd9\x6c\x81\x79\x51\xf9\x5f\x79\xbf\x5c\x79\x3f\x5e\x66\xb2\xe5\xac\x53\x17\x63\x71\x63\xa9\x5d\x39\x2b\x8f\x61\xde\x58\x26\x96\xd3\x75\xea\x99\x33\xba\x3e\x5d\xe5\xf0\x97\x58\x6a\x68\x8c\xd0\xd6\x24\x88\xb2\x13\xb1\x9c\x7d\x00\x69\x6c\xda\x4a\x7c\x5a\x5f\xb4\xc9\x17\xa5\x1d\xed\xa2\x50\x8c\x4f\x36\x38\x7b\x76\xe3\xf9\x9d\xee\xf1\x58\xea\x5f\x1a\x7f\xba\xf5\xc8\xc5\xad\xe3\x7f\xeb\xb9\xfc\x4f\xd1\x3d\x5f\xd8\x35\x71\xfe\x9e\xa1\x2f\xb6\x6c\xd8\xd3\x15\xde\x36\xd2\x12\xba\x7d\x5b\x7b\xfb\xce\x4d\xed\xe4\x3b\x53\x57\x1e\xbc\x7d\xef\xc6\xd3\x3d\xeb\xb7\xc7\x36\x46\xdc\xe1\x91\xee\x89\x8e\xd4\xdb\xa9\xe3\x73\xdf\x7e\x78\xe3\xd0\x49\x69\x6e\xec\x13\xdb\x3b\x03\x1f\x7a\x68\xfb\xf6\x4f\x8e\x35\xb6\x4c\xdc\x0f\x8d\xca\x80\xd3\x4e\xc3\x89\x36\x1c\x29\x42\x81\x93\x96\x05\xe5\x7a\x2d\xed\xee\xaa\xd2\xaa\xdb\x8e\x16\x64\xc2\x85\x48\x80\xc2\x1d\xe5\x8a\x36\x1a\x3b\x26\x74\x55\xf5\xcb\x5a\xd4\xa5\xe6\xb2\x87\xe2\x09\xeb\x97\x09\x62\xbc\x22\xd0\xa6\x44\x9e\x2d\x82\xe4\x2d\xca\x8c\xe3\x0a\x36\x61\xf3\x49\x72\x87\x8a\x35\x56\x0b\x22\xe6\xf8\x2b\xf9\x8d\x53\x35\x6f\xa9\x3e\xf8\x28\x1b\xb7\x5d\x57\x90\x3c\xd7\x5c\x88\x3c\x57\x78\xdc\x76\x89\xf0\x39\x25\xea\x59\x1c\x40\x77\x4a\x09\x79\x16\x83\xd0\x71\xce\x4c\xcc\xf3\x87\xd1\x45\x89\x68\x16\xd7\x25\xa1\x84\x33\x8b\xe9\xa2\xe9\xcd\xc4\x33\xaa\x2e\x73\x6c\xfc\xb9\xb0\x2e\xc1\x42\xba\x14\x1e\x7f\x5e\xb2\x2e\xb4\x50\x5e\x5c\x9d\x46\x16\xa7\x2c\xaa\x51\x7b\xa6\x24\x4f\xeb\x34\x0d\x1b\x9a\xb1\x1a\x47\x99\x4e\xa1\xb4\x4e\xdd\x1c\xa5\xa9\x54\x6b\xe9\x52\x65\x3a\xf6\xdc\x47\x35\x6c\x11\xe9\x92\xfe\x28\xd3\x70\x0d\x09\xc8\x2d\x6c\xec\x39\x2a\x3c\xa9\x75\xd4\x37\x36\xb3\xb1\x67\xd9\xa5\x14\xdc\x72\x77\x88\x69\x2c\x57\x37\x0a\x62\xdc\xee\x53\xc2\x37\xc9\x2f\x48\xee\x5b\x8c\x3e\xe7\x77\x18\x2d\x82\x4b\x2c\xda\x57\xd4\xb4\x28\x47\x91\xdb\x94\x9f\x17\xdf\xdd\x7e\x13\x5a\x11\x3c\xb3\xd7\x28\x6c\xb4\x86\xe8\xcb\x8c\xd6\x2f\xa8\x23\xea\xe8\xf8\xb3\x73\xc1\xf8\xb3\x5b\x4c\xce\xdb\xdd\x4a\x24\x57\x6d\xca\xee\x96\x62\x4d\xce\x77\x1b\x03\x7a\xd6\x5f\x14\x94\xbb\x4d\xea\x20\x74\xb5\x5d\xe5\x8d\x47\x84\x79\xad\xa5\xa9\x2d\x5b\x78\x17\xf6\x99\x85\x31\x5b\x9e\x99\x16\x04\x6e\x37\xd9\xec\x91\x6c\x25\x69\xb8\xc9\x4a\x53\xd9\xa8\xed\x26\x83\x9d\xca\xc4\x6b\x8e\x7c\x07\xbb\x96\x3b\xfe\xc3\xe1\x0c\x92\xdc\x61\xbe\x12\x1c\xdd\xc1\x72\x15\x5d\x49\x5d\x62\x44\x33\x5d\x7f\x27\x13\x7d\x92\x6d\x69\xd9\xcc\xb6\xb4\xe4\x5f\x94\x84\x90\x5c\xea\x48\x4a\x15\x21\x8a\xea\x2d\xe5\x05\x51\x2e\xb1\xd3\xfa\xdf\x16\x71\x97\x6b\x17\xa8\x9b\x7b\x71\x46\xf3\x4a\xaa\xab\xcb\xe3\xa9\xad\x26\x11\xaf\x37\xa6\x89\x7a\xbc\xca\xa9\xcf\x1b\xd1\xf4\x7e\xf2\x93\xff\xc7\x1f\xa9\xad\x6f\xf0\x76\x76\x68\xbe\xe0\x5b\x51\x5b\xef\xf1\x46\x3a\xd5\x3c\x70\x9c\xbb\xcc\xfb\xe0\x84\x1b\x01\x4c\x33\xd2\x64\x63\x3a\x45\x6b\xb3\x65\x54\x85\x48\x17\x9e\xf9\x59\x05\xa3\x94\x51\x15\x48\x47\xd6\x7e\xe1\x8a\x5e\x2b\xd8\x8d\xd5\x0d\x6a\x15\x23\x19\x62\x90\x1b\x05\x41\x94\x6d\xac\x79\x52\x15\x50\x6a\x5e\x51\x2e\xc9\x49\x44\x3a\xb2\x5d\xa2\x0e\xbf\x94\xf8\xa2\x4d\x51\x75\x60\xdb\xac\xb1\xb1\x49\x05\xbe\xd1\xa1\x7b\x2e\x4c\x6c\xda\x34\xb2\xef\xf6\x47\x49\xdf\xe1\x73\xe3\x53\x9b\x47\xef\x9c\x78\xf4\x0b\x03\xa4\xbb\x23\x1a\xdd\x75\x5b\xcb\x97\xba\xd6\x44\x77\x8c\x04\x46\xc8\xb3\x33\x4f\xdd\xbf\xa1\xe1\x74\xd7\xd9\x87\x7e\x73\xf4\xea\xc9\xfe\x96\xcf\x47\x2f\x9e\x79\xf3\xb1\x9d\x9a\xfe\xaa\xf0\xd6\x93\xa9\x09\x4f\x68\xeb\xa9\xd1\x27\x76\xaa\x63\x72\x94\x09\xa8\x7d\x94\x8e\x11\x6f\x28\x4a\x05\xf4\x14\xa1\x02\x36\x32\x2a\x60\x76\xac\x78\x09\x64\x40\xa5\x82\x29\x4a\x07\xfc\xad\x52\xaf\xdc\x92\x10\xc8\xb3\x4a\xe5\x0f\x22\xbb\x12\x9b\x17\x27\x1b\x7a\x94\x8a\xe4\x96\xc2\x73\xe9\x5a\x24\x2b\xff\x1c\x1d\xeb\xde\x52\x54\xfe\xa6\x22\xf2\xfb\x48\x40\xe6\xd4\x31\x6f\xc9\x21\x64\x47\xbc\xad\xa2\x3a\xe2\xbd\x04\x6d\x58\x95\x52\x54\xa1\x47\x58\x4d\x72\x6b\x95\xb2\xd5\x08\x38\xa6\xd3\x28\x1b\xf7\x3e\x52\x44\xab\x82\x03\xe0\x5c\x69\x72\xbe\x9e\x4b\x0f\x7e\x2f\x50\x76\x3e\x6c\x75\xdc\x3c\xfe\xdd\x54\x2f\x28\xba\x4a\xcd\xc2\x92\xa9\x94\xc5\x7b\xc1\x8b\x1a\x61\xaa\x60\xeb\x61\x11\x9b\x5c\xbb\xb9\x51\xa1\x51\x39\x86\xda\x47\xe1\x85\xbf\x10\xc9\x70\x79\x86\x64\x18\xf8\xb7\x20\x19\x2a\xae\xba\x14\x9a\x21\xf5\xda\xa5\x20\x0d\xb5\xcf\xe7\xf8\x2e\x65\x0b\x6b\x47\xe1\xc4\x32\xbc\x5f\x4d\x65\xb9\x9a\x4f\xc6\x0d\x2c\x02\x92\x10\xa4\xdb\xb6\xa8\xe8\xb5\x8a\xd2\xa4\xac\x75\x84\x42\x4a\xa1\xe9\x22\x01\xd9\x2c\xaa\x9b\x19\x50\x9c\xb0\xc6\x60\xa3\xf9\xcf\x53\x2d\x88\x71\xb3\x43\x97\x66\x0b\xdf\xbc\x81\x46\x0e\x5e\x98\x46\xe3\x73\x8f\x5b\x0a\xf1\x85\xc7\x3a\xd3\x7c\x61\xdd\x13\x66\xaf\x90\x2a\x2d\xc2\x18\xfe\x2e\x45\x0c\x73\x2c\x5d\x46\xe1\x45\x08\xbd\x38\x9e\x9f\x32\x52\x5b\x50\xea\x09\xcb\x7e\x63\x52\xea\x0c\x11\x69\x75\x50\x6a\x7a\x51\x6e\x31\xd1\xb8\x27\x4c\x02\xf2\x4a\x53\x72\xbe\x7a\x65\x58\x1f\xa0\x69\xd7\xa7\x44\x40\x4d\x82\xf8\xa4\x51\x70\x34\xda\x29\x54\x20\x2c\xc8\x4e\x73\x8c\x92\xfd\x3b\x7b\x62\x31\xb9\x66\xe5\x7b\x4c\xda\xe2\x5e\xbc\x94\x04\x2f\xec\xd0\x4b\xf1\x00\xdd\x6d\x05\xdb\xca\xe2\x8d\xdf\x72\x7f\xaf\x35\xa3\x02\x7e\x9c\x61\xb3\xc2\x2c\x5c\x52\x9d\xbd\x50\xc3\x29\x0d\x7b\xb6\xd7\x23\xc7\xf6\x24\x4b\x94\x9a\x1d\x5c\x99\x52\xa1\x27\xd3\x88\xf2\x4a\x33\xdd\x6c\x45\xa9\xe6\x75\x62\x28\x24\x5b\xca\x92\x92\x31\x14\xb7\x50\x58\xa5\xc5\x6a\x08\x48\xfa\xd0\xfc\x6a\x4b\x99\x21\x40\xb3\x47\xbd\x12\x38\x73\xb4\xb3\xd3\x22\xd2\x21\x5c\xb9\xd4\xac\xc4\x45\x95\x74\x9d\xa4\xe4\x8a\x49\x25\x2a\x49\xd3\x66\x15\xc3\x21\x87\x33\x92\xb3\xf8\x27\xa2\x18\x51\x63\xb3\x8b\xe1\x50\x67\x54\x50\x39\x51\xa2\xfc\xa5\xc0\x98\x97\xbc\x94\xba\x48\xbc\xa9\x97\xc9\x78\xca\xef\x19\x0d\x9e\x4b\xdc\x77\x70\x4f\x64\xd4\x6c\xaa\xf7\x87\xeb\xfd\x03\xdd\x75\x9a\x13\x64\x90\xac\x6f\xf0\x77\xb1\xe5\x08\xbd\xfe\x46\xd2\x43\x46\xdf\x49\xfd\x6a\x7c\xad\xe6\x25\xcf\x9a\x70\x7d\xc7\xdc\x73\x4a\x39\x68\xba\xf1\x4f\xdc\x1b\xdc\x55\xb8\xd0\x89\x5e\x48\x6a\xaf\x9f\x54\x13\x96\x6d\xba\xa4\xd4\xa8\x76\x8d\x48\x86\xb0\x1c\xd2\x25\xa5\xee\x50\x22\xaa\xf6\x00\x46\x95\xc0\x7a\xb5\x1a\x27\x96\xd1\xe8\xb0\x99\x04\xe4\x68\x59\x52\x32\x87\xa4\xa8\x55\x0e\x3a\x93\x4a\xcb\x22\x4a\x79\x31\xb2\xc9\xa9\xba\x5b\x33\x6d\xdb\xd7\x34\x86\x1a\x9d\x31\x39\xa8\x54\x09\xcb\x63\xd2\x0a\xe1\x4a\x89\xc1\x56\x51\xe5\xf3\xb3\x28\xa4\x3c\x06\xd9\x56\x21\x88\xb2\xa3\x8a\xc2\x9c\xe5\xf2\xe5\xb1\x98\x14\x15\xe3\x70\xd3\x10\x3c\x24\x48\x41\x3a\xdd\x2e\xa7\x3f\xa0\x93\x0e\xa7\x64\x7b\x05\x7d\xba\x05\x78\x14\xca\xdc\x62\x99\x51\xeb\x66\x23\x2a\xa6\xf0\x87\x66\x7a\xe7\x06\x36\x9d\x38\xf9\xc7\xa9\x16\x4d\xd5\x8a\x75\xe1\xe3\x43\x43\xfb\x4f\x9f\xde\x3d\x71\x28\xbc\x77\xf3\xca\xb9\x3b\xb7\xfa\x7b\x74\x26\xbd\x18\xf3\x7b\xfb\x63\x6e\xf2\x59\xb2\xf9\xc3\xe3\x23\x1f\x20\x3f\x7e\xe0\xea\xe1\xf0\xe4\xe4\xd3\x57\x4f\xcc\x3c\x34\xec\xde\xb8\x79\x66\x6c\x34\xb0\xff\xda\xa5\x67\xaf\x05\xbc\x3a\xff\xd0\xa9\xe8\xd1\x63\x66\x5f\xb8\x71\xf4\xa4\xc5\xf6\xc8\x9d\xa7\xe6\x68\x5d\xa3\xce\x27\xda\x04\x3d\x9d\xe1\xb3\x73\xe1\x8c\x22\xc9\x16\x94\x5c\x61\xd9\x64\x4c\x4a\x95\x21\x1a\x05\x18\x5e\x94\xad\xa6\xa4\x64\x65\x3b\x5e\x8a\xc9\x79\x87\xae\x44\x1f\x90\x6b\x4d\x6a\x30\x60\x35\xa8\x0c\x56\x87\x3a\xe5\x48\xae\xd5\x09\xa2\x5c\xe9\x8a\x15\x9e\x85\x54\x74\x26\x55\x76\x6e\xd2\x6b\x85\x97\xb2\xe4\xce\x55\xfa\x5f\x37\x4f\x95\x22\x44\xe4\x45\x8e\xd7\xce\x41\x87\x00\x24\x3e\x28\xe9\xc2\x09\x0d\xc3\x7e\x64\x76\x9e\x32\xa4\x77\x9e\xd2\xf0\x6c\xe7\x29\xd6\x69\x47\x44\xb5\xd2\x5e\xd0\x4f\x47\x70\x95\xdf\xcc\xcd\x68\xa7\x51\x81\x4e\x48\xd6\xa0\x5c\xa2\x4d\x4a\xe5\x41\x59\xa3\xcd\x21\x8b\x96\x58\xe9\x70\x27\xdd\x5a\xa6\x5c\x90\xca\x62\x92\x46\x8c\x6b\xd3\x74\xd1\x82\x4d\xb1\xab\xc5\x5a\x5a\x85\xfb\x34\x72\xf9\x4b\xc8\x05\x2d\xbd\xd7\xcf\xf8\x33\x39\x9f\xf1\x58\xf0\x99\x3e\xf7\x33\x7d\xf6\x33\x72\x44\xf3\xba\xe6\xac\xb6\x1a\x56\x2c\xa3\x6d\x11\x0d\xdd\xe1\x2b\xbd\x39\x84\x4e\x64\xfb\xae\x42\x57\xaa\xf6\x97\x52\x4a\x87\xa2\x7d\xb9\x9d\x76\x97\x7b\x1a\x9a\xc8\x91\x97\x86\x62\xb7\xb9\x7d\xee\xfe\x48\x64\x9c\x3b\x77\xf1\xe5\xd5\xe1\xe3\x3e\xbb\xc7\x1d\xa8\x6e\x1f\x98\x54\x9e\x31\xaa\x79\x5d\x73\x38\xfd\x0c\x6b\x30\x51\x9a\x7d\x86\xba\x63\x7f\x9c\x33\x2b\xcf\xe0\xf4\xd9\x67\xe4\x6d\xc7\x4f\x77\xe0\xf7\xd7\xd1\x1d\xf8\xb9\x96\xc8\x9c\xcf\xee\x75\xfb\xd9\xbe\xfb\x54\x8f\xd1\xd4\x13\x9a\xc3\xf8\xf1\x7b\x7e\x06\xdb\xe5\x3f\x7f\x6f\x7f\x5a\xdf\x5f\xd0\xbc\xce\x4d\x53\x3d\xdc\xd8\xa8\x58\x4b\xaa\x0f\x33\x83\x49\xb6\x50\x9a\xb8\xb4\xd0\x66\x92\x4e\xdd\x2c\xdb\x29\x26\xe3\x4e\x41\x79\xd7\x59\x63\x08\x50\x0e\x93\xa0\xe4\x2d\x0d\xa7\xb6\xe4\xf2\x6c\xea\xcd\xbb\xbe\xf0\xd2\x60\xec\x36\x77\xa0\x7e\x30\x12\x19\x23\x4f\xbc\x34\x10\x1b\x61\x17\x19\x7b\xbb\x3d\xd4\xde\x23\x0b\x2f\xa9\xdc\xc7\x35\xaf\x73\x83\x59\xb9\xad\x41\xc9\x1d\x66\x06\xa2\x0b\x6f\x1a\x0a\xd8\x48\x32\xab\xf0\x9b\x7a\x31\x19\xb7\x2b\xf5\x0f\xec\x95\x4c\x6e\xbb\x52\xc7\x08\x6a\x0f\xb4\x2d\xcf\x86\xde\xbc\xeb\xe3\x5d\xc3\x1e\xaf\x6b\x6d\x24\xfa\x47\x2f\x91\x3b\xba\x86\xeb\xfd\xea\x39\x4b\x42\x8f\x8f\x9a\xf7\xe2\xcb\x3d\x0b\x2f\x15\x99\x53\x4f\x70\x83\x34\x3d\xff\x10\x32\x53\x37\x60\x32\xa7\xcf\x99\x4b\x78\x9b\x32\x32\xe7\x78\xc8\xc5\x97\x41\xc8\x24\x49\x68\xae\x72\xc6\x5c\xee\x8d\x49\xe5\xde\x98\x16\x70\x6f\x4c\x2a\xf7\xc6\x54\x84\x7b\x33\xb9\x67\xa0\x3f\x1a\x9e\x1a\x1a\x9a\xd2\x4c\x0e\xed\x0c\x87\x07\x07\x77\xee\xa2\x65\xbd\xf9\x46\x92\xfb\x16\x7e\x4a\xb9\x88\x4d\x18\x53\xd9\x37\xb2\xb3\x31\x1c\x66\x6c\x1d\xd9\x5a\x1b\x0a\xa9\x44\x9c\x34\x6c\xc7\x97\x03\xdb\x61\xb4\xc4\x84\x5d\xbd\xb2\xd3\x5d\xc5\x13\x6e\x95\xb9\xb0\x8c\x4a\x12\x2d\x50\xa4\x17\xb8\x30\x0f\xb5\x07\x7d\x9e\xc1\x70\xa4\x9f\x6c\xcb\x50\x7a\xc8\xf6\xe1\x20\x7d\x37\x3c\x38\x19\x1c\xf2\xf8\x5a\x82\x83\x83\xc1\xf6\x41\x8f\x37\x18\x1c\xec\x6f\x6f\x1f\xa4\xef\xf4\x83\x10\x3f\x8e\x6b\xae\x51\x56\x8c\x03\xe9\xe2\x5c\x6b\x42\x29\x2b\xce\xdb\xda\x89\x0a\xc8\x23\x7e\x12\xdd\xf4\x16\xd1\xbd\x2f\x4b\xc6\xa3\x79\x3d\xfb\xfb\xba\x02\xbf\x97\xb5\x4a\xed\xcf\x2b\x29\xcd\x00\x34\xc4\x4f\x74\xf9\xdc\x19\xa5\x5c\xec\xbf\x91\xe4\xae\x68\x75\x68\xc7\x41\xc4\x9b\xe9\x3c\x7e\x5d\x32\x6e\x51\xe2\x33\xa7\x36\x99\x00\x69\xb6\x94\x05\x24\x77\x98\x6e\xa6\xe8\x09\x25\x0c\x7a\xfa\x46\x4d\x98\xae\xd9\xab\x0a\xd1\x59\x87\xda\x17\xa5\xf6\x90\xec\x2a\x53\x22\x1a\xc9\x65\x95\xaa\x5c\x2f\x0a\xb2\x51\x09\xdc\x82\x72\x55\x19\x9d\x7e\x08\x19\x3e\x41\x94\xfc\x31\xd9\xa9\x54\xaf\xa2\x4a\x59\xe9\x68\x8a\x74\x44\x3d\xd1\xf0\x2a\x2e\xdc\xa9\xee\x66\xa1\x2b\x71\x97\xb8\x75\xf6\x5a\xe2\x2e\x71\x2b\x41\x3e\xdb\x70\xce\xd7\x5f\x35\xaa\xd1\x1d\xac\xda\x53\xb9\xf3\xc4\xe7\x86\xff\xd3\xfe\xb0\xce\xdc\xb9\x79\xdd\xe1\xaf\x35\x90\x7f\x69\x49\xb9\x79\x72\x31\x98\xfa\x5c\xed\x37\xee\x3f\x3e\xd9\x75\xec\xcf\x27\xce\x1f\x1f\xb7\x90\x6b\x47\x8d\x4e\x53\x57\xf7\xd1\xa3\x4f\x4c\x07\xc9\xcc\xa7\xf8\x40\x8b\xff\x4f\x2f\x1e\xf5\xc4\x9c\xed\x47\x2f\x49\x63\x53\xd3\xa4\xfb\xe8\xe5\x59\xb5\x0d\xe3\xd5\x7c\x9a\xfb\x5b\xad\x9d\xf2\x08\xe6\xa0\xb4\x58\xb8\x70\x82\x50\x46\x8a\x6c\x30\x85\x32\x64\x36\x9d\x21\x20\xeb\xcd\xa1\x10\xdd\xa4\x43\xf7\x62\x42\xab\x72\x67\x0a\xee\x26\x2b\x69\x29\x46\x2a\x61\x57\xa7\x1d\x19\x43\x8a\xab\x59\xb2\x4b\xf9\x1d\x24\x20\x5b\xec\xea\x8c\x44\xb3\xa0\xae\xf3\xb5\xd1\x05\x89\x1e\x81\x08\xe1\x6a\xba\xb9\x76\x49\x90\x08\x5e\xf2\xcc\x53\x5b\xc9\xa6\xa1\x47\xce\xad\x1d\x9f\x73\x1d\xe2\xbf\xf5\xbe\xf7\xbd\xfb\x9c\xa6\xe3\xdd\xe7\x34\xf7\xa7\x7e\x4e\x96\xbd\x3b\x47\xfe\xdb\xdf\x71\x2f\xa7\xd6\x81\xd0\xce\xb5\xc7\xb9\xc7\xc1\x21\xa2\x8e\x94\x24\x88\x11\x25\x7c\x20\xf7\x3c\x4d\x0c\x53\x37\xad\x4c\xef\x5d\xa9\x82\xc3\xda\x05\xb7\xa0\xdc\xe0\x9d\xad\x6a\x9d\x09\x10\xcd\x0b\x9f\x7e\xe4\x85\x07\x3f\x6c\xe9\xfe\x1d\xea\xf5\xca\xbb\xf8\xc1\x89\xc7\xbe\x9b\x3d\xa6\xce\xea\xcf\xe8\xf6\x02\xd0\x43\x03\xf5\x8f\x00\xba\xb9\xd4\x01\xc0\x50\x07\xdc\xb8\xa1\x3f\xa3\x4a\x96\xf3\xf7\x9a\xe6\x3a\xfa\x79\xc5\xf4\x7f\x01\xf0\xb4\x1b\x95\x1c\xe2\x81\x7f\xe4\x81\x30\x0f\xcc\xf1\x40\x8c\x07\x86\x79\x90\x8b\x3c\x48\x2d\x0f\x3c\xc2\x03\x63\x3c\xb0\x95\x07\x19\xe5\x81\x33\x3c\xc8\x0c\x0f\x9c\xe2\x81\x29\x1e\x48\xf0\xc0\x59\x1e\x38\xcd\x03\xdb\xd9\xfb\x9f\xe0\x81\x0b\xec\x7e\x0f\xa9\xdf\xa7\xbf\x1d\x52\xef\x83\x51\xf6\xbd\x5e\x1e\xa8\x67\xbf\x53\x9e\xa1\xdc\xf7\x18\x0f\x9c\x57\x65\xa0\xd7\x17\x79\x60\x27\x0f\x8c\xf3\xc0\x03\xec\x7b\xca\x73\xbb\xd8\x77\x95\xe3\x61\x1e\xd8\xcb\xee\x37\xc5\x74\xf1\xb0\xef\xc6\xd4\xf7\x88\x89\x3d\xf3\x12\x0f\x5c\x53\x65\xa1\xfa\xed\x64\x72\x1e\x66\xb2\x29\xd7\x27\x79\x60\x23\x0f\x7c\x9a\x07\xbe\xcf\xe4\x7b\x80\xe9\xb4\x51\xd5\x89\xea\x30\xc7\xe4\xfa\x1e\x0f\x1c\x61\xdf\x3f\xc1\x3e\x73\xf3\xc0\x1d\x3c\xd0\xc2\x64\xda\xcf\x83\x3c\xcd\x03\x4f\x33\xb9\xd2\xb6\x57\xee\xbd\x89\xdd\x73\x98\x7d\xe7\x7e\x1e\xf8\x1f\x3c\xa0\xc8\xf7\x18\xb3\xe7\x55\xd5\xf6\xf4\xbd\x77\x78\xe0\x2d\x26\xef\x3f\xaa\xdf\x25\x8a\x6c\xed\xaa\x8e\xd4\xde\x6b\x78\xe0\xed\x9c\xdf\x1b\xd9\xcb\xc9\xae\xeb\x8b\xbc\xf4\x4c\xbe\x63\x79\xaf\x8b\x79\xaf\x9e\x9c\x74\xc8\x7f\x5d\x66\xc7\xa9\xbc\x57\x8c\xdd\xeb\x10\xb3\x73\xa1\x97\x9d\xa5\x45\xfe\xfb\xdf\xcf\x7b\x8d\xe6\xa4\x43\xfe\xeb\x0c\x3b\x9e\xc8\x7b\xb5\xb0\x34\x53\x8e\x22\x0f\x98\x54\x99\x88\x72\x7e\x95\x8b\x00\x4a\x8e\x4a\x1f\x35\x1e\x80\x9c\x03\x88\xa0\xbe\xf0\x7d\x80\x28\x41\xf4\x07\x69\xde\x39\x93\x7e\x69\xeb\x70\xc6\x50\x47\xf3\xc5\x11\xd5\xcf\xa9\xaf\x2b\xe9\x71\x5c\x7d\x91\x49\x1e\x30\x2b\xbf\xe5\x41\xfc\xca\x4b\xb9\x2f\x0f\x9a\x17\xbd\xdc\x9f\xd1\xbc\xd9\xcc\xfe\x7d\x0c\x3f\x22\x09\xcd\x76\xce\xcc\x3d\xc1\xfd\x0d\x6f\xe5\x57\xf3\xd3\xfc\x25\xfe\x17\xfc\x1b\xda\x26\x6d\xa7\xf6\x8b\xda\x67\x74\x21\xdd\x13\xba\x37\x4a\x0e\x96\xbc\xa5\x6f\xd2\x3f\x6d\x58\x65\xb8\xcf\xf0\x73\xc3\x75\xa3\xd9\xd8\x60\xbc\x50\xba\xa2\x74\x6f\xe9\x4f\x4c\x6d\xa6\xbb\x4c\x97\x4d\xaf\x96\x8d\x97\x5d\x2a\x7b\xd5\x1c\x32\x1f\x30\x9f\x33\xff\xc2\x52\x67\xb9\xd7\xf2\x75\x6b\xa7\xf5\x33\x82\x55\x58\x2d\x3c\x2c\x7c\x5b\xec\x16\x0f\x88\x5f\x14\x7f\x28\xbe\x6d\xb3\xda\x56\xda\xa6\x6c\xf7\xda\xbe\x62\x6f\xb0\x9f\xb5\xbf\x56\xbe\xbd\xfc\x87\x8e\x66\xa7\xc9\x79\x87\xf3\x4a\x45\x4d\xc5\x78\xc5\x83\x15\x6f\x55\xae\xae\x7c\xac\x0a\x55\xdb\xab\x2e\x54\x37\x56\x3f\x5e\xfd\x56\x4d\x73\xcd\xf3\xb5\xa8\xdd\x5a\xfb\x70\xed\x6f\xeb\x4c\x75\xb3\x75\x4f\xd5\x3d\x55\x6f\xaa\x7f\xde\x75\xcd\xdd\xef\xbe\xe4\x7e\xbe\xe1\xee\x86\xa7\x3d\xdb\x3d\xbf\xf0\xa4\x1a\x9b\x1a\x57\x35\x5e\xf7\x1a\xbd\x93\xde\xaf\x34\x99\x9a\xee\x6d\xfa\xa2\xcf\xe1\x1b\xf7\x7d\xdc\xf7\x13\xdf\x9b\xcb\x36\x2d\x9b\x5d\x76\xdd\xff\x91\xe5\x23\xcb\x7f\x14\x30\x05\x06\x03\xf7\x05\x5e\x6d\xde\xdc\xfc\xa3\x96\x35\x2d\x7f\xd5\x6a\x6c\xdd\xd8\x7a\x2e\x28\x06\xc7\x82\x67\x83\xaf\xb4\x6d\x6e\xbb\xd6\xbe\xa2\xfd\x7c\x48\x1f\x9a\x0d\x1b\xc3\x17\xc2\xcf\x74\xf4\x77\x3c\xd6\xf1\x66\x64\x22\xf2\x6a\x67\x4d\xe7\x6c\xe7\x9b\xd1\xbb\xa3\x6f\xae\xb8\x37\xd6\x11\xfb\xd5\x4a\xa9\x6b\x6f\xd7\xeb\xdd\xd3\xdd\xff\xd0\x33\xb9\x4a\xbf\x6a\x68\xd5\x83\xab\x9e\xef\x5d\xd9\xfb\xf6\xea\x8f\xae\x7e\xa5\x6f\xa8\x2f\xbe\x66\x78\xcd\xab\x6b\x3b\xd6\x5e\xee\x37\xf5\xef\xeb\x7f\x71\x60\xe7\xc0\x77\x07\xdb\x06\x7f\xb8\x6e\x62\xc8\x34\x74\xcf\xd0\x85\xa1\xd7\x8a\xfc\x7b\x63\xbd\x66\xbd\x75\x7d\xdd\xfa\xe6\xf5\x93\xeb\x3f\xb3\xfe\x9b\xc3\x75\xc3\xf7\x0c\xff\x68\x83\x66\xc3\xd4\x86\xa9\x0d\x1f\xdf\x70\x69\xc3\xa5\x91\xe6\x91\xcf\x8c\x3c\xc5\xca\xf0\xd7\x70\x07\xb4\x50\x6b\x3a\x02\x0d\x1c\xca\xdb\x64\x13\x2b\x8b\xad\xf8\x2b\x70\x20\xbc\x01\xc0\x2b\x34\xc2\x52\xce\x09\x1c\x78\x85\x9d\x6b\x60\xc6\x5b\xec\x9c\xc3\xbd\x44\xc7\xce\x79\x34\x91\xfb\xd8\xb9\x16\x55\xe4\x12\x3b\xd7\xa1\x89\x3c\xc3\xce\xf5\x30\x91\x5f\xb1\x73\x03\x3a\xc9\x9b\xec\xdc\x88\x37\x35\xcd\xec\xbc\x14\x35\x5c\x03\x3b\x37\xa1\x86\x5b\xc5\xce\xcb\x88\x8b\x9b\x60\xe7\x66\x74\xf0\x1f\x61\xe7\xdf\x86\x83\xbf\xcc\xce\xbf\x83\x36\xfe\x19\xac\xc5\x0c\x0e\xe2\x18\xee\xc2\x1e\xec\xc6\x34\x66\xe1\xc2\x32\xec\x80\x1f\x2e\x84\xd0\x86\x36\x74\xa2\x85\x9e\xb5\x23\x84\x66\xb8\x30\x8a\x6d\x38\x88\x69\xb8\x30\x82\x5d\xb8\x1b\x7b\xb0\x0b\x07\xe8\xaf\xa6\xb0\x07\x77\xe1\x30\x66\x71\x00\xdb\xb0\x1f\xbb\xd0\x8a\x7d\xd8\xb6\xe0\x9d\xd5\xd8\x8d\xfd\xd8\x86\x3d\xd8\x87\x56\xec\xc0\x0c\xf6\xc3\x4f\xef\xbb\x98\x24\xed\x68\xcf\x93\x64\x2d\xfd\xf6\x2e\x6c\xc3\x3e\xf6\xdd\xec\x75\x2b\x66\x70\x17\x76\xc3\x8f\xf5\x38\x40\x9f\x73\x00\x87\x31\x43\xe5\x99\xc5\x36\x8c\x62\x17\x76\xe3\x08\xbd\xbe\x2b\xa3\x53\xae\x46\xcd\xd8\x40\xf5\x51\x24\xdd\x87\x31\xdc\x89\x6d\xd8\x81\x69\xfa\x8d\x62\xcf\x5a\x09\x57\x91\xe7\xb9\xf2\x9e\xb8\x32\xa3\x55\x68\x89\xbf\x18\xc7\x2e\x6a\xdd\x3d\xf4\x9b\x2e\xb4\xa3\x95\xfe\x3e\x5c\xe4\xf7\x2d\x79\xbf\xcf\xb5\x56\xe1\x34\x54\x6c\x9a\xab\xb3\x2b\x4f\xeb\x85\xf7\x73\x61\x07\xbb\xdf\x2c\x76\x61\x27\x5c\xd8\x8e\x63\xb7\xf0\x8f\x23\x54\xf6\x03\xd8\x0d\x17\xa6\xb1\x07\x87\xe1\xc2\x0c\x8e\xd2\xcf\xde\x8f\x83\xf4\xb9\x33\x68\xc1\x76\xea\x31\xea\x1d\x67\x31\x43\x35\x52\xbe\xbb\x0d\x07\xe8\x7b\x83\x54\xd3\x59\x7a\x54\xac\xae\x78\x99\x0b\x6b\xe8\xf7\x76\x16\x95\xea\x56\x7a\xb9\x30\x45\xef\xb5\xd0\xa3\xd2\xa9\x7a\x94\xfe\x6b\x2d\x98\xe2\xe9\xcf\xf6\xe5\x68\x9a\xf6\xea\xb1\x8c\x96\x69\x89\x15\x3d\x67\x30\x85\x59\x1c\xa5\x16\xdc\x05\x17\xfb\xc6\x3e\xec\xc1\x0e\xfa\xeb\xb4\xe6\x47\xa8\xb6\xbb\xa8\x54\xb3\x54\x4e\xe5\xd7\xeb\x31\x02\x17\x6e\xc7\x41\x66\xd3\xec\x9d\x47\x16\xdc\x41\x49\xc9\x42\xfe\xd2\x4e\x6d\x95\x95\x6c\xe1\x73\xd3\xd2\x6c\xc3\xdd\x2c\x87\x6e\xc3\x76\xaa\x9b\x0b\x47\xb1\x87\xca\xe1\xa2\x9e\x39\x88\x3e\xbc\x8f\x9e\xcf\x52\x4f\x56\x72\xeb\x2c\x0e\x62\x25\x82\x08\xe2\x30\x4d\x83\x3d\x38\x88\x59\x1c\x46\x2b\x95\x21\x6b\xb3\x20\x6e\xc7\x20\x46\xfe\x55\xbf\xf9\x00\x76\x61\x3b\x4d\x2d\x55\x6b\x35\x0f\x0c\xd2\x5f\xba\xd0\x87\x83\xd4\x5e\x21\x44\xe0\xa2\x79\x63\x25\xda\x10\x62\xff\xa7\xf3\x5b\x07\x2d\xcd\xe9\x5f\xea\x1c\xa6\x50\xe8\xef\x35\x25\x7c\x27\x1c\x38\xf0\xd0\x42\x87\x12\xe8\xa1\x94\xbc\xa5\x30\xa1\x0c\x66\x58\x60\x85\x00\x11\x36\xd8\x51\x0e\x07\x9c\xa8\x40\x25\xaa\x50\x8d\x1a\xd4\xa2\x0e\xf5\x70\xc1\x8d\x06\x78\xd0\x08\x2f\x9a\xe0\xc3\x32\xf8\xb1\x1c\x01\x34\xa3\x05\xad\x08\xb2\x9c\x1f\x46\x07\x22\xe8\x44\x14\x2b\x10\xc3\x4a\x74\xa1\x1b\x3d\x58\x85\x5e\xac\x46\x1f\xd6\x60\x2d\xfa\x31\x80\x41\xac\xc3\x10\xd6\x63\x18\x1b\x30\x82\xdb\xb0\x11\xb7\x63\x13\xde\x87\x51\xbc\x1f\x63\xf8\x23\x8c\xe3\x03\xd8\x8c\x2d\x98\xc0\x07\xb1\x15\x1f\xc2\x24\x3e\x8c\x3b\xb0\x8d\xf0\xf8\x33\xdc\x87\xfb\xf1\x97\x38\x8b\xff\x89\x8f\xe3\x61\x3c\x84\x2f\xe0\x2f\xf0\x38\xd1\xe2\x93\xf8\x1b\x9c\xc2\x23\x44\x47\x4a\x70\x9a\xe8\xf1\x20\xbe\x85\xbf\x23\x06\x7c\x11\x97\xf0\x3b\xbc\x81\x37\x71\x01\xff\x05\xdf\xc1\x5f\xe3\x32\xb6\x63\x07\x3e\x83\x9d\xf8\x1e\x76\xe1\xdb\xf8\x2e\x7e\x80\xe7\xf0\x7d\x3c\x8f\x24\xa6\xf0\x63\xfc\x10\x2f\xe0\xbf\x62\x37\x5e\xc7\x19\xbc\x88\x9f\xe0\xa7\x98\xc6\x3f\xe3\xd7\xf8\x04\xf6\x62\x0f\xee\xc4\x7e\xec\xc3\x01\x9c\xc7\x0c\x0e\xd1\xf4\x39\x8c\x23\x98\xc5\xdd\x38\x8a\x5f\xe1\x1e\x7c\x04\xc7\x30\x87\xe3\xf8\x28\x9e\xc2\x97\x71\x02\xf7\xe2\x63\x38\x89\xeb\xf8\x0d\xae\x42\x82\x8c\xff\x8e\x9f\xe3\x25\x62\x24\xa5\xc4\x44\xca\x88\x99\x58\x88\x95\x08\x44\x24\x36\x62\x27\xe5\xc4\x41\x9c\x88\x63\x1e\x57\xf0\x55\x3c\x83\x04\x9e\xc4\xb3\x78\x00\xff\x99\x54\xe0\x1a\xbe\x46\x2a\x49\x15\x3e\x45\xaa\x75\xbb\xf7\x1d\x3b\x38\xdd\x5e\x72\xe4\xc0\x9e\xb6\xb6\xb6\x7e\xf5\xd8\xd7\xc6\x8e\xec\x7a\x4d\x88\x1d\xc3\xec\x18\x61\xc7\x98\x72\x0c\xb5\xb5\xb5\xb1\x63\x3b\x3b\x86\xd8\x31\xcc\x8e\x1d\xec\x18\x61\xc7\x4e\x76\x8c\xb2\xe3\x0a\x76\x4c\xdf\xaf\x4f\x3d\xb6\xb3\xfb\xb6\xb7\x1b\xa7\xf6\xec\x3e\x72\xd7\xae\x9d\xdb\x0e\x4f\xab\x6f\x85\x06\xd5\x63\x64\x90\x1f\x38\x72\xd7\x0c\xbd\x88\x0c\xae\x05\xf0\x14\xb9\x71\xbf\x44\x4e\x63\x83\xa4\xdf\xb4\x59\x26\xe4\xe1\x2d\xf2\xa0\x2e\xb0\xd9\x2d\x59\xb7\x6c\x90\xec\xa3\x9b\xdd\xd2\xc7\xb6\xd4\x4a\xba\xc0\xd6\xcd\x90\x38\xd7\x80\xc4\x05\xfa\x25\xde\x35\x70\x15\x1c\xa9\x82\x26\x40\xaf\xb5\xae\x81\x38\xbf\x87\x5d\xe8\x94\x0f\xb5\xc4\x92\xfe\xb0\xc4\x35\x10\xd7\x6d\x61\x17\x7a\xd7\x40\xbc\xe4\x83\xec\xc2\xe0\x1a\x88\xeb\x37\xb3\x0b\xa3\x6b\x20\x6e\xb0\xab\x17\x44\x2a\x65\x4f\x32\xb9\x06\xe2\xa5\x76\x4d\x40\xe6\x06\xef\x0e\xf4\x4b\x65\xae\x81\xb8\xa9\x3a\x73\x69\x76\x0d\xc4\xcb\x7a\x32\x97\x16\xd7\x40\xdc\xdc\x9c\xb9\xb4\xba\x06\xe2\x96\x40\xe6\x52\x70\x0d\xc4\xad\x35\x99\x4b\xd1\x35\x10\x17\xb2\xb7\xb2\xb9\x06\xe2\xe2\x63\x99\x4b\xbb\x6b\x20\x6e\xeb\xcd\x5c\x96\xbb\x06\xe2\xf6\xf6\xcc\xa5\xc3\x35\x10\x2f\x6f\xcc\x5c\x3a\x5d\x03\x71\x47\x4b\xfa\x72\x8b\x64\x0f\xd0\xf6\xf7\xfb\xb7\x5c\x1f\x06\xfe\x6f\x00\x00\x00\xff\xff\xa2\x5f\x93\x24\x70\xaf\x00\x00") func fontsInconsolataRegularWebfontTtfBytes() ([]byte, error) { return bindataRead( _fontsInconsolataRegularWebfontTtf, "fonts/inconsolata-regular-webfont.ttf", ) } func fontsInconsolataRegularWebfontTtf() (*asset, error) { bytes, err := fontsInconsolataRegularWebfontTtfBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "fonts/inconsolata-regular-webfont.ttf", size: 44912, mode: os.FileMode(509), modTime: time.Unix(1492020681, 0)} a := &asset{bytes: bytes, info: info} return a, nil } var _fontsInconsolataRegularWebfontWoff = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x64\xb4\x63\x6c\xe0\xcf\xfb\xbf\xfb\xae\x6d\xbb\x5b\xdb\xb6\xb6\xb6\x6d\xdb\x36\xb7\xb6\x6d\x1b\x5b\x6f\x6d\x5b\x5b\xdb\xdd\xda\x27\x9f\xef\xf9\x3d\xfb\x4f\x72\xe5\x35\x93\xc9\x20\xd7\x9d\xdc\x1e\x0a\xe2\xe2\x00\x08\x00\x00\x80\x29\x19\x80\xf2\x5f\xd6\x3b\xfe\xff\xeb\xff\x77\x88\x8b\xab\xca\x01\x00\x48\x20\x00\x00\xf8\xff\x61\xda\x86\xf2\x2c\x21\xf6\x53\x1c\x00\x40\x72\x00\x00\x20\x04\x00\x80\x18\x04\x0d\x00\x57\x50\x61\x64\x01\x00\x90\x6e\x00\x00\xb4\x00\x00\x30\xb4\x43\xc6\xbc\x35\xb1\x33\x72\x04\x00\x50\x6c\x00\x00\x09\x00\x00\x90\x0d\x70\x14\x61\xc0\xc4\xdd\x95\x18\x00\xc0\x32\x00\x00\xe0\xf9\x0f\xe4\x2f\x58\x32\x73\x47\x0b\x3b\x00\x00\x5b\x02\x00\x90\x46\x00\x00\x35\x53\x69\x61\x2c\xb7\x30\x72\x71\x04\x00\x88\x5f\x00\x00\x40\xff\x1f\xc8\x16\xb6\x5e\xe6\x00\x00\x91\x00\x00\x6a\xa7\x00\x90\xe9\x18\x09\x89\xc0\x65\x69\x66\x64\x0a\x00\x3a\x9e\x00\x00\x30\x03\x00\xc0\x01\x39\x18\x6e\x6c\x69\x69\x66\x04\x00\x3a\x35\xff\xfd\x0d\x00\x00\x32\x24\x24\x68\x67\x4b\x3b\x57\x4f\x00\xd0\x99\x02\x00\x90\x90\xff\xde\x0f\x3b\xb0\x97\xb6\x75\x30\x31\x02\x00\x3d\x45\x00\x00\x19\x06\x00\x90\x19\xff\x71\xad\x7d\x3b\x23\x4f\x47\x00\x30\xc0\xfe\xbf\xb3\xc4\xa0\x60\x20\x2d\xf6\x46\x76\x66\x00\x60\xc0\x05\x00\xa0\xbc\x00\x00\xd1\x99\x56\xd7\xac\xe6\xe8\xe0\xe2\x0a\x00\x46\xae\x00\x00\xb2\x07\x00\xa0\x3d\x15\xec\x4a\x4f\x8e\xce\x66\x8e\x00\x60\xa2\x09\x00\xc0\x00\x00\x80\xa8\x55\x2b\x99\x0c\x7b\x98\x19\x9b\x03\x80\xe9\x7f\xee\x20\xff\xe3\x52\x46\xe5\x3f\x3f\xff\xb3\x3d\xc5\x5f\x34\xfb\x5f\x8e\xbd\x2c\xe8\xfd\x97\xb3\x01\x39\x13\x9e\x1b\x26\x86\xa6\x86\x86\xbb\x60\xc6\x30\x90\xc8\x86\xc6\x86\xe0\x03\xe5\x42\x53\xa0\xc7\xcc\x00\x80\xf8\x03\x04\x1b\x00\xfe\xdb\x37\xf7\x1f\xe4\x0a\x0a\x4a\x0d\x0a\x5b\xce\x70\xc3\x04\x03\x2b\xe6\x0b\x35\xef\x9d\x49\x18\x20\xeb\xeb\xeb\x1b\x9a\x1e\x19\x9f\xea\x9b\xea\xeb\x9b\xeb\xeb\x2b\x40\x4a\x99\x35\x0f\x0c\x0e\x64\x5b\x45\x87\x84\x82\xd4\x5f\x16\xb4\xb5\xfa\x5e\xc0\xc6\x5e\xab\xc2\xa1\x04\x09\x0b\x13\x76\x9e\xa2\xd5\xfc\x02\xa8\x21\x20\xc5\x01\x1b\x64\x84\xff\x04\xfe\x77\xb7\xa1\xa1\x79\xa0\x21\x0e\xa4\x38\x24\x72\x3b\xe8\x21\x73\xf0\x2b\x1d\x3c\x6f\x60\x0b\x66\x08\x68\xc2\x30\x84\xe9\x1d\xcb\x12\xf3\x87\x05\xbc\x79\x8d\x21\xcf\x88\xab\x44\x90\x8c\xb0\x98\xb0\xb4\xb0\xbc\xb0\x94\xb0\x9c\xb0\x41\xbf\xf4\x0f\x7d\xa3\xd8\xa2\xa4\xf3\xfc\xef\xef\xfe\xb2\x5b\x50\x37\x7a\x43\xf8\xe0\x2a\x33\x45\x64\xc5\x04\xc5\x84\xa0\xaa\x56\x31\xe5\xc9\x97\xef\x8b\xef\xd1\x6f\xa4\x4f\xc6\x97\x9b\xfb\xe7\xef\x1d\x0d\xa4\x38\x41\xae\x07\xc3\xef\x10\x3f\x24\x77\xc1\xb5\x3b\xc3\xc1\x90\x23\xa4\x2c\xa2\x8c\x1d\x41\xd7\x0b\xf2\x25\x3b\x31\x50\x71\x0e\xc8\x76\x48\x71\x0a\xe2\xfe\xd0\x3a\xe0\xd4\x0c\x53\x9d\xc3\x1d\x51\x9e\xc1\x9e\x50\x5f\xc0\x1f\x44\xf8\x87\x11\x8a\x12\xb3\x13\x8c\x14\xb5\x15\x8e\x16\xb7\x17\xc4\x4f\x72\x33\x0c\x35\x76\x37\x04\x39\x7a\x3b\x02\x3d\x7e\x3f\x30\x51\x52\x13\x34\x15\x56\x17\x38\x19\x5a\x1b\x3c\x1d\x5e\x1f\x28\x09\x4a\x0b\x2c\x0d\x4e\x0f\x24\x05\x46\x07\x22\x03\xc1\xef\xc0\xbe\x82\xdd\x84\xb9\x86\xdb\x5f\x63\x15\xa7\x19\x6b\xed\x2f\xa1\x62\xe1\x6d\x4f\x33\xd7\xe3\xac\xc7\xf4\xfa\x2d\xa6\xeb\x0b\x47\xb4\x1a\xf5\xda\xcd\xee\x9f\x9d\x08\x78\x9c\x0e\x7f\x9b\xec\x46\x9f\xf8\xbb\x9e\xaf\x4d\xa8\xa4\xa5\xa6\xbb\x75\x1a\x1b\x88\xdf\xa5\xb4\x30\x45\x47\xe9\xc2\x8d\x21\xc3\x1f\x9c\x1b\x2e\x9c\xad\xb1\xd5\x2f\xad\x65\x67\xc0\x1a\x5d\x6c\x6e\xc8\xd9\x5b\xe5\x05\x5d\x5f\xce\x5b\x75\x7e\xd7\xef\xac\x8d\x3b\xde\x42\x0f\x1e\x40\x21\x05\xb1\xa4\x72\xde\x30\xb5\x3c\xb0\x3d\xbb\x3f\x2a\x64\xac\x71\xba\xe1\x0e\xa6\x70\xbb\x58\xb0\xe2\xf3\xab\x43\xa7\x54\x81\x1a\x03\xc5\x6e\x61\x37\x00\x00\x80\x55\x80\x7f\x00\x01\x40\x08\xe0\x06\x78\x01\x4e\x40\x04\x10\x0b\x2c\x00\x69\xc0\x32\xe0\xfb\xbf\x79\x22\x90\x06\x64\x01\x79\x40\x09\x50\x01\xd4\x00\x9e\x80\x05\xa0\x02\xe8\x03\x62\x10\x28\xff\xd5\x4e\x4f\xa9\x4b\x5e\x47\x18\xf9\x2f\x02\x12\x58\xd0\xd0\x1a\x31\xf7\x06\x7a\x73\x66\xc2\x88\x4f\x21\x04\xcc\xd0\x72\xac\xb1\x29\x6f\xd8\x11\xb4\x15\xa7\x73\x62\xb4\x13\x08\x91\x50\x90\x18\xc2\x46\x3d\x4e\x41\x61\x89\x64\x36\xe4\x0f\x2c\x49\x5f\x11\x81\x1f\xa8\xac\x36\xbf\x8a\xd8\x78\x79\x9b\x5d\x66\x32\x59\x65\x26\x12\xab\x3c\xce\x6c\x66\x55\x4e\xc8\x12\x06\xfe\x42\x4e\x73\x7c\xca\x4b\xb6\x36\x03\xcf\x25\x17\x17\xb1\x31\x2d\x21\x50\xda\xb6\xe6\x0f\x13\x6e\xef\x5f\x70\x90\xd9\xf3\x29\xbc\xd6\xc0\x11\xbf\x03\x35\x12\x8e\x1c\x6f\x90\x76\x4b\xf9\xd7\xfc\x07\x6c\xf8\xfb\x07\xd1\x3d\x2f\x76\x0b\xdb\xe2\xc3\x12\x0f\xcc\xd9\x0f\xf0\xe3\x6c\x27\x99\x90\x1b\x9c\xe9\xce\x49\xa4\xb7\xe0\xe5\x3d\x63\x26\xa6\x92\x8c\xb2\x7d\x06\xc1\x32\xe5\xaf\xdf\x6c\x27\xd6\x93\x0d\xad\x89\xf3\xdd\x21\xac\x28\xaf\xe3\x6c\x42\x2a\x36\x76\xe0\x59\x5f\x4b\x3f\x96\xef\x9d\xd0\x65\x12\x26\xcb\x1a\x39\x32\x32\x9a\xbe\xc8\xd0\xfa\xc3\xc6\x5d\xd5\x54\x5a\xa7\x5e\x36\xfa\xf5\x9a\x9a\x4f\x0d\x43\x68\xa6\x83\xa0\xd6\x06\xd5\xbd\xe0\x09\x11\x91\x28\xd0\x17\x7e\x93\x4d\xd0\x21\xa0\x3c\x19\x57\x0f\x41\xa3\x24\xe3\xc3\x72\x1f\x6d\x8d\x7f\x95\x08\xbd\x4a\xa2\x8e\x74\x4b\x49\xf3\x1e\x84\xb7\x42\x8e\x24\xae\xf6\x15\x70\x28\x34\x7f\xf3\x65\xcb\xd9\x39\x10\x0c\xbc\x68\xe1\xf7\x7b\xfc\xc1\x91\xe1\x79\x19\x0b\xdf\xc0\x46\x31\xe6\x35\xa6\x0e\x84\x11\x13\x11\x57\x7b\x0d\xc7\x9d\xed\xa1\x83\x3c\x54\x7e\x9f\x15\x4a\x09\x3c\xba\x8b\x0f\xc8\x85\x6e\xb9\x5e\x13\xe3\x4b\x6f\x75\x43\x64\x56\x87\xf6\xf6\xdf\xdc\xfa\x37\x19\xd5\xa5\xde\x31\x13\x2d\xe2\xe1\x50\x65\x5d\xb1\x40\x3d\xfd\xae\x3f\xd3\x3b\x0a\x96\x47\x08\x37\x28\x6c\xd2\x9f\x3d\xfb\xfe\x25\x1d\xf4\xc6\x47\x57\xc7\x66\x89\x08\x2e\xea\xcd\xe9\xfd\x5d\xd4\x7a\xfe\xab\xba\x1b\x4b\xa0\x89\x72\xf1\x4f\xa3\x36\xf0\xbf\x2e\x00\xf2\xfd\x0d\x20\x79\x6e\x2c\xf5\xc0\x69\xea\x9c\x64\x32\x74\x7e\xb5\xa6\x5d\x8b\x3c\xc3\x11\x87\x22\x8b\x8c\x35\xd1\xa5\x95\x86\x25\x98\xfd\xb0\x1f\xc1\x9e\x0c\x45\x96\x66\x0f\x55\x16\x61\x1a\x89\x23\x88\xe0\x0a\x55\x9e\x30\xe7\x83\x3f\x50\x5e\x75\xc2\x5f\x8d\xbc\x28\xb1\xdf\xf7\xb6\xe0\x13\xc8\xe3\xdb\xb6\x81\xd9\x77\xdf\x92\x3d\x6f\x49\x76\x5f\x90\xcd\xe3\xe3\xf7\x3a\xcf\xe3\xe3\xf6\x62\xb1\xa2\x4c\x9e\x96\xcd\x9a\x79\x30\xb5\x58\x00\x3f\xbc\xff\xfc\xd6\xde\x37\x3e\x58\x73\x31\xcf\xe7\x3f\x61\x83\xa0\x97\xd2\xbc\xf8\xee\xfd\xee\xea\xde\x39\xfa\x16\x9b\x57\x65\xfd\x39\x1f\x12\xc5\xa8\x0c\x5f\x5a\x54\x25\x26\xe6\xd4\xaa\x85\x71\xf1\x66\xa7\xaa\x4a\xf3\x35\xbb\x41\x27\x3a\x48\x4e\xce\xf2\x62\x06\xe1\xcf\x5d\xad\x9c\x46\xb7\x64\x8e\xe2\x9f\xcb\xe9\x33\xed\x5f\xbf\xbe\x29\x9b\x7e\x44\x33\x57\xb9\x45\x38\x8c\x25\xf8\x39\x69\xfe\xc4\x0e\x2b\x80\x4a\xd0\xce\x81\x94\xbf\x29\x77\x56\xa9\x5c\x15\x36\x61\x4d\x4d\xc3\x36\x6a\x49\xcd\x8a\x27\x12\x1c\x81\x56\x51\xed\x42\xc3\xef\x4f\xa1\x59\x1c\x3c\x41\x86\x79\x7a\x12\x06\x8a\x58\x77\x4c\x75\x66\x16\x85\x36\xa9\x28\xa9\x8a\x91\x41\x4f\x52\x2c\x47\x56\x11\x8b\x12\xe0\x86\x40\xe4\xc6\x73\xc9\x51\x5a\xdf\xbd\x10\x95\xbf\x6b\x43\x6a\xec\x2b\x8b\x11\x82\x68\x1b\x2d\xf6\xf1\x75\x35\x3f\xc6\xb1\x59\x06\x9d\x6e\xa8\x55\x1b\xe0\x41\x5d\xab\x4c\xf3\x4e\x6a\xf5\x47\x70\xa0\xb5\xad\x61\xc7\xba\xa7\xb9\x78\x55\x8b\x68\xab\xeb\xc5\xa5\x73\xa4\xab\x96\xfb\xe7\xfc\x92\x43\x06\x07\x45\xcd\x69\x11\xbc\x2a\x4c\x8d\x0a\x93\xa3\x08\x8c\x60\xf9\x8a\xb2\xb5\x66\x08\x69\x14\x38\x27\x65\x83\xc6\xcf\x5c\x3b\xfd\xb9\x4c\x31\xb8\x9a\x8a\x31\x01\xc6\xb4\x81\xe2\xb8\xb0\xd4\x4a\x84\xc8\x50\x43\x66\xb8\x91\x50\x45\x53\x14\x02\x72\xd3\xdc\x15\x4f\x82\x28\x88\xc3\x47\x1c\x25\xfe\x2a\xad\xbb\x4b\x4e\xa3\xda\x19\xe4\xfb\x57\xd4\xe9\xc4\x00\x18\x9d\x87\x97\x2a\xf2\x01\x78\xfe\xfd\x4a\x27\x39\x72\x8e\xd2\x2c\x1d\x86\x59\x74\xc1\xa4\xfd\x71\xb7\x4f\x19\xd6\x8c\x74\x74\x85\xf5\x8c\x55\x0c\xb6\xa3\x22\xbe\x8a\x90\x89\x2a\x2b\x58\xec\xe2\x13\xaf\xc2\x84\xc9\x8d\x1c\x86\xbc\x93\x13\x69\x55\xd5\x04\x04\x33\xab\x66\x5e\xdc\x58\x73\x38\x99\x96\xc2\xf5\xf0\x01\x12\x39\x49\xc3\x0e\xad\x11\xd5\xf3\x4a\xc7\x7f\x2e\xb0\xff\x38\x9b\xa5\x63\xdb\x0a\x06\x60\x4a\x52\x9d\x44\xee\xd4\x1a\xc7\xb8\x19\xd1\x33\xc5\x30\x12\x4a\x18\x32\xb0\x96\x28\x94\xa0\xd2\xdf\x82\xbd\xe6\xa3\x45\x44\xe4\xee\x8e\xde\x0e\xf2\x73\x0a\x2e\x7f\xd0\xc3\x75\x91\xa2\x1b\xf4\xcf\xc6\x1f\x9c\x40\x0a\x3b\xa0\x5e\x6a\x68\x2a\x69\xdc\x42\x85\xec\xb6\x17\x21\x47\xc9\x35\xbb\x36\x4e\xe0\x66\x99\x8d\x39\x90\x7f\x21\xe4\xf3\x57\x53\x2b\x0f\x86\x0d\xb2\x55\xbb\x9d\xee\x0e\xd8\x67\xd1\x37\x5c\xec\x21\xc9\x1e\xfe\xce\xfc\x68\xdb\xdb\x79\x71\xc8\x39\x74\xd8\x35\xc0\x48\x0a\x80\xc8\x3f\x9b\x08\x90\x97\xfa\x72\xd9\x7a\x71\x30\x97\xb9\x0f\x38\xeb\xaf\x67\x5d\xaa\x99\xb9\xa6\xaa\x0b\xfe\x2e\x84\x84\x9b\x36\x64\x91\x33\xcf\xfe\xbb\x47\xe7\x9a\xda\x2e\xc3\xaf\xc6\xf9\xa1\x60\x49\x45\xd1\x35\xac\xe3\x77\x8b\x66\x31\x16\x3f\x21\xe1\xaf\xaa\xfe\x11\xb2\xb3\xbf\x5c\x0f\xb9\xa3\xf4\x45\xc1\x85\xf3\xf6\xd8\x19\xd2\x4f\x74\x1e\x80\xed\xad\xf6\x6e\xed\xc9\xf2\x91\x3d\xe7\x79\x3a\xd7\x55\xb8\x53\x90\xa9\xef\xaa\x40\x74\x6e\xe2\x62\xa1\x14\x3e\xc3\xbf\x9a\xcf\xfb\x7c\xb4\x45\x8a\xcb\x96\xf6\x8e\x19\x7b\x7d\x23\x61\x10\x4e\x0f\x7e\x95\xd5\xee\x1e\xde\x51\xf1\x4b\x49\x4d\x95\x3d\xb5\x64\x46\x49\x24\x03\x6d\xe5\xbe\xc0\xec\x5e\x84\x2e\x0b\x81\xf6\x2e\x3c\x8c\xb3\x2f\x1c\xc3\x45\x24\x05\x8d\xaf\xdb\x32\xf4\x77\xce\x7c\x0d\x73\xd4\x0e\x4b\x16\x5b\x01\x57\x6b\x4e\x41\x0f\x8d\x73\xb8\x57\x10\x6b\x24\x9e\x22\x55\x35\x9b\xb8\xe1\x9f\xe1\x04\x17\xff\x95\xf3\xdb\x21\x43\x9d\xb0\x04\xa9\x2d\x70\xbc\x53\xce\xa9\x68\x6a\xcf\xc3\x16\x73\xb8\x0a\xda\x64\x49\xb2\x21\xb9\x1f\xc8\x5a\xcd\x70\x62\x2b\x0e\x98\xd1\xd1\x42\x9a\x3f\xcd\xd6\x6c\x51\xaa\x50\x45\x1a\x5f\xdf\xd1\x17\xd2\x5e\x3b\x24\x9b\x06\x32\x91\x8b\x30\x0b\xa9\x1a\x99\x95\xe3\xf1\x39\xca\x07\xad\xea\x44\x1a\xcf\x79\x78\x08\x0f\x1a\x07\x2a\x03\x4b\xab\x68\xd0\x2b\xe0\x33\x64\x70\xba\xa6\x85\xaa\x2f\x7b\x35\x4b\x97\x8f\xd9\xf0\x90\x41\xc7\xeb\xeb\xe0\x65\x5d\xab\x53\x45\x15\x72\xbd\xc2\x2f\x70\xff\x72\xc8\x5d\x9c\xa5\x13\x5e\xae\x2c\x6c\xac\x44\x5e\x57\xd6\x11\xaf\xfa\x35\x98\x5c\xda\x7d\x23\x79\xfb\xa0\x70\x32\xf1\x31\x7d\x2c\xac\xa6\x90\x67\x19\x81\xbd\x49\x5d\x1e\x86\xdc\xe9\x5d\x31\x5f\x81\x4f\x37\x61\x9a\x74\xdd\x5f\x0c\xd6\xe8\x6c\x9a\xcd\xf2\x5f\xca\xb7\x3e\xae\x52\x46\xf8\x64\xb7\xa8\x24\x53\x98\xbb\xb2\xc5\xba\x5b\xdf\x68\xbd\x14\x9a\xf9\xea\x74\x6e\x4a\x28\xc1\xd2\x38\x5d\x81\x1d\xd3\x87\x85\xb1\xa8\xb8\x4f\xc8\x0c\x57\x50\x9c\xeb\xa8\xae\x80\x62\x52\xe2\x05\x19\x18\x8b\xb0\xe7\xb7\x06\xcf\x98\x62\x68\x3a\xf1\x55\xbd\x76\x84\x0b\x89\x29\x21\xa3\xe2\xed\x36\x55\x04\xea\x62\x56\x1e\x27\x36\x40\x6c\x92\xcf\x83\x68\xef\x32\x45\x92\xf7\xf1\xd1\xeb\x5a\xcb\x19\x73\xeb\xae\x04\x66\x2d\x65\x0c\x69\xb7\x6f\xed\xe6\x60\x65\xef\x35\x0e\x81\xd4\xd0\x37\xd0\x32\xd9\xd8\xd8\xec\x6e\xe0\xc2\x90\x31\xa9\xe0\xd1\xf5\x9d\xfc\x43\xb8\x6d\x2a\x87\xae\x6b\x51\x05\xf5\xb4\x82\x40\xfc\x37\xaf\x9c\x95\x51\x4f\xb3\x11\xe5\x39\xb4\x86\xef\xdb\x02\x89\x7d\x4c\xab\x51\x54\xfa\x1b\x81\xcd\x5f\x90\xe1\x0f\x56\x9f\x03\xc5\x87\x9b\x1e\xfe\x6a\xea\x3f\x05\x24\x47\x3d\x37\x7f\xc1\xcf\xe4\xc1\xe8\x3b\x45\x15\xe2\x04\x6b\xf8\x17\x3c\xc5\xfa\x8f\xb6\xd9\xfc\xf3\xc3\x5b\xa2\x98\xdf\xe0\x21\x8f\x02\x06\x66\x0d\x91\x6a\xa3\x1e\xf6\x70\x90\xbf\x6f\x62\xe2\x05\x50\x6c\x09\x34\x7f\x35\xc0\xe5\x37\xd6\xf0\x24\xdb\x5f\x5d\xdb\xdb\xe9\x79\xf2\x09\xcc\xe1\xc2\x97\xbd\x1f\xdc\xe5\xd2\x5f\xac\xb4\xc2\xdb\x5e\xdb\xdb\xdc\x5c\xc2\x42\x2e\x88\x99\x2f\xae\x6e\x5b\x6c\xab\x56\x54\xba\xa9\xe2\x7b\x76\xa6\x4f\xa8\x03\xbc\x61\x2c\xfa\x35\xc6\x27\xcd\xda\x53\x53\x90\x47\xa8\x9b\xc1\x69\xaf\x5a\x3f\x13\x94\x23\x86\xe4\x46\xbc\x7e\x58\x92\x2c\x58\xb0\x49\xd6\x48\xdb\xb1\xe8\xe4\xad\xb2\x60\xa8\x31\xe3\x61\x32\x16\x6b\x3d\xa8\x9b\xc8\xab\xa9\x05\xbe\x78\xa1\x8a\x84\xbc\xa2\x9a\x99\x4a\xf7\x34\x4e\xdf\x72\x1c\xab\xc9\x75\xb3\x34\x04\x93\xd2\xd8\x10\x44\x41\x55\x1d\xc8\x97\x4e\x54\xc2\x62\x27\x0c\x15\x2a\x7b\xfe\x89\xab\x93\x18\x0b\x14\xfa\xf8\x75\x0a\xd2\xbc\x20\x21\x11\x5f\xec\xb8\x79\x2d\x66\xed\xd1\xd9\x54\xd3\x46\xfa\x2f\xfe\xba\x24\x49\x9d\xc8\x7a\x9c\x8f\xc3\xbf\xe0\x6b\xa1\x2e\x2d\x82\x75\xcb\x63\x2b\x11\xf2\x8f\x87\x0d\x8b\xf1\xc3\xa1\xc0\xc5\xe5\x5f\xee\xcc\xde\x6a\xda\xbc\x53\x91\xed\xca\xdf\xb8\x61\x12\x68\x7d\x4d\x8e\x3a\x82\xb3\x37\xd7\x76\x2e\x87\xfa\x0f\x57\x88\x58\xe7\xec\x06\x79\x9e\xa7\xff\xd2\xf3\x6e\x4e\xe3\x5d\xf9\x33\x60\xec\x36\x55\xad\xef\xc1\x65\x05\xd8\xfa\x04\x65\xe2\xe1\x73\x9e\x08\xec\xec\xbf\x16\xf4\xd0\xc3\xe6\xb8\xcb\x62\x05\x60\xbf\x86\x24\x21\xa8\xfa\xc7\xc6\xeb\xc0\x61\x28\xe4\x15\x03\x89\x9c\xa6\xa2\xcd\x2f\xf9\xd0\xd7\xbc\xb0\x23\xbb\x84\x68\xb7\xc2\x40\x70\xf6\x48\x07\xb4\xe9\x9d\x50\x5c\x2b\xe3\x0d\xf6\x70\x7d\xa1\xde\x1b\x04\x85\xc6\x72\x7d\xb2\x70\x82\x7d\xd0\x95\xd5\x61\x61\x7e\x86\x7e\x42\x1e\x74\x6b\xc6\x88\xbc\xdc\x57\xd1\xf7\xd1\x95\x2f\x60\x51\x69\x50\x07\xf9\x94\xb2\x55\xd0\xca\x91\x3e\xb7\x39\x74\x73\xe5\x2d\x34\xcb\x97\xfa\x5f\xa7\x2e\x8d\x75\x14\x8e\x44\xa6\x23\xda\x15\xcb\x49\x20\x7b\x5f\xf8\xda\x26\x95\xa6\xfa\xb8\x8c\x7e\x5b\x1d\xe6\xe6\x1b\x54\xf4\xfc\xf9\x8a\xb8\xf9\xc1\xde\x8b\xe5\x46\xe2\x91\x95\xa7\xe1\x1a\x6c\xce\x4d\x25\x3c\xfa\xa3\x5f\x18\x9a\x39\xf3\xf8\x27\x65\x47\x6e\x73\x5c\xa4\x9a\xc6\x7c\x90\x27\xb5\x5d\xe3\xa6\x25\x98\x72\xee\xda\x3d\x96\xc9\xe3\x23\xe9\x2c\x22\x38\xc5\xd7\xf5\x3c\xef\xf5\xc7\xca\x05\xd4\xc9\x81\xc2\xf7\xcb\x74\x62\x22\xa7\x01\x17\x01\x6f\x46\x86\xdf\x09\x2e\xbb\x0b\xd7\xef\x5b\x24\x41\xc9\x81\x13\x0f\x25\x07\x16\xac\x35\xe0\x94\xc1\x2c\x96\x16\x9b\xf0\x8b\xff\xc0\x83\x26\x41\x3a\x02\xb4\x82\x36\x7c\xa3\xfb\xc4\x92\xfd\x4a\x98\x9e\xb9\xa1\xfe\x21\xe8\xf7\x0e\x9e\xb8\xf6\x5b\xac\x68\xf9\xbc\x40\x8f\x44\xfe\x7b\xd7\x28\xe5\xf3\x91\xfe\x95\xb8\x5e\x07\x1c\xff\xaf\xd1\x8b\xab\x52\xff\xf1\x1c\x13\x6e\x69\x09\x37\x65\x80\x04\x1c\x83\x91\xc4\x5c\x5f\x51\xac\xd9\x70\xa7\x2f\x41\x59\x5b\x8e\x2a\x9a\xca\x37\x12\xdb\x56\xe5\x71\xad\x0c\xd6\x55\x75\x29\xb0\xa9\x79\xbe\x46\x3c\x7a\x67\xb1\x62\x77\xb6\x05\xd7\xb7\xb2\x94\xed\x47\x63\xe0\x9c\x75\xac\xd7\x74\xa0\xf7\xa5\x7e\xf3\xec\x56\xf4\x93\x5c\x61\xef\xd6\x3a\x75\xa7\x0d\xaa\xa0\xfc\x71\xd9\x9c\x70\xd4\xa5\x82\xc5\x35\x1f\xbf\x48\x8f\x70\xa6\x90\x8b\xe1\xc1\x89\x6b\x13\x7c\x06\x77\x50\x50\x6e\xd3\x94\x05\x0e\x98\x2f\xcb\x70\xc5\x5e\x32\xfd\x42\x99\xd1\x59\x6d\x91\x09\x8b\xbc\x62\xe1\x8c\x58\x36\xa7\x62\x1b\x39\xe6\x7b\xf1\x6f\xe7\x9b\xe1\x2f\x99\xd2\xda\x22\xba\xc3\x7d\x9d\xb7\x8d\x99\x5e\xd1\xa7\x23\x2e\xbd\xd9\x98\xb9\xfa\xc0\x34\x1e\xe6\x5c\x12\xe5\xd9\x03\x22\x70\x44\x03\xd5\x43\x2c\x1b\x41\xf9\xef\xac\xba\xef\x63\x4e\x23\xb9\xc1\xc0\x51\xc8\x0a\x03\xd0\xce\x28\xfa\x62\x66\x38\xa1\x70\x8c\x55\x68\xd1\x06\x72\x53\x0a\xc1\x5f\x90\xff\xac\xaa\xfb\xb0\x70\xb7\x67\x9c\x40\xbe\xdb\xac\xfd\x6d\x0c\x4a\x86\x4f\x4e\xda\xd3\xcc\x35\x17\x1f\x5a\xe1\xa6\x84\x13\x30\xc2\x8b\x72\xc6\x22\xcb\xce\x2a\x23\x87\xa5\xd2\x8d\x03\x06\xcb\xcb\x7f\xf1\xe3\x74\x72\xcc\xf2\x95\x1a\x0a\x5b\xcb\x54\x3e\xaa\x66\x4d\xe0\x36\x7a\x31\x40\x99\x88\xd0\xb9\x30\x83\x4d\x22\xa1\x58\xb5\x05\x45\x37\x67\x0e\x01\x6d\xfd\x86\x22\x7d\xcb\x91\x20\xd9\xeb\x2c\x36\xaa\x5c\x20\x13\x81\x7b\x54\x0c\x11\x16\xda\x13\x8d\xfa\x6d\x58\x6b\xaa\x5c\x04\x69\x66\x17\x67\x62\x6a\x86\xe4\xf0\x2d\xad\xe8\x46\xa4\x41\x3d\x0b\x8a\xf7\x63\x91\x4f\xac\x07\xe3\x2b\x2b\xf3\x68\x76\x57\x94\xe2\x59\x7f\xf4\x83\xfd\x51\xb7\xb0\x4e\x3c\xfe\xf6\x5f\xfd\xba\x8c\x1f\xbe\xf9\x8b\xb9\x80\x77\x9a\x78\xf0\xe7\xcf\x5a\x40\x21\x69\x3a\xaf\xcb\x93\x87\xc5\xc6\x4d\xc7\x6d\xd7\x09\xa2\x80\x98\xc3\xd5\xa5\xb4\xc2\x9f\x04\x97\x67\x77\x7b\x6e\x4f\xab\x92\x47\x43\xd0\x9b\x7e\xfc\x91\x19\xdb\x38\x65\x65\x7f\x9a\x49\xe3\x80\x90\x40\x44\xb2\x0a\x68\x73\x53\x21\xd2\xe5\x06\x47\xc8\xc0\xa2\x40\x68\xa6\x87\x7b\x62\xae\x28\xee\x25\x01\x47\xb6\x74\x13\x5e\x06\x7f\xf1\x66\x3b\x3b\x31\xf3\x8a\xe4\xbe\x02\xab\xdd\x69\xf1\x73\x79\x1a\x19\xa3\xde\x1a\x8b\xe3\xd2\x68\x9a\x69\xdf\x36\x6c\xd6\xb1\x5f\x38\xe8\x3f\xb0\xfb\x4c\xc0\xe1\x2e\xb5\x50\x67\xa9\x2e\x13\xdb\xf3\x48\x38\x51\x63\xd5\xcc\x27\xf1\x2f\x1c\xbd\x69\x60\x5c\x5e\x34\x09\x0c\x15\xa5\x64\x98\x25\x54\xa5\xd5\x0a\x10\x8f\xe8\xab\x51\x70\xb0\x53\x39\xb5\x93\xc5\x9e\x92\xed\xbe\x6b\x5d\x28\x0d\x6e\x56\x35\xd8\x3c\xc2\x4c\xf4\x10\xfc\x1d\x87\x7c\xf6\x05\xbd\x0b\xec\xcc\x2d\x9b\x19\xe7\x31\x73\x1c\xd9\x39\x4a\x72\x5a\x54\x2e\x96\x68\x7c\xe4\x7b\x3b\x3e\x65\x74\x47\x9f\xcc\x0d\xda\x6d\x64\xfa\xd0\xf6\xe9\x30\xd5\x4e\xfa\xbe\x5e\x66\xce\xae\xc6\xfd\x3e\x3d\x34\x62\xd0\xed\xac\x66\x43\xe9\x46\xa1\xed\x24\x8c\x76\x22\xd0\xd1\x89\xf3\x19\x95\xb5\x08\x93\x4b\xc2\xf9\x9f\x8d\x92\xa4\x33\x5f\xb9\xb3\x23\x9f\x83\xe0\xda\x8c\xb0\xf0\x0f\x42\x8b\xaa\xf7\x79\xd6\xbe\x82\x9b\xaa\xcd\x1b\x61\x39\xfe\x40\x2e\x9a\x2b\x87\x04\x94\x2a\x62\xbc\x68\xf4\x9b\x63\x8a\xc0\x14\x2e\x25\xd1\xdf\xd7\xc9\x90\x41\xcb\x52\xff\x24\x6c\x69\x99\xdf\x05\x53\x65\x76\x8e\x84\x51\x87\xb0\x36\xfd\x5d\x4d\xf3\x33\xc9\x17\xff\x6f\xbd\xba\xcd\xdf\x32\xbd\xc6\x17\x7e\x1d\xb0\x13\x73\x59\x42\x95\x9d\x7e\xc4\x7c\x0f\x17\x0b\xd3\xce\x2e\x13\x67\x06\xfe\xe5\xdf\x67\xbd\x53\x7d\x9e\xbe\xb3\x95\x5f\x58\x14\x65\x4b\x20\x3d\x93\xe8\xf0\xf6\x17\xf5\x38\x5f\x68\x59\x84\x30\x6c\xee\x1a\xef\xbf\x6f\xb7\x83\xae\x07\x7d\x67\x2d\x55\x6e\x7e\xf7\xf4\x76\xa0\x18\x2a\xd1\xff\x6c\x78\x03\x2e\x0f\x16\x89\xd1\xb4\xab\x02\xcf\xcb\x9b\x70\xe9\x30\xd8\x14\x79\x24\xce\xd8\x5c\x41\x76\x9d\xf4\x4b\xfa\x08\xa9\x41\x02\x44\x6b\x0a\xff\xd0\x58\x16\x91\x54\x67\x63\xa9\xce\xd3\x55\x8f\xbe\x8f\xd3\xf4\xff\x3b\xd5\xf2\xad\x1c\xd5\xb1\x01\x47\x31\x7e\x6c\x68\x66\xfb\xd5\x23\xbf\x61\x1c\xc4\x01\x07\xa1\x79\x6d\xf2\x8b\xf3\xde\x9d\x48\x12\x03\xdc\x18\xac\xc5\xe2\x63\xdd\x42\xe1\x98\x50\xd8\x40\x18\xec\x99\xf9\x63\xa0\x0b\xca\xc5\x62\xae\x8f\x4c\x4f\xc6\xd5\x25\x8f\x7b\x84\x21\x70\x3b\x56\x69\xdd\xcd\x13\x89\x8d\xd8\x20\xcc\x13\x49\xb7\x01\xaa\x74\xc5\x2d\xac\x01\xaa\x14\x56\x0a\x02\x41\xe3\x67\x7e\xe4\x29\x41\x24\xb0\xad\x73\x3a\xf2\xcb\x80\xaa\x86\x05\x7a\x86\x16\xf6\x05\x2b\xf0\x45\xa6\x4e\xb1\xa8\x19\x7c\xee\x89\x4e\x7c\x8d\xa5\x40\xbc\x68\x16\xa8\xab\xad\xc0\xf6\xf1\xa8\x86\x4c\x49\x11\x41\x24\x4a\x14\xed\x96\x99\x51\x0e\x37\xd8\xc0\x49\x10\xa5\x5d\x53\x2e\x33\xc7\x79\x56\x95\x27\x5a\x5a\x68\xf1\xf6\xf3\xd3\x20\x5b\x58\xc4\x87\x6f\x7b\x1a\xce\x46\x74\xe6\xff\xe1\x6d\x7e\xf7\xfc\xd4\xff\x99\x1b\x7f\x2d\x55\xf2\x44\x34\x1b\xf3\xf5\x60\x9c\xbf\x30\x8b\x1b\xec\xaf\x51\xf1\x29\x64\x73\x11\x72\xd5\x1f\x1e\x9a\x2f\xc0\x97\xca\x4b\x28\x45\xf8\x72\x3d\x13\x54\x4e\xb4\xd6\xad\xb3\x11\x3f\x18\x88\x50\x8e\xa1\x5d\x05\xca\x34\x05\xa6\xda\x46\x57\xaf\x35\xb4\x8f\x1d\xe8\x2c\xd1\x02\x0f\x26\x04\xb5\x52\x2b\x37\xf4\xf2\x62\xc4\x4b\x4c\xf3\x98\x3d\xc4\x74\xbb\x0d\x61\x9d\x13\x38\xda\x40\xd4\x22\x6d\xa3\xc8\x35\xc1\x14\xec\x94\xf9\xb3\x15\x76\x11\x5b\x2f\x1e\x62\xd1\x6c\x98\x78\x0e\x08\x54\x54\xa4\x04\x0f\xd3\x52\x44\xa9\x36\xed\xf7\x16\xef\x6b\x32\x8d\x51\x9d\xf4\xfe\x1d\x63\x68\xfd\x6f\x4b\x71\x03\x91\xd3\xf7\x88\x31\x7c\xc6\xd7\x6d\x4e\x79\xf7\x76\xa9\x2b\xe4\xfd\xbd\x6d\xae\xf0\x20\xb7\x16\xea\xfd\x20\x32\x37\xc2\xfd\x41\xb0\x97\xf6\xc9\xd3\xd0\xc6\x40\xee\xd9\xb5\xa1\xb0\x98\x85\x1f\xad\xe4\x2c\xed\x24\xc1\xbb\xee\x79\xef\xb3\x2c\x70\xc3\x1c\xfe\xf2\x73\x3c\xb9\xd6\x83\x3c\x22\xff\xf2\xc2\xe7\x4d\xe8\x1c\xae\x7c\xe7\xce\x6d\x0a\xde\x56\xc0\xad\xdb\xaf\xbd\xd5\xb7\x41\xcd\x20\xd4\xed\x8e\x6e\xec\x84\x6a\x2c\x28\x0d\x56\x59\x4b\x6d\xdb\x3c\x12\xdd\x9d\x80\xc7\x31\x5d\xe3\x67\xa9\x9d\xfe\x92\x49\xae\xa8\xe6\x5a\x46\xe8\xa1\x54\x0b\xb2\x39\x16\xe9\x85\xd6\x5b\x6c\xe5\x9f\x1b\x5e\x5e\x47\xb7\x18\x82\xdc\xb3\xb1\x9e\x0e\x4f\xe6\x67\xdc\x7f\x8b\xcc\x87\x24\xcc\x33\x50\x53\x31\x22\x0a\x5e\x54\x88\xb7\xfb\x02\x34\x17\x03\x5b\x4f\x60\xbf\xdd\x5e\x08\xdd\x26\x0d\x1b\xa7\xd8\x18\x53\x32\x43\x63\x35\x47\x53\x0b\x2e\xa5\xe5\xb7\x2c\xfb\x18\x23\x2f\x82\x96\x11\x3d\x39\x83\x76\x58\x70\xc8\x5f\x32\xd6\x2c\xdb\x74\x17\x98\x19\x02\xd6\xb4\x45\xa7\x02\x08\x6c\x47\xee\x53\x16\x0e\xa1\x57\xe9\x40\xc4\xa9\x25\x3b\xf4\x57\xd3\x9d\x48\xdc\x41\x00\xf4\x54\x79\x5b\x3a\x32\x8f\xe8\x67\xd3\xfd\x31\xcb\xe7\xde\xac\xde\x48\x3b\xe4\xbc\x5b\x24\x5f\x2f\x4f\x0a\xb7\x9d\xc6\x99\x19\x93\x67\x72\x05\xf0\xac\x2e\xaf\xde\xae\xf1\xef\x17\xd3\x1b\x31\xf6\x7f\x18\x6e\xb7\xbd\x6d\x20\x0a\x7c\x04\xb0\xad\x23\xd2\x8a\x8b\xb7\xa9\x9a\x2f\xb6\x0e\x8b\xa2\x99\xd0\xab\xec\x39\xe7\xfc\x58\x7b\x01\x0f\x40\x46\x9c\x66\x8d\x07\xcb\xa0\xdb\x8a\x5a\xca\xaa\xbb\xa3\x9f\x02\x14\xa8\xc2\xbc\x6f\x14\xd2\x0a\xa6\x4e\x88\x84\xf6\x67\x2c\x7b\x69\x69\x22\x45\xc2\x24\x69\x5f\x75\x48\x60\x2d\xbf\x6a\xca\x86\x82\x19\x1c\x53\xf9\xa5\x57\xc7\x16\xb4\xf3\xd9\x3f\x2c\xc3\x0e\x57\xa3\x8e\x43\xf2\x32\x1c\x98\x08\x91\x82\x94\x30\x25\x25\x84\x37\x2d\x84\x6e\xea\x10\x3d\xd4\x58\x8a\x86\xe8\x1f\xf7\xb6\x41\xc3\xa5\xc4\xf0\x4d\x58\x7d\xdb\x38\x8d\x39\xb0\x65\xa1\xed\x28\x6b\xa9\x6a\x2a\x61\x91\x47\x42\x43\xc6\x23\x0d\x9d\xf8\x86\x78\xce\xfb\x92\x83\x9d\xa8\xaa\xab\x43\xf7\x1f\x4a\x84\xeb\x7c\x9e\x15\x57\xff\xaa\x6b\xd1\x66\x9f\x04\xde\x53\x85\x6b\x95\x72\xa7\xf8\x1e\xed\xe4\x5e\x12\xe3\x56\x04\xaf\x77\x1e\x24\x7f\xda\xe9\x34\xdc\x2b\x88\xb0\xc1\xb2\x99\x0d\xf8\x94\x65\xf4\xe7\x95\x23\x2e\x9d\xf8\xa7\xbc\x5f\xaf\xef\x08\xb8\x41\x7d\xde\xfa\x97\x1a\x8c\xf7\xc4\xaf\xbd\xb9\x3a\xef\xa0\xf5\xc8\xf9\xb4\x41\xf5\xce\x59\xd3\xb0\xba\xc9\x3e\xff\xdb\x29\xb4\x84\x49\x66\x02\x0b\x94\x8a\xaa\x18\xa2\x51\x25\xe1\xea\xe0\x4e\x8e\x91\x8a\x62\xbe\x13\x11\x66\xcb\x67\x6a\x3a\xaa\x17\x5b\x8d\x1d\x1b\xf2\x45\xcb\x10\x61\x68\x93\xe8\xb8\x92\xf1\x0c\xfb\x52\x32\xad\x9e\x35\x18\x6e\xb5\x25\x7f\xa5\x09\x5e\x37\xa4\xa7\x98\x90\xbb\x2a\x00\xc7\xe2\xb4\x48\xbe\x31\xc8\x92\xb0\x0b\xee\x27\x43\x0f\xd6\x9c\xc9\x2c\x0d\x03\x72\x54\xee\x5d\xc2\x16\xb4\xf9\xd6\x16\xb3\x83\xce\xca\x42\x15\x2d\x67\xce\x6d\xeb\x42\x43\xaf\xeb\xc1\xdc\xa7\xaa\x20\xea\x84\xbc\xfa\x4b\xc9\xf5\xe3\x9f\xd7\x8e\x4b\x53\x49\xaa\x52\xcf\x2d\xc0\x9f\x98\x0c\x11\x61\x6b\xfe\xe8\x85\x5c\xd6\x4e\xf5\x19\x07\xfb\xc7\x5e\x6f\x46\x7e\x3d\x79\x5e\x47\x6e\xdd\x5a\xd9\x3e\x7b\x2b\x31\xba\xc4\x65\x92\x78\xf5\x18\xc3\xfc\x08\xde\xec\xdf\x45\x86\x4b\xc9\x42\x63\x97\x21\x46\xe9\x57\x60\x4c\xd6\x6f\x1f\x2a\x51\xba\x39\x24\xe3\x11\xe4\xa6\x36\x4a\x92\x6f\x5f\x35\x3b\xd3\xbf\xcb\x80\xec\xbf\xe2\x39\xd3\xc0\x42\x9b\x32\xfc\xb6\x72\xc5\xbf\xe2\xcd\xdb\x6c\x49\x5e\x5b\x3b\xb3\xb9\x61\x3e\x08\x7c\xa7\xa9\x80\x1e\x6b\xea\x73\x72\xb9\x28\xd1\x7b\x70\x0e\xf4\xdf\x75\x57\x92\x6f\xd0\xc7\xa0\x0f\x7f\xd5\x6a\x5e\x76\x80\x9e\xb6\x4b\xc0\xb6\x4c\x2c\xb2\x65\xc7\xc6\x27\x24\xa4\x57\x6f\x68\x88\x19\xec\x8a\x1b\xc4\x74\x0f\xd1\x62\xc3\x0c\x52\x4d\xd7\x1c\x32\xce\x31\x53\x31\x49\x97\x88\xdc\x76\x5b\x2b\xaf\xa0\xc7\x48\xda\xae\x07\x65\x19\x8b\xf5\x25\x53\x6a\x24\xeb\xa1\xa9\x1e\xb2\xc7\x30\x7a\x76\x5d\x64\x24\xba\xe6\x73\x55\x98\x22\x90\x6e\x1f\x94\x7a\x8e\x59\xc0\x88\x6f\x19\xe9\x89\x6c\x53\x3c\x86\x61\xe8\xa2\x9f\x80\xf0\xb5\xd4\x21\x5b\x98\x90\x47\x24\x94\xbc\xcc\x91\xa7\xec\xd4\x31\x0e\xf3\xbf\xde\x1e\xa9\xab\x9b\x5b\x39\x6e\x93\xbc\x10\xcd\x1e\x24\x90\x72\x08\x38\x11\xe1\x5f\x3d\x87\x0b\xed\x48\xc3\x14\x09\xe0\x7f\x59\x21\xa2\x92\x0d\xfc\x9b\xb4\xb4\x5a\x79\x09\x59\x33\x09\x12\x56\x33\x69\xbf\xfc\x91\xd3\xe8\x0d\xb6\x62\x46\xaa\xcb\x83\x76\xb8\x10\xd9\x2f\x4f\xaf\x74\xe1\x7c\xd2\xad\x68\x8f\x6a\xd7\x17\x04\x1d\x4a\x8c\x82\xd6\xd6\x6b\x6c\xc4\x87\x8b\xe1\x06\xa1\x8c\x2a\x41\x04\x32\x43\x15\x73\xdd\x07\x39\x85\x93\xab\x05\x5f\x37\xda\x3b\x8a\x0d\x78\xc1\x51\x84\x5a\xb3\x7e\x90\x37\x50\x19\x8d\x6f\x4c\x54\x0e\x55\xd9\x86\xac\x63\x91\xbe\x42\x22\xf7\x91\x25\xc9\xe5\xe5\x52\x71\x23\xa2\xec\x21\x08\x4a\xb1\x95\x08\xbd\xa7\x3e\x7a\x10\xf5\xac\xe5\x72\xf7\x32\x72\xcf\xdf\xa5\x1e\xce\xb8\xde\x3e\x06\x50\x21\x5c\xad\x61\x38\x64\x6d\x2f\x2e\x71\x38\xbd\xcd\xcc\xff\xbd\x13\x55\x40\xe8\x79\x38\x4c\x9f\xef\xf0\x41\x2d\xe6\x9d\x98\xcd\x29\x29\x67\xf0\x75\x3e\x8e\x3b\xec\xcf\x27\x98\x79\xfc\xfd\x1c\xa6\xed\x43\x42\xf9\x6d\x63\xac\xa1\x53\x61\xf4\xd6\x6a\x22\xa1\x9f\x6f\x65\xbf\xbd\xbc\xec\xf4\xb4\xb8\x78\xd5\xa3\x90\x07\x03\x2f\xf5\xb5\x06\xf6\x75\x62\x17\x06\x51\xa2\x2c\x63\x97\x90\x50\xd7\x77\x3b\x04\x33\x4d\xbd\x8c\x0e\xba\x4d\xa5\x36\x84\x35\x2e\x0f\x1d\x98\x5f\x30\xcc\x84\x79\x37\x36\xea\x89\x53\x9d\x7e\x57\x40\x94\x3d\x2f\x98\xef\xc9\xf6\xdb\x61\x1f\xfd\xdc\x5f\xdf\xe8\xf5\x41\x94\x2d\x8b\x37\xd8\x3f\xe4\x8b\x37\x92\x95\x09\x92\x17\x49\x60\x06\xb4\xb3\x3b\xef\x3c\xed\xae\x05\xa3\x86\xf6\xce\xed\x22\x35\xd0\x63\xeb\x50\xbd\x74\xa2\x34\x61\x10\x76\xa5\x95\x2d\xab\x35\x69\x6e\x0e\x76\x8f\xe8\x83\x03\xf4\x6b\x23\x50\x63\xaf\x4d\xfa\xb8\x65\x09\xde\x06\x65\x45\xe7\x57\x40\x84\x24\xd3\x8d\x2d\x76\xcd\x2c\x88\x2d\x57\x75\x06\x72\x94\x91\x87\x68\x1d\xe4\x5c\xef\xde\x0d\xc2\xd2\xe5\x65\xe4\xdf\xbf\xa7\x7e\x37\xc9\xbf\xbf\xea\x2d\xca\x97\x6a\x02\x46\x55\x67\x19\xbf\x38\x58\xb7\x74\x47\x9a\x4a\xe5\x44\xed\x6e\x1a\xe0\x0a\xa7\x82\xe8\xf9\x2d\xba\xd3\x8e\xa7\x0c\xa7\xd7\xff\x64\xf2\xf9\x1a\x14\xd5\x2f\x0b\xea\xe3\xda\xc0\x85\x2d\x38\x31\xae\x0c\x33\xdc\x62\x31\x52\xa7\xec\xb6\x5e\x54\xd4\x10\x2d\xaa\x14\xa5\x90\x4f\x15\x65\xe4\x2f\xbf\x62\x58\x37\xa8\x5d\xc0\x50\xcb\x3b\x66\xff\xe8\xb6\xd5\x83\x51\xc7\x2c\x8f\x10\xc2\x8c\xce\xbc\x65\x66\xc4\x91\x57\x33\xab\xd1\x1e\x21\x77\x5f\x3f\xe7\x45\x80\xc7\x8c\xac\xcb\x1b\xfd\xee\xee\xf9\xb2\xf1\xe1\x89\xee\xad\x54\x87\x2c\x5f\xa4\x37\xe8\xa2\xc4\xec\xf2\xb0\xf6\xd9\x2c\x2e\xec\xc9\x93\x0d\x08\x30\x7d\x19\x98\x77\xf7\xbe\x0c\x0b\x53\x79\xfc\x1a\xd9\x9e\xd6\x49\x09\x27\xf1\xbb\xcf\xdd\x44\xfc\xc3\xc7\xfd\xb5\x28\xb1\xd9\xa5\xad\xf3\xf2\xa4\x79\x17\xc7\x4a\x74\xf0\x49\xd8\x9b\x66\xc2\x30\xa0\x7f\x4a\xcd\xdb\x2a\xb5\x1d\x09\x9a\xda\x8d\xe6\x3e\xe5\x0f\xa5\xe5\x02\x12\xfe\x41\x91\x84\xaf\x84\x53\xba\x15\x7c\x38\xc4\x54\x9e\xcb\x52\xde\x5f\x08\x96\x4c\xdf\x28\xcd\x13\x1a\xae\x74\xbb\x2e\x03\xa5\x72\x56\xf9\x87\xd7\xcd\xf3\xad\x56\xe3\xec\xe6\xfb\x5c\x2a\x6b\xfa\x31\xe7\xfb\x36\x12\xed\xdb\x95\xc1\x05\xa8\x14\x7c\x45\xc7\x90\x71\xb7\xc5\x3f\x34\x82\x64\xea\x88\xdb\xa0\xa8\x17\x4a\x4e\x87\xc0\xe4\xab\x15\x41\xe5\x85\x68\x53\xf5\x6e\xc2\x8e\x15\x96\x86\x40\xd6\x9a\x3b\x65\xfb\x11\x14\x27\xcd\x0d\xc2\x8d\x42\x4c\x0e\x52\x92\xef\x34\xd2\xc0\x25\xcf\x8b\x75\x72\x46\xcd\xe1\xc1\xb4\xca\x9b\x0b\x27\xe9\x05\x9c\xc3\x6f\x3d\x13\x6f\x69\x88\xb2\x4b\x3e\xf7\xdc\xe5\xad\x61\xdb\x94\xfa\xe0\x6a\x6c\x27\xcf\x8f\x49\x41\xe7\xc4\x1a\xb8\x0d\xb2\x3e\xf0\x46\x83\x7a\xf3\x9e\x98\xb8\x24\x77\xec\x8d\x0f\x17\x2f\xf4\x2c\x10\x13\x61\xed\xa9\x7c\x2e\x85\xa8\xae\x44\x5b\xd1\xe9\x46\x3a\xcb\x6c\xe9\xdb\xba\x4b\xdf\x7e\xd2\xa4\x1f\xfe\xb5\x1e\xe0\x26\x9d\x07\x3b\xac\x2a\x5e\x37\x46\x55\xc0\x4c\xef\x93\x73\xda\xd5\x83\x67\xc9\x5f\xa6\xed\xe6\x3a\xfc\x97\x01\x41\x80\x9d\x93\x24\x92\x54\x87\x86\x60\x6f\x1c\xca\xae\x8e\xe3\x8b\x92\x73\x01\x44\x6a\x93\x2b\x38\x35\xf0\xeb\xb3\x32\xb3\x9c\xf5\xb3\x9e\xb4\xc5\xf4\xa2\xe2\x2d\xe1\xf1\xab\x64\x1e\x1e\x2a\x8a\xd6\xdc\x28\x78\xe0\x6f\x7c\x0b\x74\x7e\x2f\xc8\x90\xa6\x97\xb5\xcd\x0d\xd6\x13\x0f\xce\xaf\x59\x7e\x27\x6c\x2c\x7e\x84\x8d\xad\xc5\x13\x09\x3e\x6c\xec\xad\xb8\x0f\xc9\x1d\xc3\x22\x3e\xe6\x7d\xd3\x17\xa2\x4c\x2e\x48\x25\x90\xf3\x3e\x9a\xad\x3b\x67\x90\x4f\xfe\xb0\x7c\xe5\x6e\x9d\x8e\xe1\xae\xd2\xc7\xa4\xee\xb2\xd7\x37\x55\x9b\xaf\x30\xa4\x4c\xc5\xc3\xb7\xca\x04\x61\xc3\xd0\x8c\xf4\x8c\xc4\xe4\x85\xa9\x1a\x02\xbd\x6c\x65\x76\x1b\x5a\xc2\x8e\x34\x96\x89\xb4\x6f\xc6\x62\xc8\x79\x19\x80\x4a\x1f\x9c\x9d\xd3\xc6\xf5\x7b\x20\xc0\xc5\x98\x1b\x75\x81\x74\x0f\x32\x4f\x75\x57\x41\x34\x4d\x32\x5f\x56\xff\xb4\xc0\xe7\x6f\xf0\x0c\xaf\xb9\xc7\xaf\x61\x05\xb9\x20\xfb\x57\x46\xfa\xaf\x2c\x03\x4b\x51\x75\x03\x51\x3d\xb2\x98\x9f\xc4\x9a\x6d\xfd\xa9\x26\x5c\x3f\x89\xd5\x8c\x4d\x26\xb9\x06\x4d\x6e\x6f\x5f\x4e\x35\x8d\xd3\x22\x66\x74\x2a\x54\x72\xd6\x46\xf0\xf7\xed\x0f\xfe\xde\xc0\xa5\x07\xae\x6a\x22\xa2\xef\xcb\x67\x93\xc3\xbc\x90\xdd\x90\x86\x69\x5a\xc8\xd0\x04\xfa\x81\xe7\xa5\x81\xaf\x6c\xc9\x0d\xc0\xde\x32\x08\xaf\x93\xab\x70\xb7\xca\x32\x04\x6f\x03\xf6\x96\xde\x16\xf3\x17\x1b\x9c\xed\x4b\x13\xa0\xd3\x89\x5a\xe3\x22\x4e\xdf\x27\x05\x5b\x0b\x5d\x8d\x83\x5f\x34\xe6\x41\x99\xe0\x7d\xab\x4f\x5e\x4b\xa7\xfc\xde\x21\xb9\x37\xc7\x4f\xb4\x58\xcb\xe8\x22\x6a\x42\x9f\x3e\x22\x9e\xca\xe0\x96\xb8\x62\xc5\x2c\x90\x56\xba\x83\x4f\x64\x00\x2f\x9f\x17\x60\x48\xaa\xa5\x73\xbc\x41\x39\x35\x69\xd8\x25\xab\xda\xda\xed\xe0\xed\xb5\xa3\xca\x37\x1e\xd5\x6f\x9e\x49\xc7\x25\x45\xb9\x10\xe7\x95\x84\x42\xda\x0f\x15\x0a\x09\x63\xc5\x6b\x2b\xdd\x85\xc3\x9d\x24\x19\xa2\x2a\x69\x36\xc3\x67\x51\x68\xb7\xd7\xa9\x39\x23\xd7\x1c\x90\x6a\x43\x60\xea\xe2\x9d\x6e\x74\xe7\xc7\x53\xac\xe7\xeb\xc2\x5c\x52\x66\x11\x8e\xf5\x0d\xb1\xe3\x01\x79\xa2\x1a\x48\x69\x1d\x95\xfe\xa8\x4f\x7d\xc1\x8f\xca\x76\x58\x27\xfd\xd7\x57\x5d\x8a\x4d\xbe\x12\xd2\x5f\x85\x22\xb1\x6d\x36\x5a\x5b\xeb\x68\xcc\xae\xe7\x29\xf3\x1e\xd3\xfb\x97\x1e\xd3\x4b\x6d\xfe\xa7\x6d\xd2\x9a\xf1\xcb\x56\x74\xc1\xaa\x77\x95\x5c\x99\x04\xf5\xe2\xe0\x3f\x67\x44\xb9\xa5\x10\xf9\xb3\xd2\x26\x5c\x70\x2e\xae\x48\x8a\x73\x6a\x12\xc7\xe0\x09\x78\xa5\xd4\x82\x16\x68\x5b\x91\xb2\x64\xa5\x49\x57\x6b\xe4\x19\xe4\x1f\x44\x2c\x1e\x04\x42\x52\x4b\xae\xdf\xb2\xd7\xf9\x07\x1d\xf8\x5d\x0d\x9e\x31\x84\xaf\x31\xe6\xfe\x4d\x19\xa2\xf9\xf4\xbb\xba\x78\xed\x2a\xc7\x74\x5a\x21\x39\x8c\xa8\x6c\xbe\x69\xc3\x36\x42\x0b\x07\x6e\x70\x46\x86\x20\x86\x2b\x62\x61\xf2\xda\xf0\xa4\xa5\xe8\xe0\x08\x4f\xb0\x29\x63\x49\x66\xa7\x87\x66\xc4\x91\xae\x9a\x23\x73\xa4\xae\x7b\xd4\x07\x21\xd1\xf5\x8d\x70\x70\x57\x53\x39\xdb\x76\x2f\x74\xfd\xbe\x0d\x86\xa4\xbd\x7c\x30\x1c\x27\x66\xbf\x6a\x6b\x77\xcd\xb2\x8f\x6c\xf5\x13\xc5\xdb\x78\xfc\x1f\x9d\x39\x66\x25\x9b\xbc\xda\xad\xab\x52\x9b\x60\x8d\x2b\x11\xae\xcb\xfb\x60\x1c\xe7\xe3\x6d\xc8\x52\xdc\xdd\x62\x4d\x2b\xa1\x83\x43\x92\x7d\x07\xfa\xca\x55\x71\x4e\x4d\xef\x87\x5c\x44\xf9\xcb\xcb\xb3\x36\x90\x04\xfe\x76\x9c\x0c\x78\x2e\x16\x4b\xd5\x05\xb0\xf5\xd6\x67\x2b\xb8\x3e\x3b\x28\x37\x44\x5a\xca\x19\x24\xe5\xf1\xdc\xbd\xdf\xf7\x5c\xed\x7c\xbe\x0c\x20\x61\xca\x3b\x9c\xfd\x79\x99\x67\x95\xd8\x91\x8d\x73\x34\x09\xf0\x79\x5b\x8a\x97\xf0\x3c\xa4\xc2\xef\x05\xbd\x18\xf5\xdf\xc3\x1f\x8b\x00\xd9\x47\xb2\x2f\x0d\x63\x50\x9e\x9d\xc5\xc0\x8e\x0c\x63\xe8\xc3\x6c\xd6\x94\x6e\x14\xd5\xb4\x8e\x99\x50\x8a\x38\xfc\x68\x1c\x7c\xc0\xfc\xc1\xe8\xf4\x21\x70\xc3\xe5\xed\x7c\x33\xee\xc3\x9d\x76\xe4\xfd\xa7\x95\xf2\x99\x57\x8c\x00\x47\xad\xa9\xd4\xed\x73\xda\x13\xee\xa0\xab\x6c\xf1\x4c\xb0\x83\xb2\xf7\x05\x37\x97\x80\x68\xc8\x0c\x77\x60\x70\xab\x1e\x1a\x69\xb2\xe4\x52\x53\xe0\x23\x04\x90\x64\xeb\x0f\xe1\x97\x76\x36\x76\xf4\x60\x64\x9a\x97\x29\x12\x4c\x42\xad\x0d\x1a\x4d\xc0\x9a\x6a\x18\x50\x56\x0e\xfc\xdb\xb5\x92\xd3\xba\x41\x50\xf2\xd5\x32\x2f\x96\x54\x4c\x9e\x4a\x9b\x54\xdc\xa7\x8a\x56\x9b\xe4\x6c\xda\x1d\x45\x3c\x40\x63\xce\xcd\x96\xc6\x8a\x3c\x7e\xed\xc0\xb7\xb8\xe1\xf7\xa4\x78\x1f\xcf\xd0\x5c\x19\xd3\x46\x33\x62\xb5\x1e\xd7\x3f\xa8\xf7\xf5\x64\x42\x3a\x1d\x1f\xda\x49\xf1\xfb\xfe\xdd\xc7\x38\xb2\xdf\x2f\x71\xa9\x77\x57\xdf\xfb\xb2\x74\x78\x14\xef\x77\xfe\x67\x4f\x82\x0f\xe3\xb3\x46\xff\x31\xbc\x4c\xb3\xc4\xe5\xe6\xb3\x87\x65\xd7\x6c\xf7\xf7\x60\xa4\x46\x9c\xdb\xbf\xe2\x74\x8b\x3c\x1f\x97\x60\x19\xa7\x03\xa1\x0b\xe8\xdb\x77\xd4\xdb\x4d\x68\xf5\x73\x99\xa6\xa5\x73\xb2\x69\x94\xe8\xa0\x23\x48\x34\xa3\x0e\x90\xe6\xad\x9f\xbf\x38\x40\x27\xe5\x94\xfa\xa9\xfa\x4d\x20\xa0\x91\x10\xb1\x6d\xc5\x13\x32\x40\x13\xb0\x73\xac\xe6\xc1\xfa\x29\xc0\x40\x22\x45\x1a\xb5\x14\xc7\xfa\xa6\x84\x27\xc4\x0b\xa4\x7a\x49\xc8\x4e\x34\x45\x2c\xc1\x63\xff\xbc\x2f\x46\x1d\x7f\x69\xa3\x7b\x52\x3c\x6f\x53\xe6\xe3\xe7\xdd\x52\x40\x69\x0b\x18\x61\xe9\x7b\x71\xf8\x7f\xf3\xeb\xc4\x46\x0b\x16\x7b\x59\xf9\x90\xe4\x7a\xfa\x08\xcd\x3e\x05\xc7\x08\x56\x1b\x82\x74\x3d\x28\xad\x73\xa5\x39\x62\xac\x21\x63\x25\x3a\xe6\xd0\xc9\x38\x06\x1f\x54\xb5\xcb\x73\x32\xd6\x24\x07\xfa\xa0\xcf\x4d\x9a\x7b\xea\x9e\xf4\xe1\x42\x84\xab\xce\x65\xe7\x6b\x68\xe9\x6e\x57\xb5\xab\x6a\x61\xc8\xf0\x8b\x5d\xaa\x71\x85\x05\xe1\x97\xe6\x9d\x46\x3d\x60\x4f\x38\x48\x14\x44\x25\x2e\xe0\xc4\x95\x7e\x24\x26\x2d\x39\x97\x64\x55\xd7\xfb\x3a\xa4\x63\x52\x77\xb0\x22\x51\x5c\xdb\xc1\x74\x9e\x13\x5e\x12\x7c\x78\x97\xd7\xbb\xcf\x9a\xe4\xfa\xf8\xcf\x2d\x15\x9b\xad\xf5\x15\x06\xf5\x4a\x29\x7c\x0e\x09\xed\x88\x6d\xa0\x75\xdc\x4c\x85\xe4\xe3\xfb\xe8\x9e\xa9\x53\xf2\xd2\xe0\x75\x92\x06\x85\x7b\x6e\x11\x9d\x9e\x5e\x46\xff\x96\x7d\xf8\xa7\x67\x87\x56\x23\x93\x69\xe9\x55\x40\xbf\x95\x62\x5d\x01\xdf\x62\xf6\x66\x93\xfd\x75\xd9\x2b\x2e\x12\xc0\x7f\xb9\x8e\xbf\x86\x83\xd1\x9a\x09\xaa\xd2\x91\xc2\x08\xba\x6e\x5a\xc4\x95\x80\x9e\xa2\x71\x37\x62\x8a\x51\x12\x5a\x0b\xec\x26\xa9\xd1\xfc\xfa\x39\xbc\x3e\x79\x44\x85\xb6\x2a\x7b\x9e\x39\xbf\x35\xe5\xe4\xee\x6c\x7d\xde\x6c\xe5\x9e\xe4\x2b\x50\x07\x93\x03\x91\x49\x15\xc6\x6b\x16\x7d\x9f\xcf\xa8\xe9\xd5\x21\x27\xa6\x0a\x26\xa8\x85\x67\x25\xdb\x77\x85\xe5\x9e\xe0\xb7\x85\x6d\xdc\xaf\xf5\x68\x6c\x2b\x14\xbd\x17\x4c\x26\x3a\xed\x9b\xe2\x69\x37\x55\xca\x43\x61\x7e\x3c\xdd\x84\x83\xc3\x23\xa3\xb3\xb6\xfb\xa4\x07\x83\x9f\x8d\xbf\xfd\x30\x57\xd9\xbb\xad\xf2\xbc\x5a\x44\xc4\x34\x5d\xb3\x71\xa0\xab\xb9\xc6\xbb\x71\x6c\xa1\xe5\x30\xba\x06\x26\x3b\x38\x10\x4f\xf9\xed\x6c\x7a\x7f\x0c\x35\xd3\xb7\xe1\x79\xab\xe3\x90\xf0\xf1\x45\x80\x7a\x15\x1c\x3c\xab\x9c\xe1\x1b\x7e\xe4\x95\x74\x62\x51\x17\x55\x93\x72\x32\x1a\xb9\x80\xfe\xde\xff\xb3\x92\x3d\x98\x19\xe6\x01\x23\xac\x2f\x0b\x7c\x18\x23\x1c\xf5\x94\x86\x6c\x21\xaa\x34\x0d\xcc\xf6\x24\x31\x5e\x30\xb2\xad\x30\xab\xb8\xa3\x8e\x82\xe3\x37\xb2\xf1\xf6\x8b\x2b\xc8\xf5\x59\x88\x4f\xaf\xc2\xed\xbf\x9f\x34\xd5\x94\x6b\xc2\xa3\x93\x1e\x3f\xa5\xfd\xc7\xff\x10\x33\x5d\x8c\x91\xd1\x30\xeb\xbb\xa3\x26\xc7\x61\x39\x1e\x2d\x7f\xdf\xa1\x8c\x2f\x29\x53\x08\x07\x0c\x03\x01\x20\x93\xed\x39\x9d\x6f\x5d\x21\x2f\x6a\x61\x05\xd5\x2c\xd0\x1b\xb4\x24\x45\xcb\x24\x7a\x2f\x50\x9a\xc7\xa9\x93\x82\xc7\xfe\xbf\x0d\xbc\x55\x54\xc8\xcf\x5b\xac\x3d\x77\x80\xf6\x07\x24\x50\x9f\xb0\xac\x62\x1c\xf5\x42\xf2\x69\xd4\xd3\xf7\x17\xed\xe2\xe5\x33\x8d\x16\x05\xe2\x76\x41\x29\x2f\xd4\x22\x5d\xe8\xef\xfc\xbb\xb3\x84\x59\x8f\xd3\x5b\x9b\xbd\x55\x89\x3f\x6f\xf7\x72\x0e\x3d\xc9\xe0\xab\x4e\x69\x85\x98\x98\x19\x41\x0a\x58\x8e\x59\x41\x13\xef\x73\x58\x30\x14\xf5\x29\xf4\x41\x59\x94\x91\xce\xbb\xcc\x23\xe2\xe0\x2f\xbf\xd8\xdc\x65\xe8\xee\x10\x32\x2c\x0e\xbf\x05\x10\xce\x45\x7a\x3a\xe0\x14\x7e\xf0\x2b\x0b\xa6\xf9\x80\x5c\x7d\x12\x66\xe4\x23\x9d\x91\x3e\x48\xce\x84\x6d\xeb\xf0\xb5\x71\x05\x0b\x4c\x53\xef\x11\xc2\xb4\x8f\xd2\x0e\x7d\x3b\xa4\xb8\xe4\x66\xc4\x22\xdb\xa3\x3e\xc7\xab\xe4\x62\xee\x5f\xfe\xd8\x4f\xb9\xbf\x48\x71\x4d\xdc\x21\x41\x5e\x1f\x6a\xb6\x64\xa5\x11\x48\xf5\xd9\xe7\xdd\x0d\xcd\x2f\x78\xa6\xa7\x3b\x5c\x3a\x45\x83\x71\x41\x42\xf9\xdb\xe7\x83\x91\x78\x07\xb1\x06\x29\x8c\x45\xfe\xa5\x61\xda\x80\x43\xbb\x2b\xf9\x29\xab\x3a\xde\x8a\x93\x16\x24\x41\x5e\x39\x41\xcc\x38\xd3\x13\x78\xb1\x7b\x25\xfa\xf0\xb0\x2f\x35\xd2\xf6\x82\xd0\x39\xba\xcb\x0a\xdf\x34\x53\xd9\x3f\xbb\xbd\x4a\xd4\xdf\x2a\xf6\xd9\xca\xb6\x58\x7b\x0a\xf1\x79\x20\x89\x29\x51\x48\xac\x85\x5f\x42\xa6\x85\x4f\x07\x03\x0b\x46\x45\x94\xaa\x21\x20\x94\xd0\xb4\x40\x7d\x98\x00\x72\x76\xe6\xca\x10\xa4\xdf\x51\xd2\x22\xeb\xfb\xf6\x34\x58\x7d\xee\x2a\x2e\x2d\xb4\x35\x91\x65\x84\x5f\x59\x36\x7a\x76\xe6\x14\x56\xba\xb7\x88\xd6\x2e\xe0\xb3\xa7\x9d\xf5\x45\x15\x10\x80\x41\xa9\xec\x18\x10\x3e\x48\x9c\xb6\x45\x04\x82\x06\x07\xa8\x50\xdf\x43\xa8\x05\x4d\xec\xec\xc0\x70\x42\x7d\xdc\xf4\x04\xea\x8f\x93\x9f\xae\x0c\xcb\xc8\xc1\xee\x0c\x11\x09\x84\xce\xfa\x26\xfa\x27\xee\x9a\x90\x63\x94\x1d\x8e\x19\x58\xb7\x1b\x17\x8b\x55\x56\x54\xbb\xc4\xe4\x29\x37\xfe\xa8\xd1\x28\xd8\x93\xde\xc5\x69\xbb\x68\xb7\x10\x29\x15\x65\x2c\x9a\x36\x32\xed\xfa\xb6\xb8\x59\xf8\x16\xb9\xc0\x12\xac\x13\xef\x72\x51\x48\xfa\xb4\xec\x59\x99\xd4\xed\x7d\x2a\x53\x45\x0b\xfb\x19\x9c\x38\x20\x48\x7b\xea\x02\x2a\xa3\x9d\x19\x81\x49\x88\x20\xbb\xcf\xc3\xc3\x2a\x1f\x4f\xf3\x16\x08\x67\x86\x2e\x66\xe4\x22\x29\x63\x75\xa8\xdd\xa3\x0a\xb1\x3c\x88\x3a\xa5\xec\xc7\x11\x87\x50\x9f\x42\x8a\x40\xfc\xbc\xad\xa9\xe4\x42\x27\xb4\xca\x95\x83\x91\xad\x0c\xf2\xf3\x57\x7e\xa5\xc3\x11\x67\x2a\x84\x1f\xa4\xbf\x6f\x86\x21\x69\xcc\x28\x65\x06\x16\xa0\x15\x5a\xf9\x7e\x68\x8f\xce\x4b\x7e\x14\xd2\x04\xf1\x8b\x24\x71\x02\x5f\xc7\x8a\x11\x88\x1f\xdd\x8f\x91\xc0\x58\x9f\x36\xbe\x25\x1b\x4e\xaa\x34\xa1\x2d\x42\x6e\x0c\x74\xdb\x73\x64\x13\x4f\xa4\x82\x28\x7a\xe1\xb6\x0b\xfa\x4b\x40\xa6\xa5\x8f\x19\xc1\xa4\x9e\x83\x87\xd6\x0a\xde\x35\x5c\x6d\xb3\xcf\x47\x1d\x94\xd8\x94\x6e\x42\xfd\x29\xba\x21\x75\x7e\xea\x29\xc7\x77\x4c\x5b\x3f\xc4\xbc\xb1\x2b\x71\x13\x59\x8c\x56\x0e\xa9\x43\x19\x70\xb7\x35\x1b\x97\xd3\x9d\x43\x78\x05\xcf\xff\xa5\xa8\x61\x6d\xc1\x53\xd3\xfa\x23\x3f\x9b\x91\xc7\xf1\x92\x61\x36\x42\x22\x5f\xed\x3d\x0e\x7e\x67\x95\xd3\xef\xee\x24\x9a\x11\x5e\x4e\xdd\xee\xa6\xda\xee\x1c\x6e\xc8\x86\xa0\x3f\x0d\x5d\x4f\xbb\x19\x62\x91\x27\xc8\x04\x29\xa1\x5c\xa4\xe0\x51\x1f\x47\x62\x9d\xa9\x56\x7f\x8b\x32\xd8\x0a\x81\x45\x06\x1c\xf3\xcc\xf1\x51\xc6\x14\xbf\xe4\xaa\x06\x95\x33\xf2\x94\x0c\x35\x9a\x29\x72\x97\x04\xa7\x79\x57\x1a\x3a\x15\x30\xb2\xd5\x8f\x9c\x21\x06\x72\x6b\xe6\x2b\xa5\xc7\x5e\x96\xe2\xe6\xcf\x26\xb4\xa5\xcd\x84\xcc\xc8\x67\x9c\xcc\x10\x14\xb9\xef\x72\x58\x3f\x54\x25\xde\x13\x7b\xdc\xa6\x91\xf8\x9a\xf8\xef\xb1\x47\x47\xd9\xc3\x84\x1d\x88\x8f\x60\x11\x5d\x87\xff\x7c\x62\x7f\x27\x54\x4b\xce\x8f\x5b\xd7\xbe\x0d\xc7\x6f\x5c\xcb\xc7\xcd\xc6\x12\x75\xf3\x69\xad\x6e\xf3\x05\x7d\x91\xb3\xae\xa0\xb4\xae\xc1\x97\x5e\x2d\x76\x31\x7c\x4f\x3f\x75\xa2\x27\xd6\xa3\xc8\x52\xba\x64\xfe\xdb\xf3\x1c\x10\x95\xaa\x20\xaf\xee\x03\xcf\x62\x0a\xc2\x90\x31\x2a\xcf\x5f\xa2\xeb\x67\x9d\xae\xa4\x96\x8b\xf4\x81\x40\x1c\x54\x72\x46\xb8\xce\xd3\x4e\xfd\xa5\xd2\x8f\x19\x6b\x9b\xdb\xdd\xee\xf3\xa2\xbc\x2f\x40\x5f\x4b\xf7\xf0\x3b\x86\xf2\xd9\x43\x9c\x24\xb3\x71\xa5\xb8\x8b\x55\x42\x9f\xe0\x63\x72\xbc\xf6\x34\x96\x7f\x56\xc1\xee\xe6\x0a\x5f\x03\x37\x9a\x86\x2f\x52\xf2\x46\x55\x62\x74\x4a\xe8\xa3\xb0\x1f\x8d\x8a\x3f\x56\x4e\x87\xd1\x30\x35\xb9\x01\x89\x81\x46\x1a\x41\x51\x8b\x75\x1b\x8a\x52\xbf\x2c\x22\x31\x5d\x2b\xcc\x45\x5c\x6d\x48\xdd\xd2\xf1\x3e\x44\x55\x93\x0a\x24\x45\xcd\x98\x64\xd8\xda\x85\x7c\x4c\x17\xe4\x45\xb3\x16\x83\x94\x51\xd9\x48\x31\xdd\xb0\xe6\x9a\xec\x93\x87\x50\xf7\xaa\xa9\x52\xe3\x10\x9b\x40\x1e\x95\x4e\xd3\x4e\xde\xc0\x0c\xf6\xa8\x1a\xba\xa9\x45\x4a\x12\x32\xf1\xef\xa9\x9d\xd7\x6d\xa2\x1d\x58\xfc\x5b\x5e\xdb\xe2\x06\xda\xf9\xed\x59\xdc\xd3\xa0\xcf\x39\x61\x76\xe6\x93\x6d\x6d\xf4\x69\x2e\xc4\xb0\x70\xfc\x9f\xed\xdc\x4b\x58\xf7\xe2\xdf\xe5\x0c\xb1\xf6\xe7\xf2\x8b\xdd\xdb\x26\x2f\x74\x18\x77\x58\x61\xbc\x1b\x3e\x2a\x68\xe9\x0a\xb0\x7f\x9c\x43\x2f\x68\x16\xd1\xae\x7c\x16\x72\x96\xcf\x6e\xdf\x78\x4d\xf5\xde\x03\xb9\x47\xba\x25\x53\x15\x2f\x2a\x84\x69\x74\x24\x9b\xfc\x60\x33\x0f\xa5\x97\x3f\x72\x36\x15\x7f\x35\x13\xd9\xc3\xaf\x05\xbf\xba\xe3\xf4\x13\x60\xc0\x53\x6c\x1d\x49\x16\xa1\xea\x7a\xfe\x03\x8d\x9b\xa2\xa9\x69\x97\x07\xf5\xd4\x1e\x72\xcc\x42\x45\x50\x27\x26\x32\x80\xb5\xbf\x47\x70\x8a\x52\x3e\x1a\x06\x69\xca\x91\x89\xf5\xa9\xbe\x5f\xee\xee\x3f\x9e\xbf\x79\x28\x89\xdf\xd2\x50\x58\x8c\xee\x5a\x37\x9d\x75\xfc\x78\xe9\xc9\x35\xf9\x83\xdd\xc9\xb4\xf2\xc0\x25\xb7\x18\x54\x66\xdf\xfb\xcd\xf6\x36\xbc\x86\x44\x81\x67\xf2\x9c\x4f\xc4\xfc\x3a\x05\x16\xc1\xe3\xf7\xec\x86\x5f\x9d\xdf\xfe\x20\xd3\xaa\x34\xf9\xcc\x01\xf5\x07\x86\x85\xf3\xe7\xbf\x52\xbf\x14\x3c\xd2\x63\xd4\x4b\x4a\x6a\x79\xaa\xfd\x9f\x62\x9d\x60\x3f\x3c\x31\x97\x85\x2a\xb5\x62\x9f\x97\x6a\x16\x25\x1f\xa3\x50\x17\xe6\xf6\x41\x71\x09\xe6\x6b\xa2\xd9\x42\x3a\xa3\x80\x8c\xd4\xf6\x5b\x33\x18\x48\x73\x42\xba\x42\x73\x32\x4a\x8d\x5a\x66\x7d\x91\x6c\x79\x35\x2f\x81\xc8\x03\x71\x54\xcb\x6c\x6f\x76\xff\x9d\xfc\x56\x8b\x67\x07\xe6\x1f\x2b\x3e\x01\xa2\x35\xfc\x47\xc2\xbe\xd7\xad\xc5\x0f\x03\x96\x37\x5f\x94\xef\x03\x2a\xac\xfa\xec\xe9\x74\x76\x38\x93\xb6\x78\x7a\xa6\x67\x10\x95\x3b\x8d\xfc\x1e\xe1\x5e\xb1\xaf\x38\xbb\xc7\x04\x4b\xfc\x4b\x06\x2a\x5a\x60\xb6\xe1\x86\x7b\xc3\x8c\xd4\xc7\x3f\xb3\x59\x71\x31\xaa\xb8\x1b\xe5\xd9\x19\x6d\x0f\x1c\xf9\xd5\xa9\x0e\x86\xba\x6e\x9f\x1e\x5c\x82\x8f\xab\xd6\x20\x4f\xc3\x07\x30\xfa\xc0\x75\x5b\x32\x43\x61\x7d\xa7\x31\x91\x57\x35\x94\x02\x0d\x50\x59\xdb\x39\x6c\x32\xf2\xed\x5c\xcd\x96\x7e\x6c\xa1\x51\x6f\xc3\xd5\xb7\x58\x95\x94\xc8\x43\xc8\x7c\xd4\x24\x30\x07\xfc\x99\x6a\xe8\xed\xac\xe3\xf6\xc3\xa2\xde\xd4\x16\x43\x3b\xf3\xd9\x52\x87\xe2\x9d\xde\xd3\xf5\x12\xd1\x74\xc0\x3c\x63\xe3\x4b\x03\x59\xaa\x08\x1c\xed\x9a\x2a\x6a\xc2\x27\xfc\x63\x8a\xc2\xce\xd0\xfd\x77\xe6\xdc\xd3\xac\xc6\xbb\xb2\xef\xb4\x46\x8a\x84\xf2\x38\x71\xe2\x87\x56\x3e\x40\xec\x92\x23\x66\x50\xdd\x26\x13\x4a\x84\x47\x55\xea\x66\xd6\x00\x91\x48\x67\x1d\xe0\x3c\xba\x5d\x76\x15\xf9\x35\x5e\x36\xc8\x0f\xb6\x43\xd5\x86\xab\x1b\x9e\xa7\xce\xf0\x74\x54\xdf\x4a\x76\x8e\x7b\x63\x0b\xe3\xfa\xe2\x8d\xe4\x06\x69\xf2\x3e\xb3\x1d\xb0\x7b\x09\x08\x0e\xba\x5d\x2a\xc8\x0b\x4c\xba\xfb\x49\xd9\x2c\xb6\x29\x38\x16\x1b\x39\x74\xd3\x63\x4b\x53\x76\x6f\x8b\xe9\xdc\x46\x53\x2b\x8c\x3f\x38\x06\x1c\xfd\xe5\xff\x5b\x98\xd9\x96\x56\xff\xa4\xfa\xec\x1a\xbb\xe8\xda\xce\xbe\xf8\xe0\xe8\xd1\xda\xcc\xa0\x8a\xa2\xf8\x76\xce\x3a\xff\x92\x87\x38\x93\x7e\x7e\x0a\x3f\xe2\x77\x9c\xd7\xe6\x49\x50\x6b\x9a\x7d\x3a\x1a\x62\xe7\xf4\x92\xe2\xca\xb4\x96\x76\x5b\x94\x62\xc1\x3b\xf6\x97\x79\x6d\x88\xb9\x81\xdc\x3e\xc6\x0f\x46\xa0\xf9\x56\x8b\x5f\x9d\x8a\x92\xc3\xad\x54\x2c\x7a\x8b\x27\x89\xcb\x15\xed\x61\x4f\x3d\xf0\xd9\x23\x5b\x8c\x56\xfc\xa4\x40\xb1\x9d\xc4\xdc\x6d\x90\x63\x17\x7a\x3a\xd2\xae\x4b\x5c\xfe\x58\x92\x49\xaf\x6d\x87\xd8\x68\x39\x89\x99\x8d\xa8\x0b\xe0\xe2\xf7\x67\x50\x09\x30\xf0\xb9\xd5\x09\xa9\xd5\x35\xe0\x2c\x3f\x2d\xb1\x2a\x5d\x6c\x79\xb1\x37\xa7\x5a\xf2\x30\xde\xd9\xa7\x65\x0b\x30\xa6\x6b\xf7\xdb\x59\x19\x7e\x2e\xf1\x1e\xb0\x69\x98\x49\x28\xca\x5b\x08\x7c\x3e\x4b\x56\xc2\x5e\x41\x50\x53\x55\x0e\xc0\xac\x23\x00\x06\x5a\xee\x4b\x54\xe2\x7a\x69\xaa\x5c\xef\xb5\x30\xc6\xdb\x2b\xfb\x20\xcd\xad\x96\x95\x3b\x63\x39\xa6\x37\x2c\x6b\x41\xd2\x6a\x29\xa7\x5d\x8b\xa2\x20\xa9\x99\x33\xf0\x95\xa9\xe3\xd3\x93\x1c\x77\xfd\x15\xdd\xf0\x39\x74\xce\x05\x23\x7a\xfc\xae\x3c\xfe\x08\x9b\x38\x1c\x89\xcb\xc8\x84\xfc\x42\x64\x67\x0b\x15\xa9\x64\x7e\xfb\xb7\x36\x70\x61\x72\xf9\x8d\x42\x43\x5f\x1b\x71\x42\xbd\x80\x97\xc4\x3b\xbd\x66\x58\x1b\xa6\x1a\x38\xa1\xa8\x85\x96\x94\xec\x82\x7c\x51\x2d\x0c\xf1\x91\x73\x3a\x32\xa9\x2b\xf1\xcf\x15\x53\xd3\x3c\x88\x3c\x3f\x07\x0d\xd6\xd0\x0e\xe2\x67\x43\x9b\xb3\xa6\x0e\x72\x33\xb6\xc7\x48\xd7\x67\x09\x62\x89\xfe\xc4\x3a\xf7\x41\x29\xbc\x7c\x66\x42\x0e\x41\xb8\x41\xc9\x84\xcf\x5f\x6f\xa8\xeb\xe5\x05\xef\x00\x2a\xf4\xc2\xb3\xed\xc6\xad\xe6\xd3\xe7\x6c\x28\x8b\x8d\x93\x39\xd1\xbc\x05\xe4\x58\x91\xc7\x86\xed\x70\x0f\x24\xeb\xab\x9f\xa5\xf2\xa3\x87\x4a\xe2\xbc\xbd\x8e\x96\x37\xe3\x02\x71\x6a\x14\x03\x79\x0b\xaa\xd8\x68\x21\x15\x38\xbf\x54\xfc\x61\xfe\x19\x4d\x98\x18\xe4\x2c\xaa\xfc\xa0\x69\x49\x99\x5b\x94\x82\xe1\xef\xca\x99\x53\xf1\x93\x17\x71\x38\xee\x86\xf8\x4c\x92\x19\x76\x36\x39\x5d\xc6\x72\x51\x41\x8b\x92\xef\xd1\xf9\x73\xcb\x31\x61\xed\x22\x81\x15\x50\x28\xee\x10\x7f\x98\x97\xe6\x83\xf5\xb6\x9b\x87\x5b\xe5\xbe\x2c\x8f\xe6\x5b\x9e\xc0\x72\x96\xff\xbb\xff\x55\xd7\x5b\x56\xbc\xec\xa9\x79\x2c\xed\x1d\x9c\x3f\x96\xce\xe4\x72\x77\xcd\xe2\x8b\xb9\x5d\x82\x77\xeb\x80\xfc\x96\x5c\xd8\x5a\xa1\xd7\x5e\x15\xf2\x0e\x0b\x74\xa2\x49\x5a\x6c\x2c\x74\x8e\x80\x49\x9b\xcd\xc0\x0e\x26\x38\xb2\xa8\xb8\xfd\x00\xa3\x2b\x89\xa5\x32\x16\xa4\x9c\xb6\x06\x52\x39\x1c\xa5\x47\x78\x1c\x33\x35\x53\x18\x0c\x3c\xbb\x04\xd9\x3f\xc9\x71\xf1\x10\x24\x36\x45\x88\xf2\x8a\x04\x31\x35\x96\x2a\x4c\xb7\x3a\xf9\x11\xec\x65\x59\xe0\x80\x60\x23\xe7\x72\xb9\x4b\xbc\xed\x41\xa3\x56\x62\x67\xae\x4b\x26\xa7\x4e\xb3\xe1\xd6\xb1\x82\x62\x61\x32\xe7\xe6\xe8\xe2\xa6\x42\xae\x95\x7d\xf5\xb9\x6a\x39\x1a\xe5\x4d\xd5\x8f\xa7\x00\x81\xdd\x0d\x02\x53\x61\x41\x42\x7c\x53\xe2\x99\x8e\x70\x10\xfb\x18\xfa\xfa\x1b\x78\xcb\x79\xd5\x86\x1e\x1f\x3e\xae\x44\x9b\xd6\xec\x80\x2b\xa5\x49\x8a\x9b\x3b\x62\xdb\x53\x94\x5d\x0a\x11\xc7\xea\x37\x09\x4a\x46\x06\xeb\x25\xdd\x21\x48\x32\xf8\xb2\xd6\x13\x70\xa6\x71\x67\x48\xde\x58\x25\x1c\x88\xe2\x9b\xeb\x67\x3d\x99\xad\x55\xde\x23\x78\x6f\x0b\x84\x5d\x54\x3d\x69\x7d\xce\x8c\x0e\x4c\xae\x2d\x40\x93\xe1\x1e\xe2\xd3\xbd\x63\x4e\xe2\xd9\xc5\x2f\x32\x53\x43\x64\x6e\xe7\x89\x38\x7d\xef\xc6\xdf\x9f\xc0\x4f\x0f\xba\xb6\xfd\x3c\xcf\x94\x3d\xae\x8c\xc8\xc2\x93\x90\xf7\x78\xe6\xfb\x4c\x4d\x5b\xdc\x23\xe8\x92\x32\x0f\xb4\xd9\xc1\x88\xbf\xd9\x40\x11\xaf\xbf\x79\xad\xae\x24\xd0\x41\xd4\xe7\x61\x62\xe1\x5c\xce\xc9\xcb\xe2\x9d\xe3\x66\x55\x6c\x6e\xf4\xa0\x58\xf4\x6b\x67\x44\x3d\xe3\x15\x63\x72\xb8\x06\x65\x85\xba\x68\x53\xf2\x3f\x87\x2b\x98\x2c\xd9\x07\x75\xf4\xc8\x4c\x35\x2b\x58\x40\x97\x98\xa0\x97\x14\x09\x6b\x51\xa3\x11\x6f\x77\x82\x62\x0a\xcd\x6b\x9f\xd8\x6f\x33\x69\x65\x32\x22\x99\x80\xed\xdf\x38\xad\x89\x01\xaf\x4b\xeb\xa0\x21\xd5\x65\x6d\xde\x9a\xf8\xa5\xc5\x77\x07\xfe\xec\x2a\xf1\x3e\xff\xf9\xa8\x13\x1e\x5f\xc6\x4a\xc9\xb1\x70\x99\xff\x78\x2f\x9a\x79\x9e\xcc\xda\x2f\xeb\x42\xe5\x11\x34\x4d\x60\xf3\x5e\x7c\xb8\xb6\x35\x34\x04\x97\x8c\x70\x45\xcf\x1d\xe7\x7f\xb1\xd4\xf2\xdb\xc4\xfb\x64\x4b\x61\x3d\x29\x6d\x3e\xc6\x54\x90\x55\x68\xd4\xe8\x98\x7c\x82\x61\x3e\x88\x99\xf4\x9a\xfb\x47\x83\xde\x06\x78\x3d\x2a\xd1\xf4\x78\x7a\x2c\x3e\xcf\x02\x41\xfc\x4f\x11\x15\x58\x4d\x94\x49\x88\xb2\x62\xa0\xbc\x0b\xdd\x5c\x36\x62\x35\x4c\xb8\x68\xa4\x01\x94\x8c\x87\xc0\xdd\x96\x6f\xba\x3a\x4b\xd6\x38\xa9\xc6\x34\x8b\x90\x6f\xfd\x51\xb7\x7c\x6f\x2c\x72\xee\xec\x3a\xae\xf8\x99\x5c\x21\xbc\x6d\x07\x8f\x88\xdf\xd5\x94\xcd\x7d\xb6\x0d\xd9\xfb\x44\xc8\xbd\xe9\x2c\x9b\xe3\xe9\xd6\x82\xed\xad\xa0\xc7\x63\xf3\xc1\xc0\xaf\xf6\xe4\x14\x60\xfc\x98\xa6\x55\x88\x60\x89\x80\x66\x08\x78\xd4\x8e\xeb\x00\x58\xec\x06\xf5\xc8\x94\x31\x3d\xac\xb0\x24\x59\xe6\x19\x22\x91\x51\x2c\xe7\x83\x6a\x13\x7f\xd4\xfb\x83\xb2\xc0\x59\x2b\x1b\x1f\xaa\x39\xff\xc6\x24\x95\xba\xad\x56\x68\x2a\x24\xba\xe6\x67\x9f\xbb\xac\x81\xbe\xfb\x3a\xae\x77\x5d\x9d\x9b\x0a\xeb\x08\xe2\x17\x95\xe0\xbf\xd8\x2a\x7b\xe3\xdf\x59\xcb\x8b\x96\xf1\x0a\x54\xea\xcb\x8f\xd8\xfd\x82\xd9\xba\xfb\x1d\x79\x68\x0b\x58\x74\x99\x3d\x44\x86\x4e\xe7\x28\x7a\xaa\xc1\xf7\x5f\x89\x52\x24\xf9\x9e\x08\x63\x27\x71\x05\xe9\x64\xcc\xa2\xe0\x4e\xcd\xda\xd0\x5d\x4f\xc4\x66\x33\x49\xef\xd1\x6b\x29\x78\x85\x96\x38\xd3\xb2\x93\xc9\x68\x9e\x52\x1f\xdc\x6b\x89\x98\x73\x4f\xc0\xa8\x32\x94\xc2\x68\xb8\x66\x4a\x59\x89\x74\x7c\x5b\xb5\xc8\x8c\x63\xb2\x73\xf8\x5c\x43\x83\x77\x65\x85\xf0\x96\xfb\x6c\x9d\x8d\x64\x70\xba\xdf\x14\x3e\x19\x10\x4c\x58\xa2\x5c\xe4\x8f\x83\xb7\xd9\xd1\xd0\xd6\x9c\x39\x60\xc5\x8d\xba\x13\x5d\xbc\xee\xee\xc2\x98\x35\xe6\xbb\xe0\xc1\x5e\x06\xb5\x33\xa6\x21\xb6\xb7\x5c\x3f\xb6\xda\xed\x49\xce\xae\xcc\x45\x52\x6f\xd4\x1e\xf2\xd4\x98\x2d\x9b\xfd\x04\xf9\xb3\xd3\x2f\xf7\x58\x1a\xce\xcb\x3d\x15\x62\xb2\x2a\x60\x1a\xd7\xc4\x28\x44\xe6\x97\x95\x14\x8c\x18\xad\xbd\x00\x99\xa8\x7e\xdf\x2d\x49\x7d\xf2\x53\x4f\x0b\xbd\xa6\x2c\x1d\x4d\x57\x19\xab\x25\xa8\x4f\x09\xec\x7a\xcc\x1d\x07\x5a\x72\x58\xbc\x53\xd7\x9e\xc7\xf7\xa4\x39\x80\xa4\xb2\xa6\x89\x26\xa7\x5c\xf9\x17\xcf\x34\x11\x7c\xf0\x79\x14\xe8\xd4\x05\x9d\xde\x88\xa6\x68\xf0\x0c\x5b\xf5\x4a\xe5\xed\x3c\x51\xa2\x92\x9a\x5a\xe1\x89\x95\x78\xe9\x4a\x2a\x7d\xfe\x35\x0a\xfd\x9a\xf6\x3a\x1a\xa8\x19\xa6\x1d\xf8\x04\xc8\x5c\xad\xc4\xcb\x1c\xb6\xa1\xce\x51\x94\xc0\x2f\x00\xe8\xc6\x06\x9f\x1d\xf5\xb7\xe3\xa9\x2e\x8d\x66\xea\x6b\xad\xf0\x8b\xbd\xeb\x4d\xbc\x9d\x4f\xde\xb1\xae\x53\xb9\xc0\xb1\xff\x58\x34\x8e\xd6\xf9\x7c\x7a\x29\x65\x05\x63\xbd\x2a\xac\x9b\xe7\xf7\xf0\xf8\xe2\x4c\xa6\xfe\x8c\xdf\x19\x79\x20\x0a\x5d\xbb\x45\x76\xc9\xa3\x19\x76\x5f\x8e\x32\x6b\xc8\x60\xeb\xa4\x21\xa3\x80\x0e\x2f\x0d\xa5\x00\x73\xee\xcb\x68\xc0\x86\x85\x50\xba\xa4\x90\x12\x58\xec\x3f\xbc\xcf\xb4\x46\x85\x70\x88\x69\x47\x8e\x57\xc9\xec\xce\x99\x70\x7d\xab\x52\xec\xc1\x37\x20\x28\x51\xf0\xb4\xf1\x08\x25\x35\xd8\xc0\xe4\xab\xe4\x97\x6b\x06\x1e\xf2\x2e\xed\x08\xce\x8e\xe6\x16\x5b\xdc\xef\x0e\xf2\xee\x5a\xd2\x11\xda\x62\xdd\xe6\x2f\x07\x5c\x72\x76\x76\x5d\xec\x6d\x6e\xea\xb6\xdf\xe9\xce\xce\x3a\x9e\xa8\x87\x1a\x4e\xa8\x59\x8f\x52\x6b\xd4\xd3\x44\xc8\x10\xe2\xc1\xe1\x22\x1a\xf1\xc8\x95\x29\x3a\x2e\xed\x87\xed\x37\x8e\xc5\x5e\x6e\x21\xea\x55\x99\x05\x96\xa8\xa9\xac\x4c\xb9\x30\xa4\x32\x91\x20\xa0\xbe\xf7\x0a\xb7\x9e\x33\xee\x21\xcb\xb3\x4a\xb1\xba\x14\x6f\x82\x68\x73\x67\xfd\xda\x5f\x40\x58\x85\x5d\x07\xe0\x78\x5e\x29\xb6\xca\x7f\xbd\x09\x55\x49\x98\x5f\xc5\x89\x10\x5a\xb0\xa0\x54\x6e\x26\x15\x45\xbd\x56\x19\xfe\xda\xef\x25\xd6\x55\xed\xcf\xd6\xff\x7d\x66\x70\x86\x91\x5b\x56\xd4\x79\x8a\x14\x7c\x3c\x71\x44\x64\xf0\x76\x05\x43\x2d\x71\x56\x81\x0a\x97\x6b\xed\x39\x19\x18\x9f\x0b\xb3\x41\x9b\x7e\xb1\x29\x20\x40\x43\xa0\xc0\xaa\x1a\xa9\x9d\xab\x3d\xd7\xef\xb3\xb2\x2f\x48\x05\xce\xdb\xbd\xfe\xed\xa0\xee\xa9\x12\xf1\xf3\x67\x3d\xab\xa6\x68\x33\xc4\x0b\xa7\x40\xb0\x79\xb3\x4e\x6d\x21\x5d\xb7\xe6\xd3\x74\x93\xc3\x5b\x0a\xf2\x2b\x79\x68\xb0\x18\xa6\x7e\x38\x6d\x95\x70\xf5\x8a\xa5\x9b\xbc\x5f\x50\xbf\xb5\x8e\x00\x73\x38\xee\xc3\x8b\x99\x6f\x99\xac\x41\xc3\x3f\x04\x6a\x3c\xe9\xa6\x02\xf7\x01\xd6\x35\x3e\x1b\x82\x64\x91\xee\x24\xf5\xbd\xd0\x8a\x67\x18\x76\xbf\x17\xd9\xd9\x59\xdd\x23\xf5\x23\xa3\x59\x02\xbc\x78\xbe\x67\x3a\xc9\x68\xed\x1b\xe6\xaa\xf5\x61\x81\xb7\xa5\xfd\xed\x8e\x00\x6f\xeb\x84\x67\xdf\x0c\xb8\xd9\x45\xbf\x68\x0b\x18\xa4\x77\x27\x3f\x58\xcf\x76\x1e\x89\x28\x01\x41\x89\x73\x12\x6e\xe5\xa1\x87\x62\xd7\xeb\xb0\x66\xa2\xe9\xfc\x89\x4f\x50\xb7\xfc\xd9\x23\x01\x11\x87\xc2\x55\xe7\x13\x45\x05\x86\xc4\xfb\x82\xcf\x0e\xb4\xa4\x2b\x58\x30\x8a\xdc\x10\x9f\x17\xe6\xb2\x81\x5f\xaa\x8e\x77\x22\x10\x94\xd6\xa9\xca\xe5\x40\x85\x75\xe4\x65\x95\x74\x5f\x1d\x5c\x29\x71\x91\xb6\xaf\x75\x84\x34\x34\x85\x0b\x26\xb7\x0c\x39\x6b\xfc\x3b\x34\x27\x4f\xa4\x5e\xbd\x04\x55\x83\xb2\xf3\x6d\x22\x22\x06\xe6\x96\x63\x97\xb2\x9c\xcd\xd2\x70\x7f\x91\xa9\xc3\x5a\x2e\xef\x41\x67\x89\x79\x22\xfb\x05\xcd\x22\xbf\x15\x8c\x97\x73\xd0\x98\x4a\x48\x84\x33\x91\x2c\xad\x5e\x8d\xba\x09\x73\xf9\xbb\x4e\x46\x10\x45\xb2\x4a\xb5\x3a\x9d\x7b\x41\xbc\x0e\xe5\xeb\x9a\xec\xc9\x7e\xdf\xdc\x1e\xd8\xeb\xd6\x85\x4a\xc3\x35\x9e\x4b\xfd\xe9\x4e\xb6\x8f\x9d\xbe\x6f\xfe\xd7\xf2\xfe\xec\x69\x42\xbf\x05\x7e\x49\x00\x0b\x7b\x7b\x06\x59\x87\x86\x75\xc0\x35\xcb\x62\x0d\x55\xd1\xc4\x8f\xe0\xb0\x5d\x61\x57\xaa\x63\x29\x52\x02\xbe\x53\xc9\xad\x58\x70\x22\x4a\xcf\x3a\xe3\x1c\x9b\x20\xc3\x2e\xe2\xac\xd6\x04\x42\x58\xb8\x5d\x79\x5f\xf7\x59\xd1\xdb\x2e\x28\x9d\x56\xd8\x22\xad\x35\x29\x6d\x69\xf2\x7a\x13\x69\xe8\x4e\x3e\x12\xc8\x66\xf0\x2f\x26\xc3\x7f\xf7\xee\xd0\xb4\xb9\x1c\xa9\x83\x35\x4d\x20\x7c\x6d\x26\xa3\x06\x38\xd1\x21\xe5\x5b\x06\xeb\x1e\x8c\xd1\xe2\xe5\x33\x7f\x7e\xad\x5d\xfe\x3c\x7a\xd9\x7b\x5f\x00\x53\xe0\xe4\x2b\xb9\xbe\x11\x77\x88\x81\x8f\xcd\x13\x0a\xb1\x7c\x98\x1e\xf5\x5f\x4c\x1b\xa3\xe7\xf3\x30\xdd\xf9\x95\x78\xe1\xf5\xd9\x9a\x29\xe0\x4c\x78\x14\xb6\x55\xed\x1a\x4d\x22\xff\xaf\x88\x0b\x47\xba\x06\x99\x8a\xe0\x2b\xf1\x5f\x11\x34\x1d\xbc\xf7\x5e\x76\x87\x46\xea\xf3\xf7\x9e\x13\x09\x16\x23\x70\x45\x19\xf4\xe4\xa6\x8a\x14\x06\x46\x45\x89\x6c\xb7\x2b\xf6\x17\x15\x4e\x92\xa2\xf4\xb2\x4a\x51\xd8\x39\x85\x6b\x9b\x86\xd5\xc4\x7a\x32\x01\x32\x3f\x67\xf8\x15\xdd\xb1\x59\x5e\xd6\x51\x0b\x94\xb3\x16\xe6\xc8\x30\x82\xbe\xa8\x4a\x84\x24\x3f\x75\x1c\x32\x30\x99\x52\xcd\xca\x63\x23\xe5\xf5\x89\x7a\x2a\xae\x5d\xec\x0d\x0e\x81\x7e\x27\xf3\x5a\x19\xd1\x97\xbb\xbd\xb0\x4b\xe1\xd5\x60\xf8\x1e\x6a\xc0\x29\x5f\x65\xb3\xd4\x97\xa1\x7a\xab\x27\xc2\xcf\x5d\xd5\x63\xd4\x24\x99\x52\x3c\x42\xfc\xcd\x5c\xbf\x8b\x2c\xae\x61\x03\xd4\xed\xdf\x92\xcb\x2f\xf9\xb6\xcf\xe3\xc6\x79\x61\xa9\x99\xae\x53\x95\xa9\x8b\x29\xf2\x5f\x3d\x55\x95\x74\x21\x66\x43\x20\xed\x90\xe5\x0a\x9a\xa8\x38\x49\x83\x2a\x45\x1b\xb2\xff\x74\xb8\x40\xc8\x58\x5e\x3c\xf3\x95\xcb\xd3\x0f\x75\x40\x4f\xe3\x3c\x7b\x65\xaa\x50\x2d\x6e\x55\xf5\x12\x93\x75\x74\xa0\xf8\xf5\xee\xc4\x7c\xdc\x0c\x94\x4c\x64\x3a\x8b\xcc\xfa\xfe\xae\xac\x6c\xce\x28\x12\x88\xe6\x74\x11\xb0\x73\xfc\x7e\xd7\x79\x51\xee\x6d\x49\x7e\x00\xaf\x15\xc0\xfa\x4b\x66\xe6\xda\x84\x59\xe3\x8e\x6b\xff\xf8\x6a\xb9\x75\x57\x95\xe2\x2d\x13\xfd\x70\xff\x3a\xc9\xc2\xad\x20\xdd\x00\xc7\x7d\xa9\x96\x8c\x74\x01\xfa\x22\xeb\xca\xdf\xf4\x4f\xbd\x92\xa0\xb6\x1b\x95\x60\x6d\xc6\xc9\x6e\xb3\xb8\x7b\xd6\x42\x57\x00\xa9\x27\xf3\x00\xf5\x72\x33\xd1\x95\x67\xa0\xf5\xad\x3b\x7f\x9a\xf7\x22\xe4\xfd\xf4\x65\x9f\x36\xaf\xb6\x16\xa1\x6d\xa5\x4d\xfe\x15\x7f\xb0\x55\xe0\x98\x2d\xbb\x98\x8f\x18\x24\x5a\x55\x3d\x12\x8e\x92\x01\x31\x62\x6e\xb8\xdb\xd2\xe4\xa4\x31\x56\x91\xee\x64\xb1\x24\xdc\x5e\x39\x57\x4f\x41\xb6\x43\x51\x2b\x46\x4c\x43\x6a\x99\x16\x7d\x2d\xb6\x4a\xe3\x97\x84\xe0\xdb\x78\x83\xe9\xb0\x8c\x6c\xf0\xbf\x28\x61\xc7\xcc\xbe\xc0\x03\x8b\xe6\x28\xd4\x52\x76\xd7\x8e\xaf\xbd\x80\x77\x38\xe3\x5a\xbd\x32\xad\x5c\x19\xb8\x95\x8d\xa8\x00\x5a\x73\xbb\x43\x29\xe6\x2f\xbf\x8e\x2f\x05\x41\xe6\x64\xc1\xe0\x80\xe3\x91\x6f\xdb\x95\x88\x00\x5a\x73\xda\x5b\x51\x4c\x7d\x6d\xa3\x39\xbf\x48\x3a\x5f\xf0\xde\x05\xf2\x0a\xee\xda\x99\xf3\xa7\xf1\x70\xdd\x6a\xc5\x01\x15\x9d\xc6\x4d\x0d\xa7\x5c\x14\x2c\x5a\xe2\xba\x0c\xda\x02\x78\xc4\x13\xe5\xed\x36\x42\x6e\x66\xcb\x31\x22\x5f\x33\x26\x4b\xe8\x1f\x6a\xc4\xfa\x61\x8e\xf1\xc1\xcb\x7d\xf0\x6c\xf1\xb9\x44\xce\x44\x1c\xcc\x6d\xe5\x5d\xde\x4b\x92\xb9\x97\x3d\x27\x95\x89\x57\x11\xdb\x4c\x5e\x84\x0c\x5e\xe7\x0b\xbf\x11\x1f\xdc\x38\xaf\xae\xa0\xe7\x2b\xbf\xbe\xed\xce\x11\x87\x7d\x20\x99\x3e\x4e\xf8\x03\xf8\xaa\xe0\x2b\x74\xa2\xb1\xaa\x89\x70\xf9\xbe\xe2\x47\x9e\x45\x3b\x0c\xf0\xdf\x6d\x04\x3f\x59\x74\x16\xef\xd5\x48\x9a\x09\x56\xb7\xcd\xfc\x07\x18\x14\x77\xc5\x2b\x6c\x61\xc9\xcc\xda\xa8\xd4\x4c\xa0\x61\x9c\xf4\x63\x2a\x4e\xc2\x62\x95\x9c\x6b\xd4\x5c\xa9\x01\xb9\x32\x59\x33\x0d\x2e\x23\x56\x46\x7b\x80\x15\x3b\x6e\xe6\xac\x85\xda\x46\x58\xb2\x62\x37\x72\x22\x0d\xec\xba\x8a\x94\xbc\x3e\xd0\x48\x00\x8f\x18\xc5\xa9\x40\x04\x2d\x8b\x1e\xae\x62\x09\x48\x42\x10\xeb\x70\xba\xc4\x8d\x31\x47\x30\xf3\xd2\xa4\x58\x91\xb1\x7f\x0d\x71\x11\xec\x15\xdf\xfa\x77\x4c\x63\x64\x92\xda\xb0\x4e\x16\xbe\x2e\x08\x8d\x27\x67\x9c\xf3\x39\x78\xb4\x83\xf9\xf1\x42\xd0\xf4\xc3\x68\xd1\x56\xcd\x93\xd4\x16\x3a\x22\x60\xd0\x60\xda\x7e\x03\x3f\xa2\x1c\xe6\x83\x17\xce\xa1\x76\x0d\x9b\x21\x31\x2c\xfd\x6e\xb9\x0c\x9c\x5d\x67\xd8\x4e\x5a\xf2\xe7\x88\x23\xc6\x6f\xe6\x5e\xea\x46\x2f\xb5\x44\xa5\xb0\xf8\x14\x4b\x21\x94\x61\x21\x9c\x53\xd3\x0e\x41\xa9\x06\x27\x16\x88\xa7\xee\x2c\x57\x58\x15\xbe\x99\x35\xe3\x25\x92\x4e\xd7\xdb\x2a\xb0\x55\x91\x73\xec\x9c\x40\xc4\x17\xe3\x6e\xd7\x34\xd5\x6d\x7e\x18\x12\xde\xfe\x05\x91\x12\xfa\xfc\x31\xcd\x89\xdd\x60\x79\x0f\x47\xe6\xdf\xc2\x7f\xcf\x33\xd7\x2d\x84\xb2\xa1\xca\x16\x77\x08\xcf\x98\xcf\x60\x49\x6b\x0b\xe3\x46\x02\xcf\xd8\xfb\xc3\xda\xf0\x3e\xc2\xda\x18\x1f\x1e\xbd\x36\xdb\x56\x2e\x77\x0e\xae\x37\xff\x70\x2e\xdd\xd7\x0a\x97\x4f\x1a\x31\x13\x72\x6d\x3d\x8d\x16\xd3\x57\xd6\x0d\x3e\x8f\xcc\xe5\x41\xc9\xe9\xfb\xf5\xe5\x9e\x3b\xec\xf3\x4a\x48\xf4\x3a\x7a\xc7\x94\x45\xf3\xd7\x4d\xbf\xb3\xd8\x1b\x8c\x13\x88\x8d\xc6\x15\x20\x9a\xa7\xc4\x86\x90\xff\x52\x44\xda\xcb\x73\x69\x14\x81\xc8\x1e\x8d\xf4\x4e\x5d\x62\x9b\xd6\xc7\xe0\x9f\xf1\xea\x37\x21\xb9\xab\x5b\xa6\x7e\x94\xf2\xd1\x6c\x36\xc3\xac\x64\x2b\xe5\x52\x87\xce\xb2\x68\x0d\x17\xd1\x35\x42\xae\x49\xd3\x2a\x5e\xbf\x26\xc3\x48\x86\xbd\x5d\x6e\x46\x94\xf6\x26\xb5\x0d\x17\xe4\xdc\xbc\x2b\xdd\x66\xa9\x5e\xc1\x95\x4d\x32\x4c\x8e\x31\x97\xe3\x43\xf6\xd8\xa7\x38\x6b\x47\x3b\x61\xbd\x3f\xb1\x29\x0d\x86\x8d\x64\xa5\x21\xcf\x23\xc0\x71\x4a\x4f\xf1\x14\x5f\x24\xd5\x13\xfd\xcc\x4c\x7c\x90\xa4\xf1\x22\xf6\x23\x5e\xc3\xc2\x99\xc0\x3f\x9d\x2c\x27\x51\xa2\x59\xc6\x18\x8a\x2f\x27\x44\x7c\xb2\x8b\x79\x80\x90\xf8\xcd\x9f\x22\xcb\xd7\x7e\x25\x64\x6e\x79\x1a\x8d\xd4\x46\x78\xdb\x7e\x21\x3e\x27\x29\xf0\x77\x2d\x55\x3a\xd5\x6e\x9b\xe1\x99\x31\x58\xf0\x0f\xfc\x53\x59\xc2\x5b\x55\x0a\xc4\xd8\xaa\xf5\xc9\x14\x26\xa9\x5a\xa0\xce\x87\x18\xab\xa3\x04\x51\x6e\x33\xef\x18\x9c\xb4\x7e\x0b\xad\xe3\x57\x22\xd9\x53\x8c\x46\x90\x20\x72\xfc\xbe\x4b\x03\xac\x1c\x7a\xc9\x9a\x64\x09\xf6\x6f\x37\x10\x1a\xa6\xa4\x97\x01\xcb\x08\x8b\x63\xaa\xf1\x2b\x9c\x98\xd7\xac\x7a\x13\xb5\xe9\xd5\xeb\xd4\xef\x7b\xe1\x0c\xb2\xcf\x74\x7f\x48\x88\xc4\xd7\xcd\x8e\xc5\xb1\xa4\x77\xe4\x6f\xfc\xf1\x9e\x68\xbe\x97\x88\x69\xfa\x99\xc5\xa7\xe1\xaf\xb9\xd3\x25\xd1\xfa\xee\x7f\x73\x4b\x96\xd0\x9b\x2f\x66\x01\xd5\x45\x5b\x29\xba\xe5\xc3\xd3\xbe\x31\x41\x4b\xbd\xaa\xbb\x1e\xec\x32\xfe\xe9\x89\xbe\x37\x9c\xfd\xef\x0b\x82\x7a\x5b\x53\xf8\xe5\x3b\xda\x0f\x68\xaf\x5c\xae\x57\x5c\x8b\xb5\xa7\xe5\xb8\x15\xbc\x95\x50\x54\x8a\x86\x4a\x08\xd6\x7f\xe2\xd0\xfe\x62\xe7\xb8\x25\x54\xb0\xc4\x20\xd1\xee\x5d\x7a\x92\xea\x86\x8e\xdf\x42\x1a\xf9\xa8\xca\xee\x2e\xfe\x08\xdc\xbc\x1e\xa8\x84\x14\x6a\xd9\x91\x40\x7c\xee\x94\xfc\xdb\xc6\xdb\x80\x4c\x36\xa5\xe5\xf0\x13\xbf\xbc\xb7\x9a\x5e\x04\xa7\xc1\x90\x60\x08\x7f\x27\x82\xaa\x79\x2a\x9b\x38\xe0\xc7\x68\x26\x62\x87\x13\x05\xf1\xb8\xd4\x91\xb2\x28\x2c\x22\x6f\x3a\x89\xdc\x02\x0d\xb5\xc5\x00\x6d\xad\x21\x02\x08\xcc\x0a\x78\x15\x2d\x37\xb4\x3a\xe2\xd5\x62\xb3\xb4\x85\xd5\x67\x5d\xbf\x91\x84\xdc\xce\x4a\x79\xb9\xcf\x26\xe2\x3d\x3f\x9a\x0e\xd4\x37\x0b\x4b\x55\xa9\x96\x42\xcd\xfa\xcd\x0e\xaa\xd3\x3b\x2f\x05\x0b\xa3\xab\x5d\x66\xdd\x59\xae\xf4\x4d\xc7\xc7\x5c\x1d\x94\x1f\xb3\x0b\x2e\x82\x80\xa3\x47\x42\x7d\xbe\xe9\x23\xe2\x1f\xde\xf5\xdf\xc3\x58\x3b\xd8\x2d\x77\x26\x3d\xd3\x48\x9d\x3c\xf9\x92\xdb\xab\xfd\x8f\x16\xe1\x2d\xde\x58\x44\x54\x74\xf0\x76\x0c\xd1\xb6\x71\x50\x9f\xfc\xa3\xca\xef\x7a\x7f\x25\xb2\x24\xae\x37\xd6\xe4\xbe\x6b\x3a\xba\x64\x6d\x54\xa1\xbc\xb3\x79\x69\xf9\xc3\x31\x77\x4f\x7c\x2e\xd9\x0e\xd4\x5c\x93\xee\x29\x9c\x74\xef\x30\x72\xba\xc7\x2c\xa5\x0a\xa3\xe7\x19\x1e\xbd\x2a\x1f\xee\x4d\xc9\x60\xae\xd9\x16\x92\xe7\xc4\x82\x13\xe0\xad\x5c\x34\xbd\x0a\x0c\x97\xe7\x93\x9f\xcf\x45\x84\xe3\xa1\x4a\x83\x0b\x79\xd8\x72\x86\x56\xdd\xfa\x15\x93\x72\x91\x38\x3c\xf9\x0a\x0d\xab\xec\xf5\x2a\xe2\x74\xc9\xa4\xfc\x86\xe4\x20\x32\x20\x38\x7e\x6a\x01\x9b\xbf\x8d\xae\x38\x1d\x5d\xc2\x4c\x85\x22\xe6\x26\x22\x63\x89\xcf\x9c\xe4\xb7\x00\xa4\xa3\x1c\xbe\x76\x30\x18\x8f\x84\xce\x96\x65\xa9\xf5\xdb\x2d\xf4\x33\x4f\x5b\xfa\xb5\x08\xed\x24\xe5\xac\xc5\x24\xce\x21\xf7\x1c\xb5\x2a\x76\x1d\x06\x6a\xd8\x49\x4e\x47\x1d\x9d\x48\xfe\x5f\x9c\x03\x88\x3a\x7f\x41\xe2\x36\xd6\xba\xdd\xdc\x74\x32\x94\x4b\xe1\x6b\x12\x29\x5d\xea\x18\x34\x20\xd5\x5b\x23\x93\xa9\x96\xfc\x46\x39\x8f\xc3\x21\xf3\xf3\xcf\x84\x28\xe3\xfe\x70\xb0\x3d\x3f\xf2\x7a\x5f\x44\x28\xb8\xba\x09\x7c\x09\xa9\x0c\x82\xc5\x7b\xb8\xe5\x62\xd7\x11\x45\xba\x22\x8e\x84\x13\xb5\x5e\xa9\x2c\x4a\x97\xaf\x6a\x1c\xd9\x47\xbd\xf3\xfb\xca\x30\x2d\x9c\x9d\xc2\x4c\xdb\xd6\x07\xec\xca\xc7\xc5\x5d\x06\xdc\x35\x76\x5d\x7b\x5f\x0e\x7f\x3a\x08\xb8\xc1\xba\x11\xbe\x5f\xbc\xfb\xcc\xf0\x6d\x6d\xfd\x4b\x2d\xf7\xf1\xce\x23\xdc\xec\x34\xbb\x94\xf5\xf8\x0c\x42\xb4\x57\xa0\x30\x6c\xe0\xd5\x45\xc4\x6b\x72\xd9\xac\x1a\xf4\x58\x79\x2b\x2a\xdc\x28\xbb\xf2\x85\xfc\x9d\xa2\x54\xae\x94\x83\x63\x2c\x18\x56\xad\x4c\x13\xa3\x50\x60\x18\x0a\x5b\x43\xbb\x37\xe4\xec\x09\x2d\xc2\x56\x4c\x82\x38\x43\xb3\xba\xde\xa8\xc7\x8e\xdc\x15\xa5\x92\xd5\x09\xac\xc5\x0e\x80\x56\x42\xc7\xc6\x56\x5b\xb2\x84\xd8\xa3\x67\x36\x87\x27\x39\xef\x5b\x4d\x38\x41\xb4\x34\x70\x05\x4d\xd3\x03\x1a\xf3\x05\xa9\xdf\x92\x02\x42\x2a\xb1\x48\xb2\xe4\xc2\x52\x25\x9d\x3e\xd4\xce\xa4\x95\xb7\xfa\xd4\x1a\x22\x2a\x64\xcc\x2e\x59\x5f\xaf\xfb\xbd\x95\x7b\x65\x5d\x3d\xd7\x2a\x50\x78\x3a\xe1\x79\xd9\xde\xae\x55\x0e\x87\x7d\x7b\x67\xc7\xe2\xab\x2b\x9d\x05\x9c\xac\x4d\xcb\xb1\xfb\x83\x83\xa7\xc6\xe6\x03\x35\x25\x70\xb3\x8f\xae\xb1\x0d\x50\xe5\x97\x1d\x65\xf4\x7f\xa1\x7c\x40\x75\x6c\xf7\x5c\xb7\xea\x9f\x1c\x0f\x75\x49\xd9\xc7\xf1\x2d\x3c\xa5\xa5\x30\x12\x92\x85\xe4\x31\x94\xc7\x91\x22\xe6\xcb\x78\xbf\x11\xa8\x79\x49\xa9\x56\xee\x60\xf8\x8a\x0c\x9c\xa8\xb6\x1e\xeb\x3b\x3c\x78\x95\x14\xbe\xa2\xd6\xb6\x26\x2b\x22\xcf\x0a\x02\xc4\xa9\x2b\x62\x5f\xd1\x44\x5e\x55\xfe\xd1\xd5\x91\xd1\x94\xba\x4c\x05\x62\x6b\x86\xe3\xcb\x0d\x07\xc5\x58\x9f\x91\x75\xcf\xfa\x66\x0a\x70\xcb\xfd\x96\x3d\xa2\x40\x7e\xbf\x11\x4c\x9e\xa9\x5b\x00\xe1\xc3\x38\x62\xd4\xb0\x06\x99\x9d\x1e\x56\x55\x45\xc1\x9b\xf8\xc7\xec\xeb\x22\x00\xb4\xf1\x8e\x4f\xd7\x26\x6f\xeb\x17\x62\xb6\x72\x56\x0d\xeb\xb6\x3e\xd0\x61\x62\x54\x8d\xf3\xa5\x74\x20\x2c\xc0\xe1\xa9\x57\xc2\x0a\xe8\x34\x57\xe2\xe6\xd7\x52\x33\xc6\x4c\x94\xc7\x85\x4a\x8a\x38\xea\x84\xc6\x36\x5c\xf1\xc9\xcf\xda\xc5\xf4\xb5\x8d\x4e\x35\xab\x47\x91\xce\xb0\x59\xa1\x70\x6c\x85\xbf\xed\xda\xb3\x19\xe3\xd4\xd2\x8c\x58\x44\x50\xde\x9d\x23\x77\xb6\x8e\x7c\x4c\xcb\x44\x20\x2e\x51\x94\xbd\x23\xcd\x5c\xf2\xc7\xc9\x23\x6c\x2b\xf3\x3a\x2f\xba\x9a\x17\xc4\xde\x30\xeb\x15\xc7\xfc\xd2\x16\xba\xe2\xe7\x4f\x12\xd4\x33\x44\x62\xa6\x7b\x87\xb9\xfc\xc9\x4d\x2e\x61\xab\xbc\x04\xe9\x23\x0c\x02\x85\xcd\x7f\xdd\xae\xd5\x48\x0f\xd7\x92\xc5\xcf\xc6\x12\x6c\x76\x81\xf6\x66\xd2\x90\x6c\xbf\x86\xc5\xf8\x42\x58\xc3\x85\x38\x47\xc4\x69\x4b\xb2\x92\xef\x7c\xf6\x22\x04\xc2\x2d\x10\xf8\x28\x01\x56\x75\x30\xe8\x04\xc3\x90\x82\x87\xae\x69\xb4\xc5\x35\xb7\xac\x58\x8d\xda\x67\x03\xcf\xc1\x3c\x97\x1f\xba\x09\x79\x40\x4a\x90\x5b\xd8\xd6\x3f\x1d\xd9\xdf\x36\x67\xea\xe1\xa7\xe2\xc1\xb5\xb4\x2b\x05\x0e\xa7\xe5\x66\xec\xc1\xb3\xb4\xce\x8c\x4a\x24\x1b\x21\xba\xe9\x41\x9e\x0d\xe9\xce\xc1\x71\x97\xb8\x1f\x2b\x45\x2d\x7e\x56\xea\x3b\xe5\xf5\x44\x2d\x2d\x81\xe3\x14\x1a\x87\x46\x42\x76\xe2\x7f\x51\x88\x54\xd6\x1a\x21\x80\x5d\x8a\xe8\xeb\x75\x1d\xa2\x7f\x6e\xce\xb2\xc3\xf4\x16\x84\x9f\x31\x19\x1f\x30\xe6\x97\x2d\xb5\xc8\x28\x5f\xe4\xe3\xbc\x93\x3d\x45\x20\xa6\x12\xdd\x55\x56\x16\xf8\xfd\xa7\x30\x15\x1e\xe9\xce\x05\x50\x48\x1d\x98\xee\xae\xf2\x9a\x1f\x31\x74\x61\x60\xa1\xa9\xac\xda\xeb\x88\xa2\x64\x30\xe3\x2f\x71\xbf\x71\x0a\xb6\x87\x90\xda\x84\x9e\xd1\xc2\xa4\x18\x72\xc6\x0f\x57\xb4\x0e\xa1\x75\xfc\x54\xe2\x4c\x05\x19\x97\x78\xea\x59\x58\xf7\xb7\xfa\x07\xe3\xff\xca\xb9\x95\xe9\xe7\x6b\xc0\x63\x1a\xff\xd0\x32\xd4\xe9\x67\x89\x4e\xb4\x62\xe0\xcb\x2d\xb0\x9d\xfd\x4b\xcd\x83\x23\xc6\x41\xc9\x5a\xcb\xbd\xbd\x78\x54\x23\x7d\xaf\x9f\xd2\xae\x1a\xf1\x1a\x5a\xb3\xcc\x7b\xc1\x44\x67\xb0\x9f\x81\x28\x7f\xa6\x42\x6f\x61\x2b\xfe\xd9\x32\xab\x52\xa3\x9d\x2a\xae\x33\x1b\x34\x59\x0a\x12\xe3\xac\x83\xbb\xba\xc4\x0f\x99\x31\xdd\x98\x86\x23\xc9\xda\x0f\x59\x61\xaa\x1f\x7b\x08\x2a\x09\xb9\x1f\x35\xe8\x87\x1a\xf9\x58\x90\x7e\x24\x52\x14\x13\x95\xe4\x6d\x25\x8e\x3e\x5a\x14\x9d\x96\x46\xa4\x03\xb7\x55\xa8\xe8\xf9\x47\xa1\x9f\x04\x9b\x01\xa6\xe6\xc1\xd2\x97\xcf\x73\x55\xeb\xc6\xf1\xf5\xb5\xdf\xb3\x7b\xe6\x16\x45\xad\xde\xe6\x66\x9e\x15\xee\xdf\xc4\xde\xef\xf5\x97\x19\xd7\x86\x48\x87\x37\x92\x9d\x47\xc3\x5c\xa1\xd9\xcb\x45\x48\xb6\xe9\x0a\x7e\x42\x99\x85\x07\x3f\x57\x1a\x7c\xf9\xe7\x56\x82\x87\x65\xb7\xd0\x83\xbf\x14\x57\x75\x23\x63\x58\x78\x9f\x0b\x39\x71\xcd\xb6\x19\x5f\xa9\xfb\xe8\xa7\x92\x38\xd7\x58\x83\x9f\x06\xde\xb6\x8a\x92\xe1\xa6\x71\x2b\x2a\xe1\xe4\x08\xc2\xea\x94\x21\x33\x33\x72\x3d\x33\xd7\x3f\xd5\x32\xb7\x04\xd1\x08\x7f\x3a\x63\x65\xc4\x67\xdc\xef\xba\x3c\x49\x5a\xd8\x87\x02\x8c\x98\xb4\xc7\xcd\xd6\xf8\x73\xbc\x9e\xca\x5f\x95\x24\x46\xe9\x1c\x3b\x73\xc8\x69\xe2\xb0\x7b\x6f\x86\x85\xc2\xce\xdc\x1c\xb7\x14\x22\x00\x11\x1e\x06\x8d\xe3\x6b\x68\xe8\x33\x1e\x6a\x7b\xae\x16\x9b\xf7\xed\xbc\x84\x4c\x5b\x8b\xb1\x5f\x6f\xce\x40\x92\x2b\xd3\x99\x93\xdc\x8f\x24\x9c\x11\x6a\x4e\x4a\xcd\x42\xe9\xe0\x2d\x5a\x30\x72\x49\x0c\xa5\xf3\x16\xeb\xa3\x18\xce\x6d\x5c\xe8\x92\xe4\xde\x33\x79\x0f\xe5\xfa\x9d\x25\x77\x83\xc5\xf4\xe5\x5e\x09\x8f\x16\xb9\x8e\xb3\x2d\x88\x67\xd1\x78\xfe\xfb\x97\x92\xfc\x15\x86\x2f\x96\xe6\x3f\xf3\xd3\x4d\xbd\xc7\x3d\x56\x70\x57\x5a\xb6\xdc\x51\x24\x75\x45\xef\x88\x05\xdb\x23\x71\xbc\x6d\xad\x71\xbd\x82\x34\xeb\x29\x67\x36\xc5\x53\x64\xbb\x94\xac\x6d\xb0\xda\xa8\xdf\x16\xad\x51\xe4\x7a\xfd\x11\xda\x74\x9e\x65\x41\x15\x2e\xfb\x4e\x56\x9e\x29\xd9\xe1\x31\xce\x83\xcd\x8b\x4b\xce\xe5\x55\x6a\xca\x94\xb6\x18\x0d\x0c\x7b\xdf\x55\x19\x56\xfe\x1f\xa5\xc5\xbf\x70\x79\x3f\x97\x9f\x44\x79\xd1\xa6\x28\xe9\x03\x7c\x1d\x2e\x55\xf2\x8d\x67\xcb\xcb\x33\x94\xdb\xea\x0c\x78\xe2\xa3\xc2\xcf\xa0\xf9\xfb\xda\x77\x4d\xaa\x25\xff\xe4\xb9\xaa\xbf\x70\x84\xa7\x17\x64\xe7\xc0\x96\xcd\xfe\xcc\xf2\x13\x60\xe9\x01\x0f\xf0\x57\xb9\x26\x33\x09\xa2\xa5\x7d\x94\xf8\x67\x65\x1a\x1b\x4e\x33\x04\xa5\xb6\xa7\xdf\xd4\xdc\x68\x34\xc9\x5c\x9e\xdc\x1d\x29\x6f\xdd\xc7\x0e\xaa\xe5\x0e\x4f\xc6\x44\x37\xa7\xd3\x00\x62\x4a\xa7\x1c\xa5\x6a\x82\x99\xa8\x14\x25\xe7\x14\xcf\x12\x25\xb3\x4f\x28\xe2\xa4\x4f\xce\x08\xcd\x7e\xf7\x17\x69\x78\x65\x27\xdb\xf9\x09\xfd\x25\x8e\x8f\x4f\x20\xcf\x87\x33\x59\x9c\x50\xe7\xd0\x58\xb0\xf6\x6f\xee\x69\xb2\xe7\x37\x75\x6d\x09\x14\x06\xc5\xed\xb3\xd9\xd2\x39\x33\x69\x78\xeb\x68\x4c\x85\xc0\xcf\xb2\xbc\xb3\xfc\xa6\x83\x1d\xfd\x97\x8c\x6d\xbd\x1e\x5c\x4a\x6e\x6a\xa2\x56\x3b\x18\x4a\x2d\xee\x1c\xd1\xbe\x72\x37\x76\xd8\xca\x58\x04\x01\x2c\x20\x51\x91\x0a\x43\x17\x01\xa2\xa4\x58\x8e\x6e\xf8\x4b\xd1\x64\x7a\xf5\x45\x6c\xa5\x21\x26\x70\x25\x4f\x3f\x6c\x19\xb7\x38\xcf\x07\xa8\x2c\x3d\x8f\xe0\xe5\x16\x70\x01\x08\xbb\xda\xeb\x11\xca\x37\x09\xdb\xff\xd4\xda\x61\x1f\x10\x74\x52\xbb\xb8\x6a\x90\x38\xcf\xee\xe5\x5d\x17\xf3\xbe\x66\x7d\x89\xf2\xa3\x2d\xaa\xa0\x25\x4b\xc4\xe9\xc6\xbb\xec\x53\x21\x4b\xb8\x1f\xa6\x13\x22\x92\x1e\xfd\xf9\x1b\xc9\x71\xa4\x2f\x24\x30\xe4\xbf\x10\xb4\xdf\xf1\xc7\x9f\xc0\xeb\xab\x95\xf6\x19\x32\x9d\x77\xb5\xc3\x35\xec\x75\x54\x79\xc3\x06\x2a\xc3\x80\xea\x69\xe0\xc4\x92\x9a\x57\x2c\x33\xfe\xc0\x4a\x3c\x38\x33\xdf\x05\x39\xe1\x07\x76\xb1\x56\x2e\x58\x74\xd3\x0c\x64\xef\x40\xe1\x60\x7a\x1c\x68\x82\x35\xbb\xc4\xbe\xcc\xd3\x39\xfe\x41\x09\xcd\x2e\x23\x0e\x9a\x80\x40\x78\x7c\x21\x1e\x39\x75\x83\x90\xe7\x19\xd9\x5e\x29\xce\x57\x65\xf2\x50\xae\x3c\x41\xc6\xbd\xb1\x97\x8e\x58\xe8\x2c\x0d\xd7\x74\x30\xe9\x0f\x6c\x7a\xc3\x07\x66\x28\x02\x9e\x05\x5c\xd2\x8a\x69\x43\x62\xf6\x30\x67\x31\x79\xf7\x99\xa8\x1c\x2a\x86\xf8\xa7\x40\x26\x36\x00\x38\xad\x4d\xe3\x57\x88\x9f\x57\x01\x8b\x4e\xbe\x29\x5e\x79\xfb\xdb\xf5\xae\xdf\x3d\xe0\xff\x90\x3a\x3c\x3a\x2f\x58\xff\x5e\xa3\xca\x8c\xfa\xfd\xb0\xa6\x48\xef\xcd\xe1\x11\xb0\xc9\x3a\xdb\xe2\x17\xfa\xac\xed\x63\xc7\x78\x9f\x28\xcb\x28\xf1\x49\x4d\x9e\xe2\xe4\x32\x9c\x74\xc7\x10\x0b\x7b\xd1\xc1\x1d\xf2\x00\x9e\xfc\xfb\x8e\xe7\x1f\x53\x60\xd2\xae\x2a\x87\x21\x79\x65\x11\x4b\x01\x45\x53\x54\x56\xe0\xab\x57\xab\xb8\x05\x15\x5d\xda\xc8\x5d\xca\x1e\xb7\x85\xfe\x82\x2c\x7b\xf9\x82\x16\x2d\x53\x06\xea\x72\x7b\x6e\xdc\x40\xe6\x84\x5a\x8b\xd5\x1c\xac\x46\x99\x6a\x22\x5d\xf7\xe1\x98\x75\xda\xc7\x1a\x6c\x70\x22\x25\xd3\x72\x08\xa5\x3d\x0e\x68\x6d\x24\x21\x61\xd8\x12\x87\x1e\xc3\xf1\xce\xe6\x84\x1b\xfb\xe8\xbb\x67\x69\x54\x4f\x1c\xda\xa9\xf1\x62\xdb\x42\x16\xbd\xbf\x03\x59\x13\xf7\x5a\xcb\xb8\xa3\x81\x8d\x69\xc0\xd4\xea\xc4\xdd\x78\xad\x74\x39\xaa\x69\xbf\x94\xa9\x11\xbe\xa2\x03\xbb\x9a\x02\xbb\x52\x80\x82\x14\x84\x89\xf2\xbd\x7e\xbc\x9d\x47\x0c\x5a\xd2\x87\x6e\x08\x19\x6e\xa4\x25\xc7\x4a\xe0\x3a\x72\x75\xc8\xa7\x1d\xb1\x65\xcb\x0f\xc4\xa2\x7e\x27\x17\x9a\xc8\x68\xf1\x7d\x9c\x3b\x22\x89\x8e\xf5\xa2\x8a\x51\xe4\xa4\x4c\x39\x48\xfd\xc0\x7e\x4d\xc6\xc8\x28\xb4\x78\xa4\x8a\x84\xba\xd5\xec\x21\xf1\x84\xe2\xce\x53\x5d\x11\xef\x42\x8e\x2c\x39\xb6\x7d\x24\x05\xb2\x3d\x81\x58\x18\xdf\x75\x6c\xb0\x99\x03\x14\x6c\x6d\x4a\x27\x54\xe3\x03\x6f\x4f\xdb\x3e\xe6\x6e\xec\x58\x13\xee\x7d\xdc\xdd\xb0\x32\x70\x2a\x96\x46\xae\xa2\x65\x2a\xaf\x64\xe3\x7b\xdb\xc8\xae\xe0\xf4\x23\x69\x01\x1d\x11\xec\x6e\xc2\xa0\xf2\xda\x57\x7c\x05\x9f\xe2\x0f\xee\x1b\x45\xeb\xa5\x6b\x71\x83\x26\x0f\x99\xae\x5e\xc9\x7a\xfa\x05\x0e\xf2\x6c\xd4\x9e\xd6\xf1\x29\xd7\x76\xfe\xbd\xa3\x90\xc6\x63\x43\x17\x85\x43\xc9\xd0\xcb\xb5\x4d\x2f\x14\xb3\x27\xd3\xa5\x52\x5c\x0f\x23\xbb\xff\x0f\xcc\x23\x33\xdc\x65\x24\x4a\x77\xb2\x60\xf1\x7d\xf5\xed\xa9\xdd\x6e\xae\xde\x1f\x6e\x31\xa8\x3b\xaa\x83\x5b\x62\xee\x85\x77\x6f\x94\x5f\x3c\xb7\xe5\x3d\x66\x0a\x7c\x4d\x39\x48\xef\x24\x25\x79\xd4\x52\x4e\x74\xb2\xf3\xc2\x06\x6e\xae\x52\x36\xf9\x1b\x09\x16\xb5\xd8\xe6\xf1\x2c\x01\x95\x74\x34\x0a\xdc\xeb\xac\x59\x1b\x84\x2d\xf0\x49\x63\x06\x7c\xdc\x5c\x50\xf2\x06\x58\x84\x2d\x52\x28\x2f\xf8\xcc\xa2\x89\x05\x81\x55\x49\x3d\x24\x82\xd6\x3c\xeb\x2c\xad\xdc\x40\xc4\x59\xed\xc4\x82\x5b\xec\x92\x5d\x6e\x0d\x86\x58\x29\xc4\xcb\xd8\xeb\xba\x30\xd8\xba\x32\x05\x7f\xb8\xbf\x2e\x9c\xf0\x1e\x52\xba\xe2\x5c\x3a\x8e\x87\x26\x65\x9e\x88\xee\x69\xfa\xe5\xc3\x99\x99\x7b\x22\xff\xb4\x7d\x23\xb7\x63\x1b\xcf\xfb\x7c\xa8\x7d\xef\x37\x79\x3f\xd7\xd7\x98\xc9\x70\x5b\x9a\xd2\x91\xf6\xfb\x93\xe1\x8e\xcd\xbe\x7b\x3b\x77\x0e\x1e\xd8\x3c\x30\xcd\xbc\x19\x69\x6e\x01\xaf\xe4\xf5\x4a\xbd\x94\xe4\xcc\xbc\xb2\x8b\x52\x01\xd2\x35\xe0\x53\xf3\x2c\xe9\x03\xcd\x9f\x9a\xd7\xb3\x4b\xa7\xe6\x8d\x00\x34\x49\xcb\x3c\x3e\xdd\x67\x58\x79\x6a\x3e\xae\x50\xa1\x55\x27\xe7\xc7\x3b\x51\x82\xcb\xfd\x64\xc5\xf9\x79\xc5\xcb\xc7\x2e\x65\x16\xbe\x83\x0f\xd1\xff\xcf\xb9\xa7\xdf\xa9\x60\x56\xdd\xf3\x09\xb4\xa9\x33\xf7\xe7\x1b\x56\xde\xf3\xe9\x4b\xc7\x26\x6f\xbc\xa7\x01\x30\xc6\x0d\xf7\x34\x2e\xdf\x33\x5f\xaa\x46\x58\xd8\xcd\xab\xee\xc9\x3b\x55\x01\xd5\xea\x21\x01\x95\xa8\x20\xbc\xd0\xfc\xc6\x7b\x9b\x56\xde\xf8\xf0\xab\xaf\xb4\x7f\xeb\xc8\xc2\x33\xf2\xcc\x00\xe9\xde\x7b\xe1\xde\xa5\x10\xf5\xa4\xaf\xbf\xb7\x27\x7f\x6f\x5c\x0b\xc3\x93\x39\x5d\x9c\xa8\x55\x90\x68\x08\xc7\x3e\xb0\x12\x0f\xac\xc4\x9b\x10\x8d\x38\xf2\x51\xe3\x12\x9f\xcb\x2c\x58\x57\xae\xac\x46\x4a\x34\x2f\xc9\x0d\x19\x4f\xb1\x6a\x9d\xec\x81\x31\xff\x9d\xad\x71\x23\xc7\x79\xef\x48\xf5\x70\x5c\xba\x21\x56\x18\xae\x09\xad\x5a\xf6\x0f\xb2\x5c\x92\xab\x0f\xdf\x95\x6e\x8d\x6c\x8e\xc4\x5b\x17\xee\x27\xeb\x67\xe5\xf5\x77\xc0\xfa\x6d\xe0\xdd\x2b\xf0\x99\x83\xd5\x14\xd8\x97\x28\x00\x8c\x56\xce\x03\x58\x01\x22\x00\xb1\xf9\x39\x41\x7d\x55\x34\xea\xe7\xf1\x29\xbb\x42\x9c\x01\xd1\xcf\x4b\x6d\xf9\xb8\xab\x50\x69\x4f\x90\x79\x26\x88\x76\x92\x73\xe0\x96\xac\xc2\x41\x26\x9b\x88\xc8\x2e\xf7\x29\x2c\x11\xb8\x6a\x3c\xef\xd2\x73\x29\x53\xb6\x82\x4a\x5f\x2a\x18\xf2\x78\xea\x42\xc1\xd4\x28\x10\x96\xa9\xc5\xcf\x50\x2a\x14\xac\x5d\xa2\xf1\x7d\x39\x65\x96\x5a\xf0\xa3\xff\x4e\x97\xac\xca\x9b\x79\xae\xe5\x80\xce\x5e\xca\x41\x15\x51\x7e\xea\x2b\x4b\xbd\xa9\x82\x9d\xc3\x43\x35\xb0\xb2\x6b\x64\xcb\x2b\x37\x2c\x19\x49\xc3\x12\x0b\x3e\xad\x58\xf2\x70\xc5\x26\x5c\x46\x9b\x33\x48\x39\x00\x9c\x44\x63\x1d\x52\x9b\x48\xb1\x19\x9f\x3f\x28\xb3\xcc\x6a\x50\x91\x19\x87\x2c\x06\x33\x44\x62\x94\xe8\x03\x7b\xf0\x3c\x6b\x40\xe6\x22\xa9\x95\x1f\x0f\x97\x5b\x39\x6c\x48\x1e\x4c\xa1\x43\x2b\x60\x8f\x07\xfd\xa0\xb5\xdf\xcd\xb7\x04\x02\x5b\x78\x77\x7f\x1a\xbd\xbb\x34\xaf\xe2\x4e\xb0\x00\x91\x88\xcf\xc7\xd3\xec\xc7\xea\xa1\x56\x7f\x7d\xc4\xed\x8e\xd4\xfb\x5b\xf7\x28\x3f\xd3\x03\xfd\x87\xd1\x7b\xe8\xbf\xa3\xb7\x03\xb1\x58\x20\x18\x8b\x61\x5b\x08\x11\x19\xf3\x0e\x9b\x83\x28\xd7\x4a\x9d\x94\x4f\x85\x51\x46\x9e\x5f\x1e\x63\x60\x25\xc7\xf1\xe6\x0c\x26\x3d\x39\x40\xa9\xc0\x03\x06\xf4\x4b\x43\x0d\x6c\xd2\x59\x4a\x03\xd9\x62\x3d\x22\x29\xf0\x7c\xe0\x4b\x66\x8e\x69\xe8\xa5\x71\x03\x76\xa9\xe2\x53\xfb\xaf\x1f\x8c\xe4\x0f\x92\xa1\x2b\xf0\xef\x04\xeb\x95\x59\x83\xd1\x8a\xa7\xf6\xe2\xdf\xcc\x2c\x32\x98\xac\xcb\x53\x74\x79\xb4\x3c\x10\x01\x7e\x18\x2b\x38\x7b\x35\xfa\x16\xbd\x35\x77\x16\x05\x73\xbf\x42\x3d\xb9\x60\xee\xe3\xe1\x47\x7e\xeb\x58\x1a\x91\x00\x2f\x9d\x43\xbf\xa0\x2f\xe2\xda\x2c\xe0\x6e\x3c\xdb\x62\x33\xee\x9f\xca\x8f\xb4\xc0\x18\x85\x93\xbc\x2b\x1e\x3b\x99\xcc\x4f\xb6\xc0\x0d\x89\x51\x3c\x0f\x10\x40\x37\x9e\xc6\x1a\x85\xbd\x69\xd0\x28\x2c\x25\xbe\x8a\xf5\x1b\x62\xd2\x78\x28\x0e\x3b\xc9\x0d\xb8\xe8\x3c\x4b\x39\x03\x61\x32\xfd\x42\x6e\x74\x97\x66\x15\xdc\x6c\xfc\x05\x32\x22\x59\x82\x03\xcb\x48\xbd\x8a\xe9\xea\x3b\x7a\xa1\x6d\xd5\x40\x8c\xde\x4d\xf9\x81\x18\xb1\xf3\x03\x3a\x02\xdb\xf7\xca\x30\xde\x96\xf9\xde\xc1\x34\xbd\xff\x65\x84\x4e\xa6\xd6\x1e\x8f\x91\xb9\x5f\xdf\x4e\xa0\xfd\x0e\x09\xe8\x3f\xa5\xee\xfc\xce\x07\xf2\x79\xe4\x19\xb0\x7f\x38\x9f\x71\xcb\x49\x15\xa6\x5b\x4d\xaa\x30\xdf\x30\xa9\x02\x81\x13\x58\x31\xad\x62\xf1\x59\xec\x02\x96\x36\x84\x98\x7f\x92\x57\xf9\x7f\x7d\x1d\xe0\x18\x56\xae\xe3\x5d\xe2\x16\x96\x17\x82\x7d\xc2\xea\x75\x58\x96\xa6\x22\xde\x74\x1d\xd6\x5b\xad\x03\x87\xdc\x1a\x4a\xea\x47\xbf\x7e\x3d\xc4\x69\xac\x5c\xd2\x80\xec\x32\x96\x17\x25\xf9\x0b\x62\x83\xa4\x75\x75\xc0\xba\x0a\xc1\x06\x7d\xf5\xf3\x57\x86\x87\x51\xf8\x78\xd1\x08\xe6\xb6\x24\x9a\x37\x4a\x6b\x2e\x53\xaf\xc1\xd3\x73\xad\x60\x89\x35\x52\x62\xad\x4c\x4f\xca\x45\xd8\x42\xe1\x51\x7a\xe0\x5b\x12\x09\xb1\xac\x08\x48\x28\xb9\x81\x84\x95\xc6\xd7\xbf\xd2\xf2\xae\xa4\xaa\x67\xc9\xf4\xa2\x07\x96\xed\xee\x32\x8d\x4b\x86\x37\xb8\xc2\xe6\xd2\xd2\x3c\x8b\x65\x79\xb8\xe9\x44\x0b\xd3\x6d\x4d\xb4\x30\xdf\x30\xd1\x02\xcb\x65\x7e\xaa\xc5\xe2\x07\x58\x28\x97\x66\x5b\x28\x7e\x46\x84\xf2\x7f\xc1\x1a\x40\x26\xf3\x6b\xc8\x05\x89\x40\x2e\x2f\xe2\x0c\x16\xc8\x95\x6b\xb0\xe0\x5e\xd9\x9b\xae\xc1\x7a\x5b\x6b\x20\xf2\x88\x0f\x18\x14\x18\xcc\xd2\x01\x83\xd5\xeb\x21\x32\xb9\xc4\x96\x6f\xcb\x02\xb9\xbc\xa8\x23\xb2\x40\x32\xf2\xba\x56\xc8\xe3\x4d\x56\x76\xa3\x28\xde\x7a\x99\xb3\x56\x0d\x0d\x52\xa9\xd7\xe3\xf4\xdf\x75\xc2\x49\x24\x73\x59\x1e\x57\x2d\xff\xa6\xf2\xb8\x44\xd1\xe9\x35\x85\x71\x99\xbe\xf9\x35\x84\x91\xa6\x52\x40\xeb\x65\x32\xdb\xc9\x43\xed\x96\xfb\xae\xf1\x59\x2f\x86\x74\x42\x28\xe7\xe7\x10\x65\x62\x0a\x20\x56\x90\x8e\x48\x95\x48\x73\xee\xcd\x24\xd9\x6b\x35\x60\xc8\x93\xb5\x92\x3e\x25\x6b\x29\x04\x59\x66\x12\xde\x9a\x31\xa9\x56\x12\xd6\x93\x19\x19\xde\xa5\x01\x24\x1a\xa7\xdc\x9d\xb5\x34\x80\x48\xa5\xf4\x79\xcd\x56\x3c\x84\xa8\x9a\x0e\x21\x1c\x21\xa5\x76\xa1\x92\x23\x3f\x1a\x4f\x04\x77\x1c\x68\xed\xf8\x76\x6e\x61\x7a\xe2\xe5\xbf\xbb\xf4\xf2\xf1\x5f\xfd\x8a\xde\x33\x46\xbb\xfb\x2e\xfc\xcb\xf1\xde\xef\x7f\x77\xd2\x1b\xa0\xf7\xe6\x0a\x90\xfe\xf7\x1f\xa3\xe2\x5c\xef\x18\xd1\x2b\x32\xc3\x03\x30\xa7\x9e\xf2\x51\xd3\x6b\x4f\xf1\xc0\x38\xd3\xa6\x20\xc7\xa3\x8c\x8a\xa5\x23\x86\x6b\xcc\xf4\xf0\xe7\x07\x8c\x14\xe0\x03\x94\x73\xb4\xd1\xe6\xc2\x63\x37\x05\x8d\x25\xab\x75\x16\x12\xc4\xb6\x34\xe3\x43\xb4\xe1\xec\x4d\x81\x2f\x41\xce\x24\x14\xe2\xa4\x84\x84\xe4\x56\x4e\xfe\x60\xd6\xc2\xab\x4b\xe3\x40\x6a\xd6\x86\xaa\xd7\x4d\x09\xb9\x1e\xad\x82\xac\x92\x99\x21\xa0\x43\xb8\xdf\x3f\x44\x6d\xbf\x7e\x6a\x88\x0f\x97\x8b\x36\xac\x35\x35\x24\x2c\x77\xfc\xcf\x2a\x8c\xeb\xd6\x13\x2f\x8f\x9b\xfe\xb3\x94\x4d\x9b\xb8\xf5\xe8\x90\x4a\x03\x8d\x23\xa0\xcf\x9f\x1d\x52\xbf\xaf\x2f\xd9\x4b\xac\xcf\xe7\x4e\x0f\xa1\x23\xc3\x57\xe8\x33\x92\xaf\xfc\xcf\xa4\x07\x0c\xd6\xad\xe9\x79\x52\xb2\x64\xb7\x26\x68\x9c\xf8\xdc\xd5\xf4\x54\xdd\x84\x1e\x6e\x2d\x7a\x36\xae\xa0\x27\xf4\xff\x88\x1e\x62\xf0\x6e\x4d\x52\x59\xde\x12\xde\x9a\xa8\xc1\x65\x9f\x2d\xd1\xb5\x97\xcc\xaa\xa9\xa3\x46\x65\xba\x36\xe6\xe9\xda\xac\x26\xa5\x19\x9c\x06\x0d\x90\x46\x4f\x24\xd4\x13\x2a\x43\x46\xd2\xb5\x1f\x93\xa9\x6c\xc0\x5d\xfb\x58\xcd\x6c\xb8\x28\xf8\xbc\xc2\x51\x5a\xbe\xde\x48\xc6\xaf\xe0\xc1\x58\x94\xb8\x79\x23\xa6\x39\x84\x69\x16\x5d\xe5\xa0\x65\xb6\xf5\x24\x59\x06\x6f\xde\xc8\x83\x35\x43\x42\xe6\x7a\xc6\xdc\xc0\x91\x83\x6b\xeb\xde\x1d\xd7\x33\xea\x06\x06\x31\x3f\x5f\xad\x8e\x8b\x8e\xeb\x39\x26\xe5\x4a\x25\x5e\x75\x10\x19\xa8\xa6\x1a\xa9\x03\x6b\x48\x01\x6e\x4f\xaa\xe7\xc5\x10\xf8\x92\x4d\x60\x63\x9b\x56\x8a\xc4\x3a\xfc\xbd\x13\x7a\xf2\x25\x15\x98\x6f\xb5\x7a\xd2\xa2\x90\x17\x94\x2d\xf0\x18\xe3\xf0\x41\xdb\x22\x23\x8e\x29\x6b\xcd\xb8\x07\xec\xdf\x2b\x2d\x37\xf5\x2f\xb7\x16\x20\xcb\xda\x8e\xe7\xd6\xe2\xf4\xe3\xb5\xe0\x11\xc4\x2f\x17\x51\x90\x39\xc0\x2a\xc1\xff\x52\x56\x0d\x8a\x93\x14\xa7\x4a\x83\x2e\x22\x3a\x97\xeb\xcf\x21\x7a\x67\xee\x7f\x20\xb6\x2f\xb7\x70\x8d\x42\x47\x50\x01\x32\xf5\xe5\x3e\x42\xfa\x9e\xdc\x87\xb9\xdf\xf6\x21\x53\xee\x13\x59\x3e\x0f\x32\x2f\x2b\xf6\x42\x54\x5b\x41\x6d\xc0\x13\x61\x2d\x64\x8a\x64\x9e\xe3\x1e\xac\x77\x61\x69\x42\x80\x91\x4c\x08\xc0\xe7\x95\x0b\x4c\xf3\x82\x36\x2a\x56\xc9\xf3\x01\x44\x47\x21\xc9\xc0\x3e\xaf\xb6\xd8\x15\x6e\x3f\x16\xcb\x02\xf0\x61\x3a\x6c\xfc\x03\x16\x29\xc4\xf5\x98\x9f\xd7\x15\x16\x94\xf8\xc9\x24\x49\x85\x85\x9c\x7d\xc9\x1f\xe4\xc6\x1d\x60\xe6\xfc\x79\xfa\x40\x1c\x7f\xa7\x07\x22\x85\x39\x03\xb2\x42\x34\x64\x31\x57\x07\x92\x4d\xe3\x17\xf6\xa4\xc6\x6b\xfa\x86\x47\xc6\xda\x0f\x9e\xe9\x48\x8e\x27\x76\xef\x1d\x9f\x39\xba\x15\x9d\x6d\xef\x8b\xed\x8b\x70\xc9\x27\xda\x3a\x9f\x7a\x26\x4e\x4f\x1d\xff\x97\x0b\x7d\xc1\x60\x36\xf9\xc6\xd9\xdc\x4b\x2f\x7c\xfa\x54\x7d\x65\xe8\xc5\xf8\xaf\x2f\xa2\x3b\xde\x3d\xcc\x98\xd2\x7c\x2c\xf6\xea\xe2\xf7\x9a\x11\xa2\x90\xf6\xd5\x71\xe2\x0b\xf1\x1c\x18\xb0\x3b\xa5\x54\x39\xb5\xe5\xfa\x49\x30\xbe\x9b\x4d\x82\xa9\x90\x27\xc1\x64\x8b\x3d\x5e\x29\x2b\x71\xeb\x69\x30\xd8\x11\xac\x3d\x11\xe6\xaf\xb1\xf1\xbf\xc5\x58\x18\xf6\x71\x6c\xf9\xff\x97\xae\x17\x0c\xfd\xda\xeb\x5d\x20\xc6\xfd\x56\x0b\xde\x4f\x2c\xfb\x6a\x1e\x93\xb3\x5e\xab\xd7\x5c\x79\xb3\x35\x63\x90\xa7\xa6\xa4\xc1\x7f\x78\xed\x73\xc5\x65\x5e\x1f\x11\x2e\x3b\xee\xe9\xbe\x4d\x1a\x88\x71\x5f\x9b\x8c\x69\xd9\xa0\xdf\x8a\x90\x6e\xc9\x9a\x33\x32\x1d\x1d\x40\x47\x88\xda\x84\x75\x65\x25\x25\xb8\x21\xb9\x86\x17\xcb\xc1\x30\x71\x51\x32\x9f\x69\x99\xac\x59\x8f\x1a\x87\x58\x95\xfa\x95\x04\xce\xf2\x76\x0b\xbc\xb8\x41\x8f\x33\xcb\x22\xaf\x97\xc6\x37\x6d\xa8\x24\xe7\x71\x04\xde\x2c\x70\xb7\x49\xe3\x4d\x4d\xd2\xda\x64\x7f\x7d\x4d\x33\x74\x2b\x26\x5c\x5a\xd3\x06\xd1\xd2\xac\x1b\xd8\x5b\x35\xa0\xc9\x1b\xa6\xdd\x14\x2c\x4d\xbb\x31\x7c\xfe\xb4\x1b\xfc\xd5\x1b\xcb\x13\x6f\xee\x95\xe2\xf2\x15\x73\x6f\x98\x73\x92\x30\x2d\xcf\x4e\xb3\x83\xfc\x37\xaf\x98\x9d\x36\x67\x73\x90\xc8\xd7\x06\x41\xb0\xba\x9c\x5c\xaa\xd5\xf3\x79\x95\xb0\xc3\x3e\xa8\x1c\xd1\x28\xde\x0c\xa2\x0c\xac\x34\x84\x91\x5a\x1e\xba\x68\x5f\x35\x57\x8d\xcc\x51\xf5\x79\xc7\xcf\xb0\x66\x16\x69\x57\x0c\x57\xfb\x67\x64\x6f\xba\xbb\xb6\x98\x95\xc6\xab\x7d\xca\x2e\xb0\xb4\xd2\x65\xf9\x7e\x62\x60\x3a\x9d\x9e\xea\x8b\xe7\x5e\x40\x2f\x95\xd7\x76\x92\x2f\xcd\x21\x36\xfa\x00\xf8\xb4\x4b\x8a\x1e\x90\x97\xbd\xf2\x6a\x1d\xf2\x51\x47\x90\x7c\x3c\xad\x17\x1c\x1a\x3e\x2c\x9e\x97\x18\xfc\x25\x36\x9b\x48\xa2\x50\x34\x83\x8c\x68\xcc\x65\x20\x23\x61\x23\x69\xcf\xd5\xc8\x23\xbe\xc2\xf8\x5b\x6d\x58\x87\xde\x55\x59\x48\x00\x4f\x00\xe7\x7e\xf5\x78\x68\x71\xd4\x2c\x1f\x76\xaf\x5e\x2e\xae\xc8\x73\xbb\x02\x71\xc9\x91\x2d\x0d\x8a\x8d\x2d\x9d\xf4\x3d\xf0\x77\xcf\xb5\xcd\xec\x4a\x66\xda\x12\xf7\x34\xfa\x12\x43\xdf\xe8\x18\xeb\x6b\x4d\xdd\x1d\xea\x6a\x0c\xb0\x81\xf4\xc3\x9d\x75\x69\x7f\x5b\xd2\xef\xab\xcf\x54\xc7\x33\x29\x0f\x33\x90\xfb\x34\xb9\x73\x7a\x5b\xf7\xe3\x01\x4b\x4b\xff\x68\x7d\xd7\xa3\x7b\x93\xf5\x23\x91\xd0\x96\x6e\xae\x65\xe4\xce\x0d\x0f\xbb\x53\x5f\x6e\x0c\x75\xd6\xfb\xe3\x83\x8f\x64\x16\x9e\x22\x3e\x86\xcc\xa4\x51\x9c\x22\x33\x69\x22\x78\x3e\xfb\x6d\x4c\xa5\x89\xde\x74\x2a\x0d\xbf\x6a\x2a\xcd\x25\x32\x95\xa6\x6a\xe3\x7f\x78\x2e\x8d\x35\x6e\x55\xdd\xde\x6c\x9a\xf1\xa9\xb9\xdd\xb7\x9c\x4f\xc3\x7a\x33\xb9\xff\x3d\x45\xfd\xff\x87\x7e\x17\x72\x32\xb7\x47\xff\x85\xb9\xa9\xd7\x6f\x49\x3f\xb3\x3d\xdf\xaf\x92\xa7\x7f\x82\xd0\x5f\x4d\x3d\x74\x5b\xf4\xc7\x6e\x4a\x7f\xcd\x2a\xfa\xbf\x2f\xd3\x8f\x87\xd9\x09\xf0\x62\xe4\x3f\xcc\x06\xde\x0a\x1e\xe3\xf6\x38\xb1\xee\x1f\xc2\xef\xf6\x9d\x39\x77\x6b\x66\x24\x91\x27\xf7\x4e\xeb\x1b\xbf\x58\x96\x87\x29\xc5\x1e\xe0\x47\x94\x6a\xa1\xfe\x7c\x25\x3f\x6a\x56\xf1\xa3\x3e\xcf\x0f\x61\x3d\x27\x7a\xc1\x56\x70\x9c\x58\x82\x6d\xc5\x36\xc2\x1d\x1e\xb8\xc3\xcb\xdc\x49\x49\xdc\x11\x02\x51\xb1\x15\x9f\xf4\xc5\xb0\x4c\x57\x4c\xbe\x25\xb0\x41\x03\x3c\x2a\xf1\xae\x8f\xd6\x34\x49\x4c\x12\xfd\x95\x18\x03\xd4\x5b\x30\xf2\xb5\xf2\x18\x0c\xb3\x66\x3c\x94\x53\x6d\x21\x0c\x13\xbd\xf8\xcb\x25\x8a\xc3\x51\xfc\x0e\x67\x16\x02\x9f\xc7\xc2\x7c\x30\x01\x5c\x5c\x1d\x4d\xdc\xc6\xdc\xa7\x3d\xc3\xe3\xfe\xae\xc6\xb8\xb1\xa8\xdc\x55\x68\x6d\x4b\xdd\xcd\x71\x6d\x89\xcd\x10\x53\x84\xab\x6e\x67\x20\x14\xf3\x09\x0e\x2b\x4c\x9e\x80\xa3\x33\xbd\x4d\xaa\x4a\x1d\xba\x6e\x46\x14\x2b\xcb\x5e\x27\x91\xbd\xcd\xd4\x36\xea\x7b\xb7\x21\x7d\xf8\xfb\x38\xb6\xf2\x62\x04\x5c\x79\x1d\xb8\xf2\xd6\x95\xa2\x88\x31\x6f\x0c\x5c\x76\x6c\xb5\x54\x0a\x66\x93\xd0\x84\xfb\xac\x92\xf0\x5e\x92\x13\x9b\xc0\x9d\x6f\xc7\x7f\x5a\x85\x47\x62\xba\xed\x11\xd2\xc2\x69\xce\xaa\x83\x05\xd2\xf9\x6a\x89\xf7\xc5\x37\xf0\xfe\xdf\x67\xb3\x6e\xda\x14\x7e\x7b\xf2\xab\x5c\xb3\x75\xfc\xd6\xe2\xfc\xb7\x6b\xf5\x96\xe7\x79\x7d\x84\xf0\xba\x81\x6a\xa3\xbe\x7f\x3b\xbc\xae\xe5\xe6\x9a\xa5\x72\x4b\x9a\x9b\xe3\x57\x76\x9c\xaf\x60\xf9\x5c\xa3\x54\x42\x6b\x34\x89\xdb\xe0\x59\x5c\x6a\x5c\x88\x5f\x67\x19\x70\x07\x7a\x55\xb1\x34\x92\xb3\xd1\x8c\xa3\x8e\x6d\x96\x39\xb5\xbb\xa0\x16\x77\x23\x08\x71\xb3\x10\xfc\x3c\xce\x8b\xe9\x66\xf2\x9d\x84\xff\xce\x1d\x90\xba\x4c\x9d\x6b\x34\x20\xdd\xde\x1e\xf4\x78\xf8\x2d\xfe\xb6\x44\x1c\x79\xf8\x16\xbf\x7f\x0b\xef\xd9\x13\x2d\xf7\xe1\x62\x7d\xe4\xd6\xfb\x70\xc9\xdf\x18\x2d\x89\xc5\x5b\xf1\x43\x49\xb4\x31\x10\x88\xc7\xf1\x0f\xb6\x31\x36\xd8\x8b\x8f\x98\x17\x00\xa9\xa6\xc0\xc6\x5c\x58\xee\x13\x04\xfb\x21\x44\xa2\x64\x2b\x00\xb5\x8a\x6a\xd8\x82\x2d\xd1\xb9\x7a\xa7\x17\x6f\x48\xbd\x0a\xd7\xf3\x84\x7a\x93\xb8\x49\xb9\x64\x66\x36\x18\xe6\x71\xff\x72\x1c\x91\xf4\x71\x51\x01\xd6\x0a\x3c\x43\xad\x1e\x1f\x1f\x77\xce\x13\x7b\xb3\x01\xdb\x1b\xcc\x45\x60\x73\x56\x1d\xc0\x43\x04\xf0\x37\x93\x9a\xf0\xa1\xcb\x7a\x73\xd6\x5a\x42\xc6\x79\x3b\xa4\x73\xbc\x9b\x4a\xf0\x16\x94\x56\xe0\x64\x05\x6e\x79\x80\xf0\x1c\xde\x2c\xc0\xb3\xbe\x09\xf3\xeb\x51\x9e\xf9\x4e\x79\x38\x89\xc3\x8d\x14\x64\xd6\x11\x39\x2e\x55\x19\xb8\x7e\x9e\x43\x0a\xa9\x0c\x0c\xf2\x4b\x7c\xb7\xdb\x7e\x21\x72\x5f\xda\xd6\xdb\xd0\xda\x7d\x32\x3d\x5e\xe6\x1b\x4d\x1d\xf9\x2f\xb9\xcc\x43\x3b\xfb\xe2\xad\x3d\x8f\xb5\x1f\x0e\xfa\xbe\x96\x4e\xee\x6a\x0d\xfc\x59\x61\x90\x77\x75\xb7\xd2\xe1\xb6\x9d\x49\x07\xba\x80\xf8\xb6\xe6\xf4\xdd\x0b\x47\x2f\x28\xe9\x9a\xc1\xd1\xee\x9e\x03\x68\x4b\x6d\xb2\xf9\xcd\x17\xdb\x0d\x3b\xc7\x8e\xb5\x65\xf6\xb7\x35\x35\xb5\x45\xef\xd8\xc9\xb9\xf9\x50\xd1\xfe\x03\x7a\x47\x41\x3b\xc3\x96\x56\x6f\x45\x85\xba\xd0\xe0\xe8\xcc\x2e\x32\xa7\x2d\x77\x92\xcc\x69\xab\xc1\xdf\xf8\x13\xc5\xfc\xf6\xf0\x62\x31\xbb\x3c\xaa\x0d\x20\xdf\x5c\x48\x16\xf1\x78\x7e\x68\x1b\x9e\xcc\x81\xad\x8a\x0f\x58\x89\xbf\x41\xb3\xca\x4e\x0a\x8b\xa6\x62\x4f\x59\xe5\xba\x48\x94\x38\xf6\x10\x8e\x0a\xd6\x61\x7c\x27\xfa\x82\xc0\xb5\x9b\x8d\x78\xab\x42\x35\x95\xd7\x8d\x78\x5b\xbb\xb2\xb8\x62\xe8\x1b\x5d\xb2\x7a\xe8\xdb\x78\xf6\xba\xba\x62\xcf\x93\xc3\xf5\xe8\xcd\x41\x71\x7a\xad\x19\x70\x53\xa6\xb6\xd5\x25\xc5\x8e\xa9\x8b\x92\x8f\xfb\x80\x39\x06\x98\x07\xcf\x46\xdb\x40\x0d\xdd\x6a\x3a\x5a\xf8\x26\xd3\xd1\xaa\xe4\xe9\x68\x73\x0a\x6b\x61\x30\x24\xcd\x1b\xfe\x0f\xcd\x47\x23\x30\xef\x76\x66\xa4\xed\x02\x94\x77\xab\x39\x69\xf4\x1f\xcb\x20\xef\xff\xbb\xf4\x12\x58\x77\x3b\xf4\x9e\x04\x54\x77\x2b\x7a\xd1\x39\x19\xd4\xe5\xe9\x9d\x20\xf4\x72\xb8\xeb\xe3\xf3\xe9\xdd\x78\x13\x7a\x23\x32\xbd\xcf\x13\x7a\xc3\xf2\x40\x69\xbb\x63\x43\xe2\x3f\x42\xb2\x04\xe1\x6e\x87\x6a\xa5\x84\xe0\x6e\x49\xf8\xa9\x65\x00\xc7\xca\xb4\x77\x02\xed\x41\xf2\xad\xaf\xc7\xaf\xa7\x9e\x07\xea\xd7\x4b\xd4\xaf\x27\x99\x5d\xa1\x81\x17\xcb\x00\x4e\x24\xa2\xf9\x6f\xa2\xc2\xac\x58\x1f\x9d\x75\x1b\x70\x62\xa0\x42\x8f\xbf\xe4\x87\x6c\x3e\x30\x65\x36\xa5\xad\x82\x17\x6b\xe0\xc5\x1a\x4e\x4c\xe9\xa5\xef\xa2\xaa\xc0\x23\xcd\xca\x12\x42\x8d\x79\xd6\x5a\xa8\x20\x1e\x2d\x85\x33\x6b\x2b\xb9\xb4\xfe\x56\x5c\x5a\x05\x18\xac\xcb\x2c\x5b\x55\x36\xfb\x1c\xc6\x4d\x2f\x03\x06\xf3\xf2\x34\xc1\xf4\x12\x74\xb8\x09\x1f\x99\xa3\x79\xc0\xb0\xf8\xe0\x92\xee\xf8\x57\xd5\x7a\xa5\x79\x6a\xa7\x28\x0d\x55\x80\xbf\x49\x60\xad\x79\x6a\xe4\x9b\xeb\x3e\x77\xce\x96\x51\x9e\x9d\x26\xea\x0b\xae\x9f\x9c\x06\x6a\x2f\x8d\x4b\x5b\xfc\x7b\x50\x6c\x79\x4c\x9a\xa2\x49\xd6\xdf\xff\xd9\xf7\xd7\xdd\x70\x7f\xab\x93\x91\xc7\xb5\xed\x06\x45\xcb\x8f\x69\xcb\x37\xf5\xe7\xef\x3f\x01\xf7\x37\xe1\x2e\xb0\xb5\xef\x6f\xbe\xc5\xfd\x2d\xf9\xd9\x71\x3a\xbd\xf1\x86\xd9\x71\x56\xa2\x15\x32\x13\x5e\x94\xe4\x3e\xbf\x8e\xde\x55\xf1\x89\xb4\x16\x3c\xef\xcc\x41\xf9\xf2\x79\x8b\x1b\xa6\xdb\xd9\x38\xc1\xcb\x8b\x05\x5a\x69\x26\x59\x05\x39\xd9\x82\x4b\xdc\x7a\x0c\x86\x45\x1a\x2f\x65\xd5\x42\x67\x9d\x2a\x5c\xd1\x2d\xd5\x4b\x45\x43\xb3\x96\x64\xb6\xc4\x52\x15\xf0\xab\xd8\x7b\xc3\xa4\xbb\x9b\x21\x5b\x99\x80\x0b\x6b\x42\xd7\x3c\x3d\x6b\x1d\x7e\x94\x67\x7e\x29\xfa\xc9\xcc\xfb\x5f\x4b\x33\x10\xc4\xca\xfc\xcc\x2f\x3c\xfc\x5e\xc7\x09\x56\x6e\x69\xf0\xbd\x95\x0c\xbe\xc7\xb3\xd5\x6d\x28\x34\x6b\xb7\x39\x0d\x21\x69\x98\x12\x87\x67\x94\xe1\x38\x34\x3f\x6f\x40\xa7\xc7\xf3\x06\xf4\xba\xaa\x57\x90\x68\xb5\xe1\x6b\x9b\x55\x9a\x3d\x60\x7e\xf4\xc7\x0f\xe7\x07\xc1\x68\x75\x36\x6b\x48\xd0\x9b\x66\x0b\xf4\xb8\x9f\xc9\x82\x7f\xe3\xd7\xed\xf8\xf5\x2c\xbc\xb8\xe2\x9c\xba\x25\x91\x85\x3f\xc7\x57\xa0\xe1\xb3\xda\x02\x8b\x9d\x9c\x53\x5f\xba\x22\xe7\xd3\xa5\x39\xfc\x2a\x63\x09\xc1\x08\x1b\x01\x23\x88\x4e\x2a\xb1\xe2\x7b\x00\x09\x36\xad\x42\x01\x45\x20\x5e\x09\xee\x1f\x27\xda\x2d\xe6\x9b\xcd\x27\x6b\x79\xf8\x64\xfb\x99\x41\x6f\x26\x91\xfb\x43\xc5\x2f\x7b\x47\xcf\xf5\x66\xde\xf6\x5d\x7c\x3f\x7e\xdf\x77\x77\xf5\x9c\xf9\x6a\xeb\xd3\xe1\x1d\xf7\x25\xf9\x7b\xdb\xc2\xd1\x3b\xef\x8d\x44\x06\x3b\x22\xe8\x95\xa1\x4b\xdf\xb8\x73\x6f\xfb\xd1\xd4\xf6\x81\x44\x7b\xcc\xcb\xb7\xd5\xf6\x54\xe7\x3e\xcd\x4d\x4e\xfc\xed\xa3\xed\xad\x53\xc2\x44\xd7\xe1\x81\x9a\xd0\x97\x8f\x0c\x0c\x7c\xb3\xab\x22\xdc\x73\x08\x9f\x3b\xc7\x33\xe0\x20\xee\x75\x52\x1b\x71\x25\x6c\xcd\x29\x70\xf8\x98\xb1\x47\x41\xd2\x5d\xc5\x0a\xe9\x6b\x47\xd7\x9c\x09\x87\x5b\xb1\xf0\x70\x47\xb1\x70\x23\xc1\x8e\x73\xca\x62\xcf\xba\xb0\x74\xd4\x5c\xf4\x91\xf1\x84\x9e\x75\xa0\x09\x85\xa1\x8d\x18\x79\x86\xcd\x82\xff\xa6\x33\xe3\x98\x35\x43\xd8\xeb\x27\xc9\x1d\xb8\x59\xb0\xba\xe6\x88\x39\xf6\xd2\xf5\xc1\xa9\xa4\x5b\x92\x0c\x9e\x92\xeb\xb6\xdb\xd6\x9c\x3c\xb7\x61\xad\xc9\x73\x6b\xd7\x6d\x6f\x73\xf8\x1c\x46\x3d\xb7\x1e\x40\x37\x8d\x21\xcf\xad\x86\xd0\x31\xce\x25\xcc\xf3\x9f\x43\x0b\x46\x34\xb7\xa6\x65\x0e\xc3\x99\x5b\xd1\x42\xd7\x2f\xe1\x19\x89\x96\x09\xb9\xfe\xbc\x36\x2d\xdc\x5a\xb4\xac\x5d\x7f\xbe\x6d\x5a\x88\x51\xbe\x35\x39\x15\x32\x4e\xb9\x25\x45\x91\x25\x4b\x9e\xa7\x69\x0f\xd0\xb4\x01\xe2\xf1\x31\x99\xa6\x68\x9e\xa6\x5a\x86\x4c\x53\xc1\xb5\xe7\xa0\x5c\x7b\x6e\x24\x14\x86\x2d\xe4\x48\x7f\x5c\xa6\xb0\x09\xa7\x9c\xe5\xda\x73\x1c\xd7\x9e\x3d\x15\x1b\xe4\xda\xb3\x58\x86\x0d\xb7\x58\x1b\x95\x29\x16\x5d\x15\xa0\x73\xb6\x00\x86\x6f\xf8\xcc\xb2\xf7\x73\xaa\xcf\xd7\x27\x8c\x6e\x31\x2e\xf1\xa6\xb9\xa2\xca\x5b\xce\x51\x64\x3a\xae\xd7\xc5\xc5\x81\x1b\x46\x2b\x02\xae\x93\xf8\xd5\x09\xfc\x2a\x23\xf5\xe7\x7c\xb5\x7e\x95\x8f\x28\x25\xf5\x67\xe7\xaa\xfa\xb3\xd7\x32\x3f\x6b\xf3\x62\x24\xe7\xd2\x2f\x7f\x5b\x0a\x20\xb9\x5a\x6d\x48\x2d\xe7\x8b\x38\x5c\x8f\x26\x45\x68\x97\x4d\x9a\x37\x1e\x33\x83\xcc\x54\x6e\x5c\x36\xde\x6b\xcb\xcc\x6a\xcc\x76\x1d\x9b\x56\x01\xb7\x1b\x78\x76\x62\xd9\x49\x6a\x6e\xe0\xd2\xd0\x32\x6a\xbb\x81\x61\xd3\x4b\x78\xcd\x71\xbd\x80\xbd\xb8\xb2\xfe\xc3\x00\xf6\x9d\x67\x46\xd8\x22\xb8\xc2\xdf\x60\x59\x47\x4e\x52\xab\xb4\xd4\x06\x72\xfe\x0e\x9f\xc2\x96\xbf\xd2\x72\x83\xfc\x95\x96\xec\x55\xdc\x05\xac\x73\xcc\xe3\xef\x12\xc5\xa3\x7a\x75\xf8\x68\x8f\xca\x46\xfc\x3f\x3e\xd2\xa5\x58\x45\xee\xca\x27\xc7\xe9\x5f\xe7\x92\x49\x9f\xcf\xed\x42\x31\xbf\x3f\x41\xc7\x7d\x7e\x7c\x19\xf0\xc7\xf0\xb9\xee\xcf\x82\x31\xb7\xa7\xdc\x5f\x53\x4d\x7f\x37\xb0\xc9\xed\xf1\xf9\x63\x35\x92\x0e\x4c\x32\x17\xd9\x00\xf8\x1c\x2f\xd8\xa8\x3d\xf2\xa4\xc9\x8a\xfc\x8e\xba\x97\x6d\x54\xa1\x85\x1c\x3c\x0b\xca\x0e\x06\xdb\xa8\x42\x2a\x8f\xac\x83\xe6\x4b\x6a\x85\xd9\xa6\x75\x95\x4b\x2e\x46\xd0\xe0\x61\x27\x66\x78\xdb\x2a\x87\x27\xc5\x21\xec\x79\x81\x94\x15\x9b\x48\x2a\xdb\x2a\xa9\xfc\x82\x0b\xdb\x71\xa9\xb0\x0d\xf6\x58\x6e\x2a\x08\xc0\x96\x9d\xed\xe9\xe8\x68\xbb\xff\xce\x53\xa8\x71\xe4\xa9\xcc\x50\x77\xe7\xbe\x9e\x53\xdf\xdd\x8a\x6a\xab\x61\x97\xee\x08\x3f\x93\x6c\x8a\xef\x6c\x0b\xb5\xa1\x97\x87\x7f\x70\x68\x47\xf9\xd1\xe4\xc9\x23\x1f\x8e\x5d\x9e\x6a\x0e\x7f\x3b\x7e\xee\xf8\xc7\xa7\x07\xe9\xe6\x62\xbe\x77\x2a\xd7\xe3\x8b\xf6\x4e\x77\x9e\x1f\x94\x6a\x72\x64\x26\x20\xd8\x65\x5c\x23\xde\x71\xd3\xa9\x80\xbe\x9b\x4c\x05\xac\x90\xa7\x02\x2e\xd7\x8a\x6f\x63\x32\x20\x76\x30\x37\x9d\x0e\xf8\x7b\xec\x57\x3e\x77\x42\x20\x2b\x3b\x95\xff\x94\xb5\x63\x6c\x7e\xf3\xc9\x86\x3e\xec\x48\x3e\x77\xf1\x4c\xde\x8b\x2c\xaf\x7f\x82\xd4\xba\xef\xbe\xe9\xfa\x2b\x6f\xb2\x7e\x5c\xf3\x66\xa4\x9a\xb7\xe0\x30\x2f\x57\xbc\x4d\x16\xa9\xe2\x7d\x1b\xd4\xc8\x2e\xe5\xa6\x04\x9d\x90\x3d\xc9\xe7\x93\xb4\xec\x46\x40\x87\x24\x9a\x3a\xe5\xba\xf7\xe8\x4d\xa8\x5a\xb3\x00\x0e\x24\xce\x7a\x98\x7c\xf1\x7b\x15\xb1\xb3\xbc\xc9\x71\x63\xfd\xbb\x12\x9f\x67\x29\x27\x03\x11\x6e\x77\x2a\xe5\xff\x5d\xdc\xd9\xc4\xb6\x51\x44\x01\x78\x67\xd7\x5e\xc7\xc9\xc6\x3f\x6b\xc7\xce\x6f\x9d\xad\xe3\x38\x5b\x37\x5a\x79\xb7\x8e\xeb\xfc\xa8\x85\x3a\xae\x89\xd2\xaa\xb5\x42\x1a\x55\xc5\xfc\x28\x84\x96\xaa\x4a\xab\x50\x45\x95\x89\xa2\xaa\x54\x1c\xa0\x42\xa5\xc0\xa1\x1c\x40\x55\x09\x51\x0f\x68\x37\x98\x0a\x22\x14\x84\x0a\x17\x54\x71\xa9\xa8\x88\x22\xe8\x09\xa4\x70\xa1\x42\x5c\x90\x5a\xc3\xbc\x99\x75\x6c\xa7\xb6\x88\x54\x24\x0e\x96\xf6\x47\xf6\x8e\xdf\xbc\xd9\x79\xf3\xe6\xbd\xef\xd5\xf6\x82\xd7\x14\xc2\x54\xd5\xd5\xc3\xbf\xc8\x64\xe5\xd1\x45\x05\x4b\x39\x86\x58\x5f\x43\x8c\x5c\x8d\x64\xb8\x63\x83\x64\x18\xf9\x2f\x48\x86\xa0\xaa\x5b\xa1\x19\x12\xad\xdd\x0a\xd2\xd0\xfa\x7d\x99\xee\x12\xb6\x30\xee\x67\x3f\xd3\x03\x71\x1a\x1e\xb2\x51\x6d\x59\x5f\xb2\x9b\x16\x10\x64\x54\x43\xd9\x16\x8a\x5e\x6b\xc6\xfa\x6a\xf5\xa9\x2a\xbc\x34\x61\xbb\xda\x21\xd2\x62\x06\x04\x27\xcc\x42\xba\x2e\xd8\x42\xc0\xe4\x75\xf8\xf8\x22\x5b\xf8\xd1\x02\x1a\x65\x78\x61\x62\x8d\xe7\xae\x3b\xab\xf1\x85\xc7\xfa\x8a\x7c\x61\x7e\xd1\x11\x72\x17\x1a\x6a\x30\x86\xbf\x23\x88\x61\xce\xec\x97\x0c\xee\x17\x95\xd9\x03\x99\x7c\x95\x3d\x03\x0e\xa9\x21\xcd\x90\xb1\xb2\xf6\x61\x65\xdd\xab\xe8\xdd\xd8\xee\x11\x88\xdd\x03\x1b\xac\xfd\xc2\xfa\xa7\x6d\xfd\x1a\xd6\x4f\xe8\xbb\x27\xc0\x02\xc2\x33\xf4\x67\xf5\x6e\x5f\x97\x97\x40\x05\x34\xb7\xe1\x87\xf2\xc0\x6d\xa2\xd1\x37\x84\x0d\x9f\xf6\xfe\xc7\xec\xda\xda\x5a\xbc\x95\x0e\xaf\xae\xd0\x5b\xd1\x00\xfe\x40\xd5\xb5\xb2\xf8\xf7\x1f\xdc\x3d\xab\x83\x69\xc6\x7a\x7d\xd9\x8c\x0a\x73\xe2\x59\x93\x44\x2f\xb4\x73\xb0\xb0\x37\x6b\x3d\x72\x66\x4d\xb2\x7c\x83\xc3\xc7\x35\xc2\x84\xbe\x5e\x44\x94\xb7\x38\x48\xb1\x15\x98\xe6\x79\x51\x55\x0d\x27\x40\x08\xd4\x25\x27\x81\x55\x3a\x5d\x90\xe5\xac\xe2\x83\x46\x7b\x84\x0c\x8f\x00\x18\xce\x1c\x71\x76\x3a\x45\xb2\x85\x6b\x34\x00\x82\x8d\x69\x21\x79\x92\xe0\xfd\xb2\x51\x92\xa6\xc7\x25\x82\xbf\x3b\x56\x96\xfc\x13\x03\x21\xb2\x1e\xaf\x08\x71\x8d\x6e\xca\x89\x12\x8d\x0f\x22\x63\x21\xb4\x5a\x58\x40\xa1\xc2\x1a\x1a\x2f\xc8\xc1\x8c\x72\x35\xff\xda\xe9\x13\xb1\x8c\x43\x08\xc8\x5a\x40\x1e\x1e\xdc\xc6\xce\xa3\x14\x7a\x6a\xbb\x3c\x60\xa6\x23\xec\x91\xbb\xd0\x10\xca\x3c\x28\xfc\x36\xbe\x8f\x5d\x0d\x3e\xa9\x05\x76\xe5\x6e\xc3\x7b\x50\xc0\xf6\xe1\x9f\xdc\x32\xb6\x0e\xfb\xb0\x4e\xe9\xd4\xeb\xa7\xb7\x6b\x86\x07\x2b\x54\x17\x75\x8d\xe8\x76\xcd\x50\xf1\xe9\xa0\x9a\x8f\x53\x0f\x60\x1c\x0c\xeb\xbd\xd4\x4e\x6c\x24\xd6\x21\x14\x22\x8c\xe3\x43\x87\x0a\x5b\x58\x8a\x1f\xf6\x75\xe1\x08\xbc\xff\x82\x9f\xaa\xdb\x4e\xb2\xb6\x6f\xef\x02\xff\xbf\xa1\xc0\x94\xb0\x23\xa1\xef\x76\xdf\xb4\xd9\x3d\xcd\xad\x61\xd9\xb4\x42\xc0\xfd\xe7\x81\xec\x78\x5f\x2b\x81\x39\x1b\x4d\x10\xf6\x19\x17\x97\x18\x89\x98\xe0\x2a\x44\x11\x41\xb8\x5d\x99\x3f\xa0\x8f\x6c\xa7\x94\xbc\x82\x61\xbe\x02\x8f\x42\x98\x5b\xe6\x60\xb4\x4a\xe6\x8e\x8a\xa0\x3d\x33\xbd\x27\x37\x7c\x68\xfe\xfc\xdb\x85\x5e\xb6\x75\xf7\x7e\x6d\x2e\x9d\x3e\x75\xe9\xd2\x4b\x47\xcf\x68\x2f\x4f\xf4\xe7\x4e\x1e\x93\x87\x78\xa1\x4e\x4c\xc8\xa1\x64\x42\x42\xef\xa0\x89\x67\xc7\x47\x8f\xa0\x3b\xaf\x2f\xcf\x68\xd9\xec\x97\xcb\xf3\xd3\x6f\x8c\x48\x07\x27\xa6\xc7\x32\x91\x53\x2b\x37\xbe\x5d\x89\x84\x78\x39\x7d\x21\x3e\x7b\xce\x11\xd6\xba\x32\xe7\x9d\x9e\x2b\x27\x2f\xe4\xc8\x5c\x43\xe3\x89\x0e\x31\x75\x24\xc2\x67\xb2\x32\xa2\x08\x32\x1c\x3a\x35\x43\xc0\xa3\xb6\x45\x25\x56\x80\xfd\xae\xe1\xc2\xa3\xd6\x65\x56\xbc\xc4\x76\xb8\x8f\x07\xb2\x60\x87\x40\x8d\x01\x97\x9d\x32\x58\x7d\x34\xe4\xc8\xe8\xe0\xb1\xb0\x5a\x3a\x13\xd5\xa3\x90\x6a\x46\x52\x95\x62\x93\x7e\xad\x9e\xca\x52\x1e\xab\xf4\xfb\xa3\xa1\x52\x08\x89\x16\x91\xb3\x60\xbb\x80\xc7\x73\x28\x80\x3e\x78\x2d\xcf\x9a\xd8\x8f\x8d\xca\x53\xf6\x62\xe5\x29\xd6\x62\x56\x9e\x32\x9d\x76\x48\xa4\x93\x76\x85\x9f\x0e\x31\xcb\x96\x09\x6e\x1a\xaf\xef\x9a\xb1\x3e\xea\x2e\xc5\xb0\xe1\x95\x5c\x93\x62\xb0\xd6\x32\xb2\xa8\xcd\x45\xb6\x3b\x49\x69\x99\x26\x28\x65\xae\xb3\xe2\x92\xb5\x48\x17\xad\xba\x14\x5b\xae\xb5\xd2\xaa\xee\xd3\x28\xe7\x2f\x31\xe5\xa0\xa5\xc7\xbd\x67\xb9\x5c\x76\xcf\xc2\x54\xdc\xab\x2b\xbf\x57\x57\xba\x87\xce\xb2\xf7\xd9\xf7\xac\x6d\x78\x35\xd2\x43\xd6\x22\x2c\xa9\xf0\x55\x2c\x0e\x81\x15\x84\xd6\x5d\x65\xf8\x06\xea\x2f\x25\x94\x0e\xf8\xf7\xb0\x61\x66\x82\x3a\xce\xae\xa6\x13\x07\xa4\xb0\x94\x8c\xc5\xc6\xb9\xab\x0b\x6b\x7b\xb5\xb9\xb0\x37\x28\x45\xda\xa2\xc3\x59\x78\x46\x06\x3f\x63\xa6\xf8\x0c\x97\x92\x6f\x28\x3d\x83\xa3\x84\x71\x0e\xb0\x7f\x0c\x57\x57\x7a\x06\x2d\x0d\x1f\x33\x73\xb6\x6d\x28\x93\x18\x95\xe4\x6d\xfb\x62\xb1\x23\x6b\x5c\x6f\x2c\x17\xf6\x86\x24\xb9\x4d\x4b\x65\x47\xaf\xdd\x23\xff\x23\x53\x58\x64\x67\x98\x3b\x8f\xfd\x8c\x70\x27\x79\x46\xe1\x97\xd8\xab\xdd\xde\xae\xce\x48\xe9\x19\x2c\x73\x8d\xbd\xcf\x1d\x27\xff\x43\x62\x0e\x82\xb4\xf4\x80\x66\x0a\x4c\xf7\xa8\x45\xe2\x52\xa5\xcc\x74\x9e\x16\xcb\xf6\xe3\xab\x7e\x48\x68\x61\xfc\x50\xb8\x19\x38\x4c\x6e\x18\x5b\x2c\x47\x57\x72\x9b\x64\x1a\xda\x74\x7e\x6d\x35\x85\x45\x1c\x09\xa4\x62\xb1\x31\xb4\xb8\x3a\x8c\x5b\x4a\x4f\x36\xe4\x2d\x05\x89\xbc\x47\x2b\x4f\x49\xbb\xe7\x70\xbb\x53\xa5\x76\xbb\xc0\x11\x6d\x0a\x88\x24\xde\x6c\xaf\x22\x23\xd8\x5f\x81\xcc\xa7\x00\xbe\xea\x85\xf9\x87\xf1\xb6\x98\xed\xf6\xc2\x1c\xe3\xa6\x1e\x68\xcf\x26\x19\x86\x36\x9d\xcf\x0d\x8c\x04\x43\x58\xa4\xf1\xa7\x57\xd1\x73\x03\x23\x01\x99\x1e\x9b\x5d\x18\x0c\x13\xf1\x2e\xac\x0d\x55\x9e\x42\x9b\x0b\x8b\x5c\x8a\xf4\xe7\xff\xd1\x66\xa2\x06\x66\x9b\x8b\xc7\xa6\x4a\x84\xba\x37\xda\x5c\xa6\x21\xb8\xcd\x08\x65\x51\x9e\x5d\xe6\xea\xcb\xb9\x37\x02\xe5\xde\x08\x15\xdc\x1b\x81\x72\x6f\x84\x1a\xdc\x9b\xec\x89\xe1\x64\x5c\x9b\x4a\xa7\xa7\xd8\x6c\x7a\x52\xd3\x52\xa9\xc9\x17\xc9\xbb\xde\x81\xd7\x15\xb7\x98\x1f\x08\x17\xb1\x9b\x19\xa3\xec\x1b\xc3\xdf\xa5\x69\x26\x5b\xc7\x70\x75\xa8\x2a\x25\xe2\x14\x61\x3b\xe1\x32\xd8\x8e\x49\x4b\xcc\x7b\xe9\x99\x97\x54\x15\xcf\x4b\x94\xb9\xd0\x43\x5a\x12\xaf\xf2\x4a\xaf\x72\xe2\x48\x47\x95\x70\x30\xa5\xc5\x92\xe8\xf9\x0d\x4a\x0f\x7a\x61\x44\x21\x57\xb1\x40\x94\x74\x30\xdc\xab\xa4\x52\x4a\x34\x15\x0c\x01\xb8\x27\x8a\x0f\xe0\x4a\x12\xcb\x49\xc6\x1a\xb9\x42\x58\x31\x3e\xa6\xf8\x3a\xb7\x0a\x4c\x83\xf9\x3a\xc7\xf2\xa0\x80\x3c\x24\xa3\x38\x90\xf1\x0e\x97\xc8\x78\x64\xac\x97\xbe\xbf\xad\xca\xf7\x0d\x2b\xcc\xfe\x16\xe8\x69\x13\x40\x83\x7f\x87\xdf\xcc\x9d\x81\xf7\x62\x12\xcb\xf3\xa6\x95\x67\xa2\x50\x8b\x7d\x27\x89\xe3\xe7\xd7\x97\x9c\x60\x9f\xf9\xb1\x7d\xc6\xa0\x9d\xce\xc6\x08\x6c\xda\x40\x31\xc5\xa0\x9a\xb7\xd7\x91\x0b\xd8\x80\x81\x9c\x3d\xd8\xc5\x51\x15\xdd\x7a\x57\x8f\xaa\x46\x67\x23\x58\x34\x7a\xa7\x4b\x6f\x85\xa8\xa6\x7a\x30\xdc\xf0\x8c\xd2\x48\xc2\x0f\xf1\xdc\x19\xc6\x4d\x92\x13\x86\x1f\xa6\x57\x91\x52\x56\x76\x41\xad\xaa\x60\x1c\xaf\xd0\xb4\x3e\x5a\xcd\x82\xb7\x49\x36\x89\xf7\x62\x63\xc3\x26\x81\x91\x6f\x16\x9c\x0b\x27\x5b\x33\x2c\x7f\xba\xf5\x44\xcb\xe4\xfc\xbb\x23\x1f\x9f\xd2\x78\x47\xdf\xc4\xfe\x99\xaf\xb6\xa3\xbf\x7a\x0b\x92\x05\x2d\x28\x85\x77\x3b\xbe\xbe\x38\x97\x1d\x38\xf7\xd1\xd1\x0f\xe7\xc6\x9d\x68\x65\xb6\xde\x2f\x0c\x0c\xce\xce\x2e\x1e\x57\xd0\xf4\x9b\x96\x48\xaf\xfc\xfe\xc2\x6c\x30\xe1\x8f\xce\xde\xd0\xc7\xa6\x8e\xa3\xc1\xd9\x4f\x5e\xa1\x6b\x98\x10\xfb\x16\xf7\x93\xd5\x4b\x78\x04\x39\x20\x0d\x01\xca\x15\x11\x46\x8a\x61\x17\xd4\x0d\x32\x1b\x8f\x07\x52\x9d\x03\xea\x42\x34\x41\x29\xd9\xbc\x95\x72\x67\xaa\x56\x93\xd5\xad\x04\x23\x95\xf7\xd2\xb0\xa3\x7a\x15\x54\xcd\x59\x4a\xe5\xf7\x01\xb5\xc0\x4b\x23\x12\x1d\x6e\x9a\xe7\xeb\x21\x09\x89\x41\x37\x72\x03\x19\x1f\x08\x34\x0a\x72\x87\xd0\x37\x9f\x1f\x43\x87\xd2\x57\xae\xee\x1b\xcf\x75\x9e\xb1\xdc\x3a\x7c\xf8\xe1\x6d\x76\x17\xfe\x5c\x2c\xfc\x88\x7a\x1e\xe6\xd0\x17\x3f\x73\x6b\x85\xfd\xb8\x2f\x61\x80\x5c\xe7\xae\xe3\x51\x12\xa3\x3b\x25\x40\x09\xb3\xe1\x16\x96\x1d\x17\x89\x61\xb4\x68\x65\xb1\x76\x25\x05\x87\x45\xdd\x92\x1b\x7e\xe0\xc1\x31\xfc\x85\x7f\x00\xc9\xad\xc9\xf7\x78\xda\x63\x60\x64\x60\x60\x60\x64\xba\xd8\x3f\xf9\x62\x47\x3c\xbf\xcd\x57\x06\x79\x0e\x06\x10\x38\x5f\x3f\xe7\x14\x82\xfe\x37\x8d\x63\x22\x5b\x16\x90\xcb\xc1\xc0\x04\x12\x05\x00\x85\xf7\x0d\x26\x00\x00\x00\x78\xda\x63\x60\x64\x60\x60\xab\xfe\x97\xc7\xc0\xc0\x29\xc7\xc0\xf0\xff\x3f\xc7\x44\x06\xa0\x08\x0a\x78\x06\x00\x75\x2d\x05\x94\x78\xda\x75\x93\x31\x4b\x82\x51\x14\x86\xcf\xa7\x16\x15\x12\x14\x41\x53\x4a\x48\x43\x83\x43\x44\x83\x44\x04\xd1\x20\x0e\x12\x12\x2d\x45\x44\x88\x83\x10\x21\xe2\x20\x12\x12\x11\x11\x11\xf1\x11\x34\x44\x43\x14\x08\x35\x34\x35\x89\xf4\x07\xc2\x5f\x21\x6d\xfd\x80\x88\x86\xde\x73\xcf\x2b\xc8\xa5\x86\x87\xf7\xde\xf3\x9d\x7b\xee\x7b\xee\xfd\x6e\xe4\x53\xd6\x63\x22\x12\x79\x12\x51\x8d\x49\x50\x81\xf6\xc0\x22\x68\x80\x0c\xc8\x21\xde\x02\x33\x18\x5f\x83\x4d\xb0\x83\x79\x01\x1a\x42\x0f\xa1\x27\xa0\x04\x5e\xc1\x0d\xb8\x04\xfb\x8c\x9f\x83\x07\xd6\xbb\xb0\x7c\xb7\x36\x6b\x75\xa4\xc0\xbc\x55\x90\xe4\x3a\xdd\x43\xeb\xd6\xc1\xbd\x79\x70\x73\xf8\x90\x22\xd8\x02\x67\xcc\xd3\x7d\x97\x99\xab\x5a\x05\x65\xd6\x2b\xb1\x97\x14\x73\x33\x16\x0b\xe2\xdc\xf3\x19\xbc\x99\x17\xd7\x5f\x91\x3e\xab\xf4\xa6\xf3\x63\x90\x07\x57\xa0\x4b\x7f\x67\xec\x29\x6f\x3d\xb9\x1e\x1a\xf4\xf5\x0e\x6a\xcc\x6f\xf2\xdb\x2c\xd8\x03\x69\x7a\x3a\xc0\x7e\x1d\x68\x87\xbe\xfa\x67\xaf\xb5\x37\x58\x33\xc7\x9c\x53\xf0\x01\xd4\xdf\x1d\xcf\xb3\x6d\x67\xef\x62\x3f\xe0\x8b\x7e\x7b\x96\x1b\xa8\xb7\x05\xeb\xd1\x9d\xf7\x1a\xc6\xdf\x03\xeb\xc7\xc8\x34\xe7\xc9\x7f\x18\xa1\xbf\xba\x47\xcb\x63\x65\xe0\x1e\x7c\x5e\xa8\x25\x8f\x0c\x6b\x55\x78\xce\x7f\x31\xc5\xbb\xf0\xe3\x5d\x8f\xc2\xc0\x3d\xf8\x84\xd4\xa6\x47\x9a\x77\xa6\x3a\x09\xe2\xe6\x29\xd0\x71\x3b\xba\x24\x32\x5c\x16\xe9\x6b\x24\x25\x12\xdc\x82\x09\x43\xba\xd0\x2c\x74\xdb\xbd\x9d\xb0\xcf\x50\x42\xc2\xd1\x84\x7b\x17\x35\xfb\xcf\xdd\xbf\xae\xf7\x71\x64\x04\xbb\xd0\x71\x5d\x8b\xf1\xbc\xa2\x75\x11\xd3\xb7\x38\x17\x7d\x14\xf9\x05\x36\xd2\x62\xc3\x00\x78\xda\x63\x60\x60\xd0\x81\xc2\x06\x86\x4b\x8c\x5b\x98\x92\x98\xf9\x98\x57\x30\xdf\x62\x11\x60\x71\x60\xc9\x60\x59\xc5\x72\x87\xe5\x0b\xab\x1a\xab\x19\xeb\x3c\xd6\x23\x6c\x46\x6c\x2b\xd8\xbe\xb0\x17\xb0\xff\xe0\x50\xe3\xd8\xc3\x69\xc7\xd9\xc2\x79\x83\xf3\x0d\x17\x1f\x97\x12\xd7\x22\x6e\x0b\xee\x2c\xee\x2b\x3c\x06\x3c\x45\x3c\xeb\x78\x9e\xf0\x86\xf1\xae\xe2\x7d\xc2\x67\xc4\x97\xc7\x37\x8b\xef\x0e\xbf\x1c\x7f\x1d\xff\x01\x01\x33\x81\x09\x82\x02\x82\x0e\x82\x7d\x82\x27\x84\x6c\x84\xf2\x84\xe6\x09\x5d\x10\xfa\x25\x2c\x20\x6c\x25\x9c\x26\x5c\x27\xbc\x46\x44\x49\x64\x9a\xc8\x33\xd1\x24\xd1\x0b\x62\x3a\xe2\x3c\xe2\x09\xe2\xdb\x24\x64\x24\xc2\x24\x3a\x24\x7e\x48\x3a\x48\xce\x91\x62\x90\x4a\x92\x5a\x24\xad\x22\xbd\x44\xfa\x87\x8c\x8e\xcc\x39\x59\x06\xd9\x18\xd9\x3e\xd9\x4f\x72\x3c\x72\x25\x72\x3b\xe4\x76\xc8\xf3\xc8\x9f\x53\xd8\xa7\xe8\xa2\xb8\x4a\xf1\x9c\x52\x99\xd2\x1e\xe5\x24\xe5\x3b\xca\xff\x54\xd4\x54\xec\x54\xde\xa8\x72\xa9\xc6\xa9\xae\x51\xe3\x51\xab\x53\x9b\xa7\x2e\xa6\x1e\xa6\xde\xa6\x7e\x45\xfd\x9b\x46\x80\x46\x89\xc6\x1b\xcd\x2a\x2d\x1f\xad\x4b\xda\x3c\xda\x6e\xda\x2d\xda\x4f\x74\x22\x74\x2e\xe9\x3a\xe9\x1e\xd3\xe3\xd2\xf3\xd3\x9b\xa5\x2f\xa4\x1f\xa2\x3f\x4d\xff\x91\x41\x84\xc1\x3e\x43\x0b\xc3\x05\x46\x1c\x46\x25\xc6\x5c\xc6\x8b\x8c\x8f\x98\xb8\x98\xcc\x31\xf9\x66\x1a\x65\xfa\xc4\x4c\xc6\xac\xc4\xec\x9b\x79\x99\xf9\x37\x8b\x3a\x4b\x13\xcb\x57\x56\x1b\xac\xb3\xac\x3f\xd8\x64\xd8\x3c\xb0\x8d\xb3\xe3\xb0\xf3\xb0\xeb\xb0\x3b\x67\x6f\x65\xff\xcb\xa1\xc6\xe1\x91\xa3\x87\xe3\x26\x27\x2f\xa7\x27\xce\x26\xce\xeb\x5c\x78\x5c\x72\x5c\xae\xb9\xa6\xb8\x9e\x72\x33\x70\xbb\xe0\x1e\xe5\xc1\xe3\x51\xe1\xb1\xc8\xe3\x19\x0e\xf8\xc5\x93\xc9\x53\xc0\x53\xce\x53\xc7\x33\xce\x73\x82\xe7\x21\x2f\x39\xaf\x0a\xaf\x4b\xde\x4c\xde\x69\x40\xd8\xe6\xbd\xca\x7b\x95\x8f\x8e\xcf\x04\x9f\x1d\x00\x44\xc8\x97\xfe\x00\x00\x00\x00\x01\x00\x00\x00\xe6\x00\x60\x00\x05\x00\x00\x00\x00\x00\x02\x00\x01\x00\x02\x00\x16\x00\x00\x01\x00\x01\x50\x00\x00\x00\x00\x78\xda\x9d\x53\xcb\x4a\x23\x41\x14\x3d\x6d\x7a\x44\xc7\x07\xb3\x72\x31\xcc\xa2\x70\x21\x06\x62\x6b\x32\x8e\x8b\x2c\x44\x0d\x04\x44\x41\x7c\xa0\xe0\xae\x13\x33\xda\x4c\x9b\x96\x58\x31\xe8\x62\x56\x7e\x8d\x0b\xbf\x42\x44\x7f\xc3\xa5\x1f\x20\x2e\xe7\xd4\xed\xea\xa4\x13\x3a\x33\x83\x14\x5d\x7d\x6e\xd5\x7d\x9c\x73\xab\x0a\xc0\x17\x3c\x22\x07\xc7\x1d\x07\xf0\xc2\x2f\xc6\x0e\x66\x68\xc5\x78\x04\xd3\x78\xb7\x38\x87\xdf\xce\xa8\xc5\x2e\xe6\x9c\x5b\x8b\x3f\xe1\xab\x73\x67\xf1\x28\xd7\x1f\x2c\x1e\xc3\xa4\xf3\x6a\xf1\x38\x56\x9c\x37\x8b\x3f\xe3\x6d\xa4\x60\xf1\x04\xbe\xe5\x66\x2d\x9e\x24\x5e\xb5\x78\xca\x51\xb9\x63\x8b\xa7\xb1\xec\xde\x58\xfc\x84\x19\xf7\xde\xe2\x67\x2c\xb9\x0f\xa8\x20\xc2\x05\xae\xd1\x42\x80\x53\x9c\x41\x43\x61\x1e\x75\xe4\xf9\x2f\x61\x89\x63\x05\x0b\x82\x8a\x9c\x0b\x5c\xdd\x83\xcf\x88\x33\xa2\x6d\x34\x70\xc5\xb8\x06\x9a\x12\xf5\x93\xb8\x85\x4b\xe6\x68\xd2\xe7\x9c\xeb\x1e\x42\xa2\xf4\xca\x1a\xab\x9c\x13\x07\xdc\xf1\x58\x27\xa2\x95\x97\xbc\xff\x62\x52\xe4\xe8\x67\x52\x11\xef\x06\xb3\x85\xd6\xb7\x67\x7b\xcc\xd6\x62\x9e\x3c\x36\x59\xdb\xd4\x69\x92\x47\x24\x7c\x34\xbf\x3d\xfa\x9d\xa2\x2d\x76\xab\xab\x29\xad\xa8\x80\x2d\xd1\x63\x98\x86\x38\xc0\x2f\xfa\xd4\xe9\x63\x3c\x86\xd5\x2a\x93\x47\x76\x3d\x35\x50\xb1\xdc\x55\x55\xfa\xcf\x88\x43\x5a\xa6\xbb\x81\x78\x2a\x46\x7a\x12\xff\x7d\x48\xfc\xc2\x40\x7c\xba\x5b\xd9\x67\x68\x7a\x9a\xd6\xac\x06\x54\xf7\xe7\x53\x5c\x8f\xf3\x69\xce\x27\xb4\x6b\xac\x30\xfc\x7e\xb4\x85\x7b\x93\x19\x14\x77\x03\x5a\x8a\x6c\x3b\xb2\xb7\xcf\x08\x53\x37\x22\xeb\x9a\xdc\x98\x38\xa3\xe6\x8a\x51\x64\x7c\x7d\x7a\x9a\xb5\xaa\x28\xd5\xf2\x37\x5d\x37\xb7\x4c\x61\x43\xfc\x4e\x86\xb2\xfa\x9b\x2e\xc5\x9b\x1b\x89\xa2\x4a\xc6\xa9\x76\x64\x78\x99\x27\x9e\xec\x85\x29\xa5\xc9\xad\x3e\xe8\xaa\x4c\x18\x1b\x9d\x11\x6b\x69\xc6\xf8\x92\x4b\x59\x8f\x90\xff\xba\x44\x27\xca\xdb\xa2\xb6\x21\xac\xb4\xf0\x34\xd1\x9b\xec\xa9\xc2\x0e\xbb\x15\xf7\xb4\x97\x79\xbb\x2f\x83\x39\xc9\xac\xfb\x52\x94\x5e\xf5\x98\xf5\xd7\x4d\xd8\xf8\xd4\x12\xbf\x50\x9f\xdd\x0b\x65\xa7\x43\x5b\xcb\xa9\xfa\x52\x77\x1d\xbb\x82\xb5\xdc\x64\xf3\x5a\x35\x59\x95\xb1\xc8\x71\x29\x67\x10\xd0\xd6\xc4\x9e\x70\xe8\xf5\x6c\x91\xfc\xab\xe4\xfb\x91\x98\x23\x72\xa9\xc9\x69\xc5\xaa\xe3\x37\x50\x95\x48\x45\x4e\x17\xd2\xaf\x12\x7e\x70\x36\x6f\xa3\xcc\xb9\x64\xe7\xe4\xbd\x2d\xff\x01\xa6\x2a\xec\x62\x00\x78\xda\x6d\xd0\x47\x4c\x54\x61\x14\x86\xe1\xf7\xc0\x30\x03\x43\xef\x55\xc5\xde\xf5\xde\x3b\x5c\x8a\x7d\x28\x63\xc1\xde\xb0\x2b\x0a\xcc\x8c\x22\xe0\xe0\x88\xd8\x8d\x05\x7b\x34\x26\x2e\x4c\x34\x16\x36\x6a\xec\x35\x1a\x75\x21\x04\x7b\x89\x25\xea\xc2\xa5\xb1\x41\x5c\xa8\x4b\x23\x32\xbf\x3b\xbf\xcd\x93\xef\x24\xe7\x2c\x0e\x41\x74\xe4\xf7\x61\x2a\xf8\x5f\x3e\x82\x04\x49\x30\xc1\x58\x08\xc1\x8a\x8d\x50\xc2\xb0\x13\x4e\x04\x91\x44\x11\x4d\x0c\xb1\xc4\x11\x4f\x02\x89\x24\x91\x4c\x0a\xa9\xa4\x91\x4e\x06\x9d\xe8\x4c\x17\x32\xe9\x4a\x37\xba\xd3\x83\x9e\xf4\xa2\x37\x7d\xe8\x4b\x3f\xfa\x33\x80\x81\x0c\x62\x30\x1a\x3a\x06\x0e\xb2\x30\xc9\x26\x87\x5c\xf2\x18\xc2\x50\x86\x31\x9c\x11\x8c\x64\x14\x4e\xf2\x29\xa0\x90\x22\x5c\x8c\x66\x0c\x63\x19\x47\x31\xe3\x99\xc0\x44\x26\x31\x99\x29\x4c\x65\x1a\xd3\x99\xc1\x4c\x4a\x98\xc5\x6c\xe6\x30\x97\x79\xcc\x67\x01\x0b\x59\x44\xa9\x58\x38\xc9\x56\xb6\x71\x9b\x43\x7c\x62\x3b\xfb\xd8\xcd\x11\x4e\xd1\x28\x21\xec\xe2\x3d\x5b\x38\x28\x56\xb1\xb1\x57\x42\xd9\xc1\x3d\x3e\x48\x18\x47\x39\xcd\x4f\x7e\xf0\x8b\x13\x9c\xe5\x01\x2d\x9c\x63\x31\x4b\xd8\x4f\x19\x8f\x28\xe7\x3e\x0f\x79\xc6\x63\x9e\xf0\x94\xcf\xed\xdf\x7b\xc9\x73\x5e\x70\x1e\x37\xdf\x39\xc0\x1b\x5e\xf1\x1a\x0f\x5f\x69\x65\x27\x4b\xf1\xb2\x8c\xe5\x54\x52\xc5\x31\xaa\x59\x41\x0d\x3e\x6a\xf1\xb3\x92\x55\xd4\xf1\x85\xd5\xac\xa1\x9e\xb5\xac\x67\x1d\x37\x38\xce\x46\x36\xb0\x89\xcd\x7c\xa3\x8d\x9b\x5c\xe0\x22\xb7\x78\xcb\x3b\xb1\x4b\xb8\x44\x48\xa4\x44\x49\xb4\xc4\x48\xac\xc4\x49\xbc\x24\x48\xa2\x24\x49\x32\x97\xb8\xcc\x35\xae\xd3\xc4\x15\xae\xd2\x4c\x03\x67\x24\x85\x3b\xdc\x95\x54\x49\x63\x8f\xa4\x5b\xdd\x95\xf5\x35\x1e\xdd\xe6\xaf\xf2\x6a\x9a\x56\x18\xd0\xa9\x29\x55\xcf\x37\x94\x0e\xa5\xa9\xcc\xfb\xab\xd1\xbe\xa8\xd4\x95\x86\xd2\xa1\xcc\x52\x9a\xca\x6c\x65\x8e\x32\x57\xf9\xef\x9e\x33\xa0\xae\xee\xea\xba\xbd\xc2\xeb\xf6\xfb\xca\xcb\x4a\x6b\x3d\x81\x91\xe1\x0a\x68\xba\x2c\x45\x7e\x5f\x75\x47\x31\x5d\x05\x7f\x00\xee\xa2\x95\xa1\x00\x00\x00\x78\xda\x45\xcd\x4d\x0e\xc1\x50\x14\x05\xe0\x3e\xa5\x2d\x55\x2d\x9e\x4a\xfc\x24\x95\x98\x3d\x06\x16\x20\x26\x6a\x62\x22\x46\x7d\x61\x03\x36\x60\x6c\x62\xc8\x0a\x2c\xe2\xd6\x48\x6c\x8e\x83\xd7\x6b\x76\xbf\x73\x92\x73\x1f\xe2\x75\x26\x71\xb1\xd6\xe4\x6d\xb2\x5c\x88\xab\xce\x57\x8e\xca\x46\x14\xe9\x35\xc9\x2d\x8e\x93\x1e\x92\xa3\xf6\x99\x45\x76\x92\x92\xad\x96\x54\x4e\xd2\xa7\x65\x8b\x9e\x55\x52\x5f\x57\x92\xf4\x5e\x3e\x18\x38\x9f\xb2\x22\xc2\xa2\x74\x51\x3a\xda\xc0\x03\xdc\x9d\x41\x15\xf0\x32\x83\x1a\x50\x95\x3f\x08\xf2\xcd\xa7\x3a\x52\x1f\x69\x6e\xaf\x8e\x60\x00\xd6\xfb\xcc\x06\x18\xcc\x99\x21\xd8\x98\x30\x23\x30\x54\xcc\x26\x18\x0d\x98\x2d\xb0\xf9\x9f\x6a\x83\xad\x1b\x53\x82\xed\x05\xb3\x03\xca\x19\x33\x06\x3b\x63\x66\x17\x8c\xa7\x05\x35\x49\xf5\x06\x33\xde\x5d\xe1\x00\x00\x00\x01\x53\x59\xec\x4a\x00\x00\x01\x00\x00\xff\xff\x7a\x6b\x5f\x8e\x24\x64\x00\x00") func fontsInconsolataRegularWebfontWoffBytes() ([]byte, error) { return bindataRead( _fontsInconsolataRegularWebfontWoff, "fonts/inconsolata-regular-webfont.woff", ) } func fontsInconsolataRegularWebfontWoff() (*asset, error) { bytes, err := fontsInconsolataRegularWebfontWoffBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "fonts/inconsolata-regular-webfont.woff", size: 25636, mode: os.FileMode(509), modTime: time.Unix(1492020681, 0)} a := &asset{bytes: bytes, info: info} return a, nil } var _fontsRobotoBoldWebfontEot = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x64\x8d\x73\x50\x25\x00\xa0\xf5\x6f\xb6\xed\xba\xd9\xb6\xee\x4d\x9b\x5d\x9b\x37\xdb\xd6\xd6\xcd\xb6\xb9\xd9\xb6\x6d\xdb\x9b\xbd\xb5\xb9\xad\xb6\xda\x6f\xbe\x37\xef\xcd\x3c\xfc\xfe\x39\x73\xe6\xcc\xfc\xce\x3f\x35\x00\x80\x53\x0d\x00\x80\x06\x40\x03\x60\x01\xff\x3f\xff\x0b\x28\x40\x0f\x34\x00\x00\x0b\x50\x54\xbd\x81\x06\xec\xeb\x53\x02\x54\x29\xff\x73\xf9\x01\x05\xa0\x04\x00\xa0\x54\x04\x1f\x94\xe5\x01\xff\x07\x54\x80\x3a\xc0\x09\x60\x0a\x70\x02\xb8\x03\x9c\x00\x00\x00\x22\x40\x02\xe0\x04\xb0\x07\x98\x03\x00\x00\x16\x80\x36\xc0\x02\xe0\x0a\x70\x03\xd8\x00\x9c\x00\x8e\x00\x4a\x00\x27\x80\x0d\xc0\x09\xe0\x00\x70\x00\x38\x01\x3c\x00\x4e\x80\x30\x80\x12\xc0\xf5\x1f\x8d\x1b\x00\x00\xe0\xff\x0f\x17\xe5\x7f\x33\x01\x00\x12\x1a\x5f\x54\xff\xf7\x37\x0c\xc0\x2d\x15\xc0\xe5\x05\xe0\xfa\x0e\x60\x9e\xc2\x9e\xbd\x88\x9e\xf0\xd6\xfb\x3a\x69\xad\xef\x22\x1f\xe8\x0d\x34\xeb\x72\x65\xb1\x62\x91\xfe\x43\xf7\x07\x4e\x32\x78\x87\x78\xa4\x2f\xfa\xf9\xf1\x3d\x15\xb1\x1e\x14\x06\x59\x63\xe2\x80\xd7\x96\xe1\xc0\xb6\xe9\x68\x85\x2f\x1b\x45\x1e\x34\x32\xd3\x39\x2a\xa3\xa6\xdb\xe5\x6b\xca\x21\x26\xae\x99\x94\x14\x33\xf3\xef\x1a\x88\x42\x1f\x04\xce\x99\x5a\xf8\x33\x91\x76\x2a\x71\x5c\xce\x58\xba\xf0\x34\xff\xc0\x95\xca\x0e\x71\x15\xd2\x52\xf2\xb1\x7f\x2c\x3a\xea\x39\x99\x8d\xe2\xde\x3d\x89\xe1\xd5\x0b\x6b\x82\xcb\x34\xa9\xb1\x75\x08\xef\xa6\xf2\xd0\xa9\x2c\x7b\xdf\x68\xd7\x1a\x0c\x2b\x01\xa7\x52\x72\xd0\xb7\xff\x76\x30\xbf\x18\xad\x82\xe4\xd1\x76\xfe\xdc\xf4\x8a\x79\x8c\xf2\x71\xbc\xd8\xa0\x12\xa9\x17\x8a\x20\xaa\x58\x9d\x90\xcf\x04\xe0\xba\x99\xc2\x45\x38\x2d\x51\xcc\xd5\x98\x21\xc8\xb3\x68\x7c\x5b\x93\x39\x62\x22\x77\x3a\x7d\x6a\x19\xef\x2a\x16\x64\x3e\x14\x11\x8b\x36\x21\x30\xe6\x65\xe1\x23\x90\x85\x8c\x65\x34\xf5\xec\xa3\x07\x8b\xe4\x0e\x95\x05\xcf\xce\x97\xfe\x3a\xa0\x51\xbb\x62\xff\x47\x55\xa5\x85\x44\xfe\xfb\xa1\xb3\xbe\xaf\x0b\x3b\xe6\x48\x95\x37\xfe\xcd\x05\xfb\x52\x10\x2e\xde\x04\xfc\x71\xa1\x93\x14\x71\xbd\x72\xa4\xa9\x99\x6b\xe0\x21\x88\xb4\x79\x3a\xca\x7a\x60\x11\x43\xd1\x61\x10\x17\x10\x76\x99\x4f\xe8\xad\x5b\x18\x1e\x56\x85\x9a\xa8\x3a\xdb\x70\x07\x44\x1b\xc3\x28\xe8\x6d\x8b\xeb\x3b\x08\x62\xd9\xb6\x41\xa6\xe7\x3d\xc9\x64\x65\x79\x42\xf1\x0f\x85\x81\x75\x07\x56\xf8\x61\x04\x98\x56\xb5\x68\x16\x24\x86\x5c\x6b\xc8\x0b\xed\x0b\xf0\x78\xac\x40\x54\x7f\xd5\xfc\xb2\x83\xe1\xa0\xc4\x69\x5b\x2a\x5d\xf2\x5c\x75\x4e\x43\xbb\x9c\xc6\xc8\xc4\x49\x2e\x00\x5b\x1c\xe5\x10\x70\x7b\x4e\x49\xe9\x20\x9f\xb8\x49\x73\x14\x20\xdf\xa0\xcb\xf4\x98\x31\x98\x53\xa6\xef\xf4\xf2\x32\x76\x32\x99\xb7\xda\x14\x58\x23\x34\x20\x6b\xf8\xf1\xac\xa9\xc9\xcd\x14\xb9\x99\xc2\xd3\xa7\x24\xb2\x42\x31\x19\x08\x8c\xf3\xa3\xbb\xcf\x05\xe6\x76\x66\x62\x53\xe2\xe2\xa0\xc2\xc4\xc2\xe8\xc0\xd9\xaf\xe8\x20\xab\x01\xf0\x1a\x54\x9b\x93\x07\xde\x06\x9a\x0f\x20\x4d\x90\xd8\xfc\x28\x51\x4e\xaa\xe2\x9e\x4a\x6c\x64\x1a\x52\x49\x29\xac\xb3\x22\x51\x16\xea\x38\xc4\x97\x3b\x5c\x6d\xde\xa6\x9e\x0c\x2e\x66\xd3\x5c\x36\x1e\x17\xac\x03\x10\x8b\x79\x8e\xfe\x99\x09\x96\x51\xcf\x54\x56\xda\xaf\x12\xae\xcf\x18\xc2\xb6\xda\xa2\x5d\x20\x8e\x40\x24\xd1\xa1\x19\xb5\xec\xaa\x5c\x2d\xbb\x15\x0f\xb5\x95\x03\x02\x99\xe8\xc0\x65\x78\xa9\x8d\xeb\x98\xbe\x6a\x70\x24\x07\xdc\xfb\xbc\xc1\xc1\xa0\x31\x53\x22\xc1\x17\x95\x81\x06\x68\x18\xc6\x18\x84\xc5\xf6\x99\xa8\xd7\xc4\xaf\x51\x48\xa4\xb1\x81\x9f\x79\xa3\xed\xad\xc6\x74\x4e\x74\x71\x43\x99\x44\xe1\x81\xd0\x3c\xad\x84\xb8\x32\x8c\xf5\x61\xc1\x7c\xcc\x67\xa6\xe5\x79\xd1\xf9\x80\x21\xe8\x65\x9e\x56\xe5\x6b\xf9\x36\x8c\x4c\x08\x17\x29\x9b\x41\xbb\x8b\xf7\x81\xeb\x11\x50\x01\x46\xbe\x90\x10\x54\x67\xae\x37\xba\x63\xbe\xbe\x37\x26\x27\x71\x68\x61\xd1\x51\xd1\xe1\x23\xa0\xaf\xa2\xab\x2b\x6a\xc0\x50\x75\xa0\x3b\x1c\x81\x21\x45\x3e\x21\x86\x95\x0e\x7e\xec\x80\x63\x8c\xde\x98\x1d\x4e\x1c\xd9\xf4\x0e\x9f\x61\x26\xa3\x37\x63\x36\x21\x0c\x45\x81\xd2\x1c\x1d\x64\xa2\xa9\x28\x9a\x24\x37\x6c\xd2\xde\xdf\xfe\xb2\xc0\x77\x7e\xc9\x3f\x43\xdd\x57\x5b\x40\xc5\x4b\x1f\x1d\x04\xac\xa3\x54\x30\x2c\x90\xa6\x49\x54\xa5\x66\x4b\x64\x53\x2c\xd6\x30\xed\x17\xcb\x0a\x71\x74\xb5\xa4\xf4\x49\x3a\x27\x2b\x10\x05\x7b\x22\x34\x10\x1b\x47\x03\xc6\xcc\xac\xf0\x84\x95\x58\x39\xda\x4e\x37\xed\xec\xf4\x7b\xea\x1c\xdc\xb6\x0b\x84\xec\x9d\xe5\x48\x62\xf1\xe8\x6e\x7f\xa7\xb1\xca\x31\x92\x99\x5f\x91\xba\x9a\x51\x3d\x4f\x32\x56\x12\x5c\xb8\x48\x3f\xed\x58\xbc\x00\xe7\x3e\x14\x7f\x6c\x33\x66\x57\x69\xc1\xd6\xf2\x10\x64\x9d\x74\xe2\xed\xac\x52\x0b\x9f\xcf\xf6\x71\x40\xf1\x09\xd3\xb2\x41\x6b\xa7\x22\x82\x10\xbd\xb6\x34\x47\xca\x47\xa5\x33\xac\x5a\x4c\x45\xf3\xcc\xdd\x01\x39\x87\xfd\xa8\x8a\x41\x23\x1d\x40\xf3\x70\x6e\x49\x7b\x7c\x3b\xc3\x4a\x99\xa8\x42\xd1\x99\x6c\xc4\x2f\xa4\x0e\xa1\x1b\x6b\x66\x15\x49\x08\x92\x38\x59\xba\xe5\xb8\xb5\xd4\x40\xb6\x4e\x25\xb6\x16\x29\x63\x1f\x02\x13\xc4\x38\x5c\x96\xa9\x98\xf6\xd2\x18\x6f\x91\x10\x42\x1c\x60\xf0\x0a\x4f\x01\x6f\x65\x01\xb6\xb7\x21\xdc\xfc\x26\xfd\xe9\x2f\x92\xf4\x11\x00\x22\x92\x04\x34\x54\xa7\x2b\x9d\x28\x4f\x3e\xa6\x6a\xa1\x6b\xea\x42\x23\x5b\xc9\x52\xca\x58\x69\x25\x86\x60\xca\x4d\xaf\x44\x59\x1c\x43\xc4\x08\xab\x2c\x02\x48\x16\x76\x98\x61\xee\x60\x9c\x20\xb7\xc4\x20\xfd\x50\x0b\x36\x9c\xdb\xf9\xdc\x18\x53\x3b\xf3\xf1\x3e\xdd\x69\x91\x63\x60\x5a\xef\x10\xe0\xdf\x1c\x08\x2a\xd2\xb1\x90\x79\xec\x18\xb5\x19\x2a\x48\xf4\x83\xdf\x99\x71\xcf\xd9\x0c\x40\x34\x14\x6d\x11\x2c\x7c\xc1\xf5\xc2\x4e\x88\x61\x7e\x57\x4f\xda\x6b\xcb\x67\x83\x24\xca\xb1\x77\x79\xbc\xe8\x41\x77\xe0\x02\x4e\x13\x43\x80\x0b\xf9\x67\x2b\xff\x2c\x83\xe7\x90\x4c\x31\xe5\x04\xa8\x89\x46\x04\xc4\x2a\x60\xd9\x5d\xbc\x00\xd2\xef\x94\x1a\xd8\xa8\x5e\x32\x70\xc6\x3f\x0e\x31\xe9\x0f\xa1\x40\x40\x1a\x68\x72\xdb\x9a\x30\xd0\x8e\x0e\x25\xd3\x37\x29\x28\x99\x4a\x96\x22\xdd\x73\x60\x24\x17\x38\x04\x2b\xa2\xd9\xe2\xf9\x61\xd2\x81\xf6\x52\xb7\x66\xc4\x3a\xa4\xc8\xac\xc8\xa8\x85\xc1\xbf\xe5\x8b\x06\x76\x08\x72\xd8\x04\xbf\xe4\x7c\xc8\xa8\xf1\xc0\xbe\x2c\x2b\x94\x30\x02\x21\xdc\x84\x48\xf2\x9a\x38\x02\x23\xbd\xfb\x34\xc5\xad\x73\x22\x05\xe7\xaf\x0c\x20\x2b\xd4\xb2\xc2\xba\x97\xa2\xdd\x83\x6d\x82\x49\xe4\x7d\x18\x2d\x8c\x31\xa2\xc8\x12\x42\xca\xf8\x58\x2c\xd7\x50\x5f\x6d\x01\x84\x72\x2f\x72\x30\x78\xa9\x22\x9c\x94\x8a\x4c\x13\x75\xbf\x3c\xbe\xe8\x12\x53\x44\x28\xef\x5d\x6e\xad\x0b\x8a\xd4\x84\x78\x92\x50\x26\xf2\xd4\x35\x53\x06\x72\xfa\xf4\x5d\x98\xb1\xf6\x17\xa1\x22\x68\x6d\x0f\x95\xee\x50\x58\x61\x03\xd6\x93\x20\x96\x45\x42\x70\x0a\xf5\x90\x73\x16\xf4\xe6\x86\x29\x2c\x3e\x9e\x3c\xf1\x6d\xd2\xa2\x18\x95\x55\x30\xf1\x7c\x4b\x90\x89\x95\x38\x04\x48\x27\xc4\x5f\xb4\xfc\xe1\xf2\x77\x5a\xe5\xb1\x1f\x9f\x55\xdc\xce\x91\x33\xf9\x47\x5b\x3d\xb2\xac\xca\xb6\xca\x3a\x33\xfd\x9b\xdc\x07\xed\xef\x5b\xcf\x8c\xe6\xd4\xa5\x57\xf5\xb8\x97\xf7\xe3\xb3\x68\x71\x74\x10\x27\x85\xf1\x67\xf9\x1e\x73\x96\xdc\x8b\x92\x74\xd7\x05\x6b\x2d\x4f\x92\xd8\x6e\xdc\x27\x7a\xdd\x6f\xce\x4f\x02\xc8\x96\xad\xba\x16\x6f\x30\x70\x2c\x77\xf2\x89\x63\x97\x43\x49\x11\x3d\xe9\x52\xfd\xf8\xa8\x95\x44\x1a\xeb\x9c\x50\xf6\x4b\x12\x58\x42\x34\x48\xa0\x6f\xfe\xc7\xf4\xf1\x18\x31\x41\xcd\x2b\xbb\x0e\xd3\x24\xcd\x34\x7c\x41\x4d\x5c\x92\xd9\x35\xff\xe5\x04\xdc\x6d\x31\xb2\x56\x03\x27\xab\x4d\x80\x81\xb9\x02\x95\x79\xcb\x19\x1b\x93\x37\xed\x60\xdc\x92\x7b\x03\x32\x64\x16\xae\x7e\x2a\x87\x15\xd8\xc1\x48\xa3\x5a\x6d\x20\x4d\x39\xb3\x08\x1a\x0d\x55\x41\x24\x4f\x52\x12\x43\x2c\x81\x4e\x19\x38\x2c\xa1\x1e\xa8\x45\x4d\xc2\x33\x83\xa6\x0f\xf2\x97\xd2\x87\xcf\x64\xfd\x41\x31\xa8\xdc\xec\xf4\x21\x1c\x98\xcc\x7c\xa6\x85\xcb\x7d\x57\xd4\x15\xc6\xa3\xcd\x42\xc3\x7e\xb1\x20\x68\x1f\xd5\x81\x13\xba\x33\x76\x80\xfb\x48\xda\xd7\xe2\x9a\xbd\xa0\x0a\xfc\x4d\x6d\xdd\x29\x70\x11\xa7\x91\x20\x28\x6d\x19\x84\x25\xa9\x37\xa0\xf5\xe6\xea\x56\x8a\x19\x75\x53\x12\xf8\x64\x2d\xf0\xfe\x58\xae\xf0\x0d\x6a\x56\x06\x88\x5d\xfc\xb4\xc1\x00\x84\x5f\x31\x2a\x93\x58\xf8\x0a\x49\x8a\x03\x21\xd9\xa4\x40\xfa\xe3\x13\x12\x87\xc1\x19\x93\xc8\x5c\xa6\x01\x83\xba\x7b\x62\xa2\x3f\xb0\x04\x7e\x1b\x50\x8f\x87\x67\x74\xde\x72\x2e\x28\xd8\x8f\x54\xbf\x52\x36\xc3\x37\xba\x3a\xa0\xfc\xe2\x52\x97\x8f\x4f\xc3\x65\x33\x94\x25\x91\xd3\x4b\x1b\xdd\x5b\x23\xa0\x89\x52\x64\xd6\xc4\x73\x1f\x84\x31\xa1\x31\xd4\xa6\xa4\x56\x69\xa0\x0b\xb2\xfb\x64\x6f\x18\xc7\xfa\x64\xb2\xeb\xb6\x1f\x33\x57\x8f\x39\x88\xd6\xaa\x63\x06\xf2\x14\x58\xb2\xb2\xb6\x14\x3b\xff\x62\xf1\x26\x52\x07\xa2\xae\x8d\x97\xcc\xa8\x52\xf9\x6f\xa5\x66\xb6\x3d\x1c\xc4\x35\x6e\xc5\x7b\xc7\xad\xcc\x81\x43\x91\xab\x6e\xea\x77\x1f\xa2\x33\x79\x88\xf4\x62\x44\x20\x34\x50\xbb\xa4\x2a\x12\x81\x8e\xee\x34\x49\x8b\x33\xb7\x53\xb7\x22\x86\x2f\x02\x85\x5c\x58\x5f\xbd\x29\xc6\x53\x5f\xcb\xe1\x94\x16\x0c\x08\x37\xd7\x51\xba\x17\x1c\x0c\xd4\x92\x3c\xe0\x18\xea\x14\x68\x1d\x47\x10\x2a\xc3\x4b\x90\xbc\x18\xf3\x44\xb6\x0d\x40\x0e\xd9\xcb\x64\xb1\xeb\x17\xa7\x4a\xdf\x85\xef\x5a\x66\xdd\x09\x0e\xc3\x1d\xd8\x63\xee\x6a\x2e\x61\x68\x3d\xe6\xf4\xcd\x78\x57\x40\xe3\xde\x83\x41\xf0\xd5\x24\x06\x41\x6c\x1c\x71\x74\x19\x8a\x74\xa5\x79\xd9\xd6\x09\x0a\xd9\x2e\xda\xc9\x42\xe9\xc2\x3a\xd6\x47\x9f\x3c\x72\x45\x68\x8e\x0e\x36\xb5\xca\x63\xc6\x87\x54\x44\xb2\x0c\xab\xf1\x4c\xa2\x99\x99\x3e\xbc\x8a\xe5\xc5\x4b\xde\x67\xef\x8b\x84\xbf\x41\xd9\x2f\x5a\x95\xed\xcd\xf3\x43\x47\xdf\xaf\x6e\xab\x5d\x10\x31\xe0\x1a\xa6\xf0\x82\xf8\x8e\x0c\x72\x84\x0e\x9c\x37\x3b\xcc\xf8\xb6\x0b\xf5\xf5\xc6\xf7\x9c\xf0\x98\xd2\x7c\xcd\xbe\x96\x8d\xde\xf9\x6e\x5b\xf0\xeb\xff\x42\xa9\x77\x10\x20\x9d\x4a\x7f\xa9\x34\xa8\x17\x98\xc2\x8b\x2f\x4f\x9b\xa7\x52\xa7\xf1\xb6\xcb\xfd\x3e\x65\xf3\x2d\x66\xe3\xe9\xba\x64\x52\x73\x3c\x8e\x48\x27\xb3\xe1\x77\x0a\x5e\x4b\xd3\xc2\x76\xba\xd8\xce\x79\x48\x7c\x16\x53\x58\x80\x4d\x2a\x45\x4a\xba\x79\x50\x23\xa1\xbf\xe4\xbe\x1e\x13\xbf\x57\x60\x8c\xca\xa0\xcf\x81\xde\x55\x32\x22\x73\x38\x14\x54\x1f\x25\xf4\x9a\x92\xe0\x33\x4e\x90\xe3\x5e\x0f\x2b\x9c\xb2\x19\x73\x4a\xa7\xf1\x14\x4f\x52\x4c\x90\x37\x0e\xe4\x47\xe3\x6f\x59\x04\x4a\x9d\xeb\xef\x80\x2e\x68\xbc\xec\x4f\x8a\x07\x98\x81\x5c\xe4\xcc\xd9\xef\x7b\x7f\x06\x60\xf5\x78\x0f\x2b\x7a\x62\x2d\x03\x8c\xd2\x5a\xe1\xa2\xf7\x62\x7b\xb6\xe7\x6b\x17\x2d\x58\xcd\x74\x1c\xf9\x97\x10\xbb\xbf\xaf\xd8\x5e\xe2\xe2\xc2\x8e\xed\xfe\x92\xf6\x6d\x2d\x7c\x55\x99\x53\x20\x02\x7a\x80\x8d\x6f\xbd\x2b\xbd\xd0\x7b\x3c\x1a\xfe\xb0\x52\x27\x33\xf8\xfb\x9a\xf9\xa0\x8d\xb1\xc1\xb7\x2e\x1e\x80\x84\x3f\x42\x51\x54\x4e\x8f\x0a\x1e\xda\xe1\x5d\x63\x2b\x46\x22\x3a\x9a\x17\x88\xd5\x43\xca\x3a\x5e\x6b\x0c\x9c\x59\x84\xfe\x29\xf6\xd2\x10\x9b\x14\x7b\x15\x4d\x89\x36\x40\xc0\xb3\xa2\x77\xc1\x82\xe8\x9a\xbb\xa5\x98\xaf\x31\xf1\x31\xce\xab\x9a\x80\x8a\x85\x8d\x23\x39\xe1\x17\x8a\x5c\x18\xce\x6d\xef\x37\x84\x13\x47\x89\x33\x12\xa9\xba\x61\x07\x1b\xf8\x89\xe6\x4a\x1a\x5f\x68\x96\xc6\x2e\xf2\xc4\x70\x58\x8a\x04\xfc\xb5\x80\x7a\xfd\xf6\x40\x50\x34\xbd\x83\x35\x6c\x0d\x92\x73\xf6\x15\x06\x5e\xba\x10\x36\x1c\x75\x97\xd5\x1a\x01\x2d\xf6\x80\x76\x09\x08\x6d\x5c\xe8\x4b\x5e\x73\x9c\x88\x3a\x54\xc7\x02\x18\xfe\x14\x5e\xb6\xc5\xc6\x81\xfe\xde\x3d\x6c\x11\xc9\x2d\x1b\xa6\xeb\xa9\x64\x64\x99\x4e\xfe\xfe\xa0\xe9\x26\x43\x8e\x37\xce\x14\xa4\xf9\x92\xf8\xf1\x7b\x82\xfa\xa1\xa4\x43\x74\x6a\xa0\x51\x54\xef\xf1\x5e\x60\xa6\x59\x16\x45\x69\x38\x7e\x25\x7d\x78\xb2\x52\xda\xc6\xea\xea\x11\x2b\x40\xaa\x53\x69\x9f\x46\x60\xc8\x36\x0f\x3b\x41\xdb\xfa\x73\x6e\xa3\x2a\xb8\x4c\xbe\x16\x99\x58\xae\x40\x76\xb1\x49\x27\x01\xd6\x8c\x08\xa0\xb0\xe2\x40\xc3\x12\xf4\x0f\x53\x5a\x85\xf2\x2c\xea\x0e\xfe\x0a\x66\x76\x86\xc8\x7b\xe2\x61\x54\xef\x27\xea\x6e\xf5\xd8\x19\xd6\x27\xfe\xb3\xe0\xf5\x32\x74\xe5\x20\x60\x85\xa3\x9c\x5b\x24\x9d\xa4\x4d\x8d\x50\xa3\xa4\x26\x1d\xb3\x0e\xaa\x82\x66\x12\x5b\xdd\x2b\xba\xf3\xc5\x36\x15\x3a\xbc\x21\x0b\x83\xbd\x7f\xe5\xdd\x76\x17\xc3\x36\x2b\x20\x0c\xa1\xc1\xb6\x56\xf1\x58\xd3\x76\x25\x64\x2d\x08\x65\x9e\x71\x74\xb9\xfd\xc8\x60\x9e\x11\xdb\x88\xdd\x52\xf9\x73\x3b\x89\xd5\xf6\x31\x8e\x48\x7e\x59\x5f\xd1\x2e\x5f\x31\xdc\x90\xfa\x8b\xe7\x53\x08\x7a\x24\xfc\x15\x03\xf9\x1d\x06\x16\x81\x4a\xb4\xe3\x13\xfc\x98\x71\x11\x56\xdb\x0d\xd2\x5f\x2f\x7c\x8d\x42\x3c\x8d\x42\x32\x66\x8a\xc1\xc2\xbf\x29\x15\xef\xcf\x22\xb2\x72\x49\x52\x9b\xdd\xfc\x62\x5a\x94\xc4\x83\x06\xf3\x21\x73\x5a\x68\x3d\x4c\xd6\x25\x86\x27\x3f\x81\xd4\xb6\x24\xf1\xb8\xaf\x5b\x72\x16\x27\xb8\x15\xe8\xb8\xdd\x0f\x23\xa2\x8f\xc4\xb2\xcd\x5b\xa8\x08\x8c\x46\x79\x91\x99\x93\x61\xc4\xc3\x83\x4b\xab\x49\x1b\x05\xf7\x93\xb2\x3b\x2b\xcb\x10\x9d\xe4\xae\x91\x0c\xf9\xa7\x51\x56\x8a\x54\xb1\xf4\x98\x52\x39\x55\xa9\x9e\xf9\x3d\x7f\x61\x0f\x3a\x18\xd7\x81\xbe\x80\x4a\xe7\x91\xeb\xaf\xe8\x50\xbb\xb2\xfc\x60\xb6\x79\x39\x93\x09\xf8\x86\xd9\x83\xfd\x3f\x7b\x91\xc8\x9a\x46\xf5\x22\x73\x5b\x9a\x76\x38\x0f\x26\xae\x86\xb5\x38\xa8\x51\xa9\x3d\xeb\x63\x6d\xd7\xcf\xe9\xbf\x8e\x8c\x14\xe0\x51\x2e\xa9\x45\x54\xba\xf3\xeb\xed\x2f\x3e\x3f\xad\x24\x75\xb7\x6e\xae\x63\xdf\x4f\xae\xe5\x59\x58\x6b\x3e\x2b\x53\x45\x8a\xf5\xc9\x17\xad\x65\x2d\xae\x1b\x63\x5c\xad\x17\x69\x8c\xf7\x41\xc3\x1d\xea\x02\xa5\xcf\x09\x56\xba\x72\x27\x81\x9f\x82\xa4\xf2\x82\xc6\xa1\x3e\x70\x64\x72\x07\xf6\x85\x8b\xf9\x36\xea\x31\x89\x52\xae\x62\x28\xa8\x81\x2b\x02\x4b\x58\x7f\xae\x85\x63\xeb\xc7\x6b\x27\xaa\xfb\x4b\xba\x6a\x0b\xef\xf0\xa6\xae\xe4\xda\x52\x6b\xd2\xa1\x21\xa8\x42\x4d\xcb\xd0\x6f\x09\xe9\x36\x05\xba\xd9\xb8\xa7\xd9\x98\x3d\xdd\x43\xf1\x8a\x78\xd0\xea\x57\x53\x1c\xe3\xc2\x5b\x4c\x9e\x6e\x5b\xfe\x5f\xc7\x36\x99\x99\xf2\xd8\x3f\x1e\xb3\x1f\xe1\x9a\xdd\xa1\x78\xf4\xe0\x55\x20\xdf\x84\x8d\xd6\xcd\x41\x46\x2b\xad\x69\xd7\x52\x7b\xae\x61\xaf\xad\x9c\xac\x36\x66\x51\x41\xf7\x8d\xb1\xe4\xdf\x1d\x4c\x92\x4b\x98\x67\xa6\xb5\x3d\x8f\x84\x37\xc8\x6f\x61\x65\x24\xd9\x80\x99\x82\x99\x1c\xbc\xa1\xc7\x1d\x13\x2a\x2d\xf9\x89\xeb\xb0\xd9\x4a\x1d\xc6\x42\x46\x58\x28\xf9\x51\x7a\x64\x9f\xc9\x5f\x69\x73\x73\x26\x1c\x62\x09\xb6\xfe\x48\xc0\x6a\x35\xa3\x4c\x07\x0f\x10\xab\xb5\x0f\x33\x1b\xf3\x1e\xc5\xc7\xbf\x11\x7f\x83\x27\xf6\x2c\x12\xb7\x86\x35\xf9\x9a\x22\x38\x78\x0f\xba\x3c\xfd\xbe\x73\xcc\xa7\x09\x92\xe9\xe7\xba\xb6\x28\xca\x65\xe4\xcc\x61\x74\x6e\xaa\x2d\x33\x2d\xe3\x2e\x00\xe0\xc1\x73\x12\xf1\x0e\x7a\x7b\xc7\x14\x36\x31\x74\xa8\x55\x58\xac\xdc\xf3\xc0\xa0\x4d\x0f\x63\x8d\x19\x40\x53\x80\xa5\x31\x9b\xda\x86\x57\xc8\x5b\x83\x83\x5f\x59\x22\xd3\x49\xf4\x6d\x95\x53\x00\x69\x47\x1b\xaa\x40\x44\x88\x29\xf7\x17\x5d\xce\x39\x30\xd9\x00\xd7\x10\xae\x33\x9a\xca\x5f\xa8\xbc\x0a\xc7\xc6\x18\x05\x79\x93\xe9\x74\xf1\xf7\xc6\xf5\x8d\x31\xe3\x6e\x73\xe8\x21\x16\x67\xc8\xb7\x33\xb5\x6e\xa8\x20\xa4\xc7\xd9\x1a\xbb\x94\x17\xcb\x2a\x1f\xa3\xb3\xa1\x06\x16\xe1\x31\x47\x7c\xdf\x40\xbd\xea\xcf\x95\xfd\x87\xd5\xe2\xbd\x2f\x91\xf2\x08\x75\x9e\xb1\xa0\x85\x47\x8e\x85\x88\x51\xbf\x26\x6c\xb8\xd9\x98\x47\xa9\x3e\x2f\xdc\x3b\xbc\xd8\x67\x45\x38\x7f\x99\xa0\x93\x19\xe6\xeb\x38\x1a\x48\xdc\xb0\xa5\x93\x30\xac\x40\x0b\x83\x9a\x12\x66\x7c\x70\x9a\x9b\x64\x71\x82\xbe\x4a\x96\x49\x37\x56\x41\xf6\x97\x13\x04\xd5\x25\x49\x1e\x94\x0a\xc7\xaf\xdf\x4b\xa8\x80\x94\x94\x9d\x4a\x5d\x29\x7c\x65\x58\x01\xd4\x3b\x83\x52\x9d\x7a\x8d\x71\x8c\x8f\x4b\xf2\x2f\x98\x3e\x9d\xa9\x0b\x93\x45\xc8\xa4\x82\x67\xf2\x68\x14\xc9\x2a\x41\xb0\x1f\x81\x83\x36\x0e\x83\x09\xd8\x34\x3f\x9a\x7d\x13\x5a\x44\x84\xbb\xda\x0e\xc5\xda\xcb\x7f\x81\x25\x93\xa1\xf6\x89\x08\x94\xc1\x6d\xb4\x47\xa8\xec\x4b\x44\x23\xba\x4d\x8f\xf8\x70\x34\xf0\xef\x19\xab\x31\xc5\x61\x85\x12\xc9\x16\x88\x9f\x6c\x23\xde\xce\xf6\xbb\x9e\xa6\x25\xa3\xc8\x43\xc6\x4a\x1a\xa4\x4d\xbd\x92\x94\xcf\xd6\x80\xf7\x22\x51\xaf\xe1\x5b\x9b\xfa\x11\xc5\x20\xc0\x6b\x2c\x54\xb3\x11\xe7\x58\xb8\xb1\x1b\x52\x7f\xf4\x6f\x38\x17\x58\x24\x50\xcc\x8f\x96\x87\x82\x31\xd4\x51\x92\x5f\xf9\x89\x83\xec\x0e\x0c\x26\x8b\xe9\x48\x66\xfc\xda\x9a\xeb\x73\x77\x51\xf9\x20\xc6\x30\x86\xb2\xe6\xc3\xfa\x98\xde\xed\x65\xba\x76\xc1\xdc\x6c\x2c\xe4\x9a\xe8\xe5\x7e\x6c\xd1\x51\x8b\x07\x83\x05\x11\xd1\xdb\xc4\xfa\x63\xe6\x6f\x24\x89\x78\x78\xa6\x50\xfb\xf5\x1a\x22\xed\x13\x1b\x1e\x3c\x8b\xf7\xee\xa6\x48\xab\xa5\x42\xb7\xb5\x06\xa9\xfc\xf1\xb0\x86\xc4\xd3\x0c\x41\x12\x8e\xc0\x36\x2e\x24\x2d\x1a\xc6\x78\xd2\xae\x8e\x54\xe4\x75\x37\x34\xc0\xd8\x01\xfd\x58\xc7\x99\xea\x8c\x4f\xe4\x85\xc6\x26\x17\x83\x13\xb1\x29\x8e\xc5\x6e\x87\xd9\x80\x4f\xcc\x05\x54\xef\xe2\xa0\x1c\xda\x41\x91\xab\x59\x21\x7d\x92\xdf\xc3\x40\x25\x9b\x45\x24\x4e\xe2\x42\x5d\xca\x35\x57\xd8\xa0\xc0\x24\x63\x6e\x1f\xf4\xe6\x95\x1e\x98\x71\xd9\x00\x5c\xba\x38\x88\xcf\x3c\xa4\x78\x4f\x87\xd7\xe1\xa8\xc5\x40\x60\x1f\xb3\x2c\x28\x7e\xe6\x1b\xde\xf0\xca\x6a\xc7\xbb\x3d\x93\x77\x5d\x78\xeb\x67\xb4\x6c\x0f\x8b\x38\xd4\x07\xb1\x4d\x00\x0b\x7f\x31\x86\xda\x5b\xf5\x9e\xc5\x37\x75\x64\x99\x86\xeb\xc9\x61\x3b\x3d\x4c\x06\xca\xaa\xc3\x67\x7a\x65\x8d\x43\x8f\xb5\x60\xa6\x2d\x07\x3d\x4a\x20\xca\x70\x22\xe6\x8a\x3a\x92\xe4\xf5\xff\xa3\xcd\x2e\x41\xe6\x20\x0d\x9c\xa4\x31\xd6\x74\x86\xe9\x87\x59\x31\x0e\xa2\x95\x44\xd5\x91\x10\x40\x82\xa6\x82\xdf\x33\x9d\x4c\x23\x9d\x2a\xab\xd7\x23\x8c\xc3\x0a\x63\x66\x85\x4d\x3f\x66\xd2\xb6\xb3\xfa\x48\x1f\x06\xe0\xca\x38\x09\x0f\x86\xf9\xe8\xcc\x28\x7e\x2b\x31\x86\x2b\x34\x29\xf6\x11\x0c\xae\xa0\xf3\x64\x5b\xf5\x7b\x3a\x67\x5c\xf5\x2d\xa2\xe4\x12\x7e\xa4\x6d\x12\xde\x02\xbc\xa7\xd8\x28\xed\xd7\xde\x0b\x0f\xb3\x79\x20\x3b\x68\x50\xc6\x2f\x0f\x5a\xc1\xe0\x36\x28\xbe\x60\x08\x47\x97\x50\x10\x99\xc2\xdb\x47\x9c\x14\x71\xda\xe6\x39\xb4\x28\x09\xde\x2a\xac\x2c\x14\x5b\x2b\x1d\xf8\x24\x90\xe1\x50\xce\x24\x7f\x47\x7b\x05\x21\xcd\x1d\x10\x19\x4d\x55\x7e\x1e\x11\x1d\x0e\x1c\x89\x5a\xc8\x62\x05\xdb\x8c\xe5\x97\x23\xde\x7d\xc9\x56\x27\xa1\x42\xa4\xcc\xd6\xda\x0e\x8f\x2a\xf8\xa0\x41\x41\xa0\xb7\x55\x8b\x03\xaf\xd9\x44\x09\x59\x42\x90\xb8\x5a\x98\x6f\x2b\xe8\xc7\x05\xb7\x0a\xc8\xe5\x04\x61\x06\x8d\x5e\x35\x12\x68\x00\xc5\xce\xef\xd5\xbb\xd2\x78\x7e\xc2\xea\x4b\x08\x31\xc4\xb1\xaf\xdd\x07\xbb\x4c\x56\xa3\x8e\x3f\xc0\x6a\xbf\x83\x64\xbf\x9e\x2b\xf9\xfe\x0b\xec\x82\x4a\x29\xae\x96\x62\x3d\xc8\xce\x56\x51\xcc\x6b\x89\x9b\xa7\xf8\xd1\x61\x33\xf2\x72\x25\xdb\x8b\x10\x5d\x9e\x96\x79\x3c\x05\x69\x17\x12\xa1\x30\x84\xc3\x15\xc7\xfd\x63\xe5\xc0\x55\x4f\xc0\x95\xca\x4c\xd2\x3a\x20\xd0\xb4\x08\x2d\x38\xb5\x98\x8e\x08\x13\x3e\x50\xed\x45\x76\x68\x3b\xad\xa7\xbf\x89\x7c\xee\x26\x7c\x14\x13\x63\x4b\x62\x52\x93\x4e\xb5\x75\xb1\x78\x63\x43\xd7\x95\xfe\x63\x97\xd3\x0b\xea\x8b\x43\x3d\x74\x4f\x77\x53\x9a\x78\x0b\x72\xb9\x0e\xed\xe1\x3b\xbf\x1a\x04\xfd\x03\xb2\x69\x26\x89\x8d\xae\xb5\x77\x73\x0c\xc6\xb9\xda\xaf\xae\x9e\x73\xd0\x52\x8f\x77\x2e\x5b\x70\x65\x94\x2c\xa5\x96\xa8\x6e\xb1\x94\x68\xef\xc2\x33\x0f\x78\x9a\x59\x20\x24\x76\x90\x12\x9e\xc1\x4a\xc8\xa5\x94\xde\xfd\x9a\x47\xcd\x8d\x1c\x89\x4f\x18\x79\x8c\xb1\x05\x3b\xd5\x27\x1b\xd4\x87\x09\x14\x2e\xcf\x84\x9a\x8f\x50\x99\xaf\xa7\x55\x49\x23\x7a\x22\x42\x2c\x96\xde\x00\x16\xbc\x9c\xd4\xce\xf0\x43\x6e\x08\x63\xf3\x98\x84\x5c\xb3\x4c\xac\x4b\x88\x89\x8f\x2c\xe3\x04\xd8\xa2\x4a\x63\x7d\xa7\xa6\x33\x6d\x64\x18\xd5\x32\x90\x41\xce\x3a\x02\x2b\x36\x0b\xe8\xac\x98\xcf\x15\x07\xe2\x25\xb2\xfb\xd7\xe1\x8d\x34\xf3\xef\xfe\xac\xd3\x25\x14\xe2\x2e\x67\x15\x49\x35\x0b\x22\x65\x52\x14\x55\x56\x84\xdc\x3b\xec\x1f\x6e\xbc\x79\xa6\xb3\xd9\xcb\x7c\xf6\xc9\xb8\x8d\xcb\xcc\x84\x57\xfb\x7f\xe8\xb1\x06\x11\x12\x22\x41\x8a\x17\xc7\xb3\x44\x0c\xc9\x26\x31\x66\x61\xbb\xe4\xca\x03\x36\x52\x1c\x8c\x4c\xa6\x8f\xc7\xf6\xc4\x5c\xf7\xf0\x04\x5f\xf5\x7e\xb9\x32\xfa\x52\x4f\x9b\xfa\x89\x4b\xda\x04\x69\x52\x1f\x31\xa3\x55\xce\xb7\x1e\xa4\x00\x5f\x36\xcf\x87\xe1\xb1\x1b\x7e\x6b\x0d\x71\x62\xa9\x3f\x75\x6a\xfb\x83\x0c\xa4\x19\xdd\x39\xf4\x71\x89\x46\x38\x5c\xc6\x59\x80\x57\x0c\x68\x1a\x95\x52\x82\x34\x6e\x17\x43\x6a\x63\x69\x6f\xfe\xd3\xb9\x9c\xd1\xa8\xad\xec\x09\x62\x98\x0d\x8c\x0c\x72\xac\x02\x9e\x48\x59\x1e\xde\x46\xd6\x65\x58\xf5\x82\x8b\x4f\x3e\x00\x67\x55\xda\xe0\xc5\x05\x0c\xb7\x08\x77\xbb\x99\xb1\x1f\x7d\x1d\x2b\x8b\x97\x02\xa7\x1e\xe1\x41\xb6\x2e\x02\x2c\xb4\xb0\x57\xa4\xd9\xb3\x59\xb6\x11\x86\x5f\x4a\x90\x81\xcc\x14\x16\xd3\x00\x65\xe9\x1f\x77\x62\x35\x25\x6b\xcc\xd0\xc4\x7d\xfc\xc7\x13\xc4\x55\x38\xe0\x11\xae\x53\x5c\xec\xab\xcb\x35\x39\xb8\xc6\xfb\x47\x57\x4b\xc5\xc2\xaa\xe7\x21\x96\x5f\xf8\x7d\x14\xc1\x82\xcc\xfe\xa8\xf4\x20\xf8\xb4\xf3\x58\xc6\x42\xac\x8e\x3b\xd1\x87\x09\x66\x24\xbc\x0e\x2e\xde\xc9\x7a\x87\x83\xb0\x02\x14\x8e\x56\x1e\xd0\x70\x61\x5c\x19\xe4\x8a\x33\xda\x34\x2d\xf1\xa9\x0c\x76\x7b\x27\x27\xef\x0f\xbc\xe5\x3d\xc1\xc7\x37\x8a\x81\xcc\x64\x1b\xd9\x8a\x24\x6d\x28\x90\x31\x7a\xad\x92\x65\xb3\xda\x77\xe3\x64\xb2\xa7\xc0\xe5\xf0\xa4\x8a\x38\xba\xf6\x4b\x92\x15\x96\x6c\xf6\x90\x5e\x0e\xaa\xf5\x18\x26\x2c\xe8\x3e\xba\x09\xf5\x73\x98\xee\x5e\x02\xe2\x89\x25\x6b\x22\x33\x17\x79\x03\xc1\xfc\x3f\x5f\x8f\x25\x82\x27\x97\x8b\x70\x52\x82\x91\x4b\x27\xe9\xfe\x3c\x5f\xae\xe7\xbf\x09\x99\xdd\x7e\x6d\x3b\x33\x85\x3b\xe1\xfe\xf0\x7e\x80\xa0\xe7\xc8\xa0\x7e\x5f\x2c\x04\x0f\x9a\x61\x87\xc8\x2b\x2b\x35\xf0\xe2\xf5\x0c\x15\x60\xfc\xb8\x15\x04\xbb\x72\x8b\xcf\xbe\xdd\x33\xc3\x0f\x01\x39\x83\xb3\x68\x82\x1c\xe7\x78\x97\x3f\xd5\x39\x2e\x13\x65\x3e\x4d\xa6\x2a\xa1\x95\xb9\xee\xf3\x36\x28\xd4\xd9\x0e\xbf\x69\x49\xee\x8b\x25\xd0\x61\xdd\x98\xc8\xf6\x31\x8d\x9b\x64\x21\x18\x13\xff\xf9\x4e\x1a\x1a\x1a\x8a\x80\xda\xed\x14\xdc\x99\x8b\xc9\x7a\xa8\xb1\x7e\x7a\x07\x9a\xbc\x39\x31\x9e\x2a\x30\x50\xa4\xf8\xdb\xec\xe9\x59\x17\x6f\x7f\x02\xc5\xf8\x75\xe0\xbd\xed\x88\x95\x5d\x2b\x68\x94\xe8\x2e\xd1\x2b\x3f\xcb\xa4\x2b\x70\x25\x51\xee\x99\x91\x83\x06\xd9\x9b\x86\xdd\x70\x49\x56\x86\xd8\xe9\x9c\xc1\xda\x9e\x25\x79\x15\x95\x28\x35\x8c\xfc\xc7\x86\x04\x45\x82\x38\xf5\xb8\x31\x25\xa8\xd3\x64\xbe\xd5\x9c\x45\x7d\x43\x19\x11\x69\x8f\xb1\x47\xfb\x79\xca\xa1\x4e\x8c\x04\xbb\x46\x75\x39\x3a\xdb\xb4\xaf\xf0\x33\xd9\xbb\x2c\xce\x69\xff\x95\x06\xbc\x6a\x3c\x32\x51\x86\x38\xbd\x98\xea\x84\x43\x11\x5c\x51\x80\x8c\xaa\x96\xe5\x82\xd5\x51\xe2\x5d\xb4\x4e\x6e\x8b\xe0\x69\x60\x5d\x93\xad\x68\xe8\xaf\xc8\x28\x6c\x82\x23\x89\x3b\xeb\x9b\x50\x47\x89\x03\xcb\x1e\x29\xad\xd2\x45\xfa\x4f\x08\x65\x52\x6e\xee\x67\x4e\x09\xe9\xbd\xf7\xf6\xc5\x78\x34\x11\xb6\x46\x3b\x20\x6f\x1c\xee\x8b\xcc\x9c\x70\xce\x88\xbd\x6c\x8d\x1d\x2b\xaa\xfc\x6c\x8e\x26\x61\x59\x9a\x4c\x59\x07\x90\x26\xa9\x33\x11\x64\x38\xf7\xb0\xfe\xda\x6f\x2e\x4a\x7b\x5c\x53\xac\xe0\x17\x6b\x2d\xe7\xa9\x46\x7e\x2c\xa4\x24\x47\xa9\xe5\x83\x85\x54\x6a\xa9\xb3\x90\x72\xf4\x53\xe2\x80\x55\x09\x9d\x5d\xb4\x46\x7b\x7e\xbb\x1c\x6b\x80\xb2\x0b\x01\x7b\x11\xcf\x33\xfe\xad\xe3\x4f\xfd\xf3\xe8\x06\xae\x02\x2d\xef\x80\x89\xc1\x47\x90\x2f\x49\x88\x4b\xe1\x3a\x4a\x7a\xd9\x14\xc8\x15\x8d\xd2\xd8\xe4\x7a\x7b\x65\xfd\x91\x9e\xd7\x3d\x20\x6c\xf8\x1c\x2f\xf4\xc3\x78\xea\x12\x7c\xf7\x4b\x92\xa8\x0a\xfd\x30\x37\xd9\xb6\x17\x9a\x22\x7e\x07\xc3\xb8\xb0\x82\x44\xaf\x89\x22\x85\x26\x4d\x79\xc5\xcd\x7d\x23\x53\x5b\xb3\xf0\x6d\xac\xa6\xcc\xaa\x31\xb3\x50\xca\x61\xb5\x4f\x78\x5f\xe0\x93\x28\x6c\xdf\x3d\x42\x79\xf1\x98\x8d\x5c\x82\xec\xf0\xba\x3a\x76\xb4\x8a\x75\xcc\x12\xa6\x5e\x03\xfb\xd5\xdf\xbf\x89\x79\xfd\x4b\x92\xc4\x57\xba\xfc\x71\xdc\xe0\x7c\x14\x9a\x85\x9a\x6c\xe5\x02\xc7\xd2\x1f\xb0\xc9\x04\x02\xa8\x21\xd0\x2e\x0c\xff\x74\x38\xa9\xf0\xa4\x63\xbb\xd1\x61\xe8\x64\x06\x18\xf9\xcc\x8a\xd7\x24\x7f\xa5\xee\x66\xbf\x5d\xa8\xe3\x57\x57\x06\xdd\x92\xc2\xb0\x6a\x8e\x62\x85\x9c\x86\x34\xc6\x1f\x1c\x1e\xc9\x5d\xf5\x90\x4a\x43\xbe\x81\xae\x7d\x54\x06\xd7\x81\x51\xd8\xf6\xa1\x9d\xd3\xbc\x1a\xc1\x30\x0d\x12\x17\x1f\x56\x5d\x56\xb1\xc3\x1d\xbd\x5a\x53\x5e\x17\x93\x17\xe5\x85\x6c\x97\x86\x8e\x37\xa8\x58\x91\x6e\xb9\xf5\x83\x4b\x9f\xce\xbd\x6a\xe1\x73\x38\x9a\xb8\xdd\x94\xd8\x60\x0a\x4c\xf0\xe1\xfd\xbd\x7c\x2a\xaa\xdd\x2c\xaf\x2e\xe6\x9e\x05\x6a\xb3\x70\x56\xca\xdd\x62\xba\xff\x68\x17\xba\x8c\x21\xd2\xdf\xb4\x3f\xef\xbd\x96\xee\xda\x61\x04\xb0\x06\xde\xf7\xcf\x5a\x7b\x5f\xc3\x46\x97\xb8\xfa\x53\xe4\x82\xf2\x59\x10\x74\x4c\x12\xca\x30\x6d\xa5\x32\x60\x13\x93\xd2\x20\x1f\xaf\x1a\x65\xd0\xb6\xf5\xe1\xdc\x1f\xb1\xe2\xa4\x6c\xab\xcb\xa1\x06\x99\x78\x64\xc7\x70\x46\x25\x83\x5a\xfc\xda\x7b\xc9\xda\xbd\x51\x88\x54\x3c\x89\xb9\xfe\xed\x1c\xe9\x6d\xd7\x92\xa6\xd9\x21\x2f\x1e\x72\xbb\x89\xd3\xa1\xd8\x03\x0f\xb2\x2d\x6b\xf1\x8a\x13\x56\x75\xbb\x76\xdc\xb4\xb2\x28\x0e\x71\x6a\x1b\x95\xb8\xb9\xb4\x7f\xee\x99\xae\x7b\x70\x17\xc0\xc1\x85\x75\x27\xfd\x61\xc5\xbd\x9f\xfe\xbb\xc1\xef\x2c\x2f\xef\xab\x1b\xf2\xe1\xa5\x6e\x24\xde\x28\xc3\xd0\xd7\x96\xb1\xa1\xa8\x34\xe4\x73\x96\x27\xd2\x28\xdb\xa8\x8c\x3b\x2c\xe8\xc4\xad\xf6\x35\x99\x70\x79\x59\xaa\x1b\x94\x0d\x22\x5e\x44\x8d\xf9\x13\x3e\x2b\x45\x87\x98\x48\x92\x14\x24\xcc\x16\xe1\x18\x13\xf2\x13\x50\xd2\x09\xc9\xfe\x62\x72\xe3\x0f\xf2\xd0\x3e\xd9\x2a\xd8\x67\x40\xd7\x0b\x05\x9a\xe4\x6e\x2b\x7b\xc6\xe1\x33\xb5\x33\xc3\xbf\x33\x16\xc6\xb1\x5c\x96\x74\x1c\x39\xf8\x85\xbb\xd1\x3a\x11\x49\xff\xe4\xa2\x43\x80\x43\x2f\xfe\x94\x25\xe6\x27\x0a\x8d\xd8\x00\xd3\x32\x0d\x9e\xb8\xb3\x0b\xaa\x1d\xcb\x5e\x62\xf2\x15\x2c\xb8\x8b\x16\x92\x68\xec\x8a\xba\x20\xc5\x20\x80\xce\x36\xed\x71\x40\xcd\x4f\x5b\x24\x5e\xf8\xf8\x84\x97\xec\x6d\xc4\xbd\x80\x51\xd9\x21\x7f\x3d\x1e\x2a\xb7\xa7\x9a\x98\xe2\x44\x04\x78\x22\x01\xfa\x7d\x0e\x41\x9b\x3f\xcd\x66\x77\x51\x79\xb6\x0d\xac\x59\x57\x02\x2b\x8c\xcc\x18\x06\x9d\x01\x55\xb3\x43\x0b\x0f\x0d\x3f\xaa\x55\xdf\x14\x01\xf2\x47\x31\x57\xdf\x0a\x6d\xbe\x13\x2e\x2c\x03\x07\x7d\x1a\x0b\x4c\x66\x6d\x97\xdb\xa5\x87\xde\xd7\xcb\x7f\xa8\x52\x05\x88\xbe\xb0\x80\x0d\x30\xa0\x44\x60\x83\x9b\x20\x2d\x54\xd6\xe6\xfb\xe5\xf0\x81\x45\x7c\x69\x6d\x84\x1e\x22\x60\xf1\x68\x38\x78\x61\x83\xb8\x57\xf5\x28\x66\x8a\x46\x4d\x1c\xd7\x68\xa0\x89\x56\xf8\x86\xe3\x9d\xb5\x3a\x34\x67\xeb\xf3\xd6\xef\xe6\xea\x5f\x53\xe6\xa7\xac\x41\x64\xdb\x5f\x54\xc2\x34\xa4\x08\x8b\x5c\xe0\xd3\xe0\xf5\x61\xae\x07\x61\x9d\x65\x77\x33\xc1\x83\x64\xca\xfd\x8b\x07\xc2\xf0\x33\xe0\x34\xa2\x48\x76\xe0\xe0\x97\x3b\x08\x6b\xa8\x5c\xb3\xf2\x73\x65\x70\xee\x9a\x90\x93\x7d\x4d\x89\x4c\x55\x96\xa2\xe8\x9b\x7f\x3f\xc5\xbe\xca\xf7\xb8\xa7\x9f\x72\x9d\x85\x1f\x43\xe7\x60\xb5\x93\x5f\x00\xf0\x0a\x2a\x6e\xa1\xae\x01\xd6\x00\x99\x22\x0d\xae\xeb\x77\x12\x16\x3b\x7a\x66\xa8\x57\x5f\xd3\x54\xea\x17\x26\xeb\x41\x26\x52\x8d\xd7\xcb\x0d\xdf\xfd\xea\x52\xb2\xcb\x64\xfd\xe6\x5f\x09\x91\x06\xea\x92\xbf\x67\x4f\x0e\x83\x15\xd7\x73\x5c\x78\xdf\xae\x43\x11\xcf\x5d\x70\x97\xcb\xcd\x7f\xe5\xaf\x1e\xb0\x9c\xa3\x55\x7d\x49\x7c\x6a\x86\x44\xf6\x93\x7d\x00\xbd\x1b\x2c\x92\x5e\x8a\x87\x82\x59\xbe\x5f\xc9\x7d\x0f\xd6\x8a\x23\x41\x93\x02\xfc\xbc\xe7\xee\xd7\xf8\x59\x1b\x62\xfd\x6d\x58\xc8\x85\x68\xd5\x40\xa6\xf3\x9f\xb6\x2e\x16\x07\x2d\xbd\x64\x18\xd0\x24\x92\x7a\x54\xed\xdd\xdb\x6f\xb8\x7b\x2f\xf5\x4b\x62\x35\x13\xe0\x28\x9f\x85\xc7\x3e\x3f\xb4\x90\xca\x26\xc2\x2e\x89\x66\xab\xa4\xca\xa7\xd3\x94\xd7\xd4\xc2\x6e\x79\x49\x67\xf2\x81\x05\xa9\x13\xcd\x84\x69\xb7\x19\x34\x21\x77\xc7\xe7\xa3\x1f\x95\x22\x64\x6a\x71\xf1\x05\x59\x73\x2e\x2b\x82\x90\xd1\x02\xf1\x2f\x00\x39\x48\x53\x4d\x8d\x5a\x9a\xba\x95\x94\x25\x07\x54\xf6\x0f\x69\x53\xa1\x49\x40\x8e\xea\x9f\xdf\xa1\xe8\xb0\xe6\x0a\xee\xf2\x79\xf4\xc0\x61\x36\xdd\x74\x22\xc9\x67\xfb\xb1\xfc\xc6\x27\xff\xc7\xde\xe7\xd2\xc1\x91\xc0\x8b\x54\xfc\x5f\xac\x94\x1c\x42\x7a\x69\x58\x42\xa5\xac\xf9\x76\x42\x45\xf7\x40\x19\x39\xd8\x3b\x31\x06\xc5\x0b\x5c\x28\x42\x9b\x59\x5b\xfb\xf7\x2b\xf6\xd8\x37\xff\x50\x21\x87\xe2\x01\xd5\xb3\x30\x10\xb2\xde\xf9\x9a\x80\x8d\x10\xcf\xd4\x8e\x91\x62\xf9\xf3\x39\xc1\xc7\x40\xa2\x15\xb7\x95\x00\x29\xb1\xc5\x52\x51\x98\xc0\x9b\x59\xf2\xec\x58\x30\x0f\x8c\x74\x72\x4a\xb1\xd0\xc1\x7e\x2e\xc3\x66\x7d\x43\x05\x03\x30\x41\xce\x6a\x3d\x81\xf7\x6b\xc3\x0b\x8c\x30\xf6\xb7\xc2\x40\xc4\x63\xac\x1c\xba\x5a\xd9\xf9\x96\x25\x08\x3d\x84\x94\x33\x40\xa8\x90\x36\xf2\xcf\xcc\x64\x6e\x1a\x83\x33\x66\x32\xf1\x4d\x11\x43\x4e\x5d\xf7\x17\x23\x58\x35\xd2\xa0\x4e\x77\x73\x83\xd4\xa9\x75\xd2\xc4\xcf\x93\x69\xde\xcf\x75\xca\x37\xbc\xaf\x06\xa7\x85\xc7\x34\x5d\x9a\xc4\x98\x32\xc4\xda\x65\xc5\xdc\x5c\x7f\xfa\x0c\x2a\xc8\xe0\xe5\x4a\x7d\xfe\x25\xe4\xad\xb1\x0b\xb8\xda\x07\x71\x22\x2e\x6a\x0a\x22\xa6\xc3\x84\xcb\x9c\xfa\xf2\x2b\x0c\x0c\xc3\x41\x98\x19\xa8\x9d\xa3\xd3\xe3\xc6\xa4\x72\x45\x6a\x2c\x52\xce\x3c\x47\x5a\xfd\x85\x6e\xcb\x36\x2c\x66\x84\x3a\x2a\xed\xf9\x52\x1e\x39\x75\x6d\x56\x0f\x93\x1d\xa2\x9c\xab\x2e\x52\x07\x0e\x33\x67\x0f\x91\x20\x44\x4b\xb8\xca\x48\x03\xbd\xce\xcc\x7c\x91\x9e\x4d\x64\xa0\xf1\x37\x72\x13\x59\xf5\x88\x96\xa0\x42\xeb\x3c\xfb\xf0\x22\xba\xbf\xf2\x72\x46\x65\x40\xe0\xe4\x1e\x17\xbb\xa7\x7c\xb7\x4e\x3e\x93\xbb\x14\x1d\x8b\x8e\x29\xa7\xbe\x8f\x65\x20\xe9\x54\xae\x8f\x26\x4f\x84\x93\x1f\xa1\x30\x1f\xae\x8a\xe6\xc4\x33\x85\x9c\xcc\xef\xda\x7c\xcb\x33\xdd\x27\x4a\xf3\xa0\x4a\x25\x5f\xcd\x7a\xd0\x47\x48\x15\x19\x4f\x88\xe1\xed\x10\x18\x6f\xb8\x6e\xbc\x7a\x86\xf1\x0e\x45\xac\xa8\xe9\xb8\x6b\x9d\xf4\x17\x7e\x32\x5c\x42\xc1\xc8\x8a\x0e\xb9\x39\x69\x23\x1c\xdc\xce\xa4\x45\x46\x95\x0e\xd7\x29\xcb\x81\xb1\xb1\x47\xcd\xa9\xae\xc7\xae\x40\xa0\xba\xb4\xd9\xfb\x60\xc2\xa0\xab\xd5\x78\xa9\xfa\x1f\x2b\x8e\xdb\x73\x4f\x91\x73\x88\x77\x9c\x58\x5c\x8f\xba\x28\x66\xf7\x5e\xc2\x53\x7d\x0a\x43\xd4\xde\xb1\x7a\x93\x8a\x57\x68\x4a\xac\xb5\xba\xcc\x56\xb8\x5e\xb1\x0d\x56\xa3\x60\x58\x32\x3e\xd0\xd6\xeb\x3b\xa6\x57\xa2\x7e\x9a\x62\xbe\xe5\x54\xa0\x80\x1c\xf2\x9a\x54\xae\xc8\xb3\x04\xa6\x5b\xea\x3e\xa9\xc8\xee\x8a\x82\x0a\xb7\x51\x42\xb4\x29\x56\x35\x64\x6d\xac\x23\x03\x89\xb1\x0f\xad\x07\xca\x06\x9c\x28\x55\x81\x9f\x8c\x1a\xb2\xc3\xc4\xc6\x15\x29\xe4\x85\x4d\x42\xa3\x0f\x0a\x85\x61\xfb\x9d\xd8\x86\x3b\x55\x36\x05\x87\x8d\x71\x2f\x61\x16\x41\xfb\x37\x0e\x69\x6a\x62\xcd\x65\x37\x73\x09\x80\xea\xe5\xb9\x0c\xd3\x76\x63\x24\x42\x7b\x74\xea\x09\x2d\x95\x23\x4e\x5a\x83\x98\x36\x67\xeb\xf3\x75\x67\x46\x69\x48\x94\x04\x5f\xde\x7d\x6b\x05\x49\xd9\x95\x13\xe0\xd9\x03\xbf\x1d\x74\xc3\x44\x66\xd6\xd3\x68\x17\x1d\x7b\x58\x22\x9b\x5a\x3a\x1e\x23\x05\x37\x6e\x6f\xeb\x05\xd2\xd6\xc2\x58\x2e\x30\xe5\x47\x6b\xb4\x7f\x92\x1e\xd6\x6c\xcd\x60\x22\xba\x92\x3a\x3c\x98\xf4\x77\xaa\x61\xee\x15\x6a\xb9\x48\x93\x0f\x52\x1d\x60\x1b\xfc\xe7\x04\x0b\xa4\x4c\x63\xbf\x65\x61\x6f\x13\x0a\x04\x5d\xcb\x57\x57\x2e\x07\x31\xe0\x3c\xc8\x86\xf4\x22\x15\x72\xd8\xea\x85\x77\xd0\xc1\xb0\xa4\x2e\x24\xb0\xbf\xa6\x4f\x59\xcb\x93\x1d\xd2\x1c\x7c\xad\x04\x63\xfb\x3e\xef\x07\xe3\xa3\x4c\x52\x56\x40\x2b\x88\x8a\xb8\xae\xcf\xce\xe3\x71\x7d\x48\x01\x36\x24\x78\x19\x05\x14\x50\xf5\x98\x38\x4a\x57\xd6\xa0\xa6\x52\x9e\xdf\x54\x30\x3d\xc6\x61\x32\xfb\x25\x7b\x57\xab\x25\x45\xb9\x8f\x03\x89\xb8\xac\x7b\x42\x29\x94\x5b\x8f\x24\x13\x11\x0a\xd6\x1c\x88\x0c\x6b\x0a\x31\x87\x19\x5d\xe8\x43\x60\xdd\x2a\x4c\xfe\x24\x68\xf6\xe9\x82\x71\x8e\x7d\x84\xef\x49\xbf\x3c\x7b\xfb\x4d\x94\x25\xeb\x76\x30\xb1\xd0\xbf\x77\xb0\xcb\xd4\x56\x28\xdc\x54\xc2\xda\xd2\xac\xbb\x24\xcb\x2a\xd5\x1d\xa7\x18\x87\xca\x76\xbf\x07\xf6\x57\x1b\xc5\x89\x0c\xfa\x5a\xaf\xcc\xc9\x80\xa3\x67\xe7\x27\x24\x78\xb2\x9b\x28\x87\xd5\xb8\x24\xe1\x42\x0b\xaa\x57\x90\x12\xc3\x43\x49\x6d\x16\xa9\x38\xf3\xf1\xf5\x14\xc9\x8c\xe8\xa6\x91\xc5\x1b\x93\xaa\x00\x26\xc3\x84\x08\x5e\x27\xf3\x9b\xa8\xc6\xb5\xf3\x96\xf1\xab\xd2\x4d\x74\xc3\x93\xc2\xb7\xe2\xec\xad\x99\x38\x81\x79\x99\xa4\xe6\xb9\x36\xfb\x58\x47\x39\xf9\xb8\xdf\x05\x5a\xdc\x22\xad\x3b\x2f\xd5\x0c\x35\x76\x4a\x47\x6e\x9e\xc2\x4c\x4a\xd8\x52\x85\x9e\x1f\x49\xc6\x16\x39\x1c\x3c\xe8\x2e\xff\xc9\x10\xf7\x73\xc2\x61\x06\x4e\xca\x22\x6d\x7f\xe4\x88\x72\x50\x83\xdd\x72\x59\x02\xa0\x42\x5a\x52\xda\x33\x3f\xd7\x31\xb1\x46\x49\x19\x17\x13\x4b\x20\x84\xfd\x25\x0d\x70\xf6\xdb\xfa\xb3\xc7\x82\xf2\x66\xa5\xf5\x18\xf2\x7f\x85\x33\x25\x80\x54\x2a\xd1\x78\xac\x5b\x7e\x07\xde\x93\x64\xf0\x02\x1c\xae\x1b\x74\x27\x3a\xde\x71\x90\xc3\x6b\x74\x0f\x8e\x89\x65\xbf\x46\x00\x7d\xfe\x2d\xad\x53\x1c\x91\xd3\xba\x1f\x1b\xde\xae\x47\x65\x54\x13\x12\x16\xca\xe3\xbd\x4f\x39\xf0\x5a\xa0\xd9\x50\x3f\x3d\xc5\x0e\x37\xdb\x8b\x0a\x29\x47\x3b\x0d\xa9\x04\x99\x16\x12\x8a\x89\x25\x6d\x05\x2b\xe2\xc4\x5b\x13\x8d\x16\x5f\x49\x21\x99\x76\x40\x34\x56\xd1\xa6\x54\x42\xaf\x33\xe8\x44\x07\xc7\x6a\xdd\x70\xb8\xbc\xca\xfc\x23\xa3\x85\xd5\xb3\xc7\x51\x3a\xc8\x33\x85\x4a\x90\x33\xfa\xb5\x70\x8b\x8a\xa9\x6f\x6f\x32\xd5\x91\x5f\x46\x7a\x72\xf6\x81\x4b\x02\x67\x9a\x9e\x63\x79\xd0\x97\x49\xe0\xeb\xc0\x0a\x27\x09\x51\xe7\x19\x60\x82\xdc\xb1\x12\xcf\x50\x66\x39\xff\x5c\x68\xad\x1f\x4a\xb7\x18\x49\x9f\xce\xcd\x4e\x61\x97\x1b\x2a\x34\xf8\xb3\xff\x67\xbc\xb2\x3d\xd9\x5e\xac\xf0\xc3\x43\xa5\xc2\x66\xdb\xdb\xcc\x4d\x14\xed\xa1\x8e\x55\xc0\x12\xbf\xf8\xbf\xdb\x6b\x5f\xbb\xe1\xf0\x02\xc6\xe9\xf7\x0d\x4a\xe7\xfb\x3b\x9c\xbf\x9e\x3a\x88\x70\x77\x2c\xad\xc4\xc9\x5f\xa5\x68\x1d\xf1\x63\xc0\x22\x15\xce\x98\xb7\x74\x5f\x18\x62\xfa\x37\x85\x46\x8e\xf5\xf8\xae\xab\x76\xd8\x4f\x75\x02\x40\x9c\x7c\x5f\xc0\xaa\x56\xbc\x12\x96\xe9\x2d\x93\xbf\x6c\x28\xeb\xb0\xc7\xa7\x4e\x65\xd8\xbf\x8c\xee\x78\xc2\x4f\xea\xc6\xfe\x23\xa6\x36\x0a\x4f\xcc\x7b\x2c\x7d\x10\x9d\x69\xa6\xe7\xd9\x6c\x49\x22\x81\xd2\x6c\x8e\xdc\xa6\xe2\x41\x4b\xf6\x17\xc4\x76\x7a\xe4\x2d\xd4\x78\x0c\x93\x75\xdf\x2f\xe6\xae\xd4\xfc\x9d\x5f\x33\x73\xb4\x1c\x26\xd9\x61\x5c\x72\xde\x7f\xa6\x87\x35\xe8\x17\xc3\xee\x26\x2e\xc9\x95\x31\x1b\xc3\x8c\x19\xab\x57\x6a\x03\x4f\x85\x8b\x2f\x12\xd8\x71\x0d\x15\x30\x15\x34\xcb\x1b\xb0\x95\xc9\xe2\x65\xf9\xc5\x26\x7b\xbd\xc3\x6f\x17\x72\x2b\x87\x08\xb7\xeb\xdb\xc1\xd6\x86\x79\x50\x8a\xa5\x5c\xc4\xa9\x7e\x7c\x4a\xb6\xd3\xe9\x69\x18\xdb\x72\x78\xf9\x6b\x0c\x19\x2e\x53\x16\x3b\xdf\x3b\x7b\x3c\x3c\x94\x7a\x85\x69\xcc\xfe\xfa\x2b\xa9\x25\x54\xbe\x8c\x9c\x99\xa6\x7c\x08\x83\xe1\x12\x52\x49\x33\x14\xec\x7d\xeb\x61\x95\xc5\x78\x94\xab\x96\x0b\x69\xa8\x3c\x15\x85\x3c\xbb\x09\xb7\x63\xf4\x50\x5a\xeb\xec\x1d\x2e\x1a\xaa\x88\xa9\x1a\xe8\x9b\x46\x89\xd3\xd0\x45\x02\x8e\xbd\xfd\x1f\x40\xa7\x2f\x17\x4d\x11\x32\x9c\x35\x33\x0b\x6b\xe3\xc9\xa5\xeb\x88\x1b\xa3\x16\xd8\x40\x29\x5e\x66\x6d\x81\x01\x6c\xc6\x66\x2e\x97\x59\xf3\x7b\x68\xba\xb8\x63\xde\x88\x44\x56\x34\x4f\x17\x97\xbc\x0f\x20\x57\x31\xcf\x03\xf3\x0c\x37\x40\x39\x1b\x8d\x1f\xd9\x8e\x65\xec\xbe\xf4\xed\x1e\x8a\xf8\xca\x75\x5a\x95\xea\xe2\x14\xe5\x9b\x06\x99\x7a\x76\xe7\x8b\x7a\xb9\x02\xb1\x54\x65\x5e\xcb\xd5\xda\xbb\x50\xd5\xe0\x76\xfe\xc0\xef\x2f\xfe\x3c\x1b\x22\x05\x91\x7a\xd0\xb2\xef\xe4\xe5\x39\x21\xaf\x35\xc6\xc9\x3f\xe7\xa1\xde\x31\x7e\xd1\x48\x9e\x90\xd1\x5a\x38\x59\xec\x11\x91\x04\x33\x3a\x82\x2d\x9d\xfb\x61\xb9\xe1\x2c\xd8\xbe\x5e\xae\xa2\x90\xdd\x0a\x60\x01\x91\x45\x1b\xc4\x76\x9f\x21\x3f\x9a\xbc\x23\x2e\xe2\xaa\x85\xb4\xfa\x69\xf7\xc3\x51\x44\xa4\xe7\x33\x0e\xfe\x2d\x14\x53\x55\x58\x62\x7c\xc3\x4a\x1e\x08\x3c\x6e\x77\xb1\x5a\x47\x70\xca\x06\x43\x88\x71\x59\x1f\x8c\x5c\xfc\x79\xa5\xaf\x05\xcf\xf7\x6f\x72\x3a\xba\xe1\x61\xec\xfa\x72\x20\x03\xe4\x55\x85\xaf\xea\xe4\x80\x4f\xf8\x51\x70\x97\x1b\x95\x05\x26\xf7\xc7\x25\xff\xe4\xe8\x65\x45\xd4\x04\x45\x06\x95\x3f\x7e\x3a\x33\x3a\xed\x48\x97\x78\x71\xa4\x8f\x69\x46\x87\xd1\x63\xef\xc1\xb3\x64\x1d\x10\x26\xfc\x5f\xfb\x39\xd2\x99\x00\x6e\x39\x3b\x77\xec\x02\x3e\xa6\x47\x05\xac\xcd\xaa\x8b\xf8\x1d\xaa\x9d\xc8\xf8\xcf\x20\x4d\x55\xd0\xb8\x1e\xbd\xa7\xb2\xda\x21\xb7\x43\xa2\xb0\x48\x6f\xa6\xdf\x86\x9b\x6b\xa7\xb7\x6a\x87\x1d\x7e\x7c\xf4\x20\x74\x80\x57\x01\x23\x59\x77\x9e\x5f\x72\x77\x23\xb2\xed\xd9\x4f\x90\x07\x20\xa2\xb8\x6a\x66\xa0\xb6\x3a\xc2\x4a\x88\xf4\x27\x87\xbd\x1a\x9a\xea\xef\x6b\x6c\x29\x33\x62\x7d\x4b\x19\x4b\x97\x02\x3f\x27\x22\x6c\xd5\x50\x26\xd1\x9a\x88\x3d\x5e\x88\x56\xf0\x52\xb0\xa8\x23\xfa\x2a\xf3\x85\x21\x6e\x85\x38\x65\x4f\x28\x71\x33\x46\xfd\xd0\x1d\xb2\x0c\xde\xd5\x22\x37\xd1\xcc\xbf\x5b\xdf\x81\x72\xf8\x23\x4b\xa5\x0b\x42\x83\x93\x23\xf8\x93\xa9\x85\xd5\x55\xff\x26\x48\x79\x57\x28\xac\x6f\xb1\xaf\x05\xe7\xf1\xf5\x0e\x01\xf3\x92\x73\x13\xc2\xf6\x67\x8f\x1d\x15\x61\x60\x93\xe0\xc8\xd0\x37\xac\xbe\x80\xa3\x90\xd7\x1c\xb8\x7b\x6d\xc4\x78\xf9\xc6\xaf\x76\x54\xfe\x24\x34\xbe\x81\x22\xf3\xd3\x3d\x4d\x5d\x24\x97\xde\x6e\x22\x71\xbb\x68\x16\xf7\x25\x3b\xb6\x47\xb1\xf7\xfe\x89\x89\x5b\x68\x04\x53\x1e\x0c\x54\xe0\x75\xa2\x68\x25\xc5\x4d\x28\xca\x93\x28\x7d\x3d\x03\xc2\x85\xb1\x46\xae\x10\xa8\xd7\x62\x24\xd2\x48\x47\xa5\xd3\xa7\x6f\x1a\x06\x74\x3c\x1a\x69\x5c\xf5\xe6\x29\x89\x86\x33\x76\x81\x25\x53\x25\x6f\x09\x71\x17\x1d\x0b\x2c\xae\xa0\x4d\x39\xe5\x42\xd9\x49\x45\xd4\xb2\xa6\x57\x44\x0e\x2d\xd4\xf6\x99\xa8\x51\xe3\x0b\x44\x89\x45\x7f\xf1\x95\xbe\x5a\x76\x7b\xcc\xb6\x77\x66\x98\x1c\x89\x05\x8e\xec\x51\xe4\x58\x28\x1a\xf0\xd4\x19\x87\x7f\x8a\x1c\xf7\x26\xdd\xc4\x09\x39\x3a\xc6\xae\xdc\x6d\x2e\xa1\x01\x7c\x45\x4e\x18\x36\xb1\x73\x64\x8e\xce\x0f\xce\x62\xad\x5a\xf6\x98\x01\x76\x63\x24\x6a\x9a\x96\xf1\x78\x4e\xa1\xc9\x96\x3f\xa6\x4b\xef\x01\x15\xbd\x7b\x43\x00\x57\x8d\x26\x71\xd5\xa2\x90\x4b\x2b\x16\x51\xaf\xc7\x03\x4c\x8a\x07\xb9\xef\xf4\xca\x44\x4b\x44\x06\x30\x9f\x4f\x82\x31\xfc\x27\xc0\x30\xb2\x91\x45\xdf\xf6\x28\x52\x14\x3a\xe2\x9a\x67\x6c\x7e\xae\x04\x99\x01\x84\x1d\xed\xf2\xc9\x42\x9c\x45\xa4\x22\x0a\xcc\x19\xb7\x3e\x9b\x14\x1c\xa8\x7c\xdb\xc7\xdf\x1a\x7f\x26\x4a\x0f\x6d\xd4\x6b\x90\x13\xa1\xbe\x12\x92\x6d\xf3\xbd\xe9\xf1\x49\x88\xd9\xfc\x6d\xc8\xf9\xea\x10\x4e\x4d\x86\x81\xe6\xf1\x7d\x5f\xbc\x28\x50\x1a\xaf\x29\x72\xc0\xb4\x91\x37\xde\x5d\x42\xec\xeb\xdf\x00\x67\xcc\x35\x44\x9d\x15\x60\x82\x66\x34\x3b\x9d\x16\x1e\x68\x55\x43\x18\x3a\x0e\xdd\x57\xa5\xbd\xb4\x46\xf8\x61\xf3\xb0\xe1\x78\x58\x00\x17\xdb\x9e\x08\x74\xbd\xe9\x03\xb4\x59\xe3\x5a\x39\x51\x1b\xed\xd8\x14\x48\x53\x8b\x25\x2b\x66\xc7\xc4\xce\xeb\x30\xd0\xd8\x55\x75\x9a\x4c\xa9\xc9\x18\x19\x30\x4f\x26\x0d\xc9\x11\x8c\xe2\x21\x88\x90\xb7\xe9\x6c\x5f\xc2\xb7\x80\x1b\xb8\x40\x1e\x16\x1b\xbf\x38\xfd\xfc\x9a\xec\x8b\xf4\x16\xcc\xa4\x23\xeb\xc5\xa9\x3d\x38\x72\x67\x71\xf5\xac\x51\xc0\xfa\x02\x13\x15\x0d\x5d\x4d\xe1\xbf\x3b\xe3\x6a\xbc\xba\xdc\x91\x98\x7c\xd5\xc7\xfd\x80\xfe\x13\x76\x26\xaf\x67\x59\xec\x44\x90\xc6\xbf\xbf\xff\x81\x32\x9b\xab\xb1\x88\x9a\x6f\x04\x36\xf7\x54\x76\x52\x5d\x5e\x05\x27\x46\x29\x0b\x66\xca\x09\xc0\xc9\x8c\x6a\xce\x7f\xb7\x24\x6c\x5c\xa2\x31\x38\x50\x5d\x32\x61\xb2\x6a\xaa\x25\x11\x57\x19\xe1\x4c\x4a\x6e\x83\x2e\x6c\xe4\x9c\x5a\xaa\xba\x1f\xba\x5c\x13\x75\xa7\x5c\x1c\xe9\x68\x55\xac\xba\xa9\xc5\x81\x89\xe3\x12\x05\xd5\xa0\x3e\x61\x65\x73\x7b\x21\xa4\x19\x3c\xb5\x24\x96\xb4\xdf\x9b\xf0\x61\x02\x65\x63\x2c\x0b\x8c\x19\x8e\x08\x8d\x8f\xfc\x52\x4c\x8c\x79\x29\x30\x4a\xbf\x1f\x33\x26\x39\x47\x34\x18\x26\xa2\x3d\x99\xd9\xfb\x13\xde\x7a\x83\xbc\x1e\xab\x29\x40\x28\x53\xd9\x53\xbc\x54\x6e\x94\xdb\xb9\xdf\xc1\xe6\x44\xba\x52\xba\xa7\xba\xec\x2b\x5c\x75\x55\xcd\x28\x5a\x90\xc9\xe7\x48\x37\x1a\xe1\x76\x6b\xce\x19\x11\xb1\x10\x4e\x9c\x44\x93\x35\x10\x63\x56\x12\x83\x61\x5e\x83\xe6\x10\x5b\x03\x40\x57\x8d\x8a\x87\x4b\x04\xd6\xad\xd2\x56\xd1\x99\xf2\x40\x28\x0e\x1e\xf7\x96\x51\x92\xd1\x71\xfc\x79\xc5\xe5\xec\x63\x1c\xdd\xe5\x28\x53\xe6\xd2\xb4\xd9\xe1\x93\x4e\xe0\x4a\xe1\xf0\x32\x15\x45\xad\xbc\x4b\x46\xd8\xde\x36\x75\xa5\xd8\xee\x55\x94\x03\xdb\x2f\x1c\x6e\xa7\xef\x86\x28\xd0\xa6\xb8\xdc\x4d\x36\xd4\x14\x3a\x24\xcd\xe9\xb0\x3d\x66\x25\x60\x7f\x62\xdd\xef\x37\xa7\x28\xd6\x16\x5f\x66\xc0\x63\xfd\x8f\x72\x9e\xd8\xef\x38\xfd\xca\x2c\xeb\x4d\xef\xc5\x07\xbe\xc1\xa3\xb4\x18\xde\x44\x41\x19\x39\xcd\x80\x43\x06\xed\x4d\x48\xb5\x83\x2b\xd2\xcd\x57\x66\x26\xe6\x18\xb1\x9d\x1f\xfa\xd7\x89\x3c\x80\xbd\xe3\xe9\x85\x51\xaf\xed\x48\xdc\x58\x02\x53\xc9\x36\xd9\x61\x05\x93\xc4\xe7\xaf\x49\x13\xdc\x8b\xee\x34\x7c\x98\xe2\xf2\x0c\xb7\x98\xa5\x66\xd4\x9e\x29\x89\x1e\x4f\x07\xb8\x8d\xfd\x3d\x70\xf8\x2e\x95\x12\xf7\x8e\x55\x99\x74\x0b\x67\xa4\xb3\xb7\x1b\xc9\x4d\xe5\xf3\x6f\xd1\x4f\xef\x4a\x95\xb0\x55\x4a\x11\xbf\x7b\xda\x72\x26\xd9\x9c\xe9\xf8\xe8\xf6\x3c\xbc\xe8\x3e\x1e\x54\x18\xd2\x08\x4d\x78\xac\x3b\x36\x0d\xae\xeb\x50\xc3\xf5\xef\x33\x5c\x47\x21\x92\x23\x25\xf7\x7c\xfa\xd3\x7b\xdc\x7c\x4b\xda\x8a\x73\x12\x6b\xc2\x89\xc5\x43\x1e\xa4\xfc\x79\x6a\x19\xa9\x9f\xf2\x56\xc3\xe9\xc9\x9b\x22\xf3\x61\x63\xfe\x16\x13\x29\x2e\x42\x82\xce\x4f\xf3\x5f\xd8\x6e\x3a\x81\xae\x3a\xe3\x1d\xf4\x2e\x76\xa0\x9e\xc6\x95\x53\x4e\x80\xff\xd1\x8e\x72\x10\x9e\x94\x87\xe7\x0d\x8a\x49\x75\xe8\xed\xd0\x7e\xf0\x3a\xa4\x86\x81\xfe\x51\x8b\x48\x46\xc9\x38\xbb\x2b\xea\x77\x5a\x76\x83\xbb\xa3\x3b\x90\xa2\x8a\xa5\x45\x27\x9e\xe3\x82\x3e\x26\xf6\x41\xbe\x04\x0e\x8e\x61\xc3\x33\xd0\xc9\xf7\xf0\xed\x3d\x2a\xb3\x6b\xb2\xad\xdb\x0a\x99\x9d\x38\xd9\xda\x2a\x82\x4b\x62\xfa\xf4\xe7\x3f\xad\x1e\xaa\xcd\x0a\xba\x70\x9f\xa7\xb0\xd3\x84\x66\x36\x19\x65\x83\x7e\x99\x32\xa2\x06\xc8\x8d\xeb\x23\xac\xf7\xef\xbf\x67\xb3\x6d\xc8\x37\xbb\x47\xf6\xb6\x9a\x30\xeb\x99\x8c\x72\x09\xf8\xeb\xef\xad\x97\xa4\x0e\x09\xf9\x70\xde\x4d\x21\xd0\xcf\x1f\x93\x83\x07\xca\xc9\xc2\xbf\x6b\xfe\x8c\x85\xc2\x6c\x86\x48\x8b\x01\x77\x7e\x63\xcb\x47\x66\x87\x37\x65\x67\xc2\x47\xd4\xe8\xd9\x5a\x8f\xb1\x2e\xa2\xf3\x5a\xc0\x07\x0e\x99\x3f\x1f\x69\xb2\x0a\x6a\x50\xe8\x78\xaa\x4d\x2a\x2b\x99\x2f\xe8\x3e\x2d\xe1\xf4\x67\x1d\x0d\x9b\xd8\xd8\x35\x7d\x2a\x70\xa3\x25\x44\xf2\xc2\xbb\x63\xe7\xa4\x7f\xe7\x9a\x36\x95\x65\x1a\x89\x5b\x68\x8a\xff\xc2\xcc\x0c\x0b\x07\x88\xda\xcd\x9a\xd1\x18\xf6\x0d\xf5\x97\xde\x46\xdb\x27\xed\x0e\xfd\x68\xa6\x2c\x3e\x86\xba\xcb\x5a\xfd\xc3\x8d\x17\x55\x1a\xe5\xa4\xaa\xbd\xe8\x21\x52\x79\x4f\x5c\x56\x30\x9e\xbe\xcc\xe1\xbc\xd0\x1c\x1c\xf9\x4b\x65\x19\xae\x04\x1b\xff\x4b\xf4\x4d\x0a\x3f\x3e\x8d\x4c\xb9\x75\x45\x7b\xc5\x1e\x1d\xd1\x7e\x30\xff\xe7\xb0\xd9\x2f\x04\x98\x38\x8b\x9c\x69\x73\x18\x6b\xb0\xa9\xa5\xe6\x1b\x0e\xe2\x07\x6a\xc7\x73\x05\xcc\x33\x5c\x99\xb7\x4a\x12\x0b\x92\xbf\x97\xb2\x26\x5b\xb3\xfd\x28\x88\x30\xf8\xb7\xc7\x8a\x62\xa6\x60\xaa\x31\x07\xa2\x6b\x8c\x96\x4e\x25\xf3\x18\xcf\x69\x1f\xce\xac\xd3\x29\xb3\x38\xcc\x4d\xe5\xa0\x67\x53\x65\x7b\x1c\xde\x77\xc4\x50\x6e\xf5\x74\xc4\x7c\x7e\xcc\xee\x82\x58\x9c\x10\x11\xda\x25\xb2\x1f\xe2\xff\xce\x6b\xeb\xae\x4d\x0d\x1e\xe9\xb9\x83\x5e\xc7\x0d\x78\x3f\xc7\x15\xc6\x5f\x1c\x79\xc5\x70\xd2\x87\xab\x7c\x6c\x69\x27\xff\x66\x77\xcf\xf0\xff\x61\xc3\xac\xf3\x44\xd7\x85\xe9\xe3\x01\x28\x08\xb3\xca\x5a\x43\xa2\x97\x7c\x91\xe5\xed\xc6\xe4\x56\x9c\x9c\xeb\x2d\xc5\xf2\x94\x89\xc6\xe7\xac\xae\xf0\x6a\xa6\xcf\x50\x0a\x06\xcc\xc2\x15\x16\x96\xc3\xe5\x07\x10\xe2\xfd\x14\xa8\x94\x2d\x95\x71\xbd\x95\x30\xdb\x7a\xad\x2c\xc9\xa5\x70\xcb\x52\xaf\xa4\xbc\x6b\x91\x0c\x79\x19\xed\xaf\xe0\xcd\x8b\xb9\x79\x1a\xfe\x1a\x53\x3f\xb4\xc0\xdf\x1f\xd3\xa3\xf6\x74\x14\x0a\x7c\xf1\x06\x6a\xb3\xbf\xc2\x8e\xe7\x52\x63\x06\x7d\x3f\x9a\x20\x3d\xb2\xe2\x3a\xbf\x9e\x08\xab\x8a\x93\x31\x21\x94\x2c\x08\x77\x3c\x78\x03\x03\x94\xf1\x9f\xc1\x66\xd1\x2c\x17\xd4\xf4\xea\x93\x95\xc4\x9f\xdf\x47\xc3\x37\xad\x86\x65\x6b\x06\x06\x6b\x26\x43\xf7\xba\xe8\x51\x51\xf8\xec\xb9\x48\x9d\x37\x2e\x52\xa7\x6a\x8b\x36\xca\x8e\xd0\xcf\xd1\x9a\x1f\xec\xe9\x6f\xd0\x14\x45\x8e\xf0\xc2\xa9\x04\xdb\x8c\x3f\x9a\xa1\xc8\xce\xf8\x91\x57\xa6\x96\x9d\x64\x34\xcc\x2a\x3b\x1b\x44\x3c\x41\x76\x5c\x93\x48\xf1\x7c\x17\x7c\xc9\x0f\x8c\xdf\xa5\xfc\x5f\x16\xe4\x0e\xc2\x93\xfd\xef\x73\x32\x91\xec\xf1\x63\x46\xc4\xd4\xef\xe4\x0b\x79\x2a\x1b\x16\x01\xc5\x29\xf5\xfc\x7c\xc6\x71\x53\x4f\xf4\xad\x3f\x7b\x8b\x86\x4c\x74\x91\x68\xfa\xa8\x8a\x24\x95\x91\xc6\x15\x10\xd0\xb2\x24\xf5\x5c\x38\x9c\x3f\x08\xee\x30\x83\x48\xa3\xbc\x7b\xeb\x2b\x6f\x10\x41\x02\xb6\x5f\x43\x79\x98\x83\x21\x50\x15\xfb\xd1\xe0\x11\x69\xb8\x78\xa7\x49\x30\xd8\x93\xcc\x35\x8d\x12\x0f\x4b\x3a\x22\x19\xad\xec\x1e\xca\x5b\x7e\x20\xc6\x65\x27\xc7\x7f\x47\x0d\x41\xf9\x51\x63\x4f\x7a\xdb\xa3\xa3\xe7\xed\x63\x02\x27\x19\xba\xbc\xe6\x90\x72\x70\x6f\x51\x37\xd7\x50\x95\x7a\x37\x99\xf0\x1e\xda\x02\x7e\x2f\xa9\xf3\xc0\x21\x51\x2e\x7b\xe7\xe0\x46\x96\xf5\xe7\x6f\x03\x87\x9d\x4f\xd4\x35\x19\x79\xfd\xc3\x10\xab\x57\xe5\xf7\xfb\x3c\x14\xef\x1d\x9f\xce\xf8\x24\x9a\x7a\x1e\x83\x14\x4b\x7d\x10\xb6\xb2\xdc\x5a\x28\x07\xed\x69\x04\x51\xdd\x89\xb9\x75\x32\xe9\x92\xf9\x94\x64\xb4\xf8\x29\xfd\x93\x0b\x43\xaf\xb5\x30\x9d\x9f\xec\x07\xd2\x4f\xe5\xdd\x6c\xb9\x74\x1e\x0f\x8a\x1e\x99\x7e\x6c\x4a\x33\x63\xe8\xc5\xd2\xd5\x23\x6c\x67\xdb\xd7\xbc\x63\x67\x89\xdf\xb3\xd1\x3f\xc3\x22\xbc\x22\x8b\xdd\x17\xf3\xc4\xbb\x4b\xda\x31\x29\x42\x42\x65\x9c\xdb\x15\x41\xc6\x7a\x80\x08\x42\x9b\xc1\xc8\xc5\x07\x74\xae\x18\x41\x09\xe4\x08\x16\xd0\x41\xc3\x16\x4d\xf2\x82\x7f\xea\xce\x1f\x15\x09\xae\x4b\xbf\xde\xc1\x13\x52\xcb\xa1\xd2\xc2\xc2\xfc\x66\x0f\x49\x8f\xfe\x6e\x49\x88\xbb\xf3\x01\xe8\xa7\x13\x69\x1d\xb8\x05\x65\x36\x3e\x86\x07\x6f\x04\x63\xde\xaf\x82\xd9\x1c\x23\x15\x47\xbc\x64\xbb\x85\x1f\xa7\x26\x5e\x9f\x93\xa7\xf7\x8d\xbe\x57\x5e\x1d\x7d\xa6\x08\xb8\xfe\xb9\x1b\xaf\x13\x6d\xe9\x39\x47\x5f\xdb\xa8\x2c\xad\xeb\x7f\x6c\xf0\xf3\x57\x0b\xeb\x91\x2e\x04\x07\x4a\x5d\xd0\xf2\xfe\xb2\x66\x6e\x69\x20\x8f\xca\xa5\x80\x3a\xe3\x97\x3a\xfe\x80\x07\xac\x1a\xb5\xfc\x4c\xb6\x98\xc1\xf2\x42\xb5\x08\xa7\xec\x5c\x89\x70\x3e\x89\x39\xd2\xc4\xd2\x2e\x59\x17\xb1\x0b\x8c\xc6\x50\x14\xa1\xbf\xe0\x31\xaa\xc6\xb0\xbb\x74\xd3\x94\x20\xac\x94\x88\x0e\x65\x36\xa2\x2d\x35\xc5\x80\x5a\x21\xb1\xda\xa5\xee\x74\x78\xa7\x95\xec\x87\xfc\xb4\x1a\xf7\x01\x51\x3e\x06\x3e\x95\x48\x27\xc9\x10\x92\x88\x82\x5d\x65\x3d\x1e\xcf\x59\x55\x58\xf9\x98\x16\x7e\x9f\xa9\x91\xc2\x27\x8a\xd6\x1a\xe8\xb8\x9b\xbf\x78\xc6\xf3\x4f\x98\x79\xcd\x03\x7b\xb5\x73\xaf\xe8\xbc\x9d\x97\xdb\xfb\xc8\xde\x05\x15\xb6\xed\xfc\x0d\xd0\xd7\x5b\x7d\x8b\xd7\xaa\x94\x54\xb1\xe2\x5e\x8e\x84\xf8\x3b\xd0\x8f\x89\x10\xb1\xbc\xd1\xb7\x70\xd4\x02\x6e\xf2\x8d\x5e\xf4\xec\xbc\x0b\x60\x21\x2d\xab\xf4\x4f\xea\xad\x15\x1d\x70\x79\x91\xc9\x60\x6a\x1c\xde\x40\xb0\xe1\x4d\xe5\x81\xab\x04\x1b\x20\xf3\x0f\x31\x6c\x2d\x8a\x33\x7f\x56\x68\xd2\xbf\x26\x96\x48\xa3\x2b\x62\xe8\x03\xe2\x22\x61\x23\xf6\xe8\x9f\x23\x24\x0e\xc7\x6f\x75\xdc\x1f\x80\x2e\x0a\xc2\xd1\x8b\x06\xb5\x48\xff\x00\x03\xe0\x6a\xea\x2b\x98\x84\x06\x85\xc6\x9a\x75\x68\x0b\x38\x5a\xf0\xdc\x84\x3e\xa6\xd4\xba\x5b\x81\x9d\x5a\x85\xa3\x0a\x4d\x94\x8f\x84\xb2\xef\xb1\x82\x73\xfd\xc9\xcb\x59\x07\x6a\x17\x12\x4a\x15\x9b\x41\xaa\xd8\xd0\x3a\x89\xbc\xfc\x3f\x85\x41\x6c\x88\x09\x89\x9a\x06\x1b\xbe\xa9\x9b\x7a\x78\x7d\xad\xd8\x50\x24\x4a\x26\x28\x24\x59\xb5\x36\x4c\x15\xbb\xd4\x05\x26\x45\x76\xc1\xfe\x06\x93\x38\x13\xa1\x98\x89\x88\xe6\x15\xd3\x97\x4d\xfd\x3f\xa6\x7e\xa0\x8b\x18\x59\xec\xaa\x6a\xbf\x26\xcd\xa2\x4c\x25\xd3\xb4\x83\x80\x8d\x6a\x63\x10\x4d\xde\xc7\x84\x1a\xe6\x67\x6f\xc9\x9c\x46\x98\x7c\x24\x20\xf5\x24\xf5\x46\x30\x95\x91\x5a\xc7\x4b\x5e\x83\xb0\xe6\x8c\xca\x45\x11\x31\xf2\x42\x4e\x32\x15\x6b\x7a\xd9\xc5\x76\x88\xf2\xdb\x75\xcf\xa5\xa7\x77\x60\x8e\x48\x3f\xec\xec\x18\x0e\x89\xd6\xa0\x83\xc0\xdc\x74\x4f\x9d\xb2\x60\x66\xe8\x31\x0e\x7b\xdf\xb9\xd2\x14\xde\x6e\xeb\x98\x15\x38\xaa\x46\x63\xcf\xad\xbc\x97\x87\xbf\xbe\xb2\xa2\x56\xb5\x94\x90\x43\x06\xcf\x27\x25\xe1\xeb\x20\x0e\xdd\x04\xb4\xbf\xa9\x56\x44\x75\x56\x7e\x7f\x72\x7b\xed\x7c\x26\x65\x71\xee\x66\xf8\x66\x74\x33\x03\x2f\x75\x91\x37\x82\x5b\x01\xa3\x85\x29\xf3\x50\xbb\xad\x5a\xe2\x6f\x9f\xe9\xc2\xac\xb0\x0e\xf0\x44\xe9\x86\x8f\xd2\x53\xee\x5b\xf9\xc8\xc3\x80\x60\x54\xc2\x1c\x32\x01\x75\x6d\x77\x7f\xfc\x5a\xba\x63\x5c\xa0\xcb\xaa\x54\x03\x7f\xf9\x6c\xac\x2a\xfc\x8f\x4b\x09\x22\x9f\x54\x8e\xef\x43\xe0\xd0\x5d\x54\x0a\xc7\xc8\x8e\x84\xac\x32\x54\x49\x43\xe4\x08\xa8\xed\x5f\x71\xad\xef\x13\x86\xd9\x7c\xfa\xfa\xa5\x36\xfc\x90\xe2\x06\xc4\x1d\x33\xa5\x35\xd5\x51\x54\xdd\xb1\x50\x8b\x2b\x5c\x1d\xee\x7d\x45\xce\xb7\x99\x6c\xd3\x6d\x53\x4e\xc2\xb7\x3c\xc5\x6d\xa4\x2d\x58\xed\xe8\x28\xb2\x76\x09\xdd\x10\x0e\x5a\xe4\x9f\xa8\xd0\x2c\x15\x9b\x39\x4c\x95\x51\x96\x67\x81\x12\x56\x07\xb7\xad\x1b\x89\xba\xf3\x55\x4b\xd9\xf0\x6a\x3a\xbd\x3b\x0e\x7d\xbf\x9d\xea\xb5\x7f\x2e\x08\x39\x07\x3e\xb8\x4d\x86\x92\xa2\xf0\x57\xef\xf7\x69\x53\x56\x57\xd4\x12\xb1\xbb\x29\x0b\xb4\x26\xe2\xa2\x94\x41\x00\x72\x6d\x09\xcb\xca\x9c\x73\x64\xa9\xaf\x54\x71\x71\x3c\x62\xc2\xc7\xe1\xf0\x08\x42\x64\xa4\x8a\x82\x8e\x1e\x36\x3a\x36\x13\x65\x90\xd9\x25\x1f\x99\xd4\xe4\x15\x33\x36\x19\xca\xe9\x5d\x2a\xdc\x8c\xfb\x0d\x52\x55\x9e\x51\x22\xc9\x12\xbc\x92\x61\x14\x43\x5a\x7b\x7f\xce\x7f\x37\x76\x36\x57\xc8\x74\xb0\x08\x30\x59\xd0\xa8\x41\x08\x03\x75\x62\x8f\x3d\xbb\x2e\xbc\x8c\xf1\xe9\x41\x00\x57\x6a\x25\xa3\x88\x71\x32\x4c\xa1\x47\x67\xd5\x89\xe1\x6d\xac\x6c\xcc\xaf\x45\x10\x85\x7d\x38\x73\x26\x29\xec\xa1\xec\x51\x58\xe4\xfb\x35\xce\xb6\x5d\x91\x2d\x6c\x26\xe7\x98\x28\x50\x6c\x61\xa1\xe5\x03\xa2\x30\xfb\xbf\x54\xc7\x29\x0b\x08\xd1\x17\x6a\x49\xb1\xf0\x64\xb2\xbf\xee\x50\x8e\x73\xfc\x06\x92\xe0\x71\xf5\x2c\x63\x55\x1f\x2a\xa5\xd0\x00\x1b\xc6\xbf\xb6\xeb\xc1\xa6\x58\x74\xd2\x05\x2d\x13\xda\x62\xc1\x86\x6b\xb5\xba\x67\x15\x07\xc4\xb0\x1a\xe1\x98\x7e\x21\xd9\x15\xb0\x88\x99\x58\x98\x9c\x90\x6c\xe8\x59\xdb\xe3\x90\xd6\x38\x15\x8c\x69\x17\x6d\x0a\xce\xe3\x81\xa0\xc1\xec\x17\x87\x8a\x7e\xe9\xd8\x2d\x6e\x55\x16\xdb\x68\x2c\xd1\x64\x6e\x86\x83\xd8\xe8\x6a\x3d\x30\x4c\xac\x1b\x34\x1e\x3a\x34\xac\x0e\x2e\x6c\x9c\x31\xfe\x6a\xcd\x65\x89\x16\x98\x9a\x1c\x84\x0e\xe1\xf8\xcb\x29\x8f\x46\xa5\x17\x41\xe2\x2e\x1c\x31\xa7\x7c\x5a\xf7\x8f\xcc\x93\x25\xa4\x4e\x3e\xc3\x30\x8a\x50\xb8\x6f\x58\x41\x40\x50\xe5\x68\xbc\x64\xc7\x11\x48\x62\xd8\x35\x82\x40\xf5\x3a\xdd\xfc\xe7\xd7\x18\x66\x34\x8f\x5f\x4c\x0e\x90\x0a\x4c\x8e\x9f\xa8\x54\x7c\x8e\x57\x20\x4a\x85\x34\x9c\x8a\x85\x40\x6c\x64\x3b\x2c\xe0\x42\xf5\x1e\xc3\xc5\x3c\xbd\x6b\x27\xb8\xc0\xf7\x38\xb3\xfa\x79\x84\xb6\x3a\x53\xc6\xa3\x1e\x4b\xcd\xd0\xfc\x70\x0b\xdb\x2a\x81\x3b\x2a\x0c\x47\x49\xe3\x34\x83\x77\x8b\xb8\x0e\x95\x89\x0d\x5d\x11\x89\x76\x1a\xdf\x85\x02\xaf\x3c\xb4\xe4\x41\xad\xf6\xb3\x11\x1b\xd0\x0a\xf2\x19\x91\x13\xf8\xf3\x49\xc8\x3e\x8f\xe7\x8e\x1f\xc9\x51\xc3\x03\x0a\xc4\x3f\x38\xb0\xfd\x1a\xa2\x5a\x88\x60\x2a\x16\xcc\x4c\x38\x3d\x5d\x64\x05\xf9\x03\xb2\xae\x90\xe4\x90\x82\xe1\xf3\x51\xc7\x25\x2d\x35\x61\x14\x5c\x6e\x75\x5d\xb6\x4e\x0b\x4c\x25\x09\x85\xa3\x15\x36\xe9\x5d\xf4\xa4\x0e\x81\x92\x24\x45\xf8\xa9\x77\x2b\x18\x91\x8f\xef\xd3\x60\x01\x2f\x2a\x87\x1d\x9a\x57\x84\x1f\x96\x9e\x3c\xc3\x7a\xe0\xf0\xfd\x3b\x65\xa4\x87\x2c\x88\x58\xdd\x17\x5b\x5d\x47\xae\x58\xfd\x7c\x21\x5f\xd0\x19\x17\x48\xd9\xc3\xf2\x0c\x67\xe0\x64\x9b\x1d\xf0\x6d\x05\x3b\x18\xab\xce\xbb\xdd\x83\x23\x18\x93\x5c\x4e\xbe\x09\x2a\xbc\x6e\xd1\xd6\xb6\xec\x9b\x40\xc4\x59\x05\x55\x41\x5a\xb7\xaf\xcb\x88\x3c\xf4\xd6\xb4\xb9\x35\x6d\x74\xd6\xe8\x7d\xb6\x3b\x6c\x02\x38\x92\xf9\xc9\xa8\x80\xa3\x84\x85\x81\x17\x58\x48\xaf\x7a\x71\x95\x3d\xcc\x89\x3a\xc3\x20\xbc\xe6\x92\xb4\x86\x67\x35\x06\x5d\xaf\x45\x8c\xbe\x8b\x4b\x27\x44\xef\x11\x4d\x18\xcc\x99\x3d\xc9\x92\x79\xe5\xc4\xe2\xe8\xcc\xb6\x24\xe6\x61\xa0\x86\x2a\x6a\xd1\x57\xd0\x58\xcf\x57\xca\xa1\x96\xee\xc9\x56\x4a\xa9\x2b\xdd\x3e\x80\x88\xdd\xa7\xbf\x5e\xce\x3e\x6a\xdf\x58\x4e\x79\x7a\x9f\x88\xe3\xf8\x85\x65\x54\xc5\xc8\x08\x99\x17\xfa\x2a\x71\xa8\xbc\x02\x37\xcb\x77\x3f\x28\x15\x56\xb0\xcd\x41\x4e\x39\x06\x17\xab\x13\xdf\x63\xbe\xf6\x27\x8a\xe4\xdb\xea\x68\x26\x25\x33\x55\xd5\xaa\x76\x25\x9e\xc2\x8c\x98\x75\xec\xa4\x62\xf7\x04\xc4\x93\xe3\x86\x94\x10\x96\x30\xc1\xc4\x4c\xd9\x7f\xce\x0b\xdd\x27\x5b\xc6\x30\x19\xce\xef\x33\xce\xac\xaf\xa4\xa6\xc5\x47\xd0\x66\x54\xa7\xb9\xfe\xe0\x80\x24\x0b\x77\xd4\x71\x76\x7a\xac\x04\xc1\xe1\x00\x47\x95\x30\xf5\x85\xc9\x24\x5a\x73\x5d\xa5\x2b\x97\x2e\xcd\xae\x0f\xdc\x58\x1b\xc2\xb2\xcc\xd2\x5c\xa6\x21\x87\xb4\xa1\xee\x67\x44\x22\x6b\xc2\x28\x26\xfb\xb5\x33\x8f\x36\x6f\xe6\x2b\x49\xbb\x22\xbb\x96\x7f\xe7\xb0\xcd\x88\xec\x56\x25\x86\x9c\xe4\x1d\x23\x44\xc8\xb4\x5c\x72\x28\x95\xcf\x90\x5e\x4c\x03\xa7\xaa\x3e\xc5\x4a\x50\x0a\x0b\xb9\x0a\x4e\xdf\xcc\x60\xab\x55\x13\x8a\x57\x28\xeb\x24\x4a\xc0\xad\x3a\x93\x0f\x02\x2f\xcf\x25\xbf\xda\x17\xab\x1d\x1c\x2b\x2f\x73\x39\x14\x25\x3b\x99\x69\x95\xc8\x66\x9f\x6c\x9f\x4f\x3f\x11\x37\xe4\x98\xc5\x38\xe8\x95\xd1\xd4\xa1\x5e\xc8\x02\x6a\x91\xfc\x13\x55\x62\x3c\x54\xde\x4c\xff\x45\x71\x3f\xf3\x57\x16\xb4\xf7\xf9\xd3\x8c\xe1\xe0\xa3\x74\x71\x80\xee\x7d\x59\x72\x43\xc8\x30\x68\xe8\x6b\xd2\x2c\x9b\x4b\x72\xa3\x6a\x4d\xe7\xfd\xc6\x2e\x2c\xcb\x02\x63\x5d\xc8\xe0\xf8\x79\x9a\xf1\xfe\xe2\xbb\x0b\xb8\x7b\x11\xce\xd8\x2b\xa3\xcc\xcb\x77\x05\xfc\xf3\xb2\x12\xcd\xac\xc4\xc3\x99\xa6\x2b\x84\x7c\xb4\xbd\x6b\x4f\x20\xb9\x31\x9d\x89\xa9\x17\xe7\x7b\xb0\xe7\xb7\x62\xe7\x26\x81\x55\xdb\x5a\x1d\x7d\x2d\xa7\x57\xe2\x7a\xdb\xc4\xa0\xa6\x93\x30\x9b\x6d\xad\xb5\x30\xe5\xa7\xab\xb4\x0b\xda\x00\xda\x45\x7c\xbe\x3a\xeb\x2a\xd9\xcb\xeb\xeb\xd5\x73\xd5\x8d\xe2\x5e\x03\xdc\xce\x03\x86\xf3\xfd\x9b\xa9\x19\xed\x29\xa3\xd5\x03\xa3\xa0\x50\x8d\x29\xd9\x20\x09\x58\x2e\x21\xc4\xb7\x64\xb5\xab\xf4\x36\xc4\x48\x44\xd5\x5e\xe4\x22\x2a\xd2\xe1\xb4\x16\x69\xb2\xdf\xc9\x1b\xa2\xc1\xfc\x49\x29\x8c\xc5\xf4\x15\x46\x74\xba\xbe\x3e\x4b\x8e\xf4\xb7\xc9\x82\x34\x95\xfd\xd1\xe6\x1d\xca\x54\x96\xf0\xa4\x32\xc6\xc2\x8d\x02\x1f\x00\x81\x17\xd8\x23\x4b\xf1\x00\x64\x3d\x46\x03\x74\xc5\xde\x54\xb5\xbf\xde\x75\xe6\xaa\x3d\x1d\x15\x93\x18\x72\x68\x38\xef\x7d\xa4\xea\xa1\x0e\x21\x06\x66\xd0\xed\x29\xbe\x78\xe1\x99\xdd\x99\x17\x47\xa0\x00\x2a\x18\x4e\xc4\x97\x5f\x17\x00\xe4\x51\x6d\x65\xde\x92\x61\x10\x8f\xf8\x11\x10\x09\x8b\x14\xf3\x8e\x24\x1c\x63\x41\x35\x32\x9a\x0e\xe4\x5f\x01\x8b\xa4\x48\xf3\xcf\x43\x2b\x33\x62\xf5\x7c\x86\x1b\xa0\xd2\x95\xbf\x62\x06\x7d\x36\x0e\xbb\x87\x94\x32\x75\xb5\x46\xa0\x4c\x11\x60\x51\x47\x01\x54\x6c\xf9\x01\xff\x6d\xe2\xb1\x70\x4f\x6f\x8f\xaa\x49\xcd\x02\x84\x29\x27\xd9\x5c\xa0\xb5\xfd\x3d\x41\xd2\x5d\x3f\x6e\xe7\x52\x96\x61\x6c\x1a\x6f\x55\x6a\x20\x06\x39\x3f\xe4\x94\xb0\x06\xeb\x2f\x4e\x2c\x49\x32\x66\xf1\x6a\x9c\x2c\x91\x5b\x8a\x1a\x98\x8e\x0b\x78\x2c\x57\xf7\x36\x95\x04\xdc\xce\x83\x10\xc6\x71\xa5\xf3\x43\xf6\xdf\x64\xe8\xf9\x21\xf8\x6f\x7a\x41\xd9\xa0\xcf\x37\x89\x09\xdd\x81\xd4\xb7\x00\x06\x53\xa8\xe5\xc9\xe0\xc2\x48\x94\x04\xda\x35\xe9\x05\x7c\x23\xa5\xe9\x98\xf6\x8d\xa0\x2b\x0e\x05\x99\x8b\x04\xe3\xa6\xce\x98\x9c\xaa\x7c\x97\xe5\xd9\x2e\xbb\xba\x2e\x74\xfc\x9f\x82\x6a\xba\x30\x0f\x8e\x07\xa6\x0e\x64\xd9\x6e\xc7\xb3\x3c\x50\x68\x82\xc3\xbb\xd9\x48\x63\xb9\x58\x81\xa2\x70\xfa\xca\x59\x94\x73\x3b\xb2\xf5\xf9\xc3\x5b\x0d\x43\x70\x10\x36\x3d\x00\x00\x0a\x06\xca\x18\x00\x0c\x63\xe5\xfe\x9d\x83\x9f\x1c\x82\xd2\x9d\x53\xb3\xef\x92\x05\x27\x91\xb9\x80\xa5\xfb\x06\x14\xe2\x8a\xa4\xd6\xc2\x3c\x04\xc9\x44\x6d\xc0\xb2\x90\x00\x5d\x25\x01\x94\xef\xbd\xfc\xee\x0c\xa9\x13\xa5\xb6\xdb\x0e\x98\x8e\x75\x13\xd0\x5a\xc2\xdf\xe9\x06\x3c\xac\x62\x77\x1e\xca\xc9\x52\x25\x4a\xe9\xef\x7b\x63\x2b\x34\x9c\x34\x4d\x69\x79\x1a\x9b\x19\x84\x35\x3d\xdf\xd5\x18\xf4\xbe\x13\x33\x54\x06\xa1\xd2\x40\x7b\x19\xd0\xa7\xda\xbf\x2a\xc8\x78\x05\xf9\x89\x99\x3a\xaf\xd0\x5d\xe4\xce\x97\x48\x1a\x59\x21\x16\xab\xa2\x42\x7f\xaf\xcf\xab\x5a\x58\x91\x1d\x3b\xc3\x47\xc3\x95\x99\xd0\x68\x7e\x53\x88\x4d\x65\xd0\x0c\xf4\xfc\xd4\x08\x40\x5a\x34\x32\x31\x36\xb3\x16\x83\x39\xdb\x84\xeb\x83\xed\xf3\xc9\x74\xec\x47\x8b\x09\x79\x66\x1f\xce\x0a\x56\x56\xed\xd4\x7e\x5d\x97\x75\x84\x19\xff\x65\x24\x98\x00\x2b\x36\xae\xa9\x6a\x3e\xde\x67\x1d\x72\x87\xfa\x34\x15\xba\x05\x6d\x6e\x3c\x2c\x05\xc0\x1f\x5d\xc0\x5c\x7e\x1a\x35\x6b\x02\x4c\x47\x87\x64\xb7\x0d\xa4\x09\x6e\xfe\x6c\x57\xec\x59\x61\x69\xd1\x26\xd6\xb9\x04\xfe\xbe\xbc\xdd\x50\xc9\xff\x9a\xf6\x8e\xdf\x01\xd4\x22\xfd\x13\x07\x6b\x91\x6c\x02\x10\x5d\xdf\x51\x9b\x9a\x31\xc6\xe2\x70\x93\x95\xbd\x80\xb8\x76\x4a\x98\x12\x3b\x8d\x52\xcb\xd8\xf4\xe6\x29\xca\x0c\x06\x2d\x2b\xa7\x84\x8c\x55\xed\xd0\x73\x79\x4f\x90\x4e\x3e\x75\x47\x31\x5d\x85\xc8\x11\x35\x52\x39\x4d\xa5\xd1\x01\x1d\x08\x3e\x74\x8a\x89\xb2\xf3\x60\x8d\xa0\x8b\xa5\x14\x8c\x65\x94\x67\x0b\xa2\x87\xf3\x2b\x01\x71\xf9\x85\x4b\x98\x0a\xa6\x43\xd0\xfc\x5f\xdb\x0b\x95\x43\xff\x5a\xd4\x58\x4f\x83\xf0\x74\x5e\x46\x28\x9a\x9c\x9d\x58\xb4\xbc\xcd\x6f\x05\x0e\xb1\xbe\x50\x90\x62\xe2\x7e\xd2\xee\xba\x28\xc8\xdb\xc1\x1c\x66\x6b\x11\xa5\x7a\xfc\x0c\xb6\xf9\xfb\xad\x79\x81\xac\x5a\xea\x47\x3f\xd3\x67\x06\xc8\x27\x70\x45\x23\x2f\xfe\xf1\x31\x49\xce\x52\x7a\x60\x38\x97\x8a\xae\x4f\x3e\x93\x67\x3b\x97\x53\x7a\x8e\x50\x9c\x09\x32\xcb\xb5\x99\xae\xdc\x4a\x99\x79\xde\x84\xca\xa3\x64\x95\xd9\xf3\x47\x1b\x3a\x49\x7b\x4c\xbe\xd6\x7d\x49\x54\x62\x46\xbf\xb7\x65\x68\x45\x7a\x65\xc6\x57\xc3\xe0\xeb\x44\x13\xeb\x11\xae\xf3\xe5\x46\x06\xa7\x13\x23\xc3\x61\xb3\xbc\xcb\x40\x81\x42\xa4\x88\x94\x6e\x0c\x3c\x22\xa1\x92\xd5\x0a\xa6\x5a\x29\x95\x15\x76\x3e\xde\x99\xed\xa3\x8d\xd1\x4f\x0e\x0a\x96\x49\xba\x87\x86\x53\x64\xa2\xf8\xae\xe0\xa9\xca\xfc\xcb\x8b\x8d\x4f\x17\x17\xf5\xbf\x09\x25\xbd\x01\x9d\xb6\xe7\x5a\xe2\x0f\x7f\xd5\x23\x10\xae\x23\xfe\x75\x90\x32\xce\x14\x48\xf1\x5d\x9f\x6b\x53\xc7\xb4\x01\x28\xc9\xf3\xce\xe3\xae\x39\x54\x96\x3f\xdb\x9f\x32\xb2\xf3\xbc\x54\xbc\x3f\x08\x89\x22\x75\xef\xc8\x21\x78\xb1\xb0\xd0\xd0\x4b\xb0\x03\xc6\x47\xd8\xa3\x25\x6b\xea\x6b\xee\xa6\xc9\x22\x3a\x8c\xa4\x2d\x50\xd8\xa3\x8e\x6d\x00\x5f\xcc\x9f\x8e\x58\xed\xc1\x2c\x1e\x96\xdd\xec\xba\x49\x9d\x62\x63\xc4\x26\xa6\xfd\x4e\xe6\x1f\x91\xa6\xed\xc2\xbf\x2b\x02\x8e\x79\x78\xd0\xe8\xe1\x4a\xdc\xc5\x54\x70\xd6\xb1\x65\xb1\x2f\x81\xe8\xc2\xbd\x32\xe8\x8f\x89\x97\xa1\x30\xf3\x45\x39\x04\xc0\xaf\x20\xf4\xfe\xd1\xdc\x6d\xeb\xd8\x09\x7e\xa4\x46\x4b\x58\x76\x36\x2d\xc0\xb7\x25\xa0\xb1\x71\x40\xcc\xe8\x3f\x46\xc4\x06\x92\x84\x40\x66\xcf\x3b\x56\x3d\xd7\xb7\x51\x93\x44\x7a\x71\x9d\xd0\x2f\x67\xf8\x9d\x31\xb7\x1e\x42\xb3\x55\xdd\xde\x54\x0f\xfb\xe4\xc9\xcf\x07\x34\x3e\x16\x03\xcf\x82\x65\x3c\x7f\x88\x94\x21\x8a\xdf\x5e\x69\xb9\x00\x64\x59\xce\x8f\x7e\xa3\xe5\xeb\x2d\x4e\x53\xbf\x72\x32\x95\xa8\xc5\xdd\xf9\x0a\xe0\xac\xe7\x46\x7e\xfc\x40\x3e\xff\x7b\xc9\xe8\x6c\x9b\x02\x39\xd5\x2a\xa5\x9f\xb8\x65\x3c\x11\x1e\xd6\xd9\x30\x1b\x09\xda\x44\xd4\x5c\x76\x57\x64\xc0\x90\xe7\x4a\x0d\x75\x59\x4f\xf9\x69\xcd\x06\x40\x35\xd8\xa8\xb4\x03\x7f\x38\x27\x23\xb2\x32\x91\xdc\xac\x6c\x84\xf7\xde\xcb\x37\xbe\x59\x6b\x37\xa4\x5f\xe3\x60\x27\xa3\x33\x27\xb2\xb8\x80\x85\x63\x54\xc3\x16\x5d\x02\x2a\x78\x84\x14\x9e\xa8\xf8\x8e\x52\xb3\x2d\x68\x32\x40\x2b\x4f\xad\x38\x4b\x89\x78\x29\xd6\x1f\xa1\x94\x3e\xc1\xfc\x36\x00\xb6\x41\x86\x1b\x13\x20\xac\xe0\x0d\x74\x92\x33\xbd\x16\x3e\xf1\xb4\xa6\x62\xee\x63\x61\x14\xfb\x42\xb3\x95\xc9\x70\xd5\xe6\x4d\x79\xc8\x08\x59\xd4\x60\xd9\x9c\x81\x0e\x26\x3a\x93\x55\x0d\x8d\x4f\xde\x7e\x74\x69\x8e\xe9\xd5\x86\xf0\x14\x05\x4a\x91\x0d\xcc\x5d\xb6\x7f\x3e\x14\xb1\x06\x1d\xdc\x57\x21\x74\xca\xcb\x64\x7d\x64\xbf\xee\x3d\xd0\x96\x70\xb7\xc5\xf4\xcf\x44\x1a\xe4\x65\xfd\x3c\x60\x81\x4d\x5e\x25\x01\x2d\xcc\x9f\xed\x05\x63\xf8\x5c\x9b\x6f\x52\xbb\x94\x02\xac\xc7\x85\x40\x65\x90\xeb\xc4\xa7\xfb\x11\xa1\x38\xe1\x10\x8d\xb6\x4f\x08\x01\xb2\xa6\xad\xb0\xe7\x44\xde\x3e\x1c\x8d\xb4\x69\x87\x9e\xaa\x6d\xa2\x9b\x4f\x6e\x03\xc1\xd5\x82\x25\xf2\x19\x0c\x74\x87\xc7\x97\x5c\xc3\x84\x09\x3d\xa3\x3d\xbe\x1e\x45\x56\xdd\x74\x12\xd7\x08\x55\xc9\xe8\x93\xb0\x3d\xcd\x9c\x43\x7c\x0f\x65\x06\x74\x0f\x1a\x51\x5f\x72\xc3\x1e\x5c\x2a\x41\x23\x2a\x53\xd5\xc0\x07\x7a\x3f\x3e\x54\x78\xf3\x91\x65\xc8\x72\x73\xec\xfc\x2e\x02\xa7\x96\x7b\xd9\x56\xbc\x77\x45\xec\x07\xad\xdf\x29\x66\x10\x9d\xcc\x3f\x6e\x8e\x14\x33\xca\x8c\x2e\x8d\x80\x0a\xd2\x1a\x0b\xbf\x42\xa3\xc2\x50\xc0\x12\x9e\x94\x15\xc7\xcb\x26\x47\x4c\xa6\x1e\xe3\x7d\x99\x81\x47\x1d\x60\x94\x56\x12\x0f\x36\x56\x31\xce\x4f\x87\x9a\x43\x96\x96\x80\xfd\xfd\xbb\xbc\xf4\x56\xab\x08\x11\x11\x71\x57\xe3\x70\x14\xe5\xa8\x35\xf9\x44\xe4\x8a\x05\x1a\xd2\x4c\x45\xe7\x68\x98\xda\xe8\x06\x5b\xe3\xa0\xe4\xd5\xcf\x1e\x3f\x9b\xc5\xc6\xf6\xef\xaa\x65\xcd\xb6\x8b\xb8\x69\x8e\x50\x99\xbb\x91\x42\xfe\xd5\xd8\xa0\xf9\x28\x02\x5c\x11\xab\x11\x43\xd0\xd2\xf0\x51\x7d\x3e\xd1\xe9\x53\xb7\xf3\x6a\x7f\x50\x15\xd6\xaa\x5a\x2c\xdb\xed\xa0\xc8\x69\x93\xc4\x64\x57\xaa\xae\x84\xdb\x22\x45\x9e\xd4\x08\x4f\x18\xc3\x03\x2d\x14\xa3\xd6\xaf\x19\xb5\x48\x36\x26\x89\x0e\xb9\xe9\x26\x22\x39\x6b\xd7\x24\x11\x3b\xdc\x05\x4a\xef\x6a\x9d\x46\x96\x0d\x6f\x8e\x05\x1a\xa3\x6d\x8c\xbc\x66\x37\x7d\xeb\xd7\x13\x64\x2c\x4b\x25\xe6\x75\x11\xb8\x65\x9b\xa5\x0e\x16\xe3\x81\xa1\x4c\x1f\x7b\xf6\x41\x1d\xfd\x1e\xce\xea\x37\xb8\xb6\x61\x0c\x59\x3e\x12\xaf\x1b\x66\x5c\x75\x27\x5d\x84\x72\xcb\x45\x9e\xe2\xca\x41\x31\x72\x84\x07\x6f\x7f\x09\xd6\x61\x43\x0e\x59\xe0\x4f\x06\x1e\x3d\x51\x43\x2c\x45\x08\x4e\x33\x8a\x88\x42\x52\xe6\x19\x69\xb8\xf5\x5f\x1e\xcb\x92\x4b\x4d\x8a\x19\xc8\x07\xca\x13\x42\x8c\x87\x1b\x09\x96\x63\x4a\x8a\x3f\x76\xb5\x94\xbe\xea\x46\x14\x26\x02\x3b\xb5\x74\x33\x3a\x6a\x6a\xca\x5c\x83\xe4\x2f\x8a\x99\x72\x03\x0d\x5e\xd6\xc4\xbb\xd0\x99\xd3\xbf\xf8\x1d\x99\x94\xf4\xb1\x3a\x55\x0b\x6a\x7e\x4c\xd5\x3b\x4c\xe9\x7a\x7b\xe7\xa0\x33\x31\x89\x40\x52\x1f\x95\x55\x05\x4f\x11\xe1\x0a\x97\x08\x27\xc5\xbf\xa6\x61\xa7\xed\x7b\xfa\xbf\x19\xad\xd1\x9e\xf9\xa5\x7f\xa4\x15\x86\x36\x7e\x8c\x2a\x76\x94\xd4\x32\x05\x98\x66\xab\xd8\xf5\xb3\x1c\xfc\x1d\x49\x2a\xbc\x51\x75\x84\xf6\xee\xc5\x88\xe7\xa1\x85\x61\x27\x9c\xa7\x8f\xbd\xf1\x3c\x44\x47\xf5\x20\x8b\x95\xae\xe4\x25\xc4\xc7\xbc\xa7\x10\x20\x96\xad\x56\xde\xd7\xfb\x4b\xf0\x90\xf6\x25\x92\x9d\xd2\x65\x83\xf0\xfe\xdf\xab\xb8\xf6\xdf\x8e\x2b\x58\xf7\xbf\x61\x18\xef\xa9\x7c\xea\x6b\xe0\x46\x7c\x23\xc7\x6e\x13\x58\xf3\x0f\x81\xed\xd9\x7b\xd9\xde\xb9\xdf\xd4\xe5\x76\x65\x07\x2b\x17\x24\x7d\x48\x3e\x44\x4e\x00\x6c\xf7\x0c\xd2\x2a\xc6\xeb\x84\x3d\x18\x03\xc7\x23\x23\x54\x2e\x5e\x97\xbf\x99\xbb\xc4\x3c\x95\xde\x0e\x70\x21\x43\x1d\xba\x17\xa6\x17\xce\x5c\x27\x04\x52\x28\xb9\xd3\x27\x83\xbf\x4f\xff\x7e\xbb\xe1\xf8\x12\x36\xe3\xc2\x66\x18\x90\x1e\xbd\x06\xf6\xc7\xf8\x5b\x8a\x89\x35\xb6\xc1\x18\x90\xa1\xfd\x63\xdf\x01\x9f\xf5\x1a\xac\x9a\xdf\x14\xed\x8c\xbc\x24\xc1\x07\xcd\x7c\x3b\xc4\x8c\x07\x16\x3f\x3e\xda\x6a\x44\xc3\xdf\xb0\xaf\x08\xf3\x44\x3d\x47\x25\xfa\xc6\x10\x0a\xa0\x63\x12\xf8\x90\x26\x9b\x42\xc5\xdf\x60\x14\xdb\x9e\xcd\x57\xa9\x65\x27\xe1\xe0\x82\x44\xd4\xa9\x27\xec\xd2\xb4\xb4\x30\x87\x01\xf9\x9b\x86\xa0\x6d\x58\xa3\x9f\x27\x27\x9a\x11\xfd\xd1\xfa\xe2\xc4\x89\xf6\x8f\x0d\x92\x5f\x1c\x48\x25\xc5\xe8\x50\x6a\x10\x74\xb5\xbd\xa9\x82\x48\xaf\xb3\x4d\x1e\x8f\x3e\xc7\x1d\xb3\x79\x46\x05\xb8\x4b\x7b\x34\x35\x6a\x3d\xe6\xa9\xaa\xba\x98\x89\x0e\x09\x75\x46\x42\xa0\x3f\x42\x03\x77\xeb\x7f\x37\x0d\x10\x14\x4a\xe2\xb5\x13\x9c\x2c\x88\xb4\x3f\x40\xd5\x90\xff\x55\x96\x3a\xf7\x88\xa7\xaa\x9b\xec\x97\x43\xdb\x68\xc4\x3f\x90\x6d\xda\x22\x19\x86\x45\xb5\x26\x39\xe2\x20\x6e\x30\x78\x0d\x26\x13\xb5\xaa\x18\x38\xcd\x34\xac\x92\xe5\x91\xa4\x07\xec\x1f\x78\x86\xb8\x51\x85\x97\x76\xd0\xdd\xfb\x7e\x37\xe4\x67\xfa\x42\xbe\x22\x0b\xd1\xec\x98\x33\x73\x67\x2e\x3c\xba\x9f\x38\x2f\x86\xa2\xb9\x8b\x3a\xd0\x69\xa2\xb6\xbe\xcd\x09\xb2\x87\x87\x57\x54\x36\x1a\x45\xf4\x22\x06\x6c\x53\x6e\x6f\x66\xef\x1c\xb3\xa0\xcf\x70\xb8\x89\xd7\x17\x3c\xe3\xd5\xd7\xb2\xd8\x56\x1a\xd3\x70\x72\xb5\xea\x50\xc3\x66\xec\x1a\x08\xac\x02\x96\x56\xc2\x27\xa9\xf1\xca\x42\x1d\xe3\x3f\x37\x9f\x47\xa5\x7a\x43\x88\xf8\x17\x3a\xe6\x20\xea\x28\x4f\x7d\x2a\x5a\x46\x50\x04\xb4\x6e\x96\x3a\xbe\x32\x06\x4b\xdf\x98\xb3\x40\xad\x7a\x42\x08\x53\xd0\x48\x80\xaa\x03\x2a\xcc\xd4\x0c\xdd\x40\x96\xe3\x5f\x6c\xfa\xd4\x99\xad\xc8\x19\x04\xe3\xa5\x51\x8d\x03\x10\x21\x57\x32\x3b\xea\xb6\xa5\x9d\x3e\x01\xac\xea\xa0\x70\x6b\x6f\x8c\x64\x74\x80\xfb\x64\x85\xf9\x0d\x34\xc5\xe1\xfc\x9d\x24\x24\x45\x20\x85\x53\x62\x97\x11\x83\xe1\x21\xed\x96\xaf\x70\x86\xe3\x54\x06\x8b\x4b\xf1\x46\x21\xef\xfb\x4d\xf0\xf1\x7e\xca\x25\x79\x72\x4d\xab\xbd\x9c\x3f\x29\xca\xe2\x2c\x04\x9d\x58\xda\x78\xb0\x82\xd8\xb2\x5d\xdc\x23\x7d\x08\x99\x2a\x84\xaa\xfa\x17\xfa\x37\x45\x75\xec\xb2\xa6\x31\xf0\x1a\xf2\x87\x93\xdf\x9d\x3f\x84\x6f\x6a\x9b\x3f\x36\x5c\x92\x6f\x78\xb3\x2b\xcb\xf0\xbe\xb3\x41\x2d\x0b\x0f\x03\x37\xe1\xe2\x72\x18\x8a\x63\xc4\xf4\xb4\x54\x19\xc0\x06\x87\x40\x37\x9f\xb9\x83\x4c\x8a\xed\x5a\x8c\x79\x1d\x16\xaa\xaa\x8e\x18\x6a\xc7\x87\x5c\x21\x36\x4b\x91\x98\x85\x9a\x17\xd0\x10\x7c\x7d\x47\x7d\x47\xd6\xb4\x47\xfc\x37\x8e\x33\xb0\x1d\x55\x54\x81\x86\x9e\x44\x9b\x6c\xad\x55\x09\x1c\xc9\x39\xda\x70\x8b\x3f\x5c\xc1\xfa\x8a\x46\x99\x8b\x82\x4c\x8d\x60\xc3\xe7\x8e\x59\xea\xb8\xa5\x1c\x1b\xa9\x91\xc3\x71\x90\xae\x3d\xbe\x1b\x9a\xee\x8f\xc9\x01\x45\x85\x28\x99\xfd\xb6\x03\x5c\x7c\x6e\x5e\xb9\xe7\xc1\x5a\x16\x70\x25\xe3\x10\x03\x06\x52\x66\xbd\xf6\xa4\xeb\x1c\xbd\x0a\x31\x8e\x67\x2a\x28\x27\x0e\xa0\xc2\x9b\xda\xbd\xae\xde\x81\xad\xdb\x4f\x32\x8e\xbb\x45\x8d\x28\x6a\x5f\xb4\x1b\xbf\x31\x09\x91\x09\xdc\xc5\x60\xb6\xe9\xa6\x7c\x17\x58\xc3\x09\x64\x7c\x2e\x62\xf2\x93\x7a\xf4\xd6\x26\x0b\x44\xfb\x49\x28\x6b\xb9\x1d\xdb\xd2\x00\x9f\x34\x7b\x1d\x40\xa7\xb0\xd0\x17\x01\x97\xfe\xad\xb9\x9d\x3f\x67\xc5\xca\x3e\x01\x4c\x7c\xbe\x85\x75\xb8\x7c\xdb\xc7\x6a\x30\x87\x98\xa5\x8d\x64\x62\x27\x6a\x1e\xd8\x23\xa5\x12\x74\x9a\x9b\xb0\x10\x93\x77\xc0\x41\xd3\x20\x23\x1b\x36\xfb\x0f\xb6\x2f\x6c\x96\x93\x01\xf9\xb0\x7a\x98\x50\x4b\x0f\xfe\x0e\x6c\xca\xd2\x4f\xd3\x2b\x20\xcc\x91\x3a\x18\x73\xfb\xb9\x20\xea\x86\xf4\xa3\x88\xea\x63\x87\x68\xd4\x82\x33\xbe\xc7\xd0\x84\xe2\xe8\x01\x9d\xbf\xc9\x26\xa9\x14\xd5\xf9\x48\x9f\x56\x0c\xbb\x05\x0d\x13\x10\x95\x37\xa3\xd9\x36\x56\xd7\x19\x9d\x92\xdb\x1e\x35\x06\xf7\x45\x2c\x4b\x9b\x89\xfd\xc7\xcd\xa5\x56\x61\x32\x55\xfe\x67\x05\x1f\xe2\x8e\xa6\x04\x3f\xd6\xf4\xbf\xa8\xae\x21\xa3\x7b\x78\x89\x11\x52\x3c\xa8\x46\x6b\x80\xc3\x93\x59\x37\x09\x75\xae\x53\x06\x60\xc3\xa3\x29\x8c\x44\x4a\xf8\x38\x8a\x6f\xf6\x57\x7d\x6a\x0e\x59\x5f\x46\x5c\x35\xe8\x8f\xc5\x5f\x6c\x38\x8f\xb3\x1c\x2a\x22\x79\x19\xdd\x24\xf9\x54\x57\x4c\x78\xbe\x5f\xe6\xf0\xe2\x4a\xda\xa7\x56\xf8\x92\x2a\xf9\xd0\x1b\x03\x87\xb3\xa8\x27\x17\x61\x6f\x58\x91\x98\x38\xb4\x9b\x67\x9a\xd6\x2f\x22\x30\x77\x6b\xcf\x6e\x9a\x02\x83\xdc\x22\xab\x1a\x71\xb7\xfa\x3e\xc5\x60\x84\xbd\x56\x35\x4f\x99\x20\x26\x2c\xba\xcd\x10\x49\xd1\x95\xf5\xd2\x48\xee\x11\x3c\x79\x9e\xdb\x63\x1a\x80\xae\xec\x16\xb3\x90\xf9\x2f\x58\x86\x0d\x9e\x78\xbe\x83\xe8\x5c\x0e\x2a\x4e\x37\x7e\xd1\x43\x22\x53\x3c\x64\xdb\x38\x72\x61\xfe\x3a\x64\xd3\x15\x65\xde\x99\xf9\x65\xba\x5e\x03\x25\x8d\x36\x39\xd2\x4a\x9d\xb3\xf0\xc1\xca\x34\x6b\xa3\x02\x65\x56\xf5\x06\x26\x14\xce\x2c\x01\xbf\xf2\xa0\x1d\x3b\x3c\x0c\x7e\xc9\x92\x83\xa8\x68\xa5\x2d\x24\xb4\x46\x3d\x00\x5a\xf0\x11\xc6\xd4\x90\xa5\x5c\xc1\xfd\x28\x06\xa8\x66\x1f\x93\x6e\xce\x8b\x5f\x87\x50\xa9\x22\xcb\x6b\x69\xbc\x0f\x8f\xb1\xb1\xdc\xd6\x36\x2a\xc8\x98\x0d\x06\x3f\x15\xa7\x71\x9f\xcf\x9a\x47\x13\x5b\x3a\xc9\xc0\x62\x2f\x63\x65\xcb\x92\x4c\x3f\xa3\xf7\x52\x99\x0c\x55\xbc\x32\x8c\xf1\xb5\x04\x8a\x26\x12\x6f\x21\x63\x2b\xf4\x60\xd4\x86\x98\xcb\x7d\x09\x10\x3b\x41\x59\x3a\xa1\x9e\x44\x0e\xaf\xcd\x6a\x42\xc3\x13\x32\x27\xf1\x0a\x9e\xe9\xa1\x46\x31\xfa\xb6\x0f\xeb\xe3\xdd\x9c\x58\xa5\x55\xb2\x73\x48\x38\x7a\x3d\xc2\xd9\x3f\x2e\x1d\x66\xcc\xd2\x9e\xa4\x6f\x5b\xce\x03\xbf\x55\x57\x23\xdb\x86\x9f\xac\xcb\x8d\xe4\x30\x36\xb7\x1d\xf8\xb8\x1a\xf8\x51\x5d\x4b\xa0\xbd\x73\xfd\x42\x85\xaf\xe3\x8a\x82\x75\x35\x21\x24\x20\xe3\xad\x4e\x18\x9a\xc5\x1a\x8a\x3d\x61\x5a\xb2\xd1\xc5\x08\x2e\xbe\xf9\xad\x49\x36\x32\x94\x62\x20\xcc\x9c\x30\x97\x81\x81\x09\x33\xad\xd4\x52\xa7\x49\xca\x09\xc0\xe2\x50\x30\x7d\xed\x50\x89\x4f\x8b\xae\xfc\x51\x69\xb6\xc0\xf4\xc3\x37\x9c\x3d\x94\xcb\x4e\x02\x2e\xca\xc4\x87\x2a\x42\x58\x11\x62\x64\x14\x4a\x7f\x85\x26\xab\x91\xc7\x5f\x39\x90\x5a\x7c\x8a\x36\xc9\x44\x5f\x80\xe3\xc8\x55\xb4\x65\xdc\xf3\xe3\x61\xa0\x1a\xef\x94\x43\x4d\x49\xfe\x13\xf9\xda\xf7\x82\x52\x65\x7e\x32\x0a\x9c\x3b\x77\x41\x54\x94\x04\xda\x2c\x57\x9e\xb6\x38\xc5\xc6\x05\xec\x9e\x17\x38\x8c\x21\x0f\x20\x44\xae\x7f\x97\x2a\xc6\xf0\xdd\xba\xdd\x7e\x5c\x15\xe0\x16\x29\xac\x16\xf9\xd7\xe0\x2c\x2f\xb9\x94\x8e\x49\x44\x15\xc6\x15\xd4\x8d\x27\x4e\xe3\x5d\x2b\x1a\xab\x1a\xbe\x69\xea\x70\x48\x3b\xbf\x38\x37\x8f\x64\x49\xfd\xc8\xf7\x48\x68\xd4\xe5\xd9\x19\x2b\xe7\x42\x28\x2e\xf0\x30\x83\x38\x76\x24\x72\xf1\xcf\x8d\x5f\x1c\xa6\xb6\xaa\x45\x82\x19\xdd\x5f\x15\xd4\x79\x22\x01\x5c\x50\xfb\x7f\x00\xb6\x11\x49\xee\xa0\xf4\x98\xc6\x5d\xf1\xc1\xd3\xb1\x01\x73\xdd\xf5\xa1\x47\x93\x7d\xb7\xee\x66\xc8\xfc\x5c\x1f\x66\x17\x6d\x1c\xc2\x99\xb7\x36\x67\xca\x9c\x9b\x80\x43\x6f\xf1\x95\x36\x57\xe1\x2a\xcc\xfa\x2e\x45\x9e\xf7\xdb\xb2\x83\x6f\x8b\xe6\x8e\x87\x3b\x73\x69\x3e\x57\xfb\xf9\x99\xab\x20\xbb\x56\x8f\x5b\xda\xdf\xcc\x5e\x2f\x1d\x3e\xf5\x3b\xcf\x97\xd3\x5e\x36\x5a\xad\x6e\x2f\x4e\x64\x77\xb7\xa9\x7e\x52\x44\x27\x2f\x98\xf6\x9f\xa8\xb4\x7e\xa7\xe2\xec\xf3\x7e\xd9\x9d\x60\x5e\xb8\x98\xda\x6d\xa7\x56\xf0\x60\xa7\x55\xc9\x16\x9f\x27\xdb\x5e\x97\xe0\x7b\xc2\x04\x91\x24\x6e\x79\x78\x06\xeb\xde\xbe\xe9\xaf\x6e\x7e\x43\xb1\x3e\xd8\x64\x08\x23\x8a\x0a\xaa\x90\xcd\xc1\x0b\xec\xb9\xf3\x6a\xcd\x0e\xe3\xad\x04\x1d\x68\xf8\x45\x86\x0b\x74\x78\x9e\xa2\x8b\x4b\x94\x4a\xc1\x4d\x83\x0c\x4b\x99\xcf\x73\x45\x9e\x71\xa5\x5a\xc5\x7c\x63\x95\x06\x9c\x50\x14\xfa\xe3\x2c\xba\x2c\x3b\x93\x8d\xa2\x34\x44\x9a\x51\x5e\x48\x93\x59\x51\x1a\x79\xb2\x29\x5f\xe4\x1c\x6b\xa0\xd0\x54\x22\xdd\xa7\x66\x82\xcd\x0c\x27\x1d\x12\xbb\x90\xc4\x29\x60\xa5\xf0\x1b\x58\xa6\x9d\x60\x64\x20\xef\x69\x2e\xf2\xc6\x1a\x15\x8a\x64\x75\xda\x2f\xdc\x89\xac\x23\xad\x81\xee\xa7\xcf\x1c\xfd\xdb\x3c\xd8\x99\x08\xb5\x40\xb9\x89\x95\x08\xe4\x6e\xc5\x34\x79\x10\xae\x67\xe0\x00\xd4\x2d\x0a\xdc\x01\xae\x76\xd0\xa9\x57\xa1\x03\xaa\x1e\xa2\xcc\xad\xea\x85\x79\x67\x9b\x38\xb8\xe1\x68\x30\xf3\x77\x96\xdd\x51\x06\xdb\x8a\x21\x4f\x15\x82\x6e\x61\x6a\xd9\xa0\x4a\xbb\x4d\xaa\xcf\xa5\x49\xda\x09\x97\x3b\x82\x70\x85\x3e\x21\x85\x73\x8b\x67\x4e\xb8\x73\x58\x5d\x0f\xdf\xf2\xb8\x06\x86\xed\xc2\x19\xca\x26\x2f\x0e\x0d\xa9\xe8\xc5\x4e\x74\x7e\xf9\x0f\x5f\x93\x6f\xd0\x6e\x2a\xda\x3a\x94\xd8\x4d\xb3\x21\xac\x97\x84\x0f\x42\xcf\x82\x46\xed\x36\xfb\x5a\x36\x61\xf6\x53\x6f\xa7\x46\x0d\x6f\xb6\x6d\x25\xce\xf5\xd6\x0f\x24\x82\x1b\x0d\x51\x40\xe9\x5b\x4d\xbc\x29\xe2\x24\xcd\x16\xe1\xd3\x49\xfb\x6a\xff\x63\x0a\xb4\xb2\x55\x8a\xa8\x0a\x26\x18\xbf\x4b\x08\x04\xdd\x56\x5b\x84\x65\x76\x3d\x12\x9a\x07\x31\xf7\x27\xc6\xc2\x65\x62\xd4\x85\xf7\x98\x8f\x57\x4d\x40\x06\x65\x07\x45\x2d\x05\x13\x48\x99\x34\x7a\x18\x45\x2f\x83\x42\x60\xc4\x66\x9b\xe9\x92\x62\x19\xda\xa9\x91\x54\x28\x92\x82\x13\x11\xa8\x19\x90\xce\xb2\xee\x69\x29\xd9\x2c\xdf\x15\xd4\xbc\xe4\xc3\xc0\xc4\x5b\x4e\xe8\x8e\x40\xb8\xc6\x41\x9c\x0d\x88\x45\x98\x32\x73\x49\xe0\xb4\x81\xfb\x7a\x64\x22\xe3\xcd\x29\x60\x20\x7c\x20\x68\x9d\x31\x3f\xee\x65\x9a\xb9\x6a\x00\x33\x05\x22\x33\x71\x3d\x27\x6f\x09\x72\x93\xec\x7f\x07\x45\x7a\x1d\x0f\x98\x3b\x71\x7c\xda\x19\x0d\x0c\x50\x52\x07\x30\x64\xe8\x78\x2e\xa3\x86\x1a\xc3\x9c\x74\x36\x3f\x6b\x2e\x72\x82\x03\x36\xf4\x9d\xa4\xb6\x2f\x98\xa3\x59\xa5\x3d\x37\x09\xa1\x44\x4a\xf1\xeb\xf2\x3b\x20\xca\x5e\xfb\x50\xb4\xb8\xe3\x8c\x90\xe8\x8a\xc0\x5f\x73\xb0\x6b\x5b\x4a\x28\x73\x7e\xad\x38\x2b\x49\x6d\x2d\x33\x2d\x4d\x72\xc3\xba\x0c\x40\x05\x0c\x26\x40\x1a\x2f\x69\x11\x03\x91\x04\x49\x3b\xaf\x05\xa9\xc2\x1e\xea\x18\x3c\xad\xb3\x27\x3a\xa0\xc6\xc0\x0a\x14\xa3\x11\x08\x31\x1d\x9d\x93\xb3\xb8\xad\x3f\x9b\x81\x1c\xdd\x2f\x89\xf1\xed\xc2\xbd\x27\x1b\x70\x17\x24\x78\xfd\xc1\x6b\xe4\xc1\x23\x0a\xbe\x50\x74\x2c\xe5\xf5\x33\x00\xe1\xc3\x7c\xc2\xc5\x13\x2a\x94\x85\x57\x56\xcf\xf3\x9d\x7d\xda\x80\x21\xb5\x57\x74\x9d\xfd\xe9\x36\x48\xcf\x57\x77\xd2\x91\x3a\xdf\x75\xf1\x54\xf2\x7c\x3c\xef\x54\x9b\xff\x7a\xd9\x38\xe1\x5d\x28\x40\x72\x71\x45\xcd\xc7\x09\x9f\x73\xd2\x81\x7f\x36\x05\x02\x5e\x73\xd8\xc4\x51\xde\xcb\xd5\xa0\x67\x51\xe1\x7b\x44\x3e\x00\x5b\xa2\x6f\x4f\xa2\xa6\x48\xdf\x5a\x60\x08\x13\x7b\x00\xc9\x1a\x70\x04\xc0\xd7\xc8\x8b\x60\x64\xba\x5f\x94\x3c\x09\x88\x77\xdf\x85\x0e\x3c\x46\xbe\xf0\x0e\x05\x92\x14\xdc\x09\x66\xf2\x0a\x01\x19\x56\x51\x8a\xab\x19\xc6\x6b\x38\x60\x03\x00\x51\xc3\x93\x96\x06\xb1\xa9\x9c\xb6\xa0\x40\x27\x97\xba\x87\x09\x81\xaa\xfe\xc9\xd2\xc1\xb8\xb3\xe9\xb2\xce\x4c\x07\x33\x75\x39\xc9\x62\xb3\xb1\x6e\x90\x30\xf2\x50\xd7\x8d\x07\x42\x9b\xb7\xf0\x81\xd1\x5b\x84\xf2\xc0\x85\x02\x7e\x9e\x10\x5a\x30\xec\x53\x40\xce\x5c\x72\x52\x2b\x72\xdc\xf9\x60\x1a\x2d\x17\x9c\x0a\x17\xa4\x7d\x7a\xd7\x76\x50\x3c\x0d\x10\xbf\x5d\x06\xd3\x2c\x28\x04\x87\x92\x87\xc0\xa8\xde\xa6\x58\xab\xf1\x80\xb8\x44\x38\xc8\x40\x71\xbc\x3b\xda\x16\x16\xbf\x01\x47\xb5\xca\xe0\xb0\x03\x8d\x66\x96\x93\x21\x10\x8c\x65\xf4\x22\x5b\xbc\xc3\x46\x20\x27\x22\x5b\xad\x76\xa4\xc9\xc1\x60\x9a\x14\x10\x2a\xf1\xc2\xf1\x59\x56\x5d\x1c\xec\x9b\x14\xbe\x5d\x1c\xe7\x33\x15\x19\xa9\x0e\xb4\xde\xfd\x99\xde\x6b\x38\xb1\xd4\xec\xc8\xc0\x17\xe0\x56\x54\xa7\xed\x86\x07\xdc\x4e\xfd\xb0\x5e\x48\x85\x36\x63\xb6\x08\x90\x1e\xbc\x5c\xec\x4d\x7a\x87\xf6\xa5\x11\x15\xd3\x05\x54\x83\xb7\x26\x43\x28\x63\x0a\x24\x40\x31\xc0\x98\x54\xd0\x09\xa7\x99\x38\xdc\xf5\x3c\xf0\x0d\xbc\xb8\x6a\x23\xc4\x2f\xdd\xf5\x3c\x41\x23\x19\xb6\x2e\x22\x7a\x93\xa1\x3b\x41\x89\xbe\x49\x8a\x08\xf6\xb8\x9c\xd3\x02\x68\x31\x11\x28\x20\xfc\xb3\xd8\x8e\xea\x76\x75\x99\xf3\xd3\xed\xb6\x82\x7d\xa5\x52\xd9\x00\x75\xc5\x10\x5a\xfe\xc1\x66\xb2\xd8\x7d\x92\xee\x69\xcd\x16\x21\xe0\x47\x4b\xae\x41\xac\x59\x06\xaa\x8d\x6b\x80\x1b\x5d\x52\xd6\xf6\x34\x1f\xba\x95\x67\xb8\x30\x72\xa2\x81\x48\x12\xcd\xe3\xea\xc1\x37\x8c\x37\xf8\xcb\x51\x9c\x2b\xc8\x89\x11\x79\x14\x51\xed\xba\x99\x96\x10\xef\x9b\xdd\x63\x60\xe0\xa2\xb3\xe0\x91\x8f\xf9\x0a\x21\x3d\x3f\x0c\xa2\xaf\x12\xcf\x63\x59\xe8\x55\x03\x1c\xe8\xaf\x7b\xdc\xf8\xcf\x0e\x08\x49\xc9\x69\xec\xc7\x36\x22\x5d\xab\x51\xc8\x70\x6f\x62\xfd\x03\xdf\x30\x5c\x52\x61\x0f\x8e\x61\xda\x4c\xc2\xc9\x76\x8c\x95\xc1\xa2\x65\xe0\xc1\x1e\x2e\x82\x5a\xff\x00\x87\x84\xf6\x01\x00\x05\xdd\x00\xc0\xb5\x8b\x00\x08\xaf\xc2\x61\x42\x72\x75\x0f\x91\x2d\x16\xdf\x72\xdb\x79\xea\xa4\xf1\x4c\xfb\x09\x21\x93\xc9\x6f\x76\x15\x6d\xc4\x96\x5b\xd7\x56\x88\x28\xdc\xbf\xc9\xd6\x06\x49\xe1\x53\x92\x9e\xc4\x44\xb8\x27\x1a\x3b\x3c\x54\x41\xe4\x4f\xb8\xb7\x18\x6c\xfc\x85\xfc\x2d\xb0\x1d\x02\xf6\xbc\x0a\x88\x36\x43\x06\xcc\x31\xd9\x79\x28\x22\x41\x46\x85\xae\xba\x42\x24\x5c\x38\xad\xdd\xd5\x8d\x39\x21\x1e\xea\x8e\x7d\xc9\x10\xf4\x7b\x30\x82\x50\x75\x0c\x14\xbe\xd3\xb8\x29\x20\x24\xcc\x07\xc6\x4c\x3d\x8b\x59\x9d\x82\x8d\x75\xea\xd8\x77\x38\x37\x34\x82\x96\x08\x05\x29\xe3\x1b\xb2\x44\xe5\xac\x79\xb5\xdd\xca\xc2\x81\xc5\xe4\x1c\x7c\x0e\x2b\x28\xba\x05\x4b\x99\x03\xc2\x00\x95\xb0\x73\x71\x09\x69\xd5\xcc\x89\xaa\x90\x50\x04\x86\x24\xfa\x90\xe8\x21\x5d\xc0\x3f\x01\x87\xc7\x01\x01\x44\x36\x3f\xf4\xc0\xb4\x72\xb9\xd1\x97\x07\x8a\x00\x2b\xb3\x72\xbe\xd2\xed\x3c\x4d\xae\x9d\x55\x48\xb5\x8e\x4f\x88\xba\xc2\x07\xb1\x4e\x1c\x6c\x59\xb8\xa1\xa0\xfb\x01\x8d\xa0\xb5\x55\x1e\xcb\xb8\x3f\xc1\x21\x1b\xe9\x27\x66\xbf\xca\x5a\xab\xe8\xa1\x02\x9a\xe0\xab\x41\xf0\x2c\x30\xa7\x85\xbc\x74\x88\x74\xb7\x8b\x56\x34\x57\x6d\xa2\x44\x89\xa6\x0c\x87\x0d\xc1\x0e\xae\x36\xef\x93\x69\xe9\x38\xff\x1f\x27\x5d\x14\x1f\xe7\x62\x14\x74\x87\x62\x0d\xf4\x56\xa7\x22\x24\x47\x88\xd2\x42\xf4\x84\x69\x71\xe7\x5c\x28\x67\x89\xc7\x1d\x82\x80\xbe\xfb\x15\x84\x6b\x9c\x4a\x64\x8f\x06\x46\x6d\x7d\xef\x07\x90\xc4\xc8\x7a\x26\x5d\x63\x30\x33\xfe\xc9\x6a\x2a\x21\x7a\xca\xeb\xd9\x12\xab\xe2\x4e\x3d\xf1\x9c\x3a\xdb\x4c\x62\x5d\x61\xfb\x2a\xec\x45\x3c\x90\xf2\x8b\x06\x12\xb7\x24\xc3\x56\x68\x8a\x30\x16\x34\x92\x6e\x14\x37\x04\x46\xe8\x57\x90\x44\x6d\x32\xa3\x06\x2d\x6c\x24\xdb\xc6\x99\x77\x7c\xbb\xc2\x1b\xb0\x79\x66\xdc\xbd\x57\x2c\xca\xcd\x95\xa7\x61\x1b\xf8\x4a\x1d\xb4\x85\xc4\x84\xdc\xbb\x93\xb7\x08\x88\xef\xb5\xd4\x1b\x6c\x0c\xb7\x4f\x1a\x5b\x94\x47\x2c\x7c\x5e\x7e\x2e\xef\x3d\xcc\x46\x12\xda\xe3\x13\x5e\xbc\xac\x8f\xa6\x15\x0a\x8a\x1f\x69\x51\x80\x07\x2d\x3b\x98\x94\x6f\x06\x94\xcc\x5b\xc5\x68\xb5\x62\x94\x44\x43\x8c\x63\x08\x99\x17\x1b\xa0\x13\xe9\x61\x80\x18\x5e\x2a\xe0\xf0\xd6\x0c\x6d\x3e\x48\xb6\xb8\xff\x14\x16\x48\x9e\xdc\xc9\x32\xce\x0a\x79\xf6\x1d\x7f\x6c\x43\x74\xa5\x28\x02\x35\xe2\xdf\x57\xac\x52\xa2\x5d\xb2\x6e\x72\x47\x04\x5c\x04\x53\xca\xe1\x11\x23\xc7\x27\x11\xdc\xa9\xce\x51\x10\x6f\xc7\x94\xfd\x2b\x2c\x17\x75\xb6\x94\x17\xeb\xad\x17\xb8\x1e\xc7\xa0\x7d\x34\xdb\x13\x2f\x02\x91\x9e\x00\xc9\x54\x75\xa5\x5d\x05\x93\x42\x3a\x93\x8c\xf5\x3e\x7c\x84\x39\x4e\x99\x5a\x8e\x24\x5f\xa6\x7a\x83\xb0\xec\x09\x81\x6f\xda\x7a\x1d\x8e\x25\x26\x28\x04\x8d\x8d\x08\xb2\x13\xe0\xeb\x02\xa0\x0a\x1a\xee\xd7\xdb\x05\xa7\x43\xfa\xe0\x94\x30\xe7\xef\x3e\x88\x0f\x2e\x37\xce\x4c\x47\xb0\x44\x00\x22\x01\x36\x00\x08\xa2\x90\x58\xf2\xc4\x1c\xb7\xb2\xd7\x2d\x03\x73\x17\x7e\xa1\xdb\xa5\xe2\x89\xd7\x2b\xe2\x9a\xf4\x2d\x8b\xb8\x5d\x32\x1a\x39\xc8\xe8\x93\xbb\x12\xef\xa9\x0f\x4f\x4b\x26\xaf\xb5\x56\x10\xe5\x2d\xf7\x97\xa2\x3f\x10\xf5\x81\x04\x88\x18\x2f\x74\x96\x2e\x26\x82\x69\x0f\x83\x52\x32\x1e\x83\x31\x74\x28\x9e\x59\x7d\x66\x54\x1e\x2f\x74\x90\x96\xd1\xfc\x09\xe5\x0b\x43\x82\x5e\x15\xe9\x3c\x11\xbc\x9c\xa1\x8e\xa2\xe1\x48\x26\x84\xa8\xb8\x60\x44\x94\x07\x32\x3f\xd3\xd2\xe3\x6c\xb4\xb2\x27\x8c\x66\x05\xb6\x57\xb5\x00\x98\x2d\x79\x01\x40\x51\x21\xcf\xd6\x94\x18\x33\x00\x11\x94\x53\x58\x00\x8e\x88\xdf\xf8\x8e\x10\x44\x33\x02\xd3\xd0\x5c\xd2\x03\x7e\x44\x8d\xef\x75\x4c\x4a\xc6\xe8\xc0\x52\xcc\x01\x70\x12\x71\x14\xce\x0e\xaa\xc1\x17\x68\x7d\x82\x14\x51\x5a\xb1\x59\xfc\x04\x3c\x31\xbf\xe5\x32\x0e\x48\xfb\xb2\x18\x4e\x21\x2c\xf5\x7e\x57\xd4\xc4\x50\xff\xf1\x0d\x9f\xeb\x81\xf5\x61\xa1\x3f\xb5\x05\x32\x76\x92\x40\x69\x22\x7b\xc1\x04\x37\xb1\x12\xd6\x52\x73\xb8\x0e\x1e\x64\x4c\x29\x7d\xdc\x9e\x09\xec\x31\xfe\x6a\x5f\x9f\x81\xb2\x5f\x13\x7e\xa2\xc9\x01\x6a\x00\x0a\x29\x41\xd0\xec\xd0\x0d\x80\x78\x9e\x0b\x23\x98\xc4\x5b\xa1\x7c\xc8\x3a\x0b\x99\x7f\x5f\xcc\x10\x54\x3f\x4e\x7e\xee\x2c\xab\x2a\x3f\x1f\xc4\xcd\x58\xf5\x88\x0e\xb3\xcb\x51\x13\x55\x8e\xa4\x4f\xe8\xba\x5a\x18\x44\x22\xc3\x58\x89\xa2\xec\x0b\xb1\xde\x0b\xcb\xf0\x87\xfc\x75\x3e\x00\xd6\x26\xc4\x66\x0e\xe5\x46\x43\xee\xf2\xea\x98\xde\x4c\xae\x61\x79\x70\xee\x05\x8a\x6f\x66\xf8\xbd\x25\xa6\xf2\x3e\xb4\x09\x68\x2d\x42\xeb\x86\x2b\x81\x77\x34\x52\xfe\xa8\x40\xd9\xff\x5c\x16\x1a\xff\xb1\xf3\xda\x4b\x59\x49\x60\x6d\x8d\xbe\x80\xa4\x55\x46\x02\x51\x60\xea\x75\xd8\x86\xd9\xb7\xe2\xbd\x05\x81\x85\x75\xad\xc5\x35\x1e\xb3\x9e\x28\x74\x9c\xa8\xa4\x35\x01\x2a\x22\x71\x5b\xa9\xf2\x86\x61\xd2\x74\xb0\xf4\x90\x54\x0c\x1f\xde\xee\x53\x17\xf6\x61\x4f\xd8\x60\xce\x40\xdd\x68\x60\xd5\x1c\xda\x39\x76\x4b\x11\x8b\xe6\x3a\x7a\x88\x67\x47\x5f\x0e\xc3\x16\xba\x23\x10\xbc\x06\xb2\x53\x70\x14\xb1\x2b\xb4\x0a\xa6\x22\xd1\xd9\xf2\x79\x09\xfa\xdf\xb7\xe0\xc2\xb0\x32\xbf\xcc\x47\x55\x1c\x48\xaf\x80\x55\x71\x36\x90\xe1\x43\xb2\x5f\x01\xae\xee\xe8\xb5\xfc\x12\x82\xb4\x67\x85\x2b\x0a\xcb\x69\xd8\xe2\x4c\x2a\xf6\xb8\x2b\x52\xcb\xe7\x29\x4f\x1a\x37\x5c\xe4\xd9\x37\x90\xf8\x0f\x69\x2d\xd1\xa4\x1f\xf3\x43\xf1\x32\x51\x67\x43\x70\x74\xf6\xc9\x2f\xb1\xed\x3f\x3c\x82\x4c\x1c\x85\xa1\x08\xf2\xeb\x3a\xb2\xff\x91\x5a\x56\xaa\x2b\x41\xc4\x26\x6b\xf1\x05\xfb\x0a\x3c\xbc\xb0\x2b\xc4\x2f\x87\xe4\x3d\xb2\xaf\x62\xd3\x8c\x21\x60\xf5\x21\xbd\xcb\x2b\xc3\xe8\xc7\x45\x32\xd1\x7f\x0d\x32\x63\x35\x73\x2e\x18\xa8\x6b\x05\xe7\x47\x26\xb7\xfa\x59\x0f\x61\x28\x09\xf0\x00\x46\x5d\xf2\xe6\x74\x41\x21\xe1\x65\xd1\x0a\x31\xb0\x2e\xf9\x48\x5f\xb5\x3f\x50\x3e\xf3\x83\x3d\x87\x8f\x55\x4a\xf8\x36\x78\x19\xf3\x66\xd1\x0d\x94\x16\x71\xed\xc8\x0c\x0c\x04\x7c\xe1\x8b\x2e\x50\x2c\xb5\xe0\x66\x27\x14\x6b\x77\x1b\x0c\xeb\xd0\xb8\xa8\x46\xd3\x33\x15\x19\xd5\x19\x14\x71\x59\x24\x0f\x09\xb6\x33\x58\x4d\x4c\xe4\x9a\xa2\x2c\x28\xbf\xf1\x54\x0b\x7d\x20\x41\x14\x93\x28\xe5\x31\x1b\xb8\x4e\xc6\xac\x00\x9a\x3f\xfd\x97\x8d\xd3\x9f\xaa\xc5\xc0\x08\x09\x69\x2e\xd4\xd3\x64\xde\x27\x1f\x8b\xa2\x97\x34\x24\x01\x8c\x50\x8e\x7e\x32\x8c\xea\xf6\x9f\x9b\x69\xd8\xfa\x22\x80\x5d\xaa\x7a\xb5\x46\xdb\xc6\x0e\xb6\x27\x9b\x43\x90\x54\xf2\xfb\x60\x42\x0c\xf0\x44\x9b\xaa\x0e\xaa\x61\xaf\x96\x80\x6b\xc6\xc2\x22\x3b\x10\x74\xda\x7f\xac\xfe\x0d\x45\x62\x53\x2a\x49\x7f\xe0\xe9\xf4\x67\x15\x24\xff\xb9\xdc\x66\xa5\xab\x38\x59\xac\xa7\x26\x08\x79\xb8\xc0\x2a\xa9\xfc\x7e\x08\x5c\x41\x00\xee\x41\xcd\x37\x01\x10\x71\xd8\xa7\x46\x21\x2a\xb9\x42\xc9\xa7\x2e\x32\x1b\xb2\x04\x30\x02\x8c\xb1\x11\x55\xcf\x17\x73\xb0\xe2\xe0\xda\xad\x71\x9a\x8e\x35\xc3\x09\xf0\x62\xcf\x0c\x4c\x52\xcb\x2a\x8d\x66\x16\xa4\x74\x4c\xe9\x8e\xe6\x10\xfc\x0c\x70\xd0\xe9\xb4\x75\x18\x9b\xea\x81\x88\x3b\x5a\x53\x4b\xc0\x05\x04\x2e\xcf\xbf\x72\x06\x43\xe4\xc1\x03\x20\x71\xa1\xc8\x93\x85\x1a\xac\xc1\xb4\xcd\x5d\x12\xe7\xe8\x7a\x69\x63\xbd\x9e\x90\x44\xbe\xa4\x9b\x95\xce\xa1\x06\xc0\x7a\x55\x0c\x23\xce\x8c\x22\x78\x30\x40\x4e\xec\x88\xb0\x83\x58\x17\x01\x65\xd1\xcd\x07\x57\x9e\x47\xe5\x5a\x7b\x15\x8b\xe3\x78\x72\x29\x10\x30\x43\xa9\x80\x0f\x5a\x65\x45\xbe\x52\x2a\x2d\xe4\x03\x8a\x36\xff\xa2\xf1\x95\x45\xdb\xd9\xd6\x1b\xf0\x86\x80\xac\x7f\x0a\xd9\x57\x43\xac\x57\x1d\x39\x1a\x1b\x2e\x60\x58\xda\x37\xdd\xd1\xa4\x92\xb7\xe0\x64\x8e\x3f\x08\x00\xf6\x5d\xc8\x94\xa2\x60\xd7\x58\x46\x8c\x93\x48\x4b\xc9\x27\x40\x98\x3b\xe6\x55\xb2\x90\xc6\xc2\x3a\x2c\x81\x18\xc3\x27\x38\x44\x3f\xde\xf1\x28\x3f\x07\xa2\x0d\x8a\x3d\x16\x45\x18\x47\x82\x10\xaf\x5b\x81\x3c\x33\x9f\xf5\x60\x57\x9a\xe2\x25\x98\x53\x1f\x6f\xcd\x1d\xce\xed\x5c\x0b\x32\x20\x26\x46\x27\xb2\x43\x1b\x59\x8c\x03\x22\xbc\x7e\x64\xc5\x1c\x16\x67\xf0\xe4\x43\xa3\x16\x42\x6b\xb3\xe5\xe0\xa3\x90\x7c\xce\x3c\xc1\xe2\xb3\x6f\x36\xeb\x9f\x1f\xbd\xd7\x5a\x86\xac\x99\x74\x1e\x0e\x89\x46\x80\x18\xf2\xbe\xd4\x26\x0a\xd5\x7b\x51\x59\xd7\x29\x7b\x52\xb4\x38\x49\x18\xc5\xf6\xc5\x72\x07\x5f\x58\xa1\x96\x08\x22\xdb\xc0\xf2\xd9\x38\x6c\xed\xc7\x0c\x2d\x8e\x38\xb8\x24\x7d\xf3\x72\x7f\x11\x6d\xa6\x71\x73\xe9\x4a\x05\xbf\x8a\xe1\x23\x8f\x5e\x45\x9d\x60\x59\x81\x59\xb3\xf4\x8b\xed\x03\xd7\xaa\x3b\x12\x15\x42\x2d\x67\x9c\x59\x20\xdf\x2c\x48\x50\x0b\x89\x97\xc2\x41\xa4\x11\x72\x1b\x53\x70\x72\x61\x3d\x58\x0c\x0d\x85\x88\x15\x55\xfa\x87\xbf\x0f\xca\x97\x4c\x70\x60\xea\x22\xe1\x0a\x80\x2e\x6c\x6f\x4b\x20\x32\x62\xba\x45\x53\x78\x8c\x45\xe8\xfc\x39\x11\x78\x26\xa3\xb1\x51\x32\x78\xd8\x7e\x22\x14\x60\xdc\x21\x80\xa9\x44\x84\x57\x6b\x38\xb9\x0e\x3a\xdd\xc0\xe2\x37\x0b\xa9\x08\xe3\x91\x78\x86\x99\x72\x38\x7b\x0d\xf9\x8a\x08\x74\xb1\xc5\xc3\x0b\x08\x25\xe2\xc0\xac\xa3\xce\xb8\xfe\xb1\xf3\x00\xca\xf9\x73\x3d\x9f\xde\xbc\x22\xb4\xde\x7f\xe1\xba\x58\x49\xc6\xdc\x7f\x48\xf2\x88\x4b\xd6\xab\x8a\x1f\xe0\xa4\xb9\xaa\xfc\x08\xe2\xe0\x9c\xc5\x72\xae\xdd\xb1\x39\x5c\xf8\xda\xdc\x1a\x29\x64\x50\x8b\x25\xab\xe4\xf9\x62\x45\x0f\x2f\x2f\x5c\x51\xb5\xcc\xf0\xbe\xb4\xa3\x2d\x4a\x3b\x43\x38\x9a\x13\x8c\x86\x68\x5f\x90\xbc\x53\x0b\x77\xf4\xa4\xef\x7c\x1c\x18\xd4\x2c\x8c\xcb\x3e\x31\xa0\x2c\x8c\x70\x08\xd2\xa1\xac\x2c\x8c\xc8\xb7\xcb\x7d\xe2\xbc\x3c\x8a\x68\x9b\x7b\xb8\x1d\x86\x10\x1b\xbe\xf1\x67\xa7\x57\x40\xcb\x03\xe6\xe1\xd3\x4b\xd5\xf0\xd2\xd4\x02\x58\xaa\x37\x55\x22\xc3\x97\x1b\x41\x4d\xe1\x5b\xa2\x3e\x04\x9d\x76\xa4\x29\x24\x72\x3b\xe3\x2d\x27\x5d\x42\xe6\x34\x82\x6a\x08\x4d\xb9\x9d\xb1\x48\x11\x6f\x81\x15\x77\x3c\xae\x6a\xb4\x02\x36\x2f\xb8\x94\xb2\xae\x55\x0e\xb0\x70\x4d\x94\x0d\x10\x1a\xcd\x10\x4b\x35\x37\xe6\xa8\xd1\x37\x0a\xe7\x06\x89\x74\xdb\x08\x5d\x96\x5c\x79\xa4\xcb\x10\x42\xd3\x58\x1c\x78\x88\xa7\x91\xdb\x48\xb2\x17\xe0\x0b\xdc\xe8\x51\x76\x33\xad\x1a\x71\xe3\xd9\x36\xff\x10\x2c\x30\x3a\xd7\x97\x33\x97\xfe\xfa\x8d\x66\xf1\x1f\xa5\x50\x41\xdf\x2c\x45\xe7\x39\x44\x91\x1a\xd3\x4a\x8f\x11\x56\x6d\x19\xbe\x79\x7c\xce\x11\x3c\xd2\x03\x93\x0c\x04\xb5\x46\x44\x63\x33\x79\x8f\x47\x0b\xf4\xba\xd1\x46\xb3\x34\x40\x44\x97\x44\xf2\x61\x69\xb4\xc2\x79\xe6\xda\x78\xa2\x73\x68\x21\x64\xc5\x28\x81\xb7\xd9\x8a\x84\xf3\xd9\x64\x4a\xf9\xfd\x71\xef\x54\x60\xb3\x21\x67\x61\xd1\x94\x51\xda\xf4\x82\x6c\x59\x65\x51\x67\xb5\x33\x0a\x2f\x9f\x2a\x50\x56\x39\xad\x8d\x68\xca\x14\xda\x7c\x83\xb7\x6f\x02\x48\xb2\xc1\x77\x2e\x9e\xeb\x52\x62\x4e\x66\x65\x25\x77\xb5\x57\xa2\xe0\xd8\x5a\x65\x03\xde\xf3\xc7\xb9\xb9\x4e\xd9\xf8\x3b\x90\x7c\xf9\xf0\x08\x05\xc3\x31\x3f\x01\x18\xfd\xb6\x7b\xd5\xcc\x18\x94\xf3\xff\x60\x59\x68\x9e\xc1\x87\xd6\x09\xb2\xe5\x0f\x82\xc6\xbb\x88\x50\x7b\x36\xc7\x35\x3d\xc6\x32\x33\x5c\x52\x3d\x38\x39\x3e\xaf\x38\xb1\xe4\x8e\x82\xe6\xe3\x60\x74\x4c\x12\x06\x60\x08\xd7\xbc\x3b\x5a\xa0\xaa\xf1\xa1\x45\x6a\x56\xba\xc0\x07\x65\xb1\xdf\xad\x19\x21\xb6\x78\x51\xf4\x7b\xa5\x91\x00\x2c\x00\x08\x28\xd0\xed\x39\xf6\x20\x93\x0c\x21\x7a\xf3\x93\xba\xf6\xa4\x16\x9b\x32\xb6\xcc\x31\x0c\x7a\xc1\x00\x00\xd2\x89\x73\x14\xe7\x66\x4f\xbb\x52\x9c\x52\xa9\x39\x36\x50\x12\x23\xb7\x20\x87\x24\x4b\x47\x0c\xff\x78\xa9\x6e\x3e\x4c\x9c\xb5\xd6\x8a\x98\xc2\x8f\x04\x72\x7b\xd2\xb5\xb4\x02\x3d\x72\xc4\x04\xe5\x77\x3d\x54\x87\x05\xad\x71\x98\x88\x97\x0c\xcf\x8b\xe4\x65\xe2\xd3\x35\x88\x27\x7c\xf2\xd0\xc3\xd4\x10\xb6\x9c\xa2\x59\x41\xa2\x08\x08\xaa\x0c\x90\x40\xa1\x3f\x62\x18\x25\x93\x25\x36\xc7\x00\xbc\x89\xe0\x18\x2d\xd9\x90\x82\xa5\x25\x31\xc4\xf6\x38\x14\x9c\xad\xd2\x88\x25\xe6\xa0\xc2\x37\x30\x59\xde\xc1\xb6\x57\x00\xfc\x25\x84\x93\x05\x43\x21\x2c\xc6\xdd\x28\x7b\xef\x87\x6d\x6a\x91\xae\xa3\xc3\xa3\xec\xd8\x8e\x33\x69\x7c\x00\x9c\xd4\xd7\xa0\x4a\x79\x0a\x51\x67\x6d\xc3\xea\x91\x54\x36\x86\xac\x38\xdc\x63\x43\x54\xbe\x0a\x1e\x9e\xd6\x15\x36\x9b\x85\x96\x1a\x34\xd1\xe9\x51\x90\x09\x47\x21\x65\x9f\x2e\x52\x79\xc9\x45\x0a\x38\xdd\x8b\x65\x78\x12\x8e\x81\x82\x39\xaa\x01\x3e\x60\x72\x17\xe8\x67\xe3\x42\x8a\x8d\x20\xa9\x85\xf7\x12\x79\x49\xf7\x44\xc8\x93\x7d\x20\x78\x4e\xc3\x28\x54\x90\x33\xe9\x10\x5e\xa0\xa7\x16\x51\x83\x18\x70\xf0\x9b\xf6\x95\xce\x94\x0c\x57\xbb\xab\x82\x58\xae\xc3\xf6\x59\x8e\xc6\x04\x2c\x71\xb0\x96\x49\x01\x12\x05\x13\xb9\x43\xb6\x0f\xe7\x61\x24\xec\xaf\xab\x9a\x85\x97\x43\xc9\xe9\x71\x43\x04\x24\x58\x5b\x2e\x8f\x79\x7c\xd7\xdd\x1e\x7e\xac\x06\x16\xb4\x47\x35\xab\x21\xfe\x61\x91\x3d\x52\xde\x52\x7a\x32\xb5\x66\xdb\x17\xc0\xd1\x0c\x9f\xe7\xb1\x2f\x35\x78\xda\x15\x21\xde\x4d\x88\x75\x3f\x39\xa7\x67\x11\x47\xcc\xc5\xd8\x5c\xb8\x09\x7d\x3d\x05\xf9\x2c\xa6\x71\xc9\x2b\x32\x8b\x23\x03\xa3\x19\x96\x6e\x66\xda\x11\x72\x98\x84\xdc\xe7\xd9\x29\xf1\x1c\x6e\x6e\xbb\x0b\x46\x9d\x6e\x59\x15\xcb\x73\x45\x66\x39\x17\x85\xc1\x49\xa1\x4c\xe1\x82\x28\xd3\x64\xc0\x62\xfb\x82\x24\x44\x6a\xaa\x1d\x2b\xe5\x95\x04\xac\x1d\x34\x5a\x73\x4e\x81\x5c\xa1\x56\x5f\xd4\xea\x8a\x74\x88\x69\xf6\x34\xee\xc2\x30\xbe\xe1\x2c\x0d\xb3\x81\x46\x06\xda\x68\x0b\x45\x44\x10\x25\xd0\x68\xd4\xd3\xa8\x6b\x4a\x0d\x20\x70\xdb\xbd\x9e\x16\x18\x87\x4b\x61\x3e\x11\x6d\xa4\x74\xa5\xbc\x4c\x22\xe2\x34\x32\xcd\x08\x18\xc0\xb7\xf1\x2c\x6b\xb2\x7f\xad\xfe\xd6\x30\xec\x95\x8d\xbc\x5a\xa5\x1d\xb6\x28\x9d\xd0\x33\x38\x19\x3b\x41\xb6\xbb\x0c\xbd\x21\x6c\xdd\x1f\xc6\xb6\x9f\x1a\xdb\xa0\xb7\x6a\x37\xb7\x2f\xc4\x4a\xdf\x8d\xad\x82\x84\xd1\x9e\x20\x8d\x7f\x75\x0a\x64\x19\xe8\x69\xc3\x16\xba\xe8\x06\xc5\xad\x61\x80\x1e\xf5\xad\xc7\x8b\x3f\xd4\xe0\x01\x00\x00\xff\xff\x55\x1f\x0f\x9e\xff\x51\x00\x00") func fontsRobotoBoldWebfontEotBytes() ([]byte, error) { return bindataRead( _fontsRobotoBoldWebfontEot, "fonts/roboto-bold-webfont.eot", ) } func fontsRobotoBoldWebfontEot() (*asset, error) { bytes, err := fontsRobotoBoldWebfontEotBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "fonts/roboto-bold-webfont.eot", size: 20991, mode: os.FileMode(509), modTime: time.Unix(1492020681, 0)} a := &asset{bytes: bytes, info: info} return a, nil } var _fontsRobotoBoldWebfontSvg = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\xbd\x69\x9b\x1d\xc7\xb1\x26\xf6\x79\xf4\x2b\x72\x20\x5b\xde\x3a\xc1\x8c\x88\x5c\x47\xa2\xae\x79\x25\x8e\x3c\x12\x7b\x28\xdd\x4b\x91\xa2\xc6\x63\x1b\x4b\x83\x07\x56\x11\x60\x01\xc5\x12\xd5\x5e\x7e\xbb\x9f\x78\x23\xeb\xf4\x52\x5d\xa7\x4f\x37\x9a\x14\x78\xad\x2f\x40\xf5\xa9\xac\xac\xac\xcc\xc8\x88\x37\xd6\xfc\xc5\x3f\x7d\xf7\xf5\xe0\xe6\xb3\x37\x6f\x5f\xbe\x7e\xf5\xe1\x23\x7a\x1c\x1e\xb9\xb7\xd3\x93\x57\xcf\x9f\x0c\xaf\x5f\x9d\x7d\xf8\xe8\xd5\xeb\x47\xff\xf4\xcb\x9f\xfc\xe2\xdf\xff\xfa\xd3\x5f\x7d\xf6\xe5\xef\x3f\x76\x6f\xe7\xaf\xdc\xef\xff\xf8\xcf\x9f\xfc\xa7\x5f\xb9\x47\xfe\x83\x0f\xbe\x90\x5f\x7d\xf0\xc1\xaf\x3f\xfb\xb5\xfb\xd7\xcf\x7f\xe3\xe8\x31\x7d\xf0\xc1\xc7\xff\xf9\x91\x7b\xb4\x9b\xa6\x6f\xfe\xc3\x07\x1f\xfc\xf5\xaf\x7f\x7d\xfc\x57\x79\xfc\xfa\xcd\x57\x1f\xfc\xe6\xcd\x93\x6f\x76\x2f\x9f\xbd\xfd\xe0\x5f\x3f\xff\xcd\x07\xda\xf0\xd7\x9f\xfd\xfa\x83\xb7\xf3\x57\x44\x8f\x9f\x4f\xcf\x1f\xb9\x5f\xfe\xe4\x17\xda\xf5\x77\x5f\x0f\xaf\xde\x7e\x78\xc3\xf3\x1c\x42\xd0\xf6\x8f\x7e\xf9\x93\x5f\x7c\x7d\x36\x3d\x79\xfe\x64\x7a\xf2\xcb\x5f\x7c\xb0\xbf\xfc\xc9\x2f\x9e\x9f\xbd\x78\xfb\xcb\x9f\xfc\xe2\xc5\xeb\x57\x93\x7b\xf9\xfc\xc3\x47\x6f\x5e\x3f\x7d\x3d\xbd\x7e\xfa\x7a\x78\xfe\xc8\xed\x5e\xbf\x79\x79\xee\x9f\x3c\x9f\xfd\x77\x1f\x3e\x22\x4a\x19\x2f\xd4\xa6\xfe\xc5\x93\x67\x67\xee\xdb\x57\x2f\xa7\xb7\xfe\x9b\xb3\x37\xfe\xec\xeb\x0f\x1f\x71\x88\xf5\x91\x7b\xf2\xf6\xd9\xd9\xab\xe9\xc3\x47\x94\xa5\x3e\x72\xcf\xcf\xfa\x9f\x3e\x52\x78\xe4\x3e\xd0\x61\xbc\x7c\xfb\xf6\xe5\xab\xaf\xfc\x57\xc3\xdf\xbe\xd9\x5d\x7d\x45\x5a\xda\xd8\xbd\x6f\x5f\xbd\x7c\xf6\xfa\xf9\xd9\x87\x8f\x7e\xf6\xd3\xef\x5e\x3c\x0d\xf4\xf3\xeb\x23\xe2\xd8\x1e\xb9\xe7\x1f\x3e\x3a\xe5\xe0\x6a\x29\x33\x87\xb4\xa3\x4c\x73\x89\x63\x70\x1c\xa2\x23\x8e\x8f\x93\x13\x8a\x8f\xd3\x24\x29\x3c\x4e\x8e\x28\x3c\x4e\x63\xa9\x2e\x38\x4a\xd1\x79\x4a\x8f\xd3\x44\x25\x3b\x1f\xe3\xe3\x34\xf8\xc8\xce\xb3\x84\xd1\x17\x71\xcc\xce\x93\xb0\xf6\x10\x27\x4f\x92\xf5\x79\x1e\x3d\x05\x72\x41\x1f\xa5\xc7\xc9\xf9\x98\x27\x8f\xae\x3d\x49\x9a\x7d\x89\x3b\x26\x99\xbd\x8e\xc5\xe3\xaa\x96\xb2\xf3\xdc\x78\xc6\x05\x65\x3a\x3f\xad\xdc\x5c\x98\x29\x54\xde\xe9\x0d\x8f\x2b\x6d\x73\x7e\xf9\xfb\xaf\x7c\xac\xcd\xee\x91\x37\x2f\xcf\xdc\xf3\xeb\xd3\xb6\x35\xcb\xee\x91\x3b\x7a\x39\x42\x3b\xb6\xd7\x9f\xfd\xf4\xbb\x27\xe1\xd8\xc6\xff\xfe\x7a\xbb\x54\x6c\x81\x49\xa2\x0b\x33\xa7\x6c\xf3\xa5\x17\x98\x2e\xdc\x48\x81\xe7\x96\xa2\xdd\xd2\x8b\xd5\x4c\x5e\x1e\x0d\xf3\xf5\xd1\x64\x25\x6c\x7d\x4b\x0a\x8e\x82\xb4\x39\x71\xdc\xb1\x84\xd9\x73\x49\x83\xa7\xa0\x34\x11\xdb\xce\x13\xd7\xf3\x53\x29\xf9\xf6\x56\x37\xbe\xfc\xa7\x2b\xfa\xa5\x4e\xbf\xb1\xba\x48\x61\xa6\xdc\x76\x9c\xf2\x90\xc8\x71\x0b\x3b\xcf\xc2\x33\x15\xda\x71\xe6\xa1\x88\x8b\x94\x77\x54\x65\x50\xda\xf4\xf8\xa3\xf1\x50\xe2\xfa\x77\xe6\x30\x7b\x7d\xd0\x73\x0a\x83\x4f\xe4\xbc\xf6\xc7\x9c\x66\xaf\xef\xf0\x9c\xe2\xe0\x0b\x6b\xeb\xb0\xf3\x54\xe3\x50\xd8\xd9\x75\xe3\xc1\x17\xba\xe1\x0e\x73\x39\x3f\x8d\xb5\xba\x54\xda\x8e\x1a\xed\x47\x49\x5b\x93\xfd\xdf\xac\x38\x48\x49\xf6\xbd\x2d\xbb\x18\xdb\xc0\x2e\xed\xb8\xa6\x51\x37\x93\x44\x97\xb1\x9f\xa8\xf1\x44\x49\xf7\x9a\x4f\x75\x6c\xba\xd5\x48\xda\xe3\xe4\x62\x7d\x9c\x26\xfd\xc7\x91\xe8\x26\x0e\xae\xea\x38\xb1\x2b\x85\x27\x4f\x49\x5b\xb5\x34\x7a\x66\xc6\x3d\x61\xfd\x85\x6a\x78\x9c\x26\x4f\xa1\x3c\x4e\x8e\xab\x3d\x4a\xb9\xba\xfe\x4b\x51\x16\xc0\x15\x4d\x39\x3f\x4e\x33\x53\xda\x51\x6a\xb3\x67\x2a\x23\x78\x03\x67\xc7\x05\x43\xa2\x58\xa6\xa6\x63\xf0\x42\x71\xf0\xe2\xbc\x6e\x73\x7c\x03\x51\x75\xde\xc6\x57\x75\x38\xe0\x1c\x39\xba\xd1\xd7\x0c\x7e\xc1\x7a\xbf\xe9\x58\x22\x38\x0b\x61\x24\xbe\x54\xa7\xbc\x47\x1b\x64\x65\x46\x59\xf4\x8f\x96\x1e\xa7\x91\x99\x9c\xaf\xc5\x09\x17\x34\xa8\x79\xa2\x80\x71\x70\x29\x98\xb6\xa2\x3c\x2c\x14\xfd\xa1\x4e\x9e\x1b\x69\x37\x32\x7b\x6a\x75\xa7\x33\x32\x53\x2b\xa3\xa7\x5a\x1c\x35\xe7\x25\x34\x87\x71\x4d\x5e\x47\x2b\x22\x8f\xd3\xcd\x6b\xf7\xdf\x5e\x5f\xbb\x44\xd2\xd7\x2e\x39\x0a\xad\xcd\x18\x00\x71\x73\x55\xc7\xcb\x94\x26\xc6\x17\xd7\x3c\x52\xd2\x55\x63\x89\xce\x57\x9d\xdc\x2a\xce\xb3\x72\xda\xd9\xf7\x61\x73\x73\xde\x7e\x8d\x93\x92\xb9\x36\x1c\x3d\xa5\xa0\x13\xa5\x0f\xd6\x34\xf9\x1a\x1d\x53\x3c\x3f\xe5\xda\xf0\x4a\x7d\x32\x55\xa7\xad\x5b\x79\x9c\xa6\xc6\xce\x2b\x65\x8c\x49\xd9\x39\x16\x50\xff\x9c\x74\x62\x9d\xb6\xb0\x31\xa6\xaa\x94\xe0\x74\xd5\x26\xdf\xc8\x45\x90\x43\x03\xcb\xb6\x6b\x3c\xe0\xb5\x81\x0e\xf0\xfc\x54\xa8\x39\x90\x3e\x91\x23\x92\xea\x06\xd2\x15\xd3\x6d\xae\x3f\x79\xfd\xed\xfc\xb4\x34\x52\x72\x5a\x26\xa2\x3a\x1b\xef\xc4\x22\x36\x09\x01\x93\x80\xd5\xec\xd3\x80\x95\x53\x69\xb4\x9f\x08\x09\xcb\x44\xa4\x1b\x27\x42\x27\x54\x9f\xf5\x35\x62\x96\xe3\xe3\x74\x7e\xda\x2a\x08\x19\xf3\x51\x1c\x1a\xf5\x19\xd9\x7f\xd4\x98\x93\x0b\xae\x89\x93\x02\xea\x76\x14\xc2\x7e\x42\x8a\x4d\x48\xb9\x34\x21\xa3\xcf\x78\x65\xa3\xa5\x07\xb7\x9f\x97\xd2\xe7\x65\x93\xa3\xe6\x95\x64\x96\xd8\x59\x6a\x26\x27\x8d\xfb\xee\xc8\xc9\x71\x10\xa5\xf1\x56\x1d\x95\x8a\xd7\x56\xa7\xeb\x48\x41\xdf\x45\xb9\x4e\x1e\x33\x46\x09\x5b\xaa\x88\xa3\x50\x6d\xf3\x4d\x46\x07\xf2\x38\x8d\x94\x9a\xce\x6d\xaa\xcb\xba\x4d\xad\x61\x6e\xa5\xda\x9e\x6a\xd8\x6a\xba\x3f\xda\x04\xde\xe2\x29\xf2\xe0\x9b\x38\x9f\xf3\xc0\xba\xa7\x85\x79\x94\xec\x72\x70\x29\x2b\x47\x99\x38\x38\x8a\x75\xc7\x54\x6d\x65\x94\x6c\xa2\x53\x5e\xa9\xcc\x43\xaf\x42\x1e\x38\x54\x65\xf3\x71\xf0\x8c\xad\x2f\xac\x9c\xb4\xb8\xda\x74\x9f\x2b\xcf\xd2\x7d\x5a\x74\xc9\x6d\x9b\xe9\x2b\x75\xf7\x8e\x9e\x49\xc9\xd4\x4b\x2c\x8e\x80\x48\xb0\x0d\x58\x87\x7f\x7e\x2a\x49\x5c\x0c\xa0\x89\xda\x1c\x3a\x89\xe0\x06\x31\xea\x22\x2b\x91\x8b\x72\xc2\xa0\x63\xd5\xdf\x03\x63\xdd\x06\x2f\x21\x38\x89\x75\xf0\xba\xc1\x49\x46\xb0\xfb\x58\x9d\xcf\x98\x92\x26\x78\x93\xcd\x14\xe9\xab\xa2\x8a\x39\x0a\x20\x9f\x28\x8e\xb1\xc8\x55\x27\x31\x1b\x1b\x52\x4a\x19\x6a\x76\x29\x8f\x29\x3b\xc9\x4e\x39\xa4\x2b\x71\x22\xed\xb1\x8a\x92\x90\x7e\x88\x32\xa2\xda\xdc\x04\x5e\xe5\xa4\x8d\x1e\x44\xa7\x1d\x68\xcf\xd8\x59\xe8\xaf\x6e\x71\x99\xff\xee\x1a\xdd\x88\x84\x4b\x92\x38\xd4\x39\x25\xee\x32\x36\xb7\x45\xc6\x56\x39\x20\x63\xff\xfb\x6b\x3d\x16\xa2\x8e\x20\x38\xba\x54\xc2\xcc\x4a\x8c\xd2\xd8\x51\x62\x97\xb3\xee\x2d\x89\xd1\x49\x8a\x8f\xd3\x2e\x0f\x49\x30\xf3\xa3\xb2\x67\x23\x23\x66\xfd\x56\xca\x93\x2e\x8c\x4f\x29\xeb\x60\x74\xee\x44\x9a\xeb\x3f\x29\x71\x5a\xb3\xaa\x4b\x62\x9d\xc8\xce\x6b\x3f\xad\xcb\x22\x7b\x89\x8a\x29\x7d\x6f\xbe\x79\xf8\xff\xc3\x6a\xf8\x9d\xeb\xea\x68\x24\x94\x51\x49\xa6\x55\xc7\xd4\x9c\x50\x99\x5a\x70\x29\xd5\x19\x03\x12\xc9\xba\xc4\xce\xc6\x03\x72\x13\x5d\xb1\x21\x45\x47\x91\x77\x79\xa4\xa6\x1c\x39\x38\x49\x0c\x09\x96\xda\x44\xb6\x87\x72\xa6\xd9\x63\x6a\xbc\x28\x3b\xba\xf8\xd9\x56\xb1\xb7\xaf\x8f\xd3\xce\x6f\x0c\xfd\x7f\xbc\x36\xf4\x16\x6a\x07\xe7\xc5\x51\x48\x69\x48\xc5\x51\x29\x03\xb7\x02\x19\x35\x78\x1d\x60\x2c\x3b\xaa\xc5\x88\x57\x92\x0c\x2a\xc1\x88\xc3\x90\xb2\x8a\xbb\xa0\xe4\x9d\x75\x4b\x0c\xac\x44\xc5\x59\x91\x56\x52\x7e\x41\x61\x80\xf4\xe3\x86\x0b\xdd\x65\x95\xf4\xa6\x72\x0c\xdd\xa7\xcd\x71\xd9\x00\x26\xff\xd3\x0a\x98\x50\xc7\x99\x49\xa9\x5e\x81\x26\xef\x24\xf3\x2c\x2d\xee\xb8\xe4\xd9\xeb\x85\x64\xa5\xc3\xc4\x3b\x8f\xab\x48\x0a\x34\x4b\x9e\x71\x21\x79\xe3\x5d\x27\xd7\x21\x2d\xf7\x69\xc9\xa2\x2b\xca\x43\x09\x4e\x38\xce\xcc\x75\xc7\x35\xce\x9e\x45\xa7\x23\xe9\x7c\x50\x52\x74\xb5\xb1\x77\xfc\xb5\x8e\x6b\x58\x28\x9d\xc4\x25\x52\x4a\x4f\xbb\x94\xb5\x47\x4e\x3b\x9f\x72\xbc\xb9\x9f\xc7\xd7\x07\xd8\x3a\xeb\x56\xd6\x73\x13\xe6\xbe\xb1\x97\x0f\xae\x8f\x86\x3b\xd4\xf3\xa4\xcc\x97\xd3\x90\x24\x3a\x4a\x95\xf4\x2b\x75\x8b\x40\xf9\xaa\x8a\x51\xeb\xc6\xc8\xc2\x36\x7e\x4c\x2e\xe5\x32\x0b\x93\x2a\x7a\xb5\x1a\xa8\x71\x51\xd9\xff\x24\xc0\x81\xa4\x3a\xd9\xc8\xac\xd0\xcb\x7e\xf1\xf8\x69\x22\x93\xc8\x68\x3b\x7b\xeb\xc2\xab\x68\xe9\x88\xcd\xee\x4c\x46\xed\xba\x8f\x1b\x98\x37\x1b\xf3\xce\xe4\xc8\x30\x1c\x89\xd8\x0b\xcf\x4f\x45\x99\xa5\x34\x03\x64\xd9\x99\x5e\xc8\x29\x4f\x5d\x45\xac\x61\x6c\xd0\x38\x63\x73\x35\x4c\x0a\x9c\x53\x9e\xa5\xb4\x2e\xe2\x7c\x62\xc7\xc9\x18\x75\x0a\x0e\x10\xd5\xb7\x66\x4a\xa6\x4a\x84\x30\x19\x88\x4f\xd1\xcd\x5e\x4a\xbb\x79\xbe\x68\x73\xbe\xa8\x28\x90\x69\x75\x56\x11\x96\x14\xc3\xab\xd2\x19\xfb\x8a\xce\x04\xb4\xc8\x6d\x63\x67\xf3\x66\xbf\x50\x85\x42\x19\x7d\x72\xd4\x8a\xa2\x41\x15\x04\x3a\xc1\x93\x64\x06\x30\xcf\x58\x85\x84\x55\xc0\xc4\x13\x95\x89\xb8\x43\x68\x36\x51\xab\xe0\x0a\x73\xcf\x26\x36\x58\x4c\x9c\x37\x56\x76\xca\xba\x19\xb8\xca\x00\x91\x9b\x49\x89\x91\xe3\xce\xb7\x16\x67\x55\x44\x62\x21\x97\x42\x1a\x55\x3c\x10\x15\x47\x11\xc3\x51\x6d\x41\x6c\xb5\xc6\x00\x90\x11\xf7\x84\x31\x79\x02\xc6\x49\xc0\x20\x7b\x85\x1e\x03\xcc\x58\x7e\x63\x79\xa4\x52\xfc\x00\x89\xca\xf6\xd4\xa8\x94\x09\x03\xbb\xbc\x63\x88\x4c\x85\xb3\xd9\x80\x85\x52\xa1\x32\x31\x95\x39\xa3\xbd\xdc\x94\x97\x94\x27\x50\x1d\x25\x83\x4c\xc9\x64\xbf\xe2\x22\x8c\x19\x22\x5d\x47\xb9\xf3\x94\xe3\xcc\xd4\x76\x94\xe3\xa8\xe8\xc4\xec\x19\xda\xe3\xa4\xc2\x33\x99\x72\x51\xab\xf3\xfa\x67\x24\xfd\x62\x7d\x76\xf4\x95\xdd\x82\x6f\x62\x9d\x3c\x38\x2d\x2b\x25\xa8\x0a\xc9\x2e\x8f\x3e\x3b\x10\x8c\x28\xbe\xe5\x49\xa2\x0e\x85\x96\xbd\x94\xcd\xd6\x11\xea\x44\x86\x3c\x25\x54\x07\xcc\xa5\x73\x17\xc0\xb6\x6d\xb0\x30\x89\x00\xae\xa9\x1a\xa3\x6b\x51\x0d\x60\x08\x4f\xa6\xe4\xb0\x21\x1e\xf0\x76\x8a\xa9\xab\x55\xd8\x7d\x46\x0f\x00\x4a\xa3\xe7\x20\x06\x9d\x30\x39\xa1\x5c\x2c\xa0\x84\x4d\x15\x26\x6e\xae\x4d\x2a\x2e\x36\x1a\x72\x88\xae\xe5\xb4\xe3\x16\x67\xdf\x28\xee\x28\x27\x25\xad\xac\xb3\xab\xbc\x81\xb0\x3f\x68\xc6\x45\x6a\xf1\xfc\x54\xb8\xb9\x14\x79\x27\x92\x54\xff\x1f\x7c\x76\x3c\x78\x86\xde\x7d\xf3\x28\xd2\xf6\xa6\xa4\x85\x44\xd2\xc0\x55\xf9\x0a\x66\xb1\x18\xfa\xd3\x05\xec\xe8\xcf\xa8\x84\xb1\xc4\xfa\xcd\x3a\x35\x5d\x11\xae\x46\xdc\xc4\xd9\x98\x48\x80\x1e\x1c\x5d\xc9\xa3\xd2\x9b\x69\x9d\x36\xad\x93\xb7\x39\x57\xee\xcb\x90\xc5\x43\x8d\xae\x12\xed\x2a\x76\x94\xc4\x9d\x4f\x45\x06\x1f\x81\x6d\xf2\x18\x83\x93\xe0\x9a\xce\x95\x0e\x45\x75\x60\xb0\x54\x1d\xb6\x13\x4e\xa6\xb2\x96\x89\xc8\x16\x2e\x63\x33\xeb\x6d\xd3\x64\x75\xbd\xda\xe4\xa5\xa3\x4a\x51\x84\xcc\xb6\xd3\x14\x0c\x51\xe8\x6c\xb4\x3a\x51\xf0\x7f\xf3\xf4\xe5\x6d\x19\xd0\x5c\xca\x6d\xe6\x0a\x63\x5f\xcd\x4e\x09\x2e\xa6\x34\x45\x05\xf2\xb9\x8d\xd5\x66\xcc\x8c\x0a\x30\xf3\x19\x57\x51\x3a\x1b\x74\xb6\x54\x15\x1b\x7d\xce\x4e\xd7\x8f\xa8\xc0\xd0\x67\xba\x31\x18\x05\x81\x37\x08\x48\x8f\xc9\xb4\x72\x8c\xb9\x44\x53\xc1\xb5\x23\xe5\xde\x63\x6c\x2e\x29\x6e\x89\xca\xde\x29\x2b\xaa\x1f\xa9\x81\xe9\x05\x9b\x27\xdb\xf4\x14\x0c\x47\x89\x69\x29\xc0\x8c\x66\x57\xf4\x92\x65\xf2\x0b\x8b\x8c\x32\x7a\x16\x9b\x2a\xe5\xb1\x30\x87\xd8\x0e\x8e\xd0\xd9\x4f\x45\x81\x9e\xcd\xb8\x4a\x90\x6c\xdc\x33\xe7\x89\x72\x36\xd8\x3f\xb6\x00\x91\x03\x15\x52\x29\x46\xe9\xc8\x51\x5b\x28\x86\xa0\xab\x50\xcb\xda\x6f\x71\x25\x8d\xbe\xd2\x9e\x33\xb0\xe2\xdd\xea\x7c\xa1\xd9\xb7\x0d\xd5\xaf\x6c\xae\x4d\xd6\x17\x08\x01\x82\x50\xe0\x06\x0c\x32\x42\xb1\xf7\x5c\xa2\x92\x23\x96\x22\x91\xf2\x25\xc6\xe0\x53\xe1\xc1\xc0\x42\x84\x30\xe2\x81\x14\xb7\xd6\x51\xa2\x13\xd6\xed\x91\x5d\xaa\xd0\xef\x83\xd2\x24\xb8\x60\x89\x1b\x7a\x40\xdd\xa6\x1b\xd5\x48\xeb\xa2\x91\xea\x64\x71\xc0\xe2\x40\x3d\x27\x53\x86\xa1\x5e\x29\x4e\x4d\xcd\xac\x4d\x93\x6a\xda\xa4\xf2\x48\x9f\x6c\xd1\x11\x17\x27\xaa\x29\x4d\x22\xca\x93\x20\xe7\x42\xd1\x25\x37\xa5\x07\xda\x1b\xab\x12\x19\xcc\xe4\xe4\x29\xb4\xce\xcf\x55\x2d\x9c\x16\x90\x4d\x42\x23\x51\x86\xc2\x4a\x00\xdf\x31\x4c\xb9\x28\x5b\xac\xc6\x1d\x61\x2d\x52\xa5\x9d\x42\x47\x26\x5d\xab\x52\x5c\x62\x9c\x11\x5c\x19\xbf\xe9\x96\x02\x29\x6b\x63\xc5\x26\xd1\x45\x32\x0e\xad\x8a\x19\xd8\xbd\x0e\x62\x52\x34\x62\xaa\xa5\x19\xd9\x62\x71\xa9\x4e\xaa\x0c\x27\xe5\xca\xaa\xfb\xe8\x37\xa7\xa2\x04\x52\x5d\x6a\xa3\x6f\x26\x3a\x22\xbe\x21\xb5\xc9\x27\xa3\xee\x54\xce\x4f\x23\x01\xe7\x83\xa1\x37\x72\xc6\xcd\x41\x7e\x53\x67\x07\x20\xfb\xa2\xb0\xc6\xec\xf2\x40\x3c\x68\x87\x66\x5d\x5c\x99\x41\x2f\x92\x29\xc8\xa9\xb7\x1b\x55\x6f\x01\x67\xd1\x8e\xa0\x5a\x47\xf4\xcf\x5b\x9c\xa3\x6d\x52\x40\x65\xd7\x8a\xaa\xbf\xaa\x22\x81\xff\xe8\xf6\x99\x44\xb7\x30\x06\x62\x93\x2a\x99\x3b\x26\x50\xce\xa1\x02\x8c\x80\x18\x23\xf8\x34\x43\xbc\xd9\xf7\x47\x2a\x93\x97\x66\x06\xc2\xc4\xa3\x2f\x66\xf0\xc3\xb6\x05\xeb\x31\x18\x89\x49\x19\x24\x3a\x26\x1a\x33\x30\xa2\x5b\xf8\xb3\x29\xfb\x1d\x21\x29\xc3\x27\x65\x1f\x54\xcb\x62\x01\x82\x40\x64\x1d\xdf\x5c\x78\x84\x75\x03\x03\x24\xdb\xef\x71\xda\x4b\x50\xbe\x10\x98\xc6\xc8\x80\x6b\xa7\xde\x14\xb8\xf6\xfc\x54\x8a\xf4\x59\xf0\x50\x8d\x83\xc9\xe3\x70\x31\x8c\xa2\x24\x5d\xc0\x44\x61\xff\x9c\x6a\x71\x85\x67\x92\x08\xfb\x69\x70\x0a\x1d\x38\x8a\xa9\xb4\x55\x91\x45\x35\xf2\x30\x39\xc3\x0b\x79\x70\x08\x37\x2f\xd1\x7f\xb8\xae\x7a\x54\x3e\xac\x7a\xe0\x46\x2d\xf9\x58\xad\x64\xe5\x77\xc8\xcb\x0b\x94\xd1\x1c\xa9\x7d\x9d\x2a\xdb\xbd\xc3\x4b\x7f\xf6\xd3\xef\xe4\xd9\xca\x22\x16\x62\xd7\xe4\x53\x74\x51\xf2\xcc\x5c\x86\x9a\xd9\x49\xce\xb3\x67\xe5\x7d\xa9\x60\xcf\x97\xd9\xe7\xa1\x5f\x0b\x6e\xdd\xfc\x9a\x0f\x57\xf4\x5d\x17\x05\x50\xb2\x13\xe1\x99\xb9\xed\x6a\xd3\xee\xb9\xed\x7c\x6d\xf9\x1c\xb7\x4a\x96\x1b\x6e\x6d\x7e\xca\xd9\xfa\x53\x52\x5d\x66\xb1\x39\x15\xc1\x25\x0c\xa9\x2a\x3c\x68\x73\x1e\xbc\x5d\xe6\x99\x73\x1b\x6a\x61\xa5\x6d\xbc\x68\x43\x8a\xfc\xd3\xaa\x7b\xee\xdf\x21\xac\x1c\x8d\x46\x2f\xca\x79\xcd\x38\xef\xb8\xc5\x49\xc0\xe0\x28\xf0\xc8\x1c\xa1\x59\x98\x90\x37\xcb\x98\xd9\xca\x25\x74\x53\xa0\x32\xea\x45\x62\x0b\x4c\x61\xb6\x4f\xb5\xe3\xac\xb8\xb4\xc0\x26\xe2\x9b\x89\x7e\xe8\x81\x01\xa0\xbf\xd1\xa8\x1c\x21\x38\x65\x46\x8e\x43\x9a\x08\x2e\x0a\x4a\x75\x54\x95\xa3\x3a\xbc\xd1\x11\x2b\xe8\x30\xd5\x62\xd1\x34\xaa\x71\xb5\xc9\x24\xbf\x03\x53\xe8\x78\xcc\x58\x46\xdc\xab\x18\xba\x02\xaa\x60\x9c\x8a\xb2\x9d\x99\x53\x70\x06\x49\x39\x05\x1d\xc5\x86\xea\xf1\x3f\x5f\x9f\xb7\xba\x18\x31\x72\x76\xb1\xd4\x91\xaa\x8b\x5c\x1c\x63\x13\x66\x95\x6e\x53\xc6\xcb\x59\xf9\xd2\x28\x55\x85\x55\x82\x7d\x52\x47\x3f\x51\x0b\xce\x67\x65\x85\xa3\x57\x85\x8b\x6a\xf7\x59\x48\xc9\x2a\x74\x20\x38\xea\xe8\x8b\xed\x72\x49\x4e\x3f\x42\x81\x2b\xcb\xe8\x15\xa9\x56\x18\x72\x4d\xd7\x66\xf0\x05\x53\xb5\x69\xf4\x14\xc9\x60\x14\x58\x22\x2d\xa2\x43\x28\x8d\xac\x23\x52\x51\xaf\x8d\x63\x28\x13\x83\xe9\x51\x12\x88\x45\x65\x82\xe6\xf2\x50\x7d\x3a\x9a\x3e\x0d\xcf\x4b\xdc\x25\x73\x6e\xa5\x22\x6e\xf4\x05\x2a\x08\x10\x84\x84\x09\x46\xee\x0b\x36\x0a\xec\x13\xda\x54\xcc\xe5\x93\x47\xca\xaa\x90\x2e\xf0\x2b\x25\x9a\x7c\x2c\x58\xdd\x56\x47\x2f\xc6\x3f\x63\x8d\x80\x7e\x4a\x17\x8a\xb0\x8b\x7e\x09\x3a\x4e\xc0\x23\x3e\xe5\x30\xc5\xac\xb3\x15\xd2\x58\xf1\x2a\x18\x4b\x39\x4c\x26\x1b\x52\x18\x14\x4e\x51\x2c\xa3\x57\x99\x0e\xcf\x4f\x01\xb3\x85\xed\x51\xa5\xbb\x91\xa6\x4e\xbb\x34\x08\x8e\x0c\x9c\xc8\x8a\x9e\xa1\xc7\xba\x5c\xf9\xfc\xb4\xb0\x52\x62\x56\x70\x62\x54\x6d\x46\x5d\x80\x12\x37\xe1\x5f\xf4\x39\x26\x4c\x1a\x0c\xea\x9c\xa7\x0a\x6f\x48\x9e\x21\x60\x5c\x7e\x9c\x86\x18\x5d\x6c\x59\xe1\x98\xd3\x11\x65\xa7\x28\x2c\x56\x17\x47\x4f\x64\x10\x50\x3f\xa9\xc1\x8c\x08\xf7\x57\xdb\xc4\xe7\x1f\xad\x2c\xff\x17\x06\x57\x17\x86\x14\x74\x07\x81\x6f\xb6\x21\xb6\xe6\xf6\x56\x87\x34\xf8\xd6\x9c\x90\x6a\x1d\x44\xf8\xc3\xe3\x2f\x56\x96\x1b\x4b\x75\x29\xca\x4e\xb2\xb2\xe3\x1a\x5c\x2a\xbc\x69\x79\xfc\xe7\xf5\x18\xe2\x05\x27\x0c\x33\x5e\x19\x1b\x8f\xaa\xf6\x04\x17\x03\x01\x0a\x99\x76\xc5\xe6\x57\x52\x2d\xdc\x77\xf4\xdd\xf5\xd7\x8e\x6d\x54\x84\x8e\xb0\x06\x73\x55\xb8\x6c\xd4\x1d\xa6\x6c\xb2\x8d\xc4\x30\x5a\x5b\x5c\x06\x84\x69\x13\x78\xe2\x54\x53\xdd\xf9\x94\xe9\xfc\x34\x72\x75\xcc\x71\xc7\xb9\x2d\x64\x5d\x0a\xc4\xee\xb4\xd8\x94\x54\xac\x86\x02\x45\x0e\x4e\x40\xd5\xa1\xa3\xd3\xcd\x6a\x6a\xa8\x8f\x1c\xac\xa3\x1a\xf3\x8e\x29\x8c\x44\x05\xd4\x1d\x5c\xac\x53\x16\x30\x2b\xf4\x42\xce\xb4\x3d\x02\x0d\x55\x73\x9f\xee\x54\x12\xcf\x5e\xea\xc6\x5a\xfe\x6a\x35\x8f\xa1\xfb\xa7\x9b\xb8\x54\x65\xe6\xaa\x73\xa5\xc8\x47\xc5\x7f\x94\x34\x45\xca\x8e\x4a\x18\xb9\xe8\x1c\xba\x68\x21\x13\x6d\x54\xc0\x08\x16\x81\x0b\x51\x6d\x9a\x18\x3e\x13\x18\x1a\x80\x20\x74\xf6\x55\x55\xe2\x60\xe6\xea\xe4\x80\x38\x60\x79\xc7\x94\xd6\x05\x46\x7b\x48\xc3\x02\xf8\xa5\x5c\x19\x14\x5a\x60\x56\xe7\xa2\x13\xc5\x60\xdb\xc0\xe0\x0a\x94\x83\xb3\x5d\x85\x7b\x58\x27\xd6\xbd\xb2\xeb\x36\xa4\xac\x83\x19\xf5\x61\x15\x0d\x14\x05\x76\xbd\xd1\xf7\x41\x57\x38\xbf\x0d\x72\x8f\x9e\xb3\x71\x02\xdd\x6f\xb9\xd9\x92\x44\xd9\x98\xc1\x5f\xaf\xfd\x60\xbc\xa2\xc4\x14\xc2\xc8\x19\x94\x18\x43\xe7\x06\x13\xcc\x80\x51\xe0\x6a\xe3\x68\x36\xc9\x5c\x4d\xb9\xb3\xdf\x27\x6f\xcd\x73\x03\x4d\x85\x70\x41\x53\xd4\x64\x24\xd0\x36\xeb\x6e\x0e\x79\xaa\xcd\x71\x29\x33\x47\x01\x56\x6b\xf0\x2a\x71\xd1\x79\xb6\x16\x0a\x6d\x64\xd6\x6d\xb0\x21\x96\x3f\x5e\xc3\xe7\xbc\xfa\x94\xd6\x52\x37\x2f\x17\xc5\x2a\x92\xf3\x2e\x03\xb4\xe8\x4f\xb8\x8a\x94\x77\x25\xa4\xbd\xc5\x6e\xe3\x6d\xff\x71\x0d\x66\xd6\x13\x47\x21\x2c\xd6\xec\x42\x3c\xfb\x18\x68\x97\x29\x2c\xaf\xd3\xab\x8c\xa8\x9b\x2d\x64\xf6\x9b\xd5\xf2\xe4\x76\x61\x4c\x28\x79\x96\x00\x63\x42\x8e\x8e\xb2\x19\x94\x75\x6d\x22\x18\x2d\x14\xeb\x91\x73\x06\x0b\x29\x5d\x74\x9b\x91\xc6\x8c\x1d\x70\xc7\x75\x12\x87\x3a\xed\xa0\xd6\x95\xe8\xa0\x5b\x9a\x33\x30\x17\xa3\xf1\xd8\xc5\xa1\xd2\x2d\x6e\xaa\xf0\x64\x7d\xc7\xec\x25\x64\xa3\xf1\xec\x2a\x04\x5f\x83\x83\xa9\xf5\xb6\x8b\x31\x28\xab\x22\x31\xb5\xe8\x12\x2b\x06\xdb\x79\x4e\x75\xe6\xc0\xbb\x94\xc2\xec\x53\x34\x87\x9c\xaf\xd9\x2d\x52\x86\x92\x4c\x5e\x4c\x7d\xcb\x46\xdd\x05\xd4\x2d\x59\xbf\x0f\x16\x46\x17\x65\xc3\x94\xf5\xbf\x5c\x9f\xbe\x98\xc2\x6a\x91\x00\x90\x33\xe7\x5d\x6a\x71\xd6\xff\xc1\xb9\x16\xae\x4f\x33\x56\x48\xef\xdd\xb2\x56\xff\xe9\x7a\x90\xce\xde\xbd\x91\xe2\x95\x77\xed\xcd\xd8\x37\xf7\xf3\xdb\x15\x65\x2d\x6b\x9e\xc5\x45\x2a\xdd\x42\x0b\x9d\x4e\xc1\x02\x8c\x6f\xd9\xf4\xe3\x6a\xaa\xe6\x58\x2d\x08\x05\x92\x18\x96\x14\x80\x18\xf0\x23\x0a\xd4\xfa\x27\x06\x6a\x66\x00\x23\xd7\x55\x70\x2f\x66\x4f\xea\x33\x4e\x26\xe4\x2f\xbb\x12\x48\xd9\x0e\xbc\xf3\xc5\xc0\x96\x10\xcd\xb4\x21\xe7\x7e\xb7\x22\x5f\x96\x9b\xe7\x3f\xb5\xb4\x23\x2e\x03\x1c\x13\x2d\xed\x24\x95\xc1\x47\xe0\xbb\x52\x87\xa4\x94\x54\x4a\xdd\x29\xa8\x1b\x20\xaa\x72\xa8\x3b\x4f\x59\x97\x2e\xd4\x03\xb3\xf9\xc9\x6a\x36\x17\x2f\xdf\xf5\x21\x10\x0b\xef\x72\xac\xcb\xce\x8f\x1b\x3a\xe0\xe9\xf5\x1e\x4b\x2d\xab\x1e\xa5\xd2\x20\xc5\x24\xaa\xec\xf2\x20\xba\xa7\xf4\x52\xea\x15\x47\x46\x94\x38\x70\x75\x39\xca\xe0\xb3\x23\xfd\x36\xc8\x76\xfd\x56\x6a\xfa\xad\x15\x73\x0d\xc3\xad\x27\x6d\xeb\xb3\xb4\xd9\x47\x39\x14\x35\xf6\x9f\x8f\x24\x7c\xb8\x56\x7c\x6b\x71\xc8\x8e\xe6\xd6\xe4\x1a\xf1\xab\x6e\x54\x5d\x53\xec\xa3\xaf\x9f\xb5\xe9\x81\xd7\x7e\xba\x5a\xef\xb6\xb0\x2b\x76\xa9\x95\x99\x61\x00\xd4\x3d\x0c\x8a\x75\x11\x38\x3e\x5a\xa0\x62\x41\x00\x51\x21\xc8\x19\x42\x50\x02\xe4\x8c\x6e\x77\x6d\x37\x7b\xee\x16\x5b\xc8\x19\x8b\x16\x88\xaa\xce\xc7\x68\x26\x7e\xe5\x61\x9c\x9b\x31\x88\xa2\x3d\x2a\x83\xa8\x2e\x46\x39\x3f\x95\x2a\x3a\x86\xc5\x00\x89\x18\x96\xca\x13\x0b\x56\xa9\xed\xc3\x5f\x60\xe8\x9d\x6a\x74\x5c\x79\xe6\x0c\xc9\xaf\x63\xa8\x0a\xc3\xdb\xe4\x97\x16\xbe\x3f\x59\xf7\xbc\xb0\x34\x1b\xe4\x86\xfe\xf3\xfb\xd5\xec\xc8\x1a\xf5\xa5\x1a\x46\x46\x34\x92\x34\xec\xc0\x6a\xa8\x4f\x04\x56\x2d\x5c\xa9\x72\x63\x37\x8b\x62\x93\x3a\xfb\xc4\x7d\x0f\x40\xc2\x96\x24\x3b\xae\x75\x24\x06\xd7\xad\x09\x56\x43\xc0\xad\xbc\xa0\x36\xe5\xa7\xd0\x00\x4b\x0f\xb7\x30\x9d\xcb\x7c\x47\x75\xf6\xb1\x6c\xd8\x29\xff\xb0\x22\x2d\x91\xef\x61\x8d\xe1\x62\x8b\x50\xf5\x7a\xe4\x89\xaa\x3e\x2d\x3d\x4e\x03\xeb\x83\x2c\x79\xf0\x04\xcc\xaa\x2c\x81\x33\xab\x4e\x36\x7a\x84\xc8\xaa\xdc\x21\x5d\x11\x33\xd8\xc3\x68\x0d\x2b\xe9\x83\x13\x87\x7b\x30\xea\xf8\x97\x15\x75\xa4\x1b\xa8\x23\xb6\x91\xa3\x7e\x83\xd4\x76\xc9\x82\x60\xf4\x0f\x24\x6f\x62\x41\x9c\x4f\x3a\x0b\xb0\xb2\x15\xe9\x36\x5b\x65\xa3\x52\x9d\x2d\x36\x5c\x21\x16\xb6\x68\xe1\x97\xe6\xda\x52\x26\xdf\x55\x86\xb2\x48\x8e\x1e\x69\xc6\xb4\xf3\x12\x68\xf4\x31\x20\xa6\x4d\x61\x7f\x50\xb2\x64\x47\x91\x67\x0a\xc0\x6e\xb0\x19\xc3\x8a\x97\x6d\xfa\x41\x05\xd9\x2c\x14\x45\x89\x75\x09\x1d\x36\xcd\x20\x94\x1d\x27\x1e\x09\x26\x4c\xb3\x69\x27\x76\x93\xd9\x87\x13\xb6\x5f\xd0\x71\xd9\xdf\x0a\x68\x0b\x0c\x14\x88\x0a\x2d\xaa\x63\x6c\xcc\xe8\xbf\xae\xa2\x57\xf7\xdc\x48\xa9\x2f\x5d\x11\xa4\x12\x5c\xb1\x19\x6d\x01\xd8\x05\x06\x1a\x7d\xe9\x48\x04\x0b\x70\x65\x17\x1b\x36\x91\x28\xda\x55\x45\xdb\x3e\x53\xa0\x14\x57\x28\xad\x4a\x62\xc1\x15\x5d\x8c\x26\x8e\x4a\x35\xb7\xbb\xd2\x12\xc1\x7a\x02\x0f\xf1\x64\xab\x87\xc5\x1b\x39\x06\x47\xce\xd4\x2f\x2e\x23\xb4\x74\x9d\x0c\x5c\x88\x42\xd2\xcb\x8a\x88\xec\xb5\x25\x73\xb3\xf6\xdd\xdb\xba\xa4\x57\x85\x18\x00\x89\x54\xd7\x48\x3c\xf9\x0c\xf3\x82\xc0\x9c\x5e\x22\xb6\xb8\xf6\x4f\xfa\x91\xe6\xc8\x41\xf8\xd4\x88\x5d\x95\x8b\x13\x98\x89\x4b\x99\x88\x23\xc2\x0c\x30\x3d\xb5\xec\xad\xe8\xdc\x14\x20\x74\xf2\x0b\x55\xb5\xf2\xea\x10\x7f\x9b\xcc\xb0\x42\x85\x1d\x61\x0f\x16\x76\x22\x34\xd3\x86\xb8\xf8\x6c\x13\xe9\x28\xc0\xd8\xbb\x63\x88\x16\x10\x1d\xc9\xe4\x34\xf5\x28\x00\x5c\x45\xda\x10\xd4\x7f\x5c\x71\xaa\xb0\x08\x6a\x0e\x2e\xb6\x30\xb7\xac\x52\x50\x66\xdf\xb2\xe1\xd7\x18\x1d\x34\x37\x98\xc0\x59\x59\x48\xa1\x0b\x15\x4d\x15\x3e\x9a\x4a\x75\x4c\x79\xf5\x2c\xc3\xba\x9f\xd9\x79\xd1\x55\x8f\x6c\xf3\xae\x04\x41\xa6\x8f\xc1\x56\x23\xa2\x3b\x02\x8e\xe0\x2d\x0e\xfb\xf9\x5a\xab\xed\x1c\xb6\x98\x69\x42\x42\x1d\x84\xcc\x67\xd3\x06\xaa\xce\x97\xb6\xcb\x03\x15\x57\xca\x20\xf0\x6a\x14\x42\x2b\x1f\x21\x27\x20\xce\x65\xcb\xa8\xfd\xc5\xda\x2e\xd7\xfd\x0e\x1c\xbb\x2d\xa4\x5a\x7c\x92\xaa\x43\x83\xe1\x90\x22\xae\xb5\xba\x63\x4a\x03\x17\xf8\x19\xeb\xce\x82\x0d\xf1\x73\x4d\x83\xea\x17\x7b\xeb\x49\xa1\x01\xd0\xbd\x65\xda\xf9\x6c\xd7\x1e\x7f\x70\xd9\x00\xef\x7f\xda\x9c\x06\x55\xb7\x87\x18\xc5\x15\x89\x83\x8f\xc2\xae\x30\xef\x44\xea\xa0\xfc\xdd\x27\xca\x18\x5f\xa2\xbc\x93\x18\xac\x85\x2f\xcc\x43\x4c\xc5\xf9\xa2\xc8\x49\x92\x0c\x9e\x2b\xb9\xc4\xc9\x2e\x7c\x52\x0a\x93\x2d\xaf\xf8\x97\x6b\x66\xd2\xf5\xbd\xd4\x17\x85\xc3\x20\xba\x16\xb9\x90\x02\x3e\xaa\x4e\xaf\xf4\x67\xd5\x7d\x9d\x6f\x31\xce\x3e\x11\x9b\x56\x91\xb6\xac\xcb\x7f\x5e\xbd\x28\x74\x35\xb6\x14\x15\x03\x89\x87\xdc\xc0\x78\xdb\xce\xe7\xb6\xb8\x2c\x63\x51\xd8\x96\x07\x9f\x9b\xed\xcb\xbc\x2b\xfb\xb8\x13\x0a\x79\x43\xff\xff\x2f\xd7\xfd\x0d\x25\x5c\x58\xca\x15\x6a\xa8\x7a\x56\x76\x51\x74\x0b\x92\x2a\xe1\x51\xf1\x21\xe0\xba\x5e\xe1\xb7\x28\x1b\x1c\xf8\x7f\xbd\x1e\x63\x95\xfb\x0a\xf2\x42\x57\x6d\xc8\xb0\x9a\xf4\xb8\xaa\x8d\x38\xa1\xff\xba\x39\x4a\x81\x69\x6b\x07\xf1\xa3\x83\xf2\x7a\xa5\x83\xb2\x11\xeb\xd8\x75\x78\xfa\xd3\xcd\x5d\xff\x6f\xd7\x87\xb8\x04\x93\x29\x2b\xe0\x36\x70\x6b\xae\x70\xd9\x31\x31\xae\x7d\x01\xe8\x12\x1a\x10\x2f\x12\x49\x06\x5f\x9d\x92\x54\x1e\x7c\x51\xa5\x7a\x30\x2e\x10\x49\xd0\xee\xe6\xd7\xfe\xef\xd7\x63\x0f\xf7\x06\x40\x17\x76\x0d\x26\x02\x6a\x3b\xaf\x57\x4c\x1b\xb3\xf2\x7f\x5c\x57\x38\x4b\xdd\x13\x0a\xc5\xc2\x90\x6f\x12\xda\x40\xad\x40\x53\xd7\xf1\x6c\x50\xdd\x93\xb5\x9a\xb4\x04\xb6\x26\x27\x01\x98\x31\x35\x67\x9e\x6f\x46\xa0\xaf\xc0\x31\x5c\xcb\xe3\xb4\xa3\x2c\x73\x55\x2e\x58\x60\x8a\x72\xc4\xf0\x92\x93\x8b\x32\xfa\x62\x06\x5a\xb3\xb2\x77\xf5\xb2\x2e\x09\x03\xba\xf7\x58\xf5\x1e\x72\x79\x46\x3c\x09\x94\x4b\x6a\x8e\x59\x31\x01\xc2\xb5\x54\x88\xe8\xff\x08\x07\x0d\x0e\xac\x0f\x31\xd4\x88\x09\x40\x82\xc4\xec\x63\x04\x7c\x29\x19\x61\x10\xb0\x92\x4d\x5d\xbe\x89\x40\x5e\x8c\x9e\xb2\x93\x62\xd1\xcd\x0e\xa2\x19\x01\xc1\x71\x84\x67\xb6\x00\x35\x2e\x0e\x6e\x37\x19\x36\x55\xbe\xa0\x22\xcd\xc2\xdb\x33\xe3\x83\x27\xdf\xd8\x71\x0f\xa5\x8b\x19\x4e\x81\xe0\x14\x7b\x4a\x76\xbe\x96\xa9\x55\xdd\x3c\x63\x29\xa6\x86\x3b\xa9\x53\x25\x57\xeb\x4c\x49\x54\x6d\x95\xd1\x37\x31\xd7\x63\xcf\x08\x81\x3d\x5b\x51\xeb\x96\xdd\xfa\xe9\xb2\x2f\x19\x5c\x20\x07\x53\xd5\x52\x93\x31\x16\x97\x15\x4d\x00\xcf\x87\x30\x59\xd0\x8d\xa4\x91\x03\x02\xa0\xe0\x61\x48\x00\xda\x01\x0b\x14\x0d\xcd\x99\xd8\x82\x0b\x44\xc7\x5b\xcb\xe4\x45\x65\x1e\xc5\x34\xfa\x66\xce\x1f\xc4\xc2\x48\xbb\x1c\x64\x62\xcb\x06\xbb\x69\x44\xc2\xce\xf9\x69\x0c\xe2\x24\x94\x91\x0b\x82\x02\xcc\x79\x55\xd2\xd4\x7d\xbd\x9c\x47\x85\xa4\x4a\x43\x15\x30\x6b\x8a\xc9\x31\x27\xa4\xae\x8c\xf6\xb3\xb9\xd1\xb9\xc7\xba\x21\xd0\x00\x1e\x02\x04\xdc\x77\x53\x87\xe7\x6a\xd1\x2c\xce\x57\xd8\x56\x63\xda\x90\xa1\xcf\x56\x3e\xba\xdc\xe9\x39\xb3\xf2\xfc\x59\xe0\x4e\x97\x1e\x2c\xe1\xa4\xc9\x64\x11\x5c\x0a\x39\x2d\xe8\x47\x2c\xca\x26\x8e\x06\x66\xa8\x27\xcc\x40\x3d\xba\x04\xc9\x20\xfe\x15\x0d\xc6\x6c\x79\x3f\x13\x7c\x1d\x3a\xdf\x8a\xc6\xcc\xb1\xde\x53\x64\xc2\xe4\x3b\x88\x12\x9e\xbd\x98\x33\x3b\x26\xb7\xfc\x08\x30\x6f\xe1\x47\xb5\xee\xd3\xfe\xd8\xfc\xf0\x53\x2c\x0e\xc0\x6d\xc7\x19\x61\x3c\x59\x41\xfb\x68\x7e\x7b\x73\x8a\xab\x7a\x61\xf6\x19\x8c\x57\x35\x02\x07\x17\xc9\x88\x85\x46\x74\x8e\x38\x18\xd5\x94\xc6\xa5\xc9\xcd\xd3\xf7\xbc\xcf\x55\x71\x89\xc8\xd6\x88\x53\xb6\x5c\x44\xe5\x79\x93\x90\xf9\x15\x4b\x37\x35\x01\xab\xea\x7a\x23\xbb\x27\xcc\x09\xa6\x04\xc5\xae\x4a\xa9\x9e\x93\xca\xff\xe8\x48\xd8\xc2\xfd\x8b\xf9\x24\x7a\xc4\xdc\x92\x0a\xe5\xa5\x8d\x9e\x2c\x8e\x54\xc0\x30\x28\x66\x25\x3c\x2c\x51\xcd\xe7\xa7\x92\xaa\x0e\xc9\xe6\x8d\x5d\x44\xb8\x3b\x66\x4d\xa7\x40\x89\x62\x84\xf9\x5b\xbf\x9e\x11\x84\x50\x40\x8d\x73\xcc\x34\x7a\x09\x0e\x2f\x57\x4a\x2b\xb6\x52\xc0\xed\x88\x68\x18\x91\x96\xb4\x8f\x82\xf0\x0a\x73\xa3\x45\x75\xc2\x28\xb4\xc1\xc9\xcf\x56\x94\x56\xe3\x9e\x0d\x27\x0a\x73\x0c\x23\x39\x45\xd7\x8a\xc2\xa5\x95\x51\x55\x5b\x52\xb6\x9a\xf0\xff\x4e\x46\x86\x86\x61\x78\x49\xd8\xd8\x9a\xa8\x6e\x43\xaa\xe5\x64\x15\xeb\x4a\x6c\x63\xb5\xd4\xa9\x62\x0c\xae\xe4\x89\x2c\xe8\x30\xb7\xb1\x81\xd5\xa8\xf2\x66\x16\xde\x80\xe4\xb4\x01\x4c\xad\x06\x04\x8d\x99\x6e\xac\xca\x20\x82\x92\x80\xdb\xbd\x80\x4c\xd9\xac\xbb\xb0\x52\xa5\x80\x50\x45\x27\x95\xce\x4f\xa5\x34\x97\x13\x23\x68\x6c\x27\x4b\xe0\x7e\x13\x4b\x97\x70\x14\x7b\xfc\x0e\xc1\x25\x89\x59\xec\x31\x59\xb0\x54\xf1\xe4\x11\xfa\x93\x37\xe8\xec\xc5\xf5\xec\x01\xe1\x7d\x08\xfe\xe5\xfc\x58\x62\xa5\x73\x55\xc1\x28\xf4\x94\xb8\x89\x5b\x42\x8a\xd4\x08\x70\xde\x79\xf5\xe3\x34\xf5\x90\x4d\xe3\x52\x70\x78\x15\xa5\x7e\x17\x3b\x8b\x29\xdd\x8f\x7d\x49\x34\x99\xe9\x13\xa1\x7f\x46\x91\x50\x33\x82\xa2\xdb\x7d\x5e\x6c\xba\x29\x2f\xf6\xc6\x8f\xfa\x6a\x6b\xf3\xd0\x7e\xf3\x70\xdf\x3c\x16\xc7\x94\x55\x3d\xa0\x09\xdc\x85\xa8\x0c\xaa\xfc\x49\x55\xad\x18\x5a\x79\xb9\x64\xa4\xb5\xd0\x1b\x36\x8f\x5d\x57\xe3\x09\x4b\xd8\x83\x64\x4b\x74\x6c\x79\x3c\xa5\x93\x40\x8a\x8e\xa9\x8e\xd9\x72\xa8\x7a\xf0\x5e\xb4\x90\x5e\x23\x24\x78\xa1\x18\xc1\x77\xd8\x1a\x29\x74\x83\x71\xca\x73\xab\xa3\xe5\xe6\x50\x37\x2b\x20\x0e\x2c\x36\x8b\xda\x59\xf6\x2a\x36\x28\xf2\x7f\x10\xb5\x43\xd8\xae\xc9\xd2\x84\xda\xad\x1b\x16\xa4\x8b\xc0\x04\x56\x78\x00\xe9\x01\x5b\x75\x2c\x61\xf4\x5c\x9d\xbe\xce\x7e\xcd\x4b\xf7\x5c\xee\xb9\x5f\x77\x5d\x8e\x86\x74\x21\x47\x79\xf6\x99\xd2\x98\xc8\xe9\x06\xe0\x2e\xe4\x26\x78\xce\xa0\xff\xc1\x6c\xc4\xb9\xcf\xb7\xce\x6f\xeb\xf1\xa2\xf0\x7f\xe5\x68\x16\x8d\x39\xc7\xb8\x04\xb7\xc2\xc7\x02\x53\xc5\x92\x59\x09\xcb\x7c\xcf\x5a\xa3\x90\x75\x4d\x17\x7f\x75\x06\x84\x29\x4d\x0e\x18\x57\x5f\x5e\x07\xc1\x71\xaf\xcd\x96\x8d\xdc\x6c\xdc\x22\x89\x84\xc0\x6b\x8b\x04\x52\x58\xb9\xf9\x8e\xff\x73\xf5\x8e\x0e\xd8\x2d\x3f\x8d\xc3\x40\x4a\x5f\x32\xaa\x68\xcc\x4e\xb9\x7e\x9b\x40\x0c\x23\x12\xdc\x1a\x61\xc2\x26\x25\x34\x45\x59\x33\x11\x73\x17\x04\x64\xd9\x3a\xd4\x16\xe7\x35\x5b\xa6\x17\x94\x2f\x73\x13\xf9\x88\xc9\x29\xe2\xe2\xe4\x8b\x42\x27\xfd\x84\xaa\x9f\x20\x33\x53\xb1\x9e\xf4\x42\x1f\xbe\xf9\x13\xfe\xb2\xe2\xc7\xad\xdc\x00\x9d\x78\xf6\xb5\xa6\x9d\xa2\xe4\x44\x2e\x86\x02\xfd\xd1\x2b\x9a\xf3\xb1\x85\x41\x1a\xcc\x58\xbc\xf3\x22\xca\x48\x5a\x73\x51\xb1\x5b\x0d\x8a\x3a\x0e\xad\xd3\x70\xcb\x3a\xed\xdf\xdf\x45\xe3\x56\x3f\x5f\xaf\xfc\x0c\x85\xaf\x7c\x08\x16\xbc\xd0\x60\x90\x4d\xc6\xc4\x8a\xbf\x0d\xcf\x40\xb6\x4e\x84\x50\x8a\xc8\xf0\xc0\x21\xe2\x1e\x00\x3d\x4f\xb0\x8e\x92\xb4\x31\x05\x57\x95\x44\x74\xae\xf3\x44\x55\xf7\xda\x48\xa0\x51\xee\xd1\x3e\x08\xe1\xb4\x60\x0d\x11\x78\xfb\x72\x4a\x9d\xdc\x53\x06\xb9\xab\x38\xd0\xce\x09\x20\xd1\xc5\x3a\xfa\xcc\x97\x58\x2b\x2c\x89\x3d\x61\xa2\x2c\x36\xca\xe6\x90\xf0\x8c\x20\x0f\xb4\x98\x7d\x21\xea\x3e\xb7\xde\x71\xb0\x8e\x61\xea\x37\x43\xae\x25\xb7\x24\x4b\x35\x09\x16\x93\x0f\x7e\x57\x2c\x15\x42\xd0\x4f\x05\x91\x6f\x70\x80\x57\x0b\x07\xb8\xd8\x36\x85\x07\xa8\x92\x29\x8d\x29\xba\x2a\x90\xd5\xc4\x6d\xa2\x52\x5c\xcc\xa3\x72\x02\xe3\xe2\xfa\x52\xcb\xe3\x65\x99\x7d\x2e\xf0\x93\xc8\x9c\x4b\x5a\x6c\x9f\x51\x65\x68\xdc\x27\xdc\x80\x39\x27\x83\xb0\xc8\xc9\x94\x25\x3e\xc0\x5c\xa7\xa5\x1e\x72\x2a\xbe\xbe\x90\x25\x12\xba\x2c\x89\xca\xc5\x15\xb2\x42\x0b\x2b\xfd\x75\xb0\x23\x06\x27\x05\x51\x4f\x71\x22\x55\x45\xa4\x95\x0b\xa0\x0f\x83\x94\x05\x5c\x5a\x26\xad\x94\x2e\x2a\xcd\xcb\x67\x9b\x4f\x20\x49\xa9\x27\xf7\x88\x25\x4a\x16\x63\xe5\x55\x47\x61\xac\xbc\x3a\xc4\xa3\xc3\xcf\x4f\xb9\x1a\xa6\x58\x50\x3e\x18\x65\x0b\x93\x59\x3c\xa5\x74\x94\x8f\xdc\x00\x71\x16\xd4\x96\x8b\x6b\x34\x7a\x7b\xc2\xdb\x23\xc8\xf7\x5c\xc2\xcc\x2c\x97\x78\x9b\x91\x7f\x73\xb1\x19\x7c\x24\xd5\x1e\x5b\xdd\x71\x96\x81\xcc\x33\x39\xc6\xea\x90\x45\x94\x2c\x92\x0a\x32\x07\x71\xc6\x15\x91\xcf\x80\xf8\xd8\x07\xa9\x4c\x8a\x91\x55\x65\xbf\x98\xad\x60\xc0\xd9\x4b\xcd\xaa\x16\x85\x9e\x65\x59\x53\xaf\xa4\xe1\xc4\x02\x7e\x49\xa0\xa7\xcc\x3e\x51\x27\x3a\x68\x43\xdc\xba\x36\x94\x9d\x51\x66\x09\x13\x72\x43\xb4\xef\x91\xa0\x98\x59\xc0\x4e\x95\x09\x62\x8b\x79\xaf\x0d\x29\xda\x52\xcc\xa8\x2a\x6a\xca\xa8\x10\x90\x4d\x8f\x20\x9b\x9a\xe2\x16\x82\x2f\x65\xf6\xb1\x6c\xd8\x5f\xc6\xe3\x61\xbc\xc5\xde\x23\xf3\x1c\x33\x85\x49\x54\x99\x3c\x40\x84\xc8\x0e\x42\x15\x73\x8c\xad\x9f\x14\x55\x01\x18\x5c\x0c\xab\x21\x67\xc7\xc0\x14\xdd\x07\xc8\x2f\xa8\x40\x46\xec\x37\x80\xf8\x38\x95\xe4\x4a\x98\xa3\xa2\x58\x6e\x68\x69\x58\x20\xee\xe1\x7b\x5e\x61\x81\xec\x2e\xc0\x40\xdb\xa6\xa1\x37\xab\xec\xd5\x72\x33\x8b\x55\xe6\x90\xc3\x28\xd5\x55\x43\x9d\xbd\x2a\x41\x2f\xf4\x50\x10\x83\x8d\x38\x0b\x7c\x3d\x36\x26\xb4\x38\x24\x3c\x23\x13\x0e\xe9\xc0\x45\x61\xe7\x92\x74\x0c\x53\x84\x59\xe8\x4b\x9e\x7d\x31\xbb\xf6\xc6\x50\xdf\xae\x83\x5a\x97\x8c\xf5\xe8\x60\xfb\x74\x79\xc7\xb9\x8c\x82\x02\x0c\x09\x9b\x20\x4f\x30\x30\x48\xeb\x6a\x9a\x32\x1f\x27\x6c\xc1\x9f\x55\x81\x65\x5c\x34\xef\xaa\xb8\x0e\x2c\x3a\xb3\x25\x01\x0b\x92\xd8\xf6\x3a\xff\x84\xbc\x7a\xcb\x3d\xc0\x6e\xd6\x05\x2a\xb6\xc1\x51\xc3\x20\xf6\x22\x06\x4b\x56\x01\x37\xe7\x55\xdd\x51\x58\xdb\xa4\x2b\xcf\x72\xcd\x9f\xa1\x98\x20\x23\xe4\x12\xbb\x34\x4f\xe6\x9b\x70\x91\xf6\xf0\xdc\xec\x39\x66\x39\xb2\xf9\x45\x78\x25\x2c\x2e\x01\xd2\x0d\xb1\xdb\x5d\x17\x4a\x65\x44\x76\x56\x0c\xce\x12\x77\x09\x75\x06\x4a\xcf\x88\x31\x82\xcb\x3d\x2e\x9f\x7b\xe6\xa4\x04\xe7\x91\x2a\x81\xa8\x2e\x8f\xec\x67\x52\xa6\x31\x42\xe8\xc0\x5d\xaa\x17\xca\xcb\x68\x03\x78\x4c\x2b\x5a\x5a\xf2\x37\x2e\x54\x19\x28\x50\xa9\x23\xb1\x9c\x76\x54\xb9\x2b\x18\xb8\x4a\x09\x1b\x22\x8b\x53\x04\xd9\xc2\x54\x94\x15\x95\xd1\xa2\xfb\xc1\x24\xe0\x3c\xd2\xe5\xd2\x9d\x09\xed\x86\x2c\x94\x95\x96\xc0\x19\xee\x45\x12\xbc\xc5\xed\x24\x8b\x4d\xb3\x4a\x17\x32\x01\x72\x3b\xce\x82\x4c\x75\x4f\x5b\x06\x94\x6f\x2f\x60\x72\xe4\x36\xe7\xd4\x43\x03\x72\xea\x1e\xc6\xea\xf6\xc1\x5d\xa6\xb9\x20\x81\x0f\x76\x32\xcc\x94\x0e\xa3\x32\x3c\xcf\x73\xa9\xe5\x0a\x34\x8d\x6d\xf0\x8c\x2c\xa1\xd1\x27\x73\x9e\x5a\xd4\x33\x89\xb2\x90\x02\xbe\x39\x7a\x32\x02\x60\x73\x75\x59\xf6\x15\x70\x37\x22\x97\x6e\x1e\xf7\xbc\x0e\x63\x5f\xa2\xc0\xb2\xc3\xeb\x25\xa4\x41\x35\x49\x9f\x4b\x1b\x2c\x0c\x2f\xc0\x75\xe1\x28\x84\x41\x11\x52\x2e\x0d\xad\xbc\x64\xcb\x5b\xd1\x31\x6f\xe5\xb0\xfe\x75\x55\x77\x64\xf1\x32\x71\x73\x9d\x81\xc4\x01\x31\x7b\xb9\x09\x5e\xc4\x4e\xaf\xa8\xa5\x81\x03\x42\x0a\xd3\x2e\x0f\xba\x51\xf5\x4a\x5b\x7b\xb8\x54\x96\xc9\xd2\xbf\x03\xb9\x1c\xcd\xc8\xcc\xf0\xfe\xe9\x1f\x1c\x37\x48\xf1\xbb\xed\x49\x68\x2e\x0c\x22\xc5\xa5\x58\x06\x2f\xac\xb8\x22\xed\x84\xeb\x60\xae\xab\x18\x75\x28\x39\x3b\xbd\x12\x09\xda\x26\xab\xd4\x4e\x78\xca\xa7\x58\x76\x5e\x58\x79\x59\x29\x4e\x52\xbf\xf0\x92\x9a\x22\xe5\x0d\x0f\xd3\xdf\x36\xc7\x93\xfa\x9a\x50\x1c\x90\x49\x94\x75\x24\xba\x36\xb6\x24\xc5\xe5\x5a\x71\xd7\x47\x65\x47\xc4\x31\x8e\x1e\xdb\x97\x96\x3d\x8c\xa0\x80\x49\xa1\x88\xf3\x05\xe8\x10\x06\x01\x64\xc5\xba\x3c\x99\xb5\x87\x8a\x65\xb1\xc8\xa8\xac\x9c\x1d\x2a\xdb\x4c\x4a\x72\xdc\x33\x46\x88\x9c\x82\x9d\x29\x07\x57\xab\x25\xbd\x6c\xe5\xd0\x9e\x6f\x7e\x4e\x81\x52\x59\x78\x48\x94\x5c\xae\x71\xe7\x63\x6b\x33\x73\xde\xd5\x9c\x67\x05\x3d\x83\xe2\x04\x5d\x73\xda\x25\xc9\xdd\x3f\x53\xdb\x06\x71\xfd\x5f\x2b\x13\x7f\xde\xd7\x5f\x4a\x54\x67\x0e\xd4\x25\x37\x72\xc4\x01\x3b\x63\xaf\x46\xf2\x38\xcd\x6c\x1e\xf9\x42\xc8\xa7\x73\x6c\xae\x6d\x44\x94\x93\xca\xd0\xa1\xe7\x56\x59\x21\x10\x04\x2c\x20\x56\x62\xc9\xda\x72\x16\xcd\xad\x2c\x4a\xc6\x05\xc0\xf6\xd2\x3f\xb5\x43\xdc\x5e\x08\x48\x61\xae\x6a\x76\x11\x0a\xe7\x45\xfc\xc0\xd2\x9a\x2f\x77\x43\xd5\xed\x3b\x9f\x2e\x5e\x39\xf8\x7d\xc8\x3e\x35\x0b\x6c\x5b\x06\xab\xf0\xbf\x7f\x03\xf5\xcf\x6a\x6d\x31\x42\xa1\x48\x85\x4d\xc0\x06\x57\xf8\xbf\x57\xe5\xbc\xda\x92\x67\x8e\x6a\x27\x58\xb4\xbc\x23\x15\xc3\xb8\xf2\x54\x36\x1c\x46\xff\xcf\xd6\x92\x20\x55\x30\xf0\x58\x93\x13\x94\x84\x30\x9c\x35\x49\xcf\xed\x5e\x56\x23\x44\xd5\x9b\xa9\x46\x58\xe9\x88\xcd\xd6\x6e\xb9\x61\xf8\x1b\x72\x2e\x5b\x94\xc6\xf2\x10\xc1\x54\xd7\x93\xc4\xfd\xbe\xf3\xa1\x27\xbf\xa1\x4e\x46\x4a\x8e\x75\x2f\x62\x69\xad\x84\x51\x0b\x57\x56\x8f\x5c\x94\xbd\x2b\x40\x57\x20\x99\x27\x20\xd0\x3e\x53\x0e\xbf\xea\x00\xd0\x30\x5e\x3c\x5c\xa8\xd7\xfd\x51\x94\xd7\xdf\xb3\x31\xdb\xff\xef\x3a\xec\xaf\x5c\x12\x27\x11\xb9\x8c\x99\x1d\xc4\xf8\x12\x2b\x2a\x4b\xa2\xf4\x58\xbb\xa7\xc0\x34\xce\x0b\x3b\x15\x12\x41\xa3\xae\x7a\xb2\x47\x7d\xc6\x87\xf6\x22\x5c\x8f\xd3\x88\x20\x1d\x05\x3f\x3c\x49\xd1\xa9\x1c\x38\x60\x7d\x2d\x38\x95\xcc\xaa\x8e\x05\x07\xcb\x60\x0b\x9f\x0f\xe0\x1a\x0b\xb2\x2f\x0b\xb2\x4f\x3d\x27\x61\xf4\x89\x1d\xb2\x45\x10\x65\x11\x17\x19\x1a\x70\x43\xc5\x97\x65\x17\xd2\xe4\xa5\x07\xd6\x6c\x27\x5a\x3d\x59\x15\x05\x4c\x75\x71\x66\x46\x04\x0f\xc4\xb9\x41\xd8\xa2\x34\x9c\xec\xd3\xc8\xd8\x55\x55\x10\x52\x59\x32\xba\xca\xe1\x8c\xae\x27\xab\xaa\x71\x17\xf9\x56\xe5\xb2\x0f\x84\x6a\x57\x08\x24\x1b\x8e\xdb\xb3\x87\x99\x99\x76\x88\xc0\x67\xee\x11\xf2\xca\x44\xb1\x75\x61\xe6\xa9\xf0\x2b\x26\x8b\xec\x89\x7f\x07\x37\x48\x41\x85\x85\x51\x3a\xe1\x9a\x41\x94\xa5\x20\xfc\xea\xf1\x52\xe1\x90\xc5\x32\x09\xdc\xac\xdf\xe1\x55\xac\xb0\x28\xbf\xb3\x2f\xed\xd5\xc5\x6c\x0a\x36\x2b\xff\xe8\x94\xca\xba\xa0\x23\xe5\x8b\xe0\xb7\x5a\xcd\x19\x9f\xd2\xe0\xab\x63\xb8\x33\x99\x82\x19\x63\x9c\x48\x98\x04\xfe\x53\xe2\x30\x32\xd2\x7c\x44\x7a\xfe\x24\x72\xe7\xbb\x7a\xd8\xe2\xa5\xb0\x6c\x84\x27\xb5\x6c\xd3\xda\x73\x4c\xa9\x74\xb3\x82\x79\x25\xe1\xe9\x49\xd5\xe0\x31\x82\xb0\x1f\xa7\x81\x60\x33\x8e\x3b\x49\x4b\xc0\xbb\xc4\x34\xa0\xbe\x59\x2f\xe1\xe6\xc5\xaa\x75\x4c\x80\x8d\xc4\x6d\x57\xa0\xff\x5a\xd8\x7b\x9e\x11\xa7\x1f\x46\xcc\xb6\x43\x02\x50\x4b\x93\x6d\xd3\x42\x83\x8f\x0e\x05\xdb\x72\x74\xdb\xf3\x15\x57\xf3\x15\x17\x05\xab\x82\xa9\x0d\xc8\xb8\x90\x82\xec\xd0\x92\xbb\x66\x47\x3d\xd1\x08\x8a\xbb\x6e\xae\x1e\xf3\x84\x74\x96\x38\x55\xb2\x11\x50\x8c\x8e\x62\x01\x72\xa2\x18\xad\xe4\x19\xc5\x34\x96\xa8\xb2\xc3\x02\xe2\x6b\x9a\x2c\xdc\x4d\xc2\xd8\x72\x0f\x87\xf4\x88\x92\xd7\xb1\x43\x95\x18\xac\xa7\xba\xef\x61\xe8\x99\x15\x89\x46\xf8\x8b\xaa\x83\x1f\xc5\x38\x95\xde\x68\xbd\x12\x1e\xd4\x0a\xdb\xf3\x56\xf4\xac\x17\x81\x50\x3a\x1f\x90\x83\x4b\x11\x23\xb5\x7e\xdd\x80\xb8\x46\x92\x38\x9a\x05\x88\x97\xcc\xa5\x9e\xca\xc7\x66\x11\xbb\x28\xf0\xd1\x4c\x61\xbb\x88\xa3\xd3\x1f\x06\x2b\x47\x47\xc2\xe7\xa7\x12\x10\x0b\x6d\x41\x5a\xc9\xe2\xae\x84\x78\xe2\x7d\x3c\x19\x88\x64\xa9\x16\x08\x81\x0b\x3f\x2e\x54\x7f\x38\x55\xa4\xe7\x0c\x39\xa1\x30\xf9\x7d\x4b\x0b\xe4\x0a\x6e\xa9\xd1\x57\xcc\xb8\xe7\x65\x2b\xde\x4a\x57\x3c\xad\x77\x48\x5a\x62\x3e\x78\x09\x94\xa1\x81\x2b\x22\xfa\x10\x32\x54\x2d\x98\x1b\x81\x32\x52\x11\x72\x15\x77\x1c\x21\x7a\x02\xea\x95\xcd\x4a\xe2\x3b\x5c\x5c\xfc\xc4\xd2\x6d\xee\xb8\x10\x69\xb3\xde\xd3\xff\xb5\xf1\xfe\x07\xce\xdb\x65\xe0\x9e\xac\xca\xc0\x25\xba\x64\xab\x05\x2e\x28\x0a\xc9\x33\xcf\x5e\x2f\x3c\xe7\x6e\x54\xcf\xad\xce\x25\xd5\x7e\x2b\x55\xbb\xb5\xf9\xa2\xb2\x9e\x96\x25\x68\xbc\x45\x97\x04\x2e\xe4\xe6\x22\xab\xdc\x83\xff\x8f\x48\x46\x9f\x1b\xea\x96\x51\x90\x6e\xd0\x55\xfe\x8b\xd2\x2a\x80\x75\x6c\x1c\xa1\x17\x9b\x93\x62\xb5\x46\xcc\x16\x08\x8d\xb1\x76\x07\x2b\x4d\xbd\x52\x90\x10\x5d\x0d\x25\xac\x66\xc1\x41\x22\xb6\x85\xc3\x26\x53\x1b\xc9\xdc\xff\x28\xac\x29\xbd\x9a\x80\x31\x49\xb0\x8f\xee\xed\xeb\xf1\xa7\xa6\x5d\x62\x2f\x8d\x1c\x95\xb0\xa3\x13\xe3\xf5\x3d\x73\x7f\x89\x03\x48\x5d\x71\x57\x92\xc2\xa6\x40\x40\x27\xc3\xb9\x44\x63\x86\x1a\xe9\xa8\xe7\x7e\x30\x4d\x1d\x4a\x66\x23\x70\xa0\x8e\x08\x9d\xb8\x4c\x5e\xf0\x67\x08\x23\xca\x10\xa2\x10\x18\x76\x48\xeb\xd2\x1b\x14\x5d\x1e\x23\xce\x73\xe0\x2a\xce\xac\x4d\x21\xbb\xbe\x4b\x13\x4f\x64\x53\x14\xf3\x68\x06\x24\x2b\x46\x01\x3e\x6b\xc1\x9d\x16\xc0\x9b\x69\x29\xe2\xc2\x12\x5c\xb3\x58\xe2\x18\x9d\x72\x10\xa4\x45\xa4\xb2\x70\x66\x7c\xe3\xf9\xa9\xd4\xb4\x94\xbb\xa8\x61\x99\x2c\x58\x36\x96\xd9\xd2\x9d\x3c\xa2\xa8\x54\xe8\x51\x99\x1c\x26\x0b\x6a\x67\x1a\xa5\x39\x66\x44\xcd\xba\xd4\x26\x3c\x08\xce\xad\x0b\x92\xd9\x11\x65\xab\xbe\xd8\x0a\xbc\x26\x64\xd1\x9d\x4c\x93\xcf\xc9\x31\x8f\x1e\x35\x31\x54\x3a\x5a\x25\x83\xb6\x94\xd4\xdb\xca\xa5\x53\x32\xad\xeb\xcc\xe9\xb6\x80\x13\x45\x9a\x9c\x78\xe6\x10\x77\x8c\xfc\xe8\x10\x11\xfd\x70\x7e\x9a\xb7\xef\x6d\xbe\x6a\x55\x8e\x97\xf2\x12\xe7\x56\x75\x81\xda\x68\x81\x3e\x2a\xac\x93\xd0\x94\x82\x38\xa6\x3c\x32\x8a\x94\xa4\x9e\x83\x4a\x79\x62\x73\x31\x24\x04\xe5\x5a\xc0\x03\x12\xf1\x92\xc8\xe4\x13\xea\xef\xc1\x01\x6c\x89\xaa\xd6\x8d\xe2\x03\xf4\x2b\xe7\xa7\xda\xd8\x5e\xe7\x91\x46\x65\xce\xf5\x88\xa8\xf3\xd8\x23\xa1\xab\x05\xc8\xea\x96\x88\x66\x4e\xae\x96\x02\x07\x4b\x55\x2f\x05\xc1\x59\xb0\x61\xf6\x21\xef\xbe\xb7\x35\xa5\x94\x23\x06\x10\x61\x58\xed\xc1\x07\xd8\x5d\x28\x08\xe1\x4e\xa3\x88\xcb\x59\xb9\xd7\x52\x64\xab\x45\x2b\xff\x3a\xb1\x15\x42\x09\x65\x9f\x33\x07\x72\x42\x27\xe6\xed\x66\xae\x17\x98\x81\x00\xb0\x55\x23\x88\xbd\x9e\xd5\x64\xc9\xcf\x96\x28\x6d\x1b\xdb\x72\x19\x27\x98\x5f\x60\x7b\x32\x17\xbb\x65\x14\xe1\x37\x59\xca\xf9\x80\xdf\x74\x2d\x33\x2e\xbb\xc3\xdc\x9b\x82\xe8\xaf\x58\x91\xa4\x38\x46\x33\x8c\x7b\xe4\x20\x5b\xec\x3d\xa2\x62\xad\x6e\xa6\x79\x95\xfc\xf2\x31\x79\xf2\xfd\x03\xe9\xdc\x6d\x92\xc9\x93\xeb\x64\xd2\x96\x0c\x4f\x22\x76\xcd\xc2\x02\x88\x9c\xa5\x4b\x17\x9a\x10\x9b\xe6\x72\xd8\x91\x94\x19\xe6\xb4\xdc\x13\x01\x9c\x09\x59\x68\x0e\x26\x64\xbb\x4d\x1d\x34\x92\x27\x2f\x8a\x3f\xc4\xe2\xfa\x48\x10\x92\x36\xfa\xec\x1a\xa4\x3f\x65\x99\x98\x93\xcb\x69\xb4\x54\x38\x36\x9b\x37\x02\x82\x6d\xf3\xa2\x00\x13\xa2\xc9\x13\xb9\x0c\x87\xb4\xaa\xb6\x15\xda\xa4\xea\xd8\x0e\x7c\x4e\x9c\x65\x34\xd4\xee\xcb\x12\xe9\x29\xfd\xd5\xec\xf9\xdd\x73\xf4\xb8\xc3\x94\xd1\x5b\xfc\xb9\x6a\xdc\x2e\x93\xc3\x06\xa7\x5c\xce\x4f\xb9\x16\xd7\x38\x2e\x55\x31\x5b\x4f\xd0\xae\xd5\x8c\x80\x23\x2c\x7f\xaa\x71\x49\x98\x0a\xb9\x9c\x66\x0a\xb2\xf3\x24\x79\x9f\xda\xdf\x0b\x21\xf1\x64\xf6\x57\xbf\x15\x92\xac\x4b\xf1\x74\xcd\x1c\x96\x92\x79\xad\xba\x14\xca\x4c\x0d\x82\x5d\x5a\xb0\x12\x89\x70\xa2\xc4\x10\x06\x5c\x48\x6b\x3b\x4f\xb5\x9c\x9f\x46\xe1\xbb\xb4\xdf\x1c\xd1\xba\x66\x05\xf1\x42\x1d\x9c\x5d\x96\x88\x62\xd4\x55\x75\x80\x08\xe3\x7a\x08\x33\xe7\xb0\xf3\x79\x2b\x1f\x56\xbb\x5d\xd5\x1f\xbf\x6f\xa1\x42\xed\x6c\x5d\x8c\xe2\xff\xe7\x7c\x2e\x05\x72\x42\x79\xae\x29\xec\xb8\xd2\xbe\xf4\xb2\x02\x91\x0a\x8d\x92\x5a\xec\x85\x93\xbd\x65\x90\x42\xeb\x51\xd8\xae\xda\xc1\x98\x4c\x75\x31\xc6\x07\x2b\x14\xf7\x7c\x15\x24\xa9\xc0\x73\xec\x23\x39\x73\x8f\x59\x31\x9c\xc7\xbd\x98\xcf\xec\x11\xc3\x9c\x50\x30\xc2\x50\x87\xb3\x8a\xa1\x0c\x13\xd9\x8c\x7c\x13\x1d\xae\xd5\xf4\x0d\x08\x11\x03\x36\x8e\x30\x96\xcf\x5e\xa4\xe8\x15\xa9\xd8\x63\x57\x6a\xd9\x91\xa4\xb1\x98\x7b\xc5\x0a\xbc\x99\x3f\xcf\x02\x62\x51\xf1\x19\xda\x0b\x0a\xf2\x3b\x56\xa2\x46\x7d\xd8\x78\x40\x3a\xbe\xb8\x61\xaf\x2d\x69\x8b\xb1\x3a\x42\xf6\x43\x4e\xbb\x22\xa4\x9f\x94\x76\xbe\x6c\x45\x1a\xff\xec\xa7\xdf\x3d\x5d\x95\xb3\x2f\xfb\x92\x99\xac\xa2\xbb\xdb\x98\x18\x85\x1c\x1d\x35\x99\xac\x46\x83\x2e\x0f\x81\xf1\xd7\xe6\x7c\xa5\x09\x6a\x50\x93\x7d\x8e\x91\xfd\xcd\xc8\x40\xd1\xbf\x2e\xfc\xb9\x4d\x5c\x69\x93\x62\x1f\x6a\x7c\x7e\xca\x45\x96\xf7\xf8\x24\x88\xc2\x45\x01\xdf\xda\x7a\x08\x1a\xa8\xa0\x66\x27\x30\x98\xd5\x06\xf3\x63\x23\x28\xa7\xaa\x1f\x76\x4b\x8b\x36\x07\xf4\x53\x08\xb9\xfd\xc1\xeb\x93\x17\x68\xd9\xc3\x4d\xd7\x37\x41\x6b\x10\x91\x59\xb2\xec\x38\xe5\xd9\xeb\x85\x70\xe9\x8a\x05\xae\xa4\xca\xce\xa3\xf0\xa5\x5e\x88\xee\x22\x04\x38\x46\x41\xf9\x9d\x8a\x10\x73\xae\x3b\x5f\xb7\x02\xe0\x75\x2c\x2b\x3b\x4c\x5d\x42\x51\x29\xe8\x52\xb2\xa0\x7e\x61\xc8\x66\xa4\xa5\x4a\x3d\x31\xa7\xa4\x11\x65\x85\x1c\x23\xda\x26\xd9\xec\xf7\xd2\x8c\xbc\x2f\xfe\xd0\xf3\xe3\x4c\x0a\x41\x75\x1e\xac\x70\x57\xb3\xda\x01\x3b\x89\x79\x56\x9a\xdf\xf9\xcc\x3c\x53\x4a\x83\x84\xe6\x38\xf1\x98\x51\x17\x19\x26\x56\x13\xf7\x08\x8c\xb6\x6d\x0e\xef\x9f\xbe\x21\x5f\x28\xb6\x8c\x72\x07\x09\x86\xb2\x8a\x6a\xb0\xaa\x2f\xaa\xd0\x52\xde\x7a\x60\x3d\x56\x86\x93\xba\x38\x2f\x9b\x2e\xb6\x98\xf3\x32\x80\xb5\x45\x76\x66\xbb\xc1\x8b\xad\xbc\x37\xf2\x90\x51\x25\xa4\xc1\x25\x2c\xd1\x41\x25\x40\x55\xe7\xe4\x54\x1b\x50\x31\xce\xba\x35\x89\x66\x12\xd9\x41\x9f\x50\xa2\x69\x6c\x61\x65\x12\x60\xc5\xd0\x4f\xab\x16\x49\xec\x2c\x7b\xca\xca\xc1\x5b\x9c\x06\xb4\x6e\x4b\x04\x63\x9e\xac\x95\x87\x15\x2e\x84\x8b\x5a\x93\x81\x5c\x65\x33\x30\x4c\xac\x30\x1d\x41\x62\x20\x51\x36\x0f\x65\x02\x36\xeb\x4b\x62\x39\x97\x28\xb4\xdd\x0d\x84\xc1\xca\x95\x5b\x10\x19\x46\x05\x4f\x5f\xec\x15\xfe\x91\x75\xd4\x3d\xc8\x16\xde\x17\x7a\x46\x63\x4f\xbb\x2a\x51\xa1\x95\xcd\x12\x8f\x70\x68\xf6\xa0\x05\x8c\xc9\xd7\x6a\xa9\x96\xdb\x2b\xb2\x32\xcd\x94\x0b\x1b\xad\x52\x25\xf1\x40\xad\x39\xce\x96\x42\xa0\x84\x34\x98\xd9\x17\x02\x94\x65\xc3\xf5\xa4\x7d\xdf\x60\x04\xc8\xfb\x5c\xc6\x76\x39\x5a\x03\x1e\xc5\x0e\x3c\x63\x83\x11\x1c\x89\xff\xdd\x3a\x8d\xf2\x6b\xa9\xdb\xfe\x60\xbb\x28\x16\x3f\x3e\x97\xdc\xae\x78\x14\x0b\x0f\x3e\xbb\x5c\xcc\x17\x0a\xe3\x75\xb8\x54\xb3\xc6\x1c\xdf\x06\x8b\xfa\x22\x37\x83\xa1\xa0\xed\x0a\xf3\x1c\x02\xca\xe5\x50\xe4\x90\x7e\xdc\xba\x74\x7c\x58\xf2\x2e\x32\xb9\x56\x2b\x4e\x72\xb9\x28\x2d\x5b\x2e\x95\x96\x0d\x8f\xd3\x4e\x4a\xba\x9c\x00\x9e\x38\x28\xff\x50\x1d\xb6\xd7\xc5\x33\x0b\x61\x37\xa0\x5a\x1f\x87\x8c\x92\x4f\x57\xb6\x85\xbc\x77\x6e\xa4\xe6\x52\xae\x80\x3c\xdd\xe5\x7c\x28\xe0\x4c\x3b\x5b\x69\x80\x69\x39\xb1\x06\xbe\x74\xc9\x83\x10\x6a\x73\x33\xb5\x41\xa5\xa7\x4f\x65\x44\x8a\x21\x2d\xa5\x60\x26\xcc\x3e\x77\x65\xbb\x2c\x15\xfa\x11\x1d\xc6\x16\xe6\x9d\xe3\xe0\x8b\xa3\x4c\x9d\xed\x13\x0a\x75\xea\x0e\xcd\x56\xaf\x10\x41\x0b\xec\x16\xad\x3a\xa0\xe6\xfb\xf6\xa8\xd7\x67\xbb\x94\x25\x63\x0e\xc2\x32\xcd\x94\xda\x20\x52\x1d\xcb\xec\x2b\x72\xb0\x88\xe6\x2c\x61\xe7\x69\x2b\x11\x4b\x3b\x5e\xab\x1f\xb2\x0f\x10\xa9\x4e\x01\xf0\x4c\x84\xd3\x14\x62\x55\x8d\x0b\x7b\x72\xe2\xc4\xb0\xd3\x4d\x3d\x84\x0e\xd7\xad\xc7\xfe\x20\x6f\xc1\x1e\xb2\x38\x5a\x55\xd4\xec\x39\xcf\xaa\x3d\x59\x1c\x82\x1d\x18\xe0\x51\x64\x19\x01\x46\x8b\xba\x14\x51\x12\x9f\x9b\xe0\xf5\xa3\x79\xcf\x2d\xb6\xcb\x0a\x38\xb6\xee\x8a\xaf\x4b\x21\xbc\x64\xfa\x9a\xa9\x82\x7d\xbc\xca\xbd\xbb\x0a\x67\x86\xfa\x5e\xf2\x6b\x29\xc1\x6a\x58\x53\xf5\x02\xd9\x9b\xd1\x89\xca\xb6\xa6\xf6\xf4\x80\x7a\x80\x32\xc7\x89\x06\x96\xe6\xa4\xb5\xc1\xeb\x45\x0c\x8a\xfa\xab\x99\x02\xa5\x85\xd9\x2b\x45\x2d\x7f\x29\xf2\xaf\xe7\xa7\x51\xc1\xce\x7d\x9e\xdc\x1c\xe6\x5a\x67\x88\x6d\xa9\x49\x91\xb1\x6b\xe3\x2d\xc4\x72\x8a\x33\x49\x1a\xef\x0f\xdb\xb8\xf9\xac\x8d\xcc\x8e\x73\x1a\x22\xc3\xbe\xb7\xd3\x2e\x7c\x0a\x69\x47\x01\x09\x74\x2a\xa9\x70\x05\x86\x03\x99\xd5\x2c\x97\xf5\xb4\x95\xea\xb8\xa9\x3c\xac\x33\xa7\xd2\x4b\xf6\xc2\x6f\xbd\x6d\x79\x7d\xba\xd2\x5a\x28\xa5\xbb\x7e\x18\xf3\xed\x1f\xd6\xa8\xb9\x94\xf2\xfb\x8f\x59\xdc\xbb\x82\x96\xb5\xea\x76\x29\x3c\x8c\x5c\x6d\xf1\xdf\x3c\x6c\x71\x37\xe0\x96\x1f\x02\xb6\x9c\xc6\x76\x0c\x29\x26\xba\xef\x1e\x23\xdd\x13\x77\xdf\x64\x37\xe8\x65\x8b\x40\x28\xc8\x49\x30\xa8\x52\xa2\x63\x91\x09\x87\x18\x55\x51\x92\x8d\x96\x70\x64\x9c\xfc\xa2\xc6\xa9\x22\xa0\xd1\xf3\x92\x07\x68\xca\xbe\x55\x10\xa3\xe5\x08\x00\xd8\xe3\x55\x8f\x44\x26\x0d\x5d\xc4\x5b\x4c\xfd\x81\xa5\x14\x9b\x6f\x01\x47\x4e\x21\xa2\x72\xa9\x1d\x9d\x78\x2c\x62\x05\x6c\x5d\x94\x29\x45\x47\xa8\x1c\x6a\xfb\x6c\x64\xd7\x8b\x68\x70\xcf\xed\x67\x8b\x87\xeb\xcb\x4d\x56\xfe\x07\xcb\x24\x49\x74\x29\xcc\xad\x2b\x41\xb9\xb3\x88\xab\x42\x6e\xe6\x44\x4b\x01\x48\x3a\x50\x00\xf2\x67\x3f\xfd\xee\xd9\x4a\x15\x7d\xa0\xfa\x7b\xa2\x90\xab\x72\xd8\x48\x7a\xbd\x5b\x7d\x3e\x1d\xe8\x5a\x85\xfc\x7e\x0b\x05\x9e\x26\x6a\x8e\x52\x0e\xf7\xc6\xdd\xcf\xd6\x1e\xff\x87\x19\x32\x6a\x95\xa7\xc6\x33\xe7\x81\xab\xf2\xa5\xb0\xa3\xdc\x06\x86\xff\x3f\x8a\xea\xcc\x38\xfb\x6d\xb0\x10\x16\x91\xc1\x9b\xf3\x13\x99\xb7\x7c\x9f\xe9\x5f\xbb\xda\x1f\xea\x5b\xc8\x91\xa5\xe9\xb4\xe8\x7a\x9d\x12\x33\x75\x23\xba\xa3\xed\xcb\x51\x26\xee\xae\x2f\xf8\x82\x63\xf7\xd6\x04\x97\x83\x13\x9e\x38\xbb\xd2\x06\x9c\xc8\x18\x6d\xf3\xe5\x5e\x0f\xc4\x2f\x45\x39\xac\x42\xb1\x95\x4f\xeb\x9e\x7a\x04\xb5\x98\x3f\xcd\x6a\xb6\x44\xab\xa2\x69\x45\x34\x43\xcf\x87\x50\x8e\x0a\x43\xf0\x95\x79\x73\xc7\x4d\xdc\xda\xe7\xfe\x40\x13\x57\x54\x74\x04\xba\xc9\x01\xb4\x49\xd3\x65\xfb\xa1\xcd\x0f\x58\x6b\x8f\x0f\xb4\xf1\x14\x02\x17\x1c\x7a\x52\xc5\x8e\xee\xb3\x38\x15\x0b\x2f\x42\x89\xd9\xba\x1c\x7a\x02\xb7\xd9\x84\xa4\x37\xe9\xdc\xb5\xc6\x5e\x84\xc6\x93\xd4\xa5\x3e\xb6\x4f\x71\xf4\x2d\x5c\x9c\xae\x99\xe2\xe4\x7b\xdf\xf5\xd0\x66\xcf\x61\x19\x0c\x8c\xf7\xd5\xe4\xe9\x84\xca\xac\xaa\xf5\x64\x2b\xfb\x0a\x7f\x21\x80\x95\x61\x00\x14\x00\xc5\xdf\x3c\x59\x09\x18\xae\xa3\xb7\xd4\xde\xee\x3b\x84\xc3\x92\xf7\xf2\x78\x7b\xa2\xd7\x9a\x6c\x5b\x10\xbb\xb8\x30\x94\xda\xab\x7f\x50\xa0\xdc\x0d\x5d\xa9\xe5\x81\x32\x0a\x24\xef\x62\x43\x95\xfc\xb2\x43\xbe\x14\x15\xe7\x63\xa8\xbb\x6c\x6d\xcb\xce\xd7\x56\x51\x1e\x5f\x24\xed\x7c\x8c\x61\x80\x7b\xd9\xe3\x4f\x89\x7c\x7e\x9a\x45\x5c\x2a\x69\x27\x14\x70\x22\x45\x4a\x0d\x45\xd0\xb6\x47\xbc\x76\xa3\xdf\xad\xe0\x67\x58\xea\x7d\xd6\x65\x5b\x8b\x6e\xb3\xf7\xa6\xcc\xe7\x88\xfc\xa0\xb4\xaf\x48\x2e\x16\x9b\x14\x7b\x85\x62\xb1\x53\xd9\xae\xd4\xf7\x74\x17\x05\x3e\x4f\x93\xd5\x9c\x29\xef\xa3\x8e\xfe\x6c\xed\x5b\x7e\xa8\xfa\x9c\xa7\xac\x3b\x7b\x5b\xf6\x6f\x0e\x69\xed\x83\x7e\xb0\x21\x45\x04\x66\xbe\x8b\x30\x5f\x99\x1e\x1e\x70\xbe\xa4\xbe\xa3\x3c\xdf\x1c\xf5\xda\x0a\xf0\x70\xa3\x66\xda\x14\x40\x65\xfb\xde\xe6\x50\x57\x96\x80\x7d\xc1\x4e\x45\xda\x87\xb0\xe4\x1d\x0b\x7a\xea\xcb\x56\xda\xf9\xa5\xea\xa0\x7c\x1c\xa5\xdc\xe7\xb5\x2b\x15\xf6\xe2\x1b\x73\x7c\x57\x4c\x77\x8f\xf1\xac\xf4\xa7\x8b\xf1\xd4\xed\xd5\xdd\x7e\xd1\x69\x54\xd0\x7c\xb7\x85\x7f\x7e\x83\x0a\xb2\x64\xd6\x0a\xb9\x9c\x78\xa6\x4a\x3b\x92\x34\x67\x96\x07\x2b\x7e\x3c\x67\xe4\xdb\x08\xce\xb3\x7c\xd7\x2a\xc8\xd2\xaa\x85\xc8\x11\xea\x26\xe9\x55\xdc\x3a\x60\x52\x3f\x79\xad\xcc\x3c\x78\x41\xd0\x53\x89\xed\x47\x84\xac\x37\x0d\x99\xcf\x6f\xd0\xa2\xde\xa7\x2a\xa6\xd2\x0e\xf2\xa6\x07\xae\x72\xea\xee\x5e\xc8\x52\xe7\xf0\x06\xed\xed\x7d\x9a\xc3\x1f\xb0\x12\xec\x69\x4a\x84\x53\x24\xdd\xbd\xa1\xc0\xf3\x1b\x54\xba\xf7\x69\x36\x45\x14\x26\xca\x3b\x48\x92\xfb\x2c\x88\x7b\xd0\xda\xbc\x3a\xcd\x37\x28\x9e\xef\xd3\x34\x73\x74\x94\x73\xfa\x41\xd9\xab\xbb\xbf\xe5\xe2\xef\x5e\x6e\x59\x97\xf4\x86\x73\xbe\xdf\xa7\x25\x55\xd5\x34\xf3\x8d\x31\xb5\xdf\xe3\xf4\xb9\x35\x93\xaa\xdb\x23\xd9\x9c\xdb\xb5\x32\x1e\x6a\xbd\xc8\x48\x2f\x04\x97\x8d\x10\x4e\xfc\xb6\x0b\x84\xac\xe7\x38\x48\x40\xfa\x4d\x18\x24\x44\xa7\xff\xeb\x0d\xd5\x63\xad\xa9\xd7\xb6\xfb\x0b\x7f\xf9\x66\x74\xca\x3d\xbd\x75\x10\x36\xb2\x26\x75\x74\x6b\x75\x33\x52\xb8\xe3\xca\x53\xb0\xd8\x27\x8b\xef\x84\x77\xd5\x8e\x2d\x44\xee\x64\x15\x28\xd9\x14\xc1\xcf\x70\x38\xa2\x8c\xa5\xc1\xc9\x64\x91\xde\x9e\x5a\x3f\x67\x49\x41\xe2\x71\xc4\x52\xda\x52\x5f\x82\x72\xaf\x20\x52\x06\x1c\xf7\x44\x08\x3c\x8b\x32\xa0\x3a\x62\x88\x23\xd2\x31\xab\x55\x26\x40\x3e\x1a\x62\x06\x10\xef\xcd\xa5\x5e\xda\x83\x4b\xed\x5f\x4a\x7b\x33\xc2\xd4\x4f\xbb\x0b\xe5\x71\xb2\x8a\xae\x31\x57\x57\x83\xc0\x98\x14\x51\x60\xd1\x95\x30\xa1\xaa\x1c\xa7\x11\xae\x6a\xe4\x91\x1f\x90\x74\x92\x1c\x27\x1a\x45\x10\x79\x8e\x53\x13\xa5\x07\xa4\xda\x09\x71\xdb\x34\x8b\x30\x61\x57\xcb\xe4\xa9\xba\x22\x87\xed\x40\xcf\xd7\x8a\xfb\xfb\x57\xda\xf7\x54\xee\x67\x95\x78\xbe\x56\xfc\xdf\xc3\x8f\x4b\xef\x6a\xdf\x78\xbe\xb6\x14\xbc\x87\x9f\x29\xdf\x9b\xa5\xe4\xf9\x0d\x81\x08\xef\xe1\xf7\x1f\xb0\xb9\xd4\xbb\xdb\x5c\x9e\xaf\x83\x14\x1e\xa0\x8c\xf2\x69\x0a\xf1\x1d\x89\x71\xed\xea\xe7\x7d\xd5\x2e\xe1\x2b\xc6\x07\x2e\x61\xc7\x4c\x23\x27\xd4\xa2\x6d\x56\x79\x73\xb2\xe4\x5d\x8b\xc6\x47\x85\x86\xfe\x03\x4e\xd6\xb2\x36\x4a\x10\x2a\x05\x6a\xdb\x97\xbf\x8f\x2e\x51\x44\x77\x4b\xf9\xfb\xb8\xf8\xf7\x97\x83\xfb\x2c\xfd\x08\x68\x4f\xd9\xb1\x35\x48\xbd\xaf\x18\x0f\x50\xd8\xda\x59\xcd\x6d\x1f\x86\x87\x42\x05\x84\xd0\x05\x46\x0c\x70\x73\x12\xdb\x84\x9a\x94\x2c\x23\xe1\xf0\x52\x14\x3c\x46\x79\x05\x64\xfe\xc1\xd2\x6d\x26\xe3\xba\x84\x72\x70\x80\x27\xba\xc7\x75\xe4\xee\xf4\x07\x77\x08\xfb\x0c\xff\x84\x03\xeb\x97\x87\x71\x72\xbd\x55\x73\x95\xc9\x8b\xb0\x2e\xea\xbe\x6e\x64\xaf\xf3\x3f\xf5\x5a\xbc\x91\x86\x94\x50\x72\x0e\xc1\x1d\x8c\x5c\x58\xb3\xdf\xc3\x94\x8f\x23\x3f\x01\x7b\xa9\x39\xa9\x38\x40\x1d\x61\xc6\x38\x7c\x25\x05\x87\x01\x3a\x4b\xe7\xe6\x5e\x7c\xac\x05\xd7\xcf\x16\x0e\xfd\x90\x61\x94\xef\x52\xb9\x1c\x53\x77\x72\x07\x71\x31\xed\x0f\x46\xb5\xf8\xc1\x6c\x86\x1d\x0b\x70\xa8\xc8\x9d\xa7\xd0\xca\xe1\x88\xc1\xb3\xb5\xbd\xe9\xef\x50\x5c\x79\xf4\x05\x95\x88\x01\x1e\x10\x29\x26\x42\xc8\x95\x7b\x2f\xab\x2a\x13\x9c\x4f\x6d\xab\x86\xf5\x0f\x56\x75\x59\xd7\xef\xa6\x60\xf2\x7f\xac\xdf\x0f\x5e\x15\xfb\x54\xf9\x28\xa9\xac\xbd\x2f\x9b\x3f\xbb\xa1\x24\xc2\x3f\x56\xf2\xb6\x9d\x88\x10\xda\x12\xde\xc5\xbc\xf3\x03\x6e\xd6\xb5\xe5\xf1\x1f\x4b\x7c\xeb\x12\xe7\xe6\x48\x50\x9e\xf5\x47\x60\xb9\x3f\x96\x9c\xdc\x83\xd0\xd3\xda\xf6\xfa\x0f\x7a\xba\x9d\x9e\xf4\x43\x4b\xbb\xd1\xae\xf5\x3d\x08\x86\xbc\xfd\xbe\xcd\x75\x5d\x1b\x7b\xff\xb1\xae\xb7\x0a\x75\x41\xc5\x89\xf2\x43\x46\x50\x7d\x1f\xf4\x82\xac\x82\x48\x66\x17\x3b\x1c\x7d\xf5\x7d\x05\x5f\x9d\xad\x2d\xd3\x65\xc9\x5d\xc6\x17\x97\x3d\xfd\x15\xc7\x31\x4d\x52\x82\xab\x79\x47\x95\xe6\xd4\x94\xee\x5a\xa7\x3b\x8b\xa4\xa7\xd4\x4b\x02\x2d\xd5\xf7\x8b\x2a\xfa\xbd\x92\x98\xb7\xa2\x31\x28\x81\x51\x2f\xc2\xc1\x63\xec\x76\x4a\x96\x3a\x89\x58\x8a\xfc\x72\x54\x2b\x4a\x49\xda\xa1\xa2\xd2\xeb\xea\x65\x72\x09\x27\xbd\x2d\xa7\x27\x58\xf1\x0c\x46\xc9\x4f\x62\x2b\x67\x74\xe5\x04\x83\x3a\x2b\x7b\xdf\xf9\x9c\x42\x3f\xc1\x20\x5a\x40\x78\x56\x8d\x18\xb5\xd1\xf1\x22\x14\xdd\x18\x51\x81\x4c\xa5\x07\x87\x7e\x80\xc1\x80\x0a\x1f\x4a\xb5\x38\x51\xa7\xf6\x6a\x39\x56\x7a\x8e\x05\xc7\x20\x23\x32\x8b\xcd\x38\x89\x74\xa9\x18\x2e\xaa\xe5\xa0\xee\x08\x6a\xae\x7b\x33\xba\xf6\x63\xf7\xbb\x44\xb1\xda\x1f\x11\x5d\xb4\x5e\xeb\x26\xa3\x74\xb1\x9d\x0d\x61\x09\x37\x26\x74\xa4\x3a\xb1\xa3\xb3\x53\xb3\xf3\xf5\x2d\xaf\xa7\xab\x86\xd2\x53\x93\x83\xce\xa9\xb3\xfa\x42\x21\xa0\xd2\xc8\x4c\x05\x25\x00\xda\xe8\x9b\xd5\x81\xb6\xb4\x20\x9c\xa8\x1f\xbb\x19\xd6\x9d\x9f\x52\xe0\xe2\x72\x04\xa6\x4d\x3b\xc9\x3c\xf3\xbe\x90\x03\xdb\xd1\xd8\x96\x14\x96\xfa\x61\x0b\xa3\x6f\x56\xb3\x2c\xea\xdc\x5a\xe9\xe4\xd8\x0b\x40\x6d\x53\xde\x0d\x76\xfb\xbb\x9d\x8d\x82\x32\xd3\xdc\x8b\x83\xc7\xa9\x33\x12\x09\xe1\x7d\x38\x12\x05\x14\x86\x60\xb7\x9e\xf2\x57\x8c\xff\xf6\x0c\xf7\x7e\x0c\xe4\x95\xb3\x50\xdc\xc5\x61\x28\xa7\x91\xd2\x7b\x1b\x42\x77\x76\x43\x79\x96\xf5\x59\x23\xa1\x9f\x35\xc2\x56\xb8\x7b\x92\x64\xf5\xbc\xd3\x7b\x7c\xca\x88\x32\x01\x8a\xad\x6e\x6a\xfb\xeb\x53\x48\xdc\xc1\x63\x48\xee\x76\x0a\x89\xce\xed\xda\xa5\xf0\x6f\x64\x6e\x1f\xee\x04\x97\x53\x69\x38\x96\xb1\xde\x5f\x01\x5f\xfb\x36\xfe\x8d\xcc\x32\x55\x65\x4a\x85\xee\xa3\x25\xbb\x45\x4d\xbe\xe3\x4a\xdd\x9d\xc8\x6f\xc8\xd1\xfc\x37\x32\xfd\x59\x1c\x71\x0d\x37\x6a\x1c\x0f\xc6\x3c\x4e\xf3\xf6\x6b\x36\xe7\x7c\xe5\xe7\x49\xb9\x7b\x3c\x7c\xa9\x07\xb9\x9e\x92\xc6\xcd\xe7\xba\x6c\xbe\x6c\xe5\x5f\xd9\xbf\x0c\x75\x07\x99\xca\x11\x61\xa6\x77\x7f\xed\xca\x7d\x72\xf1\x8d\x15\x07\xea\xdc\x6b\x5f\x2c\x61\xa6\x77\x1f\xcf\xca\xf3\x71\x31\x1e\x0a\x0a\x9a\x95\x0a\x6e\x88\x33\xdd\x7c\xd3\xa9\xb4\xb6\xf5\xd8\xd6\x28\x5e\xac\xed\xfe\x4c\x75\x5f\xbe\x39\x22\x13\x14\xbe\x17\x54\xd5\x42\xe2\xff\x24\xc8\x0a\x40\xa6\x76\x2f\xd9\x9f\xc4\x4a\x4c\xda\x79\xbc\xaa\x89\x0c\xd1\xc5\xd1\x93\xf9\xfe\x53\xdc\x9f\xd5\x11\x7a\xf5\xe0\xa1\x3b\xfb\x24\x0f\x20\x31\x92\x81\x70\x62\x68\xee\x4a\xa7\x62\x9b\x0c\x44\x2c\x01\x39\x0c\x9c\x07\xd5\xf2\xa8\x8e\xf0\xd5\x37\xab\x31\xe8\x70\x10\x47\x37\x02\x79\xc5\xfa\x03\xa9\x04\x08\xcd\x70\x39\x6a\x64\x29\x30\x6f\x01\x5a\x03\x4a\xeb\xf5\xba\xbd\xaa\xb2\x58\xe5\x39\x3b\xc1\xb8\x61\xcf\x79\x4e\xbd\xc4\xae\x8f\x16\x43\x20\x8d\xbb\x09\xc8\xce\x11\x46\x15\x3f\xd4\x31\xec\x30\xde\xca\xf8\xc5\x6e\x54\x0e\x7d\xda\x4c\x89\xd0\xb1\x56\x53\x22\xa4\x1f\x2c\x63\xe0\xd2\xbc\x64\x38\x1f\x05\x1f\x02\xf5\x7d\x26\xaa\xa3\xc7\xc1\x29\xce\x37\xe5\x09\x13\xe2\x2c\x70\x7a\x04\x5b\xf5\xe3\x8a\xb3\x74\x27\xb0\x21\x0e\xdb\x01\xb5\x2f\xe8\xe7\xef\xe7\x21\x32\xa7\x1c\xf8\x07\xb1\xe5\xb9\x87\x31\xe6\x6d\x4e\x30\xff\xfc\x3d\x3a\xf9\x86\xa9\x1c\xc6\xa7\x0f\x7f\x32\x8e\xbb\xf5\x68\x9c\xed\x53\x4d\x74\xfe\xe4\x7d\x9a\xbf\xbf\xdf\xc9\x41\xa7\x91\xdb\xbb\x61\xd6\x17\xf1\x7d\x9a\x49\x26\x7a\x67\x6f\xcc\x5d\x17\xc3\x3d\xc0\x6a\x1c\x26\xd6\xf4\x5e\x4d\xf1\x0f\xc4\x41\x1f\x2c\xd0\xf6\xef\xb0\xb9\x0e\x2f\x67\x7e\x9f\x96\x93\x5a\xdc\x76\x46\xfc\xdd\xf8\xf6\x69\xde\x1e\xd6\xe6\xbc\xae\x2d\x77\x94\x97\x88\x5b\x71\xa9\xc8\xcc\x5c\x76\x14\x78\x49\xcc\xd5\x4b\x2b\xb7\x49\x39\xce\x2c\xfd\x4c\x5e\x36\x2f\x81\xd8\xad\xa6\xcf\xad\x6e\x6d\x0e\xa2\xde\x61\x71\x11\xef\x69\xd5\x42\xea\xd4\x40\xec\xcc\x43\xd1\x89\x93\x1d\x65\x1a\x10\x66\x83\x33\x8c\x5a\xb2\x10\x55\x9c\xed\x82\x39\x4b\xa4\xdc\x99\x2e\x1f\x55\x7d\x0b\x2d\x44\x00\xa4\xc6\xae\x4c\xd0\x3b\xda\xe0\x11\x05\x14\x33\x4e\x6b\x1d\x08\x45\x31\xc9\xaa\xab\x5b\x7c\x90\x58\x14\xd0\x7e\x89\x70\x1a\xc5\x15\xc2\xc8\xec\x6a\x37\x75\xf6\x54\x6c\x5f\xb3\x85\xcc\x72\x0e\x2e\xd9\x49\x67\xae\x1f\x9c\xe6\xcc\xb4\x0c\xc5\xd2\xec\xca\xc7\x10\x43\x0a\xc9\x31\xa5\x91\x10\x05\x6b\xb5\x5f\x55\xf7\xb5\x12\x1e\x7c\x1b\x19\x2a\x8b\x41\x35\xaa\xc9\x33\xbb\xca\x87\xa3\x67\x5f\xb4\x9f\xbf\xff\x67\x3b\x9d\x32\x65\x47\xb1\x94\x3b\x46\xcf\xbe\x78\xf2\x63\xf8\xb8\xc8\xf5\x38\x65\x7c\xf3\x33\x9f\xfe\x18\x3e\xd3\xce\xbe\x78\x17\xe5\x7f\xf3\xfb\x9f\xfd\x18\xbe\x9f\x9a\x6c\xda\x1a\xf2\xf6\xbd\xcd\x8f\x5e\x47\xcf\xfe\x68\xce\xd1\x3a\x95\x92\xde\x91\xe4\xd7\x31\xba\xb4\x37\x6e\x31\x5d\x39\x59\x37\x35\x1a\x63\x71\x39\xa2\xa8\xad\xf9\xcf\x53\x70\xf0\xd1\x7d\x7f\x07\x7f\xce\x11\xc5\x85\xcf\x4f\x23\xbd\x27\xe7\x7f\xea\xb4\xdd\x50\xb2\xea\x47\x43\x34\xa4\xb8\x62\x6b\x03\x6d\xdf\xdb\x9a\x0b\x4a\xeb\x00\xc0\xb6\x18\xc0\x5b\x71\xa9\xe4\x59\x42\xdc\x17\x10\x29\x2e\x0a\x4d\xc8\xdb\xca\x79\x44\x16\x17\x4e\x9f\xc8\x16\xd1\x4c\x69\x57\xf3\xdd\x0a\x19\xd4\x5c\x70\xd2\x96\xa7\x8b\xb3\x4a\xed\x6c\x4d\x33\x3f\x7b\x33\x73\x9b\x2a\x10\xa5\x2e\x47\xe1\x20\x65\x4c\xc8\x72\x7a\xaa\x0e\xd4\x22\xa9\x19\x35\xf0\xec\x3c\x8c\x7e\xe2\x51\x4b\x23\x20\x31\xca\x8d\xb1\x15\xa7\x2f\x33\x05\x09\x88\xfd\x50\xa8\x80\x0a\x79\x56\x20\x2f\xdb\x99\x92\x23\xf0\x2f\xf2\x7b\x80\xd2\x7a\xa9\xfc\x4e\x6c\x49\xa9\x5c\xc2\xa1\x89\x5d\x87\xdd\xd5\x58\x8f\x07\x8a\x38\x1a\xdb\xb1\x6d\x18\xe0\x6f\x1c\x5f\x8a\xa8\x83\xe4\x2a\x4a\x15\x58\x05\xd5\x09\xa7\x78\xba\x98\xff\xfe\xde\x08\x1b\xb4\x67\xae\x0e\x87\xdb\x22\x8a\x4e\x15\x00\x1d\x3c\x44\x46\x5e\x44\x46\xff\xb2\xf7\xd4\x54\x62\x20\x94\x28\x95\x77\xf1\x3f\xb9\xdb\x1d\x50\x54\xd6\x2e\xec\x87\x48\x00\xe1\xbc\x59\x05\xe2\xb4\x6c\xdf\xdb\x1a\x26\xdf\x50\x1a\x29\xd0\xbe\x8c\x49\xe9\x87\x9d\x3c\x34\xa8\xe1\x75\x4e\x50\xab\xcb\x5b\x09\xa1\x40\x3f\x92\x10\xcd\xcd\x2f\x0c\x61\xe5\x14\x69\xb9\x1c\x68\xbe\x8e\xbd\x6f\x92\x0e\xb4\x5f\x31\xf8\xc3\xdd\xaf\xd9\xd6\xe1\xee\x57\xd1\xa0\x39\x1e\x6a\xbe\x0a\x32\x8c\x55\x0e\x34\x5f\x51\x9d\x30\x1f\x68\xbe\x32\x07\x1c\x6e\xbe\xda\x7a\x1c\xe9\x40\xf3\x55\x40\x84\xd4\x43\x33\x79\x83\x67\xff\x40\x73\x5a\x91\xc1\x3b\x9c\xb1\xc1\x81\x56\x64\xf2\x6e\xdd\xad\x4b\xf6\xbf\x53\x77\x6b\x2a\x8b\xb4\x94\xe6\x8d\xe4\xc0\x9c\xb8\xee\x28\xd4\xe5\x40\x01\xbd\x3c\xd4\xe3\x3a\x2a\x39\x97\xfd\xa1\x02\xf9\xa2\x47\xd9\x1f\x51\xa0\x97\x87\x7a\x5c\x51\x47\x0c\xbd\x16\x9c\x1d\x83\x99\x66\x6a\x8c\x43\x82\x25\x89\x25\x3d\x63\xe3\x27\xd5\x9a\x9a\x72\xb6\x78\x68\xdf\xd3\x8a\x9c\x2e\xfa\x2f\xda\x7f\x1e\x94\x41\xc5\x36\x53\x4b\x3b\x46\xf5\xdf\x16\xbb\x7f\x51\x52\xd8\x79\x8a\x07\xc7\xbf\xa2\xbf\xb8\x1c\xb3\x82\xe4\xb3\x2c\xda\xbf\xb2\x7f\xae\xd1\xfa\xe7\x8c\xfa\x74\x05\x89\xf5\x3b\x45\x0d\x87\xfa\x5f\xb1\xe6\x12\xf9\xce\xf3\x83\x58\x84\x07\x98\xcc\x95\x22\x58\x96\x6a\x3e\x77\x98\xcc\x53\x69\xf1\x21\x66\x7e\xa5\x97\x15\xe1\x4b\x33\xcf\xc9\x66\xbe\xce\x9c\xd2\x8e\xed\xe8\x93\xc5\x73\xcc\x15\xb5\xa7\xab\x0e\x86\x2e\x1a\x97\x3c\x73\x2c\x3b\x16\xba\xa1\xf1\xa1\x65\xe2\xd5\xce\x2d\xfb\x82\xed\x92\x5c\xa1\x3c\x37\x1c\x19\x15\x70\xea\x3c\xe5\xa8\x68\xd0\xe5\xb8\x9c\x73\x52\x54\xf4\x59\x75\x3e\xc4\x11\x2a\x38\x6a\x61\x39\x3d\xd7\xe7\x7e\x1c\x1d\xce\xca\xb7\x94\x40\xd6\xcb\xd8\x0b\x18\xe7\x7e\xec\xe4\xa1\x21\xae\xb1\xc5\xc5\x69\xc4\x31\xba\x30\xf3\x3e\xd5\x74\x5f\xe6\x2a\xd5\x72\xf3\x0d\x0a\xe1\xe6\x3b\x07\x06\xb0\xd2\x08\x0f\x72\x76\x59\xed\xdc\x2c\xed\xe2\xa4\x88\x14\xe9\x5d\xcf\x71\xe2\x20\xab\xdd\xbb\x3f\xc3\xa0\x86\x87\x2d\x00\xcf\x21\xad\xbe\xff\xa0\x54\xbe\xe9\x94\xa9\x05\x0b\x16\x72\x31\x25\x9c\x33\x49\x31\xcf\x04\xfd\x3f\xe6\x8b\x1f\x04\x87\x41\x88\xdb\x87\x31\x4c\x62\xe7\x4e\xc4\x34\xe2\x38\x34\x42\xf9\x72\x5f\x27\x8b\xea\xf5\x2c\x83\x47\xa4\x3f\xb7\x51\x61\x3c\x14\x6d\x24\x12\x58\xc5\x67\x33\x00\x34\xb3\x2c\x5b\x3c\x80\x1d\x7a\x8b\x83\x9a\xcc\x95\x64\x3f\xa9\x1e\xb4\x8b\x5c\xfb\x99\x99\xb8\xd2\x01\x5e\xfb\x09\xd1\x14\xad\xb9\xfe\x24\x2a\x78\x93\x1d\x68\x5c\x78\x1f\xd2\x0c\x9d\x0b\xa5\x43\x50\xcc\x12\x83\x19\x6c\x9c\x65\xb4\xa3\x21\x93\x19\xdd\x3c\xa3\x42\xb4\xea\x4b\x23\xe2\x50\xb0\x28\xd9\x8e\x8a\xb3\x80\x0b\x51\x1d\x73\xae\x98\xaa\xed\x75\xa2\xf5\x5e\xbe\xc8\x5f\x46\x87\x89\x66\x0a\x69\x27\x4d\xbf\x2c\x24\x30\x92\xd9\x47\x9c\xd4\x14\xe3\x6c\x17\x8c\x62\xab\xc9\x35\x4a\x73\x8a\xb4\xa3\xd4\x06\x3b\xc6\x34\xf3\x2e\x0f\xc4\xc1\xe9\x15\x8e\xba\xd6\xfb\xca\x60\x66\xee\x36\xf4\x41\xfb\x45\x9e\xf2\xce\x4e\x86\xa3\xe0\xb8\xd5\xa5\xf6\x19\xb7\x72\x0b\x43\x4a\x2f\xd6\xd4\x13\x96\xf3\x9e\x83\x45\x8e\x04\x15\xfc\x01\xb6\xc7\x00\xc9\xbf\x5d\x7f\xfc\xc5\xd3\x35\xc0\x25\x2e\x7d\xab\x70\x71\xb5\x94\x99\x43\xda\x51\xa6\xd9\x0e\xf4\xa3\xca\x38\x03\x0e\xa9\x23\x13\xb7\x04\x73\xd8\x08\x2b\x4d\x4f\xfa\xd8\x9f\x22\x48\x16\x3c\x94\x96\xa3\xc4\xa2\x8b\xa6\x8f\xbb\xd2\xf5\xc5\x4b\xc9\x2d\xc5\xdc\x30\x93\xef\x99\x27\x64\x67\x08\xee\x98\x70\xa2\x78\xda\x79\x5c\xd5\x62\xe7\x54\xcf\xb8\xa0\x4c\xe7\xa7\x35\xb5\x2b\xd6\x3a\x5c\x1d\x64\x5a\x2f\x9e\xde\x84\xd4\x97\xd3\xac\x7f\x2c\xdf\x5d\x12\x5f\x19\x28\x4e\xcc\xe6\x10\x2d\x89\xc3\x09\xa1\xdc\x3f\x38\x85\xc5\xa9\x5b\xa8\x3b\x0c\x10\x56\x77\x28\x5b\xb6\xc2\x80\xa3\x53\x59\x82\x1b\x7d\x11\x67\x25\x6d\x31\x4c\x1c\x84\x0f\x93\x1b\x5f\x9c\x21\x6c\xa7\xa7\xc7\x3c\xf9\xd4\x93\x6f\xd2\xec\x4b\xdc\x31\xac\x9e\x36\x62\xb9\x71\xc4\x94\x32\xdd\x31\xf6\xee\xc5\xd3\xb5\x92\xa4\x00\xfd\xc7\xb6\x54\xed\x21\x07\xea\xbe\xbf\x91\x52\x6a\x74\x70\x37\xed\xfe\x72\xf6\xe6\x95\xfb\x96\x8c\x21\x29\xfb\xf8\x96\x3f\x7c\xf4\xd7\x47\xee\x2f\x1f\x3e\xf2\xc4\x37\x35\x2a\xc7\x34\xaa\xbd\xd1\xde\xac\xa3\x4d\x39\xdd\xd2\x14\x15\x40\x6e\x6f\xf9\xe5\x31\x8d\xbe\xe8\x8d\xf2\xa1\x46\x9f\xf7\x46\x72\xbd\xd1\x47\x97\xbf\x51\x11\xcd\x8d\xb7\x27\xdc\xe6\xb0\x71\xfb\x67\x3f\xfd\x4e\x5e\xd8\x17\x95\x72\xbd\xcd\xaf\xf6\x6d\xb8\x59\x1b\x59\xf5\xf3\xeb\x7d\x1b\xd8\x9c\xfe\xa2\xc8\xe7\x7a\x9b\x8f\x2f\x8f\x74\x3d\x25\xff\xf1\xe2\x35\x06\x2e\xf5\x45\x87\x9b\x01\xb3\x1f\xd1\xec\xc9\x11\xcd\xcc\xf6\xfb\x97\x0f\x1f\xa5\x15\x99\x5c\x34\x7a\xd1\x27\x89\xeb\x81\x36\xcf\x8f\x68\xf3\xec\xe7\xb7\xce\x02\x7c\xa3\xb7\xb5\x79\x72\x44\x9b\x76\x44\x9b\x3e\xdf\x29\x1e\x68\x93\x8e\x68\x13\x8f\x68\x23\x47\xb4\xe1\xdb\xdb\x9c\x3d\xbd\x7d\xbd\xce\x9e\x1c\xd1\xa6\x1d\xd1\xa6\x1e\xd1\xa6\x1c\xd1\xa6\xcf\x61\x3e\x40\x1b\x67\xf1\x88\x36\x72\x44\x1b\x3e\xa2\x0d\x1d\xd1\x26\xdc\xde\xe6\x59\xff\x2e\xca\x2b\xfe\x74\xa9\x51\x3c\xa6\x91\x1c\xd3\x88\x8f\x69\x44\xc7\x34\x0a\xb7\x35\xfa\xdb\xe1\xcd\x3c\x1f\xbe\xfd\xed\xe1\xad\xf7\x66\x83\x9d\xf6\xdb\xe3\x61\x82\x7a\x7d\x78\x8f\x7c\x75\xf8\xe9\xb3\xc3\xb7\x9f\x1f\xbe\xfd\xec\xf0\xed\x27\x87\x49\xe6\xb3\x2e\xcd\xb6\x3e\xfc\xa3\xdb\x57\x4e\x8e\x61\xea\x7c\x94\x80\x78\xb6\xd9\xe8\x77\x97\x45\x56\x59\x4d\xf4\x27\x97\x6f\x53\x58\xdd\xff\xf4\x08\xa9\xf8\xfb\x55\x1b\xca\xab\x71\xfc\xfe\xb2\x14\xf7\xb4\x42\x0a\x7f\x58\x63\x98\xb2\x7a\xd3\x1f\x56\xe8\x65\xb3\xcd\x97\x87\x6f\x1b\x62\x59\x63\x91\x3f\x5c\xc6\x2a\xb2\x75\xfb\xb3\x0d\xa8\xf2\x2f\xeb\x8f\x48\x2b\x30\xf2\x2f\xab\x8f\xd8\x6c\xf3\xe5\xe1\xdb\x36\x4a\x5e\x51\xf0\xbf\x5c\x19\xe5\x6a\x0a\x3e\xbb\x10\x52\x7d\x90\xb4\x06\x96\x17\x8d\xce\xfa\xa2\xb6\xd5\xe7\x7e\xb6\x5e\xf8\xb6\x5a\xf8\x8b\x46\x4f\xbb\xb8\xa3\xb2\x9a\xd7\x8b\x46\x4f\xf6\x8d\xb6\x7a\x32\x5a\x4d\x5b\xb7\xdf\x6c\x60\xc0\xcf\xf7\xaf\x28\x7b\xe4\xbb\xfa\xea\xcf\xaf\x30\xb5\xd5\x2b\xfa\xed\xff\xba\xb5\xf7\x3f\x5f\xe1\xcc\x1b\xe0\xee\x17\xeb\x81\xac\xb7\xc3\x17\x97\x07\xc2\xab\x6d\xf9\xc5\x95\x81\xd0\xd6\xfd\xcb\x03\xa1\xd5\x8c\x7c\x79\x19\xae\x2e\xf2\x28\xac\x3e\xfa\xcb\x15\xb9\xb4\x15\x49\x7d\xb9\xa2\x96\xba\xa2\x96\x2f\xd7\xd4\x22\xab\xef\xfe\x72\x45\x2d\x79\x35\xcb\x5f\xae\x89\x85\x0e\xbc\xed\xc0\x72\x7f\x79\x99\x29\xad\x77\xfb\x97\x97\x17\x21\x6f\x3d\xfd\x02\xb7\xe3\xd6\x30\x17\x62\x39\x30\x67\xdc\x05\x41\x5d\x09\x9b\x2f\x8f\x21\xa8\x4b\x8d\xf2\x16\x43\xf9\xf3\x15\x1d\x6b\x35\x96\xff\x72\xc1\x93\x16\x5c\x7f\xa8\xcd\xd3\x23\xda\x3c\x39\xa2\x4d\xbb\xa5\xcd\x1f\x0f\xdf\xfe\xed\xc6\xed\x17\x97\x35\xa7\x65\xf5\x65\xb5\x49\xae\x34\x7b\x76\x5c\xb3\x76\x5c\xb3\x7a\x44\xb3\x3d\x5d\xca\x6a\xb5\x5e\x5c\x21\x9d\xbc\xda\x25\x2f\xd6\x64\x91\x56\x64\x71\xa9\x51\x39\x66\xd4\xbc\xd9\xe8\x2f\x6b\x15\x73\x4d\x85\x7f\x59\xa9\x35\x07\xdb\x3c\x39\xa2\x4d\x3b\xa2\x4d\x3d\xa2\x4d\xb9\xa5\xcd\x78\xf8\xf6\x57\x87\x6f\x9f\x1d\xbe\xfd\xfc\xf0\xed\x67\x1b\xb7\xdf\x5c\xde\xb0\x9e\x57\x24\xf2\xe6\x0a\x9e\xda\xbc\xff\xa2\xdf\x5f\xad\xe9\x7c\xe5\x3e\xad\xb8\xfe\x5f\x6f\xb0\x65\x94\x15\x0b\xfc\xeb\x0d\xa6\x8c\x5b\x5a\x3d\xb9\xbd\x95\x1c\xd1\x86\x8f\x79\xdb\xb3\xad\x36\x7f\xbb\xe5\xeb\x75\x7b\x3e\xfd\xf9\x9a\x29\xae\x96\xe9\x7a\xc3\x4d\xd2\xbf\xde\x70\x93\xfe\xaf\x37\xdc\xdc\x04\x97\x1b\xfe\xf1\x88\x36\xbf\xdd\x6e\x03\x1d\xf2\xdb\x03\x36\xb8\xcb\x6d\xb6\x0c\x71\x97\xdb\x1c\xb4\xc6\x2d\x9a\xed\x6d\x2f\xa4\x23\x5e\x48\xc7\xbe\x90\x8f\x78\x21\x1f\xf1\x42\x3e\xf6\x85\x72\xc4\x0b\xe5\x88\x17\xca\xb1\x2f\x8c\x47\xbc\x30\x1e\xf1\xc2\x78\xec\x0b\xd3\x11\x2f\x4c\x47\xbc\x30\x1d\xfb\xc2\xf2\xf3\x95\xdc\x5b\x1b\x1e\x96\x13\xee\xbe\x3d\x60\xa8\x5d\x8e\x9c\xbb\xad\xcd\x93\x23\xda\x3c\xbd\xbd\xcd\xf3\x4b\xdb\x62\x5b\x8d\x5e\x4e\x3c\x3a\xaa\xa1\x1c\xdb\x30\x1e\xdb\x30\x1d\xdb\x30\x1f\xdb\xf0\xf9\xcf\x8f\x53\x30\xae\xb5\xdd\xd6\x32\xae\x35\xdc\x56\x35\xae\x35\x3c\xa0\x6f\x5c\x6b\xb9\xad\x74\x5c\x6b\x78\x40\xf3\xb8\xd6\xf2\x80\xfa\x71\xb9\xe5\x96\x0e\x72\xb9\xcd\x96\x22\x72\xb9\xcd\x96\x36\x72\xb9\xcd\xa6\x4a\x72\x7d\xd5\x36\xf5\x92\xeb\x0d\xb7\x95\x93\xeb\x2d\x37\x35\x94\xc5\xef\x70\x9b\x5c\x86\x03\xe3\xb6\x46\x66\x7e\x39\x92\xf8\xae\x34\x3e\x48\x7d\x57\x5a\x1e\x24\xbf\x2b\x2d\x0f\xd3\xdf\x95\xa6\x07\x09\xf0\x4a\xcb\xc3\x14\x78\xa5\xe9\x61\x12\xbc\x68\x7a\x80\x06\x2f\x1a\x1d\x20\xc2\x8b\x46\x07\xa8\xf0\xa2\xd1\x21\x32\xbc\xba\x80\x87\xe8\xf0\x6a\xcb\x83\x84\x78\xb5\xe9\x21\x4a\xec\x2a\xdc\xb7\xb7\xb9\x5e\x4d\x21\x3c\xa2\xd9\xb3\xe3\x9a\x3d\x3f\xd4\xec\x2b\xfa\xf0\xd1\xb3\xd7\x5f\x7f\xfd\xe4\xe4\x9b\xb3\x37\x2f\x5f\x3f\x3f\x79\xf6\x7a\x78\xfd\xea\x64\xfc\xf6\xf5\x74\xf6\xf6\xe5\xab\xaf\x86\xa7\x4f\xde\x9e\xd9\x9f\xcf\x9f\xda\x1f\x67\xc3\xf0\xf2\x9b\xb7\x2f\xdf\x3e\x72\xff\xee\x2b\x55\x74\xfa\xbd\x4b\xcf\xf4\x07\x86\xb3\x17\x93\x5d\xbd\x79\xf9\xd5\x6e\xda\xf7\x72\xf1\xfb\xf3\xa7\x03\x6e\x3d\x72\xff\x0e\xee\x82\x74\x7d\x68\xff\xdc\x5f\xf2\x99\xb5\xb8\x6a\x64\xb8\xdc\xe0\xf3\xa5\x8b\xad\x06\x5f\x9e\x7c\xf9\xe4\xd9\xb7\xd3\xd9\xc9\x97\xcf\x5f\x9e\xbd\x39\xb3\xf1\x63\xff\x84\xeb\x8f\xfc\xea\xe4\x57\xcf\xce\x9e\xbf\x1c\x86\x27\xd7\xde\x1e\xaf\xb7\xfc\xf5\xc9\xa7\x27\x1f\x4f\xbb\x93\x4f\xbf\x7a\xf3\x64\x3e\x3b\xf9\xd4\xde\xf0\xe9\xb3\x97\x6f\x9e\x7d\xfb\xf5\x8b\xe1\xec\xbb\x93\x4f\xa7\x97\xc3\xf3\xb3\x93\x4f\x2f\xbd\x54\x7b\xfc\xe8\xe4\x23\x7b\xe4\x23\x7b\xe4\xa3\x4b\x8f\x7c\x64\x8f\x7c\xb4\x3c\x72\xf2\xd1\x9b\x97\xaf\xbe\xea\xdf\xf7\x70\x43\xd8\x9c\xd2\x7b\xf7\xb8\xac\xc1\x6a\x15\xef\xdd\xe3\xd6\xa2\xa5\xd5\x9a\xdd\xfb\x15\xf7\x27\xfe\x15\xf3\x78\xa7\x71\xfc\xe9\xc1\x27\xef\xcf\xbd\xc7\x7c\xbd\xc7\x8f\x4f\x3e\xb6\xbe\x3e\xb6\xbe\x3e\xbe\xd4\xd7\xc7\xd7\xa7\xe7\xe4\xf9\xc9\xd9\xc9\x57\x27\xe3\xc9\xb3\xbe\x27\x4e\xce\xec\xe1\x33\x7b\xf8\xec\xd2\xc3\x67\x7b\x92\x7d\x7d\xb6\xec\xae\x77\x79\xf9\xeb\x93\xd7\xd6\xf6\xb5\xb5\x7d\x7d\xa9\xed\x6b\xfb\xe8\xd7\x57\x09\x83\x57\xcc\xed\x2e\xef\xeb\x5b\xe2\x9a\x11\xfe\xae\xbd\x7c\x7b\xf2\xad\xb5\xfd\xd6\xda\x7e\x7b\xa9\xed\xb7\xd7\x86\xfb\x4e\x2f\x9a\x4f\xfe\x76\xf2\x37\x6b\xf6\xb7\xab\xfd\xae\x79\xda\x6f\x4f\xfe\x78\xf2\x47\xeb\xf9\x8f\xf6\xc8\x1f\x2f\xf5\xfc\xc7\x87\x62\x4f\x2b\xea\xfd\xdd\xc3\xd0\xd1\xfa\x83\x7e\x77\x6f\x1a\x59\x73\xbc\xdf\xdd\x63\xe5\x56\xbb\xea\x77\xb7\xae\x4a\x2c\x5b\xcf\xec\xfe\xf6\xcd\xee\xec\xd5\xc9\xb7\xaf\x5e\x86\xf0\xd1\xaf\x4f\xce\x5e\x3d\x7f\xf2\x76\x77\x72\xf6\xb5\xfe\xd7\x37\x52\x5e\xb1\x9a\xe5\xe1\x5f\x9d\xfc\xe6\xe4\xd3\x93\x3f\xec\x85\xd6\x1d\x38\xc5\xc9\xa7\x6f\x07\x7d\xd3\xa7\x1f\x77\xbe\xba\x7a\xc9\x27\x0f\x2f\xe5\xdb\xe6\x4b\xee\x4b\x76\x7e\xbd\xed\x3f\xb9\xba\xa5\x79\xcd\x88\x3e\xb9\x26\xb5\x68\x45\xbb\x9f\xdc\x22\x85\x38\xaf\x16\xf4\x93\xbb\x53\x12\xad\x28\xe9\x93\x5b\x29\x89\xe2\x6a\x3f\x7c\xf2\x3d\x50\x43\xdb\x7a\xc9\xb1\xbc\xe4\x46\x44\xb6\x74\xf2\x45\xff\x16\x5a\xcd\xe2\xef\xdf\x91\x1e\x6e\xd8\x2c\x4b\x97\x4f\x4e\x9e\x58\x97\x4f\xac\xcb\x27\x97\xba\x7c\x62\x5d\x3e\xd9\x77\xf9\xe4\x52\x97\x2b\x0a\xfb\xfd\x03\x49\xc8\x15\xd9\xfd\xfe\xde\x9c\x6d\xbb\xaf\x77\x42\x39\x52\x37\x3f\xbe\xa3\x96\xb2\xb9\x84\x1d\x84\xc8\x8a\x94\x7e\x7f\x2b\x91\xfb\x35\x61\x7c\xf6\xae\x84\x11\x56\xfb\xe6\xb3\x77\x24\x8c\x35\x37\xfb\xec\x81\x08\x23\xac\x56\x73\xe9\xf9\xeb\x93\x57\x27\xdf\x9c\xbc\xc2\xa8\x3a\x10\x5d\xb1\xb7\xcf\xee\x4d\x45\x6d\xb3\xaf\xa5\xc1\xe6\x24\x2e\x00\x8a\x56\xcb\xfd\xd9\x55\x6e\x7b\xa0\xc5\x16\xb7\x3d\xf0\xc8\x3b\x51\x37\x87\xcd\xef\xbd\x03\x17\x5f\xef\x80\xcf\x6e\x25\xf0\xb6\xf9\xcc\xed\x78\x80\xb7\x29\xf9\x01\x25\x80\x6c\x4e\xcd\x17\xb7\xee\xd1\x7f\xed\x64\xbc\xb9\x6a\xdf\xf5\x59\x58\xc1\xb1\xa5\xc1\x79\x9f\xda\x55\x83\xcf\xdf\x95\x0d\xc4\xcd\x2e\xef\xcb\x06\xd2\x4a\x31\xff\xfc\x61\xd8\x40\x5a\xf1\xde\xcf\xef\xbd\xb3\x0f\x0c\xf2\x9d\x76\xd0\x5a\xee\x7c\x7e\xf7\x1d\xb4\xa6\xb5\xcf\x6f\xc7\x41\x9b\x93\x73\xfb\x0e\x2a\x9b\xef\x7b\xc8\x0d\xb4\xda\xa5\x5f\xbc\x23\xed\xae\x87\xfd\xc5\x3b\x92\xee\x5a\x36\x7f\xf1\x40\x4a\xdb\x0a\xd9\x7e\x71\x7f\xa5\x6d\xb3\xaf\xbd\xcc\xd9\x6c\xf1\x4e\xc4\x4d\x79\x73\x7a\xee\xa2\x2e\xae\x08\xf5\x8b\xe3\x55\xbf\xb0\xe2\x56\x7f\xfa\xbe\xb4\xea\x3f\xdd\x7f\x81\x56\x5f\xf8\xa7\xeb\x22\x7f\xb5\x40\x7f\xba\xc7\x44\xae\x58\xd8\x9f\x6e\xe5\x12\x69\x73\xfe\x8e\x98\xfc\xba\x39\xea\x87\x64\x13\x2b\x29\x7a\x23\x0a\x7a\x27\x99\xb7\xd6\xe6\x36\xdf\x71\x6f\x2c\xbc\x9a\xab\xcd\x57\xbc\x2b\x38\xe6\xe3\xbf\x66\x8d\x96\xd7\x60\x6d\xf3\xe1\x7b\x28\x61\x71\x45\xa2\x9b\xbd\xef\xc5\xd8\x8a\x42\x37\x1f\xd9\xb6\x51\x6e\x3e\xb2\x6c\xc0\x3b\xbc\x65\x13\x84\xdf\xa1\x8f\x77\xc3\x14\x6b\x63\xd9\xe6\x8b\xee\x02\xd3\x57\x48\x65\xb3\xd7\x6d\x7e\xc2\x2b\x11\xbc\xd9\xc9\x11\x0c\x66\x6d\x8e\xdc\xec\xed\x21\x39\xce\xf1\x44\x7a\x07\x63\x4f\x3e\xfe\x5b\xbe\xb8\x3b\x1d\x6f\x6a\x14\x9b\x4f\x7c\x77\xe7\x8f\xed\x3a\x47\x5c\x49\xb3\xcd\x27\x7e\xbb\xc9\x5f\xff\xfc\xae\x66\xcd\x35\xae\xfe\xf3\xc3\xb0\xcf\xb5\x14\xfd\xf3\xfd\x5d\x2e\x9b\x7d\xbd\x13\x3e\xfa\xf3\xed\x4e\x8e\x15\xb1\xfd\xf9\x87\x00\xf0\xf7\x12\x8e\x0f\x6b\x42\x5f\xbb\x3f\xef\x3d\xa8\x03\xba\xd5\x8a\x01\x3f\x3d\xf9\xe6\x64\xda\xbd\x7e\xf3\xea\xc1\x3f\x28\xae\xf6\xce\xf5\x77\xdd\x45\x07\xbc\xfe\xec\x77\xc7\x7e\xd0\xf9\x56\xc3\x67\xfb\x6d\xf6\xf0\x9f\xbe\x1a\xfe\xd9\x31\x5b\xf9\xc1\xc7\x21\x2b\x3b\xe6\x5d\xc6\x71\x60\x79\x56\x3c\x6c\x77\xa2\x88\x6c\x8f\xc7\x1e\x78\x6b\xac\x20\xe8\x1d\x39\xda\xc3\x0e\x67\x2d\x10\xef\x31\x9c\xbb\xec\xd1\x7b\x74\xff\xdd\x96\x02\x77\x8f\xbe\xce\xb7\x44\xf4\x9b\x07\x9f\xda\x1b\xec\xc1\x6f\x1e\x44\xe1\x8f\x2b\x12\x7a\x73\xbb\xaf\x62\xed\xe6\xda\x68\xfc\x4e\x4e\xa8\xd5\x72\x1f\x78\xc9\x83\xfb\xa5\x0e\xbc\xeb\x1e\x5a\xd2\x9d\x3e\xe5\xdd\xd6\x73\x25\x2d\xbf\x7b\x20\x14\xb5\xd2\x03\xbe\xbb\x3f\x8a\x5a\xd1\xcf\xf9\x03\xad\xe3\x6a\x97\x9c\xdf\x7f\xd1\x7a\x5f\x1f\xbc\x78\xfd\x6a\xd2\xff\x9f\x9f\xbd\x78\xfb\xcb\x5f\x7c\xf0\x76\xfe\xea\x97\xee\xff\x0b\x00\x00\xff\xff\xa4\x49\xfe\x60\x83\x16\x01\x00") func fontsRobotoBoldWebfontSvgBytes() ([]byte, error) { return bindataRead( _fontsRobotoBoldWebfontSvg, "fonts/roboto-bold-webfont.svg", ) } func fontsRobotoBoldWebfontSvg() (*asset, error) { bytes, err := fontsRobotoBoldWebfontSvgBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "fonts/roboto-bold-webfont.svg", size: 71299, mode: os.FileMode(509), modTime: time.Unix(1492020681, 0)} a := &asset{bytes: bytes, info: info} return a, nil } var _fontsRobotoBoldWebfontTtf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xa4\xbd\x07\x7c\x54\xd5\xf6\x3f\xba\xd6\x69\xd3\xcb\x99\x9a\x64\x52\x66\x32\x29\xc0\x24\x4c\x32\x93\x10\x26\xb4\xd0\x82\x74\x08\x20\x5d\xe9\xa2\xd2\x55\x40\xaf\x15\x14\x11\x15\xcb\xc5\x72\x2d\x60\x17\x45\x74\x9f\xc9\xa8\x58\xae\x22\x8a\x22\xe2\xb5\x47\x51\x50\xb0\xe1\x88\xd8\xbd\xf7\x2a\xe4\x9c\xf7\xd9\xfb\xcc\xa4\x00\xe2\xef\xfe\x1f\x71\x66\x4e\xdd\x67\xaf\xb5\x57\xf9\xae\xb5\xf7\x3a\x02\x02\x80\x1b\x01\x04\xa8\x6a\x6c\x1c\x3f\x72\xc6\xd6\x31\xbb\x01\xb0\x37\x00\xe4\x0f\x19\x34\xb8\x91\xfb\x19\xdf\x05\xc0\x49\x00\x50\x31\x64\xcc\xe8\x71\xcd\x81\xcb\x46\x02\xe0\x95\x00\xb6\xcf\x87\x8c\x9b\x30\xa0\xec\xe5\xe0\x07\x00\x8e\xf9\x00\x30\x63\xf4\xb8\x68\xec\x99\xe2\x63\x97\x01\x38\x76\xd1\xfd\xd9\x0b\x67\x2e\xf9\x6a\xcf\x80\x6e\x00\xce\x2e\x00\xf8\xf9\xec\xe5\xe7\x07\x73\x72\xe4\x19\x00\x2e\x2b\x00\x0c\x98\xb7\xe4\xac\x85\xe3\x52\xd1\x87\x01\x5c\x63\x00\xb8\xb9\x67\xcd\x3c\x6f\x09\x00\x38\x01\x3c\xdb\x00\xc0\x78\xd6\x82\x0b\xe7\xe5\x0e\x92\x9e\x01\xf0\x6c\x07\xb8\xfe\xd7\xf9\x73\x67\xce\x11\xbb\x5e\x39\x11\xe0\xbe\x14\x00\xf4\x98\x3f\x7f\xee\x4c\xc7\x05\x52\x35\xc0\x7d\xdf\x01\x40\xc9\xfc\x85\xe7\xaf\xfc\x60\xc0\x80\x3e\x00\xf7\x3b\x01\xf8\xcd\x0b\x16\xcf\x9e\x39\x6d\x5e\x3d\x00\x3c\xb4\x0d\x00\x5b\x16\xce\x5c\xb9\x84\x33\x20\x01\xd8\x7c\x23\x00\x04\x17\xcd\x5c\x38\xb7\xf1\xa7\x95\x31\x80\xcd\x04\x80\xaf\x5a\xb2\xf8\xbc\xf3\xf3\x2e\x8e\x3d\x04\xb0\xe5\x00\x00\xf7\xd5\x92\x65\x73\x97\xdc\xb9\xe8\x81\x7b\x00\x1e\xdf\x05\x80\x43\x56\xcc\x9d\x35\xef\xbb\x91\xe3\x26\x03\x10\x27\x00\x48\x00\x8c\x7b\xb0\xa7\xcf\x7d\x6f\xd1\xdf\x57\x7e\x94\xbb\xd3\xdf\xb7\x2e\xbb\x6b\x0f\x3b\x63\xa7\xbd\xa2\x47\x80\x03\x1e\x10\xbe\x02\x84\xaf\xe1\x6b\xe0\xe0\x10\xa4\x01\x41\x60\x67\xf4\x56\xcc\x50\x05\x7d\x81\x1b\xd4\x38\x62\x3c\xd8\x17\xcc\x3c\x7f\x11\xe4\xb1\xf3\xa0\x69\xec\x7c\xc7\x6d\x3c\x77\xee\xb2\x45\x60\xcc\xdc\x49\xdb\xe1\x58\x4b\x66\x7e\x0e\x20\xf7\x3d\xbb\xb6\x06\x96\xc1\x32\x58\x09\xeb\xe1\x2e\xb8\x0f\x36\xc3\xe3\xb8\x04\x97\xc3\x7d\x78\x31\xae\xc1\x7b\xf0\x29\x7c\x1f\xbf\xc6\xff\x72\x31\xae\x27\xd7\xc4\xad\xe4\x1e\xe2\x52\xdc\xb3\x5c\x8a\x7b\x1f\xd6\x77\xf8\xbb\x0b\x36\x67\xfe\xee\x6b\xff\xc3\xff\x72\x29\x2e\x85\xff\x65\xed\xd3\x3f\x84\x29\x60\x05\x11\x12\xe0\x87\x7a\xc8\x83\xde\x90\x0b\x9b\x20\x17\x5e\x81\x5c\xe0\xa1\x58\x6b\x86\x89\xda\x77\x30\x45\xdb\x0b\x08\x56\xed\x73\x40\x58\xab\xbd\x4c\xef\xd2\x0e\x41\x15\x38\xd4\xe7\x40\x56\x9f\x83\x02\xf5\x39\x28\xd1\xa6\x43\x1d\x78\x60\x90\xf6\x3c\x34\x6a\x7b\x60\x88\xb6\x07\x4e\xd3\xf6\xc0\x30\x6d\x0f\x34\x69\xbb\x61\xbc\xb6\x07\x26\x68\x9f\xc3\x24\xed\x10\x4c\xd6\xbe\x84\x69\xda\x97\xb0\x4a\x9b\x0e\xab\xb5\xe9\x70\xa5\x36\x1d\xae\xd2\xa6\xc3\x1a\x6d\x3a\x5c\xad\x4d\x87\xfb\xb4\xe7\xe1\x7e\xed\x79\x78\x40\x7b\x1e\x1e\xd4\x9e\x87\x87\xb4\xe7\xe1\x61\xed\x79\x78\x44\xdb\x03\x8f\x6a\x7b\x60\x8b\xb6\x07\x1e\xd3\xf6\xc0\x56\x6d\x0f\xa4\xb4\xdd\xf0\xa4\xb6\x1b\x9e\xd2\x76\xc3\xd3\xda\x6e\xd8\xa6\xed\x86\xe7\xb4\x43\xf0\xbc\x76\x08\xfe\xa9\x1d\x82\x17\xb4\x43\xf0\xa2\xf6\x25\xbc\xa4\x7d\x09\x2f\x6b\x7b\x60\xaf\xfa\x1c\xec\x53\x9f\x83\x4f\xd5\xe7\x18\x1d\x4f\xb1\xef\xdb\x81\x83\x89\xe0\x84\xb5\xda\x54\x90\xa0\x4e\xdb\x0b\x09\xed\x33\xa8\xd7\xd2\xd0\x5b\x7b\x06\x36\x69\xcf\xc0\x2b\xda\x33\x20\x42\x9d\x76\x10\x12\xda\xb7\xd0\x5b\x7b\x0d\x36\x69\xaf\xc1\x2b\xda\x6b\x60\x80\x09\x5a\x33\x4c\xd1\x5e\x87\x85\xda\x58\xb8\x44\x1b\x07\x6b\xb5\x3e\xb0\x59\xbb\x1b\x9e\xd5\x6e\x04\x01\xac\xe0\x87\x06\xf0\xc0\x04\x6d\x3f\xcc\x00\x1f\x3b\x22\x43\x03\xd8\x61\x82\xf6\x0d\xcc\x00\x27\xd8\xc1\xa4\xbd\xc6\xae\xb3\x69\x9b\xa1\x01\xbc\x30\x54\xfb\x08\x26\x68\x3b\x60\xa2\xf6\x19\xbb\x67\xa1\x76\x0d\x5c\xa2\xbd\x02\x6b\xb5\x95\xb0\x59\x7b\x18\x9e\xd5\x1e\x84\xfd\xda\x6d\xac\xef\x07\x41\x82\x4a\xed\x30\xf4\xd4\x0e\xc3\x9d\xda\x61\xb8\x4b\x3b\x0c\x77\x6b\x87\x61\xa3\x76\x18\x4c\x20\x42\x31\x98\xa1\x18\xac\x50\x0b\x0d\x30\x00\x66\x40\x29\x7c\x08\xc5\xf0\x11\x14\xc3\xc7\x50\x0c\x9f\x40\x31\x58\xa0\x51\x4b\xc3\x10\x2d\x0d\xa7\x69\x69\x18\xa6\xa5\x61\xbc\x96\x86\x47\xb4\x34\x3c\xaa\xa5\x61\x8b\x96\x86\xc7\xb4\x34\x6c\xd5\xd2\xf0\xb2\x96\x06\x1e\x86\x42\x0e\x4c\x84\x00\x4c\x81\x00\x20\x0c\x05\x07\x48\xe0\xd0\xb6\x81\xac\x6d\x83\x02\x6d\x1b\xec\xd5\xb6\xc1\x3e\x6d\x1b\x7c\xaa\x6d\x63\x7d\x4b\x43\x4f\x2d\x0d\x77\x6a\x69\xb8\x4b\x4b\xc3\xdd\x5a\x1a\x36\x6a\x54\x87\x6a\x40\x04\x33\x58\xa0\x04\xca\xa0\x1c\xba\x40\x57\xe8\x0e\x51\x88\x41\x1c\x6a\xa0\x16\xea\x20\x01\xf5\xd0\x1b\xfa\x40\x5f\x18\x0a\xa3\x60\x02\x4c\x86\x29\x30\x0d\xce\x80\x55\xb0\x1a\xae\x84\xab\x60\x0d\x5c\x0d\xd7\xc0\x3a\xb8\x16\xae\x83\xeb\xe1\x66\xd8\x00\xb7\xc0\xad\x70\x1b\xdc\x0e\x9b\xe0\x45\x78\x09\x5e\x81\x0f\xe1\x23\xf8\x18\x3e\x01\xce\x74\x07\xd5\x2c\x83\xcf\xd8\x08\x45\x50\x00\xa0\x7d\xa0\x35\x69\x4f\x68\x0f\x68\x69\xed\x11\xed\x11\xf8\x1f\xfe\xa9\x5f\xfc\x2f\x57\xff\xf9\x3f\xed\xa0\xf6\xa5\x76\xa9\xf6\xf2\xff\xc3\x9d\x9f\xfe\x4f\x57\x7f\xd3\xe9\x99\x87\xb4\x7f\x01\x68\x9b\xb5\x43\xda\xd7\xda\x9b\xff\x87\xbb\x7f\x01\xd0\xbe\x05\x00\xcf\x71\xc7\xbf\xd3\x3e\x3f\xc5\x5d\x87\xfe\x97\x1e\x9e\x70\xf7\xe7\xb4\xa7\x27\x39\xfe\xb5\xf6\x8e\x36\x49\x7b\x55\xbb\xf9\xc4\x73\x6a\x0b\xf8\x3a\x5c\x19\xd1\xba\xaa\xbf\x75\xd8\xff\x51\x3b\x1f\x40\xdb\x09\xa0\x7d\xa9\x5d\x7b\x42\xbb\x93\xb4\x5f\xb5\x9f\x00\xe8\xa7\xad\xbd\x55\x5a\xb3\xb6\x57\x9b\x07\x00\x72\x87\x2b\xef\x3d\xee\xce\xbb\xb4\x8d\xda\x6d\xda\x56\xed\x7e\xed\x21\x70\xb3\x3f\xd0\x6a\xd9\x99\x1d\x5a\xb3\xb6\x49\xeb\xa9\x7d\xa6\xcd\xa1\x6d\x68\xf3\xb4\x23\xda\x83\xda\x33\x6d\x77\x9e\xa7\xed\xd6\xf6\x00\x68\xbb\x3b\xb4\xd6\x35\xf3\xfb\x99\xf6\xab\xf6\xf4\x9f\xf1\x57\x7b\x5a\xdb\xab\xed\x03\xa0\x1f\xea\x6f\xd9\xb1\x89\x99\xdf\x6f\x01\xb4\x3b\x4f\x7e\x5f\xe6\x0a\xca\xdb\x03\x6c\xd3\xd9\xe1\xb0\x47\xfb\x46\x7b\x53\x6b\xd4\x3e\xd1\x9a\xf5\xfd\xe3\xee\x9a\xa9\xdd\xa3\x5d\xa6\x35\x6b\x4b\xb4\xab\xc1\x03\x5e\xf0\x02\x68\xa6\xcc\xb9\x27\xb5\xb4\x76\x09\x95\x49\xed\x65\x7a\x9f\x76\x44\xfb\x54\x6b\xd1\x66\x66\x6e\x75\xe8\x12\xd8\x51\x0a\xdb\x5a\xfd\x96\x8e\xf2\xc9\xe9\xa4\x52\x7a\x4a\x3a\x7e\xf8\xd3\x33\x6f\xfd\xc5\x9d\xbf\x76\xd8\xfe\x91\xb6\x94\x6d\x4b\x6b\x39\xf5\x9d\xa7\x68\xf3\xe3\xbf\x38\xff\xd3\x9f\x9e\xd9\xf5\xff\xfc\xcc\xbf\xb0\x1c\x1d\x39\xa4\x1d\xa1\xa3\x4e\xbf\xd9\x3f\xf7\x49\xaf\x5f\xd4\xb6\x99\x7f\xea\x76\x99\xae\x74\x6c\xfd\xfc\x93\x5e\x77\x12\xca\xb4\x34\xd5\xc0\x53\xf7\xfb\x4f\x9e\x7a\x44\xff\xfc\x8f\x77\x0d\xd0\x1a\xb5\x7a\x6d\x86\x36\x4a\x1b\x07\x56\xf6\x07\xea\xdf\xd9\x99\x55\xda\x39\xda\x69\xea\xed\x5a\x4a\xa5\xf2\x67\x54\x0f\x69\x7b\xb4\xa6\x2c\x25\x5a\xaa\x53\x2b\xd7\x6b\x2f\x68\x1b\x4f\x26\xc1\x6d\x57\x6c\x67\xdf\xcc\x33\x68\xb7\x68\xf7\x68\x8a\xb6\x53\x53\xb4\xdd\x54\x4f\x98\xae\x44\xd8\x99\x97\xd8\xf7\x0c\xed\x6b\xed\x6b\xb6\xf5\xc4\x49\x5a\x4a\xeb\x9f\xbf\xa0\xeb\x9d\x4e\x7b\x33\xff\xe2\x6a\x66\x75\x98\x15\xd7\xf7\xb3\x1a\xc0\x41\x0c\x1c\xe0\x00\x04\x19\x64\x40\x28\x80\x02\x40\x28\x85\x52\xe0\xa0\x0c\xca\x80\x87\x72\x28\x07\x01\xba\x40\x17\x10\xa1\x12\x2a\x41\x82\xee\xd0\x1d\x0c\x10\x85\x28\x18\x21\x06\x31\x10\x20\x0e\x71\x30\x41\x1d\xd4\x81\x19\x7a\x42\x4f\x90\x20\x01\x09\xb0\x40\x3d\xd4\x83\x15\x7a\x41\x2f\xb0\x41\x6f\xe8\x0d\x76\xe8\x03\x7d\xc0\x01\x83\x60\x10\x38\x61\x30\x0c\x06\x19\x1a\xa1\x11\x5c\x70\x1a\x9c\x06\x6e\x18\x0e\xc3\xc1\x03\x63\x60\x2c\x78\xa0\x09\x9a\xc0\x0b\xe3\x60\x1c\xc8\x30\x01\x26\x80\x0f\x26\xc3\x64\xf0\xc3\x54\x98\x0a\x39\x30\x0d\xa6\x81\x1f\xa6\xc3\x74\xc8\x85\x6b\xe0\x1a\xe0\x61\x1d\x5c\x0f\x22\xdc\x0c\x37\x83\x00\x1b\xe0\x76\x10\xe0\x4e\xd8\x08\x12\x6c\x82\x4d\x60\x87\xfb\xe0\x61\x70\xc2\x23\xf0\x08\xb8\xe0\x51\xd8\x0a\x6e\x68\x86\x66\xf0\x40\x0a\xb6\x81\x17\x5e\x84\x17\xc1\x0f\xdb\x61\x3b\xc8\xf0\x12\xbc\x04\x7e\x78\x05\x5e\x01\x3b\xec\x05\x8a\x7a\xf7\xc1\x3e\x40\xf8\x14\x3e\x05\x04\x0e\x7a\x82\x08\x22\x20\x98\xc1\x0c\xc8\x78\x67\x05\x27\x38\xc1\xc5\x38\x68\x65\x1c\xb4\x42\x09\x94\x64\x38\xe8\x86\x6e\xd0\x0d\xdc\x8c\x77\x01\xc6\x2f\x37\xd4\x40\x0d\xb8\xa1\x07\xf4\x80\x1c\xc6\x35\x23\xe3\x9a\x97\x71\xcd\xc4\xb8\xe6\xeb\xc0\x35\x33\xe3\x9a\x9d\x71\x8d\x87\x46\x38\x0d\x04\x18\x06\xc3\x40\x60\x9c\x12\x19\xa7\x24\xc6\x29\x11\xc6\xc3\x78\x10\xe0\x74\x38\x1d\x0c\x30\x09\x26\x81\x93\x71\x4d\x66\x5c\xcb\x65\x5c\x93\x19\xd7\xf2\x60\x31\x2c\x06\x17\xac\x82\xab\x81\x63\x1c\x74\x33\xae\xb9\xe1\x0e\xb8\x03\xdc\x8c\x77\x5e\xc6\x3b\x33\xe3\x1d\x0f\x8f\xc0\x56\x10\x18\xd7\x44\xc6\x35\x09\x9e\x83\x17\xc0\xc9\x78\xa7\x73\x4d\x86\x1d\xb0\x03\xdc\xf0\x32\xbc\x0c\x02\xe3\xa0\x19\x3e\x80\x16\x70\x31\x0c\x86\x8c\x9b\x56\x86\xc5\x74\x9e\x5a\x19\x4f\xad\x80\x30\x9a\xa1\x40\x07\xc8\x50\x00\xa5\x19\x24\x58\xd9\x86\x04\xeb\xa0\x27\xc3\x81\xbd\x18\x12\x1c\x04\x83\x19\x0f\x86\x33\xea\x9b\x60\x1c\x43\x85\x53\x61\x1a\x4c\xff\x13\x24\x78\x27\xdc\x05\x77\xc3\x46\xd8\x04\xf7\xc1\xfd\xf0\x00\x3c\x08\x0f\xc1\xc3\xf0\x08\x3c\x0a\x5b\xe0\x31\xd8\x0a\xcd\x90\x82\x27\xe1\x29\x78\x1a\xb6\xc1\x8b\xb0\xbd\x0d\x35\xee\x65\x7d\xdd\x07\x9f\xb6\xc5\x78\xdd\xa1\xf7\xff\x21\xc6\x03\xc0\x05\x67\x9f\x35\xb3\x53\x84\x27\xb0\x5f\x23\x20\xb8\x32\xbf\x02\x8b\x24\x47\x00\x32\xfc\xcc\x0b\xdd\xb9\xe7\x41\x04\x41\xbc\x43\x8c\x03\x60\x91\xfe\xcb\xbf\x03\xf3\xb8\x4c\x98\xa9\xff\x3b\x00\xdc\x0f\x63\x20\x38\x95\x46\xc0\x74\x7f\xc8\xe2\xc5\x67\x41\x10\x6c\x47\x05\x69\x9e\x3a\x0f\xc0\x78\x31\x37\x2e\x08\xb8\x69\x34\x02\x08\xf5\x22\x61\xd7\xd1\xdb\xf9\xcc\x27\x5f\x8f\x7a\x61\x1f\x8b\x69\xe9\xbe\x00\xd4\x76\x55\x40\x90\xc5\x25\x00\x36\xb8\x14\x34\x1c\x87\x2b\xb9\x57\xb9\x7d\x41\x73\xd0\x13\xcc\x0b\x16\x06\x8b\x83\x65\xc1\x68\xb0\x3e\x78\x66\xf0\xb1\x50\x71\xe9\xb1\xa3\x02\xa3\x94\x5e\x1d\x84\x7b\xb0\x29\x73\x35\x04\x9d\xc1\x9c\x60\x7e\xe6\xea\x44\xdb\xd5\x48\x79\xa4\xfd\xa6\x7d\xa1\xed\xd0\x96\x68\x23\x5a\xb5\xd6\x6f\x0f\xbc\x76\x60\xc7\x81\x17\x0f\xbc\x70\xe0\xb9\x03\xdb\x0e\x90\x03\x0f\x1f\x58\x7d\xa0\xee\xb3\x1d\x1f\xa7\xc5\xaf\x32\x3d\xfc\x3f\xff\x43\x09\xda\x6e\xc1\xce\xec\xca\x1c\x04\xe0\x05\x51\x32\x18\x4d\x66\x8b\xd5\x66\x77\x38\x65\x97\xdb\xe3\xf5\xf9\x73\x72\xf3\x02\xf9\x05\x85\x45\xc1\x50\x71\xb8\xa4\xb4\xac\xbc\x4b\xd7\x6e\x91\x8a\xca\xee\xd1\xaa\xea\x58\xbc\xa6\xb6\x47\x5d\xcf\x44\x7d\xaf\xde\x7d\xfa\xf6\x6b\xe8\x3f\x60\xe0\xa0\xc1\x8d\x43\x4e\x1b\x3a\x6c\xf8\x88\x91\xa3\x46\x8f\x19\xdb\x34\x6e\xfc\x84\xd3\x27\x4e\x9a\x3c\x65\xea\xb4\xe9\x67\x9c\x39\x63\x26\xac\xb9\xfa\x9a\x6b\xff\x7e\xfb\xc6\xfb\xef\x7b\xe0\xa1\x07\x1f\x7e\x64\xcb\xa3\x8f\x6d\x7d\xe2\x71\xa2\x34\x3f\x99\x7a\x6a\xdb\xd3\xcf\x3f\xf7\xcf\x17\x60\xd9\x9c\xb9\x67\xef\x5f\x79\xef\x92\x73\xbf\x5c\x7e\x0e\xac\xbd\x03\xce\x03\x38\x6b\x05\xeb\xdd\x82\x8b\x61\xf3\xb3\x57\xcc\x66\xce\x77\xe1\x25\x9f\xce\x5a\x75\xd5\x6d\x3b\x5e\xfe\xa0\xe5\xe3\x4f\x3e\xfc\xe8\x19\x78\xe9\x15\xf8\xe2\xc0\xc1\xaf\x0f\xc1\x85\x7b\xf7\xc1\x95\xd7\xad\xbe\x7e\xdd\x0d\x37\xde\xb4\xfe\x96\x5b\x61\xc3\x5d\x77\xdf\x09\x3b\x5f\x5d\x0a\x00\x17\x65\xc8\x64\xe3\x7d\x10\xad\xf0\x12\xec\x82\x37\xe1\x03\xd8\x0b\xfb\xe1\x2b\x38\x02\xad\xf0\x20\x96\x60\x3d\x5a\xd1\x85\x39\x58\x88\x25\x58\x83\x46\x48\xc1\x6e\xf8\x02\x9e\x83\x6f\xe0\x45\x2c\x86\x41\xa2\x0c\x40\xa0\x82\x80\x7b\x38\x19\x31\x66\x12\x19\xb6\x7c\x32\x81\x70\xbf\x1c\x22\x45\x26\xf5\x99\xcc\x8e\x5d\x32\x39\xf8\x3e\x41\x77\xf7\x9c\x4a\x82\x15\xc1\x8f\x89\x35\x52\x49\xb8\x8a\xe1\x4d\x93\x06\x87\x27\x87\x2a\x09\x5f\x71\x76\x4e\x90\x34\x8c\x99\x14\x22\x0d\x93\x2b\x89\x50\x41\x6f\x0d\x85\x43\x17\x4d\xda\x1f\x78\x73\x72\x60\x78\xd3\xa4\x49\xad\x81\x23\x93\x03\xe1\x10\x11\x23\x93\x48\xe3\xf2\xc9\xec\xc4\xe4\xc9\x39\x95\x44\xac\xb0\x4d\x9b\x52\x49\xa4\x0a\xa5\x18\xd7\x8e\x99\x44\x82\x6b\xa7\x4d\x0b\x10\x98\x5c\x49\x0c\x15\x4a\x09\x3b\xd4\xd0\x76\xc8\x58\xe1\x92\x83\x89\x68\x25\x31\x55\x04\x2f\xa1\x0f\x79\x25\xf0\xe6\xe4\x20\xe1\x4b\x87\x86\x83\x44\x28\x1b\x46\x60\xcc\xa4\x75\x73\xd7\xcd\x0c\xd2\x8d\x9e\x81\x50\x68\x72\x60\x1d\xdb\x6b\xd2\xf7\xe8\x03\xcd\x7a\xef\x9c\x01\x67\x68\x72\x25\xb1\x54\x04\xdf\x65\xe4\x58\x2b\x82\x51\x62\x88\x4c\x9b\x14\x0c\x0e\x09\x37\xce\x3c\x27\x38\x29\x38\x67\x96\xde\x04\xbd\xce\x46\x9f\x1c\x4c\x44\x83\xeb\x82\x43\xd6\x35\xce\x0c\xaf\x0b\xae\x0b\xb3\xc7\x85\x69\xe3\xa4\xa1\x67\x20\x34\x39\x10\xa6\x07\x48\xc3\x5c\xba\x33\xb9\x92\xd8\xd9\x93\xfa\xb4\xe4\x84\x42\x81\x60\xcb\xba\xe1\x4d\x93\x82\xeb\xc2\x43\x83\x04\x26\x64\xfa\x16\x62\x97\x39\x2a\xc2\xc1\x96\xcc\xc3\xc3\xc1\x49\xc3\xc7\x05\x42\x04\x27\x4f\x5a\x47\x84\xb2\xa1\xe1\x75\xe1\xe0\xba\xa1\xeb\xc2\x33\xe9\x0d\xfa\x2d\xf4\xa7\x92\x38\xe9\x30\xb8\x22\x95\x44\xa6\x04\xd0\x0d\xd7\x71\x04\xac\xa3\x3f\xe1\x99\xe7\xcc\xe8\x48\x09\xbd\xd5\x5d\x11\x5c\x17\x5c\x77\x35\x65\xdb\xb0\x39\xe1\x75\x06\x12\x1c\x33\xa9\x77\x60\xfb\xe4\x4a\xe2\xa9\x68\x86\x06\x6c\x18\x30\x00\x87\x6f\x73\xc2\x6c\x60\xdf\xf4\xe2\x09\x93\xe8\x77\xd3\xa4\xf0\xac\x20\x81\xf0\x80\xc0\xac\x20\xc1\xf0\x80\xc9\x41\xd2\xd0\x34\x29\x09\x41\x18\x38\x7b\x40\x12\x83\x38\x70\xf6\x00\x12\x9c\x4d\x72\xe7\xe6\x67\x9f\xe5\xad\x20\x38\x70\x76\x98\xc0\xc0\xd9\xe1\x4a\x5d\x23\xa9\x45\x70\x00\x07\x83\x00\xb8\x39\xe2\x04\xe0\xc1\x00\xdd\x15\x84\x68\xef\xa4\x41\x28\x3a\x12\x53\x24\x71\x5f\xef\x24\xcf\x15\x1d\x89\x81\xc2\xd3\xc3\x22\x3d\x9c\x34\x48\xc1\x63\xbd\x93\x48\x8f\xc7\xe5\x90\x5c\x1a\x92\x43\x83\xb8\xa0\x5a\x82\xb7\xab\xf3\xc5\x09\x7f\x6c\x19\x24\xbc\xc9\x2c\xc0\x1a\x00\x7c\x54\x24\xac\xdd\x38\x24\x01\x20\xa2\xa0\x2d\x9d\x14\x39\x88\x20\x31\x46\x09\xb4\x10\x21\xa6\xf0\x8e\x34\x91\x62\x8a\xc1\x91\x56\x4c\x18\x01\x45\x44\xd9\x45\x84\x44\x55\x35\x6d\x1c\xe5\x90\xbc\x06\x4b\xd4\x7d\x58\x82\xa0\x01\xfe\x9b\x7f\xf6\x58\x23\xc5\x4c\x82\x83\x3b\x43\x0a\x80\x00\x26\xa8\x01\x02\x51\x22\xc6\x53\x28\x80\x51\x88\x10\x29\x86\xc4\x4c\x5b\x4f\xf1\x7e\xc8\x15\x22\x84\x77\x2a\x22\x46\x52\x46\xb6\xa7\x58\x30\x02\x55\xd5\x6e\x39\x2e\x1b\xe2\xf4\x2b\xf6\xf5\xbc\x57\xbf\x9e\x27\x38\x38\xab\x7a\xe4\x77\xf6\x05\x1c\x54\x01\x08\xd7\x89\x04\x02\x50\x84\xf3\x20\x99\x07\x10\x49\x7a\x7d\xb9\xf1\x78\x3c\x69\xe0\x20\x92\x34\x5a\xac\xf1\x78\x3c\x05\x98\x67\xb0\x45\x9a\x39\x39\xbf\xa0\xc4\x1f\x57\xc0\x9e\x6e\xf6\xf8\x73\x02\x25\xfe\x58\x4a\x14\xd8\x29\xde\x59\x58\x44\x4f\x89\xf6\x74\xb3\x64\x32\xdb\x4a\xfc\x31\x24\xc1\x28\xc9\x6b\x49\xe5\xfa\xc1\x22\x44\x48\xae\x53\xf1\x61\x24\xe5\x65\x7b\x49\xaf\xcf\x1c\x69\x6e\xf0\xba\x4d\x91\x66\xa3\xd7\x67\x8c\xa4\x0c\xfa\x55\x86\x28\xed\x3f\xbd\xc2\x60\xa4\x57\x18\x04\x53\x84\x78\x9d\x94\x9a\x94\x95\x9d\x50\x42\x18\x21\x3d\xf2\x9e\xed\x67\xfc\xf5\x5b\xf0\x46\xcc\xcf\xf6\x33\xfd\xfa\x23\xdd\x20\x79\xce\x66\x2e\xcf\xe0\x8e\x34\xf3\xec\x5b\xa2\xdf\x24\xd7\xd9\x6c\xca\x35\xba\x23\xc4\xe7\x6c\x36\xfb\x2c\x6e\xda\x5a\xb3\xcd\x6b\x75\x47\x9a\x9d\xec\x5b\x66\xdf\x1e\xfa\x4d\xaf\xf1\xb3\x6b\x72\x9d\xcd\x39\xec\xae\x3c\x67\x73\x20\xdb\x4e\x7e\xb6\x9d\x02\x7a\x4d\x73\x61\xf6\xca\x22\x7a\x9c\x6f\x70\x72\x3c\xa5\xdc\x29\x53\xd6\x50\x63\xdf\xfd\xb8\x7f\xa4\x21\x8f\x8e\x48\x6d\xc8\x1d\xae\x0d\xb9\xe3\x7c\x9c\x7e\xbc\x61\xf6\x09\xbb\xe9\xa7\x2e\xee\x0e\x57\x21\xc4\xbf\x41\x69\xe8\xd3\x43\xb7\x0f\x7b\x7a\xe8\xbe\x3f\xe2\x07\xd5\xd3\xb6\x9d\xb6\x7d\xc8\xb6\xd3\x3e\x78\x31\xbe\x1d\xef\x78\x04\x8b\xb7\xe0\x3d\xea\x0c\xfa\xd9\xa2\x7e\xfa\x88\x3a\x0f\xef\xa0\x9f\x47\xb0\x58\x97\xf7\x19\x5a\x37\xa1\xa7\x74\x3b\x54\xc2\x0d\x40\xba\x45\x53\xa2\x00\x66\x21\x42\xf2\xa3\x29\x17\xdb\x42\xd2\x3d\x4a\xec\x2d\x4a\x91\x23\x4d\x20\xd8\x22\x2b\x9c\x27\x4d\x8a\x9c\x8a\x8c\x91\x94\x47\x1f\x85\x6e\xc1\x16\x39\xd5\x55\xdf\xf6\x38\x15\x23\x46\x48\x6e\x4c\x29\x75\xa4\x89\x3f\xa6\x44\x31\xa2\x14\xd9\x65\x17\xb1\x26\x94\xae\xdd\x64\x57\xb3\x45\xcc\x2f\x2e\xf1\x27\x40\x11\xbb\xc9\x2e\xa5\x4b\x24\x91\x20\xf9\xf2\x93\x80\x76\x7f\x4e\x69\x89\x3f\x41\x5c\x2e\x45\xf6\x24\x12\x55\xd5\xee\xba\x90\xc7\x17\x8f\xf5\xa8\xad\x29\x2b\xef\x8e\xb5\x35\x3d\xea\x6a\xe3\xde\x42\x74\x60\xa8\xa6\x2c\x5c\x2c\x79\x3d\x3e\x7f\x21\x7a\x3d\x92\xc1\x1b\xae\xed\x8e\x33\x38\x2c\xf8\xdb\x99\x53\x67\x4e\x5f\xfa\xe9\x87\x1f\x3e\xb5\x89\xbc\xce\xf1\xea\x17\x33\xc7\x9f\x3e\x7e\xf2\x8a\xfd\x1f\xb4\x6c\xdb\xf4\xdc\xaf\xf8\x92\xb8\xe6\xfc\x99\x4d\x63\xe7\x55\x8c\x7d\xed\xc9\xcd\x1f\xba\x3f\xdc\x9b\xf7\xf3\x4b\xe2\xf2\xcb\x67\x37\x8d\x9a\x19\x9d\xf8\x6a\xf2\xf1\xb7\xdd\xaf\xee\x74\x7f\x01\x22\x9c\xa9\x7d\x27\xde\x24\xee\x04\x1b\x95\x74\xa8\x84\x5e\x70\x33\x24\x23\x54\x53\xab\xed\xe9\xa4\xc0\x41\x44\xc9\xb1\xa7\x53\x3d\x4b\x22\x82\x2d\xa2\xf4\xb4\xa7\x53\xb2\x85\x6d\xca\xf6\x34\x92\xde\x4c\xcb\xec\x7e\x70\x09\x11\x62\x77\x2a\x1e\x5d\xcb\xe8\x9e\xd1\xa9\x04\x31\x92\xea\xae\xef\x75\x77\x2a\x35\x18\x49\x75\x61\x7b\x4a\x1f\x8c\x28\x1e\x3b\x65\x90\x90\x5f\x54\xe2\x4f\x28\x35\xdd\x65\x57\x73\x41\x49\xa4\x90\x71\xab\x67\xb5\xec\x22\xf9\x09\x25\x47\x96\x5d\xa4\x90\xb2\xa7\xb6\xa6\x47\x3c\xe6\x2b\x40\x8f\x14\x2e\x2e\xab\x63\xac\xea\x83\x3a\x6b\xdc\xe8\xc7\xd2\x53\x9c\x3f\xf3\xe1\x5b\x6e\x7b\xe8\xa1\x5b\x6e\xdd\xbc\xa3\xa1\x77\x7d\xbf\x86\x5e\xbd\xfa\x15\x72\xaf\xad\x6f\x4d\xe0\xb0\xcd\xb7\xdc\xfa\xf0\x43\xb7\xdc\xfa\xc8\x8e\xc1\x3d\xfb\xf7\x6c\xe8\xd5\xbb\x9f\x30\x7c\xe4\x15\x8f\x6d\x59\x35\xf2\x8a\x47\x1f\xbd\xa2\x7e\xf4\xe8\xfa\x91\xf5\x63\xc7\xd6\x1f\x0b\x0a\xcb\x86\x1f\x5d\xbf\x65\xe4\xe5\x8f\x6d\xb9\x62\xe4\xaa\x47\xb7\x5c\x91\x18\x3b\xbc\xdf\xc8\xc4\xd8\xb1\x09\x8a\xe6\xfa\x68\x87\xc5\x7c\x71\x27\x84\xa0\x02\x12\x94\x77\x01\x6a\x29\x8a\x28\x03\x4b\xf9\x74\xd2\x44\x19\x58\xc7\xa7\x91\xd4\x53\x56\x29\xc5\x8e\x34\x29\x76\x92\x4a\x2a\x5d\x92\x3f\x4d\xa4\xa8\x52\xe9\xa7\x87\x18\x7b\xac\x3a\xb3\xac\x3a\x23\xbd\x3a\xb3\x7a\x61\x44\xa9\x94\x64\x17\xe1\x13\xa4\x46\x4e\x99\x8a\x4a\xbb\x3a\xa9\xf0\x58\x5d\x49\x39\xbf\x4b\x22\x91\x20\x1e\x99\x04\x12\xa0\x94\x06\x18\xdb\x48\x9d\xfc\x24\x48\xd6\x9c\xae\x55\x25\x7e\xca\xbb\x9a\x1e\x75\x4c\xa4\xe2\x31\x9f\xd7\x23\x39\x10\xfb\x62\x6d\xdc\x23\x19\xfc\x86\x50\xb9\x1d\xc3\xc5\x25\xa5\x8c\x5f\x75\x68\xb0\xa3\xdb\xe3\xf3\xd7\xf5\xc5\x5a\xc6\xba\x3e\xab\xae\x1a\x34\xf0\xa3\x27\x37\xbd\x36\x6b\xc2\x74\xf4\x94\x74\xf9\x78\x50\xe3\xdb\x9c\xfa\xfc\xc8\x09\xa9\xb3\x3e\x56\x55\x2c\x59\x34\xb9\xf6\x9c\x6a\xf5\x7d\x77\xbc\x74\x66\x24\x72\x7a\xcf\xf2\xa1\xbd\xfa\x37\xe2\xda\xe5\x5b\xa6\x4f\xbb\x7d\xf4\xd6\xb7\x76\x5e\x37\xeb\xbe\x3e\x03\xd4\x17\x7a\x5f\x37\x6a\xdd\x37\x53\x7e\x15\x27\xd7\xd5\x7d\xf5\xda\xe4\xf3\x02\x01\x9c\x66\xab\x9a\xca\x5d\x1d\x99\x5a\xd7\xb3\x64\x44\x65\x6c\xd4\x44\xa6\x9b\x31\xfe\x47\xcc\x91\x72\x40\x80\x72\x6a\xcd\x33\xa6\x1c\x89\xd8\xc1\x8e\x67\x7e\x14\xa9\xcd\x80\xf3\xb1\xaf\xe7\xf1\x3f\x72\x5d\xd4\x5f\xd4\xaf\x74\x1d\xbf\x58\xed\xcb\x3d\x2c\x8d\x00\x19\xdc\x80\xc4\xc5\x98\x6e\xf6\xa7\x15\xb7\x7e\x4f\xad\x13\xea\xe2\x7e\x89\x93\xbd\x4e\x97\xdf\x10\x2e\x83\x8b\xb1\x6a\xbb\x54\xbb\x3a\x99\x5c\x5d\x2b\x6d\x57\xdf\xe6\xea\x7d\xb8\x96\x0b\x8f\xbd\x79\x96\x3a\x42\x7d\x3c\x4f\xdd\xaa\x8e\x9c\x7b\xc3\x58\xae\x98\xb5\x5d\xa4\xf6\xe5\xa6\x74\x6c\x9b\x6f\x51\x6c\xed\x6d\xf7\x70\xc9\xb5\x4e\xae\xbc\x2e\xee\x03\xd9\xeb\x04\x43\xb8\xe8\x8a\xd4\x53\x97\xf5\x90\x76\x60\x1f\xf5\xe5\x1d\x92\xfa\xe6\x2c\x7c\x0a\xc7\xe5\xe1\x18\x7c\x66\xf6\xfa\x31\xad\xef\xaa\xab\x7c\xea\x15\xad\xef\x8d\x61\x6d\x07\xb8\x81\xfc\x22\x91\x80\x1d\x64\x48\xf2\xcc\x41\x3a\xa2\x8a\x53\x6f\xb9\x4e\xe4\xe3\x7c\xa9\x5f\x74\x1b\x2c\x58\xee\x0e\x24\xb0\xab\xeb\x39\x37\x86\x7b\xaa\xff\xda\x75\xfb\xe3\x5b\xff\xf1\x8e\x50\xa4\xfc\x0d\xa7\xaa\x9b\x56\xa6\x26\xab\xff\x59\x84\xc5\xea\xa1\x73\xd0\xa9\xf3\xa3\x27\xdc\x2c\x14\x0a\x4f\x81\x05\x9a\x98\x97\x34\xc4\xa9\x0b\x26\x62\x2c\x09\x48\xdd\x08\x98\x4d\x91\x24\x02\xdd\x44\xde\x14\x41\x62\x8d\x12\x73\x0b\xe1\x62\x8a\xc9\x95\x26\x42\x2c\x69\x32\xd3\x73\x26\x83\x29\x92\x34\x9b\xe8\xa6\x19\x4c\x11\xc5\x96\x61\x67\x48\x0e\xc9\x21\x2f\xfd\xee\x89\xe7\xa0\x07\xe7\xab\xb7\xab\xdf\x71\x55\xc7\x70\x9d\xba\xfc\x98\x3a\x0b\x37\xd2\x3e\xf4\x53\xdf\xc5\x7b\xe1\x0f\x10\xa1\x94\x8d\x2d\x97\x19\x5b\x29\x4a\xb0\x45\x11\x3c\x69\xc5\x80\x11\x45\xa0\x6e\x5f\x4c\x40\x55\x75\x00\x6b\x43\x5e\xbe\x5f\x23\xe6\x6f\x52\xdf\xc5\x41\x5f\x1e\x51\x77\x32\x5a\x96\xa2\xca\x3d\xc8\x7d\x06\x3c\x14\xd3\x76\x14\xe4\xd3\xf4\x83\x44\x88\x2a\x80\x91\x14\xef\xa4\xed\x52\x57\xaf\xf7\xcd\xbb\x94\xab\x41\xf5\xe0\x41\x7a\xef\x8d\x00\x98\xa2\x41\x08\x74\xed\x80\x44\xb2\x1b\xb4\x09\x2a\x29\xbc\x23\xcd\x3e\x7a\x13\x14\x7f\xdc\xa8\xe3\x0e\xfa\x7c\xed\x67\x6d\x35\x5f\xc2\xf0\x8c\x0c\x49\x64\x63\x24\x44\x33\xd7\x1a\x30\x84\x76\xce\x87\xf9\xad\xdf\x5e\x22\x55\xfe\xfe\x1e\xc5\x3f\x67\x6a\x87\x85\x9e\x19\xdb\x5a\x0f\x49\x0b\x7d\x98\xcc\x67\xad\x2a\xed\x78\x3e\x7b\xaa\xdd\x91\xce\x18\x4f\xc5\xe8\x48\x2b\x05\x19\xeb\xa8\x58\x84\x44\x82\x09\xba\x13\xe2\x31\xc8\x45\x27\x84\x8b\x01\x75\x47\x21\x67\xac\x1b\x9a\xbe\xf8\x1c\x2d\xea\x7f\x3e\xff\x52\xfd\x37\x86\xcf\x9a\x33\x6b\xde\xfc\x59\xb3\xe7\x71\x75\xd8\x1f\x83\x58\xa9\xbe\xa7\x1e\x50\x5f\x54\x3f\x53\x3f\xc0\x08\x8a\xe4\x9e\x7b\x08\xfe\x6d\xeb\xbd\xf7\x3c\xae\xcb\xc6\x16\x00\xee\x3f\x22\x01\x91\xa2\x33\x81\xda\x2d\x8e\xf6\x0c\x39\x67\x70\x7b\x54\x01\x43\x9a\x0d\x91\xc0\xd8\x92\x14\x78\x3a\xf8\x02\x1d\x7c\x43\x86\xc1\xa5\x72\x48\xde\xc2\x8d\x50\xf7\x09\x8f\xff\xab\xe6\x8f\x31\xc2\xe3\x80\x30\x02\x40\x18\x2c\xee\x64\xd9\x8d\xa4\x9d\x52\x6c\xe1\xd3\x4c\xa0\x15\x1f\x9f\x4e\xfa\x58\x2b\xbe\x3c\x2a\x69\x01\x0a\x82\x94\x5c\x4f\x9a\x22\x20\x37\x46\x14\xc9\x91\x4e\x4a\x6e\x7a\x81\x64\x33\x45\x92\x6e\x89\x6e\xba\xed\xa6\x88\x92\x8f\x11\xc5\x9d\x2b\xbb\x92\xbc\xc5\x9c\x48\x24\x40\xb1\x50\x37\xeb\x48\x10\x9f\x9c\x94\xc0\x9d\x60\x3e\xb4\x0c\xe2\x31\x81\x3a\x49\xf4\x87\xbc\xa1\x5a\xcc\xda\x31\x6f\x68\x84\x88\xb6\x2f\x0f\x22\xde\xf4\xb0\xda\xca\x71\x73\x8e\x15\xe2\x87\xf3\x4e\x9f\x3d\x75\xee\xd9\xea\x97\xfc\x0f\x3b\x51\xfe\xf6\xe5\x2b\x3f\x7b\x52\xfd\x4a\x3c\xf0\x22\xfe\x7e\xc1\xbd\x83\xa7\x5d\x70\xcd\x32\xca\x9f\x46\xed\xb0\x50\x2b\xee\x84\x6e\x70\x11\x24\xbb\x50\x5a\x44\x3e\x9d\x14\xbb\xd0\x6e\x89\x68\x8a\x24\xf3\x29\x59\x1e\x3e\x9d\xf4\xe4\xd3\x63\x9e\x1c\x53\x24\x65\xb3\x76\xc9\xb7\x45\x14\x9b\x29\x8d\x24\x12\x25\xc6\x16\x86\x0e\x64\x6a\xf0\x8b\x1c\xe9\xa4\x5c\x44\xaf\x94\xad\xa6\x88\x52\x41\xe1\x82\x51\x76\x91\xe2\x04\x28\x56\x51\x76\x29\x50\x9a\x48\x10\x9b\x4c\x8a\x13\xc4\xe3\x52\x72\x8b\x8e\x83\x06\x11\xac\xd5\x37\x18\x51\xe5\x65\x25\x19\x7a\x29\x34\x10\xc2\xc5\x25\x8d\x1c\x06\x56\x4e\x9b\x7b\xc1\x79\x4b\x1e\x78\x60\xfe\x9c\x39\x67\x36\x2d\x51\xbf\xe2\x24\x74\xbd\xf1\x39\xda\x56\x9e\x7d\xe1\x65\xea\xfe\x2f\xde\x50\xf7\xe3\x1a\x69\xfc\xc2\x25\x33\xce\x3b\xf7\x93\x85\x33\x27\x9d\x33\x63\x94\xb4\xe5\xd3\x8f\x76\x9d\xb9\xa5\x2a\x92\x5c\xbe\xeb\xab\x0f\xa9\xdc\x26\x00\x84\x19\x22\x61\xf9\xa0\x91\x90\x34\x52\xc9\xa0\xe2\x9e\x32\x5b\x8c\x68\x8b\x10\x3e\xae\x98\x79\x6a\x43\x90\x38\x29\x85\xc4\xca\xd0\x3b\xe1\x62\x49\xa3\x81\x92\x67\xa4\x52\x22\x53\x2c\x6f\x31\xcb\x2e\x02\x09\x82\x32\xb1\x53\x62\x30\x24\xc7\xbd\x61\x6a\x34\x4a\x43\x72\xb9\x21\xc1\x4d\xc3\xb2\x07\x1f\x54\xf7\xb7\x3e\x8e\x3c\x8e\x96\xfc\x78\x98\xdf\x79\x6c\xd1\xe7\xea\x2b\xd8\xfb\x73\xce\xca\x75\x65\x72\xba\x48\x3b\x2c\xf4\x12\x09\x14\xc1\x28\x48\x16\x64\xc7\xc1\x49\x99\xef\xb6\xa6\x53\x7e\x4b\x81\xd3\x16\x51\xfc\xc6\x34\x03\xd6\xc6\x16\x25\xcf\x91\xa6\x60\x58\xc9\x33\xca\x2e\x45\x76\x31\x81\x11\x65\x57\x0a\x38\xbb\x23\x8f\xfa\x4e\xbf\x4c\x3c\x8c\xb7\xa5\x59\xde\x86\x8b\x25\x43\xa9\x3b\xe4\x0d\xf1\x7d\xb1\xae\x87\xcb\xeb\xe1\xc2\xc5\x25\x8b\x38\xcc\x5d\x34\x79\xde\xcc\xf9\xf3\xc6\x4f\x76\xab\xda\x78\xbe\xa2\xf5\xe5\x2e\x5d\x96\x0d\x7e\xf7\x50\xeb\xf7\xaf\xab\x9f\xe3\x1a\xd1\x3e\x73\xe1\x4d\x17\x5c\x7a\x7b\xdf\x5a\x99\x8f\x7c\xab\x92\xc2\x72\xe4\xd5\x63\xdf\xbc\xab\x7e\xfb\x09\x70\x30\x5b\x3b\x2c\x9c\xce\x74\xa1\x9c\x6a\x43\x0e\xed\x79\x61\x56\xff\x2d\x96\x74\xca\x55\x92\x43\xa1\x94\xcb\x9c\x46\xd2\x85\x99\x82\x00\x35\x05\x31\x12\x70\xb2\xfe\x7b\x1d\x69\xa5\x2b\x46\x94\x50\x80\x61\x25\x57\x0e\xed\xbb\x57\x56\x8c\x06\x4a\x52\x49\xa1\xec\x22\xde\x04\x71\xc9\x8a\xdd\x91\x48\x10\x8b\x8b\x18\x13\x44\x90\x89\x21\xa1\x1b\x8d\x50\xcc\xe7\x37\x74\xc7\x70\xb1\x54\x84\x7d\x31\x1e\x73\x79\x3d\x1d\x2c\x88\x4e\xf3\x6c\x1c\x06\x5a\xd3\xb5\x8d\x35\x03\xce\x1a\x74\xd5\xbd\x12\x5f\x7d\xeb\x19\x2f\xef\x57\x7f\xd8\x7b\x48\xfd\x14\x4b\x2e\x99\x3f\x65\xe1\xa2\x69\x63\x97\x15\x71\x09\xcc\xc7\x42\x6c\x2a\x2a\x6c\xf1\xfb\x5f\x23\x62\xbc\x5e\x3d\xfc\xe1\x3e\xf5\x73\x4c\xa0\x7d\xeb\xb3\x0f\x5e\x70\xe1\xad\x35\x99\x98\xb2\x37\x80\xd0\x5f\x24\x60\x85\x9a\x0e\x92\xa3\x00\xb5\x76\x36\x36\x38\x06\x47\x3a\x1b\xc2\xf0\xa6\x88\x62\xa7\x62\x02\x46\x86\x6f\x74\xab\x6d\x46\xde\x10\xaa\xcb\xc3\xba\xde\x82\xf8\xed\x96\x52\xbb\xba\xcf\x5e\x7c\xe0\x65\xe1\xad\x83\x07\xd5\xef\xd5\x32\x55\xd9\xb0\x01\xfb\x73\xb9\x6c\x6a\x92\x87\xa9\xda\x61\xa1\xb7\xb8\x13\xfc\x10\x86\x28\xac\x83\xa4\x97\x72\x39\x90\x85\x5e\x95\x7c\x3a\x55\x1e\xf2\x9a\x6c\x11\xa5\x9c\x76\xa1\x8a\x71\x39\xc7\x91\x26\x39\x4e\x52\xc2\x50\x98\x83\xa1\xb0\x12\x76\x48\x29\xc4\x88\xe2\x72\xa4\x19\xce\x57\xac\x8e\xb4\x52\x8d\x11\xa5\x24\x83\xbe\xba\xc9\xcd\xde\x40\xc8\xa4\x83\x2f\xe2\x48\x00\x1b\x18\xc5\x05\x89\x04\x29\x97\x15\x07\x9f\x48\x90\x4a\x97\x62\x95\x12\x9d\x71\x57\x27\x25\xed\x28\x71\xee\x0e\xdb\x53\xaf\xba\x60\xde\x32\xf5\xed\xb7\x10\xce\x9b\x7b\xfe\x1a\xf5\xfb\xfd\x9f\xa9\x47\xb0\x74\xc9\xf4\xa9\x4b\x96\x4d\x9d\xb6\x38\x34\x75\xec\xe8\xa9\xd3\x47\x8f\x99\x82\xeb\x97\x3f\x19\x8b\x3e\xbc\x70\xc7\x07\x1f\xec\x58\xb8\x39\x5a\xfd\xd4\x05\xbb\xf7\xee\xfd\x74\xce\x79\xe7\xcf\x9e\xb5\x7c\x39\x57\x30\xf5\xdc\x73\xa7\x4e\x3a\xf7\x6c\x7d\x5e\xa1\x49\x3b\x2c\x54\x65\xe4\x6f\x21\x24\xcd\x59\xff\xc3\xac\x71\x29\x9f\x4e\xe5\x14\x9a\x79\x5b\x44\xc9\x31\x76\x92\xbf\x00\x73\x45\x24\xa4\x87\xe4\x54\xfe\x02\x20\xbb\x14\x9b\x9d\x41\xcd\x66\xb3\xcc\xe7\x30\x98\x2e\x53\xdd\xb6\x25\x48\x0e\xd5\x6d\x52\xc8\x64\xb1\x54\x26\xc0\x88\x6f\xf7\x58\x65\xe5\x75\x85\xc8\x00\x39\x45\x9b\x5c\x06\x6d\xea\x44\x37\xa1\xe7\x83\xcf\xd0\xa7\xbe\xfe\xd3\x88\x7b\x07\x17\xf7\xbf\x6c\xcc\x79\x37\x55\x5f\x3d\xea\x8d\x34\x86\xe7\x4e\x3f\x6d\x41\x68\xc9\x8c\x49\x8b\xf9\xdd\x1f\x63\x48\x7d\x53\xfd\x56\xdd\xac\xfe\x47\x7d\xbb\xa8\xf0\xbd\x5c\xff\x96\x4d\xa7\xf5\x6d\x40\xd3\xe7\x17\xff\xa3\x47\xe5\x9a\x7b\x1e\x7a\x00\x38\xdd\xbf\x0b\x0b\x58\xae\xa1\xb2\xdd\xc3\x33\x07\x4d\xfd\xfb\xf1\xd9\x06\x3e\x93\x6d\x68\xcf\x32\xdc\xd8\x9e\x65\xe0\x17\x64\x7c\x3e\x07\xcb\xd4\x77\xf1\x7d\x61\x01\x88\x60\x82\x5a\xa0\x92\x62\xa0\xcd\x99\xa3\x44\x6a\x51\x4c\x8e\x34\x31\x39\x89\x40\x85\x05\x3d\x69\x82\x51\x86\x66\x2c\x18\x51\x4c\x9d\xd1\x8c\x85\x3e\x61\x19\x45\x34\x0f\x60\x49\x16\xd4\x08\x77\x64\x1e\x03\x08\x3d\x60\x30\xbf\x41\x10\xc1\x00\xe0\xae\x45\x59\xf4\x8a\x72\x0f\xfe\x8c\xd6\x17\xb9\xfe\x98\xfa\x02\x17\xa9\x3f\xbe\x25\xbd\xa1\xfe\xa8\xf7\x69\x2d\x8e\x10\x8c\xfc\x01\x46\x6b\x9e\x8e\x84\x2c\x3a\xa5\x16\x46\x69\x86\x30\xaa\x4b\xf4\xd9\x6b\xf9\xcb\x8f\x5d\xce\x5f\x8e\x23\xbe\xfa\x0a\x9f\xf8\x2a\x83\x93\x57\xc0\x60\xfe\x33\xfd\x79\x75\x72\x69\x6d\xa9\x8c\xde\x15\xdc\xb0\xd6\xa7\xf8\xf9\x83\xd1\xfe\x8e\xf4\x2f\xb4\xa9\x37\x7f\x01\x1c\x04\x01\xf8\xb7\x98\x0c\x15\xc2\x5c\x3d\xba\x51\xf2\x6d\x59\x8f\x6e\xe9\xec\xd1\x8b\xa2\x24\xd0\x42\x6c\x31\xa5\xd0\x91\x26\xd6\x18\x29\x6c\xf3\xeb\x34\x16\x54\x0a\x03\xd4\x83\xcb\x3e\x1a\xb3\xb8\x65\x62\x4e\x10\xc9\x45\x4c\x09\x50\x7c\xf9\xb2\x2b\x09\x92\x35\xe3\xc7\xb3\x7e\xcd\x8e\xde\x50\x5f\x6c\x8b\x47\x0c\x21\x4a\x4d\x90\x47\xfe\xed\x03\xa0\xdd\xb2\xa4\x4f\x99\xba\x1f\xc7\x5e\x38\x64\xc2\xcc\x29\xc3\xce\x42\xf5\x4b\x0c\x61\x99\x90\xd8\xbe\xe7\x8b\x97\x2f\xfb\x68\x68\xf4\xcc\x71\xd7\xad\x9a\x5e\xbf\x66\xdc\xb4\xf9\x93\x26\x1c\x7d\xf3\x8f\x3f\x80\x83\x01\x6a\x2f\x69\x87\xb8\x0e\xe2\x30\x10\xb6\x41\xd2\xc4\xec\xb1\x3d\x9d\x74\xd0\x8d\x3a\x7b\x9a\x54\x47\x95\x6e\xf6\x34\xe9\x1f\x55\xbc\xf6\x34\x29\x89\x2a\x3c\x0d\x72\x07\xb1\x10\xa4\x5c\x8f\xcd\xca\x99\x65\x4e\x49\x7a\xc6\x65\x70\x26\xe3\xf2\xe2\x1f\xe3\xc0\x1b\x31\xdb\x49\x1f\x27\xe9\xbb\x5d\x09\xe4\xfe\x4e\xf2\xb6\x43\x73\x5e\xa0\x4f\xdf\xee\xdd\xbb\x77\xc7\xb6\x2d\xd2\x90\x87\x4a\x39\x55\x27\xec\x92\x48\x90\x90\xdc\x60\x32\xf1\x72\x49\xb7\xee\xd5\xb5\xf5\xd4\xae\x48\x2e\xc5\x50\x4c\x8d\xbb\xa9\x9b\xec\x22\x95\x09\xa5\xae\x50\xcf\x27\x78\xfb\xcb\x2e\x92\x4b\xd9\xe3\x82\x50\x10\x78\x89\xa3\x9a\x45\x35\xaa\xac\xae\x87\x2b\x4e\x2d\x7d\x9c\x97\x98\x6a\xe9\x17\x70\x10\x8a\xf5\xa8\xf3\xdb\x31\x1c\x04\xd4\x4f\xf4\xc6\x3a\x37\x73\x07\x03\x5c\xf8\x09\x5e\x89\xab\xf1\x2e\xa7\xe9\xfb\x23\xa3\x96\xe5\x54\xac\x9e\x74\xfd\x6d\x9e\xdc\x23\x8f\x9c\x7f\xfd\x78\x5e\x8c\x1b\xba\x95\x9c\x77\xad\xd1\xa9\xbe\xa5\xbe\xa4\xbe\xa3\xde\xea\x90\xb1\x11\x63\x13\x9e\xec\x5f\x36\xf0\xad\xd9\xea\xf9\xea\x38\x6e\x93\x39\xd1\xd0\x73\x6a\x09\x56\xf8\xbb\xe7\x2e\x3e\x1f\x3f\xc5\x2d\x1c\xaa\x01\x75\xda\xc7\xea\x2b\x93\x46\x37\x35\x7d\xff\x8a\x8a\xb1\x9a\x1e\x42\xeb\xcb\x67\x36\x7e\xfc\x30\xce\xc4\xeb\xd4\xd3\xd5\x3b\xd4\xbb\xd5\x79\x5d\x0a\xff\xde\x2d\x8a\x3f\xe3\x79\x97\xad\xae\x69\x14\x44\x01\x7f\x34\x18\x5f\xa2\x32\x6d\x05\x10\x8b\x44\x02\x06\xb0\xc0\x70\x5d\x7f\x09\x1f\xd7\x61\x87\x64\x04\xb4\x45\x14\x89\x4a\xb7\x95\x99\x29\x8a\x36\x0c\x4e\x45\xc0\x08\x53\x64\x1b\x0d\x1f\x0c\xb2\xab\x99\x43\xa3\x89\xd9\x26\xa4\x0e\xc5\x9c\xa8\xaa\x8e\x63\x08\x43\x7c\x88\x77\x87\xf8\xb0\x15\x7f\xc3\x08\xfe\xa2\xee\x9d\xad\xe2\xec\x2d\xb8\x38\x25\x89\xe4\x8f\x31\x58\xaf\xbe\xca\x15\x71\xbd\x75\x7f\xb2\x16\x40\xd8\xcd\xe2\x30\x3f\x04\xa9\xd5\x64\x18\xd6\xc1\xa7\x75\x6c\x1c\xa4\x56\xd3\x6f\xe7\xa8\xd5\x94\xd2\x48\x42\xac\x3b\x0e\xea\x3c\x62\xc4\xa1\x8b\xbb\xc5\x91\x26\x16\x27\x11\xa9\x55\xc8\x77\xa4\x49\x7e\x54\x11\x1d\x69\xa5\x18\x23\x8a\xe8\x96\xa9\x93\x06\xc5\xef\x90\x5d\xc4\xc2\x6c\xa7\x31\x41\x82\xd4\x54\x30\x4b\x14\xec\xe0\x2b\x4a\x43\xba\x6f\x08\xd5\x66\xe1\xdf\x5a\xfc\x0e\x11\x83\xe7\xce\x5b\xbd\x5a\xfd\xae\x55\xfd\x05\x6d\xe7\x5f\x34\x7f\x89\xba\xff\xdd\x0b\x2e\xbd\xec\xd2\x5d\x22\xd9\xf5\xda\xdc\x4d\x5d\xf2\xb7\x5d\xf8\xce\x87\x07\xe6\xce\x3e\x77\xe9\xee\x19\xd3\xe6\xce\x00\x84\xe9\xda\x61\xe1\x43\x71\x27\x84\xe1\x0c\x48\x86\x20\x0b\xc5\x43\x59\xc5\xd5\x01\x09\xa5\xd1\x21\xd0\x63\x0e\x0b\x55\xe6\x12\x46\x9a\xdb\x91\x26\x6e\xa7\x92\x8b\x11\x8a\xf2\x0a\x3c\x69\x62\x8c\x29\xa5\x18\x51\x72\xdd\xb2\xee\x03\x1d\x3e\xd9\xa5\x18\x03\x89\x2c\xe8\x10\xfc\x3e\xaf\xc7\x6b\xc8\x64\xae\x64\xdd\xc5\x85\xfc\x1e\xaf\xcf\x20\x95\x06\x61\x3a\x36\x20\xa0\xfd\xf6\x0d\x9c\xfa\xe5\xba\x9b\x57\xdf\x71\xdf\xba\x6b\x56\x63\x80\xc3\x1b\x37\xa8\x7f\xa8\xbf\xab\xdb\xb8\x21\x18\x42\x13\x8e\xc7\x75\x57\x7f\x2d\x49\xd2\x8d\xff\xf8\xe0\x41\x75\xff\xc3\x1f\xfc\xfd\x26\x49\x92\xbe\x58\xb3\x0e\xb1\x49\xb7\x81\x00\xc2\x41\x91\x80\x09\xdc\x50\x95\xd1\x65\x73\x76\x94\xdc\xd4\xd5\x7b\xf4\xd8\xdf\x91\x26\x66\x27\x45\x19\xcc\x0c\x79\xb3\x26\x3f\xc8\x62\xf4\x50\x79\x26\x53\x44\x79\xfb\x2b\x5a\x70\x8a\xfa\x90\xfa\xdb\xdb\x2f\xdd\x9d\x4c\xde\xfd\x92\x48\xd4\x2d\xea\x6f\x3f\xa9\xbf\xaa\x5b\x0f\xbc\xbf\xe5\x97\x47\xde\xa7\x76\x93\x3e\x77\xa1\x48\xc0\x02\x43\x32\x5e\xc6\xc4\xa7\x75\x8c\x23\xf0\xe9\x94\xa8\x8b\xaa\xc8\xb7\x89\x2a\xf5\x11\x34\x8c\x66\x21\xb6\x89\x37\x45\x88\x39\xa6\xc7\xd3\x99\x20\x3a\xae\x07\xd0\xec\xb3\x96\xff\xa2\xb5\x3f\x37\xb5\xf5\x41\xee\x25\x91\x1c\x54\x6f\x3e\xa8\xce\x38\xa0\xdb\x6b\xfa\xdc\xf3\x19\xbd\x0d\xfa\x73\xdb\x9f\x69\x14\xd9\x33\x8d\x7c\x3a\x93\xf6\x3e\xf1\x99\x99\x07\x5a\x8e\x7b\xe0\x5a\xfe\xbb\xd6\x9e\xdc\xac\xd6\x8d\xf4\x61\x8b\x0f\xb6\xde\xaf\x3f\x8b\xe2\xd6\xaf\xc5\x9d\x10\x84\x15\x90\x2c\x04\x9d\xa1\xba\x90\x58\xf9\x74\xd2\xca\x84\xc4\x6a\x34\x45\x52\x39\xb9\x85\x42\x67\x55\x70\x3a\xd2\xc4\xc9\x12\xda\xc4\x14\xa3\x70\x22\xe9\x0b\x30\x39\xcb\x31\x45\x88\xcf\xa9\x18\x5c\xba\x26\xf8\x9c\xb2\x2b\x29\xb8\x0b\x59\x34\xe7\xa6\x46\x2e\x90\x50\xac\xb9\xb2\xab\x1d\xbd\x06\xc1\x6f\x08\x31\x7b\x95\x91\xa2\x3a\x39\x54\x1b\x92\x25\x21\x1c\x84\xd9\x38\x18\x01\xcd\x18\xe0\x39\xf5\x88\xf1\xca\xcb\xd6\x3c\xf0\xe8\x8d\xf3\x2e\x0e\xaa\x2a\x57\xd6\x5f\x3d\xf2\xae\xfa\x9b\xfa\x38\xd7\x80\x55\x68\xc4\x91\x6a\xeb\x7b\xd2\xf9\x57\xbf\x75\xbf\xfa\xaf\x87\xde\xea\x56\x84\xf6\xdd\xad\x9f\x9c\xbe\x06\x47\xe8\x3c\x15\x43\x6c\x2c\xfb\x65\x2c\x8e\x41\xb7\x38\x44\x8c\xa7\xcc\x3c\xe3\xaa\xb9\x7d\x24\x2d\x2c\xc4\x21\x16\x3d\xed\x2b\xe8\xf0\xa8\x6d\x0c\xdb\xfe\xd6\x62\x09\xd7\x84\x61\x1a\xd3\x88\xa4\x75\x3d\xb7\xec\x8f\x31\xdc\xf4\xd6\xfb\x01\xe1\x0e\x00\x7c\x81\xe5\x0f\x42\x1d\xc6\xf0\xcf\x73\x0f\x77\x60\x09\x35\x50\x6c\x4c\xfa\x69\x87\x05\x9b\x48\xc0\x4d\xe5\xce\xde\x16\x8b\xda\xdb\x62\x51\x13\x6b\xca\x13\x25\xae\x16\x96\xb7\xe6\x58\x37\x69\xa7\xa9\xd0\x2b\x46\x4e\x76\x11\x3b\x75\x2c\xa2\xec\x22\xae\x8e\x81\xa5\x1c\x92\x29\x32\x2d\x2f\xab\xad\xe9\xc7\x61\xfe\xa2\xe9\x63\x97\x62\x58\x3d\xf2\xee\x97\x57\x5d\x8e\xf7\x4a\xe7\x9d\x7d\xc9\x42\xfe\xe8\x31\xf1\xbd\xff\x2c\x3e\x77\x8f\x31\x2b\x8b\x62\x82\x61\xfc\x44\x86\x6f\xc6\x76\xbe\xf1\x16\xc6\x37\xde\xa6\x03\x7e\x68\xa1\x30\x9a\x70\x31\x1d\xe8\xf3\x96\xcc\x08\x53\xfa\xe2\x18\x32\x61\x08\xc3\x94\x65\x97\xe1\x2a\x9c\xab\xfa\x38\x59\xbd\x4b\xbd\xf0\x3e\x91\xb4\x6e\xe5\xc6\xb5\x4e\x39\xf6\x6f\x6e\x46\xeb\x3d\x59\xf9\xaf\x61\xb9\x8a\x8a\x8c\xde\xf1\x19\xbd\x63\x49\x0a\x9d\x7f\x49\x9e\x49\x3c\x2f\xb6\x25\x29\xd8\xc0\x78\xe9\x90\xac\x15\xc9\xd1\xaa\x03\xd9\xfe\x4b\xcb\x44\x02\x32\xcc\xce\xb4\x65\xb0\xc6\xdb\x28\xc8\x66\x0d\x65\x47\x5a\x71\xf8\xd3\x44\xd6\x19\x99\x71\x39\x66\x7f\x9a\x98\xa3\xcc\xce\xcb\x0e\xc6\x52\x62\x94\x9b\x39\xd1\x6a\xa3\xee\xdb\x4c\x8d\x3a\x28\x08\x2c\x55\x61\x67\x78\x26\x2e\x87\x30\x8e\x54\x32\xdc\xe5\x18\x46\x83\x5b\x5e\x8b\x97\xe0\x79\x12\x2e\xc7\x4b\xd5\x7d\xf9\x92\x7a\xd1\x2b\xea\xc5\x52\xbe\x48\x8e\xbe\x25\x54\xff\x31\x06\x93\xdc\x6a\x3c\xba\x5b\x88\x61\xeb\x15\xea\xa8\x36\x7e\xeb\x72\xda\x78\x82\x9c\x76\x14\x4e\x8b\xee\x11\x33\x62\xa9\x58\x40\x76\x11\x8e\x45\x84\xc6\x4c\xa7\x14\xde\x94\xed\x52\x1d\xe5\x0c\x1a\x98\xb8\x8e\x90\x98\xbc\x52\x7f\x78\xac\x10\xf9\x83\x7f\x8c\xe1\xbf\xc0\x63\x85\xd4\xce\x4e\xd3\x0e\x8b\x81\x3f\xcd\x61\x59\xfe\x32\x87\x25\x58\xda\x72\x58\xa1\x20\x8b\x08\x42\xc1\xe3\x72\x58\xd3\x70\x34\xda\xd0\x81\xe3\xd5\xad\xea\x4f\xea\x2f\x2a\xc1\xf0\x43\x1b\x6e\xdd\xfc\xe8\x2d\xb7\x3c\xc0\x4d\x40\x09\x2d\x78\xa6\x7a\xaf\xfa\x9b\xfa\x87\xfa\xab\x7a\x1f\x9e\x81\xd6\xad\x1f\x7f\xbc\x15\x8d\x8f\x7e\xbc\x77\x0b\xb4\xf9\x82\x43\x2c\x5f\xe1\x86\x01\x19\xcd\xca\xfa\x81\x94\xc9\x02\xd4\x5b\x9b\x3a\xbb\x04\x4b\x8c\x7a\x05\x07\x75\xc9\x19\xaf\xa0\xb8\x2d\x72\x9b\x1b\x8e\x01\x75\xc0\xa1\x5c\xcc\xba\xe0\xb5\xdc\xa0\xa3\x18\x54\x0f\x1c\x55\x0f\x60\xf0\xa2\x4b\x2f\xf9\x9b\x7a\x40\x24\x1a\xbc\xf3\x8e\xda\xfa\x23\xf7\xd3\x55\x67\x9d\x7d\x0d\xe3\x95\x57\x9c\x27\xee\x04\x37\x84\x60\x14\x24\x65\xca\x2b\x7f\x96\x57\x85\x94\x57\xc5\xac\x03\x1e\x47\x9a\x78\x9c\x4a\x5e\x86\x57\x61\x8c\x28\x79\x1e\xd9\x95\xb4\x0b\x32\x85\xc6\x46\x59\xb1\xd8\xa8\x59\xf4\xcb\xb2\x4b\xa1\x52\xd4\x81\x7f\x2c\x71\x5f\xaa\xa3\xba\x93\x73\xf1\xf4\x31\x3f\xbd\xa8\xfe\xd1\xe3\xfc\xbe\xa7\x62\xe5\x95\x07\xc7\x7d\x77\x97\xea\xf6\x1e\xc7\x4e\xc6\x4b\xd1\x25\x12\xc8\x83\x30\xcc\xcc\x48\x9b\x33\xae\xb3\x33\xcc\xa7\x53\xb9\x01\xc6\xce\x5c\xca\x4e\x1d\x21\xe4\xd1\x90\x31\x46\xf2\xf4\xa8\xb1\x28\xc6\xf4\x5d\xd4\x41\x82\xd5\x43\xb1\x81\x4c\x89\xc9\x05\x1d\xf1\x04\x18\xe2\x09\xb7\xb3\x3a\x83\x78\x0a\xd0\xe3\xf3\x7b\x43\xdd\x91\x4d\xdc\x84\x72\x31\xde\xc6\xfa\xd2\xdf\x31\x77\xf9\xb2\x2b\x96\x86\xba\xa8\xef\x75\xc9\x59\xb1\x40\xfd\xf6\xd8\xdf\x2e\xbc\x70\xb9\xaa\x89\xe4\x8b\x37\x96\xde\x17\x2b\x4b\xae\x3e\xb7\xcf\x55\x41\x6f\xf0\xd6\x81\x67\x2d\xbc\xb0\xf5\x59\xbe\x7c\xfe\xbc\x39\xcb\x75\x5f\x36\x45\x3b\x2c\xbc\x20\xee\x84\xca\xf6\x1c\x9e\xb9\x53\x0e\x4f\xa6\x94\xe5\x9b\xd3\xc9\x7c\x99\x1e\xcb\xcf\x31\x75\x9a\x07\xac\xe8\x30\x0f\xd8\x61\xb6\xcf\x9b\x99\xed\xe3\x18\x3a\x27\x46\x39\x29\x5a\x8a\xe9\xe0\x95\xba\x48\x38\x01\x4a\xbe\x28\xbb\x9a\xed\xde\xd2\x0a\x7d\x0e\xa6\xc3\xf4\x5e\x05\xd6\xd6\x94\xc4\x7b\x74\x02\x49\x99\xe9\x3d\x21\x5c\x46\x8d\xf0\x14\x0e\xf3\x37\xad\x5f\x71\xe9\x8a\x5b\xd4\x63\xea\xbf\xb1\xfa\xc8\x8f\xb7\xdd\xcc\xa9\x5f\x5d\x7d\xd1\x05\x97\x5f\xb3\xf9\xa7\xff\xaa\x7b\x7f\xfe\x5e\x79\x0c\xff\x29\xad\xba\x70\x56\xd3\xf8\x79\x95\xc3\xff\xd5\xdc\xfc\x05\x5e\xfe\xb7\x94\x24\x49\x73\x2f\x99\x3f\x76\xd8\x99\xb5\x03\xf7\x35\x3f\xf7\x11\x5e\xb4\xe2\x7d\xbd\xc2\x26\x1f\x40\x58\xce\xb0\x75\x3d\x24\xa5\x8e\x39\x19\xc2\xc7\x58\x68\x2c\xb5\x50\x3d\x48\x8a\x2c\xe3\x2a\xf2\xa6\x48\x52\x12\x59\x1e\x16\x4c\x91\x0e\xd1\x24\x35\x62\xf9\xc2\x14\x75\x8e\xba\x4f\x78\xeb\xe0\xc1\xa3\xd5\xc2\x5b\xb4\xfd\x95\xda\x61\xd1\xc8\xec\x69\x1d\xe8\xc1\x94\x94\xb1\xcd\xc4\xdc\x66\x4e\x69\xdc\xcd\x3b\x69\x63\x2c\xaf\x42\x0d\xa8\x89\xd7\x21\x24\x15\xef\x90\xdc\xee\x8c\xa8\xa4\xaf\xc4\xd2\x3b\xae\xbe\xe6\x2e\x2c\x55\x9f\x57\xff\x50\x8f\xaa\x2f\xe2\xb7\xfc\xab\xc7\xea\x6f\xbc\x61\xfd\x4d\xf4\xf7\x37\xf5\xdf\x68\xa6\xcf\x36\x00\x88\x4e\x86\x8b\xfa\xe8\x28\x30\x09\xf4\xb9\x52\x3c\x8b\x85\xd0\x97\x26\xe8\x54\x24\x6a\x18\x7d\x7a\x6c\x2e\x21\x95\x4a\x13\x95\x4a\x30\x65\x13\x4f\x21\xf4\xc7\xeb\x68\xb0\x60\xc0\x1a\xec\xe5\x92\x64\x2a\x88\xaa\xac\xbe\x2f\x92\xa3\xef\x8d\x1e\x29\x44\xa9\x23\x46\xc8\x01\x90\x8e\x8a\x04\x1c\x70\x53\x86\x56\x8b\x3d\x1e\x67\x0f\x4d\x0a\xa2\x31\x1e\x8f\xb3\xa4\x28\x7d\xb0\x87\x3d\x98\xfa\x0e\x93\x27\xad\xc8\x7a\xa8\xd8\xe7\xb9\x1f\x0a\xd8\x9c\xbc\xd0\xdd\x4e\xf8\xed\x8a\x2d\xef\x77\x91\xd8\xb7\x3f\xbb\x63\xe4\x0f\xc0\x8e\x5b\xba\xdb\x89\x75\xbb\x22\x59\x7e\x17\x89\xb8\x9d\x87\x66\x5e\xb2\xda\x58\x10\xf9\x34\x2f\x88\x92\xc5\x6a\xb3\x77\x98\x36\x57\x8c\x94\x16\xb3\x43\x37\xb2\x21\xb7\x1f\xe3\x18\x77\x87\xa8\x57\xc5\x50\x0e\x16\xbe\x23\xa1\xfc\x21\xba\xa5\xb7\xb1\x40\x7d\x4c\xfd\x49\xfd\x4d\x52\x7f\x53\x7f\x12\xc9\xb1\x00\xf2\x5f\x1f\xcb\xe3\xbf\xfe\x63\x0c\xff\xd2\xb1\x7e\xba\xae\x14\x01\x88\x06\xe6\x67\xca\xda\xfd\x3a\xd7\xee\x67\x18\xd8\x51\x38\xea\x47\x04\x33\xf3\x23\x26\xe6\xc1\xd9\x7f\x45\xf8\x9c\x3a\x06\x9b\xd0\x86\x32\x8e\x57\xc7\xe0\xeb\xea\x26\xf5\x90\x7a\x88\xfb\x94\x7b\xb7\xf5\x18\x27\xb4\x76\x6f\x2d\xe6\x6c\xad\xbf\xd0\xe7\x88\x99\xe7\x98\x20\x96\xc9\x11\xb2\x31\x13\xf4\x31\xd3\x53\x84\x6c\xa0\x0c\x46\xea\xb2\x38\x36\x50\x46\xe6\xcc\xd8\x40\xd1\x98\x4e\x0e\xc9\x22\x36\x60\x5f\x09\xfb\x62\x83\x6a\x55\xf7\x8b\xa4\x75\x26\xb7\xe9\xd8\x18\x15\x38\x07\x20\x8c\xcc\xc8\xbc\x09\xba\x67\x7d\x7c\xd6\x12\xf3\x3a\x50\x66\x68\x58\x31\x50\xb3\x84\x09\x45\xa0\xb2\x28\x51\x9a\x6a\x31\x54\x1b\xf2\x62\xc8\x3b\x92\x4b\xb5\x8e\x14\xfc\xad\x43\xb9\x5d\xb7\x0b\x75\x07\x6f\x3e\xba\x23\x83\xc5\x57\xa8\x84\xeb\x2a\xdd\x09\x06\x2a\xef\xac\x49\xce\x94\x26\x86\xa8\x22\x9a\xb2\x99\xa6\x94\xc1\xc9\xd6\x16\x70\x31\xaa\x58\xd9\x3d\x3e\x96\x55\x26\x39\xe4\x0d\xcb\x71\xef\x0a\x4c\x5e\x7f\xbd\x4a\x0c\x87\x3f\xfa\x7d\xe7\x47\xac\x6d\x4e\x5b\xcd\xaf\xce\xce\x31\x41\xe7\x39\x26\x3a\xae\x1c\x86\xb8\x19\xea\x67\x22\xf9\xfd\x3d\x76\xbd\x4d\x25\xf8\x22\xeb\x4b\x83\x3e\x6f\xa8\x08\x7a\x5f\x20\xd3\x17\x43\x0b\xe1\x63\x29\x49\xef\x80\xe4\x54\xd0\x91\x26\x18\x25\x92\x33\xdb\x29\x43\x36\x5f\xe4\x8f\xcb\xe1\xda\x90\x1c\xb2\xad\x5f\x8f\x49\x75\xd4\x4a\xa9\xd7\x47\xff\xf5\xd2\x67\x54\x70\x7b\xf9\xd3\x19\x2f\xdb\xe6\xbd\x32\xec\xab\xaa\x76\x63\x1c\xc3\x7c\x79\xd8\xc0\x57\x60\xe4\x7d\x8c\x1c\x7a\xd0\x28\x19\xee\xe3\xf6\x72\x1f\xb6\x76\xc5\xbb\x8b\x8b\xd5\xd9\xd9\xb5\x46\xa5\xfc\x0d\x2c\xc2\xce\xcb\xe2\x37\x93\x3e\xff\xd6\x81\xc0\x78\xc8\x1b\x42\x7e\xfd\xb1\x65\x9f\xb0\x7b\x46\x0a\xcf\x73\x43\xc5\x57\x41\x80\x22\xd0\x3d\x90\x20\xa4\xdb\xa6\x84\x9d\x60\x6a\x9f\x0b\xae\x0b\xb9\xc3\x23\x39\xac\xdd\x79\x44\xdc\x2e\xa9\xff\xd6\x71\x41\x9d\x76\x58\x70\x08\xa3\x20\x0c\xdd\xe1\x82\xcc\xcc\x3c\x0b\x7f\xcb\x4d\xe9\xa4\x1b\x21\xa2\x18\x8d\xe9\x14\x5f\x11\x72\x53\xc0\x6a\x4f\x23\x89\x32\xcd\x2d\x71\xa4\x49\x89\x53\xe9\x86\x11\x45\x28\x8c\xc5\x14\xbf\x23\xad\x54\x61\x44\x29\xa1\xb0\xce\x6a\x73\x50\x3b\xdf\x4d\x4e\x5a\xdc\x21\xba\xe5\x77\xb1\xd9\x77\x3e\x24\xbb\x14\x7f\x21\xf3\xdf\x49\x8b\xc3\x97\xc8\x24\x81\x7b\x65\x67\xa1\x4a\xcb\x6b\x6a\x6b\xea\xd8\x34\xbc\xec\xf1\xf9\x43\xdd\x51\x4f\xdf\x64\x13\xa2\xe1\x62\xa9\xee\xb7\xc3\xf7\x37\x8d\x19\x32\x52\xfd\x1a\x57\x5c\xfa\xe6\x8e\x9f\xfd\xb9\xea\x3e\xa7\x5f\xac\xfc\xfb\xbc\x47\xb7\x61\xf8\xb4\xbe\x23\x57\x7a\xef\x9f\x3e\x03\xab\x37\x3d\x71\xfa\xa8\xd3\x07\xf7\x41\xc9\x60\xb8\xfc\x8c\x39\x3b\x9f\x52\xfb\x8f\x58\x33\xa0\xb4\x29\x32\x7a\xfe\x13\xf7\xf6\x18\x30\x22\xf6\x8f\xe9\x8c\xfe\x25\xda\x61\xa1\x41\xca\x01\x19\x8a\xb2\x48\x37\x69\xa3\xf4\x7b\xf9\x74\x52\xa2\xf4\xe7\xd3\x0d\x36\x77\x25\x21\xf5\x7b\x41\x46\xbf\x4b\x0f\x74\x5c\x4e\x25\x07\x23\x14\x2e\xb1\xc9\x08\x17\xd5\x14\x67\x82\xe4\xc8\x8a\xc4\xe0\x89\x57\x3f\xa0\x48\xf9\x19\x1b\x4a\xc1\x36\x9b\x67\x90\xd9\xf4\x49\x59\xb9\xc1\x9d\xc9\xfc\xea\xf9\xbb\x25\x18\x8e\xae\x9e\xf0\xaf\x8f\x3e\xda\x73\xc6\xf5\xd5\xbe\xae\x81\x33\x07\x2f\x9d\x32\x7d\xc9\xa0\x33\x02\x52\x4e\xeb\x13\xfd\x1b\xd5\xd7\xd5\x56\xef\xcf\xea\xa7\xa3\x47\xac\xc1\x78\x75\xcd\xa6\x9b\xbd\x1b\x9f\x49\xd4\x02\x42\x5f\xed\x30\xff\x3d\x1b\xc7\x3f\xcb\x5f\x60\xe7\xfc\x85\xf5\x4f\xf3\x17\x72\xe7\xfc\x85\x90\xcd\x5f\x98\x0b\x12\xfa\x3a\x13\x88\xc7\xfc\x3e\x43\x9b\x6b\x2e\xc0\xf6\xfc\x85\xc7\x20\x19\x8a\xa1\x2f\x8a\x3f\xbf\x7e\xd1\x0a\xe4\xd4\x7f\x4f\x1b\x7b\xfe\x99\x67\x5e\x30\xea\x0c\x34\xf1\x17\x5f\xfe\xfc\xcf\xea\x1f\x9c\xad\xf0\x07\xac\x59\xb6\x28\x29\x49\xd2\xf8\xc5\xa9\xf5\x85\x37\x29\x53\x47\x48\xa2\x78\xd7\x82\x45\x88\x31\x36\x26\x03\xb5\xc3\x82\xab\x7d\x4c\x28\x9e\xd6\xdd\x08\x1d\x13\x21\x3b\x26\x02\x1b\x13\xc1\xd8\x79\x4c\xf4\x01\x21\x86\x58\xdb\x98\xe4\xb8\xa8\x2d\x76\x24\x12\xc4\x2c\x13\x2b\x1d\x13\x8b\x9e\x2e\x14\xf2\xb3\x91\x74\xad\x93\x65\x07\xe5\x90\x1c\x2e\xef\x98\x80\x97\xf5\xc8\x7a\xe0\xfe\xd7\xc7\xae\xaa\xc6\xd2\xa3\x39\xf1\x6b\xa7\xbc\xb6\x1f\xc3\x33\x16\xf4\x3b\xa3\xb0\x70\x7a\xdf\x73\x67\xa3\xe6\x45\xc0\xfa\xc6\xfe\xdc\xd8\xdf\xbf\xb9\x72\xf8\x28\x2c\xf9\x71\xfd\xfd\xf1\x6a\x7c\x33\x9e\x78\xe1\x1f\x94\x96\x91\xda\x61\x81\x13\x46\x41\x2e\x14\xc3\x38\x48\xfa\x29\x19\x4e\x1a\x95\x62\x26\x53\x16\xb0\xfa\x45\x5b\x44\x09\x88\x69\x24\xe1\x28\xc9\x6f\x51\xcc\x9e\x74\x32\x9f\xad\x28\xc8\xa7\xd0\xa2\x84\xca\x57\xbe\xec\x52\xdc\x1e\x2a\x51\x4e\xbf\xec\x22\x9e\x04\xb1\xca\xc4\xcd\xfa\xde\x83\xea\x4b\x3c\xe6\x2a\xc0\x90\x81\x89\x12\x4b\x68\x16\x03\xfa\x43\xba\x56\x8d\xc4\x2b\xaf\xdc\x87\xdc\x27\x3f\xb7\x5e\xc4\x19\x2f\x5b\x38\xf3\xf2\x11\xa3\x07\xb4\xac\xfe\x56\xfd\x06\xbb\xf3\x38\x6f\xe2\xa4\xb1\x67\xa0\xda\xe5\xa7\xbb\xee\x54\xff\x7b\x70\x93\x74\xee\xba\xf2\x6e\xa9\x1e\x43\xb0\x02\x2f\x10\xf3\xa6\x2f\xbe\x98\xad\xbb\x00\xe0\xbe\x93\x2a\xc1\x0f\x93\x20\xe9\x63\xd8\x08\x21\x42\xe4\xb8\x02\x86\x34\x71\xc7\x88\x2d\xaa\x27\x1e\x73\xa2\xc4\xc7\xd6\x45\x78\x1d\x69\xe2\x8c\x75\x58\xa7\x97\xf4\x79\x99\x24\x52\x82\x72\xa9\x4f\xb1\x21\x4b\x3e\x12\x49\x26\x26\x46\x46\x5c\x5f\x7e\x93\x99\x8c\x2b\x40\x7d\x0a\x34\x70\xef\xbb\x2f\x94\x8e\xec\x9e\x9b\x53\x59\x38\x64\xe8\x87\x1f\xaa\xfb\xf8\x85\x6f\xae\x7c\x6a\xa7\xc5\xbc\x57\x90\x46\x0d\x5d\xf9\xe6\xb1\xbf\xf3\x0b\x75\x99\x51\x87\x0b\x1e\x61\x14\x14\x40\x04\x96\x64\x72\xf0\x21\x3e\x9d\x34\x22\x64\x64\xbf\x0b\x9f\xa6\x1d\xf5\x58\xd3\x48\x2a\x98\xbc\x14\x3a\xd2\xa4\xd0\xa9\xf8\x31\x42\x4a\x74\x79\xa9\xc4\x88\x52\x48\x7d\xb7\x53\xa6\x56\x4b\x6e\x16\x3c\xb6\x40\x26\x68\x35\x24\x40\x09\x78\x64\x17\x91\x13\x4a\x17\x9b\xec\x22\x39\xd4\x8c\x75\x12\xa0\xba\x38\xcb\x12\x9c\x7c\x36\x27\x2b\x4c\x9f\xbd\x3e\x75\x5d\xb5\xff\x98\x7a\xf8\x3f\x4d\xdb\x46\xf5\x18\x78\x6d\xd3\xca\xa5\x55\xab\xc6\xbf\xf6\x19\x96\xcc\x58\x30\x70\x7a\x7e\xfe\xf4\xfe\x6d\x62\xd5\x34\x62\xdd\xd1\x37\xde\x3b\x54\x59\xfe\x71\x30\x34\xe7\x9c\x59\x7d\x1a\xb0\xf4\x87\xf5\xf7\x57\x47\xb1\xa5\xba\x07\x15\x2f\x40\x38\x1b\x40\xc8\x91\x72\xc0\x0d\x23\x33\x78\xc4\x1c\xd7\xed\x16\xd5\x75\xc9\xd1\x6e\xb7\x3c\x6d\xba\xce\xc5\xa8\xba\x5b\x32\x76\xcb\x4b\xc3\x60\x37\xf3\xec\xa0\x48\x8e\xe3\xec\x94\xcf\x2b\x87\xf4\xe8\xc9\x20\x9f\x8d\x25\xf1\x0d\x53\x1e\x79\x49\xdd\x37\x79\x52\xef\x69\x85\x52\x4e\xeb\x3f\x86\x8d\x3b\x78\xb8\xf5\x52\xee\xca\x4b\xcf\x8e\x94\x1f\x3b\x04\x1c\x5c\x06\x80\xf7\x4b\x39\xfa\x3a\xd9\x6c\x06\x87\x4a\x8b\xd0\xd1\xf5\xff\xf9\x24\x53\x6d\xc8\x7b\x99\x3e\xc9\x24\xd4\x1f\x7d\x55\xec\xf3\xc9\x27\xcc\x4f\x69\x1b\xd5\xe1\xb8\x45\xca\x01\x07\xb8\x21\x0e\x6c\x58\xe9\x68\x0a\x96\x34\x11\x9c\x0c\xa6\x3b\xa3\x8a\x6c\xd2\x03\x58\x43\x0b\x71\xb2\x01\x25\xae\x58\x26\x9d\xc9\xeb\x43\xc2\xb0\xb3\x14\x2e\x2e\xa3\x50\x7d\x96\xdd\xdf\x3d\xaf\x57\x03\x96\xee\x4e\x75\x19\xf0\x4f\x2c\x55\xa7\x7d\x26\x49\xe3\x4e\x17\x66\x1d\xdd\xf8\xc2\x5b\x46\xe9\xbb\xbd\x7b\x75\xbf\xbc\x04\x40\x38\x43\xca\x01\x6b\x76\xd6\x8c\x62\x3e\xaa\xc0\x27\xcb\xde\x88\x2c\x85\x60\x4e\x64\xf3\x37\xee\x4c\xfe\x66\x09\x96\x9c\x76\x14\x9b\xd4\x87\xf0\x06\x55\x51\x3f\x18\x23\xe5\x1c\xbb\x16\x6f\x53\x7d\xad\x04\x77\xaa\xbd\xd8\x73\xda\x79\x97\x0f\x6d\x6e\xff\xe4\x69\xaf\xcb\xb0\x44\xca\xf9\xfd\x9b\xb6\xfe\x49\x17\x0b\xa3\xa0\x14\x16\x66\x70\x83\x33\x3f\x1e\x67\x6c\x67\xa2\x40\xac\x71\xaa\x0b\xc4\x1b\x43\x52\xc6\x1a\x2c\x75\xa4\x15\x4e\x4e\x93\x52\x27\xcb\x42\xb0\x0c\x3c\x5b\xc3\xa9\x38\x1d\x69\xa5\x1c\x23\x4a\x29\xc7\x04\x41\xc9\xa7\x0e\xcc\x94\x20\xb2\xac\x58\xbd\xd4\xfe\x60\xa8\x63\x8a\xc4\xcf\x64\xc4\x7f\x9c\xa4\x78\x3a\x4a\xcd\x12\x74\x58\x6b\xee\x3e\x6b\xfe\x86\xb2\xd8\x3d\x0b\xee\x79\x46\xdd\x37\x66\x74\xdf\xa9\x01\x4e\xdd\x3f\x66\x4c\xaf\xc9\x05\x42\xfd\x0d\xa3\x26\x4c\x9b\x3e\x71\xd6\xfe\xcf\x5b\x97\x72\x37\xfe\x6d\x46\x5d\xb5\x3b\x60\x6f\x4d\x70\x37\xae\x9c\x5d\xd9\xf5\xd8\x61\x4a\xdf\xb9\x00\x42\x9e\x30\x0a\xdc\x30\xaa\x5d\xc6\xdb\xa8\xa3\x82\xde\x41\xba\x15\xce\x95\x3e\x5e\xbc\xdd\x3a\x31\xc4\x22\x33\x21\xc7\x0e\x42\x7e\x7c\xd7\xe5\x73\xd1\x69\xeb\xb1\x71\xd6\x03\xdb\xd4\x4f\x26\x4d\xae\x9f\x56\x24\xd4\xdf\x39\x6e\xda\xbf\xf6\xb5\x4e\xe3\xee\x5f\x38\x35\x1a\x39\xf6\x03\xb4\xf9\xa8\x06\x61\xd4\x89\x39\x1f\xfc\xdf\xd6\x2d\x31\x6f\x0a\x05\xc8\x56\x1d\x94\x76\x5a\x95\x39\x10\xed\x3f\xfc\x88\x4e\xf5\xa7\x1f\x7e\x54\x7f\xc2\xf0\xfc\xf3\x97\x9e\x7d\xce\xb2\xa5\x67\x73\x2e\xef\xcf\x58\xab\xee\xf9\xc5\xfb\xab\xfa\x26\xc6\x7f\xdd\xd0\x9c\xfa\xbb\xf7\xc6\xa7\x9e\xbe\x41\xc7\x33\xea\x0c\xd6\x2f\xea\x3b\xa7\x42\x3b\x94\x69\x67\x57\x3e\x9f\x26\x10\xcd\xfa\x4c\x99\x29\x09\x91\x3b\xe3\x18\x19\x74\x86\xe5\xc8\x8a\x4d\x62\x38\xc6\xa6\xe3\x18\xcc\xe2\x18\x77\x86\x75\x6d\x38\x26\x17\x8f\xc3\x31\x06\xb9\xea\xea\x29\xaf\x7f\xfa\xe9\x6b\x13\xae\x8c\x06\xa6\x0f\x3a\x67\xf6\xbc\xb3\x07\x4c\x0f\xa8\x33\xc4\x8f\x2f\x1f\x32\x52\x7d\x55\x03\xef\x8f\xea\xbe\x7e\x7d\x5a\x7f\xe7\x5e\xef\x5e\xf5\xd0\x7a\xef\x3f\x5e\xe8\x11\xcb\xf0\x56\x9d\xc1\x30\x69\x86\x86\x36\xd7\xdf\x6e\xcb\x29\x0d\x96\xe8\x71\x7e\xdf\x82\x11\x92\xd3\xee\xf7\x2d\x1d\xfd\x3e\x35\xde\x5e\x87\xee\xf7\x8d\xc7\xfb\xfd\x3a\xaa\x51\x27\xf7\xfb\x53\xd6\x56\x07\xfe\xab\xee\xab\xba\x62\x9c\xee\xf7\x1b\xa6\x15\x14\x4c\xed\xd7\x66\xa0\x47\x0f\xbb\xea\x8f\x32\x4e\xec\xdd\x97\xfa\xfd\x87\xaa\xba\xe3\x81\xaa\x9a\xed\xff\xc8\xe8\x24\xb7\x4b\x18\x05\x0e\x2a\x1d\x6d\x56\x50\x1f\x01\x0b\x45\xe8\xce\xec\xac\x18\x55\x44\xa6\x7a\x0e\x5d\x4a\x41\x41\xcb\xf1\xf2\xe9\xe7\xcb\x33\xaa\x64\x2b\xbb\x70\xb4\xaf\xd4\x5d\x74\x6e\xff\xf1\x3e\xa1\xfe\x9e\x09\x67\x1a\x44\xb5\x95\xef\x51\xdd\x5a\xaa\xdb\x82\x06\xed\x30\xff\xbe\x30\x0a\x2a\x61\x65\x36\x97\x23\x75\xce\xe5\x30\xfe\x49\x6d\xb9\x9c\xdc\x0e\xb9\x1c\x77\xa7\x14\x8e\x3b\xad\x78\xfd\xb1\xf6\x25\xdb\x49\xde\xca\xe9\xb9\xb7\x66\xd1\x22\x17\x53\xb7\xf8\x67\x99\x9c\x42\xec\xb8\x50\x9b\xc2\xc5\x13\x33\x39\x52\x58\x2a\x2f\xab\xad\x69\xe0\xd0\xc2\x2f\x98\x38\x76\xc2\xf4\x4b\xb7\xbf\x7c\x78\xe7\x5b\x17\x2d\xe7\xd4\xaf\xc7\x8d\x19\x32\x76\xc2\xaa\x5d\x3b\xfe\x78\xf3\xc3\x4b\x57\x62\x93\x34\x71\x54\x43\x5d\x55\x63\xa0\xfc\x1f\x57\x5e\xf7\xf2\xcc\xe9\xd7\x49\x92\xd4\xbf\x69\x70\x4d\xac\x21\xb7\xcb\x9d\x6b\x6f\x7e\x06\x17\x9d\x7d\xa5\x01\x10\x4c\xda\x61\xee\x66\x71\x20\xf8\x61\x06\x24\xdd\x94\x76\xab\x45\x97\x7c\x22\xea\x58\xc5\x10\xcb\xae\xe3\x14\x28\xd9\x6d\x78\x25\x3b\x19\xe4\x6b\x5b\xc7\xe9\x33\x75\xc6\x2b\x56\xb7\x8e\xec\x41\x26\x0e\x1d\xaf\xc8\xfa\x32\x2d\x5d\x62\x18\xe4\x2a\xab\x95\x4d\x1b\xb1\xe4\xa9\xa7\x6a\x2a\xfc\x21\x5f\x6e\xc5\xf8\xea\xdb\xee\xe7\x17\xbe\x89\x26\xf5\x3f\x6f\xb6\xee\xed\xd7\x43\x94\xde\x73\x38\x1e\x4a\x71\x5d\xa8\xdf\xd6\x0e\x0b\x39\x42\x3d\xb8\x61\x98\xae\xa5\x7a\x2a\x54\xca\xa8\x2a\x4b\x0a\x79\x4e\x96\x14\xf2\x66\x93\x42\x32\xc3\x80\x76\xea\xb4\x6d\x2c\xc9\xde\x21\x45\x54\xd7\x06\x65\xcb\xce\xc6\xf0\x98\x51\x8d\x73\x82\x58\xf2\x7b\x5e\xec\x8e\x39\x5b\x5e\xc2\xad\xdc\xf5\xad\x4b\x97\x9f\x55\x59\xc1\xbb\x8f\xbe\x7a\xd7\x84\x69\x9f\x50\xb9\x71\x02\x08\x06\xa1\x1e\x4c\x10\xca\xe6\x88\xb0\x2d\x47\xa4\xa7\x01\x3a\xe4\x81\xdc\xfe\x78\x1d\x8d\xb4\x9d\x58\xfd\x94\x5b\xf2\x24\xb1\x5a\xbd\x51\x4d\x0b\xf5\xad\x93\xe7\xcc\xe1\x1e\x3e\xfa\xaa\x2e\x8b\x05\x00\xe2\x0e\xa1\x1e\x1c\xd0\xa8\x6b\x31\xb5\xdb\xb4\x59\x45\x30\x76\xc8\x01\xb9\xda\x73\x40\x2e\x5d\x13\xda\x13\x36\x0a\x38\x64\x57\x92\xcb\x2e\x7b\x08\xb9\xe3\xec\x2f\x84\x61\x3e\xcc\x87\x0b\xd0\x75\x83\xb4\xfb\xe5\x3d\xd2\xf5\xe8\x52\x8f\xfc\xfa\xba\xf4\xfa\x2f\x42\x7d\xeb\x70\xee\xc9\xd6\xa1\xdc\xd3\x47\x5f\xe5\xae\x6c\x65\xf8\xd5\x0d\x20\x18\x85\x7a\xb0\xb6\xe5\x6c\x4c\xf1\x24\x97\x25\xcf\x16\xd5\x1d\xb7\x9e\xb3\xb1\x64\x73\x36\x6e\xdd\x73\x5b\xd0\x8d\x63\xd5\x67\xf0\xb4\xfb\xa4\x87\x70\x98\xfa\x2c\x8e\x55\x9f\x56\x14\x2e\xcc\xf9\xd5\xcd\x38\xa9\x35\xdd\xba\x1f\xcf\x52\xff\xa1\xd3\x2b\xaa\xc3\x05\x59\xa8\x07\x2f\x54\x81\xce\x3e\x31\x4e\xb9\x27\x53\x6c\xec\x8b\x12\xb1\x45\x91\x9c\x69\x8a\x37\xdb\x17\x06\x81\xdc\xce\x52\x77\x88\x01\xc6\x2c\x7c\xec\x87\x22\xd6\x3f\x6d\x95\xde\xc2\x7a\x75\x68\xf7\x8d\x1b\x4b\xfb\x55\x16\xdb\x0a\xad\xa7\x8d\xf2\x16\x0b\xf5\xad\xd7\xf5\xe6\xc8\xd1\x92\xf3\x37\x59\x2d\x1f\x70\xc2\x90\xda\xf1\x80\x30\x1c\x80\xff\x17\x1b\xc3\x4e\xf9\x1c\xfc\x1f\xf2\x39\xc3\x39\x5e\xb5\xf1\xb3\x5a\x7f\xe7\x72\x1e\xe3\x1e\xfb\xfc\xe1\xd6\x91\x99\x7c\x4e\x95\x7a\x3b\x77\x85\xd4\x07\x0a\xa1\x4a\x5f\x4d\x23\xa5\xb3\x6b\x59\x84\x98\xe2\xf1\xa7\x69\xe8\x18\xa4\xde\x2d\xc0\x14\x45\x9f\x4b\x21\x4e\xa6\x2b\xcc\x2d\x30\x25\x29\xc0\xf6\x44\xb6\x41\xcf\x63\x57\x4d\x99\xf8\xe0\xcb\x3d\x27\x34\x4e\x9e\x32\x65\x72\xe3\x84\x9e\x2f\x3f\x38\x91\x93\x5e\x5f\x38\xf7\x8d\x2d\x3f\xd4\xdd\x5d\xb4\x69\xf9\x1b\xf3\xef\xad\x8c\xde\x3b\xef\x8d\xe5\x9b\x8a\x36\xd6\xfd\xb8\xe5\x0d\x56\x80\x88\xb0\x55\xfd\x19\xa7\xb3\x1c\x50\x31\x74\x9c\x22\x4c\xf1\x6c\xd5\x49\xe6\x27\x9b\x14\x92\xe3\xf2\x56\xa2\xfe\x2c\xbd\xf0\xfb\x00\x40\x28\x56\x6f\xe7\xce\xcf\xd2\xe2\x8f\x2a\xbe\x0c\x2d\x7c\x0b\x31\xc7\x94\x80\x9f\xc1\x46\x4a\x4b\x80\x97\x75\xdc\xef\xf3\x67\x5c\x86\xbf\x2f\x32\x52\xf4\xae\xd3\x81\x62\xd1\xaf\x97\x45\xc1\x92\xa1\x78\x42\xe3\xb4\x33\xce\x98\xd6\x38\xa1\xe7\x8e\x87\x4e\x9f\x36\xed\xf4\x87\x76\xec\x66\x24\xdc\x53\x59\x79\xef\xd9\x94\x84\xbb\xeb\x7e\xd8\xf2\xc6\xdc\x85\xaf\x2f\x9a\xfd\xc6\x96\x1f\xeb\xa8\x1d\xc0\x8b\x84\x57\xf8\x04\xe4\xc2\x38\x20\xbe\xa8\xc2\x5b\xd2\xcd\x26\xde\x67\x8c\x28\x4e\x2a\x35\x79\x8c\xa6\x5c\x7d\x5d\x4d\xae\x53\xb1\x62\x24\x65\xd3\x6b\x1e\x02\xd4\x20\xe4\x52\x30\xe6\xa4\x8a\xe2\x73\xca\x2e\x05\x72\x13\x09\x85\x37\xc9\x2e\xc5\x6a\xcb\xe4\x56\xa8\xf7\xd0\xcd\xb1\x9f\x01\xdf\x72\xdd\xb7\x9d\xbd\xf5\x9a\x71\xb7\x8d\xa8\x1e\x5e\x11\x1b\xf6\x86\x72\xf5\x84\x1b\x47\xd5\x0c\xaf\xa8\x19\x82\xdb\xef\xfb\x70\xe0\x80\xca\xf2\xf9\x43\x03\xf7\x7e\xd2\xaf\xb1\xa2\xcb\xbc\x21\xc0\xc1\x7a\x75\x1d\x26\x85\x7a\x86\xe9\xcb\x40\x0f\x5d\x85\x53\x2f\x18\x73\x67\x16\x8c\xad\xd7\xb1\xbc\xba\x8e\x7f\xe6\xd8\x10\xe1\x09\x44\x55\x5f\x27\x0e\xa7\x69\x16\x5e\x15\xcb\xa0\x18\x96\x01\x29\x8a\xa6\xbc\x7a\x9d\x91\x3d\x5b\x71\xc4\x82\xe1\x76\xdf\x5e\xc4\x66\x93\x53\x85\x3a\x23\x24\xb6\x6c\x8a\xc6\xf9\x96\x98\x92\x27\xa7\xe9\xb0\xd1\x30\xb9\xb0\x48\x76\x29\x76\x06\x53\xbd\x74\xb3\x20\x98\x48\x10\xbb\x9c\x34\xe7\xe4\x51\xc7\x25\xba\x14\xc1\x90\xc9\x61\xb8\xf4\xea\x21\xef\xf1\x29\x0c\x1f\xab\x1f\x2a\xe3\x4e\xdb\xff\xd6\xae\x0d\x8f\xab\xdf\xb7\xe5\x2f\x2c\x1c\xaf\xdc\xb0\xeb\xad\xfd\x9c\xad\xf0\x63\x8c\xe4\xee\xff\xaa\xf8\xc3\x8d\x6d\xf9\x0b\xf1\xea\x3d\xa1\xef\xbf\xa2\x8a\x4d\x69\x9b\x06\x20\x5c\x2e\xee\x84\x62\xb8\x0d\x92\xf9\x54\x0f\x0b\xf8\x34\xc9\x8d\x25\x25\x0e\x22\x8a\x9d\x4f\x27\xed\x6c\x12\xc1\x6e\x31\x45\x52\x80\xf9\x92\x2d\x42\x5c\x71\x16\xc4\x78\x62\x8c\x70\x8e\x11\x9e\xe4\x5c\xf4\x32\x0e\x4c\xf4\x3b\xdf\x14\x21\x9c\x93\x84\x82\x2d\xb2\xe2\x73\xb4\xe5\x76\x3c\xf4\xa4\x2f\x60\x8a\x64\x20\x90\x62\xf6\xa4\x19\x33\x5c\x21\xb6\x1a\x4a\xb1\xf8\x64\x97\x22\xd9\x29\x53\xec\xc8\xc0\x3c\x73\x5f\xe5\x4c\x34\xda\xaa\xa7\xfc\x21\x6f\xc8\xef\x91\x0c\x21\x6f\xa8\x36\xde\x17\x6b\xcb\xa7\xdd\x69\xfc\x69\xf7\x87\x47\x04\x4e\xfd\x72\xda\x90\xc6\x31\x66\x9c\xad\x3e\x2c\xf4\xee\xc9\xbd\x7e\x2c\xdf\x1c\x8d\x0a\xdc\x88\x83\x2d\xef\xfe\xf8\xd9\xd3\xd2\x8c\xa9\x17\x2c\x68\x39\x38\x61\xd4\x8d\x89\x03\x07\xac\x0f\x4d\x9a\x05\x1c\x8c\xd1\xbe\x12\x07\x08\x3f\xb1\xd5\xa6\x97\x81\x5e\xe8\x13\x08\xc7\xe3\x4a\xb9\x98\x26\x95\x51\xc5\x26\xea\xab\x4c\x85\x96\x54\x89\x5e\x26\xa6\x67\x12\x53\x3e\x5d\x69\xd9\x7a\x52\x41\x76\x35\xa3\xc1\x14\xa6\x30\xa3\x9b\xdc\x6c\x76\xb2\x32\x31\xe2\x73\x35\xcb\xee\xdc\x00\x5b\xc0\x54\x5e\x24\xbb\x9a\xf3\x40\x3f\x51\x29\x37\xa3\xc1\x9d\x4b\x37\x6d\xae\x66\xa3\xd9\xe9\x62\x60\xa4\x1f\xea\xb5\x62\xe5\x75\x19\x24\x55\xe7\x37\xe8\x65\x62\x7e\x83\xee\x20\xcb\x0d\x6c\x89\xa9\x4b\x4f\x96\x8c\xb9\xba\x3a\xde\xb3\xf6\xc6\xeb\xd7\x0f\x53\x66\xce\x48\x0e\xbf\x71\xfd\x86\x78\xcf\x78\xf4\xda\xf5\x57\x8e\xdc\x36\x67\xee\x33\xc3\xaf\x18\xf3\xfd\x63\x8f\xfe\xf0\xc3\xa3\x8f\x7d\xbf\xfc\x9a\x11\xcd\xb3\xe6\x3e\x3b\xea\xef\x37\xde\x54\xd7\xbb\x4f\xcf\x0d\x37\xdd\x36\xea\xe9\x39\x33\x95\xe1\xd7\xdf\xb4\xa6\x6f\xff\xfe\x7d\xae\xe4\x2e\x7a\x46\x05\x6d\xdb\xd3\xaa\xca\x64\xc2\x07\x20\xfc\x4b\x24\xe0\x87\xe5\xba\x2f\xcc\xe6\xf3\x53\xb2\xcb\x01\x36\xea\x1a\x15\x59\xa2\x56\x34\xe5\xf5\xb1\x03\x52\x5c\xf1\x4a\x69\x62\x8c\x31\x9c\xe2\x68\x21\xee\x18\x8b\x26\x4c\xb1\xa4\x9d\x85\xf5\x76\xab\x29\x42\x11\x8d\x83\x2d\x70\x70\xc8\xa6\x08\xf1\xc6\x28\x5a\x51\xec\x8e\xf6\x39\x01\x5f\xe7\x39\x81\xb8\x37\xa4\xff\xd5\x66\xfe\x7c\xd8\x1f\x73\x24\xcc\xc5\x06\x75\xd5\xaf\xea\xf3\x38\x48\x7d\x5e\xdd\xa7\x6e\xc5\x71\xea\x56\xb4\x88\xa4\xf5\x1e\x6e\x46\x6b\x8f\x5d\x8b\x76\x7d\xf3\xcd\xae\x45\xbb\x74\x7c\x7e\x99\xfa\x33\x5e\x95\xa9\x59\x2d\x86\x13\x4a\x55\xfd\xba\x2d\xf0\x1f\x6f\x0b\x2e\x43\x49\xfd\x03\x25\xf5\x67\x3e\x70\xec\x2b\x7e\x17\xf7\xef\x56\xb3\xde\xde\x19\x6a\x5c\xb8\x4b\xdc\x09\x71\x18\x0c\xb7\x80\xbe\x28\x99\xc6\x52\x32\xc3\x60\xb2\xdd\x14\x21\xe1\xa8\x12\xa1\x2e\xac\x91\x3d\xa5\x2c\xa6\xd4\x38\xd2\xa4\x4b\x8c\x48\x54\x1b\x3c\x8e\x34\xa9\x71\x2a\xdd\x31\x42\xec\x31\x25\xa8\xaf\xab\x0c\x3a\x49\x1e\x3d\xd9\xc7\x93\x26\x7d\xa2\x4a\x9e\x27\xad\x0c\xa1\xee\x49\xa2\xac\x89\x25\x12\xa4\xbb\xdc\x60\x96\x4d\xfe\x70\xa4\x3a\x51\xdf\x30\x90\xca\x4d\xd0\xa5\xe4\x14\x50\xa6\xc9\x11\xd9\xf5\x94\x64\x0d\x96\x75\xa9\x1f\xd8\xa9\x40\xac\x24\x1e\x13\x4e\x2c\x38\xcc\x2e\x5b\xee\x87\xa5\x1d\x2a\x14\x4b\xd9\x79\x3f\x5b\x99\x59\xce\x12\xd9\x67\x8c\x1f\x3d\x78\x10\x06\x8e\xfc\x82\x6e\x91\x53\xbf\x5a\xb9\x60\xd9\xb2\xc5\xca\x7f\xd2\xe3\x47\x0f\x1a\xac\x7e\x73\xe4\x1b\xf5\x75\x91\xc3\xc0\x4d\x0b\xce\x5d\x71\xd1\x23\xbf\x7e\x8b\xe1\xc5\x4a\xf1\xe0\x70\x79\xe4\xe2\x47\xbb\x0c\x2a\x2a\x2b\xe5\x72\x26\xaf\xab\x88\x5d\x3f\xeb\xb1\x77\x3e\xdd\x25\x4d\x3a\x6f\xe2\xc0\xe1\x23\xab\x1a\x9e\x7b\x6c\xea\xda\x48\xfc\xba\x59\xca\xae\xd7\x3e\x96\xf0\x9c\x69\xe3\x06\x0e\x1c\x1b\x6b\x78\xee\xd5\x31\xe3\x6a\xcc\x1e\x8b\x6f\x58\xd5\x90\x29\x35\x66\x9f\xc5\x37\x8c\xf1\xf9\x2e\xe1\x4b\xfe\x8e\xcc\xb8\xf5\x80\xec\xea\x08\x06\x8c\x85\x58\x66\xbe\xd3\x90\x35\xeb\x0a\x2f\x33\xdc\xc9\x56\x4b\xc8\xe9\x0e\x33\x9c\xf1\xda\x90\xf7\x2e\x34\x7f\x8b\x66\xe1\xcb\x3d\x7b\xf6\xec\x61\x33\x16\xa7\x6b\x87\xc5\xcf\xc5\x57\xc0\x02\x7e\xa8\x85\x27\x74\x0c\x99\x72\xd8\xc1\x2e\x44\xd8\x9c\x4b\xca\xcb\xb6\x53\xf1\x88\x89\xb7\x45\x52\x71\xfd\x4c\x24\x4e\x87\x38\x12\x35\x45\x52\xf9\x25\xec\x44\xbe\x7e\xa2\x84\x65\x77\x4b\x82\x14\xa6\xf7\x60\x4e\x50\x2f\xe0\x25\x56\x66\xf8\x53\x5d\xf4\xbd\x2e\xfa\xb0\x87\x62\xa9\x2a\xfd\x40\x51\x8c\x54\x39\x15\x57\xfb\xf2\xd3\x3a\x8c\x28\xdd\xbb\xc8\xae\xa7\x4c\x0e\x2f\x5f\x92\x1f\x67\x96\xa3\x24\x22\xbb\x9e\x94\xac\xae\x22\xc8\x14\x00\xb2\x95\x03\xfa\xfa\x01\x37\xab\x24\x92\x59\x21\x51\xa6\xa8\xd2\x81\xe1\x4e\x6e\x22\xee\xf7\x51\x57\x7a\x3a\x6e\xc4\x2e\x58\x8e\x9b\xd4\x19\xea\xc7\xea\x47\xea\xac\x8b\x70\xe2\x6f\xbf\xe2\x44\xf5\x91\x5f\xff\xad\x3e\x7a\xf0\x9f\xf7\xdc\xad\x08\xdc\x86\x29\x53\xce\x98\x33\xe7\x8c\x29\x93\x37\x70\x02\xb9\xfb\x9e\x7f\x72\x7b\xb1\x17\x12\x75\x8c\xba\x53\x7d\x45\x1d\x85\x49\xec\xad\xfe\x57\xbd\x0d\xcf\x46\x23\x1a\x28\x94\x54\xff\xb9\x62\x6b\xcb\xa6\x5b\xa4\x33\x26\xac\x5b\xba\xf2\xbc\x6b\xc6\xcd\x90\x6e\xbb\xfb\x7d\x5d\x4f\x96\x70\x29\xde\xc6\xd6\x9c\x45\xe0\x0a\x60\xc5\x1d\x29\xa3\x1d\x06\x0b\x11\x52\x18\x4d\x95\x30\xc6\x91\xae\xd1\x14\xcf\xb6\x32\x59\xce\x54\x48\x67\x4c\xc8\xc9\xf2\x3a\x42\x20\x16\xcb\x14\xea\xb2\x6c\x67\x88\xa2\x5e\xab\x9d\xad\xce\x4f\x5a\x9c\x85\xac\x56\xd2\x45\x72\x32\xb5\x13\x8a\x3f\x90\x48\x90\xae\xb2\xe2\x81\x44\x42\x31\xf2\xb2\x2b\x69\xb1\xba\x4f\x98\xb7\x89\x62\x59\xdb\xa4\x4d\x38\x3b\x69\x53\xd7\x3e\x69\xb3\xe4\x91\xfb\xae\xe9\x95\x18\x70\xda\x83\x28\x3d\x7a\xdd\x9a\xbb\xad\x76\xc5\x68\xe6\x43\x8b\x47\xad\x58\xf5\x44\x7d\xaf\xf8\x02\x79\xed\xb0\x71\xfc\xed\x8b\x57\xc6\xfb\xf6\xaf\x89\xda\xa4\x59\xab\xd6\xaf\x51\x5f\x8d\x4f\xea\xe6\x8d\xe6\x45\xfb\x5c\xb4\x28\x52\xd9\x3b\x7c\x56\x83\xce\x83\x59\x70\x01\xbf\x9a\xdf\x00\x12\xd8\xd8\x2a\xf0\x38\xef\x0e\x67\x7e\x66\x61\xce\x73\x3f\xfe\xf8\x5c\x0f\xfd\x07\x8f\xba\x71\x8d\xba\x44\x5d\x8a\x6b\x32\x1b\xcc\x0e\x5f\x8a\xcb\xf9\x97\xf8\x52\x56\xcf\xc5\x70\xac\x3d\x9d\xad\xf2\x63\x21\x21\x2b\xe6\xa2\xe8\xd1\x25\x44\x4e\x56\xcf\x15\x92\xc3\xf2\xa5\xfc\xc0\x5d\xdc\x45\x5b\xd4\xb1\x28\xfc\xff\xac\xb9\x13\x3a\xe9\x4d\x0c\x7a\xc1\x8b\x7f\xae\x39\xd5\x71\xa6\x20\xd5\xfa\x99\x6a\xa6\x39\xd5\x39\xa6\x08\xe9\x12\x4b\xe5\xf5\x62\xe7\xf2\x32\x23\xdf\xfb\x24\x1a\x13\xd3\xf7\xe2\x31\x12\x73\x2a\x15\x18\x21\x75\xb1\xac\xfb\x2d\x88\x65\xf5\xa9\xa4\x93\xee\xf4\xc1\x88\x52\x11\x93\x5d\xcd\x4c\x77\xfc\x09\x52\x22\x93\x60\x02\x94\x6a\x87\x4c\x03\x7f\x12\x97\x53\x92\xd5\x05\x41\x7a\xaa\x97\x8b\x14\x9c\x42\x93\x50\x0e\xb1\xda\xda\xb6\x55\x2c\x61\x1d\x42\x47\x30\xbb\x8a\x25\x82\xa7\xd6\x27\x2c\xc5\xdc\xdb\x1e\xaf\xef\x59\x5f\x6b\x30\xdf\x69\x12\x06\x8e\xd8\x78\xf5\x90\xd9\xa3\x66\xae\xfa\x2b\x85\x6a\x9d\xc6\x37\xad\xbd\xb4\x7e\x62\x51\xe1\xc2\x61\x3d\xbb\xf6\xf7\x3a\xbd\x63\xbb\xf5\x18\x32\x48\x7d\x02\x3f\xec\xdd\xf3\xb4\x7a\x40\xd8\x20\x5a\xf9\xc5\xa2\x02\x3c\x14\x42\xc6\x0c\xda\xd3\x6d\x1b\x1d\x27\x97\x6b\x43\xde\x0d\xdc\x27\xa2\xf5\xc1\x07\xa9\x2c\x5e\xca\x3f\xc0\xdd\x29\xee\x64\x63\x37\x0a\x3a\x8e\x15\x31\x45\x33\x23\xc8\x9c\x77\xa7\xb1\xe8\xc0\x5f\xea\xab\x5d\x56\xd9\xa5\x98\xf8\x44\x26\x41\xa5\x48\xd0\x0e\xdc\xbd\x1d\x6a\xb5\x75\x4d\xbb\xf4\xde\x25\x8b\x36\x6e\x5c\xb4\xf4\x9e\xbf\x0f\xab\x89\x37\x36\xc6\x6b\x86\x09\xcd\x4b\xee\xbb\x6f\xc9\xd2\x8d\x1b\x97\xd6\x0e\x69\xec\xd1\x63\xd8\x30\x5d\x4f\xa6\x68\x1f\xf0\xdf\x8b\x85\x60\x01\x07\x4c\x06\xb6\x30\xc1\x92\xce\x16\xb7\x5a\x4e\x55\xdc\xea\x6c\x2b\x6e\xf5\x9f\xa2\xb8\x55\x3e\xa1\xb8\x15\x6b\x43\xde\x29\x38\x12\x01\x87\xa8\xcf\x68\xa0\xbe\xc1\x0f\xe0\xde\xf8\x06\xcf\x55\x6f\xf9\x46\xbd\x02\x2f\x6b\x35\x7f\xf9\x25\x20\x2c\xe0\xee\xe4\x0e\x88\xaf\x41\x1e\x8c\x04\x62\x8f\x2a\x16\x7b\x9a\x85\x3d\xf6\x13\xea\x1e\xdd\x2d\x94\x4d\xac\xd6\x3b\x76\x5c\x9d\x63\xc7\xda\xc6\x2c\xc3\xca\xda\x8a\xb7\x59\x65\x63\x69\x5b\x65\x63\x78\x81\xa4\x6c\xb8\x71\xe3\xb9\x97\x2c\xe4\x70\x4a\xeb\xcd\x58\xdb\x3b\x1c\xad\xae\xeb\xf9\xba\xf0\xda\x39\xb7\xae\x5a\xde\x74\xc9\x59\xd3\xa5\x3b\xef\x3c\x16\x1b\xd8\xb5\xbc\xb6\x77\x94\xe9\xf3\x99\xdc\x0d\xdc\xcf\xe2\xab\xd0\x8d\x5a\x59\xbd\x7e\xd1\xde\xb1\x7e\x91\x74\x89\x2a\xa2\xbd\x63\x56\x8d\x58\xa3\x29\x5b\x66\xbc\x59\x41\x63\xaa\x54\xef\x7a\x51\x8c\x94\x3a\x53\xb2\xbe\x23\x47\x93\x72\x29\x83\x34\xb6\x4c\x69\x63\xe9\xff\xa1\xb4\x31\x7e\xd2\xd2\xc6\x70\x79\x96\x60\x1d\xce\x86\x8b\xcb\xce\xe4\x5e\xef\xd7\xbb\xe7\xa0\xc6\x81\x8b\x17\xf7\xed\x9d\xa8\x8b\x27\x76\x71\x12\x59\x73\xbb\x32\xa4\x4f\xe3\xf0\xe6\xdb\x6f\x7e\x9e\xbf\x44\xea\x16\xad\xaa\x88\xf5\xb8\xaa\xba\x7b\x59\xbc\xa2\x48\x9a\xfb\xb7\x15\x8b\xea\xa6\xe6\xe6\x9c\x39\x68\xc9\xc5\x97\xd0\xb1\x11\x9e\xe7\xce\x61\x6b\x09\xba\x66\xf5\xe0\x64\x6b\x09\x14\x9e\xfa\x0c\x4e\x4f\x60\x07\x30\xe4\xc7\x05\xaf\x61\x2d\xa7\x1e\x16\x9e\x47\xb3\xa4\x1e\x63\x3c\xbc\x56\x9d\x21\x8c\x65\xb9\x90\xa6\x3f\xc9\x6f\xb1\x24\xb4\x8f\x41\x0d\xaf\x3e\x29\xe5\x6d\xcf\x72\xf9\x31\xa2\x98\xbc\x27\x64\xb9\x14\xbb\xfe\x2a\x88\x8e\x79\xae\x50\x06\xc6\xcb\xd7\x62\x78\xca\x94\xe1\x73\xf2\xb1\x44\xfd\x51\xaa\x58\x3a\x30\x3e\x31\xac\xce\x10\x3f\x6e\xdd\x70\xcb\xb9\x75\x35\x3c\x1e\x7d\x75\x60\xa4\xd2\xeb\x57\x87\xb2\xfe\xf5\x01\xe0\xef\x61\xeb\x21\xeb\x32\xeb\xbd\xf4\x82\x72\x0b\x23\x56\x70\x82\x41\x88\x10\xc1\x99\x29\x7d\x23\x82\x33\x05\xfa\x31\x88\xd2\x20\x1c\xf4\xfa\x2d\x2a\xf7\xe1\x62\xe8\x43\xad\xfd\x0a\x75\xdf\xb8\xb4\xda\xca\xef\x7b\x0b\xc5\x3f\xc6\x70\x46\xe4\xe9\x73\x36\x71\x3d\xf1\x65\xbe\x77\xbb\x6f\xb0\xa5\xff\xbc\x98\x9a\xd2\xb5\x09\x4b\xb8\x9e\x28\x30\x36\x02\xc2\x4c\xb5\x16\xbf\x06\x09\x1c\xd0\x1b\x88\x29\xaa\x98\xed\x69\x56\xfa\x9f\x11\x36\x67\x94\xd8\x5a\x14\xc9\xaf\xe7\xcd\x18\x8b\x32\xb8\xdf\xcc\x72\x3b\x04\xf5\xfc\x92\xbf\x2e\x9e\x91\x93\x72\x26\x42\x33\x8b\x3e\xb1\x34\x9c\xfe\xf4\x66\x43\xbc\x77\xc3\xda\xf5\x09\x4b\xd3\x98\x73\x2f\xbf\xb7\x6b\xb7\xae\x21\xfa\xcc\x51\xdc\x3f\xf0\x1e\x71\x27\x7b\x93\x9e\xbe\xb6\x49\x77\x94\x7f\xed\x1d\x4b\xe5\xb0\x3c\x0a\x9b\xde\x13\x1d\x9b\xfc\xc7\xde\xe7\x96\xeb\xb6\x68\x39\xd7\xcc\x47\x32\xeb\x63\x07\xe9\xab\x81\x52\x39\x3a\x6e\xb1\x44\x53\x72\x86\x94\xfc\xec\x7b\x32\x2c\x9d\xde\x93\x41\xed\xe4\x49\x66\x4d\xfe\xf4\x5d\x16\xcb\x9f\xdf\xb8\xf1\x9f\xcf\xdf\xbd\xe9\x9f\x4f\x4c\x9a\xd0\x34\x69\xf2\xb8\xf1\x13\x05\xbc\x60\xc3\x73\xcf\x6d\xb8\xe0\x96\x67\x9e\xb9\x65\xc2\x59\x67\x4d\xb8\x60\xdc\xfc\xf9\xe3\x68\xbf\xe6\xc1\x6d\xfc\x06\xfe\x29\x1d\x4b\xd4\xb9\xf9\x38\x7a\x31\xae\xff\xcc\xfb\xe1\x87\xe7\x31\x47\xfd\x66\x63\xe6\xf7\x36\xbc\x01\x6f\x54\x2f\x72\xab\x17\xb5\x6d\xb0\x57\x59\xc1\xc3\x00\xe2\xc7\xe2\x2b\xac\xf6\xcd\x03\xb9\x70\x17\x24\x5d\xd9\xb5\xb5\x29\x8f\xd7\xc5\xd9\x22\xc4\x16\xa7\x06\x84\x38\x62\x49\xaf\x87\x4d\x88\x5b\x4c\xed\x15\xe4\x76\x3d\xcb\x73\x32\xb6\x52\xf8\xed\xc2\x08\xf1\xc5\xb2\x16\xc4\x1a\x63\x69\x1f\x5e\xa0\x8e\xc2\x94\x48\x10\x97\x9c\x32\x18\xcd\x16\x2f\x43\xb5\x1e\x97\x3e\x57\xe7\x95\x15\xb3\x94\x48\x10\x70\x25\x79\x63\x0e\x45\x74\x98\x9d\xa7\xa6\x03\xc4\xde\x06\x82\x71\x39\xee\x0d\x7b\xc3\xb5\xa1\xba\xb8\x5c\x6e\x78\x18\x9b\xde\x73\xe8\xef\xfc\xa8\xc3\xcd\xef\xcd\x9d\xfb\x9e\x3a\x6f\xf7\xdb\x92\x4d\xb4\xeb\x03\x79\x34\xc9\xde\xf0\xb1\x81\xcb\x51\x0d\x77\x5f\x7b\xed\xdd\x88\x9c\x87\xe1\xfe\x87\x01\x24\x4b\x86\xfe\x12\xb8\x3f\x53\xc1\xeb\xb5\xeb\x55\x26\xa9\xa0\x2d\x87\xb3\x45\x94\xa0\x3d\x4d\xf8\x58\x32\x68\xa3\xa4\x05\x4b\x8e\x23\xbf\xf4\xcf\xc9\x2f\xc0\x48\xca\xa9\xd3\xee\x8b\x25\x0b\x9c\xf4\x5c\x41\x8e\x29\xa2\x94\x75\x62\x43\x81\xfc\xa4\xc1\x68\xb1\x79\x74\x3e\x04\xbd\xb2\xab\x59\x72\x9a\x73\x4b\xfc\x09\x05\x72\x32\x0b\x19\x4f\x60\x82\x09\xff\xdc\x67\x50\x7e\xe4\xeb\xfc\x78\xed\xe4\xee\xe3\x38\xce\xe0\xd3\x27\xf3\x26\x02\x2c\x06\x90\x6e\x13\x5f\x83\x6e\xd0\x1d\x12\xd0\x17\xde\x80\x64\x1d\x40\x84\x24\xa2\xa4\x26\xae\xd4\xdb\xd3\x24\x16\x3b\x95\x3f\x21\x9e\xa8\x92\xdf\xc9\xfb\x20\xe9\xf7\x7f\xf3\x30\xa4\xd4\x49\xa3\x1f\xd2\x2b\x96\xea\xa1\x9f\xae\x8e\x29\x0d\x19\xaf\xa3\x14\x77\x4f\x24\x48\x9d\x9c\xaa\xa8\x8c\x56\xd5\x33\xb6\xd5\x27\x64\x97\x12\x8d\x24\x12\xa4\x8b\x4c\xfa\xb0\x74\x59\x55\x75\x82\xda\xdf\x8c\x67\x72\x31\xcf\x24\x27\x73\x8b\x2a\x13\xff\xa3\x6f\x32\x9d\x44\xe6\x16\xff\x85\xbf\xc2\xd5\xfa\x00\xf4\xe9\x28\x90\xfc\xa5\xa7\x72\x62\xad\xcd\x27\x15\x53\xe0\x60\xb8\xba\x9c\xff\x43\xa8\x67\x35\x9a\xb3\x21\x99\x8f\x10\x51\x02\xb6\x34\xc9\x89\x2a\x4e\x4b\x3a\xe9\xcc\xa1\x5c\x73\xba\x33\x15\x9a\xd0\xa2\xd8\x1c\x69\x62\x73\x52\x75\x23\x92\x5e\xac\x69\xd0\x93\xc2\xb6\xcc\xdc\x68\x40\x26\x42\x82\x14\xba\x92\x16\x67\x0e\xab\xd0\x09\x38\x59\x85\xa6\x97\xf1\xa6\xae\xa6\x47\x5d\x5f\xac\x0d\xd9\xd1\x60\x47\xaf\xee\xac\x42\x7e\x9f\x10\x2e\x2e\xa3\x40\x69\xf8\x86\xa5\xbd\xcb\x31\xcc\x8d\x5d\x71\xda\x84\x99\x53\x87\xce\xe3\x31\xc0\x71\x6a\xeb\xbf\x3e\x57\x71\x1e\x96\x05\x2e\xf9\x68\x78\xe5\x99\x13\xae\x5f\x3d\xad\xfe\xea\xa6\x29\xf3\x4f\x9f\x20\xbd\xf8\xc6\xe7\xfc\xa1\xa3\x47\xf5\xfa\x3b\x56\x07\x68\x28\x06\x03\x7b\xa7\xe7\x84\xe3\x2b\x01\x6d\xd9\x4a\x40\x62\x8d\x22\x91\x4f\x56\x0c\xe8\xa2\x41\x3d\xc8\x99\x62\xf8\x14\x87\x16\x9b\x5d\xaf\x09\xb4\x31\x5c\xd5\x5e\x13\x28\xd7\x85\xdc\x61\xfe\xf8\xc2\x40\xb6\x8a\x70\x4e\xc7\xea\x40\x43\xbe\xa4\xfe\xfb\x98\x81\xeb\xdd\xa9\x7f\x16\xf6\x66\xcf\x3f\xab\x54\x3c\x75\xff\x04\x83\xec\x7a\x8a\x43\xa3\xc9\x6a\x63\xef\xf2\xe1\xf5\x12\xfe\x3f\xa9\x5b\xe4\xdd\x21\x3f\x9e\x58\xbc\x78\x9d\x8e\x4c\x3a\xd6\x30\xe2\x3f\x75\x94\x92\xed\xe7\x00\x30\x80\x13\x3c\x70\xe6\xf1\xfd\x94\xdb\x2b\x2a\xbd\x27\xeb\xa4\x2f\xc3\x44\xdd\xba\x08\xf2\xd3\x1c\x9a\x2d\x76\xa7\xec\x62\xbd\xd5\x53\xf0\xa0\xa0\x2c\xbb\xd8\x4a\xad\x4c\x6f\x2d\x58\x5b\x1a\x17\xbd\xe1\x72\xc3\x09\x5c\xf5\x62\xde\x23\x58\xf4\xcd\x75\xd7\x86\x3b\x72\x56\xea\x99\xf7\xe3\x2f\xfe\xab\xae\x3a\x7a\x28\x5b\x7f\xa9\xf7\x7b\x21\x18\xd8\xfb\xa8\x6e\x3b\xbe\xdf\xf9\x6d\xfc\xf5\x46\x15\xbb\x3d\xdd\x9c\x63\xf7\x1a\x23\x14\x69\x67\xde\xfd\x90\x0a\x30\xb7\xda\x6c\x08\x18\x8d\x11\x05\x1c\x14\x51\x30\xe2\x02\xfa\x7b\xbc\x5c\xfa\x69\xc1\x25\x1b\x75\x4a\x43\x18\x51\x02\x46\x1d\x50\xc8\xf2\x93\x9c\x05\xbd\xf9\x05\xfa\xcb\xb9\x88\x48\x69\xcc\x67\x2f\xa1\x22\x5e\x99\x04\x12\xc4\x4e\xc5\xaa\x03\xbd\xcc\x57\xb7\x4f\x40\xb0\x17\x52\x1d\x4f\x7a\xde\x8a\x29\x3d\xb7\xd7\x14\xd7\xdc\xb1\x62\x6a\xa3\x52\x53\x52\xd5\xb5\x13\x07\x16\x9c\x71\xed\xc4\x86\x68\xe5\x8c\xab\x27\xf6\xaf\x3c\xba\x9f\xeb\xad\xbf\x01\x54\x2c\x32\xd8\x98\x8c\x39\xc0\x0d\x57\x1e\xcf\x05\x6b\x1b\x17\x8c\x51\xe2\x8c\x2b\x26\x43\x9a\xc8\x31\x36\xa9\x6a\x6c\x51\x2c\x72\xba\xd9\x60\x39\x8e\x7c\x8b\x53\x71\x62\x44\x71\xcb\xe9\x66\xc1\xed\xcc\xd0\xce\x96\x47\x19\x65\x57\x12\xd9\x24\x24\x71\x66\xde\x24\xe1\x76\x25\x39\xd1\xc6\x14\x1f\xad\x99\xf9\xd7\xf6\x21\x0e\x79\xe9\xe8\xd2\x78\xb1\x13\x99\x61\x34\xf7\xa6\x94\x2d\x45\x73\x1b\x71\xfd\xf7\xec\x39\xfa\x29\xd7\x1b\xbf\xde\xb3\xa7\x8d\xae\x1b\xc0\x00\x6e\xf6\xbe\x86\x7b\x8f\xa7\xcb\xd3\x46\x97\x1c\x4d\x05\x74\x1f\x11\x8a\xa6\x2c\x19\x14\x55\xd2\x51\x52\x8d\x18\x49\xe5\xe8\x80\x4a\x7f\x6f\x43\x07\x78\x95\x95\xe2\x52\x8c\x28\x46\x83\x3e\xb6\x39\xb2\x82\x9e\x04\x35\x6a\xcd\xb2\xcf\x6f\xa1\x23\x6c\x97\x15\xce\x4b\xc5\x3b\x33\xd2\x1e\xd9\x45\x7c\x09\xfd\xa5\x0e\x76\x63\xa2\xa3\x16\x76\x08\x59\x99\x46\x76\x08\x5b\x3b\x31\xe1\x9a\xbf\x4d\x99\x74\xd1\x85\x93\xa7\xfc\xad\x98\xb2\x62\x76\xcf\xae\x5d\x6b\x6b\xbb\x76\xab\x6b\x63\xc8\x1b\xe3\x96\x2e\x1d\x37\x7e\xc1\x82\xa3\x9b\xb9\xde\xdc\x92\x48\x5d\x5d\xa4\xa2\x67\x42\xff\xbf\x9b\x80\x61\x28\xab\x2b\x70\x53\x6d\xb5\x52\xbe\x40\xbc\x43\x71\xa9\x25\x9d\xb2\x3b\xad\x94\x3f\x76\x6b\x3a\x25\x1a\xad\x6d\x75\xa6\x7a\xcd\x9f\xe0\x49\x27\x05\x36\xa7\x22\x48\xa6\x08\x1b\x5a\xc1\xc5\xd6\x2b\xcb\x6c\x20\x05\x1a\x85\xb9\xdc\x19\xaa\xbc\x21\x77\xe6\xc3\x87\x78\x0c\xf1\xe5\x3c\xef\xe4\xff\xdb\xfa\x98\x13\x7f\x51\x7d\x32\x37\xff\xd8\xa5\x76\xf5\xb4\xcd\x18\xc4\x1e\x7e\x49\x24\x5f\xaa\x37\x7f\xa1\xce\xff\x02\x47\xab\x0a\xd7\x8f\x8b\x22\x70\x30\x5d\xad\x61\x35\xc5\x05\x50\x09\xd7\xe8\x6b\x12\x53\x45\x7a\xf6\xe6\x24\x85\xa2\xa4\x3c\xaa\x74\xa1\x3a\xda\xbd\x63\x91\x68\x04\x23\x4a\x89\x9f\xad\xb5\xce\xd4\x8b\xe6\x78\x98\x2b\x8a\x62\x44\x89\x38\x65\x57\x73\x61\x51\x79\x17\x3d\x37\xf3\xa4\x55\x08\xb8\x43\x41\x66\xc8\x03\x5d\x64\x57\xb2\x30\x54\x92\x48\x24\x14\x6b\x91\xec\x6a\x36\xb8\x7d\x39\x7a\xae\x53\x4f\xce\xb4\xa5\xb1\xdb\xaa\x8f\x7d\xac\xec\xec\xb8\x40\x21\x53\x8a\x8c\x55\x42\xe7\x5a\x64\x41\xdd\xab\xd7\x22\xe3\x13\x1d\x42\x89\x6c\x61\xb2\x7a\xf8\x87\x8e\x55\xc9\x87\xd5\x23\xd8\xa4\xd6\x77\x8e\x33\xf4\x9a\xb4\x85\x86\x62\xe6\x25\xc6\x9f\xba\x52\x98\x38\xdb\x5c\xc5\x29\x8a\x85\xa9\xdb\x30\x41\x66\xf6\xf3\xb8\xb2\x61\xa4\x8e\xac\x43\xed\xf0\xb1\xab\xf5\xa5\xf0\xd9\x12\x62\xe6\xc0\xda\x6b\xe5\xb2\xfd\x1a\xf6\x17\xfd\xb2\xfe\x1f\xfb\x75\x7c\x6f\xa8\xbb\xea\xd0\x9b\xd6\xa9\x59\x47\x95\xe9\x8e\x94\x93\x8d\xa5\xb3\xfd\x19\x00\x16\xf0\xc0\xd8\xbf\xaa\xa8\xf6\xfe\x55\x67\x7c\xa7\x62\x52\xd6\x37\x75\x64\xd4\x15\x59\xb7\xd4\xde\xb9\x8c\x4b\xca\xbc\x0b\x60\xa1\xc1\x96\xb1\xc2\xcb\xfe\x92\x5b\xd4\x14\xdb\xda\x4d\xf1\x29\xbb\x4a\x4c\x4e\xe2\x60\x2f\x99\x91\xe9\xad\x8a\x43\x4e\x13\x53\x9b\x8d\x6e\xaf\x53\xef\xd0\x7d\x7d\x76\xa2\x63\xef\x97\xb0\x99\x8a\xf6\xae\xf7\xcf\x4c\x59\x00\xa7\xbd\x0a\x80\x3b\x0c\xc5\x20\x80\x91\x46\xba\x22\x8d\xdb\x24\x36\x2b\x17\x45\x62\x62\xeb\x35\x8c\x0e\x1a\xb8\x28\x66\x6a\x24\xa9\x71\x10\x38\xc6\x33\x9e\xa1\x22\x39\x24\xd7\x33\x21\xea\x85\x25\x4c\x7c\x7e\xff\x26\x53\x8b\xcc\xc1\xed\x00\xdc\xad\x27\x6b\x1b\xb2\x6d\x13\x88\xb1\x25\x81\xed\x6d\x63\x7b\x46\x85\xb6\x7d\xbb\x2e\x12\x87\xb0\x24\x23\x0c\x6d\xcd\x03\xa7\x6d\x07\xe0\xee\x33\x0c\x00\x23\x58\xa1\x5b\x66\xc5\x8e\x99\xcb\x2c\x49\x35\xb1\x25\xa9\xac\xa0\xdf\x6a\x92\x5d\xcd\xbc\xc4\x19\xa9\x55\xa8\xaa\xe6\xdb\xc0\x87\x1c\x92\x1b\xb2\x03\x6b\xc2\x92\xec\x90\xfe\xbe\x2b\xfb\x0c\x5e\x7b\x02\x80\xdb\x6a\xb0\xb1\xf9\x22\x0b\x0c\xce\xbc\xff\x4c\xd4\xa9\x20\xc6\xb8\x82\x86\x34\x31\xc5\x58\x79\xad\xc0\x9c\x4e\x33\x6f\x10\xa8\x4f\x95\x99\x4f\xe5\xe5\x74\xb3\x91\x1d\xb0\xc8\xd9\x2a\x70\x9e\xba\x46\x39\x24\xd3\xdf\xb1\x68\x2e\xc2\x92\x00\x9a\xe9\xa0\xfc\xfe\x22\x7d\x30\xdd\x62\xfc\x2b\x02\x10\x34\x91\xb0\x9c\xc1\xf4\xcc\xfa\x4a\x7b\xb6\x3a\xc9\xcf\xa7\x53\x08\x16\xc1\x16\x21\x79\x71\x05\xc5\x34\xc9\x89\xb1\x04\x82\x95\x25\x2e\xed\xec\x55\xa3\x49\xbb\x95\xcd\x92\xe6\x99\x22\x49\x2b\x9b\x22\xb5\xd2\xa0\xd2\xce\x62\xea\xec\x62\x4c\xc8\x2c\xe5\xd2\x5f\x75\xd0\x15\x65\x6c\x7b\xd9\x01\x8d\x55\x8a\xae\x6e\x7f\xe3\x81\x6a\xc5\x12\xfd\xa5\x07\xbf\xfe\xca\x5d\xf7\x24\xb7\xb8\xed\xcd\x07\xdc\x75\xea\x78\xf6\xf2\x03\x75\xd9\x93\x19\x7d\x15\x43\x86\x85\x60\x81\x22\x78\xf8\x84\x6a\x64\x92\x1b\x55\x5c\xf6\x74\x73\xbe\x2b\xd7\x18\x51\x1c\x19\x54\xd6\x56\x9e\x4c\x8a\x82\x2d\x72\x5b\xba\x38\x9a\x2a\xd2\xb7\xda\xeb\x96\x9b\x7d\x94\xa5\x99\x57\xe1\x12\x6f\x34\x3b\x6b\x4e\x41\x5a\x11\x4b\x26\x73\x09\x96\x03\x70\xe4\x26\x12\xc4\xe7\x52\x78\x63\xa2\x63\x69\x33\xc9\x95\x49\x51\x82\xe4\xb3\xb5\x90\x0e\x17\xf3\xe7\x9d\xcb\x9d\xf9\x93\x20\xb6\x4e\x25\xd0\xa3\x8f\x43\x6b\x9d\x4b\xa2\x3b\xc1\x35\x8a\x57\x59\x7d\xb4\xa1\x18\x6c\xe0\x82\x20\x0c\xcd\x8c\xa6\x2f\x3b\x9a\x05\x96\x34\x71\x45\xb3\x2f\x47\x68\x2f\x46\x61\x63\x54\x4c\x95\x9d\x76\x9d\x81\xae\x5c\x39\x25\x38\x2d\x2e\x59\x17\xe6\xce\x05\xd3\xac\xbe\x89\x3f\x75\xd5\xf4\x7f\x98\xba\x7e\x71\xaa\xd2\x69\xf1\x3d\x1a\xc8\xf4\xe9\x5c\x3f\x9d\xa5\xa1\x8e\xc9\x63\x10\x1a\x4f\x5a\xe5\x1d\x3a\xd9\x8a\xdf\xe2\x4c\xee\x2a\x25\x58\xf2\x0b\xd8\x4c\x89\x51\x56\x0a\x8b\xfe\xb2\xe2\x9b\x99\x81\x53\x94\x7d\x6f\xd6\xad\xc3\x5f\x55\x7f\x73\x6f\x67\xfd\x48\x96\x86\x89\x60\x03\x1f\x94\xc0\xe8\x0c\x0d\x79\x59\x1a\x42\x16\x3d\x17\x03\x2d\x8a\x9f\x6a\x90\xbe\x36\x9c\xd2\x50\x86\x11\xc5\xdf\x36\x08\x05\xf2\x93\x82\x53\xf6\x58\x7c\x8c\x18\x1d\x30\x9d\x38\x1a\x6d\x86\xe6\xd4\x23\xf2\x53\xd6\x06\x29\xa7\x1c\x14\x41\xb7\x4e\xc7\x8c\x27\x1f\x97\x55\x60\x83\x10\x44\x61\x55\x86\xa6\xd2\x2c\x4d\x15\x96\x34\x09\x44\x15\x8f\x3d\xdd\x5c\xe8\x09\x18\x33\xaf\xe4\xad\xca\xbe\x67\xb6\xd9\x5e\x0c\xc6\x48\x76\x8a\xb4\xd8\xa9\x74\xd1\x29\x6e\xce\x31\x76\x31\x46\x52\x7e\xfd\xb8\x3f\x9a\x41\xd1\x6c\x65\x8a\x3f\x24\xbb\x9e\x14\x64\x4b\x80\x2d\x77\x05\x25\x20\xc8\x2e\x12\x62\x6f\x98\xb5\x27\x4e\x60\xc3\x49\x54\xe9\x2f\x38\xf2\xcd\x71\xca\x35\xf3\x94\x8c\xe9\xd9\x31\x34\x52\x3b\x72\x47\xe8\xa0\x77\x32\x14\x41\x18\xe6\x66\xb8\xe3\xcd\x72\x27\xdf\x92\x26\xf6\x28\x09\xc6\x15\x87\x21\x4d\x42\xb1\x6c\xf8\xe0\xa2\x9c\x71\x01\x65\x97\x9c\x2d\xa9\x62\x6c\x09\x1b\x73\x8c\x11\x25\x28\xa7\x49\x30\xaa\x84\x65\x3d\x7a\x08\xca\xb2\xab\x59\xb0\x78\xf3\x4f\xaa\x95\xd4\xde\x77\x22\x98\x3a\xe9\x13\x88\x3e\x80\xe6\xd7\xb2\x74\xa2\x82\xe6\x93\xd2\x6a\xdb\xb3\xe7\xa8\xd6\x41\xb4\x7f\x67\xbe\x02\xa1\x01\xde\xe2\xff\x23\x5c\x0f\x16\x00\xb7\x09\xeb\x4c\xe8\x37\xa1\xc1\x84\x0d\x58\xab\xbe\xf1\x18\x46\xb1\xea\x31\xf5\x0d\xac\x7d\x4c\x7d\x5b\x7d\x07\xcf\xc3\x5e\xd8\xeb\x01\x75\x37\xf6\x78\x40\xdd\xa9\xee\x7c\x80\x5e\xa3\xcb\xd1\xbd\x62\x40\xfc\x1e\x72\xa1\x14\xaa\x61\x4e\xe6\xcd\x04\x5d\xb3\x9c\x2a\xa6\xba\x11\x6b\xab\xe5\xcf\x63\x33\xa8\x54\xd5\x95\x38\x46\x94\x3c\xd0\xdf\x32\x58\x21\xa7\x04\x8f\x5c\x54\xc6\x02\x27\x7d\xe5\x60\x57\x59\x76\x29\x1e\x7f\x22\x41\x8a\x65\xa5\xb0\x9a\x45\x52\x8a\xc1\x9c\xe8\xf0\xfa\x41\x1d\x71\xd3\x9d\xe2\xb2\x72\x43\xb8\x8e\x2d\x1d\x29\x42\xd4\x17\xea\xb9\x33\x75\x2b\x35\x65\x51\xdd\x1c\xcc\x51\x86\x8d\xbb\x61\xd5\xe8\x09\x94\x75\xa3\x6f\xec\x33\xe6\x86\x15\xf3\x97\x62\xb8\xa8\x50\xc2\xf7\xbb\x2d\x19\x74\xcb\x03\xb7\x87\x9a\xa2\xb7\x6e\xb6\x5b\xa4\x2c\x0f\x6b\xab\xd6\x7f\x36\xee\xc0\x15\x3a\x1b\x83\x45\xd7\xec\x19\xd7\x7a\xfb\xb0\xcb\x2a\x90\x0f\x57\xc6\xf6\x6e\x69\xdd\xe8\xf3\x53\x8e\x56\x8e\x2f\xa2\x31\x0b\xab\x53\x37\x14\x83\x0c\x3e\x18\x72\x62\xa5\x3a\xf1\x45\x91\xf8\x4f\xb6\x2e\x39\x27\x3b\x31\x44\xcd\x01\x31\xc9\xcd\x0e\x8f\xd7\x97\x95\x88\xe3\x2b\xd7\x99\xad\x3e\xa1\x7c\xfd\x00\xb3\xce\x27\x29\x62\x97\xca\xdb\xb0\xf9\x5f\xf5\xcf\x75\xaa\xfe\x99\x78\xd9\xd5\xec\x70\xb9\x99\xe5\xb2\xca\x8a\xc7\x9b\x38\x79\xff\x18\x3c\x3f\xb1\xbc\x3e\xa5\xdb\xdc\x93\xf4\x50\x0c\x67\xcd\x6c\x5b\x1f\x07\x80\xcc\x66\x39\x4f\x52\xed\x1f\x38\x59\x07\xf3\x8f\x63\x60\xca\xe1\xf1\xe6\xe4\xe9\x2f\x52\x54\x7c\xfe\x3f\xe9\x69\x9b\x9d\x3d\xa1\xb7\x1f\x67\x2d\xeb\xc9\xba\x3b\x30\x03\xe0\x99\x0d\xd5\xfb\x4b\xad\x84\x17\x72\x61\xe6\x49\xb9\xfa\xff\xf1\xf6\x25\xe0\x71\x14\x67\xda\x6f\x75\x57\xcf\x25\xcd\xd1\xa3\x39\x74\x6b\x46\x1a\x49\x96\x46\xd2\x8c\x7a\x24\x5b\x97\x2f\xc9\x92\x83\xb1\x8d\xb1\x0d\xd8\x46\x60\x8c\x2f\xe4\x1b\xdb\xd8\x5c\x6b\x1b\xaf\xc1\x86\x70\x38\x40\x6c\x20\x09\xd7\xfa\xdf\xec\xb2\x24\xe9\x1e\x0d\x4e\x9e\x2c\x10\x8e\x04\x4c\xec\xb0\x59\x02\x5e\x96\x0d\x81\x84\x63\x19\x1b\x08\x4b\x82\x21\x01\x8f\xfe\xa7\xab\x6b\x46\x33\x3a\x6c\xb3\xf9\x9f\x1f\x3f\x4d\x55\xcf\x8c\xba\xeb\x7b\xeb\xeb\xaa\xaf\xeb\xab\xef\xfd\x54\x5f\x4c\x2b\x30\xeb\x76\x15\xdf\x94\xaa\x37\x7f\xd0\x2d\xea\x83\x84\x57\xce\x16\x64\xb0\x28\xdf\x6a\x09\x6b\x3e\x99\x39\x76\x8b\xe4\x24\x73\x59\xf8\xbc\xb2\x5b\x73\x9a\xc6\x95\xc2\x30\xdc\x47\x09\xf1\x12\xb3\xde\xc7\x92\x60\x76\xc6\x8e\x37\x62\xe5\xcd\x95\xb0\xc2\x81\xf6\xdc\x68\x79\xd5\x16\x21\xaa\x33\x13\x30\xef\xe2\x01\xf3\x09\x51\xb0\xe5\x19\x2b\x9e\x63\x04\xcd\xb3\xa9\x37\x37\x72\xde\x92\x7e\x3d\x1b\x0e\xa0\xa7\x56\xa3\xcb\x05\xec\x01\xe8\x43\x8c\xeb\xc7\x9b\xe6\x65\x33\x16\x6b\xf2\x8c\xa5\xd8\x3c\x31\x99\x10\xbd\x06\xe5\x8f\x98\x4c\x3b\x3d\xf5\x3e\x17\xec\x8a\xa2\xe6\x1b\x91\x57\x66\x27\xdf\x1a\xce\x62\x6d\x32\xfc\x3f\x0a\xf5\x7a\x68\xf6\x2e\x89\x3d\x24\xf4\x66\x8a\x94\xa6\xde\x4d\xbd\xf9\xe6\x0d\x37\xdc\x70\xc3\x9b\x92\x9a\xfa\xf4\x8b\x23\x2f\x7d\x91\x7a\x4b\x10\x76\x2e\x5d\xba\x9b\x8d\x89\x7b\x87\x4e\xd2\xa3\xa6\x6a\xd4\x62\x3b\x6f\x91\x8b\x53\xad\xa8\x55\x11\xfd\xb5\x2c\xcd\x66\x59\xeb\x4c\xaa\xb5\x8c\x87\x9e\xaf\x1a\xa9\x36\xfd\x95\xab\xcc\x99\x54\xcb\x22\x9a\xcd\x99\x1c\x2c\x36\x07\x2c\x61\xcd\xce\x79\x2e\xcb\x6a\xf5\xd1\xde\x53\xc0\x36\x66\xda\x64\xcd\xe5\x67\x34\x2c\x60\xab\x9c\x6a\x95\x1c\x37\xdb\x3d\x9c\xd3\xa7\x25\x64\x2c\x08\x79\x3d\x30\x96\x85\xf8\xc6\xf6\xd6\x16\xb4\xb6\xa4\x9d\x05\xf2\x5e\x22\xbc\x95\xf8\x78\x2d\x69\x78\xff\x3f\x2f\x7c\xa8\x76\x52\xed\xe6\xe9\xb3\x2f\x4e\xbd\xba\x7e\x49\xc7\xec\xa5\x74\xce\x1f\x4e\xfd\x4c\x5d\xf7\xfc\x8c\xb6\xd4\x7b\xb7\x3f\xf5\x64\x79\xf1\x5b\xbe\xe0\xec\xe9\x33\x89\xfd\xce\x25\x47\xce\x9f\xb1\x64\xef\x35\x5f\xfe\x58\xd7\x5f\x16\xc3\x2e\xbd\x81\x00\xaa\x11\xc5\x75\x86\x0f\xca\x20\xe5\xaa\xb3\x26\xe3\xae\x4c\x14\x7b\x53\xb9\x2b\x1d\xc5\xde\xcc\x84\xaf\x71\x26\xd5\x1a\x63\x2c\xa7\x25\x8a\xa2\x79\x9c\x49\x4d\x21\x61\xad\x06\xb2\x7b\x30\xdf\x11\x64\x3b\x4b\x1b\xe4\x27\xf2\x5c\xe5\x55\x21\x96\x8e\x80\xef\x8d\x12\xcb\xf5\x61\xbd\x84\x47\xb2\x8f\xb1\x23\xaa\xba\xb6\x66\x74\x18\x7b\x96\x89\x3a\x32\x96\xdd\xfc\xd5\x88\x58\xf6\x9b\xd8\x60\xb8\x7e\x8c\x80\xf6\x5b\x5f\xcc\x89\x66\x97\x3a\x74\x83\x75\x6d\x26\xa6\x3d\x1b\x8f\x30\xa2\xb8\x3e\x1b\x8f\x50\x0e\x1e\x75\x23\xf1\x08\x3a\x93\xd9\x1b\xc5\x32\x78\x64\xef\x12\xd3\xc1\x68\x68\x8c\x1a\x60\xc4\x0b\x9b\x22\x6c\xe9\xec\x7f\x07\x48\x56\x5c\x3f\x7b\xe8\xce\x04\xc8\x70\x70\xbf\xc2\x87\xe1\x71\x21\xe1\x01\xfe\xe2\x82\x61\xdb\x97\x61\x62\x02\x02\xa8\x43\x0b\x76\x64\x63\xd2\x98\x83\x89\x32\x8c\x49\x2b\xc3\xa4\xde\x99\x54\xeb\x5d\x8c\xdc\x20\x83\xc9\x44\x12\xd6\xea\xb3\x75\x24\x2a\x1f\x66\x3a\x52\x5b\x97\xc6\xa5\xba\xe6\x6f\xc0\x65\x84\xf5\x7c\x56\x65\xb9\x21\x3d\xd6\x77\x9e\x5d\x5f\x68\x3f\xb7\xa5\x7b\x33\x2a\x93\xc1\x27\x8c\x00\x5a\x30\x15\x4f\x65\xe3\xd3\x66\x4d\xc6\x6b\x75\x23\xa8\xc9\x91\x1c\x6c\xae\x6d\xb2\x84\xb5\x90\x23\x1b\xb2\xc9\xc3\x90\x4d\x63\x90\xb5\x3a\x93\x83\x2d\xad\x59\x96\x75\x30\x92\x68\x31\x6a\xad\x2e\x96\xac\x21\x8d\xe4\x60\xbd\xa7\xd3\x12\x4e\x84\x0d\xf3\x7a\x3a\x09\x6b\x9d\x2d\xb2\x5b\x57\xb1\x50\x6d\x73\xc8\xdf\xce\x50\x8e\x3b\x0a\x9b\x18\x98\x93\x0b\x65\x77\x1c\x3a\x9a\x39\x7b\x11\xb5\x26\x97\xec\x56\x5b\x74\xe5\x54\x83\xe7\x04\xef\x58\x2e\x89\x73\x43\x7a\xf3\x08\xeb\xdc\x7b\x0e\x80\xef\xcf\xb2\xd1\xbf\xea\x4c\xa3\x4e\xf9\x73\x7a\x14\x01\x84\x10\x41\x0c\x0f\x67\xa3\x3e\x21\x47\x2b\x1b\xd3\x10\xeb\x2f\x99\xd1\x98\x56\x69\x4e\xaa\xcd\x0a\x51\x5b\x22\x6a\xf0\xb8\x16\x92\x93\x6a\xc8\xa5\x56\xeb\x03\x37\xf7\x67\x54\x1b\xfc\x1c\xe1\x2c\xac\xd5\xa8\xfe\x7d\x4c\x4e\x6a\xad\x24\xac\x85\x82\xb2\x5b\x2b\xcf\x6b\xd7\x75\x37\xee\xb2\xb0\x24\x19\x31\x63\x70\x6b\x1c\x1b\xe6\x73\xd2\xdb\xb4\xb5\xcf\x80\xd4\x4d\xfd\x33\x81\xb9\x86\xd8\x2e\xcc\xe0\xd7\x49\x6c\x67\xc0\x70\xe5\xb1\x63\x5f\x75\xf1\xc7\x7a\x37\x9b\xf8\x39\x7e\xa6\x39\x08\xa0\x01\x93\xd0\x83\x7f\xcd\xc6\x2f\x9a\x83\x5f\x6b\x06\xbf\xfa\x48\xa2\xd3\xf0\x9a\x4c\x4f\xef\x99\xe5\xf4\xb5\x5a\xa3\x33\x39\x18\x6c\xd4\xd5\xb6\xcd\x50\xd6\x46\x17\x33\xef\x33\xca\x5a\xeb\x89\x59\xc2\x89\x29\xc6\x97\x53\x22\x89\xda\x0c\xc3\xad\xd6\x96\x81\x73\x8a\x9c\x70\x59\xea\xa3\x21\x7d\x20\xa8\x35\x00\x6d\x1d\x47\x6f\xa7\x77\xca\x6e\xad\x36\x78\x4e\xd0\x92\x6c\xf7\xca\x30\xc4\xd9\xf4\xd8\x67\x1c\x3d\xbd\x69\xaf\x8b\x23\x8d\xf8\xaa\xb4\xe7\xe5\x0c\xb0\xff\x91\xfb\x62\xbe\x32\x19\xd8\xd3\xfc\x8c\x3f\x46\x44\xd3\xd0\x49\xd3\x1d\x74\x2e\xdb\xd9\xd0\x8d\x1f\x20\x5e\x03\x84\xd5\x86\x98\x56\x21\x26\x59\x5d\x53\xcc\x46\x27\xe8\xd6\xa3\x45\x4c\xaa\xd3\x94\x44\x67\x49\x8d\xcb\x1e\x56\x27\xc6\xb4\x4e\xc9\xe0\xd6\xea\x61\xe0\x47\x9c\x49\x35\xe2\xd2\x47\x56\x95\x2a\x5a\xa9\x2f\xa9\x76\x28\x6a\xa9\x4b\xeb\x22\x61\xad\xc8\x93\xd4\x66\x90\xb0\x16\xc9\x4c\x43\x13\xe5\x78\x9e\xab\x41\xd7\xd9\x52\xb7\x56\x50\xd7\xde\xae\x76\xc9\x83\x25\x3e\xe3\xd5\xab\xc8\xad\x55\x56\xe9\xe3\x45\x67\x8d\x8e\x7b\x65\x5d\x16\x63\x9c\xea\x32\xbc\xb1\x23\xf0\x0e\xa5\xa3\xd8\x47\xd2\x68\xd4\x8c\x9a\xa8\x32\xbc\x1a\x4d\xa9\x3f\x3d\x31\x7f\xd6\x85\xfd\xa9\xf7\x04\x13\x86\x5e\x5d\xf5\x4f\x9d\x93\xff\x61\xf9\xab\x9f\x9e\xde\x26\xd0\x1b\x6f\xec\xbf\x71\xee\x9c\x29\xc7\x77\xdc\xf4\x52\x4f\xd7\xd1\x6f\x3e\xf3\xef\x24\xb4\x60\x7e\xc7\x8e\xea\xc1\x2b\xd7\x0b\x9a\x40\xd6\x5c\xb4\x60\xe9\xe5\x64\xf2\x43\x8f\x77\x5e\x70\xe9\xf9\x6d\x6e\xd3\xfe\x27\x27\xb5\xb4\x4c\x4a\x7d\xf1\x87\x07\x4d\x9b\x6e\x9e\x50\xf7\x93\xe8\x79\x17\xce\x9e\xb1\xf8\x89\xfb\x3b\x7b\x27\xd7\xab\x8b\x88\x2c\x95\x5e\xbe\xf1\x06\xc3\xd6\x9d\x92\x6a\x61\x3c\x2f\x65\x2c\x43\x53\xae\x4f\x89\xe4\xfa\x94\xac\xe3\xf9\x94\xd2\x8e\x24\x39\xa9\x9a\x95\xc1\x50\xa1\xcf\x12\xd6\xc2\xfe\xa4\x1a\x8e\x68\x21\x7f\x72\xb4\x67\xc9\x27\x3f\x41\xf3\x0b\x4a\x02\xc1\xb3\x79\x96\x58\x30\x7b\x26\xa6\x28\x3b\xa8\xaa\xaa\x72\x94\x67\x69\x0a\x91\x3e\x3d\xf2\x19\xcd\xe5\x88\xa1\x43\x4f\x7d\x9a\xfa\x2b\xc9\xde\x9e\x66\x10\xc6\xbc\xfb\xd3\x2c\xb6\x98\x43\x6f\x12\x25\xb5\x24\xd7\x9d\x04\xd1\xe0\x5a\x91\xde\x86\x0f\x25\x08\x61\x01\xe2\x1e\x5d\x07\xed\xe9\x18\xc8\x4a\x31\x99\x28\xb3\x7a\xa8\x3d\xac\x95\x49\xc6\x52\x57\xf9\x71\xcd\xec\x49\xc6\xcb\x59\x46\x86\x72\xf0\x7d\x45\xe6\x72\xce\x00\x02\xcd\x6e\x10\x7e\xa8\x56\x99\x87\x32\xb6\xc0\x3f\x9a\x6a\xc5\xb0\xeb\x86\xf9\x56\xac\x6f\x8d\x26\x5b\x59\xcf\xec\xb9\xb9\x59\x8c\x2b\xa4\x8d\xe4\x52\xae\xd0\xe7\x4d\xa9\x53\xa7\x0f\x73\xde\x95\x6c\x79\x2a\x10\xc2\xc5\x23\xe5\x29\x13\x93\x89\x42\x43\x9e\x42\x2e\x4f\x91\x21\x4f\x11\x93\xa7\x28\x23\x4f\x91\xec\x1e\x74\xc9\x95\x55\xac\xff\xce\x4d\xa4\x8c\x96\x33\xbb\x6c\x6c\x91\x32\xfc\x31\xfc\xed\x68\x4c\xa1\x38\x8f\x0c\x79\x6f\xd8\x16\x63\x72\x99\x08\x93\x6b\xc2\x68\xb9\x6a\xc4\x64\x22\x68\xc8\x15\xd4\xe5\xaa\x8b\xa8\x95\x86\x5c\x95\x4c\xae\x4a\x5d\xae\x7a\x5d\xae\x4a\x26\x57\x49\xe9\xd7\x90\x6b\xd8\xb2\x3a\x73\x77\xad\x4e\x5b\x54\xa5\x67\xea\x31\xf1\x6d\xc3\x96\x3a\xfd\x6d\xa3\xd3\x28\xef\xb3\x63\xf0\x31\x76\xc8\x5a\xdc\x36\x52\xba\xa0\x98\x4c\x94\x1a\xd2\x95\x4a\x49\xd5\x1f\x51\x43\x31\xad\xd0\x9c\x54\xab\x15\xf6\x4a\xe6\x3f\xce\x22\x1a\x8b\x5d\x2c\x88\xaf\x56\x4e\xaa\x65\xfa\xb4\xad\x8b\x5f\xc6\xc4\x2f\xd3\xc5\xd7\xdf\xc4\x8a\xfd\xb2\x3b\x61\xcd\xb3\x31\xf9\xd5\x90\x1c\xb7\x7b\x82\xfa\x43\x59\x5b\x66\x84\xaa\x9b\x65\x55\x6e\x87\x66\xb5\x67\xe2\x70\xc7\x41\x24\xe8\xcd\x80\xa1\xcf\xd8\x63\x03\x72\x31\xb1\x29\x69\x28\x64\x62\x1b\x1b\x8e\xe4\xb1\x63\xa7\x6f\x67\x50\x08\x4e\x7d\x92\x16\x86\xe2\x00\xf9\xa1\xf4\x36\xf3\x83\xd5\xa7\xfd\x60\x8c\x3a\xe5\xdc\x1c\x6c\x73\xd9\x63\xd3\x45\x42\xd2\x1b\xa6\xd4\xa9\x2f\xeb\x69\xc7\x97\x2f\xc0\x78\xe7\x16\x76\x4b\x47\xc7\xbb\xee\x59\x9d\x6b\x7b\x0c\x95\xfd\x80\x84\xe8\xb3\x4c\x33\xbf\x9c\x6a\x5c\x1a\xc2\xd0\xe3\x80\x70\xa7\xf4\x51\xae\x6f\x8d\x7c\x3d\xdf\xda\xc2\xb4\xfe\xd8\x48\x88\xbe\xc3\x77\xf0\x94\xf1\x5b\x40\x1c\xfa\x0e\x20\xdc\x2f\x1d\xe6\xbe\xb5\x99\xdc\xb7\xc6\xd6\x5b\xac\x46\x48\x96\x45\xe1\x1c\x33\xff\x4b\xef\xda\x4a\x62\x0b\x90\x50\x31\xb1\xd1\x13\xc7\x8e\x7d\xe9\xd3\x6f\xad\xd7\x20\x20\x3a\x74\x92\x6e\x92\x3e\x42\x10\x4d\x58\x88\x4c\x22\x36\xb5\x21\xa2\x89\x96\x0c\xc3\x9b\x91\x86\x8d\xad\x88\x97\x72\x72\xb7\x09\x95\xb2\x3b\x21\xe6\x9b\xbd\x15\xba\xc6\x95\xca\x9a\xaf\x50\x1f\x24\x1b\xaa\x8d\x04\x36\xa2\xac\x99\x8c\xf8\x5a\x36\x0f\xf8\x27\x35\x91\x5a\x73\xed\xa4\xda\x26\xa2\xbf\xf8\xfb\x27\xf9\xcd\x3e\xf7\x08\xa6\x13\xb6\xc6\x19\x25\xf6\xff\xbe\x70\x7f\x0b\x75\xcc\xeb\xfa\x6c\xee\x33\xa4\x62\xd6\x84\xfe\x45\x8f\xf4\xbe\x30\xe7\xd1\x55\x57\xa7\x5e\x38\xf9\x71\xea\x37\x24\xb4\x6f\xcb\xd6\x5b\xab\x76\x5d\x72\xfd\x1e\xf2\xea\x1f\x88\x1c\x6b\xa4\x0b\xee\x98\xb4\xef\xea\x35\x26\x57\x69\xfe\x1b\x05\x3d\x91\xf5\x57\x2f\x59\x93\x3a\x71\xe8\xe7\x7f\x4d\x3d\x4f\x8a\x7e\xbd\xe9\xfe\x67\x0f\x6c\xab\x6d\x79\x50\xd7\x13\xc6\x1d\x63\x0a\xa3\x00\xb5\x78\x60\x98\x3d\xa6\x98\x39\x3c\x1c\xc9\xc1\x50\x71\xd0\x12\xd6\xfc\x8e\xe4\x48\x42\x99\x09\xd9\x84\x32\x83\xb5\x05\xba\x59\xc8\x13\x1c\x7a\xd2\x96\x5f\x16\xcf\xcc\x60\x99\x2d\xcf\x12\x4e\x94\x1b\x16\x61\xdd\x30\xe9\x8c\x96\x57\x2b\xbb\x07\x4d\xfe\x62\x63\xf6\xe4\x04\x4b\x5a\x90\xc8\x6e\xb5\xb6\x5d\x2d\x36\xb2\xec\x8c\xc5\x44\x33\x96\x1b\x6e\x24\x3b\xcd\x2f\x46\xbc\x8e\x8c\x62\xab\x91\xea\xb3\x9d\x71\xa2\xc1\x5b\x23\xbd\xcd\x7d\x71\x7d\xd9\xbe\x38\x3e\xa7\x9c\xab\x23\x2e\xcf\x45\x33\x8e\xb8\x1c\x16\x9b\xac\x55\x8e\x31\xa9\x6c\x0e\xb0\x47\x7a\xf7\x38\x7c\x36\xf4\x49\x7d\x12\xec\x1a\x66\xb5\xc9\x6e\xf3\x28\xdf\x5b\x86\x6d\xe7\xcc\xbe\xb7\x3c\x3a\xda\xf7\x76\x06\xe6\x1d\x36\x4a\x8c\x43\xbf\x33\x93\xfb\xdd\xc6\x63\xe1\x11\x7e\xc4\x27\x3a\xde\x6e\x13\xc6\xf2\xb7\xf1\x99\xe0\x5c\xfd\x6d\x79\x2e\xd9\x43\x47\xfa\xdb\x72\x41\xcf\x5d\x31\x18\x13\xf8\xfd\xe9\x31\x69\xde\x38\xd8\x8b\xaf\xf3\xe9\xac\x34\x8b\x54\x28\x2d\x47\x98\xfb\xd8\xae\xcb\xf2\xb1\x79\xf4\xc7\xa8\x24\xdb\xb9\x66\x88\xd6\x20\x66\x7b\xd9\xd4\xa0\xa2\x56\xba\x32\x7b\xcf\x22\x7c\x58\x51\xfd\x6c\x8c\xce\xf6\xad\xb1\x01\x26\x4f\xf6\x94\xd0\x31\x5d\x6b\xb9\x12\x8f\xf1\x78\xc8\xe3\x0b\xbf\x77\xc4\x93\x32\x9e\xfa\xe5\x67\x3d\x2f\xa7\xdd\x59\x38\x50\xae\x87\x47\x33\xfe\xb4\x55\xd9\xfe\xb4\x34\x2d\xd1\x38\xfe\x34\xd5\xed\x32\x12\x9c\x39\x64\xfd\x37\x23\x1c\x6b\x6a\x40\xff\x2a\xc7\xa1\x96\x47\x33\x0e\xb5\x11\x1d\x9d\x7e\xc5\x4e\x8b\xa9\xcf\xd9\x39\xa2\xee\x24\xb6\x55\x69\xf1\xc8\x3c\x62\x1b\xd9\xcb\xbf\x3f\x76\xec\x74\xc1\xb0\xc2\xbe\x6e\xac\xa3\x8b\x98\x8a\x43\x74\x06\x4d\xcf\x49\x4d\xe0\xe9\x72\x78\x48\x23\x4b\x9a\xc3\xd3\x8b\xd0\xe3\xaa\xc5\xc8\x67\x66\x53\x86\xf3\x1c\xb2\x96\xe8\xc7\x54\x2a\x9d\x5e\x47\xaa\x53\xff\x45\xaa\x85\xc9\xef\xbc\x93\x5a\x9d\x4c\x8a\x75\xc9\xa4\xa1\x4b\x5b\xe8\x34\xfa\x33\xee\x67\x5b\x99\xed\x67\xe3\x36\xfa\x39\xf9\xd9\x9e\x30\xcb\x1e\x9a\x71\xb4\x59\xce\xe2\x68\x6b\xe5\xf3\x51\xcc\x88\x3e\x64\x09\x97\xc6\x71\xb4\xe9\xa0\x46\xd8\xb3\xaf\x5c\xd6\xd0\xf7\xc8\xea\xa5\xab\x52\xff\xf3\xc7\xe8\xa2\x09\x33\x1f\x59\xbd\x72\x80\x54\xc9\x6e\x13\xa1\x05\x75\xfe\xab\x07\xee\x71\x56\x7b\xaf\x1e\x70\x39\x4c\x06\xba\x2e\xc7\x5d\xbf\x99\x75\x72\xbf\x8e\xb0\x23\xff\xee\xdf\xcc\xfc\xe3\x81\x29\x57\x55\x12\xa1\xc0\x62\xfd\xf1\x5d\x29\xd5\x2c\x25\xee\xf1\x4e\xbc\xa2\x92\xb0\x77\x38\xc6\xfd\x23\x1d\x45\x01\x0a\x71\xc9\xb8\xec\x3f\x45\x63\x39\x89\x8a\xd3\x4e\x22\x8f\xd7\xf0\xb2\xc9\x3e\x7f\x21\x4f\xb6\x75\x56\x2a\x20\x36\x30\x8f\xe2\x03\xda\x68\x78\xdd\x46\xb1\x02\xd1\x21\xc3\xe9\x96\xdb\xde\x05\x5f\xbf\xbd\xcc\xeb\x26\x7b\xbc\x46\x3b\xe5\xb8\xc3\xe7\x67\xab\x79\x67\x6c\x2b\xf3\xc0\x8d\xe6\x2e\xea\xe1\x6f\x1a\xa3\x5a\x2b\x7e\x39\xbc\x5f\xce\x68\xef\x47\x28\x40\x29\xfa\xc7\x6d\x6f\xd9\x58\xed\x2d\x1f\x81\x6f\x42\xf6\xf9\x8b\x4b\x79\x2a\x59\x47\x61\xd1\xd9\x1b\x9e\x19\x88\x47\x35\x7e\x20\xe3\x90\x1b\x8d\x75\x59\xb6\x3f\xce\x68\xff\x61\xb6\x03\xb8\x44\x1f\x6f\x73\x25\xf0\xea\x46\x62\x51\x4c\xf3\x98\x93\x6a\xa1\x32\x2c\x50\x69\x96\x40\xaa\x9f\x11\x23\xc8\x49\xd5\x13\xd1\xfc\x39\xfe\x39\xb5\x50\xff\xaa\x44\x36\xc8\xe8\x0a\xfd\xb2\x5b\x93\x4d\xed\xed\x6a\x89\xcc\xd2\x97\x9d\x55\x3c\xc3\x53\x37\x4a\xba\x45\x86\xa7\x6e\xb4\x68\x21\xee\xa8\x13\x0c\x7e\x24\xe9\x28\xbc\x28\x66\xac\x68\x23\x18\x92\x4a\x32\x0c\x49\xa5\x24\xac\x99\x74\xab\x5d\x07\xfc\x1c\xb9\x92\x58\x00\xc0\xb8\x84\x49\x0e\x1e\xa1\x38\x9a\x37\x89\x3e\xc3\x15\x47\xc0\x75\xa9\x2b\xe8\x2c\xc6\xa5\x19\xc4\x12\xce\x9d\xe7\x17\x0d\x06\x66\xc3\x32\x2c\x17\x93\xaa\x3b\xa2\x92\x48\x3a\x4d\x81\x4b\xb7\x0f\x3d\x8a\xa2\xba\x8c\x5c\x05\xb6\x74\xae\x02\x97\xec\xe6\x14\xc0\x7e\x4e\x9d\x67\x2a\x1f\x8f\x02\x58\x0e\xca\xb9\xe4\x79\xd7\x91\x50\x64\xf7\x45\x9c\x3b\x2f\xf5\x26\xa9\x1a\xe6\xcf\x33\x15\x9e\xd6\xa6\xf5\x66\xd3\xe7\x91\x87\x49\x5d\x36\x81\x9e\xc8\x71\x3e\xcc\xbc\xb9\x65\xb8\x0a\x71\xbf\xae\x31\x25\x31\xcd\x67\x4e\xaa\xc5\xca\x28\xe0\xcb\x23\xaa\xef\xb8\x56\x24\xb3\x24\xa3\x92\x8e\xbd\x2b\x69\x90\x67\x94\xc9\x49\xad\x82\x84\xb5\x22\x9f\xec\x1e\x24\xb2\xcd\xab\x3f\x09\xc5\xb2\x26\xd2\x73\xef\x17\xae\x30\xe3\x76\xcd\xe7\x06\x95\xc4\x18\x3d\x93\x64\x9a\x23\x60\xd9\xd0\x49\x73\x37\xcb\x5f\x58\x8d\xad\x46\x7c\x1d\x63\x37\xcd\xa4\x31\x34\x0b\x3c\xb3\x91\xb1\x57\x43\x4c\x26\xf2\x1c\x5e\x6a\x78\x5e\xd3\x94\x97\x85\xc3\xc9\x0b\x9d\x6c\xde\x8a\x3b\xcb\x19\x6f\x8a\xd5\x1a\x56\x5d\xca\xe0\x34\xa7\xdd\x1a\x66\x9e\xaf\xf2\x42\xd9\xad\x79\x69\x7b\xbb\xea\x94\x55\x77\x66\x4b\x8b\xe2\xf3\x0f\xef\x34\x0d\x66\x65\x97\x48\xd3\x05\x2e\x23\x73\x89\xa3\xf7\xce\x0b\xc4\x65\x99\xcd\xa7\xdf\xeb\xbf\xa9\x27\xf5\x69\x4a\x25\x55\xdf\xbf\x77\xc2\x05\xb5\x8d\x73\x6a\xee\xfd\x3f\x2c\xe7\x8e\x95\xcc\xce\xb7\xf2\x2d\xa9\xb6\x3c\x72\x3e\xb1\x1d\x7e\x9a\x4a\xd4\x44\xa5\xa7\x9e\x00\xb7\xb9\xcc\xf9\x74\x2e\x2a\x11\x45\x3b\xae\x47\x3c\xa0\xbf\xb9\x14\xc7\xb4\x1a\x31\xa9\x16\x28\x6c\xb6\x54\x6d\x31\xad\x51\x4c\xaa\x93\x94\x84\xe2\x0c\xe8\xf2\x2a\x52\x26\x8b\x76\x95\x33\xa9\x56\x19\xeb\xd7\x76\x4f\x92\x39\x5d\x62\x55\xb2\x7b\x9a\x95\xda\x9c\x05\xc5\x01\x57\x5d\x33\xa3\xca\x91\x8d\xad\x05\x5a\x4d\x40\x76\x6b\xfe\x32\x43\x68\x5f\xbb\x46\x1b\x33\x24\x89\xc6\xe4\x39\xfe\xe2\xe8\x08\xe3\xb9\x3a\xbd\x96\xa0\x4f\xa2\x3b\x8f\xf4\x4c\x7f\x6a\xfb\x88\xd5\x84\x9d\xbf\x9c\xd1\x73\x64\x67\x8e\x55\x2d\x56\xf0\xb5\x05\x63\x36\xbd\x6c\xc1\xc2\xfe\xec\xa5\x85\xfe\x8b\x2e\xea\xcf\x36\xb2\x57\x66\xd6\xc8\x0c\xdf\xbf\x1d\x56\x66\x95\xad\x19\xe5\xfd\x57\x1d\x31\x2d\xcf\x9c\x54\x9d\x0a\x4b\xb2\x60\xec\x03\x18\xb4\x9b\x2d\x96\xb0\x66\x93\x59\x9e\x1a\xbb\x9c\x1c\x74\xb0\x0f\x64\xd9\x48\xba\x60\xb1\x19\x04\x69\x0e\xbb\xec\xd6\x04\xb1\xbd\x5d\x93\xcd\x9c\x09\x7b\x8c\xed\x02\xc3\x1a\x9e\xbd\x63\xe0\x1d\xbe\xef\x38\x6b\xc3\x80\xc2\xf4\x99\xe0\x56\xfa\xae\xb8\x56\xfa\x18\x16\x94\xb3\x7c\xd3\x52\x4c\x13\x68\x92\xb0\xf0\xde\x34\x13\x5d\x3a\x54\xd1\x98\x4b\x6e\x4d\x4f\x1d\xf4\xdd\xcc\x44\x41\xb0\x9d\xbe\x2c\xae\x90\xfe\x82\x02\x5c\x00\xc6\xc1\xec\x48\x0e\xba\x4c\x76\x0b\xf7\xc5\xb1\xed\xd5\x89\x82\xcc\x9b\xaa\x95\x84\x13\x36\xc3\xd6\x66\x24\x82\x05\xb2\x5b\x13\xd9\x10\xe5\xb2\xb3\x17\x78\x4d\x34\xf1\xc8\xaa\xb1\x6c\xeb\xed\x23\x5f\x35\xbf\xc8\xd9\xe6\x99\xc3\x83\x81\x1c\x96\x8b\xbf\xe5\xbb\x3b\x84\xc5\xf4\x25\x71\x32\x44\xf8\xd3\x59\x1c\xf5\x63\x04\x29\xc3\x1d\xb4\x4b\x58\xcc\xf8\x05\xd6\x08\x8b\xa5\x87\xcf\xfa\xfb\x35\xd2\x44\xfe\x7b\x45\xfc\x9c\x2c\x37\x15\x8e\x95\x77\x1b\xc7\x35\xc9\x6f\xe4\xdd\x96\x8c\x34\x41\xec\xaf\x0b\x62\xa2\x57\x79\xf4\xae\x2e\xf1\xf3\x67\xc8\xb2\xd4\xc3\xcf\x1a\xed\x6c\x17\xbf\x20\x6b\xc7\xbe\x0e\x39\xae\x51\xff\x18\xf9\xbb\x63\x5e\xb1\xbd\xeb\xd4\xa3\xe2\x17\xe4\xb2\xe7\x9f\x4b\x3d\x6a\x5c\x47\x49\xfd\x85\xac\x20\x15\x5f\xe3\x3a\x2c\xc5\x7b\xd7\xa9\x7b\x52\x7f\x21\x36\x52\x9a\xfa\x73\xea\x7d\x7d\x2e\x53\xc4\xcf\x85\xc7\x59\x7b\xf2\xd0\xcd\xb4\xcc\x14\xe3\x17\x63\x94\x52\xf9\x69\xf9\x54\xc9\x48\xfc\x91\xe7\x37\x32\x22\x71\x51\x55\x93\xcc\x18\x73\x99\x71\x9d\x16\x3b\x96\x11\x7e\x61\x16\x00\x1c\x06\x41\xc7\x40\x78\xf2\xcc\xf7\x34\x64\x50\xa9\x8b\x89\x61\xe3\xf7\xe4\xe2\xa8\x66\x59\x35\xa5\x13\x44\xa5\x21\x8a\x15\xa4\x81\x7a\x36\x0b\x2c\x0e\x99\x00\x65\xa8\x42\x78\x8c\xd4\xb3\x7b\x7e\x03\xac\xdb\x62\x09\x8b\x71\x4f\x21\x7d\xcf\x04\x65\x49\xf1\xf9\x6d\xf5\x87\xa0\x88\x86\xcf\x70\x67\x7f\x81\x9c\xb9\xb3\xd2\xf5\xfe\xa3\xaf\x75\xfd\xf7\xa3\xbf\x27\xf9\x18\xfa\x53\xea\x03\xe2\xf9\xfc\x4f\xa9\x0f\x8c\x3d\x36\xe4\xa4\xb0\x82\xda\x60\xd7\xdf\x95\xf2\x22\x09\xca\x6e\xcb\x0b\xa2\xbf\x09\xe2\x78\xc2\xc2\x78\x13\x78\xa1\x39\xb9\x0a\x66\xc7\xaf\xef\xdd\xbd\x76\xc3\xee\x9b\xd6\xaf\xdf\x2d\x1c\x5b\xb2\x62\xd7\xce\x95\x4b\x56\xde\xf8\x77\x6c\x0e\xd8\x0f\x48\x05\x2c\x1f\x3b\xdf\x7f\xcf\x62\x2b\xa8\x25\xc6\xf2\xd3\x6b\x92\x55\x51\xb2\xb2\xb3\xe7\x67\xdb\xb3\x74\x38\x1b\x57\x3a\xc3\xd9\x70\x16\xb6\xf4\xb1\x9f\x84\x0e\x92\xd0\x2e\x23\x9f\x6b\xfa\x00\xc1\x3a\x1c\x14\xa6\xb2\xb8\xf8\x20\x88\x6a\x66\x62\x48\xac\xfd\xaa\xa8\xb0\xeb\x31\x25\xa1\x86\x62\x30\xee\x9d\x75\x06\xe9\x8e\x50\x96\xcd\xb5\x33\x0f\x07\x85\x50\xee\x75\x54\x41\xe1\x97\x1a\xbe\x0e\xd1\xaf\xc3\xc3\xef\xe7\x8d\x8a\xb7\x07\xc1\xcc\xa1\x93\xe2\x47\xd2\x2f\x10\xc6\xdf\x21\x5e\x0b\x83\x38\x9f\x45\x3b\x68\xb2\x98\x4c\x80\xd4\xda\xec\xcc\x22\x86\x29\xa9\x96\x28\x09\x89\xb2\x0f\xfc\x31\x4d\x32\x19\xac\xd7\x0d\x11\xb5\xfe\xb8\x26\x98\x14\x45\x2b\x73\x26\x35\x4f\xa1\xa2\xc4\xcb\xea\xd9\x6a\x7a\x89\x95\x85\x96\xd7\x97\xe9\x67\xf5\xb0\x32\xf7\x63\x23\xe3\x3b\x0d\x30\x96\x1b\x4d\x96\xd2\xf6\x70\x6b\xac\xb5\xaa\x35\xc6\x27\xc4\x34\x51\x3d\xe7\x53\xf3\x66\x11\xc1\x62\x32\x99\x79\xf7\xdd\x77\x93\xc6\x3f\x77\x6d\x99\xe1\x6d\xbd\xba\x6d\xdb\x5e\xf2\x78\x6a\xa1\x7e\xec\xbd\xb6\x63\x63\xcc\xdb\x7e\xfd\x94\xcf\x52\xaf\x90\x17\x8f\x6c\x3d\x62\x3f\x4a\x2a\x5d\xce\xf7\x5c\x05\x8f\x0c\x38\x8f\x6c\x3d\x62\x59\xfe\x2d\x59\x7e\xc7\xe9\x22\x05\xcf\x5a\xf4\xe7\xf8\x0a\xf1\x1e\xba\x9c\xe5\x25\xf2\xe3\x6e\xce\x8d\x46\xec\xb1\xb4\x8e\xc7\x25\x67\x81\xa2\x28\xec\xf3\xf4\x47\xac\x0e\xc3\xc7\x2d\x1a\xec\x71\xa6\xe3\x09\x89\x8d\xfc\x63\xa7\x2f\xd2\xc7\x00\x0b\x19\xde\xef\xcc\x62\x6c\x12\xce\x61\x92\x1a\x97\xfe\x96\x60\xb3\xa7\x93\xcc\x0c\xe6\xe5\xbb\xbd\xdc\xe5\x17\xf4\x56\xc9\x55\x32\x91\x19\x31\xab\x5c\x25\xd7\x8a\x55\xa2\x59\xbe\x82\xdc\xb9\x6b\x3f\xb9\xe4\xa1\xed\xa6\x6b\x1f\xb8\xc9\x34\x70\xde\x06\x93\x34\x73\x60\x20\x35\x97\xc4\x53\xb3\x85\xb2\xd4\x01\xb2\xe6\xf4\x3b\xa4\x98\xa4\xde\x23\xf5\x24\xf5\x1f\x20\x8c\x4c\xa1\x8d\xb6\x41\x44\xab\xa1\xe7\x09\x42\x61\xa6\xe1\xec\x7a\x86\xe2\x93\x31\x71\xf0\x82\x8f\xea\xcd\x72\x50\xd6\x2f\xf0\x25\xe7\xa8\xf3\x00\x74\x19\xcb\x59\x50\xa2\x5b\x4f\x3e\xdd\x7a\x2a\x34\x58\xc3\x35\xb9\x28\x96\x93\xba\x20\xdf\x60\xeb\x3e\x7b\xea\x02\xd5\x6b\xac\xd8\x94\x70\x26\xef\x42\xaf\xec\x66\x04\xd9\xfa\xcb\x93\x8d\x25\x4b\x3a\xc7\xbc\x06\xba\xdd\xe0\x79\xe4\x2f\x7f\x98\x7b\xdf\x8a\xfa\xf3\xb6\xcf\x59\xb9\xf2\xb5\xd7\x52\xbf\x15\xf6\x91\x90\xb8\xfe\x57\xb3\x8e\xbd\x59\x51\xf6\xbe\xaf\xb0\x7f\xf1\x2c\x96\xdf\xe0\xab\x7b\x98\xdb\x40\x40\x09\x40\x77\x72\x99\xb6\xe4\xca\x94\x95\x8c\xc1\x1a\x51\x8b\x62\x83\x0e\xab\xc9\x11\xd6\xec\x79\x7f\x93\x68\xa6\x6c\x91\xce\x2c\xcc\xa8\x44\x0d\xc2\x43\x4c\x98\x91\xc9\x1a\xbe\xba\x27\xcd\x5b\x2f\xea\xf2\x98\x27\x33\x79\x22\x88\xe1\x17\x86\x44\x5a\x63\x94\x73\xd7\x0f\xca\x45\xba\x91\xca\x04\x8b\x17\x14\x86\x15\x45\x51\xab\x23\xba\xd1\x5b\x9e\x9f\xe4\x1c\xa0\x4c\xc0\x96\x73\x15\xb0\x89\x84\xd5\x62\x45\x6b\x64\xdc\x81\xf1\xc6\x26\xfd\xbb\xc6\xb0\x35\x1c\x6f\x6a\xd4\xab\x4d\x85\x56\xb6\xe7\x23\xaa\xdb\xca\x4e\x63\x9b\x4c\x53\x1a\x07\x2d\xda\x28\xbb\xb5\xea\xf2\xf6\x76\x35\x26\x6b\x95\x41\x1d\x99\x6a\xc2\xe8\x7b\xb4\x72\xdd\x4e\xb4\x1a\xfb\x38\xc6\xc1\x28\xf8\xb5\xb0\x6b\x19\x47\x35\x46\xa2\x39\x9e\xae\x18\xd8\x5e\x9a\xc1\xf6\xf1\x91\xd8\xc6\xe5\xa2\xba\x58\x2c\x07\x5a\x7b\x44\xad\x8c\xb1\xc0\xe2\x72\x45\xb3\x5a\x93\x5a\xb0\x59\x51\xfe\xbf\x82\x5b\x1e\xe4\x0b\xdb\xff\x2f\x20\xec\x3c\x47\x85\x1c\x57\x43\x09\x9b\xc3\x30\x6b\xee\x9f\xda\x97\x3a\xbb\x3e\x43\x85\x85\xa5\x21\xff\xb7\x9d\xdf\x3d\x96\x2e\x87\xbe\x93\x8a\x99\x2f\x35\xdf\x05\x02\x0b\x04\x80\xe7\x29\x87\xe5\xc6\xd3\x3f\x00\x2c\x18\xfa\xce\xd0\xfd\xe6\x4b\x8d\xd1\x2d\xeb\xbf\x13\xc2\x87\x98\xc1\xd2\x84\xa6\x8c\x43\x68\xc4\x2d\xc2\x7e\x28\xf4\x79\x44\xe9\x41\x5c\x21\x25\xb1\x54\xea\xc6\x64\x32\x0b\x8a\xf0\x22\x6e\x14\x5e\x42\x85\x78\x3b\x4a\xe8\x65\x68\x13\x5c\x98\x2a\x06\x71\xb5\xb0\x10\xfb\xc5\xf6\xa1\x4f\xe9\x41\x2c\xa5\x07\xf1\x2f\xf4\x20\x66\xd3\x83\xe8\xa3\x07\xd1\x4e\x0f\x62\x03\x3d\x88\xe5\xf4\x20\xba\xe8\x41\x5c\x4a\x0f\x62\xbe\xd0\x87\xfd\x82\x82\xcd\xb4\x00\x13\xe9\xf7\xb0\x8f\x56\x62\xbb\x78\x1a\x01\x73\x11\xba\xa5\x0a\xe4\x4b\x95\xd8\x27\x95\xe1\x32\x69\x0a\xf6\xd1\xfb\xb0\x8f\x3e\x88\x7d\xd2\x62\x2c\x97\x1e\xc3\x3e\x61\x31\x1e\xa0\xdf\xc2\x54\x29\x8c\x7d\x74\x21\xf6\x99\xbe\xc4\x3e\xfd\x73\x69\x3b\xfa\xa5\x89\xd8\x27\xdd\x8f\x7e\x69\x16\xf6\x49\x05\x58\x42\xbf\x85\x52\x69\x27\xae\x95\xfc\x30\x9b\xfd\x28\x94\xfc\xa8\x90\xf2\x21\xd1\xc3\x98\x23\x74\x60\xbb\xb8\x14\x82\xd0\x01\xbb\xb8\x0b\x0d\xe2\xdd\x20\xc2\x3f\x62\x0e\x9d\x8d\x49\x74\x0f\x36\xd1\x10\xa6\xd0\x3d\xe8\xa1\x5d\x98\x23\xfc\x16\x25\xac\xbe\x07\x03\x42\x15\x76\x0a\x15\x43\x0f\xd2\xf3\xb0\x49\xaf\x9b\x3e\xc4\x26\xba\x07\x6b\xf9\xf7\x7a\xbd\x47\xf8\x15\x36\xd1\x00\xa6\x09\x47\x61\xd5\xff\x86\xfa\xe0\x92\xde\x41\x19\xf5\xa1\x80\xfa\x20\x51\x1f\xce\x17\x0e\x21\x2a\x98\xf1\x03\xe1\x10\x2a\xa5\x08\x06\x18\xf6\x33\x70\x27\xfd\x1e\xbe\x41\x9f\x41\xbf\x74\x2b\xe6\xd1\xf7\xe0\x13\x24\xec\x94\xcc\xb8\x9c\x76\xe3\xbb\xa6\x3e\x5c\x2c\xde\x81\x4d\x94\xe0\x4a\x3a\x80\x1d\x3a\xf6\xfa\x67\x94\xe2\x5e\xb1\x14\x3b\xe8\x1c\x2c\x11\xfb\xb1\x4e\x5c\x84\xa5\xc2\x7f\x60\x1d\xfd\x04\xdf\xa4\x13\x31\x59\x58\x8b\x87\x84\x6a\x2c\x13\x26\x63\xae\xf8\xcf\xd8\x46\x09\x56\x49\xaf\xe1\xfb\x26\x19\xdf\x37\x3d\x81\x8d\xd4\x8e\xf3\x19\xee\x63\x1c\xe6\x9b\x21\xea\x7d\xc1\xfa\x21\xeb\x10\x16\x0f\xbd\x20\x2c\xc6\x7d\xc2\xe2\xa1\x67\x84\xc5\x43\x3f\x92\xfa\x51\x91\xe9\x87\x11\x07\x9d\x86\x69\xd2\x6e\xf4\xb3\xbe\xc8\x3e\xf4\xbe\x78\x0b\x7b\x24\x07\xf6\x32\xdc\xc7\x38\x4c\xcf\xa2\x89\xf5\x45\x17\xe6\x64\x1f\x82\x32\x14\x17\x14\xec\x11\x94\xa1\xc7\x05\x65\xe8\x3b\xf4\x39\x44\xb3\xfa\x21\xf7\xd8\x8f\xa9\xe9\xfe\xcb\x39\xf4\xbe\xb8\x0d\xd7\xe9\xa5\xf9\x19\x2c\x33\xb7\xa1\x47\x6f\x93\xf8\x05\x6e\x15\xdf\xc0\x76\xf1\x45\xc0\x7c\x17\x90\x2e\x85\x9b\x01\xf2\x0e\x40\xba\x8d\x03\xff\x03\x90\xbf\x07\xb0\x16\xd0\xfb\x22\x7d\x48\x37\xe3\x0e\xd3\x2d\x58\x43\xbe\x0d\x85\x7c\x1b\xed\xe4\x00\x14\xe1\x7d\x28\xc2\xc7\x68\x17\x7e\x0b\x45\xf8\x3d\xf6\x4a\x7f\xc4\x7e\xfd\x6f\x85\x9d\x58\x27\xac\xc5\x3c\xfd\xba\xb4\x1f\x33\x25\x07\xae\xa0\x6d\x00\xfd\x3d\x3c\x74\x08\x25\xe6\xa7\x50\x62\xfe\x2f\x7d\x0c\x45\x03\xff\xb7\x04\xb7\x91\xad\x24\x25\x3c\x28\x76\x8b\xab\xc4\x7b\xc5\xe7\xc4\x8f\x69\x94\x2e\xa4\x9b\xe9\xbd\xf4\x71\xfa\x95\x54\x23\xdd\x6e\xb2\x98\xe6\x99\x1e\x37\xd7\x98\x2f\x37\x7f\x68\xb9\xd2\x72\xa7\xe5\x39\xcb\xeb\x96\xbf\x5a\x1d\xd6\xad\xb6\x6e\xdb\x2d\xb6\x4f\xf2\x96\xe4\x1d\xc8\x7b\x25\xdf\x92\x7f\x63\x7e\x22\xff\x15\x7b\xa1\x7d\xbe\xfd\x5a\xfb\xaf\x1d\x0e\xc7\x15\x8e\x43\x4e\x93\x73\x83\xf3\x13\x57\xc0\x75\xb9\xeb\x80\x4c\xe5\x36\x79\x8d\x7c\x9f\xfc\x82\xfc\x3b\xb7\xcb\xad\xb8\x67\xbb\xd7\xb9\x3f\x2c\x98\x57\x70\xd8\x53\xea\xd9\xe1\xf9\xb5\x77\xb6\xf7\x5e\xef\x33\xde\x94\x4f\xf1\xcd\xf5\x3d\xed\xb7\xf8\x17\xfa\x0f\x17\x16\x16\x2e\x2c\x7c\xa5\x68\x42\xd1\xa6\xa2\x07\x8a\x7e\x57\xec\x2e\x9e\x5f\xbc\xab\xf8\x48\xf1\xfb\x25\x0d\x25\x3b\x4a\x76\x94\xfc\x53\xa9\xaf\xf4\x40\x59\xa0\xec\x96\xb2\x1f\x96\x5f\x59\xbe\xbf\xa2\xbb\xe2\xe7\x15\xef\x06\x1c\x81\x86\xc0\xc7\x41\x5b\x70\x51\xf0\x50\xf0\x54\xe5\xe6\xca\xfb\x2a\x3f\xa8\x2a\xad\xea\xaa\xda\x56\xf5\x60\xd5\x89\x50\x7e\xe8\xf6\xea\xd2\xea\xb7\x6b\xfa\x6a\x0e\xd4\x9c\xa8\xed\xab\x3d\x32\xa1\x65\xc2\x73\x75\xc5\x75\x8f\xd5\x9d\xaa\x9f\x52\x7f\x7b\xfd\x89\x70\x61\xf8\x1b\xe1\xeb\xc3\x3f\x69\xf0\x35\x3c\xd8\x88\xc6\x2b\x1b\x8f\x35\x2d\x69\x7a\xb9\xe9\x93\xc8\xd6\xc8\xcf\xa3\xbe\xe8\x86\xe8\xcb\xcd\x8e\xe6\x45\xcd\x2f\x2b\x17\x2b\x6f\xc7\x36\xb5\xd4\xb7\xfc\xb2\xf5\xb6\x89\x33\x26\xbe\x32\xa9\x63\xd2\x3f\xb6\x79\xda\xbe\xdb\x76\xa4\xed\x54\xfb\x84\xf6\x55\xed\xbf\xed\x58\xd1\xf1\x74\x67\x71\xe7\x8e\x2e\xa1\x6b\x73\xd7\xa1\xc9\x35\x93\x77\x4c\x3e\x3e\x65\xe2\x94\x47\xa7\x7c\x3a\xf5\xe2\xa9\x4f\x4f\x6b\x9b\x76\x6c\x7a\xcd\xf4\x59\xd3\xef\x1e\xe7\xdf\xc3\xd3\x7f\x38\xfd\xc9\xe9\xaf\x4e\xff\xb0\xdb\xd5\xdd\xd2\xbd\xa8\xfb\xee\xee\x63\x3d\xb6\x9e\x8e\x9e\x6d\x3d\xdb\x7a\x1e\xe8\x79\xba\xe7\xe9\x19\x5d\x33\xd4\x19\xaf\xf7\x76\xf7\x3e\xd6\xb7\xa8\xef\xaf\xc6\x18\x8d\x13\xe8\x83\x04\xc3\x5a\x24\x10\xe0\x63\x29\xf8\x56\xf1\x31\xda\x05\x7d\x16\x25\xd4\x0a\x60\x0a\xb3\x56\xf4\x3a\x41\x3e\xa6\xf0\xba\x00\x0b\x66\xf1\xba\x88\x26\xcc\xe7\x75\x0a\x1f\x76\xf1\xba\x84\x06\x1c\xe0\x75\x13\x7c\x78\x8e\xd7\xcd\x98\x86\xd7\x79\xdd\x8a\x7c\x52\xc8\xeb\x79\xf0\x90\x10\xaf\xe7\xa3\x86\xb4\xf1\xba\x1d\xfd\xe4\x72\x5e\x77\x60\x21\xf9\x29\xaf\xbb\xe1\x13\x1c\xbc\x7e\x04\x3e\x21\xfd\xb7\x2f\x21\x2a\x74\xa0\x0f\x1b\xb1\x01\x5b\x11\xc0\x0a\x2c\xc3\x56\x2c\x43\x00\xcb\xb1\x11\x9b\x70\x1d\x36\x63\x00\xab\x71\x15\xfb\x76\x26\x36\x62\x23\x56\x63\x1d\x56\x22\x00\x05\x51\x34\x43\xc1\x7c\x6c\xc4\x95\xd8\x88\xad\xd8\x88\x6e\x6c\xc4\x3a\xac\xc8\xf9\x65\x47\xce\x2f\x02\x99\xdf\x74\xf0\x2b\xc4\xc6\xf9\xfe\x62\xac\xc4\x66\x6c\xc1\x00\x6b\x5d\x00\xcd\x68\x42\x33\xa2\xec\x6f\x5a\xd0\x8c\xce\x4c\x1b\x72\xaf\xd0\x98\xb9\x42\xee\x75\x07\xb0\x05\x01\x26\xdb\x56\x6c\xc6\x32\xac\xc0\x4a\xac\xc7\x32\x6c\xc6\x5a\x04\xb0\x11\xab\x46\x48\xd8\x94\x73\x96\xfb\x8d\x8e\xce\x7a\xf4\xe0\x2a\x86\xcf\x16\x6c\xc5\x00\x96\xb1\x56\x1a\xf7\xd4\x5b\xbe\x15\x5b\x58\xcb\x67\x63\x00\xcb\xb1\x12\x1b\xb0\x05\x2b\xb1\x02\x01\x5c\x83\x0d\xec\xee\x9b\x59\x5b\xae\x62\x68\x4e\xc7\x26\x2c\xc3\x72\x7e\x96\xfb\x37\x0d\x08\x8c\x42\x43\x41\x13\xa2\xac\x5f\xb6\x62\x13\x3a\x10\x41\x04\xdb\xd9\xbf\x26\x2c\xcb\xba\x56\x13\x36\x62\x33\x56\x23\x82\x75\x39\xd7\xdc\x82\x08\x66\xe3\x3c\xf4\xa0\x17\x73\xb1\x00\xbd\x68\xe4\xd7\x1c\xbb\x37\x2e\xc1\x4a\x5c\x89\x55\x19\x4d\x69\x66\xbf\xed\x63\xf2\x1b\xad\xdf\xcc\x5a\xd5\x8a\x00\xeb\x93\x0e\x44\xa1\xb0\xff\xb7\x64\xfa\xa9\x25\x6d\xfb\x0c\xad\xc1\x0a\x8c\xf5\xdf\x09\x80\x08\x44\x84\x08\x0a\x09\x26\x98\x61\x81\x15\x36\xe4\x21\x1f\x76\x38\xe0\x84\x0b\x32\xdc\x28\x80\x07\x5e\xf8\xe0\x47\x21\x8a\x50\x8c\x12\x94\xa2\x0c\xe5\xa8\x40\x00\x41\x54\xa2\x0a\x21\x54\xa3\x06\xb5\x98\x80\x3a\xd4\x23\x8c\x06\x34\xa2\x09\x11\xae\xb3\x31\xb4\xa0\x15\x13\x31\x09\x6d\x68\x47\x07\x3a\xd1\x85\xc9\x98\x82\xa9\x98\x86\xe9\xe8\x46\x0f\x66\xa0\x17\x7d\x98\x89\x6f\xe0\x3c\xcc\xc2\xf9\x98\x8d\x39\x98\x8b\x0b\x30\x0f\x17\x62\x3e\x16\x60\x21\x2e\xc2\xc5\xb8\x04\x8b\xb0\x18\x4b\x70\x29\xfa\x71\x19\x2e\xc7\x52\x5c\x81\x65\x84\xe2\x1f\xb0\x07\x37\xe3\x29\x1c\xc0\x07\xb8\x05\x77\xe2\x9b\xf8\x1e\xfe\x19\x87\x88\x84\xdb\xf0\x06\xfe\x1e\xf7\x10\x13\x31\xe3\x0e\x62\xc1\x3e\x3c\x8f\xdf\x11\x2b\x1e\xc4\x63\xf8\x0c\x7f\xc6\x29\x3c\x8a\x1f\xe0\x25\xbc\x88\x1f\xe2\x4a\x2c\xc7\x7e\xac\xc0\x51\xac\xc4\x11\xfc\x12\xff\x86\x63\xf8\x15\x5e\x46\x12\xab\xf0\x1b\xfc\x1a\xff\x8e\x1f\x61\x35\x3e\xc1\xb7\x70\x1c\xaf\xe2\x35\x5c\x85\x93\xf8\x08\xb7\x62\x0d\x06\xb0\x16\xeb\xb1\x0e\x1b\xf0\x30\x36\xe2\x6a\xd6\x3b\x5b\x70\x0d\xb6\x62\x1b\xb6\xe3\x04\xae\xc5\xf5\xb8\x0e\x37\xe0\xef\x70\x23\x7e\x82\x47\xb0\x13\x3b\xb0\x0b\x37\xe1\x43\x7c\x8c\x9f\x42\x85\x86\x7f\xc5\xeb\xf8\x4f\x62\x23\x79\x24\x9f\xd8\x89\x83\x38\x89\x8b\xc8\xc4\x4d\x0a\x88\x87\x78\x89\x8f\xf8\x11\xc7\x20\x0e\xe3\xc7\xf8\x39\x12\x78\x02\xbf\xc0\x5e\xfc\x0b\x29\xc4\xd3\xf8\x19\x29\x22\xc5\xb8\x9d\x94\x90\x52\x52\x46\xca\x49\x85\x69\xf5\xba\xeb\x36\x5d\xd5\x6c\xbe\x66\xc3\x40\x34\x1a\x9d\x61\x94\xd3\xa3\xbc\xe4\xe7\xdd\x0a\x2f\x63\xbc\x6c\xe5\x65\xbb\x5e\x2a\xd1\x68\x94\x97\xcd\xbc\x54\x78\x19\xe3\x65\x0b\x2f\x5b\x79\x39\x91\x97\x93\x78\xd9\xc6\xcb\xf4\xf5\xa6\x1b\x65\x33\xbf\x6e\x73\xb3\x6d\xd5\xc0\xea\x6b\x36\xaf\x5c\xb1\x6c\xcb\x55\xc6\x47\x4a\x9f\x51\xb6\xf6\xd1\xde\x6b\x36\x6f\x64\x27\xad\x7d\x3d\x7a\xd9\xd7\x6d\xb4\xa3\xaf\xdb\x68\x47\x5f\xb7\xd1\x8e\xbe\xee\x68\x0b\x80\x9f\x90\xa1\x9b\x55\x72\x07\xce\x57\x2d\xf3\x16\x69\x84\xdc\xb9\x58\xeb\x33\x85\x17\x05\x55\xd7\xe2\xf3\x55\xcf\xfc\x45\x41\x75\xd7\xe2\x32\xd5\x14\xee\x5f\x04\x55\x0c\xf4\xaa\x62\x78\x86\x4a\x03\xbd\x71\xb1\x42\x08\xb3\x13\x29\xd0\x1b\xa7\xe9\x13\x53\xa0\x37\x2e\x1d\xe2\x27\xe6\x40\x6f\xdc\xb4\x84\x9f\x58\x02\xbd\x71\x73\x07\x3f\xb1\x06\x7a\xe3\x96\x76\x7e\x62\x0b\xf4\xc6\xad\xd5\xfc\x24\x2f\xd0\x1b\xb7\x85\xf8\x49\x7e\xa0\x37\x9e\x57\xc5\x4f\xec\x81\xde\x78\x7e\x90\x9f\x38\x02\xbd\x71\xbb\xdf\x38\x21\xaa\x93\xb7\xcb\x15\xe8\x8d\x3b\x3b\x85\xb0\x26\xf6\x6d\x0b\xcf\x50\xe5\x40\x6f\xdc\xd5\x9a\x39\x75\x07\x7a\xe3\xf2\x40\xe6\xb4\x20\xd0\x1b\x77\x0f\xff\xd8\x13\xe8\x8d\x17\x74\x64\x4e\xbd\x81\xde\xb8\xa7\x3d\x73\xea\x0b\xf4\xc6\xbd\x13\x33\xa7\xfe\x40\x6f\xdc\xd7\x94\x3e\x5d\xac\x7a\xc2\x00\x59\xb0\xf8\xc3\xd9\xc0\xff\x0d\x00\x00\xff\xff\xfd\x8c\x82\x7d\x18\xb0\x00\x00") func fontsRobotoBoldWebfontTtfBytes() ([]byte, error) { return bindataRead( _fontsRobotoBoldWebfontTtf, "fonts/roboto-bold-webfont.ttf", ) } func fontsRobotoBoldWebfontTtf() (*asset, error) { bytes, err := fontsRobotoBoldWebfontTtfBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "fonts/roboto-bold-webfont.ttf", size: 45080, mode: os.FileMode(509), modTime: time.Unix(1492020681, 0)} a := &asset{bytes: bytes, info: info} return a, nil } var _fontsRobotoBoldWebfontWoff = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x64\xb6\x53\x74\xdf\x5f\x17\xed\xfd\x8d\xad\xa6\x8d\xd9\xd8\xb6\x6d\xdb\xb6\x6d\xb3\x71\x93\x06\x8d\x6d\xdb\xb6\x6d\xa7\xb1\xed\xfc\xde\xf1\x7f\x9f\x73\xae\xce\x1e\xe3\xb3\xe7\xde\xeb\x62\xad\x8b\x79\x31\x97\x87\x82\xb8\x38\x00\x06\x00\x00\x60\x78\x01\xa0\xff\xa7\xb5\x58\xff\xfb\xff\xbf\x47\x5c\x5c\x55\x0e\x00\xc0\x4a\x01\x00\xc0\xfb\x0f\xc3\x2a\xc5\x71\x09\x51\x31\x71\x00\x00\x1b\x04\x00\x80\x0a\x00\x00\x5a\xf0\x3b\xb0\x79\x09\x45\x05\x15\x00\x00\xbb\x01\x00\x68\x2c\x00\x40\xda\x6f\xc0\x0d\x90\x93\x50\x51\x13\x06\x00\x58\x58\x00\x00\xe4\xff\x1b\x46\x3e\x40\xb4\xa4\xa0\xc2\xc0\x0c\x00\xb0\x9a\x00\x00\xa8\xff\x57\x6b\xfb\xf9\x11\x60\x62\x67\xe4\x08\x00\xb0\xb5\x00\x00\x16\x09\x00\x60\xfb\x87\x93\xc2\xd4\x26\xee\xae\x44\x00\x00\xcf\x09\x00\x80\xf0\x7f\x60\x61\xa1\x19\x9a\x3b\x5a\xd8\x01\x00\xbc\x2f\x00\x80\xd5\x01\x00\xb8\x99\x4a\x23\x43\x89\x85\x91\x8b\x23\x00\x20\x32\x02\x00\x00\xfb\x7f\x40\xb5\xb0\xf5\x32\x07\x00\x44\x4e\x00\x90\x59\x00\x80\xd8\x07\x6c\x51\xe8\x36\x4b\x33\x23\x53\x00\xd0\x44\x04\x00\x80\x09\x00\x00\x76\x28\xaa\x50\x0d\x4b\x4b\x33\x23\x00\xd0\x14\x04\x00\x80\x10\x00\x00\x52\x14\x37\x68\x26\x4b\x3b\x57\x4f\x00\xd0\x34\x04\x00\x70\x4b\x00\x80\x28\x5d\x12\x16\xe6\xb3\x75\x30\x31\x02\x00\xed\x51\x00\x00\x9b\x04\x00\xb0\x65\x5d\x73\x6e\xc0\xce\xc8\xd3\x11\x00\x74\xff\x00\x00\x40\xf4\x1f\xe0\x30\x60\xb5\xf6\x46\x76\x66\x00\xa0\xdb\x08\x00\x60\xc1\x00\x00\xc1\x28\x7e\xeb\xc9\xec\xe8\xe0\xe2\x0a\x00\xfa\x9c\x00\x00\x76\x05\x00\xe0\x87\x38\xbe\xcc\xc5\x8e\xce\x66\x8e\x00\x60\x48\x09\x00\x40\x3b\x00\x80\x49\x64\xd8\x17\xe6\x7a\x98\x19\x9b\x03\x80\xe1\x3f\x00\x00\xa0\xff\xe3\x42\x4e\x45\x0b\x00\xfe\xe7\xca\x24\x5f\xfe\xcc\x7f\x3a\x78\x83\x46\xff\x9f\xce\x04\x64\x4e\x7a\xae\x9b\x18\x9a\x1a\x1a\xee\x42\x18\xff\x80\x46\x35\x34\x36\x34\x37\x34\xf5\x84\x1f\x9c\x09\x4c\xf8\xb5\xc7\x35\x20\x43\x94\x01\x45\x3b\x00\x00\x2a\xa8\x90\x43\x00\x00\x78\xae\x57\xa5\x5a\xd9\xaa\xa9\x7d\x0f\x5b\xf1\xc3\xb7\x3c\x2f\xb8\x3c\x68\x8a\x61\x27\x0f\x55\x02\xc7\x82\xa6\x4a\x62\x82\xb4\x01\x0b\x51\x16\x34\x87\x80\xbb\x13\x81\x82\xfb\x36\x80\x32\x17\xaa\x24\x18\x23\x84\xda\xaf\x6a\x4a\x1f\x32\xd8\x38\x39\x1a\x43\x09\x86\x04\xa7\x92\xf7\x5d\x08\x5c\x17\x32\x39\x12\xae\xa7\xfd\xf3\xca\x2a\x08\xa6\xf9\xfb\x6c\x4b\xfd\x15\x1f\xdf\x71\xb6\xdf\x93\xbe\xc5\x7a\x32\x05\x95\x18\xc3\x09\x59\x58\xfb\x71\xe7\xb2\x42\xd9\x75\x2c\x96\x80\xf8\xe3\x0f\x85\xae\xc9\xef\x8d\x23\x29\x5d\x1e\x3b\x04\x1c\xe2\x52\x42\x63\x4c\xfa\xc4\xdb\xc4\x45\x83\xb1\x7f\x30\xdf\xb6\xfc\x36\xe4\x0f\x7a\x21\xfd\xaa\x87\xb4\xab\x9b\xde\x86\x71\xcf\xfd\x4a\x0f\xb7\x25\xb6\x59\x1d\xfe\xb6\x0c\xf1\xec\xe9\xdd\x5e\x85\xae\x87\xd6\x8b\x78\xe5\xc1\xe5\x2d\xe5\xe5\xcf\x22\x7b\x06\x5f\x5f\x9b\x30\x7d\x8e\xd7\x7d\xf0\x9f\xa8\x7d\xa7\xbe\xbb\xe2\x7c\x07\xe3\x45\x52\xd7\x84\x3b\x2b\xe5\x3e\x0b\x5d\xd1\x53\x55\x78\xbd\x21\x8a\x51\x11\xa1\x59\x04\x3a\xf2\xfa\xd4\x27\x53\x8d\x3a\x06\xef\x55\x78\x50\x1f\xea\x2b\x06\x33\xd5\x9b\x55\xd0\xd2\xa0\x70\xd7\x18\xdd\x14\xc3\xdb\x37\xe8\x0f\x57\x95\xba\xe0\x5d\x8c\x14\xd2\x2c\x24\x16\xe3\x3d\x02\x68\x11\x0b\x8f\x89\x3a\x2a\xf3\x1c\xbf\xf9\x91\x0f\x50\x39\x52\x67\x42\x97\x0c\x1c\xae\x6a\x82\x69\xf4\xab\x39\xb2\xe9\x42\x20\xd4\xd6\x21\x57\x47\xe0\xee\x8a\x6b\x86\x5e\x4e\x39\x22\x6c\xc2\xb7\xf4\x65\xc5\xd4\x21\xf8\xc3\x78\x0c\xf0\xc5\x34\xa1\x10\xec\xbe\x1b\xfb\xd2\x05\x15\x31\x46\x9a\x44\xfb\xd0\x1b\x42\x43\x53\x66\x9d\x84\x53\x2a\xe1\x47\xb6\x14\xe8\x29\x52\xdc\x2f\x0d\x35\xd3\x10\x12\x84\xc2\x35\xea\x16\x1e\x72\x37\x45\x94\xf1\xc9\x5e\x1a\x2d\x11\x55\x0b\xdb\x7e\x94\xce\x2d\x4b\xa0\x57\x31\xa8\xb7\x5b\x57\xd1\xcd\x21\xbf\x07\xbf\x22\x16\x5c\x4e\x50\x2e\xec\x4c\xdb\xb4\x5a\x77\xa4\xc3\xb2\x95\x2d\xea\x16\x90\x67\x29\x33\xbb\x07\x5f\x5b\xaf\x6b\x6b\x33\x2f\x0d\x4c\xcf\xb6\x13\x3e\x32\xb4\xf2\x17\xd8\x41\xa7\xa0\x18\x7b\x81\xa7\xac\x18\x7a\x25\x4f\x6f\xf8\x1e\xbf\x8b\xf1\xda\x5b\xf5\x50\xe1\xd2\x07\x47\xef\x7d\x6b\xfd\x4e\x7e\xe0\x22\xb2\x6c\x21\x52\xd9\x32\xe2\xcc\x51\xc9\xb6\x6c\xf5\xc5\x0f\x31\xd3\xef\x72\x83\x6d\x3e\x69\x31\xec\xfb\xbf\x6b\x42\xc2\x8e\xb0\xc9\x6f\xf1\x49\x69\x43\xc2\x8e\x10\xca\x6f\x59\x0c\x65\x49\xac\x0a\xba\x32\x0b\xda\x73\x56\xc4\xca\x33\xc1\x7c\xe3\x7b\x90\x56\x2d\x56\x4a\xaf\x32\xd6\xcb\xd1\x41\x46\xbc\x03\x7f\xf7\xeb\x7f\x0f\x85\x19\x77\xcf\xd4\xfe\x93\xd8\x45\x51\xb9\x25\xd9\xa9\x25\xe9\xaa\x25\x71\x3b\x2b\xab\x19\xeb\xb3\xd1\xf4\x8b\xfc\xea\x8b\x2a\x82\xb3\xaa\x2f\x9c\xc1\x48\x91\xc7\x14\x72\xab\xfa\x62\xcb\xf2\x62\xab\x76\x73\xcb\x62\xf3\x53\x96\xa9\x65\xbc\xa9\x25\x5e\xbf\xa2\x57\xed\x5e\x9c\xed\x02\xbf\xca\xfd\x85\x41\xaf\x14\x2c\x91\x31\x84\x90\x2c\xb5\x02\x77\xe5\xb8\x6c\x15\x8c\x8e\xdb\xc2\xc3\x35\x72\x1d\xab\xee\x1f\x9a\x41\xd9\xbb\x1a\x4f\x15\x5f\xa9\x39\x7a\x8d\x13\x4f\x4c\x1d\xa7\x63\x3e\x29\xfc\x73\x2b\x2b\x04\x58\xf7\xe5\x9f\x83\x3e\x74\xd7\x34\xee\x17\x4c\xde\x20\xa8\x1a\x95\x51\xcf\xd2\x2f\x68\x9f\xb6\x33\x7d\x0d\x50\x12\x73\x2a\xb8\x02\x4d\x59\x8f\xf1\x88\x5d\xae\x9f\x83\x0b\xf5\xdf\x64\x95\x8b\xc4\x77\x83\xe6\xda\x23\xb3\x80\x91\x8f\xcf\x92\xd8\x63\x2f\x58\xfd\x66\x2d\x50\x3d\xcf\xac\xfd\x06\xdd\x76\x8b\xf1\x85\x5c\xbd\x30\x4d\xb3\xd2\x77\x12\x26\x03\xff\x4f\xc5\x99\xa1\xe6\xc5\xa3\x0d\x71\x1d\xa3\x8a\x1f\x6e\x09\x4d\x1e\x74\xef\xa7\x39\x0e\x6b\xee\x7d\xe2\xd0\xec\xb6\x7f\xb6\x1a\xd5\x32\x89\x3d\x7c\xfc\x0d\x25\x38\x63\x07\xad\xdc\x76\xb4\xef\xa3\x9e\xa1\x3e\xd6\xb4\x93\xbb\x1b\xbf\xeb\xc0\x39\x8c\xae\x29\xe9\x73\xe4\xee\x4f\xc9\xae\xe5\x5b\x37\x7d\x0e\xfd\x58\x30\x29\x67\xb9\x48\xc7\x6f\xc0\xe3\x19\x91\x2a\x96\x36\xf7\x09\xa5\x6b\x50\x88\xb4\xac\x94\x2b\xa1\x43\x1f\x4d\xa4\x59\x67\x6f\x88\x20\x87\xb6\x49\x6c\x92\x15\xd8\xa7\x6d\x52\x61\xcf\xcf\xb7\xd1\x7e\x85\x8f\xd1\x0b\x7b\xae\xd4\x47\x31\x6f\xbb\xe3\x0c\x51\x7b\x1b\xe5\xfc\x2a\xad\x3f\x3c\xb6\xf6\xde\x8e\xd3\xc3\x0c\x2a\xea\x68\xbe\x58\x54\xa9\x59\x6d\x58\x6a\xdc\x29\xaf\x3f\x8c\x28\x21\xb8\xef\x3d\xa0\x31\xe5\x08\xd1\x42\xc9\xbe\xc2\xac\x7a\x78\x67\x7a\x8e\x9a\xe1\x5f\xaf\xde\xa0\xa9\x5b\x1e\x11\xb0\x37\xcd\x7c\xbb\xe8\x2d\x89\x7a\x32\xe7\xca\xa9\xd5\xe0\x58\x76\xa5\xc0\xb5\xef\x6a\x4b\x1e\x40\xa6\x7e\x9f\x6f\x92\xad\xf7\xa0\x6d\xb1\x0d\xfa\x91\x0c\x75\xce\x50\x76\x51\x8e\x7f\x28\x5e\x1a\x39\x18\x45\x50\xcb\xbc\xe1\xde\x30\x53\xc3\x67\x9c\xd9\x75\x75\x6a\x0f\x9d\x31\xa2\xff\xba\x8c\xdc\x47\xd2\xc7\xef\xe4\x53\x14\x66\xb3\x76\x9c\x3d\xc0\x35\x52\xdd\x3a\x5f\x4c\xfd\xfd\xae\x22\xf6\xfc\x25\xa4\xa3\x21\xbd\xa6\x65\x87\x0f\x97\x60\x1d\x8c\xf8\x6a\x9d\x75\xd7\x69\x58\xcc\xd3\x1c\x2c\xfe\x23\x97\x89\x4e\x4e\x10\xaf\xc5\x59\xe5\x6a\xca\x9c\x48\x88\x4e\xe8\x27\x87\x2b\x0d\x73\xf6\x32\xd1\xaf\x6d\x3b\x4b\x3b\x84\xc4\xb6\x2a\x1e\xc7\x54\x8b\x10\xd1\xab\xcb\xb8\xcd\xb3\x2c\x41\xcd\x2c\x21\x39\xfb\x5b\x7a\x53\x2e\x3d\xa1\xf4\xf6\x10\xd7\x2e\xf0\x9f\xe3\x60\x4d\x7f\x10\xf2\xcf\xa0\x98\x1f\xc2\xdf\x6e\x26\x21\xfe\x9e\x21\xfc\xdc\x7c\xff\xe4\xda\x80\x09\xe2\xc6\x01\x3f\x4b\x84\x40\x2c\xe2\x45\x5c\x3c\xf8\xca\x09\xca\x61\x69\x03\xa1\x8f\x02\x47\xbb\x33\xba\x57\x20\x4f\xba\x79\x65\xde\x31\x98\x32\xd3\x6e\x1b\xac\x3a\x60\x71\x9e\xdb\xce\xb4\x52\x38\x21\xef\xa7\x9d\xc9\x1f\xbe\xdc\xb8\xa7\x60\x58\xae\x01\xfe\x71\x18\xa1\xf2\xa8\x1f\xa6\x5d\x64\xbd\x2a\x54\x37\x8a\x64\x19\x4a\xdf\x28\x8b\x80\x19\x2b\xcc\x61\x67\x6e\x77\x08\xa8\x01\xf9\x3e\xc6\x57\xd9\x02\x78\xa8\x02\x6f\x02\xd1\x2c\x77\xa4\x4c\x7d\x25\xe7\x0c\x77\x5e\x03\x48\xb7\x2c\x6b\x29\xf9\x26\xd9\x12\xed\x7a\x95\x2a\xf7\x18\x6b\x2a\xf9\x26\xd5\x12\x6d\x3c\xeb\xc3\x6f\x3a\x0a\xa8\xd7\x7f\xa4\x1d\xa5\xc9\xb8\x8b\xbe\x2d\xa2\x0c\x9e\xcb\x29\x8a\x40\x08\xb5\xab\xd0\xed\xab\x56\x1c\xab\x46\x73\x2e\x9d\x9d\xfb\x29\x46\xf3\x5a\x73\xfb\x43\xc3\x8b\x67\x59\x2b\xd1\x41\x2a\x95\xe8\x15\x2f\xd0\x0f\x59\x61\x46\x38\xe3\xd6\xe1\x95\xa6\xec\xaa\xca\x2c\xca\x5f\x0e\xfb\xe7\xea\xb5\x59\xa3\x5d\xc2\x28\xe1\x03\xb7\xf2\x7d\xdf\xb3\x16\xa9\xc4\xe1\x9c\x19\x67\xca\xb0\xdd\xdb\x34\xdb\x8a\x8d\x4a\xac\xd2\x7a\xf4\x3d\xb4\x0c\x71\x30\xea\x35\xbd\x0e\xff\x1a\x4e\xf8\xfc\x35\x84\x69\x84\xbb\xeb\x9d\xa6\x47\xbf\x98\x2e\x87\x63\x3d\x39\xcc\x9f\x21\x39\x23\xa2\xc1\x13\x36\x1d\x28\x1f\x85\xc4\xbc\xcd\x99\xfd\xb6\x3f\x46\x91\xf8\x43\xbb\x4c\x4d\x5b\x4e\x14\xaa\x32\xe4\x71\x5d\x50\x35\x6c\xb0\x41\x4b\xa7\x31\xb9\xf4\xa9\x16\xfa\xca\x3c\x76\x68\x7a\xe5\x5b\xf2\x17\x84\x5b\x0c\xb2\xf0\xff\xcd\x10\xe3\x59\x93\x5a\x23\x43\x67\xa7\x7b\x38\xa3\xdd\x09\x29\xda\x31\x93\x04\x63\x43\xb0\x28\x96\x0f\xd0\x0c\x90\x18\x51\x87\x8d\x85\xe5\xc2\xbc\x80\x8e\xcd\x29\x48\xcb\x68\x0e\x36\xc1\x04\x2e\x86\x85\x1d\x9a\xcb\x8a\x30\xc0\x02\x4d\x0e\x4d\x48\x14\xfd\xbb\x0f\x1d\x30\x9e\x82\x5f\xf9\x2f\x67\x4c\x0c\xcd\xe7\x4c\xd6\x07\x7a\xc7\x7b\xfb\xb9\xa3\x97\xd2\x82\x82\x94\x08\x84\x59\x0c\x4c\x25\x4d\x8c\x0d\x0d\x01\x23\x58\xcf\xde\xde\x07\xfe\x40\x21\x62\x9c\x51\x55\xe0\x76\xeb\xfe\x7e\x21\x88\x76\x7b\x87\xd6\xd6\x0a\x34\x8f\x85\xc5\x69\x9d\x16\xfc\x03\x0b\xeb\xf8\x9d\x85\x99\xb1\x56\xb3\xce\x1e\xa8\x30\x01\x07\x82\x32\x91\x65\xfe\xd7\xd7\xd0\xd0\x3c\xd0\x10\x1b\x5a\x1c\x1a\xb5\x15\xe2\x1f\x53\xf0\x2b\x2d\x22\x4c\x60\x23\x72\x08\x78\xc2\x10\x84\xe9\x2d\xf3\x22\xd3\x87\x05\xa2\x79\xa5\x21\xf7\xb0\xab\x44\x90\x8c\x90\xa8\x90\xb4\x90\xbc\x90\x94\x90\x9c\x90\x41\x9f\x34\xb1\xbe\x51\x6c\x7e\xe2\x59\xce\x0e\x2d\x08\x14\x32\xb5\x07\x75\xa6\xd3\x8b\x05\xa9\x36\x95\x4b\x94\x4b\x94\x47\x04\xa1\x66\x07\xa7\x31\x05\xab\x3a\xf5\x02\x3a\x07\x8d\x80\x50\x3e\x19\x5e\xae\xef\x9f\x41\x3b\x1a\x28\x71\x02\x9c\x0f\x86\xa0\x10\x3f\x14\x77\x81\xd5\x5b\xc3\x81\x90\x43\x94\x74\xc2\xb4\x1d\x01\xd7\x73\xb2\x73\x95\x52\x84\x5f\xd0\x31\xb6\x88\x8e\x74\x31\xb2\x82\xc1\x70\x7a\x60\xb3\xe7\xb4\x95\xb6\x17\x78\x99\xba\x9b\xbc\x9d\xbe\x1f\xe0\xc1\xc2\xfd\x3f\xf3\x8d\xf7\xbf\x25\x2a\xcf\x33\xd7\x3b\xdf\xc1\x47\x49\x8f\x53\x97\x5b\x9f\xe1\xa4\x6b\xaf\x73\xb7\x7b\xbf\x41\x87\x8b\x0f\x93\x17\x9b\x1f\x61\xa4\xa8\x2f\xb3\x37\xbb\x3f\x21\xc7\xc9\x4f\xd3\x57\xdb\x5f\x11\x64\xeb\x6f\xf3\x77\xfb\x7f\x81\x05\x09\xf5\x11\xe7\x19\xed\xa1\xfd\x56\x9a\x63\xaa\x73\xba\x85\xfb\x85\x68\x77\x99\xb5\x95\x64\x31\xa9\xd3\x69\x39\x56\x5f\x34\xa1\x51\xad\xdf\x64\x7e\xf9\xe6\x86\xcb\x6e\xbf\xdd\x6e\xb6\x11\x77\xe9\xe3\x7e\xbd\x35\xa2\xf8\x27\x31\xdd\xab\xc5\xd8\x48\xe8\x29\xa9\x9e\x36\x3c\x4e\x0b\x71\x08\x11\xf1\xf4\xd0\x70\xe5\x70\x91\xb1\x72\x75\x29\x2d\x13\xc6\xf8\x78\x79\x5b\xc6\xda\x3a\xcb\xff\xe4\x66\xc9\xa6\xc5\xde\xa0\xa7\x2e\x69\x6f\x17\x2d\x7c\x04\x85\x80\xdf\x67\x5a\xd1\xeb\x1e\x59\x44\x46\xc1\xc5\x41\x03\x14\xfa\xcb\x4f\xa5\x84\x49\xf6\x2f\x8b\x07\xfb\xc0\x9c\x49\x98\xa0\x9c\x9a\x20\x22\x40\xd0\x1e\xd5\x04\x00\x90\xdc\x50\xb5\xc0\x1e\x18\x22\xd0\x07\x8c\x02\x53\xc0\x12\xb0\x06\x6c\x01\x87\xc0\x25\xf0\x09\x14\x81\x91\x82\x71\x83\x21\x82\x7d\x03\xc3\x02\x23\x00\x23\x05\x63\x05\x83\x05\x1a\x81\x71\xe0\x00\xe8\x00\x4e\x80\x1e\xb0\x9f\x80\x28\x14\xda\x7f\x5e\xea\x29\x75\xc8\xeb\x08\xa1\x6e\x21\xa1\x40\x04\x0d\xae\x12\x71\xad\x7f\x6f\xf8\x9b\x30\xec\x93\x07\x05\x37\xb8\x14\x6b\x6c\xca\x13\x76\x08\x6b\xc5\xe1\xfc\x3b\xda\x09\x8c\x50\x30\x48\x14\x69\xbd\x06\x3b\x37\xaf\x50\x32\x03\x9a\x18\x53\xd2\x57\x98\x9f\xf8\x1b\x8b\x4d\x64\x3e\x2b\x0f\x4f\x83\xcb\xf4\x5f\x16\x99\xf1\xdf\xe5\x1e\xa7\x36\x33\x2a\xc7\xa4\x09\xfd\x5b\xd0\x53\xec\x9f\xf2\x92\x4d\x0d\xc0\x73\xe1\xf9\x79\x6c\x4c\x63\x08\x8c\xb6\xad\xf9\xc3\xb8\xdb\xfb\x17\x02\x74\xc6\xdc\x1f\x1e\x6b\xe0\x90\xcf\x81\x0a\x05\x5b\x8e\x27\x48\xbb\xb1\xe4\x6b\xee\x03\x3e\xfc\xfd\x83\xf0\x9e\x07\xab\x91\x75\xe1\x61\x91\x1b\xee\x94\x18\xf2\x28\xc3\x49\x26\xe4\x1a\x7b\xaa\x7d\x02\xe5\x2d\x78\x69\xcf\x98\x91\xb1\x30\xad\x78\x9f\x5e\xa0\x58\xf9\xab\x85\xf5\xd8\x7a\xa2\xb6\xe9\xf7\x5c\x67\x08\x0b\xda\xeb\x18\xab\xa0\x8a\x8d\x1d\x64\xfa\xd7\x22\xf1\xd2\xbd\xd3\x77\x99\x84\x89\xe2\x3a\xf6\xb4\xb4\xfa\x2f\x52\xf4\xbe\xb0\x31\x57\x35\x95\xa6\xc9\x97\xf5\x3e\xbd\xfa\x86\x13\xc3\x10\xea\xa9\x20\x98\xd5\x01\x75\x2f\x44\x02\x64\x14\xf2\xef\xf3\x2d\xa4\xe3\xb4\x48\x68\x4f\xc6\x15\x83\xb0\x68\x49\x78\xf0\x5c\x87\x9b\x63\x5f\x85\x82\xaf\x92\xdf\x86\x3b\xa5\xa4\x79\x0e\xc2\x9b\xa0\x87\x7f\xaf\xf4\xe6\xb2\x2b\x34\x80\x78\x33\xe4\xec\x1c\xf0\xfb\x5f\xb4\xf0\xfa\x3c\x7a\xb0\x65\xb8\x5f\x46\xc3\xd7\xb1\xd0\x8c\x79\x8c\xa9\x02\xe1\x44\x85\xc5\xd5\x5e\xc3\x71\x66\xba\x68\xa1\xff\x29\xbf\xcf\x08\xfe\x09\x3c\xbc\x8d\x0f\xc8\x82\x6d\xbc\x5a\x15\xe5\x4d\x6d\x72\x43\x66\x52\x87\xf5\xf6\xdf\xd8\xbc\x9b\x88\xea\x50\x6f\x9b\x8e\x16\xf6\x70\x28\xb7\x2e\x9d\xa7\x9a\x7a\xd7\x9f\xee\x1e\x81\xc8\x26\x40\x18\x10\x32\xe9\xcb\x98\x79\xff\x92\x0e\x7a\xe3\xa5\xad\x66\xb5\x44\x86\x14\xf1\xe6\xf0\x06\xe5\x37\x9d\x45\x56\x74\x62\xf2\xd7\x53\x2c\xf4\xd4\x69\x03\xff\xff\x16\x0a\x06\x02\x01\x28\x9e\xeb\x5d\x5d\x30\xbe\xdf\x97\x9e\x00\xdf\xeb\xc9\x0b\xdb\x9d\x0b\x5b\xb9\x7a\xab\x0c\x64\x62\xdb\xfa\x0c\x54\xf0\x3c\x29\x15\x6f\xb5\x53\x7c\x21\x6e\xea\x55\x25\x5a\x4d\xb4\x1f\x1d\xc1\xab\x39\x9a\xe6\xec\x36\x3e\x67\xe8\x8f\x65\x44\xcd\x16\x7d\x51\x5d\x62\xd9\x5d\x08\xd8\xdd\x2e\x57\x59\x6b\xb6\xf0\xbb\xef\x5f\x3b\xd7\xe8\x49\x59\x59\x5b\x93\x9b\x2e\x57\xa7\x76\x91\x82\xe1\xa8\x3f\x27\x5b\x64\xc9\x7f\xd6\x25\x66\xe3\x90\xd5\x15\x17\xaa\x51\x7f\xb0\x57\x8f\xa5\xa0\xa4\x27\xe6\x03\x11\xa2\xe8\xb7\x8d\x50\x0a\x14\x55\xce\x73\x41\xc5\xa4\x43\xf7\x70\x64\xe5\x7f\xc4\x92\x4f\x50\xf3\x24\x19\x8a\x56\xce\xa3\x69\x93\x40\xeb\xfc\xa2\xde\x7f\x7b\xc9\xc6\xc2\x42\x67\x7d\xe8\xa8\x3b\xec\x83\x49\xf7\x74\x93\xc5\xb7\xe8\xa4\xa2\x05\xcb\x4b\xad\xa3\xcb\x4c\xe3\xa9\x87\xd8\x98\x2a\xc4\x92\x0f\xd2\xd9\x2a\xc4\x1a\x16\xa8\xf3\xb5\x4a\xf7\x55\x8a\x86\xd3\xb5\x3b\x39\xc3\x72\x10\xac\xca\xbe\xc0\xe8\x8a\xfe\x11\xe5\xf5\xfc\x02\xf1\x32\x22\x56\xe3\xa7\xd6\x87\xfe\x75\x0e\x95\x1c\x94\x3f\x8b\x94\x36\x2e\x27\xfb\x9d\xff\xad\x4e\x4a\xcd\x91\xa9\x9c\xfb\xe6\x8c\x8a\x49\xd6\x79\x37\xf4\x24\x2c\x5a\xbd\xc8\xf6\x22\xeb\x28\x34\x63\x71\xf1\x2d\x39\xd4\x58\x6e\xb7\xe6\x25\x15\x21\x07\xe4\x4c\xac\x3b\x53\x14\xf0\x4e\xf1\x0e\xb5\x52\x43\x2c\xda\x8e\xb8\x4c\x40\x1c\xe6\x4a\x2c\x75\xd4\xbf\x9e\xd4\xa7\x28\xff\xf3\xb7\xa4\xb6\xd1\xab\x54\xc6\x02\xd4\x08\x95\xb0\x4b\xd5\x55\xb9\xb9\xd0\xd8\x04\x03\x12\x05\xeb\xbe\x95\x15\x72\x68\x03\x49\xd1\x9e\xe7\xf8\xcf\xba\x78\x51\x07\x21\x62\x7f\xd3\xa0\x78\xd3\x8e\x01\x24\x42\xa5\x26\xca\xe2\xa3\x2b\xa9\xc3\xd0\x5f\xe8\xea\xa9\x07\x4b\xc2\xb5\xed\x44\x3e\x30\x1c\x4e\xaa\x6c\x28\x88\x6f\x97\x6a\x53\xcd\x86\xa3\xea\xc9\xf5\x77\x0e\x5a\x26\xad\xfe\x1f\xe1\x4b\xe1\x3b\xb5\xd2\x4f\xd4\x6c\x27\x62\x96\xca\xf4\x4f\x41\x18\x45\x6a\xd6\x35\x9b\x01\xc8\xb5\x9f\x77\x48\x70\xea\x5c\x5f\x5c\xbd\x5f\x13\x28\x9e\xb9\x47\xde\x19\x61\xba\x15\x84\x18\x03\xfe\x13\x2f\xb8\xf6\x1b\xb6\x33\x75\x7d\x42\xa3\x1b\x17\xb0\x5c\x9f\x9e\x4d\xe6\x1e\xb3\x50\x06\x37\xf5\x3b\xf0\xef\xf8\xbd\x3b\x2f\x59\x8c\xef\xc8\x1f\x6a\xec\xef\x34\xad\xe6\x83\x9d\xf2\xd9\x5e\x59\xbe\x1f\xf2\x2e\x41\xaf\x53\xc2\xbc\x0c\xc8\x0f\xf0\x3f\x85\xaf\xd4\x50\xd9\xbc\x5e\xa1\xc2\xf8\x78\x3e\x4a\x90\x27\x87\xf0\xcb\xe2\xdf\x64\x76\x29\x88\xc9\x6f\x28\x34\xfb\xfd\xa5\x3f\x5e\x16\x12\x6e\x52\x17\x15\x13\x5f\xd2\xc7\x47\x78\x9d\x27\xe3\xd0\xe2\xf1\xee\xfb\x0c\x7e\x29\x3c\x14\x10\xf2\x79\x8f\xdc\x48\xc4\xfb\x9f\x97\x0d\x22\x7b\x1f\x08\x58\xde\xba\x7b\x57\xf0\xe3\x06\x34\x9f\x13\x7e\x89\x18\x48\x3a\x0c\x12\x72\xa2\x14\x4a\x50\xfe\xf5\xab\xed\x58\xd4\xe9\xce\x56\x4d\xa2\x89\x5c\xe7\x83\xe6\x11\xc5\x0b\x5c\xeb\xd4\x1c\x1f\x89\x2b\x5d\x67\x29\xf6\x7e\xb2\x0c\x13\x4c\x28\xb4\x8c\xcf\x87\x0b\xc2\x68\x9a\xad\xa0\x0a\xdc\x07\x76\xc2\xae\x1c\xb9\x97\x62\x09\x61\x3a\xd3\x91\x18\xb3\xd1\x57\xc6\x77\x51\xfa\x9d\xe8\xc4\x2b\x1a\x85\x51\x50\x6b\x2a\x94\xce\x97\xf5\x6e\xd9\x78\xe8\xbc\x86\x8a\xf6\xc4\x89\xac\x3c\x4b\xd4\xd4\xd9\xd8\xcb\xbd\xc6\x45\x42\xbd\xfb\xd7\xcc\x1c\xf5\x1f\x5f\x59\xc9\x66\x61\xff\x5c\x39\x44\x42\x0b\xff\xf2\xac\x79\x6b\xbf\x8b\xca\x6e\xec\xae\xd6\x10\xf1\xfb\xa9\x29\xd8\x60\xd9\x58\xdd\x59\xa8\x89\x0c\x2d\xbc\x07\x8e\x83\x38\xba\x6c\x28\xe5\xa7\xc0\xad\x93\xfb\x6a\x31\x99\xce\x6e\x31\x5c\x8e\xb2\xe3\xff\xbe\x57\x75\x46\x2f\xb4\x28\x90\xc1\x72\xba\x2a\xa5\xb2\x7c\xe5\x67\x33\x53\xa0\x43\x08\x0a\xe3\xb7\x6b\xbb\xf9\xc7\x85\x3e\xcc\x70\xc1\xf4\x15\x16\x71\xe5\xb5\x01\x7a\xea\x68\x13\xe0\xb3\xd3\x72\x99\xee\x84\x33\x39\x1a\x8c\xf3\xe1\x7f\xed\xb5\xf9\x3a\xce\xb9\x0f\x10\xa7\x35\x5d\xee\x03\x69\x57\x37\xf2\x4a\x6c\x4a\x9e\x06\xfe\xed\xfe\x47\x9d\x58\x29\x2c\x5f\xf5\xd8\x48\x4a\x46\xe4\x46\xb7\xb1\x90\x78\xa6\xa7\x4d\xd6\x56\xd1\xb8\xed\x58\xca\xb9\x96\xb7\x6f\x95\x67\x8d\x7e\xc0\xac\x90\xf6\x02\x10\x12\xd4\x60\xec\xea\x86\x5f\xdb\xea\x57\xc1\x6e\x3f\xfe\xbb\xf6\xf6\x6e\xe2\xf6\xd4\x18\xdb\xb6\xfa\x04\x94\xc0\x50\x7e\x4a\x8e\x43\x1c\x59\x2e\x9e\x79\xf7\x67\x7c\xcc\x97\x83\x87\x57\x6d\x37\x05\x0e\x74\x8a\xd3\xe9\x04\xad\x80\x8b\xa2\x18\x92\xa2\xa1\x1c\x2e\x04\xea\x2a\xeb\x6e\xf7\x2a\x2e\xc5\x3b\x2f\xbe\x58\xa5\xa5\xe0\x1f\xdd\x6b\x79\x18\xb8\x6c\xe9\x79\xe8\xb9\x5c\xf2\xcd\x20\xda\x9e\xb1\x18\x1a\xee\x74\x43\xc0\x87\x62\xb2\x37\xb3\xcf\xa3\x3d\xeb\xba\x5c\x6e\xdd\xf4\x09\x64\x63\xaf\xfb\x28\x5e\x07\xf9\x65\x40\x4b\x92\x48\xe4\xf8\xec\x3c\x3d\x16\xcc\x74\x3d\x6f\xbb\xbc\xc7\xe0\x6f\x58\xb8\xe6\xdc\x1e\xbc\xe3\x51\x26\xaa\xc7\x6f\xf6\x38\xbd\x9f\xb8\x5c\x6d\xf8\x5f\x9d\x3c\x3e\xdb\x0b\xb4\x38\x7d\x8c\x82\x15\xe0\x8e\xc4\x3b\x90\x12\xad\xbd\xe1\x6f\x5a\x8c\x41\x7c\x88\x49\xa1\xcc\x47\xb6\x46\xe7\x16\x52\x8a\x42\xa6\xfc\xa2\x93\xe2\xf9\x59\x2b\x04\xa9\xfa\x28\xa4\x6a\x35\x24\x48\x35\xa4\xdf\x84\x53\x26\x83\x1c\xb2\x19\x6d\xb5\x64\xc4\x3b\x34\x7b\xb0\x3f\xea\xec\x24\x0a\xcd\x55\xff\x06\x5e\x5f\x6e\xd6\x1b\xba\x5a\xba\x4c\x45\xe5\x63\xa4\xc5\xc1\xf0\x2d\x7e\x22\x55\xf5\x8e\x1a\x37\xa8\x18\x3c\x0a\x07\xac\x31\x59\x0c\x6b\x7d\x11\x9a\x88\x69\x2d\x79\xab\x0a\xba\x1b\xaa\x15\xc2\xd8\x98\x14\x0a\x16\x1c\x7e\x3c\xbf\x51\xa0\x4a\x01\xa0\x0a\xab\x9a\x83\x47\xa1\xa3\xa2\xa7\x33\x79\xb1\xce\x55\x47\x79\x84\xc8\x63\xeb\x3d\x46\x74\xfb\x5c\x36\x60\x34\xbd\xe1\x41\xb1\xf3\x33\xba\xfa\x87\xcd\xaa\xa8\xfd\xba\x9d\x60\x54\x03\xf7\x86\x5e\x40\x51\x22\xef\xa9\xb0\x62\x75\x7a\x47\xf5\x48\xb1\x7c\xe6\xf0\x86\x6e\xe6\x52\x5e\x1e\x77\xa9\xe7\x24\xbb\x23\x34\x70\x22\x66\xd3\x3c\x93\xe6\xff\xb9\xfa\x6e\xe0\x77\x55\xdf\xd6\xf2\xc8\x23\x0d\xd2\x58\x30\x33\xa1\x7f\xf5\x3e\x63\x48\xa1\x42\x42\x32\xe8\x64\x3c\x2c\x94\x0c\x95\xf7\x58\x91\x45\x67\x57\x95\xb3\x39\xd1\xe3\x2e\xe7\xe6\x3f\xe2\x1c\xce\x70\xba\x85\x49\xa7\xb3\x08\xe1\xad\x11\xb4\xb2\x8f\x74\x2e\xd7\x66\xfe\xd7\x7a\x9b\x3f\x66\x05\x46\x1f\x7c\x81\x11\x80\x4a\xfd\x98\xf3\xc8\xc0\x19\x9f\x53\xf6\x8c\x79\x95\x22\x81\x16\xf6\x02\xa7\xe6\x87\x78\x1a\xe7\x18\x7d\x74\x1c\xa0\x72\x4d\x86\xf4\xab\x96\x96\x52\xa8\x86\xc1\x96\x8e\x8a\xc2\x62\x3e\x1d\xdf\xf9\xd3\x6b\xec\x9f\xd7\xe3\x1d\xf2\x27\x5b\x9e\x42\xa4\x3e\xe9\x9f\x98\x1e\xeb\x6a\x7e\xe9\x00\x22\x8d\x1e\x03\xc2\xae\xdd\xa8\x5b\x61\xa6\x0e\x77\x62\x5d\x1f\xeb\xa3\xa6\x21\xbe\xf4\x8e\xcb\xf5\x2e\x5f\xe9\x2e\x8d\x52\x4b\xc9\x50\x58\xdd\x6c\x4d\x19\xf8\x19\x39\xbe\xce\xea\xd4\x0f\xc4\xcb\x12\x81\xf7\x98\xca\x1e\xde\x54\x7e\x59\x8a\xa3\x79\xa7\x87\x3a\x2f\xdc\x91\xa6\xee\xea\x1a\x94\xd3\xe3\xe6\x6e\xa6\x38\x3d\x9e\x9f\x88\x18\xa9\x21\xdd\xb7\xbd\x4b\x42\x87\xf9\xc1\x93\x51\x56\xfa\xfe\x87\xd0\xd1\x69\xa8\x13\xfd\x18\x3d\x4b\x52\x34\x1f\xbf\xc5\xd7\xa7\x9e\x5b\x73\x52\x1e\x96\x0d\xd6\xbc\x3e\x21\x9e\x77\x6e\x08\xcb\x14\x79\x42\xe4\x17\x5a\xb2\xd3\xd3\xf3\x41\xdd\x99\x18\xe7\x06\x59\x92\x5d\x78\x84\x5d\x63\x6a\xca\x41\x0f\x8c\x4e\x89\x70\xb2\x32\xda\xe8\xa5\xc1\x6a\x32\xbc\x52\x94\xe5\x68\xfb\xb5\x1a\x64\x54\x7d\x22\xd4\xeb\x7b\xd5\xd5\x69\x67\xab\x05\xf0\x4e\x53\x57\x36\x60\x97\x99\x8d\x3c\x37\x2c\x1d\x3f\xba\x8f\x6a\x0f\xf2\x42\x56\x2b\x58\x5b\x82\xe4\x15\x3f\xa5\x59\x23\x7b\x7c\x16\xd0\xad\x02\xe9\xe7\x6b\x56\x40\x34\x8b\x78\xb9\xa9\x27\x36\xc8\x27\x2e\xa7\x18\xba\x03\xc0\xa7\x5b\x7b\xec\x07\xd4\x7c\x71\xcc\x65\x95\xe1\x45\x15\x9e\xca\x29\x81\x1c\x7c\xa3\xa5\x7a\xae\x13\xdc\x52\x77\x11\x1a\x3d\x6e\xde\xe3\x5c\x2e\xa7\x21\xd6\xd4\x06\x7c\x00\xd7\xbf\x7b\x87\xc7\x63\x2c\xda\x8a\x52\xfa\x4d\x2a\x5f\x48\x5d\x8d\x98\x95\xb9\xd2\xd5\x60\x01\xd5\x64\x63\x1c\xb0\x70\xb4\x2e\x4f\x3d\xd5\x47\x5f\xbb\x3e\x35\x61\xfc\x25\x81\x57\x48\x90\x3b\xfa\x87\xb4\xd2\xbf\x55\x7b\xec\x94\x48\xaf\xc0\x54\x41\x69\x30\x95\xd0\xcf\x1b\x99\xdc\xcf\xba\x5f\x1b\xf8\x9e\xa0\x10\x01\x7c\x5e\x05\x5a\xb3\x27\xc4\x0b\x34\x33\x1f\x48\x8f\xa3\x9d\xa6\x79\xca\x47\x58\xe2\xf4\x95\xb7\x29\x2d\xe7\xc7\x1c\x87\xdc\x4f\x96\xf3\x5d\xfe\xb2\x16\x62\x9d\xf7\x84\x42\x74\x87\xe2\xc8\x62\xd5\xa1\xb0\xe3\xba\x0e\x6f\x41\x4a\xc7\xbd\xb2\xb5\xdd\xa3\xd7\x70\xd7\xc5\x4c\x65\x13\x12\x12\x57\x06\xa9\x41\x29\x64\x5b\x2b\x29\xa6\x3c\x5d\x25\xca\x70\xd7\x82\xa7\x19\xfe\x22\xf9\xcf\x67\x05\x81\x95\x80\x02\x32\x8a\xc9\x9c\x0e\xc7\xb9\x4d\x2f\x84\x30\x68\xee\x48\x8c\x39\xeb\x4f\xa4\x4f\x93\x4f\xaa\x4f\x92\x4f\x3a\x6d\x31\xba\xb3\xaa\x96\xf2\x87\x98\xf7\x96\xad\x37\xa0\x24\xf6\xb2\x76\x74\x07\x8c\x00\x41\xdb\xe2\xdb\x38\x1d\x98\x86\x38\x94\xc3\x1c\x72\x6f\x69\x53\x98\xdd\xef\xc1\xd9\xc4\x3f\xa2\x9b\xbe\x70\x1c\x3b\xd6\x44\xad\x88\x37\x0d\x7a\x58\x45\x01\x44\x7c\x37\xd2\x5b\x06\x07\x85\x30\xbb\xe9\x05\xbd\xf6\x38\xf0\x8c\xc7\x89\x3f\x48\x4f\x85\x22\xb3\x00\xa6\x6f\x8d\x18\xc1\x21\xa8\x1d\xd2\x94\x98\x54\x74\xc1\xe2\x09\x29\x10\xdc\x18\xb4\x44\xbb\xc4\x72\xe1\x1b\xa3\xfe\x1f\xc1\x17\xd0\xce\xf7\x13\x9e\x27\xcf\xbd\xf8\xf7\xbb\x2a\x01\x71\xfb\x32\x51\xf2\x30\x92\xbc\xf9\x5c\x4a\x53\xe6\x6c\xe5\xc4\x64\x54\xe8\x01\x24\x0b\x79\x87\x81\x64\x70\xc9\xa4\x48\x10\x52\xcb\x2a\x2a\x71\x50\x05\x05\xb4\x8b\x9f\xaf\x14\x7f\xf4\xbd\x5a\xb6\xa9\x61\xef\x51\xbe\xcf\xb6\x60\x12\xf0\x38\xac\x07\x0f\xbd\x1d\xef\x3f\xcf\x28\x1d\x66\x58\xcc\x80\x4e\x88\x3f\x11\x26\x46\x14\xe6\x04\x14\xd6\xd8\x5d\xdf\xa8\x30\x6b\xc4\x3f\x10\x43\x3e\x2b\x60\x34\xdb\x93\x16\xa4\xea\xbf\x19\xd5\x01\xb0\x29\xd2\xba\x29\x61\xfd\xf0\xf7\xa8\x95\x40\x26\xc2\xbf\xbd\x36\xc1\xe6\x2e\xea\x43\x77\xb5\xa3\x20\x6f\xd7\x0d\x30\x1f\x35\xa6\xa5\xe6\x08\x2d\x18\x78\x78\xdf\x5a\x9a\x44\x69\x62\x7f\x15\x27\x30\x45\xbe\x59\xdd\x5a\x30\xbc\x21\x20\x61\x02\x1c\x57\x7e\x5c\x30\xbd\xe3\x07\x67\x1e\xb4\xaf\xb6\xbc\x11\xcc\x42\x2e\x3c\x24\x07\x8f\xa1\xa0\xda\x9f\x54\x9c\x9b\x7c\x2b\xa2\x20\x22\x42\xf2\xd9\xd1\xb2\x05\xcc\x4c\xe7\xf9\x71\x9e\x2b\x4d\xd6\x80\xaf\x4a\x38\x9a\x47\x06\xc8\xbf\x6f\xee\x01\xd2\x5b\x25\xf4\xfc\x76\x59\xdd\xcf\x0d\x5b\x6f\xfa\xde\x79\xbc\x56\x6b\xe3\x6b\x14\x74\x5e\x01\x6b\x99\x07\x0a\x99\x7c\xe2\xdb\x5f\x7b\x3c\x3c\x16\x76\x35\x65\xd2\xd5\x6b\xaf\x43\x1b\x92\x2d\xb9\xab\x85\x6b\x82\x98\xc8\x89\x62\xe2\x49\x85\x48\x54\x10\x63\x7c\x87\x8e\xeb\xa5\xb8\x93\xa7\xa1\x47\xa8\x4a\xe1\x8a\x4b\xd1\xa8\xe5\xf4\xe6\x5d\x21\xb3\x92\xeb\x95\xb0\xd9\x48\x65\xa2\x42\x3a\xdb\xa7\xc0\x8b\x64\x81\xf4\x8f\xa5\x90\xde\xd9\x52\x70\x71\x7c\x78\xa4\x1b\x1c\xea\xca\xd8\x7e\x57\x6d\xff\xe3\xac\xb7\xed\x65\x98\x52\xc9\x91\x71\xa3\x76\x05\xdf\xab\xde\x3b\x85\xc7\x80\x85\x62\x05\xa8\xd4\xd9\xd8\xb9\x53\xe7\xd5\x88\xee\xda\x6c\x61\xe6\x70\xd2\xfb\x29\xbf\x9b\x9f\x77\x9f\xd5\x29\xaa\xab\x7f\xaf\xa1\x62\x22\xec\xe8\x26\x6b\xa1\x63\x8e\xc1\x31\x83\x98\x2a\x0f\xc1\xdd\xd9\x86\x46\x60\xa1\x6f\x32\x7e\x06\x53\xd0\x60\xba\x59\x68\x2a\x41\x20\xb6\x98\x91\xdb\x83\x15\x2d\x33\x0b\xcc\xc6\xae\xe6\xb0\x3f\xdc\x41\x41\x80\x13\xb9\xb6\x09\xba\xa4\x28\x68\x71\x5a\xcc\xf5\x4b\xa9\x7c\xbc\xf5\x49\x19\xc7\x2f\x5b\xd0\xd0\x68\xa0\xf8\x7d\x56\x2c\x5f\xbb\x9f\xe6\xcc\x23\xd0\x65\x73\x4d\x54\xf3\x1e\x5e\x9c\xbf\xaf\xd0\x18\x2f\x71\xb4\x6b\x2b\x0a\x89\x7d\xf6\xae\xd4\x9c\xef\x74\xa2\x78\x66\xc2\x9c\xf3\xa7\xdc\x0a\x43\x39\x8b\xb0\x57\x77\xf6\xfe\x0b\x28\x69\x20\x3b\xa4\x99\x12\x57\x19\x3f\x0e\x4c\xd6\x60\x56\x42\x15\x52\x42\xd5\x20\xd1\x6f\xfe\x22\xea\x9d\x43\xd2\x2f\x40\x33\xa7\x79\xad\x77\xba\x14\x12\x6b\xd0\x42\x2b\x9c\x07\xef\xb5\x43\xad\x94\x84\x22\x85\x45\x8d\x5b\x28\x59\xc7\x51\x93\x52\xaa\x8a\xd5\xb5\x14\x3d\xc8\xab\x6d\xa2\x28\xf5\x6c\x43\x4d\x23\x46\x83\x29\x65\x26\x85\x8d\xf0\x22\xc0\x17\x42\x96\x6f\x75\xd5\xdc\x52\xa2\x40\x6c\x33\xcc\xa0\x5d\xd6\xe7\xb9\x5f\xeb\x7a\x7b\xbe\xf6\x2f\x0a\x90\x94\x99\xd1\x66\x75\x5b\xbb\x3b\x3d\xd0\xc0\x84\x8f\x65\x8d\xc7\x98\x85\x0b\x83\xf2\xe9\xdf\xc3\xec\x5d\x3a\x2b\xb8\xf6\x79\x87\xe8\x15\x24\x79\xdc\x04\xcd\xf0\x28\x70\x5d\xae\xb7\x5b\xd3\xab\xa4\x07\xba\x43\xf7\xe9\xb7\xf5\xd2\xd8\x14\xe0\xc5\xe6\x36\xba\x34\x4c\x81\x49\x33\xe9\x61\x29\x72\xa6\xc3\x8c\x85\xae\xa6\xf9\x0d\x14\x35\x87\x44\x2d\x5b\x8a\xd0\xdb\x59\x26\xd2\xee\xd8\x32\xdc\x9f\x10\x7a\x46\x09\xf8\xab\x7b\x3f\x26\x29\x3c\x5c\x3f\x38\xeb\x6d\x74\xfe\x45\xfe\xe6\xcc\xdf\xf7\xfe\xcb\x14\x67\xb7\x15\xce\x11\x8f\x9c\x8c\x54\x9c\x9e\x78\x8c\xc8\x98\xcb\x38\x5d\x7f\xc9\x58\xa6\xfc\x27\x4e\x23\x44\x0a\x8d\x23\x1c\x1b\xe2\xc4\x5a\xe0\xa1\x6d\x8d\xf6\x78\x65\x2d\xad\x79\x58\x72\xbd\x8a\x36\x98\xe1\x06\x4c\x84\xe5\xb1\x0d\xbd\x60\x00\x5d\x26\x25\x5b\x65\xcd\x95\xb4\x0b\xe3\xb7\x26\x97\x03\x84\x42\x14\x23\xdc\x82\x57\x58\xa2\x1e\xe1\xb9\x7a\x51\xcf\xaa\x27\x2b\xfa\xb6\xba\xae\xad\xa5\x38\x29\x16\xaa\xe9\x1c\x27\xde\xcb\x60\x15\x8c\xea\x65\x03\x9f\xe4\xc4\x24\x8c\x4c\xdf\xbc\xaf\xad\xed\xf8\x07\x07\xab\xb5\x71\xec\x05\xf5\xea\x6c\x76\x3f\x31\xd7\xf5\x97\xba\x05\xf3\x18\x7c\x8e\x64\x7b\xdd\x7b\x45\x5e\xf7\xe7\x7a\x8b\x6d\xef\xf3\xbf\x66\xcf\x83\xd6\x84\xfc\x87\x43\x1e\x3b\x9f\x8e\x5f\x52\x14\x33\x19\x1d\xe6\xb1\x09\x02\x76\x63\x89\x56\x23\x0c\x5a\xb2\x69\x20\x3e\x30\x47\x15\x93\xd9\x1d\xe6\x44\xd7\xb4\xb7\x08\x29\x93\x5a\x79\x95\x35\x28\x64\x34\xc6\x24\x3b\x1b\x89\x00\xb4\xe2\xa8\x45\x4a\x8f\xb1\xdf\x5f\x3f\x21\x7b\x5d\x7d\xd2\xca\xd6\x2e\x14\x07\x6d\xcd\x8b\x69\x46\x37\xae\xc4\xd9\x70\xbd\x74\xe8\x0c\x1b\x35\x8b\x81\x16\x92\x1b\x3b\x9c\x8a\xce\xfc\xbc\x40\xe6\x10\xbc\x2a\xb9\xbe\x5a\x76\xae\x59\x74\xcb\xdd\xaa\x78\x4b\xc9\x9d\xc7\x83\x52\x3b\x91\x68\x98\x2a\x5c\x8f\xf9\xe4\x26\xdc\xe1\x0b\xfb\x3c\x32\x04\x73\xbc\x2e\xd6\x76\xe7\xa7\x5b\x9a\x41\xcc\x9d\x02\xa5\x4f\xb3\x4f\xdc\x4f\x82\x4f\x8f\xcf\xa6\xfe\x60\x0e\xe7\xfe\x8d\x16\x82\xad\x00\xa2\xa6\x00\xef\x23\xa4\xae\x72\x86\xce\xc7\x6a\x1e\x40\xbd\x78\xa7\xa8\x88\x76\x59\x71\xab\x78\xef\x6f\xb0\xf8\xe7\x36\xd3\x3a\x11\xce\x5c\x78\x33\xe5\x40\x71\x33\x65\x48\xeb\xe2\xec\x2b\xb8\x16\x12\xc6\x68\x86\xa3\x1e\x42\x5d\x92\x77\xf0\x1f\xe3\xa1\x09\x2e\xe3\xf2\x4e\x89\x86\x81\xa6\x0b\x7d\x35\x61\xe3\xbc\xdc\x11\xcb\x18\x2d\x96\xdd\xc4\x81\xa6\x0d\x2d\x16\xf9\xce\x01\xeb\x46\xcb\xab\xc0\x0d\x2c\xf1\x58\xd7\x02\x27\xdc\xdd\x0c\x7d\xd3\xd2\x56\xad\xfa\xde\xb3\x5f\x3d\xd9\xd4\x29\xb9\x62\xa7\x64\xd3\xb6\x7e\xd2\x58\xa2\x2a\x39\x73\x87\x6f\x28\x35\xe3\x1d\x8f\x84\x2f\xe9\xf4\xf9\x05\xa4\x19\x2f\x4c\x21\x6c\xa9\x3a\xc2\xf2\xc8\x65\x49\x42\xd6\x40\x78\x67\xe8\x73\xb7\x24\xef\x71\x2f\xd7\x3e\x97\xeb\x22\xa6\xc1\x2c\x4c\x0f\xe3\xc5\xbf\x26\xc7\x9e\xf8\x97\x4f\x9c\x3f\xcc\x8a\x87\xac\xad\xea\x58\x73\x6f\xb5\xad\x96\x94\x8f\x1f\x12\xfe\x61\xed\x8f\x15\xfc\x21\x3e\x3f\xc0\x92\xba\xc6\x2d\x4b\x03\x69\x77\xb7\x63\x53\x8e\xd9\xd9\xda\x1b\xba\xc4\x19\x62\xca\x7e\xf3\x95\xf3\x54\xff\x00\x8c\x75\x9d\x9a\x88\xaa\x56\xe6\x30\x17\xe1\x7f\x96\xf6\x25\xa3\xbe\xd1\xfa\x8b\xb9\xb1\x96\xd7\x2b\x34\x41\x90\x85\xdd\xed\x42\xdc\x68\x21\xf2\xd9\x9f\xb1\xa1\x20\x89\x0b\xe1\x64\x78\x6f\xe2\x88\x59\x46\x89\x52\x77\x3f\x31\x71\x79\x4e\x8d\xfb\x1f\xe6\x4e\x0e\xe7\xb0\xfb\xde\x65\x96\x91\xc8\xe7\xbe\x1d\x1b\x06\x25\xcb\xc4\xf2\xe8\xbf\x5d\xac\xb9\x5d\xe3\xa1\x67\xb0\xdd\xd6\x3f\xb2\xbc\xe9\x72\x3a\xbd\xe5\x1f\x50\x5c\x07\xbc\xd6\xf4\x00\x29\x05\x0f\xdd\x77\x2c\x29\x32\xbd\xeb\xd8\xb2\x04\x64\x52\x3c\x49\x23\xbb\x87\xe6\x7b\x42\x21\x25\x62\x55\xb1\x56\x5b\x7b\x66\x8a\xb2\x08\xfd\x32\x56\xb2\xe8\x73\x63\xf8\xfd\xba\x09\xf0\x57\x19\x6a\x8c\x63\x99\x89\x5e\x83\x66\xa5\x68\x4e\x5e\x67\x35\xbf\xb0\x2c\x6f\x4b\x3f\x3b\xad\x41\xf8\xda\xa4\xc7\x0a\x6c\x1e\x30\x56\xd3\xb1\x0f\xe7\xf1\xb7\x48\xe9\xfc\xca\x30\x47\xca\x55\xe0\x6b\xbf\x82\xcf\x8b\xc5\x93\x83\xdc\x3b\x4a\xff\xb8\x5f\x6b\xe9\xec\xc0\x1c\x46\x5d\x2c\x54\x0e\x51\x6e\x5e\x6e\x05\xf9\x97\xe3\x36\x85\x83\x13\x28\xc0\x22\x07\xaf\xe0\x89\xc6\xc7\x8b\x46\x47\x52\x22\x8c\x6a\x8d\x2a\x1d\xe6\x56\x7f\xa3\x3c\x45\xcf\x9f\xd4\x8c\x0e\x10\x02\x6e\x77\x2a\x88\x11\x77\x28\x7f\xfe\x09\x98\x15\xc5\xfd\x90\xc5\xc7\x3b\x2c\xb8\x5e\xb8\x3f\xf5\x7a\x30\xaf\xf9\xec\x70\x18\xa9\x9c\xbe\x72\xda\xbe\x4d\x35\xc0\x1c\x7d\x7d\x22\xa4\x30\xe0\x97\x6a\x24\xad\xdc\x92\x51\x68\x5f\x3c\x5a\x32\x58\xca\x59\x06\x15\x18\x64\x14\xcd\x1a\xb1\xf2\xbf\xe6\x09\x1d\x86\x18\x64\x95\xe4\x54\x2a\x7c\x6f\xe6\xc6\x81\x79\xca\x56\x97\xf6\x09\xf5\x39\xaa\xe4\xfc\xeb\x2f\xd9\x82\xa0\x1a\x7f\xb2\xb0\xb3\x00\xf2\xfb\x58\x85\x43\xef\x7e\x6f\x91\x3f\x70\xeb\x2a\x5c\xb6\xb0\x40\xf2\xb9\xb6\xe7\x8e\xd0\x2f\x26\xac\xd8\x29\xdd\xc9\x67\xa8\xa4\x6d\x6d\xf7\x89\xf9\x12\x55\xd0\xf6\xd0\xdf\x62\x1c\xfb\x39\x47\x58\xd9\x5c\xf2\xbb\x58\x2f\x54\x13\x5e\xc8\x41\xb3\x4f\x05\x7b\xec\x15\xf3\x02\xd1\xde\x7d\x94\x1d\xdc\x3c\x82\x9c\xc4\xad\x23\x2d\x4d\xd8\x66\xe0\x0c\x2a\x35\x2f\x8a\xa9\x1e\x77\x0b\x86\xe6\x44\x32\x68\xfd\x42\x96\x5d\x49\x95\x12\x39\x86\x18\x5c\x4d\x74\xa8\xf4\x24\x3e\x8a\x8c\xfe\x8d\x26\xad\x4f\xe0\xfc\x7a\x7a\xe1\xb4\xf3\xd2\x55\x4c\xba\xb9\x34\x20\xb6\xc0\xef\xe1\x38\x4c\x38\xef\xd7\x79\x52\xb4\x60\x40\xd7\xe8\x47\x2d\xe3\xec\x17\xf3\x40\xf8\x14\x78\xd9\x98\xed\xc1\xcf\x3f\xe9\x46\xf1\x81\xca\x2a\xe1\x87\xa2\x6b\xce\xf5\x8a\x5e\x83\x4b\xb4\xf2\x57\xf2\x9e\xc7\x0f\xe5\x18\x7f\xe0\xbd\x1c\x33\x61\x62\xe0\xa2\x69\xc3\xe3\x69\xfd\xa1\x92\x59\xe7\xfa\xb5\x1c\x77\x4d\xeb\xd1\x5d\xdd\xd1\xa2\xe0\xc9\x7f\x45\x31\xbb\x8a\x69\xfd\x39\x0f\xb7\xec\xb2\xfa\xd2\x13\x05\xc9\x50\xd1\x69\xd7\xdf\x74\xde\x3f\x80\x9a\xcf\x04\x54\x9e\xc7\x4a\x18\xb4\xcb\xae\xfd\x3e\xff\x34\xac\x64\x75\x2d\xe4\x5f\xf9\x1a\xf5\x2d\x8f\x77\x4a\x28\xbc\xcf\x6c\x10\x32\xa4\xb5\x98\x2e\x45\x37\x94\x30\xa4\x21\x75\xf2\x43\x3c\xf4\x6e\xf4\x0e\x90\x99\x92\x4b\x89\xff\xb2\x8a\x92\x90\x1b\x3e\x84\x86\xeb\x4f\x23\xdb\x6b\xa3\xa5\x60\x76\xa1\x82\x98\x42\x01\x5e\xba\xb4\x91\x51\xb9\x35\xbd\x5e\x89\xfe\xd9\x3a\x55\x21\x0a\x8e\xdd\xd2\xe8\xc2\x98\x87\x05\xa6\xdb\xfd\x16\x5f\x38\x49\xe8\xcf\x33\x24\xb2\x64\xfb\xa9\x01\xaf\xe1\x34\xe7\x48\x84\x55\x3f\x6e\x26\x66\x0a\x8d\x2f\x09\xf7\xa8\xdb\xa3\x35\x2b\xd0\xf3\xaf\xfc\xde\xbe\xf3\x32\x31\x7a\xa6\x00\x2d\xc8\x7e\xbd\x12\x54\x04\x2a\x13\xa0\x46\x8c\xc0\x6f\x58\x90\x7a\x48\x44\x32\x18\xaf\xef\x3c\x0d\x6f\xe9\xe5\xed\x7c\xaf\xaa\xa8\x09\xe5\xc8\xd1\xf3\x84\x2b\x42\x6f\x45\x0c\xf5\x7b\x83\x7c\x1a\x43\xee\xf6\x8c\xed\x9b\x40\x76\x49\xfd\x28\x3d\x83\xd8\x7c\x8e\x78\xe4\xe9\xb4\x34\x63\x64\xfa\xce\x2a\xe6\x8f\x76\x3f\x57\xf0\x43\xbc\x10\xd6\xe9\x1d\xc1\x6d\xbe\xec\x4d\xef\xad\xa6\x86\xcf\x4f\x86\xd9\x6b\x62\x01\x43\x6d\xa7\x1a\xf4\x56\xf0\x15\xed\x0f\x1a\x71\xb0\x07\xbd\x12\x3a\xe4\x6f\x0e\xbe\xd3\x87\xbc\x73\x8f\x39\x8a\x4c\xac\xee\x55\x4f\x0e\xff\x0e\x64\xa7\xcd\x54\xa5\x33\x4e\x57\x55\x92\xc8\xc5\x9d\xd2\xb5\xe5\xd1\xe4\x2d\x27\x99\xfe\xb4\x1a\xf8\x25\xef\x08\x93\xfe\xa9\x4b\xea\xbf\xcc\x2d\x99\xb6\xec\x5d\x02\x78\x80\x44\x7b\xce\xd0\xfd\x9e\x46\x74\xf5\x0f\xfc\x14\xcc\x6f\x90\xff\x3d\xdb\x75\x94\x4c\xf5\x5f\x59\xa1\xeb\xc4\xd4\x7a\x1c\xfb\xe0\x70\xb8\xba\xb7\xee\x89\xed\x07\xe8\xf8\x20\xb8\xe8\xb4\xec\x4e\xa9\xfb\xce\x7b\xf3\xf4\x60\xae\x57\x19\x80\x77\x7d\x0f\x4a\x91\xc4\x40\x8d\x53\x94\x27\xa5\xe7\x74\x64\xfa\xe9\xb4\xd6\xbb\x36\x36\x4d\x95\xb0\xde\x10\x8c\x69\x7f\x69\x06\x66\xb7\x44\x20\xe1\xf2\x13\x3b\x8a\x91\x1b\x62\x47\x12\xc9\x8b\xad\x22\xde\x45\x78\x14\xe1\xa7\xc1\x1d\x26\xa3\xc3\x74\xbc\x30\xfd\x7c\x69\x5b\xef\x90\x4d\x83\x7e\xb4\xe4\x2a\x8e\xd9\xdd\x78\x6e\x3e\x34\x99\x36\xa1\x9a\x29\x1c\xe9\x3a\x2f\xf7\xf7\xd2\x51\x21\x92\xfc\xdc\x00\x1b\x9e\x80\xad\x30\x8f\xcd\x0e\xab\xbd\xbf\x62\xed\xf4\x7f\x50\xe6\x7b\xfc\xf4\x40\x6a\x01\x82\x58\x92\x36\xa5\xb1\x71\xcb\x3a\x3b\x09\x0a\xdb\x37\x67\x97\x6f\x34\x1e\x5d\xeb\x5d\x09\xde\xfa\xb6\x7e\xa0\x55\x84\x53\xca\x38\x15\x99\x3f\x97\x87\x80\xc8\xbe\x66\xdb\x60\x9f\x6e\xb0\x88\xa9\xa6\x5b\xe3\x65\x61\x52\x1b\x67\xef\x3a\xed\x05\x8d\xd3\x3d\x65\x57\xc4\x69\x00\xe6\x9c\xb2\x11\x38\x9d\x50\xce\x70\x7e\xb3\xfd\x77\x75\x10\x9b\x7c\x1a\x58\x69\xd1\x3f\x71\xc1\xab\x1e\xcd\x0f\xa2\xf4\xba\x88\x88\x38\xbe\x4d\x49\x19\x25\xc1\x3a\x3e\x6c\xc0\x67\x3f\xbc\xe7\x91\x64\xcb\x6b\xbe\xbb\x94\xe2\x32\x7a\x7d\xad\x28\xf0\xc4\xcf\x47\x73\x53\xdb\x70\x62\x50\x8c\x64\xce\x86\x1d\x4c\xf1\x5c\x68\x08\x3c\x2e\xe1\x6c\xc2\x95\x76\x4f\xde\xf2\xaf\xfa\x9f\x95\x15\x24\x54\xcb\xed\x3b\xec\x03\x8d\xbe\xbb\x1e\xbf\xcf\x7b\x84\xe9\xbc\x8d\x7f\x49\x18\x39\x4d\xb2\x9b\x01\xbd\x77\xc3\xd7\x34\x29\x9d\xa6\x2c\x56\x73\xf3\xa3\xb6\x1f\xe2\x10\x0e\xcd\xec\x9d\xbf\xe4\xc3\x39\xe6\xa6\x90\xfc\x81\xc9\xa1\x9b\x61\x24\xbf\x39\xab\x0b\xc6\x7e\x98\xfa\x35\xe4\x49\xfd\x60\x4a\x1d\x89\x95\x05\x28\x6f\x49\xc5\x87\x8c\xc7\x05\x7b\x88\xc1\x2d\x06\x59\xdb\x2c\xef\x5d\x0e\x23\xf7\xf3\x2a\xf2\xcf\x95\x3a\x4d\x31\x94\x90\x6b\xd1\x90\x6b\xcd\x84\xe0\x03\x06\x2a\xe6\x28\x4c\xba\x53\x22\xa8\x8d\x34\x22\xfb\x31\x31\x0c\xb7\x80\xa9\x91\xa3\xb7\xc3\x25\x47\xba\xb0\x49\x96\x6a\x33\x37\xb2\x79\xd4\x34\x25\x11\x28\xc6\xd4\x1f\xd0\x2b\x59\x24\xf3\x8a\x5c\xc8\x9c\x07\x91\x4c\x5c\x35\xa6\x4c\x7f\xca\xd9\x8b\xb4\x6a\x5b\x37\x4b\xbb\xf1\x29\x17\x85\xde\x51\x31\xca\x6f\x18\x7d\xa0\x53\x04\xc1\x94\x35\x23\x7b\x82\x53\x14\x2b\x08\x7b\xf9\xa2\xb3\x49\x17\xd8\x1e\x6c\x3f\x43\x78\xb5\x04\x3e\x77\xde\xfe\x3a\x13\xd0\x5e\xab\x95\x61\x2c\x2a\x29\x73\xc6\x5f\x05\x28\x45\x2d\x2c\xbb\x3c\x32\x59\xf9\xba\x70\xe3\x2f\xff\x92\x67\xf9\xb5\x30\xc6\x96\x2f\x94\x92\x8e\xae\x9e\x07\x3f\x49\xd2\x88\x1d\x3d\x2f\xda\xd1\x56\x08\x3d\x88\xd8\xc4\xec\x8c\x4f\xc6\xe2\x2d\xe6\xe7\x99\x1b\x18\x95\xf3\xc1\x26\xff\x11\x43\x40\x29\xc8\xc5\xf3\xb9\xcb\x2f\xf3\x2f\x81\x89\xf6\x18\xcd\x44\x33\x91\x05\x7f\x00\x3c\x5c\x3c\x1e\xd0\x5f\x1f\xa9\x2d\x5e\xa8\x5b\x94\x6b\x38\x21\xfd\xf4\xff\x94\xf8\xb4\xd0\x2b\x22\xf3\xb0\xeb\x7e\xca\xf6\xa9\x69\x3b\x42\x36\x62\x4e\x16\xa2\x9e\x99\x6f\x01\x93\x00\x41\x25\xbe\xb0\x73\x27\xb5\x5f\x05\x5c\x77\xbd\x97\x5d\x6e\x3f\x6f\x6f\xc9\xcf\xb7\xef\xd2\x60\xd4\xdc\x24\x15\x20\x4e\x33\x3f\x0a\x8e\x5f\x91\x96\x56\x5d\x5e\xaa\x05\xb3\xc4\x69\x13\x23\xa8\xd5\xe7\xfd\x60\xed\x51\x91\xaa\xd8\xe3\x14\x82\xc2\x9b\xca\x2b\x86\xef\x96\xc4\xaa\xcf\xc1\x38\x25\xbc\x5e\x11\x28\x16\x2b\xc9\xf1\x5b\xc6\x7e\x1b\xc1\x78\x24\x7a\x9d\x09\x78\x58\x26\x0c\x25\x64\xe0\x34\xba\x1d\x42\xd4\x10\x9a\x10\xee\x4d\x26\x7c\xf1\x41\x94\xa2\x8e\xac\xa8\xfd\x55\x01\x3e\xa8\xc6\xa4\x23\x08\x60\xa0\xde\x58\xb7\x41\x57\x4b\x33\x2a\xa3\x01\x51\xb7\x92\xf0\xe9\xc3\xec\x62\x2e\xed\x4a\xb4\xe1\x3f\x10\xc1\xbd\x71\x70\x59\x6e\x46\xc0\x9f\xcd\x36\xcb\xcf\x71\xa2\x47\xe2\xde\x6f\xa9\x3e\x6b\xf4\x29\x9e\x05\xf0\xa8\x67\x40\xa6\xfb\x01\x0e\xcb\x9f\x7d\xc8\x27\xa6\xad\x8d\x2f\x40\x6a\x9b\x21\xdd\x24\x53\xe9\x54\xc6\xee\x09\x2d\x98\xeb\x91\x28\x16\xb7\x0b\x6a\xd6\xa6\xf0\xa8\x58\x2a\x53\xf5\x91\x73\x4d\x1d\xe3\xf4\xcb\x56\x7f\x2c\xa4\x06\x60\x07\x01\x15\x34\x46\xbc\xb9\xff\x8b\x31\xba\xa4\x10\x69\x29\x7c\x28\x09\x65\x37\x34\x84\xe8\x5a\x6b\x1f\x5a\x31\x47\xb2\xa0\xfb\x42\x21\xbd\xc1\xfc\xb1\xad\x22\x3f\xf9\x0d\x37\x79\xcd\x26\xf5\x6c\x07\x8f\xf3\xa0\x71\x61\xf9\x04\x86\xee\xcc\xa2\x43\x63\x0b\x83\x41\x21\xbb\xa5\x70\x07\x4a\xac\x2f\xdf\x06\x26\xa7\xf6\xa2\x71\x39\x20\xea\x47\x34\xc6\xb4\xc1\x80\xdb\x9a\x6a\x42\x06\x28\x98\xaf\xcc\x3e\x7a\x8f\x6b\x7d\xe8\xe6\x7b\x28\x2d\xca\xf4\x21\x95\x27\x3d\xc3\xc6\x36\x3d\xca\x2a\x09\x09\x4a\xda\xef\x4b\x04\x9c\x35\xfe\x20\xad\xe3\x5a\x33\xa9\xe8\x06\x2c\x8e\x9a\xc9\x92\x14\xa0\xd1\x8b\xc8\x2c\x83\xaf\xaf\x9e\x80\x17\x26\xe9\xf7\xf6\x39\xd8\xb6\xac\x55\xbe\x06\x0f\xc9\x98\xe4\xb5\x14\xd9\x21\x65\x68\x49\x30\xea\x76\xbb\xd3\xe5\x9a\x4d\xcd\x1c\xca\x49\xcf\xdc\xba\x43\x40\xeb\x15\xb5\x10\xc8\x78\xe0\xb4\x24\xd3\xe5\x96\x4f\xe0\x2b\xaf\xe7\x7d\xc1\x63\xdd\xef\x41\xca\xeb\xd3\xca\x85\x42\x56\x5b\x93\xef\x2e\xf9\xe8\x68\xe6\x84\xcb\xa2\xb0\x57\x50\xdb\x71\x39\xff\x96\xc4\x7c\x09\xe5\x2b\xf7\xf5\xd6\xe3\xe4\xd4\x66\xe7\x0f\x36\xf2\x5d\xa0\xc0\x32\xe3\x06\x0e\xa7\xe6\x74\xcc\x58\xa9\x71\x66\xdb\xf0\xee\x04\x38\x21\x29\x1d\xed\xbe\x35\x58\x08\x31\x95\x8e\x26\x1e\x06\x84\x97\xdd\x36\x29\x7c\x1d\xaf\x55\x39\xbf\x01\x08\x18\x60\x7a\xb7\x29\xd2\xb8\x7d\x2b\x09\x8e\xa9\x65\xf2\x5a\x17\x6c\x65\x21\xc3\xad\xd7\x72\x2b\x1c\xa2\x7a\xdb\xca\xc7\x64\x18\xde\xa7\xa6\x14\xec\xbb\x37\x22\x27\x4d\xf4\x50\xb5\x52\x11\x97\x3c\x2d\x99\xaf\xc7\xe5\xd0\xf5\x65\xa1\x5b\xc8\x01\x86\x77\x6a\x04\xc4\x7a\xd0\x72\x04\x66\x2d\x16\x7e\xe0\xd6\x0c\xae\x18\x80\x31\x21\x77\x72\xbc\xd4\x60\x30\x34\x44\xbf\x39\xd1\x30\x4a\xdd\x74\x3b\xf7\x37\x86\x59\xc2\x7e\x38\x33\x1c\xc5\xb0\xda\x44\xbe\x1f\x31\x8b\x95\x37\x92\xa8\x7d\xeb\xc0\xf6\x8c\x9a\x77\xcc\x07\xcb\x82\xa2\xa9\x2a\xf0\xf3\xab\x0f\x0e\x2d\xa5\x79\xcb\x20\x4a\xdb\xc1\xe2\xd1\x8e\xca\xfb\x59\x4c\x8a\xeb\x3a\xe2\xdf\x6a\x80\xd1\x36\x1f\xb8\x74\x0a\xb6\x15\xc4\x21\x27\x8d\xa1\xf3\xf3\xb7\xa1\x90\x52\xa7\x53\xe0\x16\x96\x5b\x04\xdf\x6c\xf0\x9e\xa2\xeb\x8f\x77\xbe\x2f\x3f\xfe\x89\x31\x19\x3e\xbe\xf2\x56\x11\x97\xe3\x2f\x2b\x25\x3e\x9e\xaf\xd7\xc9\x93\x6b\x38\x9e\xeb\xd0\xfb\x6a\xfc\xdd\x8b\x5e\xaf\x09\xe4\xdf\xac\xd1\xf5\x13\x53\x99\xa3\x12\xa2\x63\x3f\x79\xf4\xec\x15\xc4\xd7\xf1\xe8\x51\x6a\x39\xeb\x5b\x13\x62\xdf\x06\x72\xad\xbf\x01\x08\x96\x6a\x38\x53\xc5\x50\x20\x30\xcd\x9d\x62\xff\x57\xb6\xf4\x9a\x1d\x98\xf9\x47\x0d\xec\x56\x90\x04\xea\x3d\x1a\xb5\xbf\x17\x91\xc6\xc7\x37\xd1\xcf\x05\x18\x68\x47\x7d\x2a\x48\x5d\xed\xbf\xd9\x54\x0e\x0b\xe7\xc2\x19\xd9\x46\xc3\x71\xe4\xb9\x04\xbf\xf1\x64\xe3\x57\xff\x42\x5b\x80\x30\xe7\x47\x1e\x9d\x5c\xc1\x47\x89\xa0\x48\x5f\x39\xdb\x65\x76\xca\x03\x8a\x02\xc8\x7c\x29\x3b\xb7\xbd\x05\x13\xb4\x7d\x9a\x31\x10\xae\x96\x73\x6e\xf9\x31\x0e\xf8\xdd\xbf\x71\x18\x87\xda\xce\x90\x76\x5b\xf0\x8a\x8e\xb2\x8f\x47\xdd\xea\x28\x19\xe2\x9a\x99\x8c\xc7\xd8\x7d\x7f\x73\x15\xa4\xc0\xb8\x21\x7d\x9b\x68\x14\xc0\x2f\xed\x78\xe8\x32\x64\x9e\x44\x6b\x26\xc0\x2a\x41\x27\x46\xb8\x62\x5a\xcf\xf5\xe2\x39\xb5\x3a\xf3\x54\xf9\x16\xbd\xa9\x68\xbe\x5c\x6b\x2e\x56\x27\x8a\xdb\x97\x10\xae\x81\x6d\x54\x5e\xa2\x84\x98\x29\x1a\x52\x10\xa6\x7a\x6e\x49\xb5\xe9\x1d\x53\x7b\xef\x5d\xb6\x97\x54\xf1\x24\x60\xb2\xba\x6f\xe3\xa6\x76\x42\xbe\x03\xd9\x08\xf3\x30\x4d\x4f\xb5\xda\xc7\x09\x70\xcc\xd8\x8b\xa7\x2b\xab\x33\x54\xd0\x01\x1d\x30\x58\x13\xbe\x14\xc3\x72\xe6\xe0\x05\x85\xa2\x52\x90\x2b\xf3\xff\x0e\x53\xcf\xcb\xdd\x76\x78\x02\xf8\x9f\x91\x3b\x9a\x1d\x6f\x78\x6f\x79\x59\x46\x44\xd7\x8f\xd3\x1c\x0d\xa0\x5e\x02\x9a\xbf\x7e\x8b\x0d\x7d\x47\xf7\xdd\x41\x62\xfe\xa2\x6a\x4e\x09\xe2\x75\x28\x95\xf2\xa5\x1b\xd4\x8c\x76\x43\xd9\x64\x27\xbb\x87\x1a\xd5\x8f\x35\x37\xca\x84\x8f\x9b\x14\xd3\x9a\xf2\x54\xe2\xcc\xfb\x63\x28\x3c\xd3\xe5\x44\x22\x77\x66\x22\x9f\xfc\xde\x7d\x2f\x81\x7a\x3d\x27\xe2\xa9\xc1\x9b\xb2\xc7\x9c\xf5\xcc\x3c\x1b\x81\xf6\x09\x49\x87\x46\x23\x5d\x69\x8c\xa2\xfd\x48\x5e\xf5\x76\x26\x9f\x61\xdb\x25\xe7\xa9\xe1\xd9\xd1\x84\xdb\x55\xd4\xaa\x99\x33\xe2\x24\x8e\x92\xf2\x4b\x83\x11\x85\x67\xa5\x71\xe7\x82\x17\x94\x02\x66\x08\x2e\x8a\xf8\x83\x83\x40\xf3\x93\xff\x3d\x63\x6e\x1e\xbd\x9f\x29\xe5\xf8\x17\xe4\x9f\x31\xb6\x04\xd2\xa6\x42\x95\x7e\x7d\x63\x87\x09\x28\x0e\xd1\x4f\xb2\x02\x28\x6d\xd0\x66\x4b\x0a\x7e\xfd\x17\x6e\x0b\x02\x8e\xe0\x93\x85\x94\x89\x60\xd2\x23\x69\x09\xd6\x5f\xaf\xa3\x2f\xf5\xde\xaa\xcf\xef\xc8\xb6\xcd\x29\x7f\x56\x49\xce\x24\x42\x7e\x88\xf0\x31\x0d\xb7\x61\x21\xd0\x3f\x5a\x6f\x31\x95\x2b\xa2\xc6\x87\x34\x6c\xe7\x2f\x19\xe2\x61\x4d\x71\xa7\xf2\x20\x1c\xfa\x7a\x90\x9d\x3e\x48\xdc\x52\x5e\x98\xac\x79\x30\xc1\x37\xe2\xd0\x1b\xbe\xf1\x9c\x4e\xc2\xb3\xe1\x08\xed\x76\x9b\x63\x94\x57\xe6\x57\x77\x57\x07\x15\xed\x09\x2d\x87\x09\x2d\xdc\xde\xc4\x62\xa3\x86\x5d\xb3\x7e\xb4\x5f\x3f\xc1\x1d\x84\xc7\x2f\xf7\x14\xda\xcc\xf8\xbf\xfe\xcd\xe9\xe7\x7a\x83\xd9\xae\x2d\x7a\x3b\x0b\x7b\xe6\x97\x96\x89\xbb\x12\x78\x5b\xdc\xbd\x64\x31\x5f\x58\xaf\x42\x21\xe0\x39\x5a\xcd\xfb\x2c\xb5\x6d\xca\x66\x71\xf9\x72\x41\x39\x0f\x11\xd7\xf3\x54\x5d\x0b\x2d\xaf\x8b\x26\xd8\x5c\x3e\x2f\x55\xba\xc5\x35\x67\x7c\xd1\x00\xff\x80\x38\xb4\x5d\x6d\x12\x5e\x98\x97\x6b\x47\xfb\x22\xaa\x0d\x8e\xb9\x39\xde\x03\x9b\xd0\x1b\xfb\xfe\xa8\x8f\x16\xb2\x33\x82\x8f\x9f\xa3\x31\x01\x5d\x8a\x2f\xce\x3c\x14\x91\xb9\x3f\x94\x10\x46\xce\x72\x4f\x3a\xaa\x60\xe9\x9c\x4d\x2c\x32\xb7\x6a\xee\x05\x1d\x56\xa4\x30\x4e\x53\xe9\x4f\x72\x37\x71\xe0\x41\x63\x25\x75\xd1\x39\x56\xd3\x79\x3f\x2d\xc3\xc2\x50\x83\xe4\x16\x3d\x89\xd3\x6e\x7d\x16\x93\x2c\x62\x2e\xfe\xef\x62\x19\x06\x06\x69\xc1\xe3\xb4\xaa\x2f\xe7\x01\x65\x24\xae\x3d\x81\xdc\xfa\xbc\x59\xff\xc7\xe6\x9d\xa6\x09\xdf\xac\x10\x28\xe4\x7d\xf0\x7a\x95\x9f\x80\xda\x5f\x68\x63\x84\x41\x37\x22\xc6\x80\xf2\xf2\x00\x33\x11\xbb\xc7\xf1\x1f\xc7\x1d\x37\x7a\x62\x64\x84\xc8\x72\xa3\xf5\x74\x89\xdd\x6d\x74\xa0\x5a\x33\x46\xd2\xd7\xe2\xdd\x42\xf5\xc2\x8a\xb2\x10\xc8\xee\xed\x25\xc9\x62\x8a\xdb\x6c\x52\xd6\x1a\x73\x86\xf7\xf8\x57\xce\x43\x0f\xa4\x47\xdf\x73\xa3\xfd\xe3\x1d\x69\xe9\xbe\x14\x8d\x32\x2e\x42\xf5\x62\x71\x6c\x22\x5d\x4a\x46\x2a\x7d\x09\xeb\xf4\x93\x29\xe3\xc5\xaf\x1a\x3b\x85\xd9\xec\x23\x6b\xc8\x67\x51\xe6\x67\x51\x63\x9f\x9f\x6b\xeb\xd7\x70\x3b\xa8\x4b\x38\x0a\xd7\x52\xcd\x28\x66\x4c\xe4\x01\x78\xf0\xab\xc4\xb5\x14\xf2\x04\xf4\x7f\xee\x64\x15\xda\xb7\x27\xf2\x43\x6a\xd9\xc8\x7e\xfc\x05\xf3\x0c\xf3\x59\x0e\x79\xbe\xc2\xe9\xe9\x4e\x49\xb9\x9c\x91\xd7\xe5\x7e\x0c\xeb\x6a\x34\x7d\x9a\x07\x63\x41\x80\x37\x7f\x30\x60\x8e\x27\x40\x04\xdf\x79\xc2\x66\x97\xc4\x02\x1d\xaf\x1c\xc7\xe3\x89\xc8\x04\xac\x7a\xfa\xe4\xa7\x74\x67\x5a\x7e\xac\x20\xc1\x4e\x58\x06\x8a\x05\xfa\x8d\x11\x0f\x99\xfe\x94\x0a\x47\x43\x64\xf0\x2e\x5a\x8c\xfc\x23\xa6\x6b\x84\x50\xab\x3e\x08\x5e\xa9\xf6\x4d\xe5\xbe\xf7\x09\x39\x30\x6f\x88\x1a\xfe\x6e\xb6\x91\x52\xec\x2d\xb8\xc8\xfa\x0b\x50\xfe\xc3\x81\x58\x81\xcc\x5a\x4e\x2f\xf6\xd8\xd0\xf4\x2c\xec\x0f\x16\x3c\x0e\xd3\x34\x29\xf9\x0b\x8a\x35\x1a\x0e\x49\x82\x4b\x23\xb6\xf8\x38\x07\x04\xf6\x63\x1b\x54\xf6\xe8\xda\xd7\x6c\xbf\x96\xe9\x22\x1e\xcb\x67\x3d\xe3\xb5\x73\x62\xb0\x90\xfd\x53\xcf\x73\xf3\xf6\xc0\x42\xb9\xeb\x6e\x24\xc3\x61\x1e\xf4\x62\x5a\xd1\xf9\x2f\x31\xea\xaa\x4c\x7f\xc0\x0a\xc5\x3b\x8a\xcc\x63\x38\x8a\x45\x6b\x0b\x0a\xb8\x33\x68\x4b\x0f\x1d\xbb\x25\xc5\x36\x6e\x46\xab\xd4\x57\xfb\x96\x06\x52\xff\x74\xba\x31\xf2\xda\x65\xe2\x29\x0e\xd7\xd4\x13\x45\x25\xc1\xbb\x8d\xe1\xee\x32\xa5\x1c\xa5\x44\x03\x1b\x17\xca\xda\x2f\xa6\x7d\x29\x1d\x8f\xb2\xb6\x30\x24\xf5\x7c\x8d\xfd\x1d\x33\x51\xc2\x0b\x85\xb3\xf6\xf4\xd6\x33\x2e\xfe\x3c\x39\x56\x4d\x8f\xe5\x3f\xb9\xe1\x70\x4e\x18\x39\xa1\xcf\xff\xb8\x77\x9c\x19\xe7\x41\xe6\x35\xc9\x54\xd2\xed\xbb\x6b\xed\x84\x5d\x82\xed\x57\xf8\x1d\xe0\x3d\x4e\xa2\xae\x9f\x8f\xec\x93\x00\x9b\x61\x97\x46\x5c\xaf\x81\x54\x41\xc6\xc0\x71\xec\x13\xf6\x61\xf4\xee\x83\xf5\x0d\xd2\x40\x80\xe8\xfa\xe3\xec\x5d\x36\x0c\xcb\x7b\x66\x5f\x13\xac\x2c\x63\x95\x02\x7e\x15\xb9\xd7\xa8\x0d\xf6\x8a\x56\xbb\xa4\x56\xa4\x54\xe1\x3a\x60\xc3\x1e\x55\xe7\x0e\xb9\x98\x60\xa8\x14\x5c\xdd\xc0\x45\xce\xe4\xd7\x68\xb3\x4e\xd6\xb4\x07\xf1\xd6\xbd\x43\xc1\xcb\x5d\xbc\xb2\x2b\x43\x91\xd9\x5e\x6e\xfe\x59\x88\xc9\x9f\x5f\xd4\x90\x8a\x9c\xfd\x3b\x95\xc3\x44\x31\xbd\x92\x3c\xa6\xdd\x14\x74\xc5\xd1\x5d\x5e\xed\x59\x43\xc9\x0d\x1a\x6c\xfb\x84\x9e\xaf\xbf\xe6\xd8\xd6\xc7\x2d\xf0\xb1\xf6\x21\xf6\xea\xdb\xa6\x85\xc6\x8f\x63\x13\xf2\x9f\x14\x66\xf1\x19\xfc\xbd\xeb\x8c\xe0\xa5\x37\x6d\x9d\xa4\x13\xc4\x5a\x13\xb2\x79\xd7\x90\x2f\x09\xcd\x22\xce\x9f\xe9\x5f\xbc\xf6\x8b\xdc\xc2\x2d\x41\x85\x28\xb2\x60\xd3\xa7\x9e\x3a\xda\xca\xca\xf8\x7e\x31\x80\xb7\x2a\x80\xf1\xf0\xa5\xf8\x14\x8a\xe8\xb7\x3d\x16\xd3\x6d\x92\x5f\x95\x05\xc2\x71\x4e\x57\x6b\xf9\x7e\xaf\x46\x2d\xca\xb9\xa1\x52\xcb\x80\xb7\x66\x56\x25\x76\x9f\x90\xf5\x6f\x66\x35\x50\x5e\x92\xac\xa1\x7a\xe5\x81\x14\x79\xd9\xcc\xd7\x31\xdd\xe7\x76\x40\xce\x69\x59\x88\xce\xc3\x6f\x57\x1e\x5d\x0e\x04\x22\x39\xd4\xe6\xaa\xd6\x8c\x6f\xe4\x6e\x9d\x93\xb2\xcf\xc3\xac\x43\xd3\xf8\x9a\xb3\xc7\xfa\xcd\x79\xe5\x0c\xf6\xa1\x2c\x62\xdd\x64\x93\xee\xc3\xe0\x9c\xac\x4b\xc7\xde\xfd\x7c\x2e\xef\xe0\xca\x06\xb2\x6a\x04\x8f\xa4\x69\x73\x0b\x02\x89\x87\xbf\x46\xa4\x5d\x9e\x1d\x5e\x57\x2a\xd8\x5f\x7b\xae\xbb\x27\x1e\xef\xa4\x7b\x6f\x65\x5b\x5b\x26\x26\xd3\xf3\xa6\x22\x10\x37\xd5\x1e\x86\xfb\x85\x61\xe3\xc4\x59\xfc\x0f\x38\xf6\x39\x68\xac\x4e\xe7\xde\x4f\x21\x3f\xe9\xbd\xc3\xaa\x4f\x1d\x62\x93\x1a\x50\x74\xa5\x6b\x16\x44\xaa\xa8\xfd\xe4\xaf\x27\xae\x16\xc2\x3b\x78\x13\xd5\xdf\xf5\x22\xba\x00\x09\xe7\xa7\x1c\x83\x92\x15\x8a\x1c\xb8\x46\x83\xf0\x3a\x4f\x73\x0e\xcf\x7b\x46\xf5\x90\xc2\xf8\xc2\xdc\xf6\x6f\xa3\x08\xbb\x09\x4a\x4d\x99\x7a\xa8\x9b\x2c\x72\x00\x97\xc1\x91\x99\x12\x2c\x46\x90\x05\x5b\x26\x56\xc6\x22\xf5\x6e\x93\xac\x61\x68\xee\x61\x1e\x78\x03\x47\x79\x54\x7e\x5b\x30\x65\x80\x25\x2b\x8b\xe8\x37\x73\xd6\x6f\x57\x82\x54\x41\xb2\xe5\x5a\x52\x0d\xba\x6e\x2d\x99\xb5\x96\x2e\x5e\x1f\xcb\x45\x2d\xfc\xc5\x01\x8c\xf6\xb6\x20\x2b\x34\xa1\x1d\x1e\x7b\xdd\x1d\xaa\x57\xe5\x1c\x9a\x61\xd9\x6c\xfe\x83\xd6\x36\x1f\x01\x3b\x3d\x32\x5b\x6e\x13\x77\x91\x2a\x81\x7d\x2b\xbb\xef\xec\x59\xdc\x35\xed\x1b\x41\x7e\xb0\x3b\xdf\x7a\x03\xe8\x7b\x8f\x47\x22\x83\xa4\x0e\xac\x4e\x12\x66\x59\x4a\x75\xd0\x7d\xe9\xf0\xc7\x36\x66\x82\x94\xb2\xe0\x49\x9c\xd3\x85\xfe\xe1\xa7\x56\xd3\xe6\xe9\x7b\xd4\xd0\xb9\x5c\x7b\xaa\x06\x80\x5e\xa8\xfc\x8a\x31\xa5\xfd\xec\xd3\x39\x3f\x93\x51\xb4\x4b\x10\x5a\x18\x32\x30\x2a\xb8\x6f\xf8\xa4\xce\x4b\x83\x6a\x8b\xe5\x99\x08\xdf\x7a\x96\xe8\x98\xec\xa4\x05\xc3\x8c\x97\x84\xb4\x3a\xca\x27\xfb\x16\xef\x3f\x51\x16\x2b\x40\x2f\x9f\x28\x6f\xf1\x8d\xa6\x73\x63\x15\x18\x39\xad\xde\x4b\xc6\x7d\x98\x1f\xbf\x96\xcf\x19\x3e\xf1\x3e\xc4\x02\xfe\x92\xfb\xaf\x6d\x66\xb6\x73\xb7\x9e\xee\x49\x54\xef\x3e\xc5\xf0\x67\x54\x21\xb8\x1d\xb3\xce\x9b\x8f\x37\xe6\x21\xb8\x96\x48\x1b\x17\x4f\xab\x62\x25\x19\x02\x0c\x0b\x71\x4a\xb0\x12\x58\xab\x4c\xf6\x7f\xd7\x98\xec\xed\x47\x14\x17\xe2\x6e\x71\x4b\x65\x36\x98\xb8\x1a\x43\xf0\x4d\xd4\xac\xd9\x65\xb7\x1e\xf7\x22\x18\x64\xf9\x05\x30\xfe\x32\xfd\x1b\xf4\x42\xc0\x24\x64\x23\xc9\x9f\x69\xee\xf4\x40\xd6\x74\x98\x21\x24\xed\x23\x7c\x40\x81\x7e\xb0\xf9\x54\x59\x5d\x6a\x38\xaa\x8e\xed\xc3\xfd\x5a\xa2\xb1\xdf\xc5\x30\x1c\xb5\x0e\x21\xae\x7a\xdb\x30\xe5\xea\xdf\x8d\x71\x9b\x7d\xaf\x3d\xb0\x76\xcf\xd8\xf6\x30\x3f\xf3\xfb\xbe\xdd\x47\x5b\xfd\x6c\x87\xff\xe8\x0f\xe1\xac\xba\xe2\x1d\x70\x26\xd6\xf4\x5b\xe0\x01\xc5\x7a\x3a\x6b\xf4\xf1\xab\xf7\xf4\xf5\x75\x01\xba\x10\xea\x61\x15\x0d\xf3\x43\x8d\x5e\x33\xfd\xad\x60\xbb\xa7\xa2\x98\xe2\xb3\xb5\xd8\x7e\x04\x09\x5a\x01\x9e\x07\x2c\x9c\xb6\x30\xae\xf1\xfb\x3f\x9e\x5d\x51\x84\x2d\x1b\xf3\xa1\x04\x34\xec\x73\x33\x27\x6a\xa8\x37\x57\xf7\xc2\x99\x5a\x4d\xa3\xda\xc4\x8e\x8f\xc6\xba\x3c\xe6\x80\xbd\x44\xa1\x24\x61\xe5\x1c\x1d\x8a\x99\x7a\xed\x07\xf5\x3a\x0d\x3b\x1b\xec\x54\x28\x88\x3e\x64\x5f\xf4\x2b\x1d\x39\x79\x36\x13\x2e\xe7\x77\x4d\xe4\x81\x9c\xcc\xb8\xc3\x7f\xa6\x83\xce\x1f\x97\xc2\x9c\xfe\x86\xd9\x8e\x9d\x55\xa6\x3c\x54\xed\x90\x04\x3e\x36\xcd\x9c\x3f\x68\xd7\xf9\x4d\x49\x4b\x02\xcd\x31\xac\x0b\xda\x56\xb9\x12\x49\x52\x47\xb1\xc6\xb0\x29\x15\x4b\x5a\x1f\x5a\x6f\x93\x2c\x32\xbb\x0e\xd6\xfc\x66\xba\xbc\xdf\x70\x84\x40\xce\xfb\xad\x7b\x07\x14\x35\x3b\xaf\x93\x06\x0c\x3d\x7e\x4f\x65\xae\xc1\xbe\x9b\x69\x41\x48\x6c\x03\x3f\x7f\x70\x64\x06\xac\x35\xb8\x98\xeb\x42\x17\x1f\xe4\xc2\x89\x9c\xef\x43\xb8\x50\x3b\xb4\x9f\x94\x8f\x9c\xdc\x0d\x1d\xeb\x80\xb9\xbf\xf7\xf9\xf5\xab\xa5\xf4\x19\x96\x4c\x92\x4b\x09\xf4\x5f\x39\x3b\x8f\xc3\x1c\x67\xae\x51\x2f\xb7\x6a\x8d\x50\x11\xaf\x5a\xf9\x0c\xc9\x42\x87\xcd\xbb\x65\x12\xfb\xf8\xf8\x0c\x1d\x1e\xa7\xf0\x29\x2d\xd2\xda\xd7\x50\x76\xca\x46\xab\x20\xb2\xb4\x8d\x9f\xff\x78\xc7\xd0\x7e\xbb\x19\x70\xe3\xeb\x9f\x53\x94\x8f\x97\x6a\x5a\xd9\x42\x7e\x82\x6f\x3a\xef\xe9\xd9\x7c\xbb\x0a\xd4\xc7\x78\x8d\xad\xac\xec\x50\x16\x26\x3b\xb3\x4b\x20\x5c\x53\x26\x4c\xb0\x22\xe1\x4c\xbd\x53\x2c\xb5\xad\xa5\x46\x80\x87\x6a\x87\x87\x87\x9a\xca\x4d\xe8\xb7\x15\x94\xd5\x18\xb5\xc7\x30\x9d\x81\x45\x63\x2b\x94\x5b\xbb\x1b\x6a\x34\xdd\x4c\x33\xba\x8f\xb6\x3c\xcd\x69\xbb\xc5\x3d\x76\x08\x48\xdf\x66\xd0\xdd\x6e\xb7\x9e\x82\x5b\xe2\x13\x05\x7d\x1d\x3b\x64\xf3\x7e\xfa\x15\xe2\x32\x8c\x6a\xd2\x54\x8e\xc4\x79\x61\x12\x90\xe4\x9f\x62\xa1\xa1\x40\x98\x0e\x06\x7d\xec\x89\x42\x78\xaf\xeb\x6b\xbf\xd7\x1a\x20\x93\x5a\x55\x75\x4b\x39\xfc\x7e\x6b\x94\xff\x2b\x60\xd0\xea\x03\xba\xcf\xc4\xb8\x87\xab\xe3\x85\x58\x99\xec\x4f\xf3\x4d\x21\x6e\xb9\xad\x4f\x37\x9d\x88\x04\x7b\x5d\x37\x16\xe4\x9f\x86\xb3\x03\xc3\x8d\x05\x16\xc8\xa1\x1a\x2e\x88\xcf\x14\x6a\x03\x72\x15\xc5\x5e\x52\x15\xfc\x34\x46\x19\xf8\xdf\x13\x7d\xb9\x1e\x4f\x77\xbe\xea\x65\xb6\x1f\x59\x2a\x8d\x0a\x6f\x14\xcf\x99\xfa\x49\xde\x73\x30\xa7\x1d\xcc\x9e\x68\x12\x82\x4d\x43\xdc\x5a\xe7\x99\x70\x7d\x7e\x52\xa5\xed\x06\xfd\xd8\xb3\x8a\x5e\xe3\x9c\x4a\x8b\xcd\xb1\xb1\xa7\x78\x5c\xb8\x7d\x33\x79\x38\xd9\xf8\xd7\x71\x02\xfb\x99\x73\x73\x84\x26\x87\x2e\x1d\x5a\xeb\x8f\xc2\xd7\xdd\x54\xe4\xc6\xc0\x27\xd4\x13\x34\x60\x03\x86\xab\x1a\xf4\x0e\xc9\xb4\x21\xcd\xb9\x46\xfc\xf4\xbd\x31\x56\x84\x69\xa9\x5e\x22\xa9\x8b\xce\xd2\xa1\xf9\x07\x34\x18\x5f\x91\x12\xbc\x61\x1d\x1d\xcb\xe4\x08\xd8\xa2\xf0\x3b\xef\x7e\xa2\x41\x91\xdf\x83\x89\xb7\xfd\x9a\x32\x7b\x6e\xfb\xaa\xde\x2e\xb7\xb7\x6c\x2d\x56\x6e\x67\xa5\x94\xe2\x73\x6a\x76\xe7\xd2\xa1\xaf\x4c\x42\xf8\x8a\x42\xf0\x7b\x2c\xa9\xa8\x6f\xd8\xa5\x51\x87\x27\xf2\x27\xe1\x3e\x17\x09\x94\x92\x47\xb4\x8b\x10\xa5\xc5\x0e\xc5\xe6\xf3\xe9\x56\x55\x41\xac\xa7\x7c\xac\x7f\x97\x63\xf5\x66\xfc\x77\xc0\xb6\x32\x1d\x7a\xe1\x6f\x67\x0a\x94\x6d\x9b\x20\x96\x8d\x96\x26\x98\x0c\x51\x3f\x56\xd8\xb1\xf2\x2e\xe0\x15\x56\x06\x35\x4c\xba\xea\x6f\x08\x5d\x5f\xc5\x1b\xa7\xc7\xf2\xd8\xca\x93\x73\xc9\xe7\xb5\xfa\xa7\x4c\xa5\x04\x31\x63\xf3\x7d\x8d\x27\x1e\xfd\x9f\xde\x04\xc6\xc5\xf6\x97\xdf\x00\x5d\x98\xce\xca\x85\x7e\x63\x15\x77\xb3\xdd\xde\x15\x9b\x0e\x42\x0b\xeb\x47\xad\xdf\x73\xe7\xa1\x2d\xdf\xf3\xb9\xc0\x1c\x36\x2d\xb4\xaa\x2c\xb3\x4a\xa8\x26\xe8\xea\x9f\xd9\xcd\x74\x33\xb7\x05\x59\xde\x66\xcd\x99\xc0\x18\xe8\xed\x9e\xf2\x65\xc3\x38\xf0\xd0\x14\x3d\xc5\x51\x16\x01\xbb\x36\xd2\x47\x55\x42\x37\x3a\xf4\xef\x5a\x64\xad\xa8\x68\xd8\xc6\x67\x5e\x6d\x1e\xb3\x20\x1e\x8b\xe2\xcb\xbc\x53\x41\xda\x33\xae\xa9\x3e\x63\x6b\x77\x52\x84\x5c\x0e\x97\x0b\x77\xe0\xed\xa4\xde\x88\x7c\x8e\xff\x85\xde\x4c\xe7\xa8\x60\x6b\x53\xbb\xf7\x86\x31\xe4\x5e\x4a\xf8\x75\xcb\xb5\x7e\xad\xed\xca\x9d\x57\x47\x0b\x68\x36\xd0\x39\x30\x9b\xfe\x13\x37\xd4\x1f\xd9\x33\x42\x90\x24\xfd\xc4\xd6\xaa\x39\x9a\x18\x57\xd3\x58\x92\xad\x0d\xb1\x18\x4f\x5f\x23\xe9\x60\x49\xb7\x91\xfa\xf0\x88\x0f\x05\xed\x3b\x2c\x97\x65\x8c\xd7\x6f\x25\x46\xad\xca\xdf\x99\xc3\xe2\x8c\xd3\xbb\xa3\x87\xec\xc6\x34\xa5\x7c\xad\x9c\xc8\x2c\x03\x2d\xc1\xe7\xcd\x43\xcf\x06\xbc\xb7\xed\x4a\x4d\x24\x3e\x83\x12\x17\xcb\xec\xb2\xdb\xac\xc5\xf6\xa6\xf1\xed\x7b\xae\x23\x76\x0e\x28\xfc\xe5\xed\xc6\x73\x4c\xbf\xed\xae\x51\xb0\x96\x0b\x9c\xf7\x1c\x67\x47\x70\x1f\x65\x2c\xbf\x9d\xc0\xdb\x79\xef\x12\x1d\xb5\x4b\x47\x30\x60\xdd\xe3\x42\x99\xe0\xb6\xd1\xd5\x18\xfc\xe4\x77\x37\x6c\x7d\x20\x2a\xe2\xae\x41\xa7\x90\x20\x74\x8d\x6a\x2f\xc2\x73\x77\x60\x03\xdb\x2c\x09\xee\x9c\x19\x35\x71\xc7\x63\xb2\x68\x95\x6b\xc1\xac\xb7\x75\x2e\x0f\x24\x11\x36\x37\x53\x39\x39\xe6\x39\xd0\xa6\x5f\xad\xab\xb5\x3b\x21\xc7\xfc\x0e\xfe\x8f\xc0\xbc\x18\xfa\x96\xb1\x07\x76\x31\x59\x42\x8a\xbb\xde\x45\xc9\x49\x2b\xb0\xa7\x4a\x1c\x71\x60\xa4\x23\x22\x18\x5f\x04\x8b\x78\x59\x40\x95\x1e\xaf\xeb\x79\x29\x2b\x83\x70\xb6\x47\x66\x84\x21\x33\xb8\x54\xaf\xee\x7e\xa9\x2b\xb8\x63\x97\x4f\x3b\xb9\xe1\x39\x7a\xbf\xa5\xa5\xf0\x00\x33\x05\x89\x41\xac\xe7\x1d\x1c\x1b\xd7\x28\x03\xf9\xee\x08\x6f\xc2\x05\xd8\x70\x23\xfd\x1b\xe1\x9b\x86\xf2\x24\x2d\xcf\x4b\x65\xe2\x3b\x0d\xc1\x7b\x6a\x24\x05\x19\xbf\xa0\x9f\xfc\x93\x55\xc1\x5d\xa3\xac\x1b\xd2\xc5\x18\xdc\x09\xba\xb5\x17\x50\x80\xe7\xff\x48\x17\xac\xe5\x14\x1a\x6d\xd0\x28\x0b\xd6\x88\x35\xae\x27\xfb\x93\x1c\x77\x09\x79\x33\xa0\x08\xc9\xff\x80\x2d\xee\x90\x1b\x46\x3c\x80\x69\xb6\xa4\x98\x8e\x6e\xc2\x51\x0f\xf3\x7b\x3f\x6f\x32\xcd\xe2\xac\x22\xf8\xb7\x78\xbb\x0f\xfc\x44\x5f\x90\x60\xa5\xe6\x8f\xec\x13\x85\x73\x9a\xe2\x1d\xd3\xf7\xdb\xa1\x96\x9e\x64\xc8\xcf\xfb\xd3\x81\x88\x58\x97\x59\xaf\xb7\x2d\x65\x15\x07\xa3\x95\x20\x5e\x09\x5a\x72\xb8\x02\xfe\xb5\xfb\x37\x14\x42\xbe\x9f\x33\xd9\xee\xe3\xf3\x7c\x39\xb2\x04\x0d\x65\xb7\x07\xf1\x7a\x1e\xf8\x02\x98\x27\x66\x9b\x7d\x0c\xb4\x12\x52\x02\xf5\xd6\x0b\x6e\xa1\x1c\x6f\xa2\xd2\xdf\xe0\xaa\xfa\xe7\xf3\xd5\x47\x58\x5b\xc2\x34\xfe\x4a\xfb\x28\x17\x75\xca\xc5\x48\x7c\x53\x21\x9e\x6e\xac\xcc\x56\x05\x4f\x0a\xd6\xbe\x24\xb3\x34\x77\xd5\x48\xc7\xd7\x5f\x26\x2f\x0e\xf7\x9d\x8a\x12\xa0\xe8\x87\x4f\xa3\x36\x8c\xcf\x70\x81\x03\xe5\x6a\x07\xd5\xbc\xbb\xdc\xcc\x5e\xda\x34\x73\x75\xf2\x9b\xc7\x20\xe6\x76\x6a\x54\xe6\xf7\xd5\x16\xe2\xf4\xab\x6f\x93\x63\x34\x3b\x43\x69\x19\x99\x91\x15\xf3\x13\xd0\x62\xb7\xe4\xb1\xcf\x75\xf8\x2f\x1c\xe2\x4a\x58\xba\x98\x53\x48\xd8\xaf\xb7\x72\xcd\xf1\xa0\x75\xb8\x1e\xbc\x16\x10\x66\xf5\xec\xd6\xfd\x3e\x8e\x7b\xbf\xea\xf6\xe9\x01\x7d\x6d\xbf\x77\xeb\xb8\xdc\x96\x1e\xb5\x21\x7c\x71\x1d\x9d\xc9\x69\xb0\xb3\x3e\x9e\x77\xbd\x8e\x9f\x0f\xf3\x32\x07\xc4\xb1\xdf\xdd\xd1\x30\x5c\x08\x58\x2a\xf6\xdc\x87\x2d\x10\x2e\x8c\xf5\x49\x10\xce\xb9\x89\xa3\x13\xe7\xfe\xd2\x10\xd4\x0f\x1b\xc3\xa9\x46\x98\xf2\xf4\x97\xbe\x35\x43\xe3\x28\x17\x97\xfb\xad\x14\x55\x1c\x4c\xec\x2e\x2c\x6f\x29\x84\x2d\xe2\x34\x29\x3f\xb6\x5e\xf0\x76\x30\x99\x51\x3b\x92\x44\x70\xb4\xec\xa3\xeb\x8e\xe8\x4a\xd6\xa0\x19\x24\x92\x12\xdc\x15\xe7\xd4\xa8\xbe\x6b\x63\xc7\x15\xa4\xf8\x9e\x29\xf8\x13\xeb\x10\x74\x16\x1b\x40\xcc\x1d\x69\x3e\xc1\x1a\x81\xbc\xb8\x02\xca\x17\x10\x8a\x38\x51\x38\x21\x3c\x79\x5e\xf8\x75\x73\xd0\x58\x5a\xd5\x02\xdf\xa0\xe3\x73\xa9\xdb\x7d\x7f\x5e\xb3\x87\xd9\x32\xb3\x12\x74\xd1\xd5\x7b\xa2\x05\x75\xba\x51\xa7\xc6\x36\x69\x26\xd4\x5a\x40\xab\x29\x61\xf6\xc9\xf0\xf2\x2a\x15\x83\xf7\x22\xbc\x49\xf5\xb1\x7c\xb6\xbb\x92\x51\x46\x51\x98\x11\x64\xf0\xcd\x94\xb2\x2d\xfc\x26\xdf\xf4\xa1\xe8\xbb\x79\x08\x15\x01\x50\x49\x5a\xac\x96\x07\x8f\x3b\x7c\xa5\x4c\xb0\x72\x06\xa0\x27\x3b\xa9\x89\xdb\xf7\xea\x3a\x65\x69\x9c\xc3\xdd\xf5\x42\x04\x67\xac\xa8\x61\x78\x2d\xe9\x7e\xd4\x1a\xe4\x8a\x5d\x62\x2e\x38\x07\xd1\x84\x17\x78\x27\xa2\xb1\x39\x25\x40\xf3\x25\x07\x21\x0f\x11\xd0\x97\x95\xdb\x5d\xb0\x38\x32\xce\xcb\xfd\x56\x98\x98\x96\x28\xa4\x52\x8b\xba\x36\x5a\x53\x53\xd5\x5f\xb3\x70\xec\x80\x66\xaa\x6c\xbf\xd8\x74\xb4\x4c\xa1\x43\xc9\x35\xc3\xc6\x8f\x32\xbb\xb8\x67\xac\x98\xac\x34\x0c\xba\xf8\x9b\x34\x8c\x8c\x2f\x4c\xb2\xf3\x25\xfb\x89\x21\x04\xda\x5f\x2c\xaa\xd0\xa8\x99\xf5\x77\xf8\xcb\xea\x3e\xaa\xf8\x79\xee\xd0\xb3\xec\xa1\x05\x89\xd3\xe6\x7c\x9a\xd8\x54\x02\x3a\x48\x75\xb0\x1c\x83\xaf\xf2\xb4\x94\x12\x5b\xfa\xfb\xac\x8e\x4c\x45\xcb\x80\x5e\x5f\xa2\x3b\x4f\xe2\xff\xba\xf9\xfe\x75\xbf\x27\xff\xfa\x92\x14\x87\xcb\xeb\xec\x3a\xd5\x3b\x72\x9d\xe1\xae\xa4\xb6\x5f\xdf\xb6\x3e\x8d\xb9\x9d\x74\xfa\x6b\x81\x02\x99\x80\x97\x9f\xff\xe6\xf6\x78\x44\xae\xd2\x05\x32\x33\x0f\x8d\x6d\xa0\x64\x99\x4b\xd8\xb1\xf7\xc6\xb7\xe1\xa1\xcd\xb3\xa0\xce\xa1\x2b\x52\x0b\xbf\x0f\xd1\x84\xd1\xdf\xab\x7b\xc1\x3a\xca\x4d\x4e\x35\x6d\x6b\xac\x9c\xec\x4f\x4a\x0c\xa2\x05\xb8\xbf\x7d\x71\x9c\x43\xa9\xc8\xdb\x07\xd9\x4b\xbc\x19\x6d\x1c\x5f\xeb\xcc\x5d\xd9\xe1\xce\x20\xdc\x77\x7d\x05\x82\x7f\xec\xa6\xd4\x13\x22\xbc\xca\x3f\x26\xda\x0a\x83\x2f\x38\x93\x4b\xeb\xa3\xed\x3d\xf7\x72\x54\xc9\x1c\xa3\x2b\x8c\x89\x60\xef\xa5\xd7\x60\xbc\x3e\x42\x94\x31\xb6\xe8\xe8\x84\x59\xba\x30\x55\x82\x3b\x83\x30\x71\x41\xf5\x5e\xa9\xa4\xdd\x15\xff\x36\x08\x62\x4b\xac\x5f\x7e\xf5\xb7\x6a\x1f\x2c\xf9\xda\x1d\x96\x20\xd5\x7e\x65\x27\xd7\xe6\x3c\x55\xe6\x6a\xa6\xa7\x1a\x26\x16\x7c\x67\x7f\x21\x5e\x3b\xa4\x21\x15\x87\x20\xaa\xc0\xdb\x7d\x84\xf0\x5f\x96\x2a\xac\x15\xff\x59\x50\xc6\x1c\x9d\xd2\xa8\x82\x0e\xa7\x88\x4e\xc4\x15\x57\xa4\x63\x49\x56\x95\xab\xf3\xb8\xf6\xe6\xf3\xc6\xf3\xb6\xb9\x70\xea\xd4\xf3\x25\x1c\xbf\x00\xba\x9d\x70\x78\xeb\xca\xe1\xf5\x3a\xa7\x4b\x27\xb5\xcd\xe6\x76\x3b\xfa\x78\x65\x29\x91\x5f\xa3\x95\x3c\xa3\x6b\xe1\xa7\xea\x94\x79\x57\x56\x23\x2c\x11\x28\x01\xe9\x10\x8a\x24\x35\x4a\x81\x44\x7a\xe2\xe8\x8b\xd9\xad\xc5\x54\x94\x03\x9c\x2f\x3f\x7d\x9a\xf5\x49\x66\x32\x7d\xc7\xca\x55\x14\xda\x3d\xf7\x6d\x5f\xdb\x75\xb6\xff\xf9\xd6\x2b\x4b\xfe\xb2\x57\x77\x51\x17\x9b\x26\xab\x6c\x23\x31\xbb\x4f\xc8\x03\xdc\x85\x68\xd5\xc6\x51\x4b\xdc\xa3\x8b\x44\xdd\x4d\x45\xb9\x54\x94\xe2\xd2\x4a\x53\x87\xdc\x0a\x25\x79\xed\x59\xcf\xea\x2d\x2d\xbe\x57\xe9\xa7\x46\xa8\x1d\x53\x64\x6d\x83\x2f\xd3\xfc\xaa\x93\xdb\xe6\xc9\x0b\x23\x71\xcc\xc7\xbd\xc1\x02\x9b\xe8\x87\x7e\x52\x9c\x3f\xbd\xf3\x18\xdf\x18\xb4\xf4\xe2\xb6\x52\x31\x26\xb7\xc3\x59\x4f\x64\xa7\x01\x39\x6d\x0c\xf9\xe1\xc6\x73\xbf\xc9\x53\xef\xf8\xac\x85\xb5\xb4\xf2\xa6\x4f\x11\x8b\x6b\xc4\x68\x75\x7c\xf5\xf1\xfb\xa1\xcb\x24\x47\x8b\xcb\x7e\xaf\x31\x70\xb2\xce\x07\xe5\xb6\xa7\xe9\x64\x77\xf8\x1f\x84\xbd\xdd\xff\x3a\xe8\x80\x31\x69\xab\xf3\x2f\x61\xa8\x29\xb7\xa7\xe6\x32\x22\x1a\xe9\xd3\x75\x8e\xf2\xcc\x6e\xfd\x3b\x3a\x38\x55\xde\x8b\x9e\xdf\x33\xe8\xf9\x57\xa6\x81\x10\xb4\x17\x31\xe2\x73\x8b\xd9\xbe\xa3\xc0\xb0\xa8\x71\x56\x71\x12\x36\x0c\x96\x34\x60\xb1\xc0\xb6\xbf\x60\x8c\x7d\x7e\x6c\xec\x5e\x59\x32\x74\x71\x67\x42\x4f\x6c\x73\x24\x7c\x8e\x76\x11\x53\xfd\xd6\xd6\x5b\xa3\x3c\x8d\x01\x73\xfd\x5d\x7e\xa7\x3a\xbe\x64\x1e\x54\x77\x2c\x6f\x3d\xc2\xe1\x34\x9f\xca\xeb\x66\x39\x0d\xd6\x02\x89\x5d\x98\x12\xa0\x3c\xc1\x59\x82\x21\x03\x4d\x73\x50\xb6\xd9\x7d\xd1\xa0\x6b\x72\x9c\xd1\xbe\x9b\xc6\x19\x90\x1a\x59\xe1\xc4\xf0\xa4\x56\x86\xe4\xa4\xf2\x79\x34\x22\xe7\x4f\x6d\x37\xc2\xb3\x1a\xb2\x49\x82\x2c\x9d\x72\x8b\x2c\x39\xaa\x2c\x46\x07\x3e\x5e\x3a\x24\x29\x2d\x55\x90\xae\xa8\xdc\x2b\x5a\x08\x2b\x70\x76\xae\x72\x8f\x32\x20\x95\x0b\x68\x3a\xd8\xb5\x47\x15\x85\x66\xcc\xaa\x2d\x56\x1a\x97\xe5\x47\x1c\x53\x68\x8b\xbb\x54\xfb\xe4\x2a\x5c\xf3\x3f\xaa\x8f\xc8\xb9\x5b\xdd\x94\xd2\xe1\x86\xcf\xe0\xb2\x58\x7c\xfe\xc6\x2a\x77\x6b\xe7\xdc\xcb\x6f\x78\xc7\xd3\xd0\xac\xb5\x15\xbd\xb6\x0f\x09\xde\xde\x7d\xb9\xea\x0a\x47\x99\x23\x2c\x74\xe0\x78\xe4\x6f\x47\xb9\xd8\x31\x8f\x96\xd1\x35\x02\x7b\x47\xe0\x05\x17\x41\xf4\xd6\x9e\x87\xf9\x3b\x66\xb6\xda\x31\xd5\xff\x8e\xb1\x92\xe5\xf1\x93\x2e\x9b\x6e\x9b\x78\x13\xf2\x23\xd2\x87\x23\xdc\xf4\x2a\xd9\x3a\x1e\x9b\x67\xf4\x8f\x47\x47\xd7\x68\x2f\xc3\x99\x75\x0e\x42\xeb\x24\x3d\x3b\x0e\x18\xb5\x1c\xb9\x5d\xb8\x0f\x63\x81\x46\x86\xcb\xfa\xda\x86\x3a\xfd\x4e\xbd\xd9\x6b\xb9\x4e\x0d\x81\x52\x2a\x16\x3b\xad\x12\x87\xb0\xb5\xbe\xd7\x86\x1d\x8d\x86\xdd\x5a\x7d\xb9\xff\x4b\xad\x7e\x97\x78\xcc\xae\x2f\xf3\xe3\xae\xce\xbe\x47\x0a\xb8\xa6\x0e\xc6\x5f\x61\x4d\xa3\xe0\x86\x21\x5b\x7b\x37\x82\xea\xb6\xa5\x0c\x7b\x7b\x24\xc2\xe2\x36\xb5\xd3\xc5\xcd\xa8\xbc\xf7\x32\x57\x56\x32\xd7\xd6\xaf\x55\xa1\xfc\x6b\x8c\xf8\x6f\xee\x01\x72\xa9\x27\x2b\xbe\x55\x39\x32\x2b\x4d\xdc\xfc\x20\x3c\xc7\x2e\xd5\x56\xa9\x97\xd5\x3b\xf0\x31\xb2\x02\x38\xcd\xf7\xf4\x85\x85\xfe\x4d\x02\x85\x92\x6e\x09\x10\x81\x28\xfa\xf9\x63\x9c\xc7\x89\xcb\xe4\x85\x1d\x2b\x9a\x7a\xb6\xfd\xb6\x79\x56\xac\xd9\xe9\xf4\x70\x62\x51\x7d\xb3\xd7\x42\x0a\x99\x05\x1d\xfa\xc9\xe2\x72\x85\xa5\x9f\x8a\x54\x65\x73\xde\x33\xfd\x69\x18\x7a\x8d\x5e\x8f\x79\xbf\x16\xc5\x64\x82\x43\xfb\xa9\xa0\xaf\x63\x4b\xd4\x5b\x31\xd6\xc1\xb1\x56\xff\x8f\x7e\x85\x94\x63\x29\x8f\x3f\xf5\x9d\x01\x73\x49\x6b\x3d\xa5\xea\xc3\x8e\xaa\x62\xe2\xaa\x48\x37\x19\xce\xb8\xef\x53\x38\x38\x2a\x66\xbe\xa7\xb9\x71\xe3\x9d\x54\x61\x3d\x4a\xc6\x52\x45\x31\x7f\x59\xed\x0b\x9a\xea\x2e\x1c\x1a\xd9\xc9\xdb\x6d\xed\x68\xcb\x18\xc1\x8e\x8e\x68\x67\xc7\x68\x8d\x56\x02\x8b\xb7\x45\xc2\x91\xf4\xeb\xf2\x03\x54\x4c\x44\xf2\x9d\x4a\x88\x2a\x30\xf5\x6b\x90\xae\x39\x6c\x4d\xef\x1f\x35\xf8\x88\xb3\xc9\x3c\xe2\x97\x1e\x22\x9f\xdb\x73\x9b\x2d\xbc\xf2\x25\xf2\x3a\x77\x63\x9a\x26\x70\x8b\x0f\x4d\x67\x70\xea\xef\x26\x1b\x1c\x1d\x0a\x29\x42\xd1\xb5\xe8\x84\x38\x92\x50\xda\xcb\xc9\x66\x45\x17\xb1\xc1\x51\x0c\x25\x2c\x59\x65\x53\xbb\x05\xcf\xa1\xfc\x72\x1e\x20\xdd\x46\xdf\xc0\xc2\x07\x64\x1e\xd7\xe6\x3d\x31\x10\xfe\x3a\x46\xbe\x60\x20\x08\x47\xa4\x95\xa1\xfd\x93\x2a\x33\xd4\xf9\x43\x13\x33\x97\x6b\x58\x42\x99\x7a\xb4\x57\x40\xc4\x7c\xa0\xab\x34\x10\xa3\x41\x5f\x44\xa6\x52\x12\x97\x99\x03\x73\x75\x84\xe2\x1c\xaf\x16\x82\x3e\x92\x6c\xd8\xd8\xe6\x76\xcf\x26\x83\x73\x26\xda\x0e\x7a\xed\x53\x5b\xea\xab\xf5\x47\xd4\x31\x10\x60\xd4\xb6\x37\x7b\x4c\x40\x12\xef\xc2\x74\xa0\xf4\x60\x36\x24\x63\xa8\xeb\x0f\x97\xd2\x2f\x78\x44\x8a\x53\x0e\xcd\x81\x78\xbd\xda\x6f\x34\x90\xf8\x26\xf9\x4c\xb4\xf9\x96\xd7\x68\x50\x11\xc0\x58\x27\xe6\xf0\x43\xc0\x33\x59\xfb\x0b\x87\x62\xb5\x34\xf2\x79\x8d\xfa\xa1\x78\x26\x4a\xce\xae\xbd\x6f\xcb\xf9\xc4\xdc\x3a\xd4\x86\x86\x2e\x4c\xe0\x37\x16\xce\xde\xf5\xf1\xc9\xe3\x83\xcc\xac\xbb\x56\xe1\xaf\x40\xd5\x39\xbc\x6c\x8c\xe5\x37\x07\x54\x5c\xc6\x0a\x1f\x14\x79\x29\x43\x27\x96\xf0\x9f\x03\x57\x1e\xb5\xab\xc8\xec\xc9\xc6\xbe\x54\x9b\x09\x8c\x27\x85\xc1\xbf\x67\x33\xfb\x9f\xb3\x20\xe2\xfd\xfe\x11\xd8\xe4\x5b\xed\x8a\xe1\xe2\x66\xa1\x0f\xd3\x71\x59\xe8\xb4\x5c\x6d\xe5\x7b\xce\x30\xf5\x23\x3d\xa8\x27\xd8\x60\x4c\x7a\xd4\xad\x93\x57\x53\xc6\x57\xe2\x4f\x08\xf2\xc4\xe5\xa1\x6f\xd7\x9a\xda\x21\x11\x7a\xaa\x68\x0e\x98\xcd\xe1\xe4\x69\x55\x32\x9f\x99\x44\xdc\x58\xe7\xaa\xb2\xb7\xe8\x64\xd6\xfd\x31\x0e\x4c\xb4\x98\x1e\x73\x6c\xce\x48\x0a\x72\xae\x8f\xae\x1c\x23\xb6\xd0\xaa\xf4\x32\x9e\x48\xa1\xc8\x69\x35\x3b\x4f\x42\x21\x10\xf0\xea\xbf\x55\x21\x97\xe7\x96\xcf\x2f\xb1\xf5\xff\xb8\x9d\x2a\xd1\xbd\x5f\x35\x59\x91\xe5\xdf\x0b\x1d\x2b\x91\xd5\x6d\xb4\xfc\x59\x6d\x43\xdc\x26\xbf\x49\xcb\x3f\x69\xf7\x0b\xba\x27\x2d\x57\x28\x7d\x97\x01\xa1\x07\xf4\x05\x97\x5e\x15\xd0\x35\xe4\xd9\x15\xa7\x2f\xc4\x71\x5a\xf2\xfe\xb8\xb0\x00\x03\x9b\x21\x7a\x45\x3e\x78\x47\x70\xe2\x70\xe1\x87\x90\x80\xe7\xcc\x22\xf5\x36\xb9\xbe\xae\x4a\x74\x82\xde\x9b\xe4\x42\xa1\x18\x58\xaa\x75\x6b\xca\xd8\xfb\x6d\x7f\xf7\xb9\x84\x67\x94\x8f\x77\x7c\xe1\x87\xf6\xdc\x07\xb4\x5d\x5e\xf8\x7e\x31\xa4\xd3\x90\xd6\xaa\xc4\x1f\x45\xa5\x55\xdc\xba\x1a\x36\xb3\x26\xae\x4c\x21\xf3\x25\x68\x5f\x5e\x0d\x4c\x55\xd6\x08\x44\xc2\x6f\x06\xca\x8d\x66\x05\x62\x12\x53\xbc\x6c\xf6\xa8\x19\xd0\xc2\xe8\x58\x5d\xc8\x29\x8b\x12\xb8\xdf\xa4\xc3\x1e\xed\x57\x1b\x69\xf9\xef\x0b\x82\xb6\xef\x87\x83\xa1\x1c\x4e\x10\x0c\x7c\xe5\xdc\x75\x78\x7d\x49\x9e\x29\xd6\x42\xe3\xa7\x84\x9b\xed\xbb\x0e\xe7\x65\x1c\xf2\x54\x61\x19\x3b\x08\x77\x53\xb3\xa0\x3f\x8a\xfe\xb9\x17\x84\x70\x9c\xec\xe9\x91\x97\xfd\xf4\x60\x4f\xe9\xc7\xf0\xaa\x8d\x61\xd6\xfa\x27\x3e\x1b\x25\xcd\x13\x68\xe0\x6e\x79\x63\x74\xac\xa2\x8f\xec\x43\x99\x3d\xf9\xbc\x6f\xf1\x4a\x14\xdc\x74\xe7\x6e\x39\xaa\x41\x50\xbf\x9e\x79\x05\x8c\x88\xa0\xc1\xc6\x99\xaf\x9d\xf7\x1a\x06\x8a\xd7\xc7\x0a\x0f\xcb\x4b\xd6\x2e\x88\x9c\x23\x0e\x4a\x10\x8c\x8c\x20\xe8\x55\xc4\x23\xa7\xe5\xc5\xbb\x16\xc9\x91\xd6\x83\xdf\xb8\xe0\x9f\x74\x5c\x15\x52\x58\x91\x7e\x8e\xd9\x27\xda\xf6\xc2\xba\x9a\xc8\x56\xc9\x58\xfa\x01\x0c\xb7\x2f\x7b\x0f\xbf\x70\x22\xad\xbc\x2e\x1b\x51\xd4\x60\x3e\xf8\x90\x42\xd6\xf4\x6e\xfc\x17\xbb\x6f\x55\x19\xbe\x9c\xec\x74\x71\x2d\x2d\xf1\xab\x5a\x2d\x48\xe2\x84\xa4\x1e\x4b\xe3\x96\x1e\x8c\x2c\xcf\x17\x60\x4b\x4c\x38\x03\x4b\x94\x95\xde\xeb\x1c\xb5\xe4\xec\x48\xc6\x0d\x44\x58\x5e\xd3\xcc\x95\x13\xb9\xc2\x96\x62\x41\x05\xf6\xf5\x1e\x42\x2e\x34\x71\xb9\x35\x27\x5e\xbe\x10\x6f\x66\xdf\x0a\x3d\x9f\xf6\xfe\x68\xda\xb8\xa4\x9a\xc2\x77\xf2\x2b\x1b\x90\x7c\x41\xbd\xc1\xfa\xb0\x1e\x07\xa9\x8f\x60\x99\x0f\x6e\x81\x2f\x63\x43\x6b\x27\x6d\xdb\x0e\xa6\xaf\x38\xb8\x5a\x06\x9b\xba\x87\xec\x7a\xf8\xfc\xde\x62\x4c\x0f\x2a\xfa\xa9\x4e\xf0\xdd\x1d\xb7\x6d\x2e\x32\x5f\x7a\x75\x1e\x41\x5f\x85\xfd\x7c\xf6\x97\xa7\x56\x84\x79\xc2\x5e\x71\x5e\x35\x26\xbb\x99\x38\x1f\x27\x33\xf9\x68\xb2\x1a\x2b\x5e\xff\x19\x2a\xeb\x1f\x71\x7b\xfd\x25\x55\x21\x99\xd0\x5b\x9b\xf8\x6c\x5e\x8b\x75\x26\x04\x31\x1c\x34\xc8\xae\xc7\x64\x05\xb7\xf6\x84\x14\x89\x69\x6f\x0b\xd3\xc7\xca\xb1\xd4\x1c\x8e\xae\x99\x70\x38\x15\x4c\x7c\x1e\x2d\x7f\xeb\xe7\x92\x7d\x8d\xf7\xe7\xfb\x2f\x9e\x65\x18\x4b\x3a\x68\x86\x6d\x28\x69\x2b\xe7\x11\x79\xc1\x96\x35\x38\x58\x55\xd1\x20\xd2\x76\x4b\xe8\x87\x3c\x15\x85\xef\x05\xd8\xfc\x64\x8a\x25\x1b\x03\x3e\xe0\x5b\x93\xd5\xd6\xe7\x70\xaa\xb5\xd6\x8a\x17\xab\x58\xa3\xe5\xb0\xc7\x16\xee\x30\xda\xf7\xa6\x9f\x2d\x10\xea\x79\x65\x5b\x6f\x99\xb5\xdd\x54\x11\x17\xaa\xbc\x1f\x6f\xb5\x5a\xb7\x46\xb6\xea\xae\x6d\x6b\xb4\x84\xbf\x5b\x6e\x08\xf3\x1d\xd0\xfc\xc3\xac\x8e\x8f\x86\x26\x5a\xcd\x12\xd7\x06\x24\x73\xfe\xa9\x47\xb5\x4d\x17\x18\x66\xe9\x27\x6c\x35\x70\x57\xab\x58\x9d\x97\x22\xba\x37\x8d\x26\x04\x89\xd2\xeb\x91\x1e\xa2\x05\x71\x67\x12\x10\x81\x37\x6b\x13\x04\x47\x2c\xed\x07\x92\x07\x6c\x58\x67\x35\x76\xd3\x1a\x81\x11\xd4\xb9\xf7\x5b\x27\x1c\x7d\x85\x60\xf8\xfb\xad\x15\x91\xfd\x4d\x4b\xf6\x39\xfe\xba\x71\x79\x09\x46\x78\x0a\x30\x7b\x32\xb8\x73\x63\x08\x71\x3b\xe0\x2d\x3f\xe7\xae\xe6\x61\x88\xdd\x31\x94\xbd\xf7\xd4\x4e\x6f\xe0\x13\xc2\x5d\x36\xcc\x68\x20\x54\x46\x2b\x56\xcf\xa8\x42\xc3\xcd\xa4\xe0\x1c\xa3\x19\x0e\x8c\xbe\xe1\xd2\xe7\xff\xaa\xfb\xa7\x62\x8b\xa7\x2c\x5b\x22\x61\xbb\x99\xab\xf8\x27\x02\x92\x02\x69\x9f\x96\x03\x6f\x3a\xec\x73\xa3\x93\x3a\x17\xf8\x11\x8f\x63\xa5\xca\x27\xa9\x8e\x7d\xc3\xac\xb7\x95\x12\x68\x08\x51\xc6\x1d\x9c\xdd\xe1\x6e\x7d\x8d\xef\x36\xe4\xc6\x51\x9d\xc5\x2e\x5b\x41\x53\x75\xba\x8c\x0c\x21\x63\xa1\xef\xbd\xd9\xab\xf9\x78\x81\x34\x82\x54\xbe\xdd\x83\x39\x4b\x84\xcd\xe9\xc8\x82\x33\x90\x9e\x7b\xcf\x63\xdc\x97\x3c\x1c\x4c\x57\xec\x8d\x9e\xbe\xb5\x9e\x4f\xed\x94\xa2\xda\x74\x39\x97\x29\x2d\xd3\xb0\xb4\x06\xe6\x5b\x82\x19\x01\x67\xe5\xff\x22\x7b\xe7\x83\xb4\xaa\xe5\xf5\xbd\x37\xbb\x90\x16\xae\xcc\x3b\x56\xea\x9b\xbf\x81\x72\x6d\x2b\xf6\x81\x4a\xea\xef\x00\xbb\x8d\x7d\x4b\x54\x0f\xcc\xcf\x21\x77\xc3\x14\x45\x09\x74\xe1\xe6\x28\xee\xf9\x5e\x24\xef\xd3\xa2\x4f\x42\x70\x2d\xff\xd7\x79\x19\xab\xd6\x6a\xa0\xf5\xc3\x56\x7f\xa0\x39\xce\x11\x6a\xde\x91\xaa\x4e\x35\xf4\x3c\xd2\x92\xf6\x90\xb5\xb2\x74\x5e\x56\xba\xa9\xcf\xdc\xdc\x25\x24\x6a\xc6\x6e\x94\xb1\x46\x96\x7a\x98\x5b\x21\x23\xf9\xda\x8e\xbd\xf9\x84\x23\x5f\xd1\x46\x5d\xd8\x88\xe2\xaa\x56\x62\x2e\x94\x28\xb1\xa5\x6e\x41\x13\xc0\xb4\xfe\x27\x82\xcf\xdb\x3c\x2c\x4b\x3f\xe9\xa8\x85\x2d\x61\xde\x5a\x75\x99\xe0\x78\x8b\xad\x12\x2f\xf0\xd9\x48\xa5\x32\x43\x29\xae\x3a\x79\xbe\x55\xa5\xe3\xe7\xd7\x72\x85\x64\x15\x7a\x91\xdd\x6a\xbd\x34\x28\x25\x93\x7a\xd5\x23\x61\xf9\x4d\x5d\x9d\x8d\x55\xf5\xf1\x64\x2b\x92\x19\x0f\xd1\xfa\x9c\xa9\xb2\xa6\x37\x7e\xf3\x4c\xb8\x33\x41\x54\xdc\xa5\xac\x81\xec\xf0\xb6\x1d\x55\x80\x00\xf3\xe9\x6f\xfb\xbc\x5f\x71\xe7\xb1\x02\x7c\x23\x29\x59\x8a\xca\x6f\xd3\x5a\x62\x47\x9b\xa0\xd1\x3a\x7d\x2d\x23\x5c\xaa\x3c\xcc\xa3\x7b\x5c\x45\xa8\x02\xff\x03\x98\x5c\x08\x54\x1a\xd1\x39\x9a\xaf\x39\xef\x1c\x4c\x00\x8e\xaa\x3f\x1f\xc2\xc2\xe7\xa1\xe0\x3a\x4f\xac\x51\x03\x4b\xf2\xd1\xe5\xb3\x7c\xe6\x41\x2c\x67\xae\xae\x9d\x1c\x11\xd5\xf8\xfb\x32\x8f\x48\x8d\x09\xdf\xd0\xab\xa1\x84\xc1\xa4\xcd\x37\x95\x30\x5e\xef\x05\xb1\x82\x52\x6d\xb4\x05\xea\xdf\x12\x3e\xe6\xec\xbf\xd4\x8d\xe8\x49\x27\xad\xab\x62\xfd\xe7\x2e\x00\x15\x31\xcd\x64\x25\xa8\xfe\xe2\xb6\xdc\xda\xfc\xc4\x11\x73\x02\x67\x29\xb4\x80\xc6\x48\xb8\x3b\x49\xb2\x5e\x35\x54\x3a\xa8\x56\x56\xcc\x23\xa9\xca\x2f\x45\xf6\x78\xb7\xbb\x5d\x59\xee\x98\xac\x2b\x7e\xe4\xba\xe6\x06\xe4\xb8\xe0\xb9\x28\x59\x9b\xc2\xa7\xae\xd1\xc4\x2f\xfa\x6b\xb1\x62\x14\xf3\xd6\x6f\xe6\x26\xf5\xdd\xd7\xef\x93\xd5\xff\xfc\xde\x5a\x5c\x83\xb7\x4b\xba\x72\xfa\x7c\xe6\x53\x82\xb2\x05\xe9\x98\x4e\x6f\xb2\xfa\x77\x4f\xd2\xca\xf7\x19\xa7\xfa\x4b\xd9\x2f\xfe\x3f\x00\x92\x20\x6d\xdf\xc4\xc8\x7e\x76\x68\x1b\xa6\xa8\xc8\x32\x7a\x87\x0f\x6c\xe0\xa5\xf0\x66\x0b\x31\x53\x60\x6d\xbd\x72\xe6\xba\x46\x1c\x61\x5d\xae\xbf\xb9\xae\x8e\xab\x41\x75\x95\xb1\x9a\xd6\x69\xa6\xa2\x32\x96\x23\x67\x9b\xbe\xb4\xb9\x9e\xa3\x60\x3d\x01\x32\xfe\x48\x1d\xd5\xc1\x23\x2d\x26\x74\x38\x24\x99\xba\x29\x13\x51\xe7\x9a\x6a\xa9\x6d\x71\x86\x4a\x32\x66\x01\x2c\x03\x39\xcc\xa5\xf0\xea\x23\x62\x0b\x45\xb1\xbb\x4d\x14\x1f\x76\xa9\x38\x37\x24\x8b\x0d\x99\x51\xf0\x4f\xb5\x2c\x05\x47\x89\x98\x32\xba\xad\x4f\x3d\x63\xf9\x3c\x3b\x91\xb9\xfa\x95\x2c\x53\xd1\xb6\xf4\x41\x46\xca\x82\x08\x07\x9f\x07\x67\xf7\x19\xd8\x67\x89\xd8\xd0\xd3\xb5\xa0\xdf\x26\xb3\xac\x1c\x6c\xaa\x9d\xd5\x6b\xd8\xb0\xf8\x26\xae\x39\x50\x48\xa2\x70\x90\x04\x86\x33\x91\x59\x45\xe0\xad\xf7\x61\x44\xd4\x97\x96\x32\xf2\xf9\xf3\x6b\xa3\x17\x59\x20\xd7\xc3\xaf\x6b\xbb\xba\x36\x31\xaf\xad\x92\x38\x2b\x09\x6c\xbb\x36\x6d\x8b\xa8\xe0\xb5\xaf\xe7\x24\xf1\x15\x96\x7a\x32\x62\x48\x5f\x1e\xd6\xbe\x03\x7e\xdd\x06\x34\x61\x03\x8d\xd1\xdd\xa8\xd8\x71\x08\x46\x49\xaa\x9d\x95\xa4\xb2\x86\x7e\x97\x1d\x78\x5f\x94\x05\x1b\x4a\x05\x58\x78\xda\xf8\x80\x1b\x0c\x34\x37\xd6\x0e\xb7\x30\xb6\xf4\xcf\x9d\xe6\x3d\xc4\x83\x0f\xc2\x3d\xee\x87\xbd\x15\x99\x96\x1d\x6a\xcc\x3f\xb3\x70\x28\x54\x5b\x42\xa3\x56\x4c\x47\xb2\xf6\x5a\x89\x29\x9d\x66\xd1\x2a\xa1\x4e\x55\x98\x4e\x15\x41\x91\xda\xd8\x09\x50\xb7\x46\x17\xb8\x88\xaa\x11\xee\x8d\xaf\xe3\xa9\xa3\x90\x96\x46\x00\x36\xd8\x94\x3f\x9f\xc2\x1b\xe3\x11\xc3\x5f\x21\xd0\xd5\x41\x90\xf5\x18\x33\x98\x61\xd4\x57\x7a\xcc\xee\xa4\x30\x50\x15\x05\x45\x06\xbe\x75\x2e\xac\xc2\x82\x93\x25\x58\x00\xc1\xc5\x02\x97\x1e\x36\x6a\x34\xe9\x71\xb1\x2c\x29\x36\x3f\xb8\x58\x8a\xd4\x85\x4e\xa5\x87\xf9\xd4\x66\x31\x26\x31\x4a\xb9\xf8\xa8\x83\x6e\x54\xa1\xe9\x61\x07\xe8\xab\x14\x6e\x68\x9b\x78\xa0\xbb\x68\x29\x1f\x7a\xf0\xcb\x2f\xc2\x65\x0f\x09\x2b\xd2\x93\x0f\x84\xcb\xf4\x49\x6c\xf8\x81\xbe\xfa\x21\x83\x5f\x2d\x51\xb0\xcf\x9c\x00\xc5\xdd\x9d\xba\x91\xd5\x9c\x98\xe6\x03\xab\x2c\xcf\x97\x03\x98\xc9\x32\xac\xb2\x74\x7b\xb2\x5a\x88\xe3\x53\xcd\x70\x71\x2c\x55\xc8\x8f\xda\xfa\x96\x9b\x43\x88\x52\x63\x14\x2e\xb0\xbb\x99\x35\x47\x23\xad\x90\x05\x93\x81\x46\x31\x06\x90\x95\xd3\x88\xf9\x72\x4d\xb4\x35\x66\xb6\x36\xab\x39\x8a\x5a\xd8\xa8\xe6\xb1\x5a\xc8\x2c\x1f\xd3\xe7\xed\xdb\x9d\xc5\x2e\x2c\xb6\x76\x2d\xd0\x63\x3b\x58\x6b\xed\x5b\xa2\xdb\x99\x6b\x68\xaf\xb2\xfe\x68\xe0\x05\x37\xf1\x91\x22\x72\x8c\xb1\x9b\x21\x73\x37\xf3\xc1\x96\xf1\xc5\xcc\xe1\x08\x6d\xcd\x28\x6c\x8f\x70\x0e\x82\x1f\x97\xce\x8c\xae\x1c\x25\x25\x79\x9d\x3e\x85\x13\x73\xfb\x86\x69\xd6\xdf\x24\x1e\xbe\x6b\xfa\x77\xc6\xae\x9f\x1d\xae\x75\xda\xf2\x06\x3a\x32\xfd\xda\xf7\x4f\x9b\x30\x34\x30\x7a\x2c\xc2\x7a\xb6\x2e\xba\xbc\xa3\x5d\x55\xfc\x16\x1b\xb1\xab\x94\xe4\xcc\xcb\x67\x99\x12\x9b\xa2\x15\x14\x1e\xb1\xe3\x9b\x89\x81\xc3\xb4\x7d\xdf\xc3\xa5\xc3\x91\xba\xbf\x85\xd7\x4c\x3d\x62\xc2\x70\x1c\xc0\x10\x22\xa5\x64\xac\x01\x43\xae\x09\x43\xd4\xc9\x63\x31\x00\x43\x18\x39\x88\xd7\x86\x23\x0c\x18\x6c\x09\xa7\x37\x21\x5f\x79\x48\xf2\x2a\x01\x67\x88\x01\xc3\x0d\xa6\xce\xbb\x91\x16\x34\x87\xdf\x91\x1f\x4d\x19\xa4\x1d\x76\x53\x24\x2e\x9d\x0e\xd8\xba\xde\x97\xf5\x00\x53\x94\xc4\xc8\x7a\x03\xa6\x32\x13\xa6\x1e\x40\x5b\x91\x18\x86\xdf\x9a\x0b\x02\x11\x9b\x31\x92\xb7\xc6\x9c\x33\xdb\xec\x29\x26\xc0\x4b\x46\x8a\xb4\xd8\xab\x55\x72\x88\x9b\xb3\x6d\x95\x70\x3e\xcc\xcf\x87\x63\x86\x15\xcd\x2a\x53\xc2\x51\xc5\xf7\x90\xa4\x38\x23\xac\xdc\x15\x2c\x2d\x09\x58\x28\xca\x26\xcc\x7a\x1a\x3b\xa1\xa1\x0b\x56\x3a\x02\x46\xbe\xee\xc0\x5c\x73\x0e\x8b\x98\xde\x99\xae\x91\x9e\x89\x1d\x29\x83\xef\xb0\x92\xba\x04\x67\x53\x39\xd3\x6d\x54\xac\xa5\x1b\xb0\xe3\x89\xa9\x45\x09\x2d\x0b\x24\x79\x34\x6e\xba\x0f\x3e\xc4\x8c\x8f\x20\xba\x14\xb3\xa5\x8a\xa1\xa5\xc4\x96\x0d\x27\x8b\xe0\x64\x51\x4c\x2b\x51\xb8\xf7\x50\x04\x1e\x6e\xb3\xe4\x0c\xe6\x75\xc9\x95\x28\xef\xdb\x01\x8c\x4a\xba\x13\xd0\x1f\x53\xc7\x0b\x26\x9c\x54\xa3\x8e\x2e\x61\x75\x83\xa7\x74\x30\x83\xb4\xff\x64\xba\x82\x92\x81\xe4\x55\xf1\x77\xe9\x72\x90\xb7\xc4\x6f\xa7\x0d\x76\x0c\xed\x59\xed\x60\xb8\xd6\xeb\xbb\xef\xa3\x31\x5a\x73\x9f\xbe\x9b\xd6\xdf\xa7\xbf\xa6\xff\x87\x9e\x44\xfb\xd2\xbe\x77\xe8\x2f\xd2\x5e\x77\xe8\xcf\xe9\xcf\xdd\x81\xdf\xe1\x74\xb4\xcd\x12\xb1\x7c\x47\x72\x48\x19\xa9\x25\xf3\x8d\xc9\x04\xdd\x4c\x4c\x15\x23\x6f\xc4\xd3\xbd\xfc\xb9\x2c\x83\x8a\xac\xae\x25\x70\x32\x01\xe1\x53\x06\x7b\x80\x78\x0a\x28\x85\xe5\xcc\x71\xe2\x95\x83\xdd\x70\x3e\x41\x20\x0c\x6c\x53\x0c\x6c\x5f\xcb\x3c\x29\xcd\xea\x68\xcc\x18\x3f\xc8\x2d\x6e\x7c\x83\xc5\x48\x25\x0d\xac\x74\xa4\x90\x52\x5e\xa8\xe7\x37\xfa\x56\xea\xca\x63\x5c\x1c\xcc\xd7\x46\x4c\xbc\x62\xfd\xd8\xc9\x88\xba\xb1\x9b\xfa\x8d\xbb\x62\xed\xa2\x55\xb4\xa4\xb0\x40\xa6\x6f\x76\x5f\x39\xe4\x9a\x3b\xae\x8f\x4e\x88\x5d\x7b\x8f\xc7\x29\x9b\x38\xac\xaf\xd9\xf8\xd1\xc4\x8f\xcf\xe5\x68\x2c\x2a\xbc\xf8\xa5\x89\xad\xd7\x8f\x58\xd7\x83\x8a\x25\xd5\xf1\x77\xb7\xb7\x6e\x09\x85\x11\xa3\xd5\x93\x0a\xd1\x67\x61\x7d\xea\x40\x33\x0a\xc8\x88\xe1\x9d\x3b\xd5\xd5\x10\x08\xea\x70\x57\x75\xc9\xd9\x66\x62\x08\xc5\x81\x6a\x57\x9a\xb3\x02\xc1\x90\x49\x11\x1d\x3b\xd7\x99\xac\xee\xd4\xbe\xfe\x31\x93\xce\x5d\x34\xb1\xcb\x15\x69\xdb\xfc\x48\xeb\xf3\x1d\x6e\x7d\x58\x37\xdd\x9c\xe5\xf3\x33\xc9\xe5\x52\xb4\x40\xb0\xb1\xeb\xf5\x31\xf3\xbc\x73\x7b\x7d\x8a\xcb\xdc\x2e\x56\x68\x29\x31\xc5\x6c\x7a\x8d\x47\xc1\x1a\x31\xcb\xd9\x45\xb7\x7f\xa4\xab\x05\xe6\x75\x40\x60\x0a\x10\x98\x9d\xcb\x07\x29\x6a\xa1\xf0\x21\x56\x9a\x96\xb3\x9d\x56\xfb\x9e\x29\x59\xbb\x5a\xee\x60\xc3\x80\x67\x32\x94\xaf\x17\xa5\x44\x10\xe8\x7f\x4e\x97\x58\x55\x43\x09\xcd\x6f\x45\xbb\xca\x28\x4a\xc5\xe5\x37\xfb\x44\x14\x12\x41\x25\x13\x90\xe6\x1c\x97\x1d\x4e\x86\x14\x96\xd8\xcd\x01\x21\x81\x29\x8b\x50\x10\x20\xcb\x92\x0f\x09\x05\x37\xdc\x3b\x01\xb1\x8b\x59\xef\x5d\x41\x30\x2a\x6d\xc7\xf3\x5e\x79\xa0\x09\x3b\xf1\xe0\xb4\x9d\xcc\x6e\x79\xd5\x11\xc3\x21\xd1\x66\xc3\xbc\xd7\x68\x98\x4f\x89\x82\xc3\xc9\x23\x9e\x5d\x34\xcd\x33\xd5\xdb\xbe\x73\xde\x66\xba\x67\x6d\x0d\xf4\x92\x9d\x6f\xb9\x40\xce\x07\x61\xbb\x95\xcd\xfa\x09\x9a\x73\xd9\x78\xb0\xc6\xc9\x43\xb1\x4e\x30\x57\xc5\x20\x1f\xf9\x23\xb6\x98\x49\x4f\xdc\x73\xc1\x1d\x8f\x63\x4d\x80\x62\x8c\xa4\x61\xa5\xe1\xac\xd7\x26\x3d\xff\x07\x67\x7f\x48\x99\x55\x12\xe7\xd3\xd2\xbd\x3a\xcd\xd3\x3f\xd7\xf7\xee\x3d\x03\xfe\xdb\x6b\x51\xf5\x9f\xfe\xd8\xb9\xeb\x0f\xfd\x23\x41\x58\x37\x6b\xd6\x7a\x26\x13\x37\x1c\xdc\x27\xed\x96\xcb\x48\x05\xce\xa7\x62\x2b\xf2\x1a\xa3\x56\xb0\x96\x4e\x12\xd3\xd3\x2c\x2b\x80\x0a\x2b\xd8\x1c\x7a\x23\x6a\xa4\x3a\xd0\xe5\xca\x87\xe3\xfc\x18\x36\xd3\x34\xe7\x5a\x8b\x60\x3f\xdd\xc6\x9c\xcb\xfc\x0a\x94\xf6\x01\x3f\x2b\xcc\x74\x28\x9a\x37\xcc\xc6\xb0\x10\x16\xe5\x54\x4b\x94\xa4\xd5\x1d\x30\x66\xfa\x60\xb9\x1c\x06\x84\x82\x01\xc2\xc3\x42\x46\x61\x7b\x7d\x1d\xa9\xaf\x33\x93\x05\xca\x06\x2a\x7c\x94\xfa\x6e\x09\xed\xf1\xe5\xbb\xe3\xb7\x56\x34\x54\xac\x1e\x34\xea\x58\xfd\xcd\x65\x53\xfb\x8c\x9a\x25\x8d\xfe\xf4\xb7\xa7\xd4\xa5\xcf\x0e\xe9\xad\x7f\x71\xd9\x93\x4f\x14\xe4\x7e\x14\x8a\x8e\x1a\x34\x9c\xba\x37\x4e\xdd\x39\x72\xc8\xd4\x0d\xa7\xec\x7f\x04\xe9\x97\xf5\xb0\x5b\xde\x03\xbb\xac\x8c\xd4\x90\xd3\x78\x0e\x8a\x0f\xe5\xea\x66\x6f\x49\x7a\xd3\x5d\xec\x3d\x0b\xbc\x66\x17\x7b\x2d\x03\xbe\x1c\xa0\x2c\xe7\xb2\x1c\x0b\xa3\xb0\x92\x50\x8b\xc3\x9b\x72\x00\xa7\xd9\xe5\x89\xb2\xca\xd2\x1e\xca\x43\x4e\x6f\x41\x49\x29\x7b\x1c\x81\x51\x1b\x25\x62\x6d\x54\x20\x62\x74\xb2\x77\x51\x11\x55\x56\x51\xde\xb9\x8d\x3d\xc3\x44\xed\xd8\xcb\x6e\x3d\xd0\xa1\x97\xfd\x5c\x26\x0c\x97\x75\xd1\xd0\x7e\xf1\x0b\xed\xba\xd9\x2d\x7d\xd0\x60\x5d\x92\xee\x69\xcf\xc4\x07\xf8\x37\x38\xd3\xa5\x0d\x1f\xa5\xed\xf0\xd1\xad\x23\x3e\xa2\x80\x8f\x8c\x42\xb1\x34\x3e\x32\xab\xc4\x10\x19\x3d\xaa\x6b\x38\x32\x92\xd9\x3d\x63\x2c\x74\xf6\xff\x0e\x21\x19\x7d\xfd\x8c\xe9\x0e\x87\x90\xb6\xe6\xfe\xb8\x21\x86\x0f\x89\x12\xa3\xc1\x5f\x9c\xd8\x66\xfb\x32\x9c\xc8\x04\x70\xd2\x8d\xd4\x91\xb3\x33\x71\x52\xdd\x0e\x27\xf1\x36\x9c\xd4\x33\x9c\x74\xc7\x51\xb7\x5e\x36\xdc\x20\x8d\x93\x5e\xf0\xa6\x7b\x26\x8d\xd4\x28\x0f\x33\x1a\xa9\xe8\x66\xe2\xa5\xac\xfc\xff\x80\x97\x0e\xd6\xf3\x11\x89\xe5\x0c\x53\xd6\xf7\x3d\x32\xbd\x48\xd3\x0d\x5b\x7a\x68\x9a\x64\xd2\xf8\xa9\x02\xfc\xd4\x91\x01\xe4\xc9\x4c\xfc\xf4\x06\xfc\x54\xa0\x11\xd4\x13\xac\xe8\xda\x8a\x9e\x20\x0c\x4a\x3d\x99\x28\xeb\xd7\x86\xb2\x81\x0c\x65\xf5\x20\x35\xea\xea\x33\x2c\xeb\x68\x2c\x55\xc7\x8f\xea\xbd\xec\x61\x0d\x26\x26\x9b\xbb\x07\xfa\xc2\xd7\xaa\xb8\x79\x3d\x08\x3e\xe9\x5b\x07\xe6\x35\xe0\xb2\xb4\xa2\x16\xd3\xb7\x88\xe5\xa4\x27\xbb\x27\x43\x66\xbf\x6c\xcc\xb0\x21\x36\xdb\xd5\x22\x6a\x3d\xbd\x20\x7d\xea\x90\x38\xc1\x10\xff\x3b\xe8\xed\x2a\x25\xf1\xf7\x30\xbd\xba\x83\x75\x1e\xfc\x1b\x08\xdf\x94\x61\xa3\x1f\xe8\x6b\x62\x5d\x32\xf8\x74\x37\xe0\xbc\x14\x7c\x97\x04\xb9\x35\x13\xeb\x95\xed\xa8\xb2\xda\x44\x31\x3a\x99\x35\x09\xad\x18\x54\x71\x2d\xa8\xe2\xba\x98\x1a\xdd\xa3\x95\x2a\x18\x20\x56\xcb\x50\x70\x1b\xf9\x8c\x32\x3e\x9f\xa3\x2a\x03\xd7\x6a\x0d\x7e\x9e\x00\x85\x5c\x8f\x41\x65\xec\xe3\x2d\x70\x36\x22\xed\x26\xbd\x36\xf6\x90\x8c\x04\x17\x6e\xd5\x5d\xa3\xf9\x6f\xd1\xad\x69\xed\x33\x44\xa2\xa9\x7f\x38\x64\x9e\x48\x1d\xe3\xd3\xf8\xeb\x0b\x7a\xfe\xd0\x38\x5c\xf0\xd2\x4b\x07\x9a\x0c\xb6\x5e\xcf\x14\xbf\x81\x3f\x79\x34\xe0\xaf\x07\x69\x20\x83\xc9\xe3\x99\xf8\xab\x69\x87\xbf\xfa\x34\xfe\xba\xc7\x52\x7d\x79\xd6\x64\x90\x59\x33\x6b\x8c\xaf\xd5\xaa\x81\x1e\xa3\xd5\x48\xb6\xbd\x39\xb1\x56\x7b\x99\x79\x9f\x26\xd6\x8a\x40\x02\x3e\xec\xcf\x3f\xec\x1f\xc3\x79\xb7\xc6\x84\x5b\xad\x77\x1a\x9d\xfd\x95\x94\xd7\xd6\xbd\xa6\x14\x05\x41\x05\x47\x68\xfd\x21\xe8\x76\x50\x5f\xf8\xa3\x8a\xe8\xdf\x42\x2d\xcd\x4c\xaf\xb4\xa1\x38\x73\x3c\xf6\x61\xa5\x67\xd0\xcc\xba\x78\x4c\x8c\x2f\x34\x33\x2f\x87\x41\xfb\xf7\x46\x2e\xe6\x80\xcc\x71\x2f\xb9\xd2\xf9\x18\x91\xf4\x3c\xb8\x4f\xbe\x5c\x1a\xc3\x2a\x1b\x8e\x22\xf7\x93\x64\x39\x46\xba\x7a\x24\xb4\x42\x30\x1d\xf1\x58\x8b\x5b\xf9\x26\xa0\xf5\x68\x03\xd3\x63\x60\x3c\xd5\x37\x52\x0e\x5b\xa1\xf6\x4a\x68\x7d\x2d\x7c\xb6\xd6\x60\x86\xfc\x18\x10\x68\xcc\x8b\x92\x15\x9b\x08\xf2\x42\x2d\x6a\x9f\x38\x36\xa5\x37\xe1\x1c\x92\x40\x8b\x36\x04\x5e\x63\x69\x35\xd4\x0b\x8b\x95\x7b\x20\xcd\xe6\xf9\x34\x7f\x37\x78\x6d\x52\x9a\x23\x21\xee\x7a\xe5\xf8\xb4\xe2\x12\x94\x17\x7d\xcb\x11\xef\xc5\xdd\x32\x26\xc6\xa9\x5e\x9e\x8d\xed\x80\xef\x52\xb3\x8b\xbd\xe3\x18\x8d\xf2\x4e\x8a\x2a\x3d\x57\xa3\xa7\xfe\xf3\x43\x13\x46\x8c\x9f\x8e\x0f\x10\x20\x07\xdf\x5c\x78\x4f\xdf\x7e\xb7\xcf\x7b\xf3\xa7\xd6\x35\x82\x74\xe6\x99\xd3\xcf\x1c\x33\xba\xff\x9e\xb3\xcf\xdd\x35\xb8\x69\xf7\xa5\x3b\xfe\x43\x4b\x27\x4e\xe8\x73\x76\x59\xf3\xdc\x65\x82\x26\xd0\x13\x27\x4f\x9c\x35\x93\xf6\xdb\x7a\x5f\xdf\xb1\xd3\x46\xf6\xf6\xc9\x9b\x9e\x68\xa8\xab\x6b\xd0\xff\xf8\x74\x8b\xbc\xf2\x82\xca\x6e\x8f\xd6\x1c\x33\x7e\xd4\x90\x29\x0f\xdd\xd0\x77\x68\xbf\xee\xea\xf1\x54\xb1\xe4\xcd\x5c\x71\x06\xb7\x75\xfb\xeb\x75\x6c\xce\x4b\x3e\x7b\x42\x53\xfb\x9c\x12\x6d\x9f\x53\xb2\x1f\x2a\xa7\x64\x26\x92\x14\x4c\x24\x35\x97\x66\x63\xb7\x59\x55\xb8\x45\xad\x8a\x61\xaa\xa9\x73\x66\x29\xa4\x3c\x24\xb9\xfc\x91\xa2\xe8\x91\x32\x4b\xac\x99\x3d\xdd\x53\x94\xd9\x54\x85\x15\xc0\x1d\x32\x4b\x38\x24\x66\xe7\xaf\x52\xfb\x19\x31\xd2\xc1\x27\x7f\xd2\xff\xa2\x99\xe5\x69\x7c\x60\xcc\xe7\xff\xcc\x98\x16\x73\xc7\x5e\x1a\xd7\xa7\xb6\x4f\x27\x01\x3d\xb2\x59\x2b\x96\x8f\xc1\x33\x8c\x80\x44\x9d\x48\x92\x01\xa4\x41\xb7\xd9\x03\x59\x0c\x66\x78\xbe\x3d\x80\xc3\x58\xf3\x2d\x3c\xd4\x55\x00\x6e\x41\xa0\x25\x59\xc0\x9e\xc8\x50\x40\x8c\xba\x22\x6b\x81\x31\x01\x84\x68\x6e\x3e\xf0\x03\xdc\x31\xa3\x95\xb1\x8e\x84\x3b\x8f\x5a\xe1\x76\x5d\xdb\xbc\x15\xfb\x47\x9d\x87\xad\x2c\x63\xf6\xdc\x98\x8c\x89\x2b\xb4\x37\x6d\x3f\x72\x45\x7a\x16\x2c\xb9\xd6\x87\x8d\xb9\x2b\x99\xf0\x14\x02\x3c\xc7\x76\x84\x27\x1f\xe7\x2c\x73\x78\xb2\x0d\x78\x72\x38\x3c\x39\x0c\x9e\x9c\x34\x3c\x39\xb0\x4b\x5e\xa5\xb8\x84\xed\xdf\xdf\x03\x29\x4d\xe5\xcc\x2e\xeb\x1a\xa4\xf4\xfc\x18\xc3\x3b\xea\x12\x28\x63\x8e\x0c\xfd\xa2\xcd\x16\x63\x70\xc9\x94\xc1\x55\xd9\x19\xae\x72\x80\x2b\xca\xe1\x8a\x22\x5c\xdd\x62\x6a\x31\x87\xab\x98\xc1\x55\x8c\x70\xe1\xe0\x29\x6b\x31\x83\x2b\x92\xf7\x3f\xc0\xd5\x66\x59\x1d\x7e\xbb\x4e\x30\x2d\xaa\xbc\xc3\xed\x98\xf8\x31\xb7\xa5\x5a\xaf\xe1\x9b\x26\x19\x7b\xf6\x12\xc0\x86\xd3\x21\x2b\xf0\x69\x0b\xed\xa1\x8b\x02\x74\x79\x1c\xba\x3c\x10\x80\xe1\x98\x5a\x9a\xd0\xb2\x41\x9d\x97\xc5\x99\x4b\x16\xde\xc3\x3a\x1a\x73\xbd\xac\x89\xaf\x02\x0e\xf3\x51\x6d\x23\xf8\xf9\x0c\xfc\x7c\x04\x1f\x3d\xb1\xdc\x30\x38\xb2\x76\xa7\x83\xc1\xaf\x96\x2a\x49\x77\x00\x87\x6d\x69\x15\xf9\xbc\x55\xdd\xaa\x00\x3a\x88\x66\x77\xa7\xfb\x70\x0f\x81\x11\xd0\xd9\x26\x32\x50\x63\x77\x8d\x90\x63\xa9\x23\x6e\xa2\x42\x01\x55\xdd\x25\x3a\x5a\x5e\x7a\xa9\xf5\x32\x86\x0a\x21\x0b\x95\xb4\x70\x10\x7c\x4f\xfa\x00\xd0\x30\xe6\xc1\xba\x9b\x79\x30\x36\x3a\xe5\xef\x25\xd8\xc6\x30\xb6\x69\xa2\xa5\x96\xf7\x80\x39\xf6\x77\xc7\xa9\x30\x84\xfb\xdc\xc2\x7a\xb0\x9d\x0e\x71\xdd\x23\x26\xd7\xce\xe7\x24\xfb\x35\x2d\x95\x9e\x66\x94\xb9\x7f\x00\xbf\x34\xac\xf9\x3e\xf8\xb5\xd1\xf2\x6d\xfb\xdc\x1a\xfd\xdf\x72\x6b\x93\x4c\xfa\x71\xc0\x1d\x3e\x33\x2a\x78\xf2\x8d\x5b\x10\xf1\xe0\x4d\x70\x8f\x1b\x2c\x0f\x1b\xb9\xb5\xe1\x46\x6e\x8d\xc5\x5b\xec\xbc\x25\xcb\x16\x37\x66\xcc\xfc\xbf\xcc\xae\x2d\xa0\x8e\x22\x5a\x9a\x4b\x1d\xd2\x37\x2f\xbd\xb4\x3f\x84\xb7\xc6\x23\x7c\x6e\x23\xd0\xe8\x4a\x80\x2f\x0a\x9a\x7b\x12\x49\x3f\x88\x4d\xed\x01\x17\xb5\xa5\x27\xbc\xf1\xc7\xb0\xb1\x88\x78\x9e\x31\xdc\xad\xb2\x18\x43\x27\x2e\x6b\x10\x1f\x48\xa7\xe6\x29\x5a\x28\x1b\x85\x64\x8f\x32\xfe\x00\x1b\x51\xd1\x64\xde\x5f\xcb\xf4\x40\xb8\x01\x6c\x17\x2b\x78\xf4\xf0\x02\x8e\x3f\x76\x5e\x86\x7c\x1d\x26\x9d\xb0\x18\x67\x0d\x75\x7f\x35\x7e\x53\x9d\xe4\x19\xd7\xf4\xeb\x98\x1d\xb4\x70\x44\xe5\xf4\xe3\xb7\x0d\x7d\x7e\xf4\x6d\x0b\x57\xe9\xcf\xef\xfb\x4e\x7f\x83\x96\x5e\x74\xd2\xc9\x17\x97\x9c\x73\xdc\xe9\xe7\xd3\x37\x3f\xa5\x4a\xa2\x5a\x9a\x78\x79\xc3\x45\xab\x4e\x94\xbd\x79\xae\xf7\xfc\x83\x63\xcb\x56\x4d\x3d\x51\xff\xe6\x8e\x7f\xff\xa5\x3f\x4b\x73\x5e\x5b\x79\xc3\xd3\xd7\xae\xa9\xa8\xdb\x82\x74\xc2\x66\xc7\x80\x5f\xe3\x07\x5e\xbc\xb1\x6d\x7a\x4c\x2e\x4b\x78\x80\x3f\x53\x9a\x1b\x05\x0c\x86\x3d\x2d\x1d\x07\xca\x54\x66\x0e\x94\x69\xae\xf0\xa3\x59\x68\x3c\xe0\x30\x60\x5a\x7e\x19\x73\x66\x9a\xf3\x1d\x4e\xf8\x46\x01\xb7\x08\xbb\xb5\x0d\x9d\xd1\x9c\x18\x30\x91\xc3\xb9\x5c\x7b\x1a\x03\x96\xb4\x28\xb6\xe2\x56\x34\xaa\xb9\xfc\x29\x3b\x5d\x4d\xa2\xe9\x2a\x0d\xd7\x71\x3a\xcd\x73\x1d\xdc\x91\x4e\xd3\x6a\x2c\xdd\x33\x93\x71\x22\x9f\x5b\x03\xfc\xc8\x73\x71\xc3\x32\x73\x71\x86\x4e\xf9\xbb\x89\x38\xa7\x57\x4a\x27\xe2\xda\x4d\xb1\xc9\x88\x72\x74\x39\xca\xe6\x5a\xc6\xd2\xeb\x0f\x31\xcf\x46\x7a\x02\x95\x60\x53\xdb\x54\x9b\xcc\x35\x77\xca\xbd\xa5\xa7\xed\x1c\x3e\xf7\xe6\x94\x3a\xe7\xde\x0e\x33\x79\x87\x49\x89\x43\x8c\xdf\x19\x6e\xe4\xdd\x0e\x35\x85\x47\x78\xd0\x50\x74\xc6\xba\x65\xd2\x55\xbe\xcd\xd0\x04\x7f\x37\xdf\xe6\xf4\x2a\x01\xa9\x63\xbe\xad\x3d\xd2\xdb\x47\x0c\xba\x44\xfc\x26\x53\x26\x8d\x3b\x04\xee\xc5\x77\x0c\x75\x96\x97\x31\x54\xc8\x84\xa3\xca\xc8\xb1\x9d\x96\x91\x63\x0b\x20\x1b\x45\x32\x93\x6b\x1c\xb4\x1e\x62\x66\x96\x4d\x8d\xc6\x41\x92\xa4\x6b\xcf\x62\x86\x58\xc1\xc7\x81\x02\xb4\x99\xb9\x35\x26\x60\x9c\x4a\x20\x22\x75\x99\x5a\x6b\x0f\x71\x17\xec\xa1\x1c\x1a\xf8\x0d\x1d\x38\xe5\x50\xe4\xe7\xca\xe0\x97\x56\x5f\x06\x1e\x24\x83\x0e\x77\xa7\xf3\x69\x0b\x33\xf3\x69\xe6\x58\xa2\x43\xe4\xd3\x54\x9f\x97\x3f\xe0\xcc\xa3\xe0\x77\x3a\x24\xd6\xd4\x22\xfc\xa8\x5d\x42\xcd\x29\xa5\x13\x6a\x1d\x36\xda\x74\xb1\x4d\x30\x51\x67\xb7\x03\x75\x1d\x75\x2c\x34\xc1\xa3\xe3\xa8\xa3\xe3\x2e\x7f\x02\x5a\xda\xdf\x46\xb0\xef\xf0\x38\xba\x48\x06\x90\x3b\xa4\x21\x92\xa9\x93\x7a\x12\xe3\x71\x39\x46\x4b\x23\x7b\x68\x8e\xf1\x78\x11\x69\x0f\x8e\x88\xc4\x78\xb1\x23\xde\xf6\x9c\x43\xb6\x12\xfc\x19\x20\x59\x5a\x97\xd2\x32\xfd\x7d\x5a\x26\xf4\xfb\xec\x33\xfd\x84\x96\x16\xb1\x5b\x4b\x0b\xa7\xa5\x93\xa4\x81\xd2\x53\x46\x9e\x6d\x41\x66\x9e\xcd\xb0\xd1\xff\x56\x9e\xed\x21\x2b\x30\x44\x3a\xd1\x66\x3b\x42\xa2\xad\xde\xd0\x47\x09\xde\x7d\xc8\x1e\xb8\x74\x88\x44\x1b\x22\x35\xc6\x78\x3f\x3e\xa3\xc7\xb0\x6d\x27\xcc\x5a\x08\x38\xad\x39\xbe\x72\xf8\xb6\x13\x16\x2c\xa6\x25\x8a\x4f\xa6\x92\xbf\x5b\x78\xd5\xe2\xab\xb3\xca\x82\xab\x16\x7b\x3d\x32\xc7\xae\xd7\x73\xc5\x1b\x23\xf6\x6d\x42\x0c\x7b\x5c\x57\xbd\x31\xfc\xfb\x6b\xfb\x2f\x2a\xa6\x82\xdf\x66\x7f\xe4\x0a\x5d\xb5\x5a\x00\xd9\xbd\x66\x17\x53\xe6\xc3\xb1\xd9\x3f\x40\x47\x7e\x92\x4d\x8e\x3b\xe4\xf4\x9f\x9c\xae\x92\x44\xb9\x66\x92\x08\x53\x57\x98\x65\x53\x42\xe1\x6c\xe3\x61\x5b\x47\x1c\x05\xc4\x04\x73\xa7\x79\x40\x2b\x78\xd6\xad\xd3\x54\x20\xe9\x20\x4f\xba\xb5\x5f\xef\xc4\xff\x7d\xbd\x2c\xeb\xa6\x04\x82\x7c\x9d\x4a\xd2\x83\xc9\xac\x23\xad\x95\x65\xe0\x3a\xcf\x2e\x1a\x6c\x78\x1a\x9d\x56\x2b\xee\x6f\xab\x97\xe3\xeb\xfd\x16\xd6\x9b\x47\xa6\x1f\x72\xbd\xf9\x5d\xad\xb7\xa0\x03\x7e\x53\x80\xdf\xdc\x3c\xe3\x51\xb2\x9e\xec\x9c\x23\x2f\x3c\x2d\x88\x3b\x2d\x7e\x71\x3a\x21\xd7\x19\xd7\xf9\x99\xf9\x38\xbe\xfe\x87\x59\x05\x70\x04\xe5\x6d\x7b\x08\x82\x68\x24\xe6\x24\xb4\x80\x15\xeb\x9e\xda\x00\xca\xcb\x00\x48\x0d\xb3\xc1\x08\x20\x64\x02\x31\x2d\xdc\x2e\x3f\xa7\x66\xe3\x47\x11\x85\x0f\xa3\xcb\x0e\xe3\xe3\xff\xb0\x5b\x28\xa2\xb0\xc7\x97\x1d\x11\x3c\x9e\xa9\xeb\x04\xdd\xf1\x3c\x53\xd7\x19\xb4\x52\x23\x51\x27\xf0\xf9\x48\x40\x47\x41\xf0\x8d\xfa\x74\x9e\x90\x14\x49\x4f\x48\xc2\x54\xa8\x8c\x56\x3b\x22\xfc\x6f\xce\x4a\x62\x0d\x00\x87\x1c\x98\xe4\x31\x3a\x14\x3b\xcf\x4d\x92\x76\x18\x84\x23\x90\xd3\xf4\xd9\xd2\x08\x36\x4b\x33\x4a\xa6\x1a\xb3\xf3\xf0\xd9\x04\xc4\x74\x2e\xf0\xc9\x84\x98\x0b\xa5\x31\xf3\x31\x05\x38\x2e\x51\x08\xc4\xe3\x18\x56\xc9\x35\x06\xe8\xb1\x67\x15\xe0\x34\x1e\x3e\x02\x38\x6c\x8c\xce\x93\x0b\x0e\x35\x02\x18\x9b\x67\xdb\x0d\xcf\x3b\x8d\x96\xc6\xd6\x4f\x36\x66\xe7\xe9\x7b\x69\x49\xdb\xfc\x3c\x39\xbb\x55\x1b\x38\x34\x73\x7c\x1e\xbd\x95\x76\xcb\x1c\xa0\x27\x1a\x78\x7e\x98\x65\x73\xf3\xc9\x22\x92\x0c\x23\xc5\x44\x12\x5a\x08\x28\x26\x37\xde\x09\xf1\x05\x38\x06\x0d\x33\xb5\x38\x61\xc8\x82\xb8\xf7\xb6\xf0\xe1\x19\xf9\x40\x25\x85\x18\x80\x0b\xe1\x34\x16\xc5\x81\xfd\x55\x60\xb2\x6a\xa2\xf4\xf7\xf7\xc5\x20\x98\x43\x6e\xcd\xef\x7c\x94\x44\x17\x3b\xd3\xc2\x28\x47\x20\x73\x0e\xee\xb3\x1e\xc5\x9e\x5f\x58\x46\x4e\xe6\xfd\x75\x6c\xba\x69\xfa\x31\x86\xf8\xb4\x79\xf6\x64\x23\x5e\xab\x01\x1e\xb6\xd3\x13\x94\x78\xe6\xd5\x1c\x79\x99\xdd\xf6\xf0\xc2\x2c\xa6\xb7\x92\x59\x05\x6c\x6e\x0a\x86\xc9\xbc\x71\x38\xc0\xa6\x5c\xcc\x7c\x15\x60\xc7\x58\x10\x20\x54\xb3\x14\xd5\x97\x2e\x69\x01\x05\xd2\x56\x69\x1a\xcd\x78\xba\x84\x39\x2e\x70\x0e\x1d\x43\x3d\x43\x37\x8e\x15\xe7\xa4\x8b\x4f\x6f\x99\x7e\xee\x60\xfd\x27\x2c\xdb\xba\x7b\x73\xe5\xd8\x8a\xea\xd1\xe5\x9b\xef\x64\xcf\xdc\xb1\xd3\x51\x2e\xbb\x51\x92\xea\x70\xd2\x91\xd4\xf1\xf0\xbf\x24\x8b\x24\x4b\x96\x27\x1f\x22\x86\xcd\x65\x75\x49\x63\x48\x31\xa9\x21\x8d\x98\xc3\x2b\x42\xcf\x25\x37\x81\xd1\x11\xd5\x1f\x67\xda\x12\x67\xc6\x54\xc3\xdb\x86\x78\x2a\x9e\x55\x84\xf0\xc6\x2d\xe9\xa7\x68\x97\x00\x90\x25\x3c\x7e\xed\x0e\xb4\xb0\xa4\x4b\x02\xd4\xd7\x40\xbb\xe4\xc8\xf2\xe7\x16\x79\xbb\xd5\xb2\x51\x39\x0a\x2f\x2d\xd0\xca\x8b\x70\xd8\x43\x3e\x07\x3a\xd4\xa8\x49\xd5\xe9\x21\x89\x5c\x79\x1e\x3a\x38\xda\xc1\x78\x2e\x33\x63\x09\xa8\x44\xd7\xed\x1c\x3c\xe8\xc9\xb5\x1d\xa2\x09\xeb\x5e\x1c\x32\x78\xe7\xba\x76\x56\xb5\x58\x68\xc4\x16\xb8\x36\x9d\x31\x71\xd2\xf4\xcc\xd0\xc2\xf4\xc9\x93\xa7\x67\x1a\xd9\x0b\xd2\x31\x32\x9e\xfb\x77\x13\x3b\xb3\xca\x4e\xec\x94\xfd\x57\x3d\x09\xcd\x69\xc5\xe6\x4b\xf6\x90\x05\x5e\x07\xd0\xec\xb6\x62\xeb\x87\x43\x61\xcf\xa9\x71\x83\x23\xed\x61\x27\xc0\x28\x63\x0f\x5d\xb0\x39\xf8\x80\x34\x0f\xf6\xd3\x0a\x62\x63\xa3\xa6\x58\x8d\x49\xd8\x5d\x94\x0b\xb4\x51\x78\x66\xc5\xc0\x67\x46\xdd\x71\x46\xc1\x40\x9c\xd1\x33\x25\x17\x4b\x9f\x8b\x4b\x2c\xdf\x11\x1b\x29\x60\xcf\x9b\xb6\x24\x34\x01\x1b\xad\xb1\xbd\xd7\x9c\x44\x67\xb6\x2a\x72\x5d\x72\xb1\xa9\x3a\xa4\xcf\xd3\x8a\x82\x92\xb5\xd2\x2b\xe2\x7c\xcb\x9f\x20\xaf\xc6\x12\x36\x83\x19\x0c\x71\xaf\xec\xb6\x19\xb9\x38\x56\x5e\x9d\xf2\xa7\x3d\x55\x90\xff\x29\x07\xb7\xb5\xd9\x10\x41\x3f\x16\x84\x32\x11\xe5\x75\x33\x07\x5e\x13\x65\xa3\xb3\xaa\x2b\xdb\x7a\x6d\x47\x57\xf3\x8f\x76\x65\x9e\xed\xe6\x60\x90\x76\x53\x2e\xfe\x2f\x9f\x5d\x2e\x4c\x91\x76\x89\xfd\xe0\xb3\xb0\xf9\x14\x47\xfc\xe9\x30\x94\xe1\x72\xa9\x49\x98\xc2\xe6\x0b\x9c\x28\x4c\xb1\xdc\x7a\xc4\xef\x9f\x68\xe9\x65\x7c\x3f\x2e\xfe\x4e\xe7\x81\xcc\xef\xe2\xb9\xdb\xc0\x44\x96\x30\x7f\xee\xb6\x85\x3f\x26\x88\xfd\xb5\x3f\x21\x06\xe3\xb7\x5d\xd1\x24\xfe\xbe\x83\xce\xd1\x6f\x7d\x9a\xaf\xb3\x51\xfc\x83\x2e\xe9\xfa\x3a\xf8\xfc\xee\x70\x17\xcf\xef\x4e\x04\xc5\xc6\xa6\xdf\x6e\x83\x3f\x9c\xf1\xec\x33\xfa\x6d\xfc\x3a\x71\xfd\x4f\x3a\x9f\x16\xfe\x0f\xd7\x61\x8f\x78\x6f\xfa\xed\x6a\xf8\x43\x07\xcd\xd3\x7f\xd1\xbf\x44\x5d\x06\x70\x09\xf7\xb1\xf5\x38\xc9\x51\x8c\xca\xe4\x84\x71\x31\x36\x52\xca\x65\xc2\xa7\x5a\xf8\x83\x3f\x9c\x61\xfe\x44\x24\x03\x54\x1c\xcc\x2d\x1a\xcf\xcb\x4d\x83\x9d\x48\x03\x3f\x29\x03\x01\x06\x1a\x04\xc4\x81\xf0\xc4\xe1\xef\xc9\x61\xc0\xc6\x7a\x04\xc3\x61\xdc\xd3\x00\x07\x23\x96\xb2\xf9\x80\x28\x13\x45\x09\xbf\x89\xa8\xa7\x33\x90\x65\xa0\x0c\xe0\x3c\x58\x28\xdc\x4b\xbb\xb3\x7b\x1e\x4d\xd8\xb6\x25\x52\x36\x7e\x4f\xc1\xbc\x67\x4a\x0a\x93\x1c\xde\xcf\x6f\xe5\x4c\x00\xef\x0e\x73\xe7\xb0\x5f\x49\xdf\x39\xde\xf4\xe5\x6d\x6f\x35\x7d\x75\xdb\x27\xd4\x45\x0e\xfe\xac\x7f\x4d\x03\xbf\xc3\x6f\x5e\x63\x43\xf7\x09\xf3\x25\x07\x48\x1e\xf0\x95\x9c\xb1\x94\xc4\x6e\x6b\xbc\x50\xf4\x04\x81\xff\x6c\x6c\x6e\x82\xf1\x82\x4f\x53\xea\xd4\xbf\xbe\x61\xfd\x92\xe5\xeb\xcf\x5d\xb6\x6c\xbd\xf0\xd2\xd4\xf9\xe7\xac\x5b\x30\x75\xc1\x99\x67\x31\x1d\xb0\x09\x64\x9b\x9f\x3d\x8f\xdd\xa8\xbf\x67\xbd\x15\x38\x3b\x93\x8d\x11\xb0\xd8\xe3\xf1\x8c\xa7\xb3\xbb\x32\xed\x59\xa9\xed\x69\x5c\xe6\x13\xce\xda\x9e\xc2\x66\xfe\x6c\xa2\xa5\xd7\xd1\xd2\x73\xf8\xf3\x5c\xcd\x1f\x9c\x03\x41\xae\x13\x06\xb0\xbe\xf8\x28\xa1\xaa\x95\x81\x61\x61\xeb\xc7\x50\xad\xcd\x24\x12\x89\x13\x06\x9b\xbd\xb3\x94\x0f\xdd\x11\xf2\x33\x67\xed\x8c\x83\xeb\x94\xb6\xbf\x0e\xec\x89\x71\xa9\xb6\xeb\x50\xbc\x8e\xd1\x7e\x3f\xae\x53\xbf\x3d\x5c\x67\xf8\xc1\x7d\xe2\xb7\xa0\xff\xab\xc8\x59\x24\x59\x41\xf8\xe0\x7c\xd6\xed\x80\x41\xa0\x14\xa1\x15\x0e\x37\xb3\x88\x89\x8c\x8f\x59\x4a\x59\x24\x76\x22\x9c\xc0\xd9\xb7\x6c\xea\x75\x8f\x98\xda\x7d\x8f\x26\xc8\xf1\x38\x16\x36\x69\x81\x6c\xc0\x5c\x7e\x77\x16\x4d\xc7\xc9\x79\xa1\x78\xb2\x7b\x3e\xbe\xeb\x8e\x1d\x02\x52\x1c\x27\x23\x81\xa8\x2f\x62\x53\x6e\x34\xc5\x62\xda\xc3\xf5\x89\xfa\x12\x1c\x54\x4f\x32\x07\xd5\x1b\xf3\xd4\x82\x19\x83\x60\x49\x3f\x3a\xfc\xaa\xab\xae\xa2\xd5\xbf\x34\x9d\x34\x24\x58\xbf\xaa\xf7\x9a\x0d\xf4\x3e\x7d\x12\xfe\x6c\x38\xb5\xcf\x8a\x44\xb0\xf1\xf4\xfe\xbf\xea\xaf\xd3\x17\x76\x9e\xbc\xd3\xbd\x9b\x16\x7b\xb3\xbe\xf0\xfa\xb7\x2d\xce\x82\xb7\xb6\x79\x57\x2a\xca\x67\x59\x5e\xea\x7f\xda\x86\x7c\x3c\x5b\xbc\x5a\x9a\xc7\x9e\x4b\x14\x26\x57\x19\xb3\xd1\xa8\x3b\x61\xd2\x78\xd2\x92\xe5\x8f\x03\x30\x76\x36\x0b\x8a\x9f\x62\xc7\x84\xe7\xb8\x45\x3e\x3d\x4e\x86\x0d\x64\x92\xbf\xeb\xc7\x17\xa1\x0c\xc0\x5e\x41\xb3\xde\x99\xf5\xd8\xa4\xb2\xda\x86\xd4\xe0\x43\x07\x34\x87\xdb\x7c\xc8\x4c\xb3\xd3\xe5\x0b\x1a\x29\x3f\x7c\x48\x4b\x89\x02\x52\x08\x07\xb3\xc2\x51\x85\x58\x22\x5a\x95\xd9\x74\xe3\x39\x9b\xe8\x71\x5b\xd7\xca\xa7\xde\x78\xae\xbc\xf8\x98\xe5\xb2\x65\xf8\xe2\xc5\x38\x9e\x47\x1f\x25\xe4\xeb\xd7\xd2\x13\x5b\x3f\xa3\xb9\x54\xff\x82\x76\xa7\xfa\xdb\x84\xb2\x61\x0a\xbd\xa5\xde\x40\xeb\xf5\x9c\xce\x53\x54\xc2\x79\x1b\x99\xc7\xe9\x11\x9f\x6c\x12\x87\xf1\x62\x48\xf5\x5a\xa0\x67\xbc\xc0\x7e\x63\x46\x5d\x00\xae\x37\x87\x3d\xb3\x20\x82\xd6\x13\x3e\xb5\x40\xcd\xe6\x53\xc3\x35\x25\x27\xd1\xee\xd1\x05\x2e\x3e\xad\xfb\xc8\x8f\x2e\xc0\x09\x25\x18\xb1\x89\x18\x93\xbc\xb3\xb1\xa8\xd1\x6d\x38\x4f\x0e\xf6\xb0\xa4\xbf\xf9\x5c\x03\xb4\x1b\x02\xdb\xfe\xfc\x74\xcc\xf5\xf3\xbb\x1f\xb3\x76\xf4\x82\x05\x6f\xbd\xa5\x7f\x20\x5c\x44\x4b\xc5\x65\x2f\x8f\x78\x69\x6f\x61\xfe\x97\xa1\xec\xe9\x53\x46\xb0\xe7\x1b\x1c\xb8\x9a\xa5\x0d\x04\x7c\x0e\x83\xb4\xce\x80\xe9\xa4\xf6\x30\x65\x3c\x8c\xc1\x1e\x03\x56\x68\xf6\xd8\x65\x4f\x15\xce\xfc\xf9\xbf\x80\x26\x67\x82\x74\x78\x60\x3a\x3d\xa8\x41\xd8\xca\x80\xe9\xf8\xb0\x86\x03\x57\x9b\x73\xeb\x45\x84\xc7\xda\x8f\xc1\x83\xd5\x2f\xcf\x71\x88\xb4\xea\x1a\x63\x76\x7d\xb3\x92\x83\x46\x2a\x03\x2c\xe9\xcf\xae\x02\x3a\xc7\x70\x29\x18\xbd\x05\xae\x16\x63\x06\x28\x03\xb0\xee\xef\x02\x88\xa3\xe2\x72\xe3\x58\xe7\xa1\x56\xc6\x93\xd5\x3d\xf1\xb3\xea\x2a\xf8\x5a\xcf\x6a\x3c\xec\x89\xb3\x7d\xaa\x79\xa9\x57\x22\x8b\x97\xc9\xf4\x34\xf1\xa0\xd5\x80\x45\xac\x95\xe1\xc3\x6b\x12\x8a\x56\x1c\x45\xcc\x94\x51\x36\xbe\x47\x2b\x40\x3b\xd1\xce\xeb\x38\x0e\x81\xa3\xe8\xff\x84\xbb\xba\x43\x90\x46\x47\x6c\x1e\x8a\x56\x38\x6e\xa7\xa5\x71\x7b\x5f\x47\xdc\x26\x01\xb7\x89\x44\x3b\xd4\xba\x63\x6a\x71\x82\x35\x16\x17\xc4\x35\xbb\xbd\x45\x8b\xd6\xc6\xe3\xff\xbf\x22\xb7\x20\x6a\x04\xb6\xff\xbf\x40\x61\xdf\xbf\x49\x90\x87\xa2\xd0\xff\x07\xda\x23\xff\xc1\x00\x78\xda\x63\x60\x64\x60\x60\x00\x62\x2f\xbf\xcf\x96\xf1\xfc\x36\x5f\x19\xe4\x39\x18\x40\xe0\x7c\xfd\x9c\x33\x30\xfa\xff\xec\x7f\xc6\xec\xd1\xec\xfd\x40\x75\x1c\x0c\x4c\x20\x51\x00\x54\xec\x0c\xc7\x00\x00\x00\x78\xda\x63\x60\x64\x60\xe0\xa8\xf9\xbb\x16\x48\x32\xfc\x9f\xfd\x7f\x26\x7b\x34\x03\x50\x04\x05\xbc\x02\x00\x92\xee\x06\xb7\x00\x78\xda\x6d\x93\x5b\x48\x54\x51\x14\x86\xff\x59\x7b\xed\x39\x05\x1a\x86\xa1\x85\xca\x98\xd5\x53\x37\x99\x07\x73\xc2\x1b\xa3\x58\x79\x09\x09\x89\xb4\xb1\xd1\x84\xc0\x94\xb2\x1e\xb2\x20\x9c\xa8\x51\xc7\xca\x9a\xa2\x8b\xdd\xec\x25\x8a\x6e\x04\x41\xbd\x05\x56\x90\x44\xf4\x18\x41\x05\x21\x52\x10\x48\xb7\xa7\x20\x6a\xfa\xcf\xd8\x90\x86\x0f\x1f\xff\xda\x7b\xaf\xbd\xcf\xd9\xeb\x5f\x5b\x26\x51\x35\x07\x80\xe7\xf7\x14\xb2\x12\xfd\x12\x87\x5f\x9f\xa2\x50\xcf\xa3\xd5\x7e\x42\xd8\x06\x51\xea\xa9\x81\x5f\xc6\x70\x50\x9e\xc3\x67\x8e\x23\x47\x5b\x50\x2c\x19\x28\x37\x8b\xb1\x47\x1a\x11\x37\x81\xc4\x77\xe6\x87\xc9\x6d\x52\x47\xaa\x49\x80\xec\x22\xed\xa4\x84\x6c\x25\x9b\xa4\x1a\x71\xf1\x63\xaf\x66\xa2\x48\xaf\x20\xa6\x05\xe8\x31\xbf\x90\xef\x2c\x42\xd0\xfa\x90\x66\x0b\x10\xb3\x79\x68\xb1\x65\x5c\x1b\x26\x23\x1c\x37\xa1\xdd\xde\x42\x4c\x9a\x70\x51\x4f\xa1\xdc\x2e\xe7\x7c\x23\x62\xde\x9f\x5c\xe3\xbc\xed\x41\xc8\x16\x51\x2f\x50\x6b\xa8\x99\x68\x66\x5e\xae\x8d\x60\xbf\xcd\x86\xe3\x64\x63\x21\xd5\x67\xd3\x60\xf5\x21\xea\x65\x2d\xbf\x19\x86\x50\xd3\xcd\x21\xac\x30\xa7\xe1\x91\xeb\xa8\xd7\x3a\xac\xd1\x28\xba\x75\x29\xca\xa8\x95\x5a\xc2\xdc\x77\xbc\xaf\x1b\x47\xd1\x21\x4b\x10\x11\x5f\x62\x44\x37\xa0\xdb\x8d\xbd\x93\xcc\x8d\xa2\xf3\xef\xba\x1b\x57\xca\x4b\x6a\x3e\x2a\xe4\x05\xe6\xba\x7b\x34\x0b\x19\x76\x02\x79\xd4\x4c\x62\x49\xad\x5c\x43\xa1\x38\xb8\x4b\x2d\xb0\xab\xd1\x91\xac\x7d\x15\x4e\xb0\x1e\xeb\x75\x94\x77\x18\x44\x83\x7e\x40\x96\x58\x44\xac\x83\x6d\x1a\xc4\x65\x6f\x35\x36\x9b\x21\x9e\xed\xc1\x76\xed\x40\xaf\x5b\x7b\x77\x4e\x15\x67\x4c\x2e\x7a\xb5\x1e\xcd\x26\x84\x2e\xb3\x05\x61\x79\x8d\x2e\xfd\x8a\x63\x5a\x84\x52\xe9\xc4\x55\x59\x86\x36\x29\xc5\x46\x73\x13\xfb\xb8\x7f\x87\x7d\x85\x1b\xde\xf9\xe4\x01\x76\x6b\x3a\x6a\x93\x75\x9f\x05\xa7\x0f\xc6\xf5\x22\xe9\xc3\x34\xa4\x29\xf1\x8c\x5e\x0c\x53\x47\xc9\x3d\x1b\x62\x6d\x53\x3e\xfc\x87\x56\xa0\xc2\x1e\x66\xec\x7a\x31\x1d\xd7\x8b\xf7\x88\xda\x79\x18\x48\xd6\x7d\x16\xbc\x8f\xb1\x2a\xe9\x05\x7d\x98\x8e\xf8\x13\xf7\xd9\x43\x51\xea\x1d\x72\x49\x9f\xb0\x5f\xff\xf9\x30\x93\x38\xca\x53\xfe\xcd\xc0\xf5\xe2\x28\x0e\xb8\xea\x8c\xa2\xcd\x29\x46\xa5\xfb\x4f\xe6\x07\x06\xcd\x1b\xf6\xc7\x18\xe0\x9c\x04\x52\x2a\x7d\x7c\x23\x13\x24\x38\x05\xbe\x51\x8f\x50\x3b\x99\x43\x2f\x52\xd8\x3e\x0c\x79\xfb\xb1\xd3\x73\x16\x7e\x12\xf0\x9c\xe3\xdb\xf9\x48\x3e\x23\xc0\x5e\xf2\xcb\x38\x06\xec\x17\xc4\xdd\xbd\x12\x41\x17\xfd\x69\x70\xcf\xd5\x10\xd6\xb1\x16\xad\x5a\xcc\x78\x1c\x0b\x34\x81\x1c\xe7\x11\x79\x8b\x9c\x3f\x3c\x80\xbb\xdf\x78\xda\x63\x60\x60\xd0\x81\xc2\x28\x86\x2e\xc6\x12\xc6\x7f\x4c\xf3\x98\x9d\x98\xd3\x98\xa7\x30\x1f\x62\x7e\xc7\x62\xc0\x12\xc2\x52\xc4\x32\x85\x65\x0d\xcb\x1f\x56\x35\xd6\x1e\x36\x0e\xb6\x00\xb6\x35\xec\x6a\xec\x71\xec\x6f\x38\x92\x38\xfa\x38\x0e\x71\xdc\xe0\xf8\xc5\xc9\xc7\x59\xc2\xe5\xc4\xd5\xc6\xf5\x81\x3b\x8a\x7b\x1a\xf7\x25\x1e\x0e\x9e\x1a\x9e\x2d\x3c\x97\x78\x25\x78\x83\x78\x2b\x78\x2f\xf0\xf1\xf1\x25\xf0\x2d\xe1\x67\xe3\xcf\xe3\xff\x20\xa0\x20\x10\x27\x30\x4d\x90\x45\xd0\x42\x30\x4b\x70\x86\xe0\x31\xc1\x7b\x42\x02\x42\x46\x42\x3e\x42\x39\x42\x6f\x84\x03\x84\xb7\x89\xc8\x88\xd4\x89\x5c\x10\xf5\x11\x9d\x22\x7a\x40\xf4\x9f\x98\x91\x98\x9f\xd8\x3e\x71\x0e\xf1\x10\xf1\x6d\x12\x12\x12\x21\x12\x97\x24\x35\x24\x0b\x24\x67\x49\xde\x93\x12\x92\x0a\x92\x6a\x90\x3a\x21\xf5\x4c\x5a\x47\xba\x0e\x08\x57\xc8\x88\xc9\x4c\x93\x55\x90\x6d\x93\x5d\x27\x97\x24\x37\x41\xde\x49\xfe\x88\xfc\x13\x05\x3e\x05\x1d\x85\x77\x8a\x5c\x8a\x11\x8a\x4b\x14\xbf\x29\x15\x29\xcd\x50\x7a\xa1\x2c\xa3\x6c\xa3\x5c\xa6\x3c\x4f\xf9\x95\x0a\x8f\x4a\x8f\xaa\x8c\xea\x03\x35\x37\xb5\x69\x6a\xaf\xd4\xdd\xd4\x4f\x68\x98\x68\x1c\xd2\x94\xd2\x5c\xa5\xf9\x4d\xcb\x4e\xab\x47\xeb\x95\xb6\x84\xb6\x87\x76\x95\xf6\x0e\x1d\x31\x9d\x79\xba\x0c\xba\x49\xba\x67\xf4\xa2\xf4\xce\xe9\x7d\xd0\x2f\xd1\x3f\x62\x20\x66\x90\x67\x70\xce\x90\xcf\x30\xc2\xf0\x9c\x51\x98\xd1\x03\xe3\x02\x13\x2d\x93\x53\xa6\x5d\x66\x2e\x66\x97\xcc\xad\xcc\x97\x59\x88\x58\xcc\xb1\x38\x61\xf1\xcd\x52\xc3\x32\xcd\xf2\x8e\x55\x8a\xd5\x3e\x6b\x29\xeb\x3a\x1b\x26\x9b\x22\x9b\x25\xb6\x6a\xb6\x75\xb6\xd7\xec\xcc\xec\x16\xd9\x7d\xb2\x0f\xb3\xdf\xe7\x60\xe1\x70\xc6\x51\xcd\xd1\xcb\x71\x12\x0e\xb8\xc0\x71\x9d\xe3\x1e\xc7\x2b\x8e\x6f\x9c\x04\x9c\x4c\x9c\x22\x9c\x26\x39\x9d\x71\xe6\x72\xb6\x72\x2e\x03\xc2\x59\xce\xfb\x9c\xf7\xb9\xd8\xb8\x6c\x70\xb9\xe1\xea\xe4\xba\xca\x2d\xc2\xed\x17\x00\xd1\x61\x93\x7a\x00\x01\x00\x00\x00\xea\x00\x46\x00\x05\x00\x00\x00\x00\x00\x02\x00\x01\x00\x02\x00\x16\x00\x00\x01\x00\x01\x66\x00\x00\x00\x00\x78\xda\x75\x52\xcb\x4a\xc3\x50\x10\x3d\xb7\xad\x8f\x62\x2d\x22\x52\x5c\x66\x21\xae\xda\x34\x8d\x15\x24\x82\xf8\xc0\x8a\x52\x5c\x54\xd1\x8d\x08\x69\x1b\x6d\xe9\x4b\xd2\x88\xb8\xf3\x2b\xfc\x18\x97\x2e\x44\xff\xc0\xcf\xf1\xe4\x66\x1a\x9b\xa2\x84\x99\x7b\x66\xee\xcc\xb9\xe7\xce\x0d\x80\x15\x7c\x20\x0d\x95\xc9\x02\xd8\xa3\x45\x58\x21\xc7\x28\xc2\x29\x2c\xe2\x4c\x70\x1a\x26\x1a\x82\x33\x28\xe0\x45\xf0\x1c\x8a\x78\x15\x3c\xcf\xfc\xbb\xe0\x05\xec\xe3\x5b\x70\x16\x39\xb5\x2e\x78\x09\x6b\x6a\x43\x70\x0e\x9b\x6a\x47\xf0\x32\x6e\xd4\xad\xe0\x3c\x2e\xd5\x9b\xe0\x55\x14\x52\x79\xc1\x9f\xc4\x93\xde\x2f\x58\x29\x07\x35\x8c\x30\x44\x00\x03\x6d\xb8\x5c\x5d\xa2\x16\x73\x0f\x78\x86\x8f\x2e\xee\xd1\xd1\xbb\x27\xcc\x8d\x18\xf5\xe1\x31\xb2\x61\xa1\x42\xdf\x60\xae\x49\x0b\x68\x87\xb4\x3e\x59\xa6\x2b\x9d\x44\x85\x11\xd7\x38\xc2\xb0\xf5\xcf\xfe\x15\x7b\x7d\x8c\x79\x7e\xa8\xce\x60\xa5\x49\xb3\x74\x4f\x95\xb6\x1b\x6b\x48\x32\x94\x62\x86\x24\x6f\x97\x5c\x86\xbe\x5b\x40\x5e\x97\xfb\x1e\x06\x5c\x7d\xf4\x98\x1b\xe1\x6e\xe6\x86\x66\x22\x4a\xee\x84\xd3\x19\xe0\x88\x73\xf1\x35\x6f\x40\xef\x6a\x95\xd1\x99\xa1\xf2\x80\xf9\x50\x79\x9d\x7b\x2d\x66\x86\x8c\x3d\x9e\x6a\xe0\x91\xb8\xad\x6b\x42\x2d\x1d\x3d\xcd\x03\x4e\xdb\x65\x5d\x14\x25\x7b\x8a\xcc\xcc\x4e\xc3\xa6\x0a\x4b\xbf\x4b\xc0\x4e\x07\x65\x7e\x4f\xfa\x33\xc9\xf3\xcb\x65\xb2\xde\xa7\xee\x32\x95\x4f\x73\x8e\x99\xa9\xe3\x94\x77\x38\xc6\x39\x2e\xe8\x4b\xc2\xf9\xf7\x6b\x5c\xb3\xa7\xc9\x19\x4d\xfe\x94\x8a\xae\xad\xe9\xfb\x47\xea\x7d\xad\x6a\x9b\x3e\x7c\x13\x87\xde\xd6\xbe\x1a\xbf\x53\xf5\x07\x58\x2b\x74\x6f\x00\x00\x78\xda\x6d\xd0\x47\x4c\x93\x71\x18\xc7\xf1\xef\x03\xa5\x85\xb2\xf7\x06\xf7\x1e\xef\xfb\xb6\x65\xb8\x5b\xe0\x75\xef\xbd\x45\x81\xb6\x88\x80\xc5\xaa\xb8\x8d\xe0\xd6\x68\x4c\xbc\x69\x5c\x17\x35\xee\x19\x8d\x7a\x50\xe3\x5e\x71\x44\x3d\x78\x76\xc7\x83\x7a\xd5\x42\xff\xde\x7c\x2e\x9f\x3c\x4f\xf2\x3c\x79\xf2\x23\x82\xf6\xfa\x53\x4b\x15\xff\xab\xcf\x20\x11\x12\x49\x24\x16\xa2\xb0\x62\x23\x9a\x18\xec\xc4\x12\x47\x3c\x09\x24\x92\x44\x32\x29\xa4\x92\x46\x3a\x19\x64\x92\x45\x36\x39\xe4\x92\x47\x3e\x05\x14\xd2\x81\x8e\x74\xa2\x33\x5d\xe8\x4a\x37\xba\xd3\x83\x9e\xf4\xa2\x37\x7d\xe8\x4b\x3f\xfa\xa3\xa1\x63\xe0\xc0\x89\x8b\x22\x8a\x29\xa1\x94\x01\x0c\x64\x10\x83\x19\xc2\x50\x86\xe1\xc6\x43\x19\xe5\x54\x60\x32\x9c\x11\x8c\x64\x14\xa3\x19\xc3\x58\xc6\x31\x9e\x09\x4c\x64\x12\x93\x99\xc2\x54\xa6\x31\x9d\x19\xcc\x64\x16\xb3\x99\xc3\x5c\xe6\x31\x9f\x05\x54\x8a\x85\xa3\xb4\xd0\xca\x0d\xf6\xf3\x91\xcd\xec\x66\x07\x07\x38\xce\x31\x89\x62\x3b\xef\xd9\xc4\x3e\xb1\x8a\x8d\x5d\x12\xcd\x56\x6e\xf3\x41\x62\x38\xc8\x09\x7e\xf1\x93\xdf\x1c\xe1\x14\x0f\xb8\xc7\x69\x16\xb2\x88\x3d\xa1\xa4\x1e\x51\xcd\x7d\x1e\xf2\x8c\xc7\x3c\xe1\x29\x9f\xa8\xe1\x25\xcf\x79\xc1\x19\xbc\xfc\x60\x2f\x6f\x78\xc5\x6b\x7c\x7c\xe1\x1b\xdb\xa8\xc5\xcf\x62\x96\x50\x47\x3d\x87\x68\x60\x29\x8d\x04\x68\x22\xc8\x32\x96\xb3\x22\x94\xf2\x4a\x56\xd1\xcc\x6a\xd6\xb2\x86\xab\x1c\x66\x3d\xeb\xd8\xc0\x46\xbe\xf2\x9d\x6b\x9c\xe5\x1c\xd7\x79\xcb\x3b\xb1\x4b\xac\xc4\x49\xbc\x24\x48\xa2\x24\x49\xb2\xa4\x48\xaa\xa4\x49\xba\x64\x48\x26\xe7\xb9\xc0\x65\xae\x70\x87\x8b\x5c\xe2\x2e\x5b\x38\x29\x59\xdc\xe4\x96\x64\x4b\x0e\x3b\x25\x57\xf2\x24\x5f\x0a\xa4\xd0\xea\xad\x6b\x6e\xf4\xe9\xb6\x60\xbd\x5f\xd3\xb4\xf2\xb0\x6e\x4d\xa9\x7a\x8f\xa1\x74\x28\x5d\xca\xd2\x36\x8d\xd0\xa2\x52\x57\x1a\x4a\x87\xd2\xa9\x74\x29\x8b\x94\xc5\xca\x12\xe5\xbf\x7b\xee\xb0\xba\xba\xab\xeb\xf6\x1a\xbf\x37\x18\xa8\xae\xaa\x6c\xf2\x85\x47\x86\x19\xd6\x65\x5a\x2a\x82\x81\x86\xf6\xc6\x65\x96\xb5\x69\x7a\xc2\x7f\x84\x34\x94\x0e\xa5\xf3\x2f\x0f\x26\x9e\xe4\x00\x00\x78\xda\x45\xce\x3f\x12\xc1\x50\x18\x04\xf0\x3c\x8f\x24\x22\xc8\x3f\x51\x19\x31\xa8\xde\x8c\x8e\x19\xd1\x4a\x1a\x8d\x51\x25\xc6\x05\x5c\x40\xad\x51\x72\x0a\x07\xf8\xa2\x72\x3b\x76\xf8\x3c\xdd\xfe\x76\xb6\xd8\xa7\x78\x5d\x48\x5c\x8d\x0d\xd9\xdb\xa2\x12\xe2\x56\x56\xb9\xa9\x8a\x11\x79\xe5\x86\xa2\x1d\xc2\xb9\x1c\x90\xa9\x0e\x85\x41\x32\xc9\x48\xaa\x35\xd5\x93\xec\x21\x87\x35\xf5\x41\x03\xa8\xff\x60\x02\x8d\x3b\xc3\x02\xcc\x3d\xc3\x06\xac\x94\xd1\x04\xec\x25\xc3\x01\x9a\x53\x46\x0b\x70\x26\x0c\x17\x68\x8d\x19\x6d\xc0\x1d\x31\x3a\x40\xbb\xff\x85\xa0\x2e\xff\xf2\xd0\x76\x57\x35\x55\xc9\xfc\x04\xfa\xa0\x37\xd7\x0c\x40\xff\xa8\x19\x82\xc1\x7f\x1c\x81\x61\xaa\xd9\x03\xa3\xa5\x66\x0c\xf6\x16\x9a\x7d\x30\x9e\xfd\x58\x52\xa4\xde\x75\xba\x5b\x0c\x00\x00\x00\x01\x53\x59\xec\x4c\x00\x00\x01\x00\x00\xff\xff\x06\xa9\x28\xa4\xec\x60\x00\x00") func fontsRobotoBoldWebfontWoffBytes() ([]byte, error) { return bindataRead( _fontsRobotoBoldWebfontWoff, "fonts/roboto-bold-webfont.woff", ) } func fontsRobotoBoldWebfontWoff() (*asset, error) { bytes, err := fontsRobotoBoldWebfontWoffBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "fonts/roboto-bold-webfont.woff", size: 24812, mode: os.FileMode(509), modTime: time.Unix(1492020681, 0)} a := &asset{bytes: bytes, info: info} return a, nil } var _fontsRobotoRegularWebfontEot = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x64\x97\x63\x70\x1c\x00\xdb\xae\x37\xc6\x46\x1b\x6e\x6c\x36\xd8\xb0\x61\xbb\xb1\x6d\x36\xb6\xed\x6e\x6c\xdb\x4e\x63\x35\xb6\x6d\x35\x6c\xec\xa4\x71\xdb\xa8\x39\xf3\x9e\x39\xe7\xc7\xf7\xbd\xd7\x9f\x67\x9e\xb9\x67\xae\xb9\xff\xde\x26\xea\x00\x40\x84\x1a\x00\x00\x0f\x80\x07\x20\x02\xfe\x73\xff\x3f\x70\x80\x44\x38\x00\x00\x11\xa0\xa0\x72\x0d\x0f\xd8\xd5\xa7\x02\xa8\x50\xfd\xbf\xa4\x00\x0e\x40\x05\x00\xc0\x29\xbf\xff\xe6\x6b\x07\xfc\x17\x18\x00\x35\x80\x13\xc0\x14\xe0\x04\x70\x07\x38\x01\x00\x00\x2c\x80\x1a\xc0\x02\x60\x05\xf0\x00\xd8\x03\x4c\x00\xae\x00\x00\x80\x15\xa0\x05\xb0\x00\xb8\x02\xdc\x00\x36\x00\x27\x80\x23\x80\x0a\xc0\x09\x60\x07\x70\x02\x20\x00\x08\x80\x13\xc0\x03\xe0\x04\x08\x01\xa8\x00\x5c\xff\xf7\xe3\x06\x00\x00\x64\xff\xc3\x48\xf5\x5f\x3e\x00\x40\x4c\x5d\x5a\xe5\x7f\xf7\x40\x00\xb8\x4b\x00\xb8\x72\x00\x5c\x45\x00\x56\x1a\xdc\x99\xb3\xe8\x71\x6f\x3d\xed\x09\x6b\x7d\x17\xb9\xaf\xde\x34\x66\x9d\xae\xac\x56\xac\x92\x7f\x18\xfe\x20\x89\x07\x6f\x91\x0c\xf7\x46\xff\x7e\x78\x4d\x45\xad\x87\xc6\xde\xb2\x6a\x18\x63\xd4\xc4\x1a\xc3\x9d\xb5\xb7\x20\x97\x8f\xa0\x0f\xd9\xd1\x99\xd4\xb8\x2c\x81\x52\x9c\xd0\xe7\x48\x48\x30\xcd\x8b\x0a\x38\x7b\x0d\x4d\xac\xb0\x30\x93\xac\x38\xb9\x7a\x89\x02\x15\xca\x8d\x3d\x2d\xb9\xf9\xb3\xf7\x24\xa2\xbf\x67\x86\xb8\x0a\xae\x88\xd6\x34\xfa\x89\xf2\xdd\xf3\x9e\xa8\xc9\xf4\xf9\x30\x48\x70\xcb\xb4\x46\xfe\x3d\x67\x41\x3e\x22\x1c\x32\x4c\x14\x9c\x22\xe0\xd9\x99\x4d\xaf\x5a\x83\x34\x47\xaa\x99\x23\x21\xbe\xf7\xd4\x7e\xfb\xc9\x3f\xa5\x81\xe0\x65\xeb\xe5\xae\xd8\x63\x52\xc3\x58\x2f\xa0\x0d\x0b\x8b\x24\x27\xc9\x95\x50\x08\x10\x23\x63\x02\x30\x9d\x0c\xe3\xce\xf7\xcb\x18\x93\x67\x8e\xf2\x36\x8c\x45\x69\xd7\x6a\x92\xd5\x1a\x76\x23\x3e\xbc\xa9\x6a\xf9\x16\xcc\x42\xf5\xd0\x42\x6d\xa3\x75\x5a\xd6\x99\x71\x91\xf0\x58\x96\x1b\xf8\xdd\x27\xef\x08\xe4\x30\xc9\x73\xf2\xa7\x99\xcf\xe8\x8c\xed\xeb\x6f\xe6\x7f\x5b\x4b\x24\x6c\x4b\x55\x5f\x9c\xa5\x4c\xaa\xfa\xdb\x00\x5a\x5f\x15\x5e\x8d\x64\x0a\x5b\x59\x99\x3e\xb7\x71\xc7\xf2\x06\x56\x67\x25\xe1\x9f\x10\x93\x2b\xa1\x07\x46\xf9\x7f\x55\x68\x49\x6e\x72\xe2\x9e\xaa\xe6\x63\x61\x3b\xf2\x8c\x5a\x65\xf6\xd6\xdf\xab\xb8\x03\xcf\x40\x3f\x86\xe8\x50\x1a\x23\xeb\x2a\x0d\x70\x9a\x7e\xe8\x4f\xc8\x00\x29\xed\xce\xcd\x92\x04\x52\x14\x18\xee\xc3\x03\xdd\x37\x22\x70\x62\xd0\xee\x08\x94\xab\xc2\x6c\x58\x87\x4b\xad\xad\x2d\x0f\x49\xd0\x2c\xf6\x75\x36\x93\x05\x25\xf3\x56\xf1\x8b\xa2\x91\x1a\x7a\xd9\xc0\x36\x8e\xe5\x54\x39\x65\x48\x87\x58\xe4\x20\x2b\x66\x6b\x2b\xff\xaa\xe4\x51\xa9\x73\x8b\x12\xb7\x08\xb9\x22\x81\xcf\x6f\x73\x6e\x81\x8d\xac\xae\x9f\x6b\x0c\xed\x0d\x42\x5c\x5c\xc2\xda\x8a\xba\xbe\x1b\xa1\xa7\xce\x17\xea\x25\x9b\x3a\xed\xea\x16\x02\x1c\xf8\x79\xe0\x52\xc2\xe4\x69\xf8\x36\x60\x6c\x88\x5a\x05\x2b\x41\x46\x30\x70\x08\x0e\xac\x4e\x74\x87\x1f\x3b\xdb\xf4\xc1\xd9\xd9\x59\xcb\x4c\x3d\xfc\x00\xe0\xb3\x8b\x0d\x76\xaf\x41\xd5\x31\xd6\xfd\x61\x4c\x00\x25\xa2\x4a\xe3\xc6\x17\x43\xfc\x11\xca\x49\x40\xc3\x32\xa6\x12\x1d\x30\x0c\x65\x8d\x05\xaf\x90\x55\xc7\x72\xbb\xbb\x99\x1e\x06\x85\x37\xf2\x4b\xb1\x58\x9a\x52\xb2\xa2\x49\xa1\x75\xa0\x65\x10\xc6\xb2\x98\x57\x8c\x36\xa5\x11\x17\xea\xec\x95\x48\xd5\x02\x7f\x67\x6a\x2f\x1a\x67\x9f\x4a\x13\x42\x8b\xeb\x9c\xc2\x8c\x25\x12\xf4\x9c\x27\x16\xc8\xf8\x21\x03\x26\x2c\xf1\x47\xa2\x26\x65\x63\x95\x3a\x08\x28\x97\xc4\xef\x82\xc0\x98\x4b\x99\x4f\x5e\x04\xf0\x9f\x36\x71\xf9\x93\x0a\xba\x9f\x8c\x24\x9f\xe4\xec\x16\xb9\xe1\xf6\xdc\x7f\x91\x5a\x65\xfb\x2c\x90\x7f\x4c\x31\x02\x58\x9c\x26\x36\x5d\x7e\x0a\x48\x9c\x9e\x3f\xa3\xa4\x2d\xd2\x92\x76\x63\x62\xd1\x08\x12\x84\xe7\x7a\xb2\xa9\x95\xdc\x0b\x52\x08\x8a\x97\x10\x53\xa8\xc4\x40\xc3\x40\x03\x2e\xe9\x68\x19\x00\x61\x1f\x92\x6d\x94\x55\x2e\xdf\x64\x41\x83\xe2\xb1\x05\x85\x7a\xf2\x09\xb7\xf3\x54\xa2\xd0\xde\x7d\x2c\xa4\xb7\x24\x11\xf5\x10\xe7\x88\xe1\xd0\x3d\x74\x01\x18\xc3\xac\x68\xfa\x2d\xe9\xa1\x33\x6d\x2c\x4c\xec\x0e\x03\xec\x5f\x22\x13\x4b\x32\x3c\x4d\x33\xc1\x0d\x7d\x8a\x98\x54\xab\x06\x37\x5b\xc6\xca\xb3\xe8\xfb\xb9\xcc\x86\x27\x93\x28\xd8\x88\xf2\x37\xe6\x0c\x22\xa0\x61\x30\x99\x04\x85\x87\x47\x5e\x0d\xef\xcc\x4f\x9a\xb8\x80\x12\x2a\x93\xc8\x5b\xb8\x98\xd2\x14\xf2\x0c\x22\x53\x18\x4b\x65\x13\xc9\x2c\x87\x27\x62\x68\x2a\x79\xce\x7d\x97\x64\x24\xc4\x35\xb0\x72\x6d\x13\xab\x82\xab\xd1\x67\xc1\xdd\xe8\xd6\x34\x5b\x31\xae\x56\x31\xbf\x65\x7d\x70\x0f\x5f\x62\x23\x4e\xb1\xf5\x49\x1f\xfa\xc5\xb4\x60\xae\x15\x54\x14\x72\xf3\x74\x49\x4a\x4e\xbd\x54\xeb\x54\x50\xb9\x25\x81\xd0\xe3\x24\x14\xf4\xa6\xaf\x31\xdd\xb8\x63\x8e\xf0\x15\x9d\x32\xfb\x5c\xc5\xd3\x70\xfc\xe1\x71\x08\xda\xe5\xc1\xfd\x8e\xa2\x0e\xd2\x6a\x11\x44\x21\x12\xc9\x7c\xd9\x6a\x07\xa9\x1b\x9c\x60\xf3\x78\xe8\x8a\x65\x8b\xc8\x63\x47\xc6\xe3\x02\x45\xe2\x06\x72\xd8\x5d\x0a\x9c\xd2\x04\xb6\xc5\x3f\x21\x52\x12\x2b\xf9\xe2\x43\x0a\x53\xb9\xe7\x3d\x72\x7a\xb8\xcd\xaf\xbe\x20\x15\x04\x53\x15\x7c\x0c\x10\xfa\x41\xc2\x47\x16\xac\x31\x12\xda\x56\xdf\x7c\xff\x17\xd2\x47\x0c\x2b\xbf\x35\x76\x17\xf6\xd6\xef\xd4\xd4\x84\xc8\x08\xe1\xd1\xf4\x52\x8c\xbb\xd3\x7a\xd6\x6b\xad\xe3\xc2\x0b\xe2\x37\x44\xb9\xd6\x50\x01\x86\xc5\xe5\x19\x29\x17\x52\x74\xe3\x0e\xd9\x81\x78\x26\x95\x64\x3e\x9e\xaa\xcd\x5a\x5b\x0b\xc6\xda\xd2\xaa\x56\x51\x75\x0e\x53\x6d\xa4\x32\x2d\xee\xcb\x8e\x7d\xd9\x09\xe7\x2c\xc0\x7d\xe3\x51\xc8\x17\x0f\xc1\x49\x63\xfe\x41\x4a\x68\x8e\xc4\x4e\x1a\x4c\xff\x01\x2f\xb8\x05\xf0\xf4\x0e\xbe\x92\x42\x5c\x3a\x2c\xcd\xd3\xfa\xd9\x4a\xe4\x40\xad\xff\xb2\x3c\xd9\xde\x76\xae\xb4\xc5\x4b\x52\x66\xed\x2d\x0d\x7b\x9a\xb2\x33\x4e\x4b\xb9\x2c\xd2\x43\x13\xb2\x8c\x46\xbf\x01\xb1\x68\xc5\xd4\xc0\xaf\xc0\xd1\xef\x16\x0b\xa8\x66\xa5\x5a\x25\x2f\x99\x76\x3a\x14\x8f\x79\xbf\x77\x4a\x00\x1f\x0f\x8d\x01\x60\x71\xe4\x11\x9d\xb6\x67\x32\x29\x0f\x9c\x15\x39\x26\x2a\x97\x03\xb9\x62\x29\x20\x27\x3b\x4d\x70\x68\x35\x2e\x8b\x6e\x2b\xc4\x37\x08\x56\xe9\x4f\x86\x0f\x25\xc1\xc0\x8c\x16\x47\x8e\xa3\x8f\xae\xf1\x4e\x9a\x9e\x2d\x85\x0c\xdc\x2f\xb9\xa0\x13\x28\x27\x4c\x0a\x48\xb7\x81\x33\x51\x5e\x49\x9c\x53\xe1\x3b\xed\xf7\x91\xd1\xb6\x53\x29\xc5\x8d\xd1\x10\x42\x62\x86\xdb\x31\xcb\x1a\x45\x11\xab\x35\x82\xf3\xd4\x68\x86\x6a\x61\x97\xed\x61\xc3\x9c\x35\x3a\xf0\x02\x09\x73\x5d\xc5\xd5\x41\xfa\x74\xa1\xa4\xd8\x6d\xfa\x53\x2c\xfa\x20\xc9\xfa\x17\x49\x53\x02\x3b\xcf\xfc\x2f\xb3\xec\xb7\x1f\x81\x77\x05\x1a\xb7\x9c\x8a\x0d\x1e\xdb\x83\x0e\x27\xf3\x4b\x2a\xe4\x83\x8c\xfe\x17\xdb\xc4\x94\xd9\xc6\xca\xea\x09\x24\x97\x70\xf2\x55\xf2\x88\xc7\x0e\x3b\x9a\x37\xad\xc2\xd9\xd3\xd6\xd0\xfc\xe9\x45\x57\xe8\x94\xb8\xd0\xf3\xe6\x98\x94\x7e\x46\x3c\x67\x0d\x9e\xb0\x53\xb4\x10\x10\x39\x01\x8f\x9d\xc7\x92\xa3\x50\xe2\x00\x96\xe9\x26\x4d\xbc\x1f\x4d\xa9\x96\x80\x0c\xcb\xce\xe6\xe3\x31\xbd\xa3\x3b\x0e\xbf\x27\x8b\x51\xa0\x38\x5a\xfc\x71\x38\x43\x56\x72\xbc\xa7\x05\x78\xc1\x88\x41\xfd\xe4\x33\xb8\xb0\xa4\x8f\x18\x3a\x50\x0b\x09\x1d\x59\xc5\x84\xbe\x94\x37\x9a\xd6\x77\x79\x44\x3e\x32\x78\xbe\x52\xc5\x08\x7d\x4d\x0c\x3d\x61\x79\x7f\x94\xde\x92\xec\xad\x76\x98\x8b\x17\xb2\xb9\x67\xc8\x42\x79\x2e\x14\xea\x35\xcb\x66\xfe\x5d\xa9\x40\xf2\x71\x3a\x75\x78\x54\xc0\xc2\x0b\x6f\xd7\xcc\xbf\xf1\xc2\xa0\xe2\x93\xea\xb4\x20\x58\x28\xc7\x5b\x3e\x10\x6f\x77\x3c\xd4\x01\x8e\x23\x10\x55\xc1\xb5\x44\x49\xb1\x3b\xbd\x8d\x13\xb2\xcb\x08\x49\xcc\x84\x23\x1b\x30\x17\x6d\x87\xe8\x9e\x39\x9a\xe0\x44\x3b\x33\x80\x78\x7e\x68\x04\x90\x1b\xaa\x0f\x6d\x5c\xc1\xcd\xf6\x84\x84\x6c\x19\x6a\x87\xac\x7b\xb4\x26\x5f\x98\x8f\x58\xdb\xd1\xa9\x75\xdc\xa1\xae\x11\x0a\x61\xbe\x55\x4c\xc3\x95\xc8\xc1\x95\x48\xcd\xf3\xbd\x27\x97\x84\xf3\xa2\xc5\xcc\xf8\x0e\xcc\x75\xb8\x2f\xa3\x0c\x7e\x57\x85\x4c\x0e\x86\xed\xc8\x3e\x5f\x94\xde\x27\xb8\x27\xf8\xf5\xe0\x4f\xb7\x3c\x33\x33\xfd\x91\xa5\xf9\x53\xfa\xed\xbe\xd4\x05\x45\xdc\x9a\xb0\xc0\x76\xc6\xe8\xd1\x23\xe0\x11\xb5\x2d\xcb\x00\xc0\x69\x84\x85\x92\xea\xcc\x8c\x31\xbe\xeb\x48\x77\x5a\x9a\xf7\x10\xae\xa7\x10\x03\xf8\x57\x1c\x36\x52\x5c\x12\x54\x41\xd6\xa2\x0a\x74\x83\x39\x34\x54\xd1\x84\x9b\xfd\x79\x5f\x1e\x1f\x79\x54\x05\x3a\x68\x88\x23\x89\x92\x11\xe4\x8f\x38\xb8\x48\xb2\x56\x93\xa9\x37\xa0\xf4\x0e\xef\x98\x46\xa3\x63\x17\xcf\x8b\x8d\xb3\xa1\xc2\x22\x13\xc5\x72\x4b\x61\x88\xaf\x0b\xa4\xb5\x04\xc8\xb1\xd6\x79\xa7\x15\x0d\x00\xad\xcf\x68\x28\x5d\x82\x4f\xa3\x5c\x25\x21\xdc\x25\xc0\xe8\x08\xa4\x31\xc8\xe0\xc7\xd1\xc2\x1c\x7b\x78\x24\x6b\x2a\x3d\x78\x6a\xb3\x79\xe0\xdc\x98\xa4\xfd\xb8\xd1\x84\x2a\xd5\x95\x60\x78\x88\x60\x51\xe6\x65\x91\xe4\xd4\xc3\xb5\xdb\x10\xfb\x7e\x9a\x5e\x65\xfa\x39\xa1\x95\xaf\xca\xaf\x87\x86\xa9\x46\x55\xbe\xe8\x13\x01\x7a\x3f\xe8\x5e\x6d\x98\xaa\x14\xb5\x93\x8e\x9c\x6a\x66\xba\x61\x4a\x44\x4a\x71\x9d\x53\x52\xd7\xac\xc2\x5f\xaa\x35\x82\xc6\x4f\x54\x5f\x0f\xb3\xd7\xc3\x3a\x09\x75\xa0\x7f\xfb\x42\xf6\x82\x8e\x68\x6a\x83\xf8\x13\x33\x20\xb2\x6e\xa9\x46\x68\xbf\x47\x9e\x10\xa2\xa5\xee\x1a\xfc\xb1\x10\x0e\xca\x90\x44\x46\xed\x58\x19\x9e\xd3\xb7\x49\xd8\xe7\x3a\x77\xff\x09\xa3\x9f\x71\xa2\x8a\xa8\x99\xc9\x4b\x61\x60\x53\x2d\xac\x19\x2a\x4e\x8b\x56\xfe\xed\x30\x5e\xbc\xaa\x6c\x81\xfd\x85\x77\xa4\x4b\xfe\xbd\x31\x96\xa6\x8b\x78\x6e\x0d\xd2\xc2\xb3\xd1\xfc\x29\xe6\xd8\xe4\xa4\x4f\x7e\x63\x16\x09\x2a\x9d\x1a\x83\x89\x93\x93\x5c\x4e\x0c\x99\x91\xbc\xe6\x4b\x78\x64\x3b\x08\xb5\xae\x5d\xa9\x12\x85\xec\x3d\xf4\x98\x32\x88\x8d\x76\x9c\x10\xc9\xe2\x1f\xc4\x32\xf2\xc2\xde\xe8\x58\x6c\xbf\xd4\xb8\x79\xf4\xb6\x2a\x9e\x0a\x13\x47\x60\xea\xb5\x44\x64\x4a\x9b\x51\x61\xc9\xe8\x8d\x04\x33\x14\x21\xcb\x68\xc9\xbb\x8e\xa4\x33\x40\xfb\x17\x4c\xa2\xb1\xe0\xb1\x4d\x08\x67\x8a\x1d\x83\x1a\x99\xd4\x54\x73\x96\xb4\x12\xe1\x73\x8b\x96\xc1\x58\x05\xf1\xb6\xee\x8c\x19\x4c\x55\xa6\x7f\xd0\x9a\x1a\xc4\x09\x6b\x2d\xce\x61\xa4\xda\xa6\x13\x2a\x28\xee\x5b\x04\x28\xe3\xd6\x7d\x1a\xbf\x0d\x37\x3d\x73\xc9\x46\x3a\xba\xcb\x23\xf8\xae\x4f\x3b\x56\x46\xab\xc9\xbf\x3c\x7c\xc8\xc1\x2e\x4a\x11\x28\x42\xe6\x64\x3d\xfb\xbb\xc4\x3b\x5d\x76\xf0\x4d\x5e\x81\x3d\xb2\xc7\x8b\xf4\x7b\xd6\x80\xd6\xd4\xe7\xf5\x36\xb1\x0b\x5b\x99\x21\x91\x2e\xeb\x9f\xee\xbf\x87\x88\x46\x8a\xd7\xc4\x03\x45\xa8\xea\x3f\x48\x9c\xb6\xe5\xc4\x1b\x73\xf7\xf3\x92\x13\x52\x6a\xb7\xc5\xf9\xa9\x70\xcf\x1c\x1d\xb8\x4f\x62\x7f\x4b\x09\x41\xc4\x32\x9e\xbb\x71\x11\x1d\x68\x45\x41\x2f\x5b\xe3\xe8\x79\xa0\xea\xc0\x32\xc4\xfa\xc4\xf3\x17\x1c\xe1\x3d\x5b\x76\xe3\xf3\x28\xe5\x71\x57\x80\xd0\xb1\xdd\x4f\xe1\x9b\x9b\xc7\xa5\x80\xf6\xed\xc1\xa7\x93\x9c\xab\x3e\xb5\x41\x16\xeb\x9c\x5f\x00\x1d\xbb\xed\x62\x27\xf6\x85\x17\xeb\x25\x06\x21\x8b\x71\x1c\x8a\x82\xda\xe7\x0d\x1f\x70\x39\x37\x99\x85\xf7\xbe\x34\x78\x4f\x83\x00\x18\xd2\xb9\x0c\x0e\x25\x40\x4d\x7d\x40\x29\x80\x73\x18\xff\xb8\x2f\xf0\x6f\xfe\x7c\x67\x3a\x68\xac\x88\xf9\x33\x69\xbf\x28\xb1\xdd\xa6\x6d\x7c\x80\x82\xf4\xe4\x69\x11\xb0\x0f\x80\x83\x09\x3b\x50\x26\x4f\xe7\x1b\x6c\x71\xb8\xa1\x54\x21\xda\x65\xf2\x60\x15\xe3\x12\x94\x88\xbc\x5e\x83\x09\x43\x05\x4d\x6a\xe4\x20\xaf\xe7\x2d\x6d\x72\xf1\xf1\x74\x52\x0c\xcb\x36\xc6\x41\x79\xb8\x87\xcb\x84\xec\xb4\x47\x1f\x09\x79\xdb\x32\xad\x20\x84\xfe\x56\x65\xb8\xc9\x07\x67\xd1\x6d\x9e\x17\xc5\x87\xdb\x01\x65\xaa\xd1\x05\x7a\x2d\xe3\xdc\xfa\xc8\x46\xe0\x86\xc6\xf0\x2d\x5a\x1a\x5e\xb4\x4f\xd9\xac\xa0\x6f\x4f\x0e\xb1\x36\xec\x21\xcc\x62\x08\x9d\x5b\xf2\x47\xad\x63\x52\xa2\xb9\xc1\x19\x89\xc5\xc6\xf2\xbf\x75\x77\x07\xb6\x98\xa4\x6b\x20\xb1\x05\xfc\xf8\x39\x64\x42\xb4\x19\xea\x05\x2c\x49\xe7\xf3\x9e\x56\x49\x10\x9c\x32\x48\x82\x33\xa9\x64\xfb\x2e\xda\x45\x07\x68\xeb\xeb\xf6\x6b\x98\xf9\x85\xf0\x10\x56\x24\x76\xb0\xb3\xf7\x5f\x2a\xd4\x71\xbc\x21\x38\x34\x36\xe3\xc3\x3f\x49\xc9\xd0\x50\xd4\x7c\xcc\x60\x43\xf1\x70\xf4\xa5\xd3\xb5\xd1\xbc\x47\x21\xcf\xe3\x1b\x38\xdf\xfd\xfc\xe9\x66\x3a\xeb\x7b\xba\xac\xab\x50\x0c\x96\xc8\x53\xe0\xb7\x38\x10\x99\x4d\x45\xfb\xa6\x77\x02\x93\x38\xe9\x53\xda\xfe\x86\x8c\x2e\x22\x96\x71\x74\xbc\x13\xa1\xc1\xa4\x73\x3a\xcf\x2f\x16\xe2\x3d\x17\x5d\xe3\xda\x79\x06\x27\xd5\x12\xb7\x48\xfd\x53\x2c\x75\x43\xa9\xe0\xba\x62\x72\x90\x13\xf3\xb4\x03\xa8\xbf\x2e\xf1\xe6\x5b\xfa\x86\x55\x99\x41\xf3\xc1\x33\x97\x5a\xe9\x05\x92\x27\x69\x95\x85\x4b\x4b\x78\x4e\x1f\xc0\x2a\x78\x48\x5b\xf5\x5e\x50\xd3\x14\xf7\x73\x7f\x9a\x1c\x9e\xb3\xd3\xfe\xa7\x47\x4f\x86\x20\x12\x26\x16\x70\xf8\x32\x0f\x9e\x40\x65\xc8\xe1\x3f\x41\x15\xe1\x07\xe5\xb4\xa8\x07\x7e\xec\x32\x04\xf3\xae\xf1\x02\x4c\x08\x79\xcd\x11\xf8\x69\x8b\x1f\xd1\xea\x4f\x5f\x85\x26\x0a\xd1\x8a\xcc\xcf\x10\x82\xd0\x9e\xc4\x50\x78\xf4\x20\xbc\x00\xc4\x40\x14\xab\x92\x16\x95\x54\xc2\x42\x7f\x07\xc9\xbd\x0d\xbf\x2e\x11\xd4\x16\xaa\xf3\xe2\x96\x7f\x8e\x78\xf9\x5b\xeb\x99\xe2\x82\x21\xea\x62\xdd\x43\x2c\x0b\x80\x75\xea\x13\x86\xc6\x28\xa5\xf1\xa5\x84\x5f\x65\x24\x77\xe4\x43\x47\x47\x3f\x73\xa2\xb7\xa0\xf1\x9f\x28\x06\x17\x42\xbf\xae\xaa\xa9\xfa\x9a\x60\xd0\xbf\x6f\xa3\xfb\x0e\xc0\x99\x8e\x49\xca\xa4\xff\x5d\x0e\x1b\xc1\xec\xac\x0c\x0f\xa3\xba\xd5\xa8\x3d\x42\x67\x52\x53\x03\x18\x5d\x8c\x2c\x67\x79\x28\x7e\xf6\x6b\x82\xa1\x78\x01\x23\x51\xe5\x68\x1e\x7b\xe9\x81\xb1\xcb\xb8\x72\x56\x0a\x84\xea\x14\xc4\xb5\xda\x2d\xf2\xd4\x26\x3a\x1a\xa2\x61\x5f\x48\x26\xe4\xe1\x57\xa2\x68\x82\x7f\xa5\x73\x6a\xed\xd1\x34\x75\xa0\x93\xf8\x70\x10\x91\x59\x60\x28\xd3\x7b\x3a\xa0\xdd\xdc\x3f\x2e\x8e\x2b\x24\x68\xc1\x39\x28\xf8\x0f\xb6\xf0\xc2\x21\xe7\xcc\xe2\x86\xd8\xe5\x1a\xda\xef\x6e\x2e\x99\x68\x11\x30\xee\xc6\xeb\x04\xd8\x7c\xb0\x4a\x46\x4a\xb5\x46\x32\x56\x9f\x8b\x84\xfa\x50\x67\xd7\x9b\x26\xfe\xbd\xca\x0c\xca\x5f\x48\x81\xe3\xf2\x59\xb9\x46\xf5\xd6\x41\x77\x51\x85\xe7\xc4\xc6\xc1\xa6\x5d\xe1\xe1\xae\x5e\x9e\x09\xb8\xbd\xa2\xc9\xb1\x70\x5b\x96\x23\x3f\xe3\xd9\x17\x53\x38\x52\x69\x22\xe9\xb4\x57\x96\x6f\x41\xa9\x82\x8b\x8c\xfe\xbe\xd7\xd7\xf5\x33\xab\xba\x86\xa8\x49\xe6\x44\xe5\xe0\xce\x6b\xde\xfc\x4e\x93\x81\x9c\x2e\x4a\x96\x42\xb7\x5f\x9c\x79\x2a\x55\xa4\xaf\x8a\x38\xe7\xf4\xa8\x4a\x03\xc0\x11\x84\xdb\x18\x52\x51\xc1\x84\x8f\x7a\xcd\xbe\xd7\xb7\x63\x74\x13\xba\x1a\xac\x50\x7f\xf8\x85\x7e\x22\xc0\xd4\xee\x6c\x5f\xe3\xf2\xf1\xdb\xc7\xc9\x6b\x96\x03\x11\xe7\x19\xac\x14\xa7\xf1\x1f\xeb\xf7\x1c\x90\xb6\x84\x42\xab\xc4\x80\x3e\xef\xbf\x92\x59\xf4\x6a\x25\x34\xc1\x8a\xaa\x6f\xea\x3f\xfd\x0d\x17\x6c\x0a\x09\x46\x79\x01\x72\x53\xc9\x91\x58\xc2\x1f\x58\xd7\x02\x07\x7e\xf1\xfe\x64\x99\xd4\xef\xd1\x24\x45\x0d\xdc\xb6\x90\x6c\x5e\xcf\x81\x8e\xef\x5b\x82\x77\xb5\x8e\xf1\x38\x23\xbf\xec\x18\x86\x0d\x24\x39\x07\x99\xb9\xe4\x2d\x49\xe8\xe7\x80\x32\x1f\xd9\x0c\x13\x5e\x54\x27\x70\xd9\x9c\x5b\x0f\xd1\xb6\xeb\x96\xd4\x9b\x88\x00\x85\xe0\x2b\xa1\x72\x39\x51\xa3\x81\xf9\xe0\x91\x49\x04\x09\xa0\xbf\x3c\x00\x8a\x5a\xb6\x96\xc1\x6b\x42\x42\x1d\x44\x3f\xe7\xfa\x9b\x90\xf2\x83\xd2\x7b\x7f\x1c\xef\x24\xa8\xad\xce\xa5\xc8\x10\x06\xce\xc7\xf6\x1b\x62\x0f\xf4\xd2\x30\x48\x59\x51\x7f\x6a\xc4\x62\x6c\xed\xef\x07\x79\x77\x22\x77\x7d\x09\x24\xd2\xd8\x74\x32\xa1\xdb\x57\xed\x4c\x16\xc3\xb1\xc9\x23\x20\x1c\x96\x9d\x6b\x4b\x6c\xa2\x6c\xa8\x47\x72\x50\x18\x23\xe4\x0b\x43\x76\x5c\x30\xca\xc9\x04\xeb\xe5\x0e\x11\x18\xc8\x45\x62\x7c\x90\xd1\x97\x5b\x32\x34\xd5\x7a\x68\x80\x7d\xec\xb6\xb1\x36\xef\xdc\xea\x55\x5f\x58\x0a\xf7\xcb\xe5\x0e\x53\xdc\xfc\xf3\x52\x2b\xd1\xff\x36\x5c\x35\x1d\x38\xc6\x65\xd8\x78\x9c\x63\xa5\xa6\xc2\xca\xd6\x23\xe7\x13\x01\x5c\x92\x2a\xbf\x9c\x95\xe7\x87\x60\xc3\x6d\x85\xa2\x7c\xf6\xba\x4e\x11\x6e\x53\x08\xbc\x2f\x0c\x24\x66\x39\x48\x8c\x39\x10\x3c\x22\x94\x2d\x12\x51\xef\xc9\xf6\xb4\xf1\x03\x10\xb0\x5d\xf2\x2f\x61\xd0\xce\x88\x92\x4f\x93\xea\x99\x7b\x50\x36\xb7\xb2\x65\x6d\xae\xce\x4e\x55\xef\x78\xc9\x3e\x4c\xfc\x7d\xf9\x11\x3f\xc5\xff\x74\x16\x74\xce\x7e\xe6\x93\x97\xb5\x56\x86\x6f\xcb\x2b\x29\x77\x38\x2b\xd9\x50\x4d\xa9\x57\xa1\x54\x67\x6d\xc2\x8a\x9f\x4e\x3b\x99\x90\x0c\x2f\x98\x56\x1a\x0f\x5e\x75\x56\x21\xa6\x0e\xdc\x3a\x84\x3e\x20\x21\x45\x06\x9c\xaa\x67\x82\x12\x4d\x74\xb2\x5b\x15\xd1\x0a\x21\x49\xf8\x17\x78\xbb\xc3\xe8\x77\x6e\x0b\x8c\x81\x85\x4a\xe5\x54\x44\x6d\x49\x3d\xe4\x8d\xeb\x46\xab\xf3\xe2\xa8\x09\x0e\xcf\xf7\x91\xb8\x2f\x54\x82\x28\xc1\x51\x71\xa7\xe8\x29\xc0\x11\xaf\x10\x1c\x4d\x10\x11\x1c\x81\xf2\x74\xf2\xed\x08\x83\x98\xb3\xf2\x66\xa6\xce\x1b\xbe\xe1\xf5\xf7\xb5\xb1\x44\x1e\xe8\x33\x0d\xc0\xa8\x65\x8e\x95\xb8\x87\xe6\xe0\x33\x03\x93\xe6\xa8\xf9\x8c\xe7\x4a\xf9\x3e\x8b\x98\xca\xdc\x0b\x3a\x97\x56\x87\x10\xfe\x05\xcb\xc8\xe2\x5b\x6e\x81\xf5\xb4\xf9\xbe\x60\x02\xaa\xd9\xc5\xab\xb9\xb3\xfa\xe5\x44\xb4\x57\x10\xb2\xc5\x10\x2b\x06\xcc\xdd\xc6\x7a\xf7\x4f\x97\xc6\x22\x60\x52\x79\x79\x67\xea\xdd\x9b\xe3\x52\x89\x52\xad\x12\xa6\x43\x83\xd7\x93\x6a\x83\x22\xd1\x2b\xd3\x11\x4d\x42\x11\xa2\x47\xa8\xd5\x7c\x0e\x89\xf5\xf7\xb3\xfd\xa6\x5a\x48\xa8\x9b\xdf\x26\x97\xc9\x05\x0a\xe2\xfa\x2e\xca\x45\xb3\x8b\x4d\xe4\x73\xc8\x01\xff\x8b\x37\x4f\x72\xdc\xda\x43\xf6\x73\xd0\x25\xe5\xe1\x17\xfd\x0e\x50\x4f\x69\x57\xb9\x88\xe3\x8c\x70\x8f\xd2\xe8\xba\x87\xf6\x62\xcb\x12\x8d\xa1\x23\x04\x6f\xbe\xdf\x67\xd8\xd8\x3b\x04\x97\xdd\xce\x5b\x83\xb5\xb1\x80\xfe\x38\x1a\x76\x33\x45\x24\xb8\x3d\x8b\x4f\xa0\x03\xe5\x8b\xdf\xe2\x24\x0b\x58\xcb\xdf\x1a\x42\x8b\xe1\x31\xf7\xab\x89\x1e\x61\xf8\xc8\xfe\xbb\xd6\x4f\x75\xb3\x72\xee\x45\x7c\x08\x16\x3e\x99\x6b\x6e\x9d\x22\x72\x32\x08\x89\xea\xd8\x80\x61\xb5\xd0\x9b\x78\xc8\x81\x0c\x9d\x6a\x8b\xd4\xb7\x7a\x52\xbb\x49\xe3\x0c\xc9\xa7\x60\xf1\xfb\xb2\xac\xce\x79\xf0\xf9\x0d\x9b\xb3\x27\x6c\x28\x75\xf3\x88\x92\x67\x7c\x76\x88\xaa\x8a\x4a\x15\x9e\xeb\xbb\xd4\xc6\xfe\x65\x5d\xac\x0e\x1d\xb2\x89\x6d\x1c\xcf\xc0\x88\x64\xaf\xfa\x64\x2e\xe2\x15\x00\xd2\x1d\xff\x38\xd3\x1f\xbd\xea\x60\x3c\x8b\x2f\x5e\x28\x61\xe7\x4a\x64\x62\xaa\x7f\xd0\x45\x93\xe1\xff\x72\xdb\xee\x6a\x94\x4b\xa9\xcb\xe3\x40\x6c\xbb\xd3\x84\xcd\x9b\x96\xa0\x02\xc2\xa8\x40\x95\x56\x97\x41\x36\x57\x4a\x07\x1b\x25\x13\x6f\xa7\x9c\x6c\x0a\x62\xb1\x4b\x54\x92\x5f\x69\x8d\xa9\x8e\xfa\x31\x39\x0c\x81\x86\x74\xa5\x98\xcc\x87\xac\xb6\x6b\x63\xaa\x59\xd6\x16\xe0\xc6\xd6\xa2\x3c\x2c\xe3\x60\x34\x56\x92\x3c\x51\x55\xe3\x75\x61\x48\x1d\xaa\xaa\x77\x78\x3c\x72\xe1\x1d\x25\xd5\x88\x8e\x98\x75\xc9\x02\x3b\x46\x31\x9b\x5b\xe8\xde\x34\x84\x43\x3c\xd3\x20\x19\xf2\x28\x87\x4e\x49\xe7\x50\x98\xc7\xe4\xcd\xcb\x07\x7a\x48\xa8\xbf\xeb\x44\xb7\xb9\x73\x26\x77\xc2\x1c\xbe\xd3\xbc\x75\xdc\xc5\xfe\xd8\xff\xc0\xea\x26\x90\x38\x88\x79\xfb\xfa\x03\xbf\x5c\x16\x30\x66\xfc\xbb\x9b\x00\x58\x94\xb2\x80\x58\xb6\xb6\xfe\x0f\x9d\x9e\x18\x0d\x49\xcc\x55\x06\x18\x73\x59\x77\xdc\xcd\x7b\xa3\x9d\x28\x88\xe1\xbb\x6e\x90\x7f\x46\x8b\x60\xa5\x56\xc8\xca\xd8\x9d\x56\xbc\x9a\x8c\x9c\x6d\xc9\xd1\xdb\x63\xa9\xa0\x9b\x02\x98\x81\x1a\x37\xe4\x7c\x36\x1a\x12\x6d\x7d\x3e\x27\x9d\xc2\xfd\x93\x50\x56\x3a\x43\x6a\x04\x6a\xaa\xb0\x45\xf6\xf1\x0c\xf4\x23\x93\xb3\x06\x30\x87\x40\x43\xb4\xe8\xb8\xb7\x46\x16\x7f\x74\x21\x5f\x86\x21\x4b\xee\x8d\xd6\xa6\x68\x71\xe4\x59\x1a\x7d\x16\x3d\x1f\x78\xbb\xbc\x2b\xcd\x13\x1b\xa6\x45\xc4\x11\x31\x9f\x2a\x1c\x25\x91\x50\x98\x28\x8f\x67\xfa\x53\x93\x21\xb7\xdd\x30\x8a\x6f\x07\x59\x49\xcc\xc4\xe8\x54\x17\x0b\x98\x76\xc6\xf2\xfd\xa7\x16\x35\xf1\x8f\x70\x00\x29\x16\xb9\x74\x19\xae\x65\x72\x1f\xe1\x27\x8b\x3a\x49\x44\x0d\x90\x33\xde\xa0\xda\xa3\x69\x66\xfe\xaf\x39\xab\x35\xd4\x4b\x6d\xc1\xf6\x87\xe6\xc5\xf5\x4f\x25\xfc\xa4\x6b\x24\x16\xca\x4e\x92\x79\x53\x59\xe4\x8e\xec\x66\x1f\xd2\x92\x7c\x26\xf2\xe1\x06\x17\x6b\x4d\x7e\xde\x06\x6f\x0c\x5c\x46\x51\xc2\x29\xa5\x41\x0c\xa1\x67\xce\x8b\x77\x52\xbf\x0f\xa9\xd9\x21\x15\x63\x2b\xea\x12\xc1\x9b\x76\x60\x9f\x2b\x9a\xa5\x0f\xa1\x59\x93\xfa\x9e\x57\x47\x91\x69\xf3\x77\xa0\x6b\x6f\x7a\x44\x67\xa4\xab\x0d\xfd\xce\x4f\x6a\x19\x3d\x5d\x99\xb9\x59\x80\xf5\xba\xf2\xb9\xd2\x53\xeb\x8f\x38\xaf\xc8\x80\x25\x01\xa7\x15\xd5\x89\x4b\x25\xac\x21\x83\xea\x2d\x48\xb3\x51\xf0\x8f\x56\x91\xf3\x2b\x03\x3a\xe8\xde\xf7\xaf\x03\x1f\x58\xaa\xe3\x25\x1a\x1b\x68\x76\xf9\x76\xe0\x3a\x2f\xb2\xbb\x4e\x4c\xa8\xb1\x50\x94\x75\x8c\x75\xb7\xe7\x5f\x51\x08\x9a\xab\xf3\x20\x2a\x1a\x55\x12\xa8\xf9\x84\xaa\x9e\x20\x51\x0f\x90\x2f\x3f\x95\xf3\x37\x56\xc9\x3b\x0d\x10\x23\x55\x11\xa5\x7c\x4f\x2a\x82\xba\xca\x17\x0b\x07\xb3\x56\x6c\xba\xd3\x22\x3e\x78\xb5\x46\x3a\xea\xef\x4d\xca\x96\x03\x78\x73\x92\x71\xe3\xaf\x47\x8d\x41\x42\x9b\x96\xdc\xeb\x6c\x6d\x08\x0e\xae\x34\x0e\xec\x3c\xb6\x15\x2e\x59\xd9\x21\x99\x02\x83\x60\x82\xe8\xc2\xf6\xeb\x85\xbe\xf5\x07\x0b\x95\x61\xff\xcb\x5d\x63\x78\x2a\xc7\x6c\x4c\x11\xb6\x4b\x69\xd9\x9e\x60\xc7\xc5\xd3\x9d\x65\x8d\x50\xdf\x2d\xe0\x42\xb6\xe5\x99\xe2\xfe\x0d\xad\x31\xbb\xee\x20\x96\x3b\x77\xf0\xf6\xd7\xae\x38\xdf\x52\xb3\xdf\xb5\x4a\x99\xac\x52\x14\xef\x1a\x08\x5e\x3f\x6a\x9a\xcd\x0d\xd7\xe2\xbe\x17\x23\xea\xb5\xa7\xc1\x36\x7f\x32\xe2\x5e\x20\x30\x88\xc9\xb8\xf6\xfa\x48\xd0\x92\xa0\xd0\xcd\x36\xec\x50\x6e\x5c\x80\x3e\xe0\x97\x64\x6d\x55\x94\x99\xd6\xdc\xe9\x21\x82\x59\xa6\xb5\x54\x95\xb7\x3f\x72\xf9\x62\x0e\xa4\x68\x84\x43\xfc\xda\x6d\xec\x72\x45\xd4\x71\x60\x3b\x21\x0c\x5b\x74\x41\x14\x96\xba\x1e\x24\xb8\x7f\x9c\xf4\x08\x62\xbf\x8b\xd5\x7c\x19\x33\x8b\x1e\x83\xdb\xb6\x4c\x4a\x20\xf9\xbc\xcd\xbe\x2d\xd6\x05\x54\xa2\x70\xdf\x95\x42\xa8\x6c\x32\x4e\x8e\xa2\xfd\x11\x52\x1f\x3f\x3b\xb2\x4a\x00\x22\x95\x8c\x43\x7d\x33\xe1\x39\x25\x84\xfb\xbe\x5c\x05\xbc\x82\xbf\xfd\xf5\xd8\x34\x14\xa5\x1a\xea\x81\x42\x15\x35\x2d\x68\xc7\x4b\x3d\xd8\xdf\xa5\xb8\x43\x24\x7a\x63\x4c\x45\x9b\x9a\xd0\x48\x2c\x7c\x2e\xd1\x13\x3f\x1b\xf3\xa1\x87\x39\x39\xc0\xe3\x08\xd2\xaa\xb1\x3a\x50\xd2\xb1\x54\xaa\x53\x20\x6c\xf9\x7d\xe5\x4e\x53\xc2\xe6\xc3\xec\x1c\x3d\xfa\xc6\xf9\x53\x2d\xfa\xf8\xe0\x49\xd5\xca\xd9\x60\x43\x21\xb0\xef\xd9\xb2\x75\xca\x11\xf9\xd9\x40\x5f\x0b\xc9\x15\xbc\xd0\x60\x55\x4e\xdd\xaa\xab\xa4\xcc\xce\xcf\xcc\xad\x34\xd7\x7b\x2f\x0d\x71\x8d\xe9\x77\x93\xe6\x47\xad\x5c\x35\x2b\x64\x65\x3e\x7e\xef\xe5\x8d\x42\x71\x88\x54\xd6\x25\xc8\x55\x68\x70\x2f\x87\x8d\xb0\x2b\xce\xd0\x03\x3a\xd5\x9b\xd7\xc2\x75\x2a\xc2\x08\x24\x90\x51\x56\x13\xac\x55\x22\xb2\x11\x51\x27\x27\x44\x75\x42\xb3\x0f\x43\x8f\x10\x74\x62\x67\x09\xd3\x9d\x24\x0e\x3c\xd9\x23\xe8\x62\xc8\x70\x01\xe1\x47\x8c\x62\xfd\xee\x47\xa1\xcc\x1a\x39\x63\x7d\xf9\xba\x9f\xab\xe9\x73\xb3\xe6\x88\x45\x1d\xaa\xe2\xe9\x82\xd5\x5e\x12\xd6\xc7\x57\xc1\x9a\x05\x06\x0a\x48\xfd\x0f\x8a\x35\x57\xf1\x59\xd9\x52\xdb\x52\xe5\x5a\xdf\xb2\x78\x53\x4a\xc9\x34\x62\x06\xc2\xfe\xa6\x96\x9f\x14\xfa\x3f\xeb\x01\x73\xf1\xab\x1d\xb8\xd6\xdf\xbf\x4a\xf1\xa0\x79\x70\xac\x98\x61\x89\x97\xcd\x1c\xd3\x4c\xac\x18\x54\x3b\xab\x0e\x68\xa2\x91\x3b\xa4\x47\x11\xfc\x75\x65\x44\x2f\x51\xd5\x09\xa3\x74\x55\x2b\xbf\xcc\x43\xe7\xc3\xd5\xd2\x74\xf3\xfc\x44\x77\x5a\xe9\x00\x44\x9a\xf7\x96\xd3\x6a\x97\xc9\x06\xe2\x20\x0c\x25\x0e\xea\x1d\x56\x4b\xfc\xa3\x27\x9e\x7d\xbf\xc4\xa1\x66\xee\x61\x60\x75\xfb\x7d\xc2\xd4\x41\x43\xfb\x85\xae\x58\x2d\xcd\xe7\xe4\x60\x4d\x5f\xa1\x03\x5d\x4b\x4f\x02\xdf\x24\x89\x04\x5e\x69\x98\x8e\xa5\x50\x03\x15\x52\xb8\xfb\xe1\x61\x97\xf4\x4c\x6c\x75\x44\x7c\x26\xf5\x99\x35\x49\x7a\xb3\x76\xc4\xaf\x8a\x59\x8a\xc4\x41\x15\x21\x12\x72\x95\x37\xcd\xa4\xcb\xdf\xb6\xc7\x86\xfc\x45\x11\x3e\x5f\x54\x8d\x34\xe5\x88\xe5\xc7\x43\x36\xd2\x4f\x32\x3c\xbb\xcc\xdf\x16\xcc\x21\xe6\x17\x0f\x50\xa9\x76\x4a\xab\xd4\x55\xc7\x52\x99\x6b\x67\xbd\xec\x7c\x2c\x53\xff\xa4\x70\x05\xdd\xd0\xaf\x5c\x4c\x3c\xcb\xe7\x7a\x0f\xe6\x6d\x6d\x99\x23\xc4\xc8\x16\x13\xc9\xeb\xb4\x10\x7d\x63\x8c\xfe\xfc\x1d\x3c\x3a\x05\xfb\x7d\x1a\x3d\x77\x59\x31\x57\xa2\xfc\xe0\x9b\xb8\x03\x33\xdf\x01\xf8\x81\xfa\x91\xfb\xf0\xa0\x40\x39\x60\x5c\x02\x19\xb5\x79\x7c\x47\x0c\xb7\x54\x84\x3b\xde\x0f\xf1\xc9\x06\x8d\xe1\xc4\xc4\x20\x38\x02\x55\x07\xa9\xb3\xa6\x98\xc7\x83\x78\x84\xe5\x98\xdf\x53\x63\x75\xd1\x6b\x8a\x48\x75\xfc\x86\x8f\x10\x22\x8b\xc2\xfd\x69\xae\xf8\xc4\x2e\x87\x9f\xee\x98\xab\x7e\x1f\x98\x36\xfe\x25\x74\x84\xea\x5f\xc0\xd8\x2c\xf9\x12\xa5\x16\x13\xb0\x46\xba\x49\x3d\x52\x4a\x68\x1d\x95\x79\x44\x08\xe1\x07\x7b\x25\xd8\x1d\xc4\x7f\xf1\x4a\x1e\x0c\xbc\x38\xd1\xa1\x78\x67\x29\xba\x48\xfb\x71\x0c\x15\xde\x1f\xd1\x50\x24\x54\x90\x9b\x52\x49\x1c\xfd\xe4\x74\x5d\x28\xed\x6f\x93\x9a\x68\x75\xc7\x49\x72\x36\x3a\x88\x43\x62\x88\x76\x58\x53\x4f\x66\x66\x40\x30\x89\xe1\x46\x8f\x08\x6d\xeb\x0d\x75\x0a\xfe\xc8\x70\xdb\x73\x1e\x15\xb9\x0f\x6d\x66\xd3\x7f\xef\xb5\xff\xc8\x7e\xfc\x7e\xff\xf1\xa2\x7c\x00\x5e\xa0\x86\xc4\x70\xef\x9d\x7e\x11\x3f\xce\x31\xda\x15\x4e\xff\xf8\x86\xb0\xed\x71\xe2\xee\x06\x91\x3f\x7a\x9f\xa3\x29\x47\xdd\xc7\x52\xa3\x13\xc7\x14\xff\xe2\x97\xe9\x76\x73\x32\x4b\x22\xa3\x37\xea\x3e\x01\x4f\xd3\x7c\xbe\x3c\x2d\xea\x5c\x61\x68\xf9\xa6\x49\xcb\x0b\xd4\xb4\x90\x82\x4f\xa3\xc0\x70\xd6\x77\xbf\x41\xb7\x25\x76\xc5\x85\x9f\xb0\x65\xc8\xbb\x84\xed\xf3\x94\x58\xfc\xeb\xe2\x96\x74\xcb\x98\x9e\x83\x00\x9f\xaa\xab\xc7\xbf\xa7\x8d\xa7\x83\x2c\x7a\xec\xe5\xfd\xe7\xca\x93\x53\x29\x42\xca\x4b\xfe\xcd\x56\x53\xe9\x8d\xf1\x05\xee\xaa\x22\x3a\xdf\x4e\x9a\x18\xfa\x79\xb2\x6f\x2c\x84\x03\xed\xc5\x9a\x3a\x3c\x9e\x4e\x12\x12\x8d\xa8\x71\xe6\x69\x9c\x4f\x06\xf6\x0f\xb1\x88\xb5\xe4\x29\xe8\x78\x9d\xde\x1a\x95\x76\x75\x6f\xfa\xc6\xd9\x25\xdd\x1f\x73\x23\xa0\x90\x7e\x0f\x45\x9c\xa6\x2c\x9f\x53\x54\xc4\x5f\x32\xdf\xe6\x28\x01\x42\x71\x0d\x82\x01\xe4\x51\xd5\x05\xd5\x29\x7c\xbc\xae\xd5\xdc\x0f\x1d\x4a\x83\x26\x05\x9d\x50\xcb\x6d\x83\xc5\xb1\x33\xa4\x75\x46\xb0\x30\x3e\x21\x39\x20\x45\x2d\x62\x4f\x02\x78\xbe\xee\x84\x58\x0d\x1d\x0c\x02\xcd\xf2\x0d\x02\x55\x79\xbc\xe9\x9b\x8a\xfc\x80\x5a\xbf\x0c\x3c\x5a\x2f\xbc\x5f\xc2\x2b\xe5\xb5\x03\xa0\x85\x93\x8f\x5e\x7f\x9f\x8c\xe1\x99\x8d\xc6\x67\x10\x98\xa3\xbd\x7b\x6a\xa0\xf7\xc2\x15\x1d\x35\x1c\xd3\xdb\xaf\x83\x35\x6d\x78\xcc\x51\x11\x0b\xd7\xc2\x05\x41\x15\x1a\xe5\xaf\x42\xea\xf0\x30\xae\x70\xfc\x7c\xda\x91\xad\xa4\xe6\xf2\xbd\xbe\x5e\x9c\xb5\x1a\xb0\x61\xb5\xba\x23\xa7\x8e\x3e\x15\xfc\xb7\xbf\xa6\x74\xa4\xcc\x78\x0d\x8e\x08\xe5\xe5\x73\xb6\x98\xe8\x0d\x10\x20\x3c\x37\xab\xc8\x06\x3c\x7c\xfc\x9a\x7b\xf1\x5e\xbf\x5a\xea\x67\xd2\x86\x2e\x38\xf8\xe9\x0a\x56\x56\xcd\xb7\x1f\x23\xb8\x38\x7b\x6c\x06\xfd\x2c\xc9\x43\x31\x36\x4f\xa2\x6b\xdc\xae\x21\x5b\xaf\x49\x22\x5e\x4c\xcf\xc4\xb2\xa3\xe2\xf0\x03\xc8\x22\x15\x41\xcb\x43\x87\xc7\x97\x4d\xbc\xdc\xb5\xe5\xf0\xa1\x33\xe2\x3f\x8c\x5e\x7d\xa0\x5f\x79\xe2\xf7\x32\xa8\xd8\x86\x36\xba\x0e\x99\x87\x85\xae\x0a\x0c\xbe\xd2\x08\xc7\xde\xbb\x21\x30\xb0\x69\xae\x11\xa6\xed\x61\xb0\x7a\x86\x0c\xe0\x1c\xbd\xc0\xbb\x3c\x7d\xf1\x22\x66\xbc\xe4\x4c\xbb\x97\x1d\x47\xfa\x56\x3e\xa0\x50\xc7\x16\x99\xcc\x59\x05\x43\x7a\xad\x68\x30\x45\x65\xea\xf3\xa3\x5b\xe5\x28\xcf\xc5\xfa\xf5\x9d\x8a\x82\x49\xe8\xeb\x53\x7e\xad\xa9\x9c\xa4\x03\x53\xf7\x9c\x12\xfd\x6f\x15\x85\x03\x83\xa4\x52\x4d\x35\x1d\x4c\xaa\x1b\xef\x6f\x68\xda\x74\x1d\x7f\xf7\xa8\x90\x31\xc4\x59\xef\xd0\x7d\x16\x37\x49\x01\x90\x46\xb0\x58\xc5\xf0\xa5\xbb\x41\xd8\xb5\xa7\xba\xd4\xf5\xf2\xf5\x15\x19\xc2\xf0\xe3\xa6\xd8\x1f\x0c\x56\x72\xde\xc3\x29\xc9\x0f\x6d\x3f\x15\x58\xd2\xbf\xbd\x45\xf3\x9c\xc1\x8c\x08\x05\x3b\x33\x2e\xdc\x22\x8a\x30\x2e\x84\x3c\x04\x57\x45\x21\x8a\xbc\x42\x0d\x91\x95\x0d\x98\xc2\x07\xdd\x48\x75\x2f\x49\xe8\x01\xe1\x18\xa5\xf2\xe2\xff\x4c\x4f\xd3\x4a\x48\x43\x6b\x12\x60\x4e\x2c\x92\x88\xf1\x30\x4e\x72\xc5\x3b\x4d\x00\x34\x8b\x02\x56\x89\x53\x6d\x38\xe1\x4a\x07\x6f\xe8\x89\x31\x3a\x14\x3a\x0d\x55\xfc\xf6\x8a\x90\xe3\xcb\x92\x50\x25\xe7\x49\xcb\x39\x13\x6c\xc6\x6d\xb2\x34\x97\x17\xd8\xec\xdb\xb4\xe0\xbf\x11\x11\xf0\x73\xa9\x4b\xa1\x46\xd9\x2c\x90\x7e\x76\x2f\x5c\x19\x35\x14\x5d\xd3\x32\xbd\x10\xff\x87\xb5\xe5\x00\xd8\xcf\x2b\xcc\xa4\x68\x94\x9c\x85\x51\x14\xf3\x99\x1d\x1d\x0e\xd1\x9e\x55\x6e\x3c\x5e\xff\x87\xea\x78\x97\x8c\x08\xe6\x2f\xc3\x76\x66\x2d\xe4\x2d\xa4\x85\xbb\x1a\x46\xe7\xec\xae\xa1\x26\x2e\x24\x18\x32\x19\xde\xd6\xf3\x9f\x9d\x9f\xa1\xed\x7d\x28\x88\x9a\x4b\x1b\xb6\xf3\xd2\x8c\x7c\x28\x77\x39\x1d\x21\xf2\x64\xb9\xfa\x2c\x55\xac\xb3\x91\x5b\x06\x3d\x95\x21\x75\x54\xc4\xeb\x2a\x7c\xd0\x6a\x74\x46\x8a\xd1\x8c\x06\xb7\x83\x5e\xe0\x58\x93\xec\x87\xdb\xbd\xbb\xcb\xa3\x3b\x3f\xc4\xdb\x41\x37\x7a\xda\x20\xc3\x35\xb6\x74\xd4\xc3\x7a\xf1\xaf\xe9\xf2\x68\xa7\xd3\x9a\xbd\x6b\x4c\x95\xf0\x39\xb5\x1d\xaa\xbf\xa4\x4a\x35\xe4\x3b\xd9\xb3\xb3\x3e\x9c\x58\x8a\x99\x09\xe3\x3b\x99\x4e\x34\xfb\x74\xd2\xa3\xcd\x5d\xe8\x32\xa6\x47\x75\x90\xb4\x71\x53\x97\x92\xa7\xe8\x5f\x44\xb3\x83\xe1\xc0\x29\x49\xcd\x4d\x7f\x99\x7e\xb2\xa0\x21\x0f\xdb\xc9\x9e\x72\x48\xaa\xb7\x96\x8f\xbd\x08\x45\x72\x77\xce\x06\xa1\x56\xcc\xd4\x0b\xd1\x9c\x23\x99\x76\x8e\xcb\xea\x10\xc1\xe1\xd8\x7a\x75\x5a\x6c\x45\x79\xc8\xd8\xc1\x9d\x80\x10\x90\xe7\x94\xf8\x6b\xf1\xfd\x3e\xb7\xbd\x0a\x3b\x1e\x04\x3d\x4c\x58\x7b\xcb\xd1\xfc\x88\xef\x24\xed\xf9\xae\xc5\xd0\x91\x4f\x8a\x53\xc4\xb5\xf0\xdd\x94\x62\x5b\x89\x07\x8e\x87\x7d\x48\xc9\xa2\x19\x53\x97\x87\xad\x4a\x4d\xd1\x4e\x73\xea\x0f\xaa\x58\xa4\xc8\x7d\x36\xef\xe2\xed\x2b\x3f\x6d\x52\x16\x6b\xbb\x76\x85\x53\x33\xe9\xb3\x76\xc8\x1e\xfa\xbc\x39\x82\xe5\x3b\x5c\x34\x6c\x57\xca\x42\x2b\xbb\xcb\xad\x9f\xc4\x87\xf2\x59\x4a\x80\x26\x5a\xf7\xd2\xf8\x10\xcc\x81\x8a\x5c\x4b\x3c\x11\x09\x47\xcd\xd9\x76\x2f\x94\x5a\x4a\xfc\xcc\x6a\x17\xc8\xd7\x2b\x8a\xf2\xed\xa6\xf5\x34\xa3\x5d\xf4\x02\x47\x23\x9b\xfa\xb5\x8f\x2f\x6f\xcd\xe7\xc9\x5e\x8a\x56\xfa\xda\xc9\x9d\x1f\x61\xef\xf3\x5d\x28\x2f\x8a\xb3\x9b\x7f\x20\x9b\x93\x0d\x9e\xe8\x03\x2a\xa6\x51\x03\xae\xe1\xd4\x5e\x81\x4b\x38\x06\x8a\x50\x74\x3b\xfe\xc9\xf2\x24\xfe\x74\xfc\x5d\x4f\x98\xe9\xe8\x72\x1a\x49\x58\x83\x07\xfa\x66\x01\x5b\x4c\x59\xa1\xd8\xd1\xdd\x91\xd3\x31\xdd\xd0\xa9\xf2\x1b\x3c\x46\xad\xb0\x95\x2e\x51\xbf\xee\x9a\xfe\xa2\x5c\x24\xce\x32\x7e\x1c\x59\xf8\x1c\x95\x77\x22\xea\x2a\xf5\xeb\xe8\xa9\xb9\xbb\x98\x74\xf2\xad\x29\xa0\x25\xb9\xd4\xff\x3d\x21\xed\xdc\xd4\x82\xdd\xfb\x2e\x9d\x60\x49\xd4\x52\x21\xf4\xf8\x8f\x5a\xfb\x25\x96\xd8\x9b\x18\x65\x78\x83\x34\x10\x74\xf4\xd5\x95\xe2\x97\x1b\x05\xf9\x17\x48\xeb\xb3\x49\x99\xb2\x47\x5b\x0b\xc1\x7a\xc5\x8a\xa6\xee\x45\xda\x57\x64\x7a\x20\x83\x15\x8a\xcc\xf4\x7d\xa8\x75\x6c\xdd\x4c\xa6\x7a\x8b\xc0\xbf\xd0\x3e\xee\x72\x07\xd1\x67\x94\x44\xb5\x04\x46\x92\x7b\x16\xa6\xcf\xec\x92\xec\x03\xc1\xa6\x6c\x6e\x85\x31\x10\xf7\xdd\xed\x0f\x41\xfc\xb9\x7b\x14\x9a\xb6\xdc\x79\x1f\xd2\x70\x08\xce\x50\x8b\xb4\x1b\x1c\xe7\x6f\xa6\xe1\x39\x04\x49\x09\x92\x5c\xf4\xe3\x3d\xd8\xa1\x9a\xbe\xc3\x1e\x38\xc5\x95\x65\xc6\xbe\x57\x77\x3f\x39\x80\x48\x69\xeb\x69\x14\x87\x51\xfd\x4b\x3f\xef\xd9\xc8\xe5\x5d\x3e\x07\x3d\xf7\x1c\x4b\xf4\x15\x0e\x76\xb6\x89\x6c\x3c\x01\xf2\x2d\xe6\xcd\xa2\xfc\x52\x30\xa0\x0a\xb0\xea\x49\x9a\x96\xe7\x8e\x3f\x39\x3b\xb4\xcd\x72\x8d\x77\xd2\x31\x22\xe8\x68\x92\xcd\x7c\xe6\xc4\xc5\x89\x24\x8d\x2a\x3c\xaa\x35\x14\x5e\x7f\x88\xb0\xe6\xdd\x07\xc6\x52\x4b\xe4\x52\xb5\x29\x65\xe9\xb0\x30\x36\x07\xeb\x70\x00\xc4\xc4\x63\x27\x69\x82\x24\x45\x18\xc8\x98\xf3\xd8\xdd\x0c\xe2\xfc\x1f\x63\xf6\x90\x70\x4a\xf1\x9b\xf5\xa6\x2e\x43\xd7\xa7\x7f\x2f\x38\x45\xab\xae\xe0\x70\x08\x48\xa6\x39\xab\x32\xf5\x8a\x25\x3d\xd1\x39\x5b\xa8\xae\x32\x11\x07\x12\x25\xe4\x26\x9c\xee\xe8\x0a\x76\xa3\x03\x13\x3c\x35\x8c\x01\x45\x85\xcf\x4e\xdf\x08\x41\xdc\x9b\x87\xd4\x03\x36\x2d\x4e\xd1\x8d\x37\xb3\x71\x7a\x9b\x49\x63\x0f\x2e\x8f\xee\x47\xfb\xcc\x08\x92\x0e\x1d\x86\xc2\x8c\xcb\x3a\xdb\x2e\x19\xd6\xc0\x82\xfa\x35\x42\xf7\xb5\x45\x13\x06\x13\xc8\x05\xf2\xca\x28\xaa\xfa\x4c\x0a\xf9\x4c\xbf\x52\x7e\x41\x12\x93\xff\x5f\x39\xc9\xa6\xdb\xfb\xc2\x76\xbe\x05\x41\x78\x87\x94\x61\x4c\x97\x9e\xe0\x5f\xe3\xf8\x3e\x29\xf4\xf5\x28\x1d\xdc\xdb\x66\xea\x4c\x45\xee\x0d\xe1\xc4\xb7\xa2\x3c\xa6\x90\x41\xca\x7c\xf1\xd4\x0a\x05\xef\xdc\x6f\x93\x4d\xff\x0e\x47\x01\x44\x91\x7f\x28\xf1\x89\xe8\x59\x91\x4f\x16\x1c\x1e\x30\x1c\xab\x31\xbd\x37\x5a\x2f\x2c\x88\x23\xa6\x89\x99\xee\x25\x73\x9f\xd1\x60\x44\x53\x03\xfb\x04\x6c\x92\x2c\xdf\x44\x69\x78\x4d\xc3\xb1\x36\x59\x18\xfa\x7d\x6d\x4f\xae\x44\x13\x2b\xb5\xed\x71\xce\x4a\xfb\x03\x6d\xb2\x5f\x89\xef\xb1\xea\x1d\xbc\xc8\x60\x2f\xf8\x43\x3f\xd3\xea\x5e\x91\x55\xf8\x97\x5d\x83\x56\xb0\xc2\xe9\x34\xe0\x20\x8a\xd9\x74\x55\x67\x29\xd4\x63\xa8\x14\x28\x06\x6e\x7d\x26\x02\xf9\x55\x95\x6e\x24\xe2\x53\xbc\xa5\xff\x59\x0f\x3b\xa6\xec\xe7\x6f\x19\xc6\x84\x9d\x14\x9e\xaa\x8e\x06\x89\xf8\x52\xae\xf2\xdf\x0f\x9e\x40\x3a\x21\xff\x66\xe9\x75\xb2\x9c\x2e\xc3\xeb\xb8\x24\xf0\x4c\xbe\xd6\x10\x7f\x9a\x99\xed\x12\xff\x33\xa3\xf7\x80\x83\xe5\x25\xcb\x7f\x9a\xe6\x7b\x77\x18\x6f\xee\xb7\x96\x23\x2a\x09\x37\x57\x53\x30\x3b\x0d\xfd\x75\x97\xd4\x34\x3c\x04\xbd\xf9\xeb\x9f\x06\xac\x70\x87\x3b\xbd\x0f\xd2\xfc\xc5\x98\x35\x17\xce\x0c\x73\x4d\x4c\xb4\xfd\xcc\x35\xdc\x49\x39\x59\x30\xe8\x75\x0c\x85\xd9\x93\x1a\xaa\x56\xcd\xb1\x06\x0a\xe6\x14\x82\xe5\xc0\x50\xe8\x41\xf4\xe8\xe7\xb9\x2e\x34\xdb\xb8\xec\x13\x95\xf3\x11\x05\xe6\x55\xf3\xb5\xcc\xd8\xc5\x71\xe6\xb9\x6d\x1a\x22\x55\x12\x63\x05\xc6\xb5\x4e\x63\x9f\xcc\x29\x00\xcf\x43\xfa\xcc\x5f\xcf\x01\x42\x48\x83\x58\x39\xdd\x5a\xaf\x60\xf4\x23\xe9\x6c\x07\xa7\xc6\x76\x6d\xe9\xe4\xfb\x51\xcc\x78\x9e\x9c\x9a\x3d\x19\x7e\xf4\x4a\xc3\x21\xad\x65\xca\x3a\xab\x17\x02\xfd\x20\x4e\xb2\xca\xf6\x32\x70\x21\x88\x03\x4f\x25\x26\x16\xc6\x9c\x80\x41\xe2\x0a\x7f\x74\x79\x7d\x31\x5a\x17\x86\xe1\x02\x65\x98\x59\xdf\xf2\xf3\x50\xd8\x26\x58\x58\xcf\x75\x81\x55\xdf\x12\x76\x75\x1b\xed\x87\xee\x05\x21\x37\xa2\x46\xfd\xf0\xf4\x56\x03\xc3\xa7\x26\x10\x5b\x16\x9c\x04\x37\x8b\x3d\x74\x66\x5a\xf4\x99\x54\x21\x90\x68\x21\x5a\x25\x13\xdb\xeb\x09\x5c\x05\xa5\xc0\x7e\xfe\x56\x47\x90\xa2\x32\x42\xcc\x3c\x33\x62\xbb\xd2\x83\x42\xd6\x57\xff\x7a\xf1\x46\x4b\x46\x9d\xb9\x99\xa1\xb2\x60\x4b\xc4\xfa\xd3\xd8\x24\x0a\xde\xf3\x9a\xb1\x6b\x63\x8c\xca\x9a\x8e\x8c\x35\x18\xf6\x26\x39\x4b\xd2\xc6\xf0\xb4\xbf\xfb\x31\x0e\x47\x8a\xac\x1f\xb8\x7e\xb1\x2e\x25\xc4\xe0\x95\xe1\xb7\xe7\x9e\x8f\x1b\xba\x1e\x62\x15\x05\x22\xec\x4f\xe0\xed\xec\x86\x84\x4c\x9d\xda\x27\x71\x4a\x50\xbe\x12\x61\x7e\xf3\xbe\xe7\x95\xde\xf0\x41\x27\xe4\xae\xcf\xf3\x61\xa3\x7f\x59\xcb\xc1\x58\x36\x97\x3a\xf8\x4c\x12\x0d\x08\x04\x9a\x85\xa2\x8f\x17\xa6\x2a\xd1\xfa\xb2\x7e\x9e\x5b\xc5\xd7\xf4\xee\x1f\x5e\xd1\x69\xc6\xca\xed\x0d\x20\xb9\xa6\xef\x33\x1c\xe2\xd3\x89\x24\x49\x41\x54\xe6\xe4\xe0\x82\xa1\xbf\xc9\x13\x7c\x6b\xa0\x14\x55\x51\xc7\x8d\xb8\x38\xb7\x82\x3b\x3e\xda\x5a\xe8\xe6\xaa\x8f\xdb\xab\xd0\x4b\xbb\x8d\xcc\x37\xc6\x39\xc0\x57\xe1\x2c\x99\xe0\x24\x45\x3c\x88\x3c\xce\x0a\xab\x48\x24\x73\xdd\x12\x11\x39\x48\x67\x94\x2c\xc6\xb7\xdf\xa7\x2c\x19\x45\x00\xd2\xff\x02\x26\x2f\x9d\x7d\xa7\xaa\x35\x52\x87\x73\xdc\x5b\x63\xe5\xdf\xa8\x48\xf5\x0b\xd4\xcd\x65\xe2\xea\x6d\xc1\xa6\x65\xc1\xa7\xed\x40\x9f\xac\x83\x47\x07\xa9\xfd\xae\x75\x98\x08\x09\xd7\xab\x7e\x47\x08\xa7\x70\xbf\xd1\x8f\xea\xe7\xae\xa6\x09\x6b\xb2\xbb\x30\x80\x99\xc1\xee\x9a\x4a\x72\x3b\xb3\x2b\x7b\xc2\x3f\xbc\x16\xa2\xae\x99\xb2\x9e\x0b\xce\x44\x69\xe0\x53\xac\x77\x47\xe0\x43\xbe\xc8\xb5\x0d\x4d\x7f\x14\xd0\x18\xc8\xc0\x3b\x52\x43\x18\x1b\x2a\xab\xd9\x78\xcc\x36\x10\x9b\x81\xfa\xca\x45\x52\x66\xeb\x9c\xe8\xaa\x6a\xc6\x24\xe8\xb7\xb6\xe3\x91\xcf\xf7\x58\xab\xe0\xf7\xd8\x85\x8e\xb3\xbe\x70\xc2\xcb\x21\x8e\xc8\xed\x21\x09\x3c\xfc\x51\xfd\xe4\xff\xe2\x28\xf1\x94\x81\xde\x07\x9d\xcc\x9f\xc6\xf2\xb0\x23\x5b\x45\x33\x29\x41\x46\x62\xe1\x7b\x2e\x41\x0d\xba\x09\x55\xb7\xe5\x46\xe7\xbc\xbb\x77\x80\x22\x88\x2c\xdc\x03\x1c\x9e\x14\x5c\xdf\x5d\x71\x5e\xd1\xbd\xd8\x50\xa4\xcb\xc1\xeb\x15\x11\x66\x87\xc0\x5f\x22\x65\x0b\x06\xc4\x7a\x65\xbb\xa6\x08\x29\x0d\xa4\x93\x79\x84\x0d\x44\xc1\x07\x56\xd6\x7f\xb5\x40\x41\x3d\x04\xfb\xa3\xdc\xad\xe3\x7c\x31\x98\x74\x8e\x2b\xa9\xff\xe2\x2d\x87\xfd\xba\x3a\xcb\xbf\xe5\x8d\xa2\xc8\x27\xd2\x0d\xc9\x97\xbc\x1e\xe3\x61\x04\xa9\xd0\x32\x04\x4b\x52\x00\x14\x03\xd7\x44\x8c\xb1\x06\x4d\x31\x92\xe5\x1a\xc0\xac\x52\x5c\x06\x6d\x71\xaf\x0e\xba\x06\x08\xd0\xcc\xf0\x06\x9e\xc1\xdd\x27\x7c\x94\x26\x4b\xa8\x23\x1b\x2b\x92\x1f\x7e\x4a\xa9\xcb\x76\xe8\x85\x43\xc9\x72\x4f\xbf\x88\xa2\x49\x43\x1e\x87\x65\x5e\xa3\x9a\xcc\x28\xe1\x20\xcb\x1d\xfb\xcf\xe4\x02\x8b\x0f\x41\xf3\xac\x49\x57\x9f\x7c\x92\x3e\xda\xaf\xef\x85\x0f\xe4\x9b\x7f\xe9\xec\x50\x53\x7c\x50\xe8\x92\xca\xe8\x31\x1f\x10\xfd\x32\x5d\xf5\x31\x4d\x0d\xdc\x1f\xeb\xf1\xe2\x5e\xc9\xd3\x1d\xac\x27\x92\x9c\x32\x34\x26\xc5\xc7\x29\x69\xa0\x8e\x6c\x37\x3e\xc8\x48\x7d\xf5\x46\x14\xea\xa3\xc2\x48\x82\xa1\x20\x84\xc4\xb0\xe6\x3a\x2f\xbc\x54\x93\xe1\x11\x76\x85\xf6\x4c\xc3\x58\xdc\x1e\xf9\xc1\xfe\x45\x4b\x29\x29\xc3\x5d\x84\x93\x70\xd8\x7a\x78\x9a\x36\xec\x40\x8b\x2f\x86\x2c\xdc\xcb\xb1\x0f\x0c\xc1\x79\xf5\x50\x43\x4f\x32\xb4\xff\x1d\x19\xf5\x25\x3a\x8e\x09\x42\xc6\x8d\xf4\x11\x42\x11\xfa\xba\x04\x68\xc1\x42\x84\xc7\xe7\x00\x92\x88\x1b\x20\x9c\xa2\x21\xd5\x2b\x34\xa3\xab\xfb\x60\x47\x54\xe7\x78\x96\x15\xc3\x87\xc9\xc9\xd8\xe2\xad\x93\x00\x6f\xe2\x38\x0c\x79\x8f\x03\x84\x83\x7b\x44\xfb\x0b\xee\xcf\xe4\xf7\xe9\x48\x52\xff\xdc\xc6\xa3\x55\x2c\x45\xba\xbc\xab\x79\x3b\x2a\xb0\x74\xdd\x97\xe6\x7c\x80\xac\x2d\x12\x63\xce\x0b\x0d\x6d\x16\x16\x2e\x66\x2a\x7c\x61\xf7\x83\x71\xda\x30\x13\xef\x94\x71\xfe\xdb\xb4\xb5\x0c\x96\xa4\xe3\x71\xd2\x23\x3e\x1a\xa3\xce\x93\x99\x58\xe8\x74\xa9\x42\x65\x25\xfe\xc5\xf5\x48\x23\x28\x7b\xb0\xce\x1d\xad\x4f\x46\x45\x99\xd8\x3e\xfc\x39\xd8\x74\x67\x3e\x25\x2a\x9b\x31\x1f\x25\x76\x61\x74\x81\xfa\x7b\x73\x26\x2d\x90\xb8\xd4\x5f\x34\x6b\x2d\xa0\xf5\x1f\x55\x7c\x3a\xd1\x6f\xbc\x15\x3a\x9a\x6b\xa1\xe4\xa9\xdc\x3b\xb6\x36\xb3\x90\xf3\xe3\x4b\x3a\xba\x7e\x44\x77\x37\x20\x45\x8e\x42\x2d\x29\xdf\x77\x49\x3b\x63\x1e\x9e\x88\xc1\x73\x9a\x69\x4f\x66\x9e\x08\xfa\xf8\x3d\x55\x34\x50\xa6\x1c\x6b\xde\x84\xb2\x37\x10\xc6\x4d\x24\xbb\x1f\xf8\xd2\xac\x67\x8c\x1d\x1c\x58\x03\x88\xee\xdf\xf0\x46\x2c\x85\xe3\xde\xde\x1e\x7d\x5d\x2e\x32\x32\x4c\xa1\x83\x8b\x68\xaa\x35\x7d\x5e\x25\x7d\xa2\xbb\x8e\x3f\xda\x1e\xd2\x4c\x3a\x98\x04\x47\x7e\x5f\x7f\x1e\xf5\x00\x6f\x15\xd6\x62\xfa\xd3\x91\x4d\x55\xdb\x99\xa9\xe0\xa9\x7b\xad\x1b\x04\x07\x9b\xe9\xc0\x6b\xf9\x5c\x42\xa0\xa4\x25\x64\x45\xea\x60\x5e\x6d\x21\x8c\x73\x72\x41\xa4\x29\x8e\x14\x71\xcb\xf8\x5e\xeb\x5c\x13\xbf\x08\xeb\x6b\xeb\xfd\x74\xd6\x2a\x4d\xfc\x14\xa6\x6a\x42\xe2\xd1\xdd\x84\xee\x59\x6d\x85\xf2\x5f\x74\xe2\x1b\x9d\xce\x10\x7d\x52\x58\xde\xbd\x60\x45\xe9\x7a\xf2\x96\x87\x55\x17\xe1\x99\xfa\xf6\xc7\xb3\xf3\x2b\xc1\xe5\xb9\x0f\x67\x62\xde\x76\x06\x1c\x30\xe3\x36\x85\xf4\x4f\x8c\x88\xd9\x97\xfe\x8b\xcb\xfe\xb8\x35\xc8\xa6\xd6\x4d\xd1\x27\x7b\x6e\xbb\xb4\x06\x90\xf7\x72\x16\x57\xbd\x41\x63\x42\x41\x2c\xbd\x7c\xad\x7d\x9b\xbe\x88\x1b\xd6\x7e\xaa\x43\x7c\x95\xdf\x12\x2f\xea\x3f\x5f\x46\x97\x1d\x75\x8f\x37\x5c\x47\x90\x24\x83\x06\xf9\x34\x02\x2c\x5d\xfc\xd7\x96\x40\x57\xb3\x16\x79\x65\x9b\xd5\xf8\x57\xe6\xa3\x93\xa7\x8d\xfa\xd4\x56\x75\x53\x74\xc6\xc2\x49\x8d\x26\x41\x74\x37\x1f\x48\x44\x13\x05\x1c\xf5\x22\x99\x98\x53\xb2\x90\x93\x2b\x25\x64\xc7\xc6\xc3\x66\xc8\xf6\x7b\x9b\x0f\xb2\x53\x23\x93\x16\x23\x04\xe6\x0b\x9d\x59\x32\x2a\xc2\x24\x2f\x6c\x4f\x45\x25\xc9\xb9\x23\xf1\x94\x24\x8f\xc3\xa9\x6b\x45\x62\x69\xed\x95\xa8\x6f\xce\xdc\x4c\xee\x91\xf3\xb0\x10\x9a\x48\x14\x8c\x9e\x96\x18\x40\x63\x54\xfc\xa2\xa4\xba\x36\x74\x7b\xc6\xb4\x10\xda\x92\xef\x01\x16\x17\x95\xe1\x18\x9b\x72\x3c\x15\x8c\xe7\xaa\x9f\x52\xb2\x89\x17\xae\x07\x74\xd5\x4c\xf1\xcf\x85\x62\xcf\x18\xcc\x3b\x65\x1a\x37\x17\x44\x00\x75\x82\x33\xa9\xeb\xfb\x52\xfa\x85\x3f\x72\xf2\xf0\xff\x9c\x0a\xa8\x8d\xeb\x19\x08\x96\xca\xaa\x6c\xa8\x44\xf0\x12\x5b\x0b\xc2\x95\xac\xb9\x2b\xd2\x15\x58\x54\xd5\x4e\xa0\xf1\x64\x9e\x64\x7b\xf2\x70\xc0\x88\xf3\x30\x56\x55\x70\x63\xf5\x1b\xb1\xf1\x38\xe8\x74\x49\xfd\x98\xf3\x23\x14\xcb\xf0\x76\x2d\xe9\x99\xea\x1e\xf6\x2d\xdd\x46\x73\x6a\x06\x21\x0b\x32\x22\xc8\x75\x1d\xdd\x8b\xad\x70\x5e\x44\xb8\x00\xb7\xd0\x32\x04\x83\xa7\x14\x62\xfc\x56\x3f\xfc\x76\x19\xe5\xe3\xd6\x8f\xe6\x59\xb2\x93\x8e\x7e\xe4\x7a\xdb\x49\x0b\x72\x17\xd2\x1d\x1b\x84\xd3\x8f\xb7\x86\x20\xa1\xdb\x67\xf2\xa0\x8a\x56\x4d\x0b\x36\x02\x92\x44\xe6\xcf\x3b\xa7\xf8\xc0\x23\xc4\xf8\xe8\x43\x56\xc0\xfc\xd1\x56\xf7\xb8\xb9\xf8\xde\x7c\x4a\x18\x5c\x56\xe1\x8b\x9b\x6b\xd5\x55\x22\x73\xd5\x71\x7a\xc1\x48\x58\x48\xca\x19\x26\x49\x36\x14\xd5\xcd\xe6\xc5\x82\x7d\xf0\x4a\x7a\x80\x0c\x1f\xf1\xf4\xed\xf0\x45\x7c\x29\x33\xb3\x47\x8b\x15\xff\xb6\x7e\x89\xca\xd8\x31\x7c\xd2\xb2\x8d\x6b\xec\x67\x23\x19\x16\xef\x65\x37\x80\x80\x26\x3b\x66\xc9\x30\x2e\xc1\x0a\xf5\x33\xa4\x1a\xdb\xad\x4d\xfb\xd3\x69\xf7\xce\x29\xe3\x02\x87\xba\xf3\x32\xa7\x3c\x59\x92\x1c\x91\x9e\x9e\xfb\x31\xb9\x5a\x8e\x7d\xc1\xce\x07\x1a\x21\x86\x6c\x01\x9e\x2f\xb0\x6b\x1e\x37\x9e\x1c\xa6\xdd\x2e\x3c\x49\xf2\x4e\xf8\x0d\x06\x87\x01\xc5\x65\x53\xd7\xac\xd5\x93\x64\xc8\xbe\x0b\xb6\x86\xb7\x78\x66\xf5\x4b\xf4\xd3\xbe\xc3\xcf\xbc\xce\xae\x1f\x41\x18\xc8\xac\x00\xa7\x59\x40\x54\xf9\x63\x8c\x71\x21\x31\x53\x6f\xd1\xcb\x8c\x78\x9d\xb0\xd5\xcd\x32\x57\x40\xb0\xc9\x00\x8d\x77\xb1\x24\x99\x8d\x0e\xf3\x55\x1e\x5d\xf8\x8e\xbd\x7b\xd8\xf9\xd5\xeb\x23\x1a\x47\x8e\x5e\xd8\x99\xb9\x7d\x4c\x7f\xff\xe3\x29\x1a\xdd\x78\x7b\x26\xfa\x78\xf9\xd8\xe7\xbb\xfe\x4f\xca\x56\x08\x45\xa1\x29\x5c\x39\x1b\x87\xed\xf4\xa1\x22\x86\x27\x45\xbf\x55\x9a\xb6\x38\x12\x8d\x11\x67\x30\x6a\x95\x6b\x52\xcb\xb9\x02\x83\xea\x85\xe1\x15\xb7\x9b\x69\x91\x9b\x3c\xfd\x67\x2b\x23\xa3\x87\x37\x82\xd9\x43\x3e\x1d\xdf\x60\xf9\xde\x77\xb6\xfe\x73\x21\xc0\x23\x48\xfd\x05\xcc\x4b\x0c\x51\xf8\x70\x78\xf2\x6b\x0e\xff\xb2\x64\xb1\xd2\xa6\x5e\x2f\xc4\xd6\x16\xa4\x94\x0d\xce\xe5\xed\x8f\xab\xc4\x57\xb6\xae\xcf\xe2\x45\x72\x83\xd9\x78\xa1\xef\x16\x2c\x1d\x2a\xd2\xec\xc7\xff\x5d\x41\xe3\x50\x58\xb3\x62\xf4\xd8\x98\x70\x94\x35\x73\x69\xe0\x16\xd6\x3f\x04\x7c\x1d\xbf\x0e\xe1\x9c\x96\x09\xb2\x83\xa2\xff\xa0\xe9\x66\x76\x6e\xb3\xec\x04\x7a\x98\xd3\xa0\x0d\x57\x89\x90\x32\x3c\x0f\x41\xd1\x62\x82\x83\xd9\xb9\x75\xda\xf4\x1e\x17\xa2\x38\x8f\x05\x8a\xb8\x2c\xbd\x9e\xf9\x1b\x85\xaa\x09\x74\xf8\x4c\x45\xd2\x62\xfa\x04\x9e\xeb\x7d\xbc\xa5\x35\xf2\xfe\x41\x9f\x58\x8f\x7d\x3f\x52\x63\xb8\x72\xda\x9f\x16\x32\x26\x94\x4a\xfb\xfa\x01\x11\x7e\x8e\x47\x8a\xd3\xb0\x7a\x5e\x45\x38\x4b\x5c\x16\x9d\x4b\x2e\x3d\x56\x26\xa1\xae\x38\x5a\xa5\x4f\x09\xcc\x02\x17\xd0\x7c\x43\x35\xe0\x0c\xe1\x55\x07\x45\xe3\x15\xb1\xfc\xb7\xbd\xc1\x31\x3e\xcd\xc9\x61\x9d\xef\x55\xd6\x30\x91\xf4\x6e\x6b\xdf\x06\xc2\xc7\x07\x30\x8b\x64\x1c\x33\x8f\x29\x0b\x43\x8e\x79\x16\xce\xda\x1a\xd8\x18\x7d\x73\x8f\x32\x8a\xac\xab\xb6\xef\xd8\xfe\xbb\x5e\x24\xc2\x27\x23\x0c\x5c\xc5\x4b\xbf\x21\x13\x93\xe4\x2d\xd0\x90\x1c\xf2\x2d\x2e\x90\x59\x85\x40\x18\x4e\x21\x45\xc0\x7e\xc2\x20\xd4\x79\x56\xe1\xe6\xdf\xb2\xf1\x2a\xa3\xaa\x93\xa4\xb1\x31\x17\x4f\x05\x57\x6a\xef\xd8\x81\x6e\x3f\x85\x62\x68\x9e\xbc\x70\x1d\x54\x61\x18\x6c\xb3\x25\x49\x85\x56\xba\x86\x4c\x45\xca\x0f\xf9\x1c\x15\x6e\x3b\x1c\xbc\x7b\x53\x85\x92\x73\xe9\x5c\xa3\x2a\xb6\x75\xd0\x8a\xe7\x3a\x8f\xe2\x4c\xe6\x99\xb5\x38\x43\xe7\xa8\xbe\xe6\xf1\xf7\xa9\x9f\x01\xd1\xd3\x44\x02\xe3\x9f\x50\x64\xd0\xa7\xf8\x96\x5e\x32\x72\x4e\x24\x2f\xd5\x97\x6f\x40\x66\x14\xa9\xb7\x91\xb0\x4f\xee\xe6\x20\x5c\xba\xef\x31\xc0\x76\x55\x21\xaa\x04\x5c\xca\xf2\x42\x51\x44\x72\x06\xc6\xf1\x60\x63\x07\xcf\xa4\x9d\x74\xfa\x7d\xe8\x94\xfb\x20\x5e\x32\x23\xcf\xaa\x1b\x4d\x9d\x95\x0e\xb2\x28\xf3\x87\xd1\xc0\x34\x03\x84\xc1\xad\x4c\xf6\xdf\x1d\x1b\x47\x56\xde\x4a\x7b\x8e\x5b\x68\xf9\xe3\x15\x72\x84\x56\x16\xad\x6f\x8b\xa5\x1a\x7f\xa7\x37\x5d\x92\x6d\xb3\xde\x7b\x5b\xb1\x67\xfc\x3f\xc6\x87\x05\x21\xe7\x04\xb0\xa4\x44\xa9\x05\x70\xd0\xd2\xd2\xee\x80\x2f\x2f\xd2\xd3\x71\xff\x5e\x99\x1a\xb2\x20\xd3\x22\x7b\x3f\x31\x6f\x4a\x28\x6a\xa8\x86\x8b\x77\x89\x0b\x91\x97\xb8\xfc\x25\x60\xbc\x67\xe6\x1e\x48\x1f\x82\xae\x7e\xd2\xbc\xbd\x1b\x74\xae\xc0\x54\xf8\x9a\xa2\x73\xd2\x9a\x31\x1b\x71\x4b\x81\xc6\xba\xf4\x56\x1a\x14\x94\x3c\x6c\xed\xf7\x9c\xfd\x92\x0d\xce\xaf\xb4\x91\xd6\xcc\xe4\x4f\xb4\x2c\x73\x2c\x1d\xa7\x91\x77\x65\xb6\x06\x35\x96\xa0\x20\xa0\xbe\x2c\x75\x64\xca\x7b\xb9\x12\xb6\xb1\x8c\xd3\x1f\x1b\xfe\xa6\xdd\x61\x3a\xd7\xf6\xf5\x3a\x5e\xc3\xaa\xb6\x2b\x09\x74\x27\xae\x2c\x4f\xb3\x81\x6b\x11\xc9\x2c\xf7\x85\x0d\x78\xde\xb5\x0f\xe3\x24\xc8\xb2\x07\x23\x04\xb1\xc7\x84\x1c\xb2\x27\x3a\xab\x6e\x03\x96\xb8\x50\xf9\x3d\xe9\x2c\x66\x4c\x53\xb9\x9a\xb3\x6a\x2d\xc1\x1c\x03\xbe\x21\x63\xc1\x6f\x4f\xc1\x7f\xa2\x99\xb6\xc8\x18\xca\xce\x93\x92\xa3\x19\x65\x3e\x0c\x8e\x0e\xa2\x21\x52\xd6\x62\x7c\xdb\x22\xfb\x86\x99\x6d\xd7\xce\xd3\x28\x42\x12\x0f\x68\x5a\x74\xbe\x39\xca\x42\x4e\x2b\x8a\x1a\xa6\x98\xe7\x0a\x16\x46\x59\x1a\x18\xb5\xf5\xfb\xf4\x73\x3b\xf4\xb5\x53\x89\xd6\x39\x55\x24\xa1\xdf\x57\xfb\x07\x26\x1c\x62\xcc\xcd\x76\x17\x89\x10\xff\x01\x4a\x2c\x45\xa0\xc7\x78\xa6\x80\xbe\xb0\x06\x9e\xba\xb3\x4b\x5a\x49\xe1\x1f\xe6\x3c\x62\x5a\x7b\x8c\xf4\x7e\x83\x10\x0f\x2d\xa8\x28\xe0\x81\xf1\x06\xaf\x69\xf2\x50\xe8\xbb\x81\x9f\x9a\xac\x0c\x87\x8b\x0c\x12\x32\xce\x36\x98\x31\xf6\x6b\x0c\xed\xa7\x44\x1d\x7e\x74\x27\x2f\xf4\x8e\x7a\x78\xce\x57\x23\x46\x7e\xfb\xee\xc4\x18\xb9\x00\x2b\x9c\x45\xbc\x98\xac\x03\x92\x69\x25\x30\x6e\xa8\xf0\x04\xed\xa4\x8f\x18\x49\x31\x9d\x64\x44\xae\xe8\x3a\x06\x67\x0c\x6f\x37\x63\xcb\x3e\x16\x65\xd4\xe2\xa4\xc7\x2b\x0f\x38\xfc\x61\x25\x17\xd8\x5a\xf3\xb3\x75\x9a\xad\xfd\x42\xa2\x96\x2c\xa7\xab\x5f\xc6\x55\xd9\x97\xa2\x0a\xae\x6e\x5f\xa6\xf8\xe7\x17\xd9\x78\x7c\xe7\xd8\x60\xb0\x00\x67\x81\x44\x82\xb8\x0e\x0d\x19\xd2\xb1\x2e\x62\x53\xe0\x3b\x70\xa1\xf3\xcb\x28\x8f\xc9\x9b\x44\x58\x6a\xbe\x8c\x7b\xf8\x5b\xb2\x7f\xf2\xcd\xe1\x9d\x66\x48\x97\x3d\xfe\xe2\x4d\x6c\xa5\xcf\xa1\x95\x6a\xec\x90\xe4\xb5\x6e\xe7\x7d\xad\x32\xe7\xc5\x68\x70\xf9\x9d\x04\x1a\xc2\x87\x80\xe0\x81\xc3\x11\x07\x49\x12\x26\x22\x52\x4f\x48\x58\x88\xad\xd6\xc5\x9d\x18\xa7\x3e\x14\x00\xeb\x9b\x95\x16\xd3\x09\xec\x9e\x31\x31\x33\xc8\x76\x96\xb4\x4f\x83\xc2\x53\xb3\x4c\x74\x3f\xf5\x67\x3b\xdf\x9e\x60\x84\x45\xd8\xca\xe6\xfe\x80\xc5\xe7\x26\x8f\x27\xbd\x45\x04\x70\x39\xdc\x32\xe7\x3c\x11\x5b\xd9\xa2\x1a\x1e\x3c\x83\x07\x32\xbf\x2d\xc5\x8a\xe1\xf9\x58\x38\xf7\x0e\x66\x06\xd2\x32\xef\x6e\x89\x21\x43\xe4\xb7\xca\xfa\xca\xf8\xa8\x31\x9c\x02\x1d\x10\x00\xce\xa8\x10\x52\x08\xdc\x7d\x87\xc4\x34\x9e\x4d\xcb\x6a\x66\x68\x50\xb2\x9f\x4b\x84\x88\xc6\x79\x39\xe8\x74\x62\x81\xee\x67\xd2\xa6\x4c\x67\xcd\x3b\xc2\xde\xc9\x38\xc2\xfa\x07\xe3\x0c\xfb\x0f\xc1\x64\x2a\xde\x67\xb5\xc8\xde\xa2\x79\xb8\xc1\xf7\x1c\x84\x92\x1b\xdf\xc4\x86\x91\xc9\x4e\xce\xd7\xfe\xba\xf1\x34\xb2\x91\xa6\xf0\x3a\xdb\xa6\x13\x68\x36\xb8\xe3\x3c\xa1\x04\xe9\x00\x5c\x8b\x5d\x5f\xbd\x41\xa7\x7f\x4b\xe3\x4d\xd0\x70\x2e\x2d\xde\x74\x3f\x8e\x3a\x12\x24\x08\xb2\xac\xa9\x62\xbd\x6b\x24\xcb\x20\xd2\xec\xe9\x40\xd1\x56\x35\xaa\xf2\x8c\x4b\xbc\x76\xf7\x9d\xa5\xfc\x93\x73\x70\x5a\x57\xd6\x28\x77\xb6\x08\x50\xd3\x3e\x1f\x4d\x48\x05\x0a\x6f\x9b\xdc\xc8\x29\x7e\x21\xb5\xf6\x93\xb1\x40\x7c\x7d\xd1\x77\x11\x8c\x03\x8d\xa0\x6c\x58\x85\x7b\x99\x25\x1e\xf8\x76\x9f\x81\x10\xc4\x8a\x14\x28\xda\xc1\xb8\xaf\x58\x30\xfd\x15\xde\x3c\xb4\x43\x94\x89\xa2\x48\x15\xa8\x23\xf1\x83\x35\xe1\x16\xbb\x87\xd4\x06\xdc\xc0\xe6\x2e\x3e\x89\x4f\x12\x1c\x60\x28\x8a\xda\xd9\x26\x91\xe7\xbd\x3b\xf3\x0a\xe4\xd5\x94\x43\xed\xfa\x30\x36\x4c\x4f\xff\xf4\xbe\xc0\x99\x61\x7a\x2d\xc3\xbc\x90\xd8\x13\xdf\x6f\xd3\xa7\x7a\xc1\x60\x07\x24\x2a\x28\x9b\xad\x0e\x25\xde\x13\x72\x49\x7e\xf1\xad\x70\x8a\xe2\x3f\xa0\xce\x6a\xc4\xb8\x16\x8b\x94\xae\x81\xac\x47\xf6\x7e\xcd\x11\x63\xe3\x56\x6d\xe9\x20\xdd\xc1\x0a\x49\xfe\x69\xa1\xb5\x5f\x78\xe6\xad\x48\xd0\x44\xe8\xb2\x76\xbc\xea\x60\x5f\x14\x7d\x76\x79\x91\x2e\x6f\x0f\xde\xdd\xea\x69\xb1\x5e\x5d\x73\x3e\x26\x9c\x1d\xdb\x9b\xf6\xe2\x9d\xba\xac\x16\x6f\xfe\xc9\x12\x1a\x82\x8a\xf5\xa0\xee\xab\x95\x73\x52\xe4\x56\xef\x3c\x7a\xf9\xc9\x9b\xe7\x5f\x56\xdc\x65\x5d\xc6\x4a\x96\xc5\x98\x07\x8c\x6c\xd8\x25\x8c\xa6\x60\xf7\xd7\x64\xe2\x38\x2b\xde\x4d\x5e\x3b\x21\x05\xf7\xe5\x8c\x72\x6b\x99\x6c\x24\x1d\x67\x11\x1d\x03\xbc\x92\x2a\xbf\x86\x37\x97\x14\xe9\xda\xc4\xec\x51\xff\x10\xd3\x03\x44\x70\x2b\x19\x71\x12\xb7\xda\xbc\x7e\x09\x20\x19\x74\x27\x13\xf2\x46\x0e\x12\x60\xb2\xaf\x35\x0b\x2e\x5c\xf1\x41\x36\xde\xcb\x24\x2e\xc0\x9e\x55\x5a\x07\xfc\x9c\x8f\xfd\x6c\x58\x66\xa8\x63\xfc\xb7\xc9\x83\x34\xb5\xc7\xe4\x0f\x02\xae\xbc\xe8\x81\x7f\x1b\x83\x1e\x03\x47\x79\xf6\x49\x8a\xed\x03\x9a\xd3\xc7\x2c\xf1\xcf\xdd\x35\x88\xc7\x04\x30\x16\x59\x18\x6d\x95\x7c\x65\x83\xe4\xca\xa7\xeb\x71\x30\x31\xfb\xea\x5c\x75\xe6\x8f\x22\x57\x23\xf6\x2f\xfa\x7b\xa6\xa0\x36\x92\xf5\x5c\x76\xab\x94\xe1\x89\x58\x49\x3d\x6a\x2d\x2e\x77\x8d\x0b\x1a\x7a\xb7\xcc\xa0\x88\x39\x1e\xfc\x50\xb8\x88\x4a\x54\x02\x41\xf7\xc2\x71\x8f\x97\x0c\xf1\xd8\x2d\x04\xf6\xa0\x86\xa0\xe5\x20\xee\xfe\xd0\x2f\x26\x46\x6e\x14\x3e\xdb\x1e\xb4\xe4\xd4\xb0\x05\x33\x0f\x32\xbd\x9c\xb3\x21\x98\x94\xf0\xf4\xa6\x24\x1b\xdb\xa9\x1f\x44\x74\x83\x47\x3f\xca\x45\x4c\xf2\xb0\x05\x34\x0b\x85\x87\x9a\xfa\x78\x58\xdd\x5c\x26\xb3\xc9\xb8\x94\xa2\x9a\xba\x12\x5f\x72\x8c\xa1\xe5\x20\xda\xe1\x36\x87\x3e\x1c\xe8\x9c\x7b\xba\x11\x8c\xe6\x0a\xb3\xb5\xdc\x06\x46\x0a\x38\x83\xbb\xed\xd3\x69\x92\xd2\x91\x8d\x39\x4d\xc1\xfc\xbf\x90\xeb\xfd\x63\x87\xf9\xe6\x9b\x6f\xc6\x4d\x67\xe7\x32\x24\xe3\xba\x32\x29\x29\x41\xb3\xd4\xde\x92\x37\x2f\x12\xb4\x2c\x87\xb8\xbb\x32\x4d\x2a\xe1\xf3\x62\x40\x2a\x65\xe4\x40\xa0\x18\xfc\x03\x7d\xdc\x45\x1a\xbc\xdb\x61\x10\x60\xf0\x22\x43\xbf\x24\xde\xb6\xc1\x4f\x2a\x46\xe9\x79\xc7\xae\x96\xba\xd1\xf2\x0b\xcd\x76\xd1\x6e\x17\x45\x4e\xa8\x42\x6d\x33\x60\x01\x19\x4d\x10\x06\x5f\x09\x14\x1c\xd8\xf4\x36\x42\xed\x37\x7b\x72\x03\x34\xdb\x46\x67\x0f\x03\xaa\x83\xdf\xf4\xd5\x50\x8f\x60\x85\x70\x42\xe2\xf4\xae\x0e\x49\xef\x4e\x91\xdd\xc1\x5f\x87\x7f\x5d\xbc\xa0\x4c\x40\xb7\x72\x11\xff\x9e\x1d\x7e\x3d\x0f\x84\x83\x66\x4b\xdf\xa4\x20\xed\x13\x78\x47\xfc\xaa\x1d\x77\x55\x15\xe4\x7c\x5c\xb8\xe8\x73\xf1\x39\x58\xc7\x18\x79\xeb\x15\xbd\xc8\x3d\xc1\xab\x24\x14\x33\x1a\x53\xb1\xd8\x34\x57\xb9\x10\x30\xd7\xf9\x30\x2e\x3c\xc4\x81\x40\x36\x60\x73\x76\xe3\xaf\x1d\x44\x82\x7a\x23\x7b\x2e\x91\xd9\xf8\x4f\x73\xc7\x1a\xe4\x88\xc0\x0f\x42\xb2\xd1\x63\x88\x8b\xd7\x43\xd4\x2b\xeb\x92\x09\xb7\x6d\x53\xbd\xe1\xfc\x4a\x18\xd9\x21\xbe\xb6\x23\xe6\xac\xda\xd8\x3c\x40\xb8\xdb\xff\xdc\x0a\xb7\xb7\x83\xb6\x35\xd3\x3e\xba\x4c\xc5\x23\x3a\x09\x97\x6d\xb8\x29\x7a\x04\x15\x01\x90\x00\x28\x99\x58\xd0\x07\x11\xee\xc8\xb2\x6a\x75\xed\x94\x75\x46\x50\xd8\xd5\x8f\x5f\xea\xc2\x66\xa6\xa2\x63\x6a\x7b\xf1\x6c\x06\xd2\xe4\x72\x51\x12\x78\x52\xee\x47\x68\x0d\xb5\x6c\x68\x2d\x55\xe8\x59\xe0\xcf\xc0\x83\x70\xe2\x76\x25\xe5\x45\xe2\x48\x3c\x18\x11\xc7\xb8\x15\xd4\x9a\x9a\x16\xd9\x2d\x4f\xf2\x9f\x0d\x0c\xda\x5d\x13\x3e\x71\xce\x94\x2b\xf8\x4a\x95\xfd\x03\x1b\x25\xf0\x3b\xa1\x27\x56\x78\x94\x3f\x26\x1b\xe1\xea\xea\x8f\x80\x9b\xa0\xc0\x2f\xaa\xb3\xdb\x3d\x74\x9e\xd9\x2e\xb1\xa4\xe1\xc0\xcc\xee\x33\x0f\x02\xdb\xa3\x76\x17\x6d\x05\x9c\x1c\x5c\x37\x73\x06\xa7\xb7\xc3\x0a\x84\x18\xe2\xd9\x8a\x3d\xdd\x6c\x3e\x4e\xd6\xd9\xa4\x8f\xb5\x9d\xef\x99\x5d\xc1\xb2\x91\xab\x15\xa1\x59\x35\xec\x35\x1e\x3c\xf2\x2d\x2c\x27\x19\x43\xb8\xeb\x3c\x2f\x18\x3d\xa1\xfd\xc9\x43\x76\x89\x30\x1b\xc9\xdf\xac\xa6\xbf\xd6\x79\x49\x49\x0e\x17\x09\x76\xeb\x2b\xc6\xd7\x11\x77\x4e\x52\xf0\xf4\xd8\x4a\x56\x27\xed\x14\x35\x36\x7f\x45\xd1\x95\xb0\x90\xfc\x39\xb7\xd7\x3d\x72\xba\x1e\xb5\xfe\xc2\x8b\x94\x50\x3f\x29\x2f\xad\x2e\xda\x4f\x4c\xed\xb3\xc6\x12\x57\x44\xbf\xa8\x7e\xa5\x53\x55\xa4\x19\x5c\x91\xd4\x26\xbd\xaa\x61\x28\x69\xd9\x78\x7a\x85\x38\xc5\x8a\x51\xaf\x02\xfb\xf2\x34\x56\xd4\x99\x71\x9e\xf9\x76\x00\x03\xdc\x11\xd0\x67\x88\x8c\x08\x50\xa8\xf9\xc8\x67\x34\xcf\x49\xca\x78\x1d\xdb\xe3\xbb\x95\x2e\x7b\x1b\xb9\xc1\x89\xa1\xbe\xdd\x08\xca\xd5\x0a\xd1\x2d\x2e\x03\xe7\xf8\xe6\xa8\x05\x71\xf0\x32\xc0\xf8\x6c\xc4\x13\x30\x1a\x36\xda\x5e\xe9\x7d\xd5\x95\xc0\xb7\x44\xdf\x87\x69\xfa\xdf\x29\x52\xd0\x8a\xec\x5e\x18\x26\xe3\x31\x33\x5b\x47\xca\x70\xe3\xcd\x49\x29\x78\x2b\x10\xed\xa3\x78\xc4\x85\xa2\x7c\xca\x07\xec\x94\xea\xf8\x0b\x20\x4b\x41\x19\x6b\x9a\xc0\xad\x05\xab\xad\xa9\x5f\x32\xc3\x58\xe5\xde\xa4\x1e\x41\xe1\x7d\x7e\xa5\x54\x0f\xe6\xb8\xfb\x2e\x31\x23\x56\x57\xf5\x29\xef\x45\xd0\x71\x47\x84\x40\xfc\x88\x05\x35\x90\x96\xcc\xcc\xa6\x3a\x00\x63\x7d\x21\xea\x82\x75\x5c\x45\x96\x18\x81\x93\x0a\x48\x8d\x18\x77\x1a\x75\xc7\x45\xc6\x36\xaf\x61\x80\xcf\x5a\x9c\xfd\x47\x4a\x58\x00\x91\x0d\x49\xed\xe6\xf4\x85\x4e\x7e\x73\x62\x59\x03\x60\x3b\xe3\xc1\xd3\x0d\x21\xf4\x26\x4f\xb0\xe1\x28\xaf\x8c\x0d\xfb\xaa\x1c\xe3\xa0\x8b\x19\x24\x6a\xfe\x07\x29\xa5\xd9\x92\xfe\x98\xae\xb9\xf3\x04\x5f\xd9\x5a\xc3\x22\xcd\x31\x24\x8c\x00\xa8\x49\xbe\x60\x97\x6c\xd0\x75\x23\x8b\x86\x55\xd6\x99\x67\x49\xb0\x50\x2e\xe3\xc3\x5a\x1a\x2f\xc8\xe1\xcf\x33\xa8\x9e\x98\x14\xbc\x14\x33\x79\xcc\xd2\xf3\xb8\x38\xa6\xf0\x2d\x08\x98\xbb\x30\x19\x7b\x87\xc5\xf2\x61\x1c\x44\xae\xd0\x09\x67\x3f\x96\x91\xe1\x54\x29\x98\xd9\xd3\xae\xa0\xc2\x66\xfc\xfc\xfd\x3d\x8e\x95\x3b\x76\x85\xfb\x2b\x1a\xdc\x3b\x9e\x55\x9c\x11\x37\x46\xe2\x4c\xee\x4e\xb9\x9f\x41\x3d\x62\x5d\xfd\x0f\x30\x23\xab\x6d\x6f\x62\x8b\x66\xd2\x1d\x95\xe0\x0c\x7b\x7b\xfc\xa0\x4d\x7f\x32\x99\xb4\x85\xa8\x7f\xaa\x54\xcd\x23\x73\x18\x62\xc9\x33\xa2\x06\xc8\xe6\x08\x95\x10\x43\x15\x24\x45\x47\x86\xf7\x10\xcf\x65\x33\xa1\x4c\xbb\x2e\x10\xa2\x8b\x99\xcc\x17\xf8\xcc\xbf\x47\x6e\x33\x74\xcc\x65\x95\xe6\x45\xf2\xc2\x96\x66\x15\x3e\xd9\x55\xa2\x7b\x13\x3a\x78\xe3\x18\xfa\x8d\x0c\xbe\x49\x5b\xee\xa0\xae\x80\x62\xa5\xc4\xc1\x40\x81\x88\x4e\xc7\x13\xa3\xae\x17\x36\xd5\x04\x26\x36\x0e\x89\xf9\x9d\x42\x45\xc1\x69\xe2\x8e\x1a\xff\xf2\x81\xa2\x00\x80\x83\xf3\x4a\x27\x2f\x8a\x50\x81\xce\x4d\x25\xf6\xe3\x99\xba\xbe\xd8\xef\x86\xf9\x53\x31\x3a\x53\x68\xcb\x21\x26\x22\xfd\xab\xc5\xc9\x8d\xd6\x08\x99\x42\xbd\x1a\x64\x76\xb2\x3f\xa0\xc4\xdc\x6e\x8a\x53\xc5\x9a\xc6\xe0\x25\x40\x42\xbe\x94\x23\x25\xdd\x3f\x78\x3c\xd5\xba\x0f\x72\x64\x49\x14\x3b\x4f\xdb\xfc\xa1\x68\x07\xdf\xef\xe2\x63\xcd\x2a\xe8\xa0\x75\x2d\xb9\xc3\x16\x9a\xcb\x85\x48\xea\x46\x88\x9e\xd6\xae\x13\x09\x4c\x38\xba\x70\xeb\xa3\x49\xfc\x55\x8b\x64\xcc\xc5\x75\x89\xb4\x35\x6d\x22\x26\x6a\x5a\x36\x91\x1b\xf5\x67\xd1\x0a\xf1\x7b\x81\xec\xb3\x02\x00\xaf\x37\x2b\x5e\x9e\x8a\xb1\x37\xf9\x93\x3c\x00\x4d\x38\xb9\xbe\x06\xf1\x8f\x1a\x3d\xb0\xfa\x2d\x6b\x0b\x40\xac\x45\xce\x39\xaa\x93\x6e\x6d\x15\x2b\xc2\xde\x5e\xfb\x83\x7a\xc4\x86\xaa\xcc\x65\xe8\xae\x59\xe5\x63\xfb\xb9\x2a\xeb\x03\xe1\xac\x40\xf7\x98\x00\x42\x57\xfc\xf7\xee\x54\x4a\xb6\x8e\xed\x37\x7a\x40\x5e\x9b\xe7\xfc\xde\xac\xe7\xec\xe1\x8c\xd6\xe1\x0b\x99\xc0\x8c\xcb\x3c\x00\x00\x87\x00\x67\x0c\xa0\x1d\x62\xe3\xfe\x95\x43\x18\x5b\x14\xb6\x3d\xb3\xea\xcc\x3f\x1d\x5c\xa4\x60\x8d\x5a\xf3\x06\x22\x27\x96\x00\x55\x45\xba\x50\xd1\x20\x5e\xc2\x13\x62\x26\x09\x50\xc3\x70\x02\x8d\xb2\xc1\xe8\xf4\x5c\xcc\x7a\xad\x9b\x12\xa4\xd5\x79\x30\xb9\xba\x02\x99\x33\xbe\x9a\xdb\xfe\x4e\xe3\xf0\x4a\xd9\xd7\x7a\x1a\x16\xfc\x4d\x7a\x70\x94\x22\x9b\x81\x9b\x8d\xb8\xb4\x53\x93\x7a\x96\xc9\x96\x2d\xed\xa7\xe2\xda\x49\x46\xdc\xc9\x08\x57\xb8\x06\xee\xc2\x0e\x93\xee\x93\xe5\x5f\xe9\xf2\x6a\x2c\xd6\x7b\x04\x36\x3f\xaa\x5b\x4f\x47\xb2\xc7\x42\x06\x1c\xe0\x2a\x73\xed\x0b\x1a\x3d\x43\xca\x76\x94\xee\xb7\x8d\x1e\x45\xb4\xff\x06\x79\x5b\x4e\x54\x40\xf0\xa9\xa3\xb6\xfd\x33\xf2\x56\xe0\x3b\x4d\x4c\x15\x5d\xfc\x34\x54\x92\xda\xd9\x6e\xb0\x6e\x8f\x0a\x7d\x92\xe4\xd3\xbd\x9e\x07\x95\xb9\x7e\xcf\xde\xdc\xbf\xdd\x92\x6c\x95\xdd\x50\xb4\xc4\xde\xcf\xb2\xf7\x75\x29\x80\x0b\xf2\x26\xea\xaf\xe9\xc9\xbc\x69\x20\xbd\x98\xce\x4e\xfb\x38\xbc\x6e\x0b\xb8\xbd\xff\x40\xc2\x09\x40\xd6\xdd\x2e\x00\x0e\xe0\xc0\x6d\xa6\xd4\x6c\xb5\xe9\xe3\xeb\x29\x82\x57\x12\xba\xea\x54\xc7\xd3\xbc\x9e\xf3\x16\x2d\xd5\x27\x46\x39\x7b\x6e\x4b\xd9\xd0\x0c\xbc\x3a\x27\x3b\xf4\xb8\x44\x73\x7c\x92\x70\x30\xf8\xd7\x0b\xcc\x94\x9c\x71\x04\x20\xe8\x5a\x02\xe6\x6a\x2e\x0c\x09\xde\xc5\xdc\xe3\x4e\x39\x26\x02\x89\x61\x93\xd1\x83\xf0\xd8\x7e\x70\x00\x6c\x6f\x6c\x85\x7c\x2c\x5e\x9c\x34\xc8\xc8\xe0\x45\x84\xe3\x30\xe3\x66\x4d\x50\xa5\xf9\x30\x0b\xbf\xe5\xe1\x5c\xc0\x6b\x53\x29\x05\xdd\x48\x87\x96\x00\x81\xc5\x8c\xe6\x2d\x1f\x79\x65\x62\x6a\x9d\xcd\x19\x2d\xa1\x18\x5c\xf8\x09\xc1\x74\x3a\x84\x71\xe1\xd4\x6d\x1a\xfe\x7f\x10\x4c\xce\x65\x30\x8c\xda\xf9\x37\xa9\xbf\x3a\x1a\x75\x10\xf0\x8b\x5f\xc5\x02\x7e\x23\x82\xd5\x1a\x17\x92\xd2\x40\x6c\x4a\x83\x2b\x6e\x24\x48\x94\x55\x33\x7c\x48\x63\x0d\xb9\x07\x12\x45\xf2\xdf\x68\x56\x6f\xb9\x25\xa2\x1d\x33\xc7\xb7\xb8\xbd\x34\xe4\x35\x58\x5b\x99\x79\x9b\xcc\x13\xc8\x19\x3f\xb2\xe6\x97\x8f\xc6\xaa\x95\x79\xa7\x32\x06\xc4\x5e\x9f\xb2\x72\x75\xef\x92\xec\xb2\xd6\x5a\x8d\x2b\x21\x9d\xfe\xe3\x93\x1c\x65\xea\xb2\x58\xd7\x5f\x50\x4e\x31\x6f\xbc\x52\xbe\xe2\x3c\x93\x12\x2e\xf0\xf1\xfe\x25\x70\x3d\x37\x91\x59\x2a\x17\xce\x87\xfb\x1a\x22\xc1\x74\xc5\x50\x9a\x97\x78\x8a\xfc\xa3\x93\xc3\x57\x8c\x32\xed\x17\xdb\x18\xa5\xee\xcb\x4e\x19\xcb\x18\x0a\x9a\x2a\xbd\xf3\x84\xec\x7a\x52\xd6\x40\xb8\x5a\x6c\x7c\xbb\x11\x13\xca\xbd\x17\x9e\x9a\xeb\x06\x43\xde\x26\x3f\x8d\x95\x0e\x7f\x34\x24\x6e\x92\xd4\xb3\xaa\x57\xb2\xe4\x48\xc3\x3e\xb7\x8e\xf8\x89\x53\x06\xe0\xa1\xbc\xad\x2f\xea\xac\x5e\x5f\xec\xed\x89\x91\xc5\x1c\x61\x27\x51\xa0\xdc\xb6\xbc\x73\xe3\x85\xb6\x81\xe4\x3a\xa1\xb3\x04\xf6\x80\xe2\xf6\x45\x1e\x03\x6f\x1c\x8c\x2f\x95\xf9\x09\x46\x4a\x83\x00\x21\xec\x6e\x30\x0e\xfc\x3e\x30\xba\xc0\xa3\xa8\xd7\x72\x5b\xb7\xe3\x0f\x42\x32\x33\x9b\x92\x0c\x86\x3e\xae\x73\x93\x85\x90\xe2\xbd\xe2\x77\x23\xe9\xc9\xce\x37\x2b\xfc\x08\x1e\xf1\xbf\x96\x85\x42\xbf\xbe\x6f\x47\x60\xd9\x9e\xa8\x11\xc6\x3f\xf1\x67\x47\xa1\x0c\x24\x70\x6a\x2f\x4b\xe1\x55\x50\xcd\x52\x43\x93\x32\xf8\x7f\xbc\xae\x69\x00\x2a\x1c\x82\xdf\x52\xa9\x28\xd7\x4c\xd3\x5e\x4d\xd1\xd3\x70\x50\x4d\xf1\x2d\x51\x75\x31\xd6\x90\xe9\xaa\xfb\x4e\x7f\x1f\x20\x01\x15\x54\xa2\x02\xc2\xde\x3a\x4b\xf4\x41\x7d\xe1\xd9\x67\xd4\xd3\xc7\x9c\x42\xfe\xf3\xc2\xe8\x69\xd8\x4f\x85\x51\xe8\xa1\x34\xeb\xc3\x60\xef\x05\x48\x55\x78\x44\x30\x5a\x69\x91\xb7\x69\x3f\xfc\x1f\xe8\x35\x92\xac\x1d\x2a\x3d\x56\x10\xfd\xc0\x77\x46\x83\x48\x2b\xb1\x43\xac\xa8\x0d\xe1\xa8\xa3\xe9\xc3\x6d\xc9\xc9\x47\xb1\x7e\x01\x9c\x0c\x8a\xb6\x81\xef\x00\x4a\xb5\x3d\x7b\xbf\xf6\x28\x82\xbf\x25\xef\xd1\xaa\x24\xa2\xbd\x14\xa9\x56\x41\x85\x96\x45\xe7\x01\xef\x53\x65\xd5\x81\x82\xe1\x9a\x32\xda\xff\x1a\xa9\x3f\x89\xe2\x25\xd1\xf2\x93\x8c\x75\x80\x9e\x89\xd5\x84\xe1\x23\x5b\x3d\xdc\xc7\xd5\xc6\xf4\xa7\x9f\x8a\xa5\x40\x2a\x9c\x12\x01\xee\xf1\xa3\xf8\x86\xdc\xa2\xb2\xef\x7f\x0b\x2e\x32\x51\x69\x07\x42\xcb\xe4\xbe\xb3\x68\x46\x73\x7f\x13\x0b\xbf\x85\x3c\x80\x8b\x7a\x39\x15\xd7\x7c\x3c\xa3\x51\x4d\xd5\xbb\xb1\x1a\x0e\xcb\xc3\x3b\x63\xa2\x9e\x24\x02\xf9\xb2\x95\xfb\xf2\x5f\x99\xc8\x38\x8e\x08\xf4\xa9\xd0\xa8\xaf\x54\x9a\x07\x5f\x2f\xd2\x63\x07\x64\x7f\x2b\x1d\xdf\xe9\x51\xf8\xe0\x1a\xb7\x24\xfe\x12\xfa\x86\x86\x2a\x84\x83\xc6\xbd\x77\x9b\xaa\xec\xfd\xde\xb7\x01\x52\x39\x8f\x7c\x66\x41\xe8\x1f\x08\x33\x0c\x1c\xea\xca\xb7\x6b\xd8\xa0\xd3\x4d\xcb\x3b\x18\x8b\x3c\x25\x87\x80\xd8\x92\x1f\xc5\xcd\x7b\xd2\x74\x80\x55\xce\x6d\x38\x2f\x58\x59\xbf\x6d\xc4\xf7\x67\x79\x44\xaa\x90\x67\xf2\x10\x91\x7d\x4a\xbf\x6f\x6c\x1c\x22\x83\x18\xc3\x08\x84\xc3\x73\xe1\x9c\xd2\xa9\xb9\x95\xd8\x25\x12\xa3\x0e\x07\xbd\xda\x82\x8a\xd7\x3b\x91\xbd\xbd\x17\x8a\x6f\xd0\x58\xf0\x62\x6b\x66\x31\x00\x9f\x3f\xbf\x5e\xf0\x9c\x64\x21\xa6\xec\x9f\x8e\x4b\x29\x18\xf8\x3d\x42\xe3\x9a\x55\xfa\xf9\xb8\xcf\x0d\xcf\x4c\x1a\x39\xd1\x78\xdc\xd3\xe9\x04\xfa\xaa\x69\x88\xeb\x84\x23\xd8\x9d\xfe\x06\x5f\x85\xe5\x12\xbb\x6c\x71\xef\x9b\x6c\xc4\xd6\x7d\x0f\x3c\x7e\x14\xd6\xca\x5a\x8c\x92\x10\x90\x2a\x97\x25\x6d\x20\xc5\xa7\x9e\xf1\x97\x22\x23\xa0\x63\x7e\x14\xb6\x52\xa1\x25\xa0\xa3\x37\xcf\x58\xe1\x2c\x45\xe9\x61\xc6\x15\x33\x9d\xcb\xeb\xc9\x2c\x26\x16\x93\xf7\x23\xad\x59\xb7\x57\x73\x6f\x5f\xd4\xce\xd3\xd1\x57\x92\x48\xf0\x5d\x32\x34\x80\x1d\x58\xfb\x23\x0f\xa1\x0a\xad\xaa\x45\x4c\x82\xf9\x1b\xe4\xa2\xc7\x3f\xb3\x25\x18\x56\xe4\xb0\x3e\x45\x6a\x4d\xcc\x8b\x52\x15\x79\x74\x00\x22\xc9\xf1\x5c\x40\xa1\x96\x50\x37\x06\x90\xec\x4a\x02\xd1\xcb\xc9\x20\xe6\x70\xb0\x1d\x7c\x46\x73\xf3\x65\x59\xd4\x79\xd6\x5c\xa8\x42\x36\x16\xf2\x95\x2c\x31\x2f\x3d\x53\xec\x70\x78\xee\xee\x44\x31\xbf\x3a\x46\x76\x88\x37\x5c\xb3\xf9\x15\x88\x8f\xac\xd8\xac\x0c\xb9\xb1\x46\x19\x8e\xfe\x2b\xc2\xc7\xa2\x19\x23\xa9\xbf\x4b\x7f\xa6\x30\x8f\x29\xa1\x35\x62\xae\xbf\x50\x17\x44\x62\x44\x26\xfe\xac\x5f\x06\xc2\x6e\xc8\xb2\xcf\x79\xe2\xaf\x85\xda\x14\x90\x7b\xf5\x99\x4f\xe5\x99\xea\x90\xe6\x9b\xb4\x0c\x9d\x35\xbd\x55\xad\xa0\xc7\xf2\xc5\xd6\xcd\xff\xd0\xb3\xdd\xb3\x21\xf2\x50\x4f\x26\xf8\xaf\xe2\x7c\x15\xed\xa9\x3f\x24\xa0\x8c\x57\xad\x93\xe4\xf8\xf0\x82\xcc\x90\x4a\xbe\x3a\x06\xe4\x77\xb6\xd6\x04\x5d\xbe\x6f\x2d\xa0\x4d\xb3\x92\xf8\x4d\x17\xaa\x04\xcc\x96\x02\xde\xb4\x70\xe0\xc9\x30\x01\x56\xc4\x6b\x75\x3b\x47\x9f\xca\x07\xdd\x32\xc2\x91\x41\x09\x26\x54\x96\x02\x1a\xec\x35\x1f\x7c\x9d\x25\xeb\xa0\x08\x12\x35\x86\x42\xee\xa0\xef\xfc\x2d\x55\x0c\x9b\xc5\xde\x6a\xc6\x19\x48\x89\xa2\x22\x70\x4c\xab\xd9\x14\xe4\xb2\x9f\x90\x71\x1d\x15\x4b\x49\x1e\x7d\xf9\x90\x4f\x14\x38\xe7\xdc\xf0\x48\x48\xff\x89\xc8\x57\x5e\x69\x56\xe8\xe3\x84\x7c\xd4\x89\x3d\x5a\x78\xbe\xf1\xf1\xcb\xbe\x72\x9a\x99\x6f\xe1\x1e\xf2\xf8\x3e\xa6\x83\x21\x30\xbb\x92\xa4\xed\x72\x9d\x6d\x31\xd8\x2a\x56\x66\xfe\x6f\xcc\x7c\x40\x15\x2f\x5c\x4a\xc6\x0c\xf6\xc0\x23\x3b\x53\xc9\x5e\x87\xb5\x48\x2c\x2f\xb5\xd9\x0c\xc6\x4c\x58\x41\x54\x6d\xb9\x09\x93\xa3\xcd\xf8\xf7\x07\xee\xe4\x1d\x6b\x2e\xfd\x90\x86\xd8\x2b\x3e\x1e\x7e\x98\x33\xdd\x53\xc2\x42\x57\x79\xc5\x46\x07\x67\x2f\x23\x9a\x83\x45\x4d\x2b\xcd\xff\x50\x92\x94\x78\xcc\xba\xa0\x3a\x64\x6c\x52\xe2\x0d\x10\x30\xfc\xb8\x2d\x12\x65\xe3\x40\xf6\x73\x6b\xa3\x33\x58\x38\x18\x74\x25\x26\x82\xc9\x09\x1d\xa4\x0a\xc1\xb4\xb8\x6c\xff\x7a\xa1\xfb\xd1\x95\x62\x3a\x5b\x59\x33\xaa\x37\x58\x2d\x32\x98\x43\x97\xaf\x57\x6a\xaa\x86\x0d\x27\xb0\x7f\x29\x11\xb7\x32\x1c\xc2\xa9\x43\x11\xf1\x15\x16\x64\x0e\x4a\xa6\x31\xbb\xf9\x15\x7c\x36\x29\xcd\x98\xf5\x96\x2d\x8c\x51\xfc\x8e\x80\xbd\xc1\xa6\x67\x7c\x79\x30\x8b\xae\x0f\xad\x39\x63\xb2\xfb\xfb\x3b\x1b\x93\xe4\x76\xef\xf6\x36\x30\x91\x6d\xba\x5d\xc2\x2a\x8a\xcc\x1b\xad\x17\x64\xac\x9b\x33\x6b\x62\x49\x85\x98\x69\x29\x34\x65\x69\x2e\x00\x6f\x32\x21\x3f\x30\x79\x29\x92\x12\xaa\xb0\xb0\xfd\x43\xc6\xbf\x27\x6e\x50\xeb\xcb\x9c\x96\xf2\xc0\xc0\x4e\xaa\x3f\xc3\xfa\xf5\x94\xab\x0b\x87\xb2\x5f\xac\x0a\x4b\xf0\x90\x74\x38\xfa\x9e\x39\xef\x2f\xd8\x6d\x5a\x3f\x0a\xb6\xf1\x21\xb9\xdd\xe9\x90\xcf\xa5\x17\x42\x33\x7e\xc7\xe2\x73\x96\xb0\x36\x6d\x3c\x00\x85\xa8\x5f\xd8\x4b\xa6\xa2\x58\x54\x21\xde\x6c\x8e\x16\xee\x92\x90\x12\x43\x8c\xb4\x0f\x28\x26\x23\x71\x31\x9a\x65\x75\x78\xbf\x87\x32\x73\xb3\x8e\xb0\x23\x93\x65\x1d\xff\x4e\xf9\xd7\x5f\x52\x14\xac\xec\x2b\x39\x93\x72\x2c\x09\x27\x92\xaa\x9d\xdb\x68\x01\x8d\x1f\x9c\xd0\x5a\xe7\xda\x58\xfe\x0d\x1d\x57\x09\xa5\xef\x50\x4a\xdc\x8d\x18\x48\x6b\x3b\xb5\xb0\x07\xa5\xb2\x6e\x5b\xd9\x66\x28\x04\xd1\xc8\x4a\x91\x15\xec\x32\xd2\x7b\x11\xc5\x71\x56\xd2\x74\xe2\xa4\x5f\x63\x13\xc6\x1e\x6a\x37\xdc\x23\xf2\x19\xe1\xfa\xd3\xcc\x6f\x3c\xff\x6c\x5c\x8b\x2a\x65\x91\x57\x26\xca\xf9\x69\x09\x7f\x83\xf8\x49\xdb\x6b\x84\x1f\x53\xb2\x0f\x47\x74\x44\xec\x34\x26\x53\x8d\xae\x89\x13\xcc\xc3\x38\x47\xf1\x9d\x4a\x42\x91\x11\xe9\x7b\xf8\xac\xd1\x53\x1d\xf7\xc1\x55\x66\xbe\x01\x27\x4b\x29\xbd\xfc\x96\x93\x7e\x05\xd8\x96\x8f\xf2\x44\x0c\xc1\x9e\x53\x15\xa2\xa7\x4d\xa8\x56\x9b\x77\x71\xf2\x37\x90\x9b\x61\xca\x9d\x93\xf9\xcc\x4a\x84\xcc\x60\x0d\x45\x24\xca\x24\xa4\xc9\x7e\x0b\x4e\x11\x5e\xdc\x2e\x56\xd9\xd9\xf3\xf5\xa0\x4a\x24\x30\x1d\x13\x2e\xf2\x47\x66\xda\x1d\x50\xb2\xa3\xea\xf3\x06\x95\xb4\x36\x0c\x5b\xbd\xff\xd3\x24\x31\x1b\xc9\xb8\x38\x33\x8d\x31\xa3\x5b\x50\x98\xe2\xec\x97\x27\xa6\xa6\x7e\xf7\x0d\x62\x8b\x79\x90\x0c\x63\xec\x01\x44\x42\x2e\x6d\xd9\xd3\x2c\x9c\x0d\xe4\x4e\x3b\x8e\xc3\x8f\xaa\xa9\x84\x1b\x79\xe8\x6a\xc2\x00\x1a\xd2\x8e\xe7\xc0\x4e\x8a\x05\xd1\xcb\x5e\x2f\x64\x17\xcd\xbc\x36\xb9\x8a\x03\xbc\x85\xd1\x13\x9d\x4d\x67\x7e\x68\x35\x40\x7b\xb2\x19\x1c\x50\xca\xfc\x4c\xc5\x6b\xb3\x3e\x17\x69\x22\xdb\x00\xfd\x57\x1a\x33\x2c\xb0\x6b\x4b\x6a\x61\xf0\x23\x1d\xe6\xe5\xbb\x4e\x80\x92\xbc\xf6\x89\xf1\xef\x4f\x8a\x1f\x33\x7c\x94\x3e\xe2\x3d\x27\xfa\x57\xb2\xf0\x89\xda\xa5\x5e\x69\x4f\x36\x40\x8a\x92\x16\xad\xc5\xb9\x32\xe3\x50\x05\x65\x44\xad\x7c\xce\x51\xa9\x72\x5b\x76\x07\xeb\x6f\x90\x3c\xbf\xe4\x04\x9f\x35\x19\x16\xe1\x7f\x6d\x89\x66\xd3\xfa\x65\x46\x67\xf4\x32\x84\x3d\xe9\xaf\x30\x15\x37\x36\x79\x9d\xd9\x4b\x55\x79\x12\x1a\xe4\x2d\xf2\xad\x67\x71\x44\x26\x19\x65\xf3\x54\x14\x6c\x10\xe0\xb0\x96\xd9\xc7\x59\x81\x1b\xc0\x96\x5f\x34\x3f\xb8\xb7\xbe\x08\x78\x03\xa5\xf0\x67\xc9\x88\x5b\xaf\xbf\x4c\x68\x95\xd0\x69\x5c\x7e\x8b\x14\x7d\x22\x65\x62\x5a\x29\x5c\x11\x3a\xf7\x03\xd8\x83\x2d\x0f\xbe\xbb\x3d\xa9\x91\x3b\x8f\xb8\x32\xa8\xb4\xe5\x2e\xa4\x52\xaa\x6c\xc5\x50\x99\x2d\xf5\x47\x6c\xab\x63\x9c\xfc\x54\x29\x0e\x29\x20\xaf\x7a\xdd\x7d\xc0\x8c\x9c\x2f\x5f\x9b\x93\x93\x54\xfc\xaa\x98\xce\xff\x8f\x0e\x71\xf0\x07\x22\x62\x3c\x28\xc3\xd9\xa5\x9e\x12\x75\xde\xb3\x04\x85\x73\x28\x95\x97\xfa\xbb\x35\xa9\x66\x12\x48\x85\xba\x19\x9b\x15\x17\xe7\x20\x95\xf2\xdf\x61\x30\xbf\x00\xae\x6b\x6e\xfd\xe6\x27\xe2\xb0\x30\x31\xc8\x8f\x85\xf3\x4c\x77\x16\x5d\x7a\x92\x8a\xed\x60\x9c\x7a\xcd\xde\xb9\x6f\x00\x72\x3e\x0e\x7f\x4b\x02\xf7\x72\x7d\xfe\x3e\x1c\x76\x17\x14\xc4\x21\xf6\x5d\xfb\x03\x82\x6a\x16\x73\x8d\x60\xe2\xf4\xdf\xe8\xc5\x88\x7a\x30\x99\x54\xa0\x54\xa1\x60\x68\xb0\xc2\xd9\x60\xfe\x65\x51\xc8\x72\x98\x96\x6e\xa4\x13\x88\x07\x02\xc3\x28\xf5\x2c\x0f\x8d\x14\xd4\xcd\x27\x03\x0c\xcf\xd9\x6e\x87\xea\xb2\x10\xc0\x6e\x47\xdb\x91\x7f\x7f\x4f\xaa\x0f\x2b\x27\xed\x97\x5b\xa7\xf0\x56\x8f\xcc\x24\x25\xf1\x2d\x04\xe3\xa0\xf2\x44\xa7\xf5\xd8\x41\x3e\xb0\x81\x84\x55\xbb\x6d\x70\x77\x63\xb8\x87\xb5\xfd\x31\x60\x39\x9e\x0b\xa0\x30\x5d\xc7\x31\x59\xad\xfc\x50\xfd\x23\x69\xd9\x2a\x90\x6b\x4f\xc5\x98\x0b\x7f\x6c\xfb\x2b\xde\x69\x7a\xb1\x9a\x2a\xf0\x0c\x1d\x11\x19\xab\xe6\x49\xb7\x9f\x0a\x3a\x42\x2f\x84\x40\x53\xc1\x46\xe2\xd7\xe1\x6c\x73\x9b\x64\xf2\x33\xc5\x36\x40\x15\xae\xfd\x11\xdf\x47\x21\x3a\x8b\x33\x1f\x45\x38\x99\x6a\x14\xeb\x80\xd6\x7e\x66\x74\xfc\x8d\x07\xcb\x8f\x36\x51\xf1\x10\x3e\x05\x06\xb5\xb0\xc2\x35\x89\xf8\x34\xe0\xd4\x8d\x39\x4b\x4b\xab\xd5\x50\x79\xcb\xb7\xb1\x6a\x56\x83\x21\x2f\xc1\x1c\x20\xca\x17\xda\x30\xf2\x96\xd2\xbf\xa2\x34\x82\xaa\x20\xca\x71\x19\x39\x4e\x10\x97\x10\x2e\xb5\x58\xb6\xd5\x2e\x13\xc2\xd2\xf0\x9b\xd8\x3a\x98\x9b\x3b\x12\x8f\x46\xb6\x88\x2f\x7c\x95\xb8\xcb\x62\x74\x25\x01\x44\x1c\x6e\xef\xcf\x83\xbd\x73\x12\x1d\xf9\x39\xcc\x01\x66\xa5\x9e\x81\x8f\x47\x03\x43\x33\x00\x72\xbe\x3f\xbd\xc6\x4d\xa2\x5e\x82\xa0\xc4\x38\x37\xb4\x93\xb1\x69\x55\x37\xa0\x8a\x43\x5e\xc9\x07\x02\x7f\xf8\xe3\x66\xeb\xf2\x06\x29\x1e\x6c\x58\x34\xce\x67\x14\xbc\x20\x0b\xc3\xa2\x89\x7e\x13\xf3\xe3\x73\x51\x16\x24\xeb\xa1\x3e\x46\x11\xd9\x43\xdc\xaf\x9f\x3a\xb0\x4b\xf9\x9f\x62\xea\x9d\x35\x30\xf6\x9b\x09\x49\xb8\xd8\x7a\xc3\x75\x98\xc3\xb1\x08\x29\x39\x19\xfc\x4b\xad\xe7\xce\xd2\x2c\xac\x57\xe7\x2a\x75\xb1\x1f\x3c\x75\x6b\x57\x56\xb6\x0d\x55\xc9\x4a\xba\x94\x2d\x0d\xac\x71\x85\xcc\xe2\x92\xa5\x98\x8e\xc9\x28\x8b\xb0\xd8\x87\xca\x11\xd5\x53\x61\x4a\x21\x0e\xad\x9e\x0d\x34\xb7\xd3\x8e\xb5\xaa\x41\x6c\x2c\x2a\x2f\xe9\x35\x1c\x2d\x0a\x7b\x7f\x4e\xd9\x1c\x5e\x19\xde\x59\x68\x0a\x5f\x66\xb7\x9d\xff\x80\x09\xf1\x9c\x1c\x47\x0d\x00\x24\xad\x3f\xaa\xae\x51\x3f\x0e\x80\x57\x7f\xfa\xf4\xa7\xe4\x15\x32\x7c\x8b\xa4\xdc\x42\x8a\xa0\x22\x4e\xd4\xcf\x84\xcd\xe4\x44\x92\xc9\x83\x5a\x6e\x96\xec\xd8\xe3\xcf\xd5\xd7\xed\x4a\x05\x12\x97\x17\x81\x53\x69\x15\x6c\x15\xd9\x56\xac\x4e\xca\x92\x96\x96\xfc\x84\x18\x74\x54\xbd\x7f\x59\x02\x92\x62\x26\x39\x75\x0e\x4c\xa7\xe2\xfd\x3f\x78\x70\x89\xcc\x71\x1b\x9e\x99\x3c\x70\xb9\x96\x06\x53\x08\xe2\x02\xbe\x82\x20\xfb\x7d\x03\x85\x8e\x27\x82\x4b\x75\x94\x0d\xe8\xd8\xa5\x36\x3e\x12\xaf\xa3\xd7\x62\x05\xbd\x57\x1e\x97\x09\x4d\x77\xda\xc8\x64\x27\x9c\x56\x6c\x12\x01\x26\xd8\x1d\xd9\x69\xc5\x4e\xd5\x61\x87\xb8\xc5\x3f\xff\x0f\x00\x0f\x13\xf0\xec\x87\x5c\xaf\x8e\x52\xe9\x00\x04\x06\x21\x94\x81\xa7\x92\xcb\xaa\xfe\x48\xd1\x4d\x22\x19\x39\x5c\x80\xb1\x83\x91\x4a\x77\x2d\x37\x9a\xcd\xdb\xdc\x5d\xd8\xd3\x7c\x91\xdb\x12\x40\x1b\xc5\x3b\x7a\x92\x01\xa5\xe5\x59\x84\xdd\xd9\x9b\x0b\xc0\x7e\x88\xd0\x9f\x10\xe6\x32\xf1\x94\x7b\xbf\x44\x6a\xf0\x08\x3b\x9c\x63\x4f\x95\x90\x4d\x36\x44\x6f\xb9\x34\x34\x02\xaf\x4b\x30\x5a\x1d\xe6\x51\x92\xe4\xe0\x6d\xcb\x76\xc2\x9b\xf3\xcd\xa1\xae\x8f\xe6\x8a\x66\x17\xaa\xe8\xdd\x5d\x21\xde\x16\x8d\x63\x75\xdc\xbb\x9e\x24\xfe\x3d\xe9\xe6\x88\x2a\x9f\x21\xa6\xdf\x4c\x59\xc3\x74\x56\x40\x03\x49\x43\x1f\x4d\x24\x81\x49\x84\xcc\x42\x60\xa6\x92\x17\x2b\x98\x48\x01\xf7\x55\x72\x49\x2b\xf6\x5b\x4b\xc2\x43\x23\x78\xaf\x16\xda\x7a\x91\x4c\xe0\xd4\x53\xd8\xe1\x4b\x2e\x79\xd2\x8c\x22\xd3\x42\x89\x34\xd7\xe9\x28\xa0\xfd\xa1\x78\x04\xc1\xb4\x54\x25\x2a\x0f\x0c\x22\xc6\xf5\x5e\xba\xbb\xf2\x6b\x27\xdc\x29\x6e\x27\xf9\x6c\x51\x16\x50\x64\x41\x30\x71\x23\x55\x39\x90\x86\xa7\x79\xfb\x02\x76\x5e\xbc\x43\xd1\x61\x11\x66\x5a\xc1\xea\x8c\xe5\x60\x65\x13\x02\xec\x99\x7e\x14\x59\x24\x50\xb3\x68\x78\xcb\xab\xcf\x9a\x8c\xa1\x74\xb6\xee\xb2\xc5\x24\xe3\x9c\x92\xe4\xbe\x8a\xaa\x1e\xd3\x97\x80\x80\x07\x6f\xd3\xf4\x42\x9f\x90\xac\x04\xc2\x2e\x52\xad\xe4\x2d\xa4\x0c\x46\xd3\x62\xd7\xcc\x54\x66\xcf\x9d\xff\x03\x3d\x3e\x46\xda\x9b\x72\x89\xdb\x64\x80\x61\x31\x03\x53\x09\xf4\x2f\x07\x15\x9b\x2a\x4a\x16\x1f\xf0\xa0\x3a\x56\x39\xce\xea\xc3\x55\x98\x10\xe2\x42\x90\x46\xcb\xf0\x1b\x4a\xab\x73\x9d\x0b\x9e\x8d\x34\x36\xd6\xb3\x79\x32\xdc\xa8\x68\x56\xec\x4e\x02\x70\x6e\x02\x0f\x8d\x63\x40\x8c\x07\x38\xd2\xf5\xd7\x70\x4a\x9e\xaa\x60\x3e\x63\xd8\x7e\x95\x0e\xd9\xe9\xf7\xac\x24\x8d\x09\xa2\x91\x1a\x42\xac\xa0\xb1\x2d\x04\xe7\xe0\x75\xa0\xde\x11\xb4\x8a\x03\xbc\xd9\xa2\xfd\x26\xc8\xc9\x81\xbd\x9e\x38\x64\x1f\xec\xba\x76\x94\x2f\x9c\x18\x91\x89\x6e\x56\x8b\x83\xb6\xf9\x51\x70\x84\x4f\x21\xa7\x18\xdc\xd7\x2a\xe5\x15\xd5\x17\xf6\x95\x31\xc8\x6d\xdc\x7d\xa5\x4c\xa4\x6d\xde\x9e\x32\x8b\x01\xf0\x2f\xf9\xfa\x12\x66\x57\x88\x9b\xc0\x8a\x94\x18\x6d\x74\xdd\xed\xd8\xec\x6d\x1f\xba\xc8\xa1\x47\xc9\x83\x81\x3d\x30\x5b\x73\x71\xba\xce\x20\x40\x06\xac\x5d\x3b\x03\x56\x50\x37\x0d\x46\x01\x52\x71\xee\xe8\x2f\xb7\x25\x70\x70\xb8\xa6\xdf\x71\x11\xb6\xe5\x2a\x3c\x21\x2c\x40\x88\x61\x70\x80\x4f\x99\x15\x29\x40\xb7\x01\x64\xb0\x74\xd1\xa5\x46\x22\x30\x7a\xda\xec\xd2\x65\x67\x63\xb6\xbb\x7f\x84\xd8\xa3\x36\x24\x86\xf5\x10\x2b\xab\xb1\xaa\x1d\xee\x89\x22\x34\x0c\x2f\xd6\x02\xbf\x07\x3d\x8d\xd3\x1a\x03\x6c\x99\xa4\xc2\x0f\xda\xe3\x84\xe0\xa1\x06\xc9\x9e\x80\xb3\xd1\x6f\x7f\x81\x75\xb3\xc3\xf3\x8d\x81\x8c\x51\xbc\x31\x40\x37\xd1\xee\xdb\xca\x06\x93\x1b\xa2\xac\x2b\x29\x09\x7e\x0b\xc2\x95\xd8\xc9\x13\x93\xce\x39\x38\x21\xe1\x23\xa8\x37\xc1\xab\xe8\xc3\xe0\x96\x0b\xfe\x70\x38\xf2\xdd\x14\xe4\x76\xe7\x81\x52\x91\xff\xf0\x9d\x0d\x4e\xa0\x82\x45\xf2\xab\xba\xb5\x2c\xa7\x26\x19\x04\xf9\x65\xb0\xdc\x8e\x81\xe8\x20\xcc\x1f\x69\x81\x7b\x43\xd7\xf3\x36\x99\x9a\x5d\xea\x7e\x2c\x7a\x94\x24\x19\x4e\x91\xe7\x7a\x50\x43\x10\x75\xc1\xb0\x17\xd2\xa2\xb8\xa5\x3d\x98\x0f\x54\x0e\x05\xaa\x0e\xb7\x66\xf7\xf3\x82\x60\x1e\xb5\x2e\xa8\xbf\x61\x15\x49\xb6\x53\x02\xdd\x5d\xb9\xd1\x52\xe6\xb9\x38\x0d\x9b\x0e\x49\xe6\x9e\x59\x62\xac\x37\x2d\x68\xb0\xfd\xd0\x7a\x5a\xdd\x79\x40\x3a\x32\xa1\x4b\x31\x33\xd2\xcd\x01\x27\xf9\x68\x82\x26\x28\x1c\x63\x8d\x40\xb0\xc8\xc2\x7b\xba\x63\x89\x8d\x7f\xfc\x03\xc7\x31\xd2\x75\xf9\xbb\x4e\x5f\x9a\x20\x71\xe2\x5a\x8d\x87\x04\x66\x0a\xa6\xef\x8b\x80\xa9\x8c\x5c\x47\x16\x91\x3a\x00\x2f\xc8\xaa\xce\x26\x5c\x63\x0e\x8c\x09\x6d\x65\xc4\x86\xd6\x8d\xf2\xb9\xad\x9b\x92\x62\xeb\xde\x64\x08\x8a\x04\xe0\x9e\x70\x05\x73\x78\x95\x26\xe3\xc2\x6f\x44\x5e\x0a\x78\x0d\x53\x3c\x6d\xc4\xb9\x9a\x86\x17\x50\xef\xf3\x16\x39\x6b\xb4\x47\xf0\x39\xab\x62\x02\x28\x0d\x62\x51\x58\xdc\x1a\x9d\x94\x74\xbd\xad\xee\x4c\x4e\x46\x18\xc8\x48\xd2\x61\x2d\xa7\x50\x14\xaf\x23\x51\x07\xb7\x55\x41\xe6\x4a\x68\x05\xaf\x26\x6e\x8b\x00\xac\x72\x99\x14\xaf\xec\xb7\x16\x3c\x51\x81\xb9\x5a\x41\x1f\x45\x28\xe0\xf7\x79\x1f\x00\x2d\xd7\x31\xea\x2e\x47\x16\x0e\xb0\xf2\x7b\x07\x49\xec\x6e\xe4\x51\xda\xb4\xf0\x2e\xa9\x60\x02\xc0\x8c\x8c\x36\x50\x5f\xd2\xa1\x25\x67\x08\x14\x46\x2c\x7b\xcf\xf5\xe4\x6f\x3d\x19\x3a\xa2\x79\xf6\x97\x79\xe3\x64\x25\x6d\xc6\x86\x3f\x50\xd4\x34\x16\x28\x18\x4d\xf3\xdf\x40\xf2\x81\x6f\xbe\xcb\x62\x27\x83\x80\x20\xae\x7a\x23\x6a\x6b\x0d\x72\x49\x30\xde\x42\xb7\x2d\x24\xb2\xc2\xcd\x43\x00\x03\x55\xe3\x06\x00\x45\xca\xef\x00\x08\x05\xf5\x8b\x00\x3f\xf9\x4d\xce\x4a\xd7\x3b\x9b\x83\x06\xd6\x17\xb0\x61\x4c\xe6\x40\x85\xc2\x4a\x58\x41\x80\x69\x21\x03\x96\x2c\x1c\xa0\xa0\xf6\xe4\x02\x0e\x3b\x11\x68\x9c\x60\xa0\xe4\xb4\x86\x0d\x91\xc2\x08\xd9\x14\x71\x50\x35\x5e\x6d\x10\xe0\x99\xd7\xed\x60\x8d\xcf\x89\xdf\xae\xe1\x9e\x45\xb3\x87\x65\x08\x0e\xa2\xc8\x5c\x01\xbf\x35\x6b\x51\x89\x51\x4d\x3e\xe8\x28\x87\x33\xad\x40\x46\x54\xbd\x60\x99\x33\x9e\xfe\x9d\x79\xe5\x2d\xb1\x11\x61\xcd\x0e\x51\x45\x7e\xd3\x34\x76\x16\x6c\xda\xcb\x21\x56\x69\xa1\x80\xa7\x05\x34\x54\x42\x0f\x44\xec\xa2\x60\x70\x83\x65\x1c\x7c\xa4\x30\x7e\xf3\x08\x88\x34\x24\xbc\x87\xc9\xd0\x8f\x3a\x98\xf7\xf4\x7d\x42\xf6\xbb\xdc\x09\xd7\xc9\x6a\x65\x95\x39\xe7\xbd\x76\x4b\xea\x3d\x92\x05\x45\x81\x18\x3b\x00\x2a\xa5\xa8\x4a\x2b\xcc\x04\x6f\x4c\x46\x48\x5e\x2c\x7c\x17\xf7\xb2\xe4\x24\x2a\xcb\x1e\x0f\x78\xeb\xdc\xbf\x9b\x05\x67\x83\x76\x92\xd2\x7f\xb9\xcc\x41\xb8\x5f\xcc\x39\x83\xfa\xdd\x72\x6f\x4a\x15\x7f\x6c\x20\x7d\xef\x08\x1f\x7b\xca\xe6\xc3\xaf\xaf\xfd\x64\x44\x3e\x5e\xae\xb2\xb7\xaf\x56\xf5\xad\xfa\x2a\xa7\x83\x9d\x5d\xd6\xcb\x4b\xaa\xc9\x66\x59\x28\x3d\x82\x6b\x0d\x0a\xca\xbb\xf3\x50\x5f\x9e\xc4\x26\x58\x29\xae\x6e\x48\x0e\x4f\x6a\x7e\x96\x7b\x0a\xea\x96\x70\xdc\x0a\x68\x00\x13\x49\xf0\x8a\x36\x0c\x67\x06\xda\x56\x45\x34\x5e\x8a\xe1\xa1\x69\x80\x22\x81\x12\x04\x43\xf9\xbc\x53\xc1\x9f\xff\x83\xa3\x39\xc2\x39\xbb\xd7\x23\x15\x18\x8b\x6e\x83\x08\xb6\xbd\xde\x33\xb9\x5c\x63\xe5\x66\x8d\xc2\x36\x63\x20\x80\x92\x59\xbf\xac\x83\x7a\x0a\xe7\x8a\x53\x7e\x1d\xf8\x03\xf5\x58\x8b\x27\x3a\x05\x51\x0b\x9b\x16\xec\xeb\x96\x40\xcf\x84\x88\x05\xa0\x4a\x5b\x42\xd9\xd9\x24\xfa\xeb\x70\x0c\x97\x1d\x26\xaa\xa2\xfb\xc8\xbf\xac\xd4\x16\x58\xb3\x48\x1b\xd3\x29\xd9\x95\xba\x37\xeb\x8a\x8c\xd1\x9b\x74\xe4\xea\xa6\x07\x31\x51\x62\xe8\x41\x99\x8a\x0b\x63\xc6\xf6\xd4\x66\xa4\x04\x10\x5b\x58\x4a\x15\x1b\x72\xa5\x18\xfa\x14\x19\x89\x39\x8f\x61\x5c\xc0\xd1\x89\x07\x4e\x0c\x58\x10\xfe\x0c\x63\x7e\x7e\x1e\xff\xe9\x53\xcc\x83\x2a\xd6\xbf\x50\x24\x70\x03\x33\x09\xd0\x13\x10\x19\xe4\x3a\x06\x01\x8d\xc2\x24\xbf\x8d\x65\x94\x34\xa8\x49\xd9\xcc\xfe\xc2\x20\x9a\x87\x84\x4c\xdb\x51\xb8\x44\x94\x7d\xcb\x7a\xc3\x59\xe0\xf0\xd9\xe6\x22\x59\x75\x20\x79\x5a\x92\x82\x0d\x1b\x7c\x87\xaa\x1e\x02\x1f\xd1\x5c\x04\x19\x0a\x0d\x05\xf0\xab\xf8\x25\x0c\x4e\xe4\xe6\x31\x48\xf0\xf3\x40\x0c\xb1\x78\x70\xde\xe9\xfd\x36\xc5\x8f\x2a\x7f\x8e\x4d\xf0\x2b\x3b\x30\x6c\xd5\x25\xf6\xbd\x37\xee\x46\x46\x5e\xfc\x3e\xa2\xf7\x3d\xe7\xc5\xd4\xd5\x46\xc8\x51\xc7\x26\x0a\x7e\x98\x88\x1d\xbb\x94\x2a\x23\x22\xf5\xd4\xf4\x4e\xed\x6c\x7e\x0c\xe8\xfa\x8b\x3c\x86\xff\xa7\x0e\xcb\xc4\xdb\x06\x94\x8c\x09\x92\xea\x61\x9d\x79\x1c\xb7\x50\x0b\x86\x52\x91\xba\x00\x09\x7d\xd4\xaf\x1a\xdc\x1e\x05\x0d\xf6\xa9\x5e\x5a\x4d\x03\xbc\x05\x9e\x68\xb0\x85\x3a\x1f\xef\x2f\x12\xa7\x57\x3b\xe9\x6c\x8d\x70\x2d\x15\xbe\x7e\xec\x05\x14\x61\x20\x13\x0f\xad\xb7\x3a\x45\xca\xc8\x5e\x89\x15\x08\x84\x24\x79\xbc\x82\x44\xd2\xc8\x05\x86\xa3\xc7\xd9\xd9\x0d\x79\x31\x15\x52\xe1\xd6\x09\xd7\x8b\x4c\xb2\x20\x9d\xb4\x4f\xc3\x6f\x57\xca\x96\x80\xb2\x98\x89\xba\xa1\x59\x33\x76\x90\xbc\x26\x63\x08\x13\x96\x71\x76\x0b\x99\xcb\xff\x0a\x37\x58\xf0\x22\x0b\xfa\x04\x56\x19\x70\xeb\x15\x2d\x78\x32\xac\x46\x96\xc8\x29\xe0\xb7\x6d\x85\x56\x51\x48\xc1\x2c\x77\x4f\x34\x75\xf5\xf0\xa6\x14\x9f\x51\xbd\xda\x5a\xba\x77\x59\xe5\xc1\xcc\x49\xb4\x7b\x26\xd6\x9b\x84\x27\x40\x17\x0c\xde\xdc\x43\xda\x97\xae\x11\x47\x51\x23\xf3\xc5\xf0\xd3\xf8\x4b\xb3\x65\x5c\x3c\xb6\x41\xe6\x6c\xf9\x3c\xb6\x57\xa9\xc4\x56\xba\x23\x8d\xa0\x01\x42\x12\x20\x3a\x9f\x20\xd6\xcb\x91\xf0\x19\x0e\xcb\xbc\xb5\x00\xdf\x00\xf5\x41\xa0\x06\x30\x29\x05\x31\x1e\x15\x3d\x2f\x3e\x26\x90\x81\x85\x45\x59\xf2\x45\x34\x2e\x7c\xb1\xb4\xa2\x42\x51\xdc\x75\x80\xf4\x87\x13\x49\x1a\xd6\x4e\x6f\xe4\x82\x3d\x17\x5c\xab\x9d\xef\x83\x9e\x89\x03\x1c\xfa\x88\xe5\xda\xbf\xd6\x70\x3c\x5e\xfc\x36\xec\x9d\xd4\x46\x6a\xbb\xba\xd8\xc6\xdc\x60\xb1\xd4\x90\xe5\x94\xa4\x3b\x98\x36\x87\x65\x3e\xa9\xc6\xf4\x6c\xbf\x9c\x04\x45\xf2\x3a\xda\xe5\xbc\x2d\x39\xee\x76\xf1\x4b\x04\xf6\x43\x6b\x80\xdc\x20\xc5\xda\xfa\xe9\x51\x52\xa0\xa5\x8b\x3e\x02\x90\x88\x20\x4a\x42\x26\x1c\x6a\x23\xad\xd1\x81\xc7\xb7\x2d\xd0\x64\xa5\xe1\x44\x10\x3b\xdb\x51\x5f\xb1\x95\x66\x0c\x69\xeb\xe9\x3f\x11\x89\x39\x27\x55\x68\xd9\xbf\xef\xaf\x06\x06\xfd\x9a\xb0\x11\x46\xda\x24\xf1\x9a\xc1\xaf\x71\xc8\xb4\x3d\xd6\xb2\xe9\x40\x62\x9e\xa9\x15\xee\x29\x81\x1e\xef\xa5\x51\xe7\xe1\x43\xd2\x3d\x6d\x72\xa7\x31\x64\xb1\x15\xcb\x9c\xdc\x12\x30\x74\x79\x20\x86\xc8\x00\x23\xd2\x93\x68\x42\xa8\x8f\x78\x5a\xb1\xf0\xa0\x75\xc7\x2f\x00\xd9\x24\x27\x2c\x3e\x66\x73\xb5\xb7\x3e\x80\x92\xf4\x54\xd1\x3f\xcd\x54\x52\xbd\x26\x64\x3f\x53\x2a\x38\xc2\x95\xe8\x84\x26\x02\x76\xca\x01\xd6\x3b\xc5\x6b\x42\x85\x5a\x74\x23\xd6\x83\x94\x4e\x84\x3a\xc5\x4f\x1a\x0d\x11\x40\x9c\xfa\x6e\xb2\x0f\x58\xc8\x62\xd7\x51\x6c\xf9\x8f\xee\x05\x6d\x4d\x4f\x10\x5c\x52\x09\x82\x99\x06\xbd\x94\xb2\x72\x40\x81\x37\x8d\xc9\x13\x9c\x4b\x1d\x09\x1a\xf9\x4f\x03\x61\x58\x00\x5e\xaa\x81\xd1\x3e\xf2\x94\x2a\xce\xe6\x63\xe7\xae\x44\x31\x91\x46\xb2\x83\x74\x26\xb9\x3c\x89\x10\x1f\x84\xc4\x9b\x44\x5e\xf2\x82\xf7\x1d\x51\x00\x4d\xcb\x13\x03\x47\x3d\x1c\x68\x8c\xba\x38\xb8\x1b\x0b\x51\xcf\x62\x96\x49\xc8\x67\xb1\x0e\x2e\x60\x06\xec\xb4\x36\x60\xaf\x4b\xc8\x15\xd4\xdb\x5a\xc6\x6e\x40\xd1\xbf\xea\xd9\xf1\x76\xe9\x6d\xa6\x73\x84\x60\x8a\xc0\x3e\x5a\x14\x41\xf0\x73\x0a\xd4\x4c\xf5\x52\x4f\x4d\xa0\x7d\x09\x8a\xa6\xef\xdc\xdd\x52\x09\x8c\x5f\x13\x77\x6d\xf5\x07\x42\x6c\x17\xfa\xf2\x1d\x75\x6b\x62\x7a\xf2\xd8\x00\x22\xac\x5c\x63\x57\x56\xf0\xee\x86\x86\x33\x2b\x54\xa1\x3d\x01\x11\x87\x4e\xab\x01\xf8\x1a\x75\xd8\x9d\x2a\x40\xa9\x30\x9f\x04\xe1\x13\x91\x88\x47\x1d\xa7\xa2\x2a\x58\xe2\x98\x7f\x98\xc7\x68\x12\x7a\x2d\xf2\x02\xe8\xbb\xe7\xbf\x46\x6d\x54\xd0\x01\x24\x9c\x7b\x7a\x2c\xc4\x5b\xf6\x88\x98\x3a\xc6\xd7\x2f\x15\xec\xf6\xd7\x70\x96\xbf\x49\x4f\xd8\x60\x90\x97\x02\x0c\x16\x73\xb4\xa8\xaf\xbf\x0f\x02\x96\x42\x81\xe5\x66\x17\x9f\x0b\x61\x83\x24\x70\x51\x67\x42\x6f\x1b\xd8\xc9\xe0\xe0\x7a\x86\xa3\xe4\x4d\x04\x36\x12\x9f\xed\xc7\x29\xfe\xc5\x20\xfd\xcd\xd0\x9b\x54\xd0\x10\x8f\xf5\x50\x83\xfb\x7c\xa1\x0e\x00\xac\xed\x3e\x25\xb8\xaa\x4a\xd6\x5c\xc0\x69\x3f\x42\x35\xf6\x55\x61\xad\xe1\x41\x29\x5e\x3c\x58\x58\x99\xdc\xe1\x61\x72\xa6\xce\xce\x16\x00\xf3\x77\xed\x82\xea\x85\x9f\x85\x97\xdc\xb4\xec\xd4\xb2\x81\xb4\x3a\xa8\x6f\x7e\x3d\xd2\x21\x1e\x5b\x6b\xf0\x1f\xce\x22\x30\x05\x1d\x6c\x75\xb7\x15\xec\xee\x9d\x62\x83\x6f\x51\x94\xe9\x86\x83\x81\x8b\x12\xae\x72\x13\xb3\x15\x82\xbc\x64\xe4\xdb\x7a\x7b\xe2\x60\x66\x2f\x8d\x97\x3d\x8d\x14\xf8\x46\x0e\xf1\x18\x31\x6e\x71\x2b\xcb\xf2\x4b\xfd\xc2\x12\x52\xb8\x7d\xe5\xa3\x46\xe5\x3c\x52\xc7\x05\xc2\x8d\x87\x0d\xd0\xbd\x57\x79\xb8\x1c\x37\xd6\x64\x2a\x1c\x74\x24\x96\x3a\xba\x84\x15\x5d\xbd\x10\xd2\x58\x9c\xcd\x25\xdd\x27\x96\x78\xb0\xc1\xa2\xc9\x51\x33\x21\x08\xdd\x96\xc0\xa1\x8c\x66\x40\xb2\x55\xd2\xd6\x3c\x9b\xb3\x0c\x37\x16\xdd\x19\x59\x49\x45\xa8\x1c\x7d\xe7\x18\xa9\xb0\x6e\xcd\x87\xa1\x07\x47\x52\xce\x86\xc5\xee\x25\x59\x60\x5d\x5a\xda\xd4\x0e\x81\x6c\x13\x54\x9d\x39\x75\xb3\x9b\x14\x36\x60\x63\x8a\x9a\xd4\x17\x85\xe2\xb4\x95\x12\x27\x5f\xcc\x60\xd6\x1e\x1e\x80\xe3\x83\x4b\xaf\x95\x32\x68\x8e\xb2\xc9\x43\x58\xf2\x29\xef\x47\x82\x99\x55\x75\x31\x03\x3e\xfb\x08\x55\xa5\x5e\x40\xbe\x3b\x70\xb4\x03\x0f\xb1\x25\x36\xab\x43\x8b\x07\x10\x8c\x6d\xc8\x7d\x05\x34\xf8\xc6\x82\x62\x11\x61\x4d\xc4\xdd\x1d\x88\xce\xee\x53\x78\x4c\x99\x88\xa7\x2e\x4f\x61\x27\x84\xc7\xe7\x8a\xd8\x32\x1b\x1b\x98\x4c\x83\x4f\xe1\x10\x54\x1c\xc0\x6d\x0a\x77\x19\x9a\x4f\x60\x77\x0e\x05\x58\x9a\xbc\xee\x1b\x69\x8b\xbf\x0d\xa6\x08\x54\x19\x97\x90\x4d\xd2\xab\x27\x2a\xb1\x9c\xb0\x6b\xc6\xc1\x17\xe2\x38\xc0\xad\x16\x02\xab\x9c\x4d\xf1\x3d\x4b\x92\x0e\x18\x96\x6c\xa0\x2a\x37\xb4\x89\x5c\xe4\xfd\xd0\x52\x82\xb9\x09\xc3\x88\xd9\x38\x2b\x50\x9c\x2f\x93\x97\x94\xe5\x7d\x8b\x39\x4c\xac\xdc\x90\x9e\xc9\xc0\xfa\x4a\x08\x5f\xbb\x53\x8a\x4c\x9b\x0c\xb0\x28\x69\x69\x5c\x0d\xbb\xaa\x61\xd9\x19\xa5\xba\x97\x0c\x13\xd1\x42\x84\x02\x05\x51\xec\xf6\xef\x93\xc1\x4e\xd8\xb8\x8d\x10\x92\xb8\x11\xd4\xdc\x35\x62\x25\xa8\xda\xc9\xd2\x86\xd6\xca\x49\xed\x9c\x5a\xb0\x5a\xb6\xd9\x71\x6b\x79\x4b\xd9\xf1\xe6\xe9\xb5\x39\xb0\x08\x4f\x76\xc0\x40\x23\x04\xcf\xc1\xc0\x47\xd6\x24\x5b\xd7\x6c\x53\x0d\x9c\xc8\xa0\xdb\x37\x02\x73\x83\x5b\x1a\x9e\x92\x23\x2c\x1d\xfc\x8d\xb4\xee\x18\x2c\xfa\x9f\x56\xf2\xa0\x30\xd1\xde\x90\xc6\x9b\x0b\xaa\x86\x12\xe6\x3a\x07\x22\xdc\xc4\x1c\x8d\x14\x11\x80\x72\x37\x45\xdf\x44\x8d\x81\x5f\x29\xa7\x6c\x54\xf2\x82\x32\xc8\x2b\x2e\xb4\xb7\x88\x0b\xe2\x2d\x2e\xdf\x50\xfd\x7b\x21\xa9\x30\x19\x99\x32\x7e\xa4\x55\x84\xba\x53\xb4\x00\x26\x54\xf5\x6f\xf1\x90\xa9\xb6\x08\xd6\xa5\xab\xcb\xb6\x8d\x79\x08\xbe\xdf\xac\x8a\xe0\x6d\x95\x89\xf3\xae\x78\x26\x10\xd6\x0e\xac\x12\x50\x98\xb0\x7f\x74\x12\x8c\x74\x16\x7e\x91\x15\xb2\x19\xd3\xeb\x97\xa9\xc9\x3e\x28\xa2\xe5\x52\x6a\x4e\xa3\x16\x83\xf2\x95\xaf\x15\x30\xbf\xef\xef\x86\xdb\x86\x07\xd8\x72\xe1\x80\x63\x97\xa0\x04\x22\x05\x07\xc1\x41\xd6\x00\x38\x1d\x7d\x2c\x28\x11\x7d\xcb\x0c\x04\x42\x29\x72\xfb\xba\x71\xcd\x23\xc2\x35\x6f\x42\x40\x8b\x74\xe0\x4a\x98\xaa\x8d\x0b\x0a\xf0\xf8\xdb\x6a\x91\x00\x6b\xaf\x63\xf3\xf0\xd4\xf7\x38\x2e\xd3\x77\x8f\x5f\xb8\xfb\x8f\xce\xe1\xb9\x27\x5d\x04\x73\x80\xbe\xff\x6c\xa3\x89\xe4\x44\xb6\x9d\xe6\x08\xf9\x10\xaf\x4c\xae\x62\x2f\x6c\x0b\x5a\xd0\x7e\x38\xda\x39\x04\x91\x06\x90\x43\x23\x83\xbf\x33\x27\x81\x56\x23\xa1\x5f\x2a\x0d\x15\xda\xf3\x83\x88\x62\xb3\xa5\x57\xcc\x24\xa8\xc7\x49\x74\x62\x32\xa7\x7d\xb9\x2e\x71\xec\x86\xcf\xe1\x93\xa6\x87\xa4\x94\x9c\xec\xc5\xc0\x2e\x92\x8a\xcf\x90\xca\x52\x90\x35\x8c\xce\x89\xb1\x89\xe7\x4d\x40\xec\x04\xb0\x37\xf0\x5d\x0b\x01\x0c\x2e\x19\x21\x17\xc8\x60\xd4\xca\x11\x82\x64\x08\x51\x0b\x19\xd9\x72\xcf\xf0\xec\xc7\x27\x10\x7e\x0b\x08\x9a\x6a\xcc\xf9\x3b\x0d\x43\x66\x00\x79\x20\xcb\x6b\x2d\x9f\x3c\x73\x47\xdf\x43\xa6\x8a\x30\xb0\xcc\x4f\xb8\x41\x74\x82\x24\x61\x28\x1e\x7b\x19\x14\x45\x0c\xea\xf2\xaf\x15\x32\x18\xf1\x24\x8d\x4a\xbc\xd8\x16\x9c\xd1\xe1\xc3\x95\xce\x20\x63\x45\x73\x03\x84\x21\x04\x93\x92\x36\x77\x46\x0e\x08\x90\xa7\xa1\x07\x78\xc0\x51\x46\x8e\xba\x14\x6f\xb8\xf8\x63\x71\x53\x21\x20\x89\x45\x8d\xbd\x62\xe6\x4c\xc9\x10\x85\xe3\x25\x40\x44\xe6\xc9\x01\x81\xc2\x2c\xb3\x07\x36\xde\x9c\x85\x79\xa2\xd0\x11\x31\x0f\xb0\x91\x25\xc5\x20\x14\x32\x56\xe2\x48\xe1\x76\x63\x06\x5d\xb0\x27\xca\x1a\x9c\x49\x29\xc4\x8a\x71\x01\x01\xba\x11\x8f\xd0\xcc\x37\x9e\x4a\x12\xc0\x2d\x89\x48\x0c\x6e\x25\x39\x23\xca\x39\x8c\xaa\x6f\x7a\xd7\x95\xaa\x25\xc7\x06\x51\xcf\x92\xba\x08\x83\x98\xb9\x78\x1a\x12\xaa\x08\x05\x04\xe1\x4d\x59\xef\xc1\xe2\x08\xb1\xc4\xe4\xba\x0f\x02\x22\x39\x17\x74\x81\x41\x1f\x21\x29\xec\x01\x38\xb6\x9d\x60\x19\xc5\xa9\x30\x13\xc4\x69\xa0\xce\x17\xd6\x3e\xe8\x9b\x0d\xeb\x1a\xbd\xed\x12\x53\xe2\x1f\x10\x04\xaa\x01\xef\x4f\x81\x99\x0a\xcc\x88\x31\x5b\x04\xc3\xc2\x93\xab\xa1\x02\xb4\x7c\x21\xd8\xc8\x44\x44\x84\x20\x53\x6f\x44\xc1\x13\x4a\xd8\x78\x66\x27\xc0\x88\xfb\x26\x8b\xe8\xda\x9a\xad\x2d\x25\x8c\xe3\xf6\xea\x5f\x98\x70\x88\x79\x4f\x6d\x22\x38\x4e\x19\xc6\x62\xf3\x8a\x14\xd0\xc6\x6d\x1d\xcf\xa3\x40\x0b\x90\x68\xfe\xcc\x45\x6d\xe8\x73\xc1\x66\x2c\xcf\x36\x8a\x35\x66\x3c\xe0\xff\x17\xd4\x0c\xf3\x95\x64\xda\x38\xa9\x34\x3d\xfb\x89\x13\x42\x0e\xd1\x24\xf3\x5c\xa2\x6b\x46\x22\x7d\x26\x56\x36\x98\x9a\xaa\xb6\x7a\x8c\x94\x77\x71\x95\x92\xaa\x3c\x12\xca\xba\x49\xae\x49\xe4\x31\xe5\xb7\xf1\xa4\x68\xb8\x97\xa2\x14\xf3\x17\xca\x1a\x03\x16\x28\x53\x60\x2a\x1b\x4d\xfc\x13\xe0\x71\xbb\x42\x51\xea\x29\x05\x5c\xeb\xbf\xc0\x48\x32\x3b\x16\x88\x4d\xd5\x2b\x26\xb2\x12\x89\x64\x26\xc5\x54\xc4\x6d\xc7\x48\xe0\x14\xc5\x6f\x53\x03\xbd\x88\xe5\xe4\xc3\xa9\x26\xa0\xc9\xd3\x86\x89\xa8\xd8\x42\x0a\x8b\xc6\x06\xeb\x6a\x27\x60\x2a\xfd\x44\x15\x43\xf3\xc8\xea\xa8\x11\xff\xd9\xf2\xad\x00\xf1\xb1\xfa\x68\x36\x97\xa3\x70\x10\xc9\xd1\x07\x5a\x69\xa1\x8a\x1d\xaf\x84\xf8\x45\x2a\x09\x06\x92\x07\xbb\x1c\x24\x52\x45\x92\x97\xb0\xeb\x36\x36\x00\xa1\x7e\x2f\x60\xcd\x4c\xd6\x2b\xa1\x3a\x0a\x4e\xc2\x74\x1e\xb0\x60\x08\x02\xdd\x13\x91\x70\x35\x92\x9e\x75\x78\x7d\x09\x5b\xa8\xe6\xb5\x0a\x0c\xb7\x33\xbc\x09\xcb\x89\x8a\x48\x4b\xda\x8e\x02\x11\xc1\x07\x8f\xaf\x0f\x3a\xb6\xfd\xb7\x13\xc0\x74\x52\xe3\x83\x28\x18\x16\x1f\xb3\x76\x78\x1b\x9f\xb3\xd4\x4a\x9e\xb0\xfa\xcf\x52\xa5\x55\x2a\xa0\x66\x30\x13\x44\x73\xe3\x10\xbd\x65\x00\x5a\xe0\xe1\x9c\xb4\x92\x17\x96\x04\xb3\xcb\x43\x03\x75\x40\x70\xa6\xd6\x75\x82\x3c\x59\xcc\x51\x6c\xfe\x17\x1a\x5c\x84\x92\xa9\xc9\x4c\x10\xc8\x6e\x5c\x88\x28\xdf\xa0\x67\x52\x72\xc4\xb9\x97\x98\xc9\xbc\xb8\x53\x2f\x78\xc5\x6d\xa7\x19\xfb\x6e\x1e\x21\xc8\x8e\xe3\x0e\xe8\x31\xe7\x13\x03\x96\xf8\x42\x49\xc6\xed\x62\x47\x6c\x99\x04\x37\x5f\x13\x03\x00\xaa\x1e\x01\xdb\x82\xb1\x35\x4f\x0f\x64\x5c\xa4\xb2\x76\x30\xc3\xd6\x01\xbd\x3d\x61\x77\x35\xf9\x69\xa4\x2b\x19\x2c\x6d\x58\x38\xcd\x45\xab\x11\x86\x6f\x79\x23\x19\x65\xd1\x86\x39\x1a\x7c\x46\x14\x15\xae\x9e\xcb\x2a\x08\x92\xde\x38\x36\x78\xed\xb2\xb8\xf4\xf3\x34\x80\x79\xc5\x0c\xdd\x00\x04\xe1\x01\x2a\x46\x03\xcc\xd6\xcc\x2e\x95\x37\xa7\x5c\x6c\xfe\x44\x11\x37\x54\x40\x4d\xe3\xd8\x91\xa6\x90\x51\xab\xc7\xac\x4a\xd8\xdf\x9f\x78\x68\xb3\xc0\x44\xe1\xea\xbe\x9b\x8d\x65\x1c\xce\x0a\xdb\x2b\x49\x77\x3f\xf4\x21\x88\x08\x4b\x07\xe9\x34\x2a\xad\xd3\x70\xa3\x4b\xb8\x73\xcf\x70\x0a\xbc\x2b\x2c\x7a\x74\xb2\xcb\xde\x05\x1a\x12\x18\x02\x08\x72\x42\xc1\x03\xf6\xa6\xa4\x35\x09\xe6\xbb\x63\xaf\x6c\x4f\xb5\x65\x48\xd0\xe5\x4e\x98\x90\x65\x42\x4d\x4f\xb7\xc0\x10\x61\x2f\xb0\x06\xe0\x5b\xa0\x08\x00\xa7\x0b\x70\x4c\x44\xd7\x22\x63\xd0\xb2\xc0\x1a\x3f\x63\x79\x28\x24\x85\x78\x1f\xb1\xc5\xf2\x81\x99\x2f\x2c\xeb\xc8\x7f\x54\x2e\xc6\x70\xd1\x03\x83\xb7\x5e\x21\xb9\x29\x49\xd4\x0f\x2a\x6c\xac\x84\x49\xdc\x83\x31\xb2\x99\x88\x9a\x5d\x0e\xa5\x1e\xb5\xf5\x5b\x9f\x2f\x29\xb0\x70\xd4\x27\xd6\xb2\x35\xc6\x73\x09\x6d\x81\x94\x3a\xea\x4c\xa5\x78\xe4\x54\xe5\x17\xb6\x84\xbd\x38\x6c\xb4\x54\x71\x8f\xa0\xc0\xef\x65\xe3\x18\x24\x23\x44\xfb\x4d\x19\xe0\x1d\xbc\x3c\xbb\x13\xf7\x66\xeb\x01\x89\xbb\x09\x85\x34\xf1\xc1\x67\xe9\xd4\x8b\x09\xd1\x91\x9b\x03\xda\xb7\xdc\x80\x40\x07\x10\x58\xcd\x80\x7a\x48\x60\x12\x17\x40\x87\x0f\x5a\xc3\xcf\x06\xc1\x8d\x93\x62\x23\x33\xa5\x4c\xc9\x82\x51\xf3\x44\x51\x9a\x52\x4a\xf5\x43\xc3\x9c\xe7\x30\x23\x8e\xc1\xc1\x81\x28\x47\x44\x27\x65\x01\xc1\x86\xcc\xf2\xe7\x52\x77\xd5\x9a\xa7\x7b\x3a\xf7\x5c\xeb\xc7\x5d\x98\x77\x56\x75\x58\x2d\xc6\x03\xdc\xc9\x9b\xbb\x18\x0e\x7f\x06\x90\xf3\xcf\x90\x76\x9c\x68\x04\x74\x9a\xae\x57\x28\xf5\x89\xd9\x06\xc1\x7b\xbc\x35\xa2\x82\x25\x5c\x8a\x3c\x8c\xcc\x22\xec\x8a\x51\xe9\x59\xb3\x18\xc0\x63\x6a\xc7\xc0\xb1\xaa\xb6\x53\x8e\x02\x22\x5a\xbb\x11\x04\x17\xa6\x46\xf0\x15\xe0\x56\xad\xe0\x8e\x26\xd4\x8a\xd0\xb0\x50\x93\xac\x53\x75\xd4\x73\x93\x64\xd2\xa8\x24\xce\x8d\x0b\xf8\x31\x07\x8b\x00\xe0\xda\x18\x0a\xd5\xd6\xe3\xd3\x5e\xd8\xc8\xf7\x9e\x75\x44\x98\xa7\xc8\xf2\x9c\x15\x49\x61\xf2\x6e\x3d\x8f\xab\xc9\x66\x6e\x54\x8f\x8e\x31\x7c\x68\xe2\xf7\x8d\xc1\xc0\x4a\xde\x23\x6d\x1b\x2b\x7b\xb4\xac\x11\xa0\x4b\xb9\xa6\x18\x5b\x33\x20\x7f\x94\x04\x43\x9a\x9e\x06\x2c\xe2\x86\x3a\x66\x57\x71\x55\x8a\x18\x9f\xc8\xb7\x0b\x38\xf1\x5c\xac\x2e\x45\x5f\xa0\x7f\xa5\xcc\x81\x80\x6a\x40\xed\x32\x37\xf1\x2a\x81\x22\xb9\xa6\x29\x24\x31\x2d\x19\xb7\x08\xae\x56\xcd\xbb\xed\xca\x38\x4f\xff\x28\x32\x5e\x22\xd6\x10\x16\x69\xfd\xef\x84\x56\xa3\xcc\x88\x9f\x49\x3b\xd8\xcd\xd3\x08\x19\x3f\x00\x01\x00\x00\xff\xff\xc1\x4f\x1a\xb6\x61\x53\x00\x00") func fontsRobotoRegularWebfontEotBytes() ([]byte, error) { return bindataRead( _fontsRobotoRegularWebfontEot, "fonts/roboto-regular-webfont.eot", ) } func fontsRobotoRegularWebfontEot() (*asset, error) { bytes, err := fontsRobotoRegularWebfontEotBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "fonts/roboto-regular-webfont.eot", size: 21345, mode: os.FileMode(509), modTime: time.Unix(1492020681, 0)} a := &asset{bytes: bytes, info: info} return a, nil } var _fontsRobotoRegularWebfontSvg = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\xbd\x69\x9b\x1c\xc7\x91\x26\xf8\x79\xf4\x2b\x7c\xa0\x5d\xed\x55\x0e\xba\x99\xf9\x39\x12\xd5\xcb\x96\x38\x1a\x49\xac\xa6\xd4\x4d\x91\xa2\x66\x67\x77\x71\x14\x98\x58\x05\x01\x06\x10\x0c\x51\xb5\xc7\x6f\xdf\xc7\x5e\xf3\xc8\x4a\x54\x54\x24\xb2\x0a\x45\x09\xea\x87\x1f\x24\x06\x2a\x3c\x3d\xfc\xb0\xe3\xb5\xc3\xcd\x7f\xf6\x4f\xdf\x7d\x3d\xb8\xf9\xe2\xd5\xeb\xe7\x2f\x5f\x7c\xf8\x80\x1e\x86\x07\xee\xf5\xf4\xe8\xc5\xd3\x47\xc3\xcb\x17\x17\x1f\x3e\x78\xf1\xf2\xc1\x3f\xfd\xfc\x47\x3f\xfb\x8f\xbf\xfc\xf4\x17\x9f\x7d\xf9\xbb\x8f\xdd\xeb\xf9\x2b\xf7\xbb\x3f\xfc\xf3\x27\xbf\xfe\x85\x7b\xe0\x3f\xf8\xe0\x0b\xf9\xc5\x07\x1f\xfc\xf2\xb3\x5f\xba\x7f\xfb\xfc\x57\x8e\x1e\xd2\x07\x1f\x7c\xfc\x2f\x0f\xdc\x83\xdd\x34\x7d\xf3\x9f\x3e\xf8\xe0\x2f\x7f\xf9\xcb\xc3\xbf\xc8\xc3\x97\xaf\xbe\xfa\xe0\x57\xaf\x1e\x7d\xb3\x7b\xfe\xe4\xf5\x07\xff\xf6\xf9\xaf\x3e\xd0\x86\xbf\xfc\xec\x97\x1f\xbc\x9e\xbf\x22\x7a\xf8\x74\x7a\xfa\xc0\xfd\xfc\x47\x3f\xd3\xae\xbf\xfb\x7a\x78\xf1\xfa\xc3\x1b\x7e\xcf\x21\x04\x6d\xff\xe0\xe7\x3f\xfa\xd9\xd7\x17\xd3\xa3\xa7\x8f\xa6\x47\x3f\xff\xd9\x07\xfb\xc7\x1f\xfd\xec\xe9\xc5\xb3\xd7\x3f\xff\xd1\xcf\x9e\xbd\x7c\x31\xb9\xe7\x4f\x3f\x7c\xf0\xea\xe5\xe3\x97\xd3\xcb\x57\x17\x5f\x7d\x3b\x3c\x7a\xf5\xc0\xed\x5e\xbe\x7a\x7e\xe9\x1f\x3d\x9d\xfd\x77\x1f\x3e\x20\xca\x11\xdf\xd4\xd6\xfe\xd9\xa3\x27\x17\xee\xdb\x17\xcf\xa7\xd7\xfe\x9b\x8b\x57\xfe\xe2\xeb\x0f\x1f\x70\x88\xf5\x81\x7b\xf4\xfa\xc9\xc5\x8b\xe9\xc3\x07\x94\xa5\x3e\x70\x4f\x2f\xfa\x3f\x7d\xa4\xf0\xc0\x7d\xa0\x23\x79\xfe\xfa\xf5\xf3\x17\x5f\xf9\xaf\x86\xbf\x7e\xb3\x7b\xf3\x13\x29\x34\x6b\x63\xef\xbe\x7d\xf1\xfc\xc9\xcb\xa7\x17\x1f\x3e\xf8\xc9\x8f\xbf\x7b\xf6\x38\xd0\x4f\x57\x23\x8a\xe1\x81\x7b\xfa\xe1\x83\x73\xae\xae\x49\x9e\x29\xe6\x1d\x95\x30\x13\x95\x31\x38\xaa\xec\x28\xe4\x87\xc9\x71\xe5\x89\x5b\x7a\x98\x1c\x85\x30\xe6\xe2\x82\x23\x61\xe7\x29\x3d\x4c\x13\x25\x71\x3e\xa6\x87\x69\xf0\x12\x9d\xa7\x1c\x46\x9f\xc4\x31\x39\x4f\x24\x4e\xf2\xe4\x89\xc5\x51\x1a\x3d\x91\xfe\xd4\x53\xae\x0f\x93\xf3\x89\x27\x9f\x48\x9f\x28\x87\x59\x5f\xee\x98\xd2\xec\x75\x14\x1e\x4f\x4d\xf2\xce\x53\x2b\xb3\x3d\x94\x70\x79\x5e\xaa\xb8\x30\x53\xa8\xbc\xa3\x56\x67\x8f\x27\x4f\xad\x5e\x1e\xce\xfc\x8d\x69\xda\xba\x9e\xf8\xf2\x70\xcd\x9e\x5e\x5f\xb0\xad\xf5\x75\x0f\xdc\xc9\x1b\x11\xda\xa9\xbd\xfe\xe4\xc7\xdf\x3d\x0a\xa7\x36\xfe\x8f\xd7\xdb\x49\xb3\xad\xa5\x42\x2e\xcc\x1c\xa2\xad\x97\x3e\x60\xb9\xf0\x22\x96\x3a\xb7\x52\x77\xba\xc6\x5e\x1f\x74\xb5\x2f\xb7\x46\xc3\x7c\x7d\x34\x39\x57\xfb\x4a\x0d\x8e\x42\x0c\x03\x39\x8e\x61\xe6\x1a\xac\x4b\x2e\x61\xf0\x14\xc8\x79\x4e\x61\xe7\x5b\xb9\x3c\x97\xda\xae\x9a\xd6\x99\x0b\x6f\x35\xbd\x71\x18\x3f\xbe\x4e\xc3\x5c\xb2\x0d\xa1\x04\x17\x29\xcc\x14\xc3\x8e\x73\x1c\x72\x75\x12\xeb\xce\x73\x52\xba\xe6\x1d\xd7\x38\x54\x76\x91\xf2\x8e\x12\x0d\xbe\xb2\xf3\xfa\x0f\x4e\xe9\xc6\xbf\x53\x6b\x4a\x8a\xbc\xf3\xcc\x79\xf0\xb9\x3a\xaf\xfd\x31\xe1\xcf\x61\xe7\x39\x96\xc1\xd7\xa0\xad\xc3\xce\x53\xe2\xa1\x62\x04\xfa\xc9\xf4\xc6\x1b\xba\x7a\x23\xf9\xf2\x3c\xd6\xe4\x52\x0a\xf8\xf2\xd5\x28\xd3\xcd\xf3\xfd\xef\x56\x3c\x9b\xa4\x6f\x2c\x45\x17\x39\x0e\xec\xd2\x8e\x5a\x18\x95\xb1\x52\x74\xa5\x28\x47\x31\x35\x65\xcd\x16\xf4\x1f\x39\x3d\x4c\x23\x71\x73\xc1\x71\x50\x86\xcb\xf4\x30\x4d\x85\x95\x9f\x4b\x78\x98\xc6\xe0\x6a\x73\x3e\x47\x47\x49\x26\xcf\x14\x1c\x51\x1c\x3d\x07\x76\x99\x9c\x97\x90\x1c\x65\x99\x3c\x05\x71\x5c\x58\x65\x43\x4e\xae\x45\x15\x0d\xb9\x4d\x9c\xf5\x33\xc4\x69\x66\xa6\x1d\x25\x25\x33\xe6\x91\x74\xcd\x38\x3a\x7b\xed\x29\xca\xc3\x34\x35\xfd\xaa\x17\x0e\x0f\x93\x12\x5b\xd6\xbe\x24\x3b\x9f\xc5\x31\x87\xc9\x53\x49\xae\x46\x15\x15\x15\xa2\xa2\x64\xcc\x40\x47\x3d\xf9\x54\x4d\x5a\x54\x8c\xd9\xb7\xe2\x7a\xd7\xa9\x4c\x4c\xf6\x92\xe2\xc8\x41\x7f\x92\x9d\x04\xc8\xa3\xa8\x9f\x6d\xce\x73\x2e\xf6\x3b\x2a\x2a\xbb\x82\x38\xcf\x45\xc7\xe4\xb9\x8a\xf3\xa4\x63\x9a\x3d\x35\x95\x27\xa9\xcc\xd4\x68\x44\x53\xd2\x69\xa8\x2c\x64\x15\x77\x9e\x42\x76\xa2\x92\xef\xe6\x0d\xfb\xef\xaf\x6f\x58\x6c\x9d\x47\x28\x44\x47\xa1\xb5\xb9\x40\xba\x72\x71\x95\x1d\x53\x9c\x98\x9a\xab\x05\xff\xf1\x35\x3f\x4c\x93\xd2\x20\x53\xd4\xe1\xa0\xad\xd7\xc6\xbe\x92\xed\x2c\xb6\x08\xbb\x5c\xf3\xe8\x49\xb0\x50\xac\xa3\x77\x35\x4f\xbe\xea\x0a\x33\xc9\xe5\x39\xa7\x80\x0f\x6a\x0f\x25\xba\x68\x6b\x85\x59\x10\x61\x5d\x55\xfc\x8e\x45\x54\x9e\x93\xb8\x44\x53\xd4\x81\x65\x1b\x61\x89\xce\x47\xdb\xd9\x8c\x89\xeb\x88\x5c\xe2\x87\x69\xf4\x25\x61\x77\x08\x62\x5c\x5f\x46\x8c\x32\xdb\x90\x2f\xcf\x25\x36\x47\xa5\xb8\xa1\x10\x69\xdf\x75\xa0\xa0\x24\x56\x06\xaf\x7f\x51\xcd\x50\x2f\xcf\x6b\x68\x8e\x4b\x9b\x4b\x3d\x5c\x10\xdd\x12\x2c\x49\x56\xb2\x95\xac\x64\x6b\x9b\xdb\x17\xa7\x2f\x03\xbe\x55\x6d\x79\xaa\xf3\x7d\xd1\xb0\x38\xc7\x97\x26\x5e\x9e\xb7\x94\xf4\xcb\x58\x99\xb4\x5f\x99\xbc\xbd\x32\x0f\x53\x5f\x9b\x87\xc9\x86\x8b\xd5\x21\xfd\x0b\x56\xc6\x25\x1e\x75\x91\xb1\x2a\xd1\xd4\x9b\x9b\xfc\xbe\x67\x1d\xea\xb6\x60\xcd\x2b\xd5\xbc\x17\x6b\x39\x3a\x69\x60\x39\x66\xa7\xdc\xba\x5f\x21\x6c\x4d\x15\x6c\x47\x75\x4a\xe1\x44\xd9\x81\x63\x26\x2f\xd5\x51\x6a\xa0\x77\xca\xcd\xb5\x02\x5e\x0d\xfa\x43\x68\xdf\xa6\xf3\xa3\xa4\x0b\xc4\xa9\x38\xdf\xc8\x78\x84\xb0\x26\xad\xda\xbe\x2a\xfb\x34\xec\x7d\x4a\xc6\xc3\x59\xf5\x3c\xf6\xb2\x86\x41\x74\xd7\x63\x68\x63\x24\x97\x93\x53\x01\x12\xe3\xa4\xca\x3e\x97\x1d\x95\x8c\xbd\x51\xa0\x20\xda\x75\x8c\x13\x10\x81\xe7\x40\x03\x55\xdd\x44\x96\xc1\xb3\xf3\x49\x85\x6c\x1b\x7c\x55\x80\xc1\x6e\x84\xf0\xcc\xe0\x54\x0c\x0d\x3c\xaa\xaa\x41\x74\xd4\xd8\xe0\xa0\xe2\x18\x88\x84\x74\x78\xac\x73\x62\x55\x6b\x9c\xa9\x2f\x18\x3e\x56\x94\xd8\x6a\x9e\x38\x64\xe7\x8b\x8c\x85\x75\x4b\x23\x3b\x56\xb1\xa0\x83\xd3\x35\x1d\xbc\x64\x72\x51\xd2\x00\x42\xe6\x36\xfa\x46\x0e\x42\x1f\x62\x41\xa7\x11\x26\xcf\xcd\x44\x0c\xab\x1a\xab\x8e\x88\xc1\x9d\x8a\x76\x8a\xfe\x5d\x97\xb7\x52\xe7\xb1\x41\xc9\xaf\xa5\x31\x15\x27\xd5\xc4\xb2\xd2\xdf\x84\xfe\x9a\x89\x30\x95\xae\xb1\x02\x57\x55\x37\x19\x05\xba\x58\x46\x5f\x09\x94\xc4\x4a\x47\xd8\xcf\xa8\xa2\x4c\xea\x96\xd4\xf9\x1f\xae\xd1\x8f\xa4\x76\xa0\x98\x53\x52\x6d\x9b\xd3\xcc\x71\x51\xcc\xba\xf2\xa6\x6d\x15\x3f\x6d\x69\xdb\xff\xf1\xba\xbe\x2f\x0b\xaa\x10\x76\xa9\xf2\xac\xd4\x22\x4d\x15\x47\x73\xb9\xc8\x24\x12\x9d\x14\x1e\xb2\xf3\x34\x48\x05\x49\x2a\x23\xea\xf2\x84\xe2\x3c\x0b\x18\x59\x22\xb4\x09\x04\x5a\xaa\x32\x7b\x92\x11\x3b\x5a\x1c\x06\x95\xaa\x4c\xac\x44\x23\x89\x07\x8f\x7e\x42\xdd\x79\xed\xaa\x24\xd7\xc4\x79\xfb\x10\x19\x6d\xe2\xdb\x5b\x4b\xf3\x3f\x5d\x9f\x43\x2d\x9d\xb3\xb4\x7b\x95\x30\xba\xfc\xc9\xb1\xe8\x16\x81\xa8\x26\x0a\x4a\xfc\xa9\xb6\x87\x69\xc6\xd0\x24\x42\x65\x24\xfc\xd5\x74\x86\x28\x97\x8b\x4a\x06\x9d\xa8\x8e\x2f\x8f\xa4\x52\xa1\x89\x13\x11\x4c\xb3\xf0\x04\x2e\x54\xc9\x27\xb3\x07\x6f\x49\x83\xc6\x5a\xfe\x0a\x66\x5d\x9a\x93\x6a\xc5\x7c\xf3\x3c\xfe\xe7\x6b\xf3\xa8\x35\xee\xc1\x3b\x85\x42\x83\x8a\xdc\x14\x07\x6e\xba\xf8\x44\xba\xbf\x3a\xee\x1d\x65\x7b\x56\xfc\x32\x70\x13\x47\x14\x86\xa8\x6b\x9a\xf2\xe0\x25\xb0\xf3\xb5\x0d\xd4\xa0\x0f\x15\x84\x09\x39\xdf\xf2\xe0\xa9\x92\xe3\x5a\x06\xd5\xc2\xfa\xae\x0d\xe0\xe6\x26\x03\xb5\xea\xb8\xc4\x9b\x07\xfa\xbf\xac\x0d\x1f\xee\x10\xad\xba\x1c\xd2\x4c\xa5\xee\x62\xe0\x39\xb2\x18\x35\xea\x83\x00\x6f\x29\x04\xc5\x53\x4c\xcd\xa0\x3f\x1e\x62\xe0\x9b\xbf\x75\x76\xed\x5b\x31\xf4\x45\xd1\xf9\x71\xaa\x43\x09\x4e\x28\xcf\x94\xfb\xa7\xa8\x28\xe1\x27\x5d\x8d\xa0\x36\x05\x6d\x50\xbe\xbf\x8e\xa7\x33\x59\xc7\x92\x5c\x92\x3a\x53\x8a\xbb\xd8\xd4\x6c\x49\x71\xe7\x63\x0b\x37\x77\xf3\xf0\x7a\x37\x71\x01\x03\xd9\x60\xf9\x82\x7e\x03\x1f\xc1\xde\x1f\x5c\xdf\xfa\x14\x96\x5e\x20\x24\x86\x1c\x54\xdc\x57\xda\x91\x6a\xd8\xac\x9c\x86\x7f\x2a\x56\xba\xb9\xcb\xb0\xc6\x95\x71\xc1\x95\xe2\x52\x4a\xb3\x44\x95\x50\x5c\xaa\x23\x95\x95\x2e\x72\x79\x98\x26\x01\x03\x53\x54\xd5\xc2\xa4\x28\x40\xc4\xa4\x62\x04\xe2\x44\x53\x8f\xb6\xb3\xb7\x2e\x94\x72\x74\x98\xb2\x7f\xa3\x14\x6f\x68\x4d\x85\xdf\xe4\x55\x8f\x50\x6c\x13\x04\x5e\x64\xc5\x0f\x14\x5c\x22\x43\x6b\xb5\xb9\xac\xfa\xa3\x82\x33\x55\x4b\x35\x28\x6a\xe8\xb4\x96\xa7\x0c\xdd\x56\xf3\x1c\xd9\xcc\x56\x05\x1a\xd0\x07\x35\x42\x3e\x34\x28\xbc\xd4\x9f\x9d\xb7\x47\xa0\xd3\x0a\x90\xa5\x9f\x74\x37\x2e\x13\x6d\xc3\xef\x9a\x55\xf9\xab\xc1\xc1\x43\x6c\xc9\xa5\xa8\x86\x41\xea\x16\x2b\x71\xde\x60\x0f\xde\xec\xb2\xa9\xf4\x13\x19\xbd\xea\x75\x5d\xf6\xa4\xb4\x3b\x49\x56\xe5\x5f\x47\x6a\x0a\x85\x84\xb8\xe3\xdc\x2b\xb0\xc2\xd0\xe6\xd0\x78\xcd\x79\x80\x04\x93\xb4\x3a\x61\xb3\x07\x12\x14\xb7\x28\xd0\x8d\x54\x06\x28\xdd\x12\x16\xfa\x6d\x31\xce\x24\x69\x88\xa5\xb8\x24\x61\x54\x40\x45\x51\x1c\xa9\x7c\x72\xcc\x65\x32\x5d\x6b\xd8\x1f\x48\x4e\x16\xf4\x31\x75\x7b\xbe\x44\xd5\xcd\x94\xc8\x30\x17\x46\x59\xb0\xd9\xa5\x03\xd7\x02\xcc\x5f\xdb\xcd\xeb\x22\xdb\x4b\x1d\x82\x93\x52\x07\x71\x79\x47\xd5\x10\x1f\x25\x03\x43\x9e\xaa\x4c\xd4\x40\x5b\xb9\x8e\xba\x66\xc1\xe9\x4a\xe5\x3a\x15\x52\x7b\x07\x16\x46\x82\x85\x41\x4d\x69\xac\x35\x97\xd5\x08\x2e\x0c\x2e\xd6\x49\xa9\xc8\x53\xca\xd1\x49\xaa\xb5\x34\xa5\x88\xe9\xb1\x01\x28\x55\xc3\x99\x1d\x35\x35\x50\xaa\xb8\x0c\x5f\x86\x41\xe0\x1a\x4d\x90\x83\xa4\x8c\x13\x4a\xeb\x13\x55\x70\x93\xb1\x9d\x59\x81\x4a\x03\x4d\x2a\x48\x10\xee\xd0\x45\xb9\x28\x28\x24\x11\x86\x82\x29\xe0\x21\x93\x4e\x0f\x93\x03\x16\x53\x84\x11\xf7\x1d\xeb\x72\x8b\x21\x12\xc3\xc7\x0a\x21\xa4\x8f\xdd\x93\xf4\xb1\x7b\x0e\x06\xbf\x80\x0b\x05\x4b\x25\x6a\x3a\x74\x5d\x03\x03\x4f\x5f\xea\xb7\x80\x6b\xec\xe3\x86\x5d\x1c\x28\xea\xe6\x7d\x8a\x9b\xfb\x94\x92\x13\xc9\xb3\xea\x9e\x1c\xd9\x51\x08\x6d\xc7\xa1\xce\xbe\xe5\xbc\xe3\x40\x9d\xd8\xf0\x24\xe6\xda\xc9\x33\x1e\x72\x8a\x8a\xdc\x92\x8b\x2d\xec\x62\x8c\x73\xae\x32\xf8\xec\x54\x71\x35\xe7\xd3\x86\x74\x4d\xdb\x24\xa3\xa8\xab\x28\x9d\xe7\x1d\x75\x23\x81\x9a\x33\xc7\x13\xf6\x6c\x22\xb3\x94\xbb\x71\x6c\x64\x13\x5d\xad\x53\x6e\x8e\x23\xc8\x46\xb1\x60\x09\x8e\x15\xfb\xa9\x7e\x6c\x61\x04\xc6\x36\x1f\x96\xc2\x87\xc9\xab\x6a\xa4\xa0\x4a\x52\xe1\x6f\x19\x6a\x74\xa5\xb5\x5d\x61\xa8\xb3\xb4\xf3\x29\xf3\xe0\x55\x1d\x01\x28\x67\x27\x6a\x05\x02\x5e\x40\x8a\x61\x6b\x54\x6a\x8e\x8a\x70\x59\x39\xde\x36\x92\x26\xd0\x87\x7e\x05\xe3\x87\x79\x48\x66\xf8\x49\x62\x95\x9a\x26\x09\x44\xdc\xe8\x15\x4f\x83\x6c\x14\x0c\xd0\x04\xfb\x99\xb7\xf4\x49\xde\x5e\x37\xc5\x75\x85\x66\xc6\x9a\xb1\xa2\xc7\x94\x5d\x4c\x71\x92\x5a\x1c\x95\x38\xc2\xf2\x83\xdc\x56\x82\x9c\x88\xc1\xdc\x51\x06\x0f\x88\x94\x68\xf4\xb1\x39\xe5\x18\x9b\xa5\x5a\x40\x0b\x55\x81\xde\x15\x76\x40\x44\x74\xdf\x1f\xa7\x09\x12\x59\xe9\x30\xcf\x9e\x65\xcc\xd1\xa5\xec\x60\x6b\xb8\x5a\xf6\x5b\x05\xf0\x4f\x0d\x3a\x07\x36\xa4\x40\x00\x2a\xae\x01\xdc\x67\xce\x7b\x35\x23\xd9\x14\x4b\x47\xec\x91\xcd\x6e\x80\x7d\x26\x49\xf1\xaa\x0e\x2a\x06\x17\xa5\x5c\xba\x73\xe1\xea\x52\xb2\x5e\x02\xb9\x0a\x66\x09\x13\xab\xb5\x42\xa1\x8d\xc4\x26\x1f\x0c\xaa\x2b\x8a\x37\xa5\xa3\xac\x06\x42\x89\xce\xc3\x9f\xc2\x52\x60\xaa\xa8\xc2\x91\x11\x08\x7b\x71\x38\x44\xdd\x95\x00\x28\xab\xa4\x41\x1b\x8a\xb9\x6c\xee\x4d\x29\x8e\x24\xd0\x4c\x29\xed\x5a\x4d\xca\x4d\x3a\xa9\x1c\x75\xb0\xfa\x7f\xc9\x2c\x57\x33\x18\xc8\xf8\x3c\xe9\x02\x2a\x71\xc2\x4b\x02\xdd\x34\xa8\x95\x98\xca\x18\xd9\x49\x8c\x8e\xb2\xb8\x4c\xaa\xd9\xc9\x25\x6e\x3b\x5f\xda\x06\xd8\xaa\x47\x24\x34\xab\x19\x00\x59\x29\x6a\x1a\x33\x95\x89\x83\x4a\xde\x3a\xc2\x5c\x04\x71\x14\xb5\x97\x4d\x52\xaa\x34\xed\xe6\x69\x63\x47\x64\xf6\x9b\x8e\x5c\x08\xaa\x25\x44\xec\x36\x64\x23\x99\xc8\x0a\x60\x5b\x23\x38\xb4\x35\xb6\x8e\x70\x5d\x79\xf4\x37\x29\xc0\x83\xbf\x04\x5c\x9d\x9d\x1a\x4e\xb6\x1f\x6a\x3e\x4d\x25\x75\x55\x64\x5b\xcd\x60\x34\x10\x4c\xe8\x48\xc4\x9a\xaa\xf4\xbd\x22\x98\x08\x6d\x10\xfa\xba\x2a\xc3\xa2\xf9\xa5\x3b\xe7\xd6\x9c\xb4\xee\x84\x88\x0e\xc2\xa0\x45\x58\x79\x6c\x9a\x78\xd4\x15\x09\x4e\x17\xa3\xd0\xa4\x7b\xd8\xd7\x49\x65\x4b\x73\xd4\x40\x30\xc1\x95\x32\x7a\x6b\x6a\x33\x51\xe5\xa9\xd2\x05\xc3\x81\xe3\x54\x41\x52\x28\xdd\xb2\x25\xe8\x29\x5d\xd3\x3a\x91\x29\xd8\x5c\x46\x0a\x3a\x60\x2a\xc1\xe5\x32\xe5\xec\x4c\xf4\x81\xea\x40\xb0\x54\x54\x01\x42\x71\x16\xd2\x8d\x31\x1d\x56\x82\x21\xa6\xc9\x67\x88\xc7\x4d\xd9\xdf\x36\x29\xa0\x8a\x6b\x26\x33\xa8\x39\x5b\x53\x49\x6d\x12\x28\x3d\x8a\x61\x64\xae\xba\x95\xe9\x8a\x21\xa7\xbe\xf4\x51\xdb\x28\x58\xb4\x4d\xa9\xcb\x7b\x95\x2a\x65\x32\xab\x48\xa9\x97\x47\x5f\x2c\x7e\x00\x42\x27\x03\x77\x68\xa9\x1b\x34\x88\x0a\x2b\x1a\x93\x9a\x8d\x4a\x68\xbd\x0b\xfd\x50\xb4\x65\x54\x29\xa0\xbc\x0a\x91\x8e\x2d\x6d\x53\xd5\x57\xc2\x71\xce\x19\x92\xcb\xc3\x63\x60\x3f\x5e\x54\x62\xee\x32\xc5\x68\x02\x2c\x2d\x6a\x35\xa2\x93\x09\x3b\x8f\x89\x5d\x9e\xab\xc4\x6c\x5d\xdf\xa4\xd0\x21\x0a\x47\x85\x28\x98\x45\x93\x51\xb9\x41\x65\x09\xc1\xd4\x9f\x40\xd5\x4a\x0e\x0a\x19\xc1\x0e\xe4\xbc\xc1\xae\xda\x26\x73\x03\xba\x06\x2e\xaa\x1d\x70\x74\x00\x0c\xd5\xc3\xb1\x6c\x6d\xd6\x7f\xba\x6e\x7b\x50\x39\x6e\x7b\xe0\x45\x2d\xf9\x54\xb3\x64\x15\x9b\xe0\xd4\x81\x6c\x3b\xd9\xf8\x3a\xa7\xcc\xb7\xf9\xe6\x4f\x7e\xfc\x9d\x3c\x59\x79\xcb\xc2\x12\xc8\x2a\xe4\x62\xce\x33\xc5\x36\x54\xca\x8a\x1a\x67\xb8\x9b\x7c\x52\xb2\x60\x11\x38\x99\x3c\xd5\xd9\xe7\x01\x4f\x6d\xb0\x57\x6c\x2d\x6f\xfe\xea\x87\x47\x80\x06\xbb\x18\xca\x4c\x39\xee\xaa\xa8\x09\xa0\xd8\xb2\x4a\xbc\xc4\xab\xca\x72\xc3\xab\xcd\x99\x5d\xac\x67\x56\x78\xd1\xcc\xd9\xd5\x32\x53\xcb\x43\x52\xeb\x5b\xaa\x8e\x9f\xca\x9c\x31\x25\x0e\x83\xb7\xbf\xc7\x99\x5a\x1a\x6a\x52\xc5\xa8\xd3\xa7\xb8\x01\xb8\xff\xe9\xda\xb7\x5a\xe9\x16\x60\x26\x47\xc4\x3c\x7a\x71\x84\x67\x50\x63\xaa\x13\x84\xae\x6b\x65\xa4\xa6\x8c\x28\x01\xd8\x27\xc0\x61\x02\x0b\x2d\x74\x99\xcc\x07\x66\x48\x56\xcc\x9c\x7b\x50\x62\xf4\x29\x3a\xfc\xcf\xc4\x97\x4a\x3f\xea\xd2\x19\x81\xa9\x32\x92\xa3\xa8\x9f\x53\xb1\x3d\xa9\x08\xa7\x58\xc7\xd6\x1c\x51\x71\x14\xc9\x51\x0d\x93\xa2\xcb\x64\xb6\x48\x36\x0f\x59\x0f\x50\x20\x50\x90\x0a\xdc\x77\xe0\x41\x15\x01\xd0\x0b\x50\x11\x6a\xc5\x28\x32\xaf\x97\xe7\x92\x04\x4c\x50\x77\x1c\x14\x76\x84\xea\x14\x9a\x6e\x38\x5f\xfe\xd7\xeb\xfb\x52\xe5\x30\x0c\x53\xd4\x3a\x73\x91\xc5\x71\x54\x94\x59\xa7\x1c\xd8\x71\x4e\xa3\x14\xe5\xf6\xd4\x7d\xf7\x29\x4c\x1d\xa8\xe7\xd2\x46\x0f\x87\x6b\x84\x8f\xf1\x0a\xb2\x58\x60\x15\xc6\x54\x31\x75\xc0\xd9\x45\xea\x0c\x0f\x00\x38\x7a\xe5\xa1\x8a\x77\x0c\x64\xdb\xcd\x30\xe7\xd5\x18\x1f\xbd\xe1\x59\x55\x45\x0e\xfe\xcb\xc9\x27\x32\x64\x39\xea\x18\x93\x8a\x68\xd5\x07\x11\x11\x5c\x2e\x10\xd2\x09\xf6\x04\x54\x02\xc1\xe0\xce\x13\x89\x39\x7a\x7d\x74\x3e\xee\xf2\xa0\xdd\xf8\x54\x93\xc3\xd8\x89\x54\xdc\x9b\x70\x26\xb8\x3e\x4d\x9c\xef\x95\x9e\x92\x09\xa8\x67\xaa\xec\x58\xd1\xd3\xa8\x4c\x59\x75\xcc\x31\xba\x64\x86\x78\x6c\xd9\x7c\xda\x23\xe0\x6b\xd0\x1d\x33\x35\x2d\xa4\xba\x11\xa2\x38\x07\x56\x90\xab\x34\xad\xe8\x45\x6d\x22\xe8\xd9\x68\x6e\x7f\xed\xba\x56\xe8\x3e\x20\x09\x42\x60\x7a\x41\xd9\xe6\x89\x0c\x65\xf4\xb9\x38\xc3\xa9\x65\x1f\x19\xdb\x7f\x82\x6d\x08\x35\xe8\x10\x80\x9b\x74\x37\xb1\xb2\x55\x17\x28\x43\x2f\xba\xf3\xc2\xc1\x45\xb8\x35\x09\x9a\xaa\xaf\x01\x53\x9e\x2c\x5c\xee\x4b\x54\x0c\x1b\x40\xb2\xf0\x33\xb7\x02\x20\x3b\x7a\xd5\x4b\xce\x03\xf2\x63\xe5\x81\x7a\x1e\xaa\xe1\xed\x92\x42\x25\x25\x77\xee\xf6\x1e\xb5\xc9\x43\x5d\x96\x83\x0d\x25\xe0\x47\x1d\x54\x55\x06\x97\x4d\x55\xfd\xd1\x75\x8a\x15\xee\x11\x05\x0e\x2e\x0c\x49\xcd\xe1\x98\xf2\x8e\xb2\x4a\x40\x63\x8e\xbc\x33\x61\xa9\xb2\x46\xd4\x76\xc9\x04\x7f\x20\x96\x3d\xe1\xe5\xe5\x79\xe4\xe0\x52\x0c\xbb\xd8\xc2\xe0\x39\x06\x97\xb3\x6c\x3a\x2d\xff\x79\x35\x8a\xb0\x78\x90\x75\x9d\x67\x7c\x34\x96\xb4\x87\x07\xc5\xf9\x56\x01\xf3\x94\x02\x95\x0e\x7a\xa4\x4f\x21\xa3\xa7\xd2\x1d\x0e\x02\xef\x3e\xec\x5f\xdd\xff\xea\x38\x14\x53\xf1\x6d\xc1\x78\x62\xbe\xa7\x60\xf2\xc8\x30\x1e\xb6\x5b\xba\xe1\x11\x20\x0c\x92\xa8\x30\x50\x5c\x96\xe2\x4e\x22\x8d\x24\x00\x08\xa1\xb9\xac\x5a\xb6\x24\xc3\xfd\xc0\x6c\x8a\xa3\xb0\x67\x30\xb1\x10\xcb\x2c\xb2\xf3\x52\xc2\xec\x13\x37\xeb\xa8\x4a\xd9\x09\xb5\x51\xd9\x43\x09\xb2\x21\x4a\xa9\x66\xa5\x39\x4a\xb4\x27\xa5\xe4\x82\x4d\xb6\x70\x8d\xa9\xf9\x54\x75\x44\xac\x52\x3b\x6e\xb9\x8f\x7e\xb1\x8a\x14\xb5\x45\xad\x53\x75\xa9\xd5\x99\x53\x53\x1c\xa6\xdf\x43\xd4\x26\x46\x30\x4a\xb0\x78\x2f\x5c\x0e\xb1\x38\x72\xd2\x04\xf0\x77\x24\x70\x04\x5c\x3e\xac\x34\xa5\x9a\x9a\x11\x98\xc9\x70\x63\xe8\x80\x93\xc0\x13\xc1\x91\x27\xcf\x29\xba\xda\x46\x4f\x19\x44\xc9\xd8\x0d\x91\x09\x61\x23\x91\x30\x7b\xce\xb4\x38\x1f\xec\x6f\x3c\x2d\xad\x46\x02\x6b\xa0\x0f\xdd\x68\x74\x1a\x1f\xa6\x1d\xd5\x36\xe8\x27\xd5\x36\xb2\x1f\x57\x13\x13\xfa\xf3\xd1\x13\x3c\xd6\x20\x45\x30\x81\x54\x37\x2a\xfa\x81\xbc\x58\xe6\xb6\x04\xaa\x62\xdc\x58\xbd\x5f\xae\xe8\x31\xde\x40\x8f\xb1\x8c\x5c\xd5\x48\x8d\x0a\x0d\xb0\x66\x13\xec\x8a\x98\xc4\x62\xc4\xed\xca\xaf\xb9\xff\xfb\xe4\x7b\x73\x9d\x8d\x8f\xb1\x5c\xd1\x15\xa7\xb0\xf8\x79\x60\xe9\xe8\x6a\x99\xef\x4e\x22\xcd\xe6\xa4\x42\x84\xaa\xff\x51\xda\xe4\xf7\x2d\x77\xaa\x37\x74\x55\xe2\x06\x26\xfa\x78\x85\x4e\xf6\x24\x71\x35\xa9\x96\xcc\x62\xdc\xf9\x92\x94\xbe\x0a\xed\x72\x2e\xfd\x4f\x78\x4a\x4c\xbb\x92\xdb\xe2\x12\xcc\x1b\x2c\xfd\x9f\xd7\x5f\x93\xf5\xd7\xb2\x2c\x5f\xcb\x79\xf6\x29\xf0\x2e\xe7\xb8\xff\x5a\x9c\x7d\x8e\xf1\x08\xcc\xfb\xd5\x6a\x9f\x5a\x97\x5e\xaa\x2b\x53\xa9\xb3\x84\x00\x2a\x4f\x88\x3d\x45\xe1\x29\x92\x2a\xae\x32\x72\x52\xbe\x33\xea\x66\x51\xf0\xaf\x06\x41\xb9\x22\xe8\xaa\xda\x0b\x21\x75\xe0\x19\x0e\x8a\xb3\xa1\x2c\xaa\x12\x1a\xf2\x9b\xbc\xf2\x8f\x39\x27\xd4\xb8\xd5\x0e\x66\x2f\xc1\xac\x2f\x55\xab\xb0\xb8\xa1\x78\xb9\x85\x1e\xf2\x1b\xd5\x12\xd0\x9d\x14\x87\x0d\x16\x57\xd2\x2c\x42\x3b\x6d\x09\xbb\x3d\x91\xae\x86\xc4\xd1\x27\xee\x1a\xbc\xf6\xec\x88\x02\xdd\xdf\x0d\x39\xe5\x20\x50\x36\x4c\x24\x1d\xd2\x62\xb7\x45\xd9\xb0\xce\xff\xcb\x2a\xf1\x60\x09\x59\x1c\xec\x0b\x10\x76\x4e\x75\x57\x42\x99\xf5\xbf\x86\xcb\xf7\x6e\xeb\x1c\x65\xe7\xf5\x9d\xc7\xd3\xe6\xfe\xfc\xfa\x3a\xf4\xdf\x07\x06\xdb\xc1\xb7\xea\x55\xd7\x1b\xde\x8e\xdf\xac\x88\x49\x3a\x92\xcf\xd9\x49\x4b\xe6\xc0\x83\x08\xf2\x24\xa9\x3b\xf0\x60\xd0\xef\xbd\xbe\x06\x5b\x9a\x29\x7f\x07\x0d\xa1\xb2\x4f\xf7\x76\xa6\x90\x16\xdb\x23\x24\xb1\xcd\x4b\x57\x5e\x22\xd3\xa4\xd2\x43\xbc\x14\xcd\xc0\x0b\x66\xe0\x45\x07\xc8\x40\x6a\xd0\x06\x83\x59\x8e\x9b\xe2\xf9\x9b\xe7\xf2\xdb\x15\xcd\xd2\x9a\x0d\x6d\x03\x62\xdc\x51\xe2\x21\x31\x39\x7d\x66\xaa\x83\x38\x9f\x06\x9f\xd4\x00\xcf\xad\x0d\x19\xf1\xea\x58\x06\x2f\x16\x1f\x17\x7d\xcb\xc5\x65\x78\x71\x54\xe1\xe4\xee\xcf\xb9\x79\x34\x9f\xac\x56\x36\xe4\x9b\x47\x43\xa2\xdc\x59\x17\xc6\xaf\x75\x63\x7e\xe7\xd7\x7b\x2c\x6d\x2d\x3b\x39\xf1\x10\x81\xb5\xa9\xca\x2e\xe3\x19\x8f\x9c\xf8\x90\xd0\x52\xc9\x83\x72\x72\xe3\xc1\x27\x47\x83\x8f\x48\xca\xa1\xdc\x76\xaa\x93\xf4\xdf\xaa\x26\xb3\x62\x4e\xe7\x69\x80\x1b\x58\xc7\x98\x4a\x3e\x32\xeb\x7f\x39\x91\x09\x86\x12\x90\x85\xc2\x71\xc8\x8e\x67\x35\x77\xae\xb1\xc2\xe0\xb5\x09\x11\x92\xbf\x9c\xd7\xc1\x13\x1f\x13\x59\x9f\x6e\x8b\x2c\x92\x37\x14\x73\xb6\xd4\x0c\x17\xa3\x4c\x91\x0c\x05\x94\x91\xa1\x17\x63\xf7\x58\x02\x16\x90\x19\x49\x31\x42\xeb\xd8\xcf\x3d\x2b\x86\xbd\x7a\x33\xf9\xab\x9f\x8c\x9e\x13\x54\xf2\xd2\x6b\x9e\xfc\xfe\x53\x3d\xa8\x66\xce\x2a\x55\x46\xe6\x9f\x55\x85\x3d\x71\xb1\x00\x03\xd7\x91\x2a\xdc\x55\xcd\x12\x7f\xe0\x7d\x05\xb4\x12\x09\x0f\xd3\x6c\x8a\xdd\x40\x55\xa8\x4e\xb8\x4e\x5e\xe5\x9f\xfe\x12\x6e\x4e\xa8\xc5\xa5\x33\x37\xf9\xe5\x23\x30\xaf\xf3\x86\x79\xfd\xbb\x35\xe7\xf0\x6a\xd7\x52\x2a\x23\x8b\x0e\x4e\x00\x05\x39\x18\x48\x14\x3a\x08\x74\xd8\x1f\x2c\xc4\x88\x56\x04\x48\x25\x59\x01\x5a\xed\xdb\x07\xb5\x5c\xa4\xee\x24\x87\x51\x71\x45\x70\xcc\xe4\x10\x5d\x29\xa2\xb3\x83\xb1\x05\xab\x37\x28\xde\xb1\x04\x22\x5a\xfa\xc9\x72\xf3\x34\x7e\xff\x37\xa2\x00\xc0\xb4\x64\xc8\xcb\xbc\xd8\x9e\x43\x1a\x14\x0c\x99\x8b\x03\xf1\x2e\xe2\x36\x78\x2e\xd9\xb1\xda\xc3\x49\x69\x58\x16\x80\xe1\xc5\x9c\x67\x16\xad\x25\xcb\xaa\xb9\x7f\xd2\x71\xef\x40\x3b\x27\x92\xce\xbf\xae\xd6\x3c\x5d\x17\xba\x69\x97\x58\x49\xa7\x81\x74\xcc\xbb\x0b\xc7\x82\x9a\x9b\xe6\x4d\xd5\xf5\xb4\x88\x46\x4b\x8b\xa2\xf5\x24\x3c\x9a\x65\xde\x1c\x15\xbe\x4a\x11\x4b\x3d\x03\x0d\xd9\x6e\x24\x70\x5b\xe6\xea\x08\x0d\x78\x82\x66\xd7\x31\x23\xd6\x25\xa3\xfe\x5e\x22\x76\x8c\x42\x98\xd4\x6c\x24\xc9\xb3\x62\xe1\x6e\x09\x40\x5d\x21\xb6\x98\x5c\x61\x25\xb3\x3c\xfb\xac\xb8\xe1\x8a\x5c\x6b\xde\x09\x85\xd1\xd0\x09\x23\xaf\x2c\x0b\x08\x16\xa6\xa2\x74\xc3\x42\xf7\x18\x0e\x53\xe4\x7e\x4e\x3d\x10\x9b\x11\x7a\x05\x34\x4f\xb4\x61\x30\xfe\xdb\x3a\x05\xad\x5c\x79\xf7\x23\x49\xd7\xc5\xb6\x64\x70\x46\x8b\xa5\x23\x2a\xe5\xf8\x22\x23\x45\xa4\x98\x4a\x76\x59\x26\x84\x8b\x10\x45\x0b\x96\x64\x47\x16\x23\x05\xf1\x9b\xb5\xcf\x42\x2e\xc1\xb1\x0a\x8a\xc9\x3c\x75\x4b\x8d\x33\x6c\x0e\xd5\x00\x62\x41\xd3\x38\x09\x5c\x3b\x48\xef\xb4\x9d\x44\xa2\x95\x5a\x2f\x48\x2e\xe2\x62\x79\xa4\xdc\xf8\x4d\xeb\xa5\x2e\x86\x1b\x02\xb5\x1c\xca\xe4\x19\x3e\xe3\xa2\x16\x8c\xd9\x0f\xcc\x69\x41\x12\x93\x2f\x3d\xb4\x25\x4b\xfc\x35\x21\x1e\x44\x4a\x20\x13\x17\x4b\xae\x81\x23\x25\x38\x9f\x8a\x93\x64\xe1\x40\x8b\xdb\x72\xe9\x29\xa6\xb9\x1b\x2f\x5c\x65\x82\xd3\xc2\x1c\x10\x6c\x79\xad\x52\x75\x15\x94\xee\xd5\x0e\x07\xe5\x64\x76\x12\xd2\x4c\x1b\x84\xfe\xd9\x6a\x7b\x42\x47\x4a\x0a\x54\x96\xb8\x10\x91\x70\x47\xd9\x31\x57\xe8\x76\xea\x09\x09\x78\x8a\x79\x43\x7b\xfd\x61\xc5\x47\x75\x91\x5d\xb1\xb8\x98\xdb\xdc\x6a\xe9\x79\xe2\xd5\x72\x52\x91\x02\x0c\xa7\x96\x2e\x8c\x9a\x67\x15\x18\x38\x2b\x27\x33\xb6\x0b\x29\x1b\x88\x66\xa0\xd5\xaa\x0f\x86\x63\xc6\x02\xd6\x92\xe3\xe4\x63\x90\xce\x67\x23\x7c\x0b\x58\xaa\x76\x90\x83\x1a\xf5\x1f\x92\x37\xb3\xbd\x3e\x5f\x9b\xc7\xdd\x29\xcd\x6c\x0e\x0f\xa6\x38\xf4\xfd\x68\x71\x10\xc8\xc4\xb4\xcb\xfa\x44\x94\xf0\x4a\xdf\xec\x98\x64\xf0\x29\xd2\xe2\x19\xa1\xbc\xe1\x47\xfd\x62\xe5\x1b\x5c\x7c\x1c\x29\x76\x1f\x4b\xcb\x03\x33\x2b\x2d\xf1\x80\x54\xc1\xba\xa4\xc8\x35\x47\x55\x06\xd5\xe9\x2d\xf1\x8e\x4a\x1c\x60\x78\x68\x43\xa4\xd4\xd6\xb2\xcb\x03\x6b\xab\x32\x30\xf5\x56\x8a\x4e\x24\x5d\x8d\xac\xe4\xc1\x73\x45\xee\x5c\x18\xe0\x43\x52\xd9\xa1\x7f\xb4\x48\xf2\xa0\x6c\xa1\x13\x46\x3e\x7a\xd9\xc0\x77\x7f\xdc\x5c\xba\x9c\x5d\x18\x14\xa0\x15\x89\x83\x8f\x99\x5d\x61\xde\xb1\xe8\xa2\x55\xe7\x53\xae\x48\x05\x4d\xb9\xee\x58\xaa\xb5\xf0\x85\x19\xbf\xf1\x45\x62\xc7\xaf\x12\x9b\xda\x6e\x3a\x78\xf0\x4e\xd5\xbf\x6f\x58\x06\x5f\xae\x46\xb3\x24\x3d\x71\xe8\x1b\xc9\x69\x90\x8a\xdc\xe6\x80\x87\x12\x03\xfe\xe8\x13\x91\x43\x4e\x8b\x4f\xc4\x96\x66\x90\x78\x83\x60\xfe\xb4\xfa\xce\x3e\x8a\x51\xa0\x3f\xf2\x50\x4a\x55\xd2\x80\x31\x5b\x2c\xfc\x0a\x29\x13\x69\xf0\x05\x62\x88\x32\xed\x2a\xc5\x8e\xa0\x29\xc8\xc6\x12\xff\xd7\xeb\x66\x53\x5a\x70\x4e\x14\x05\x2e\x3c\x53\x2b\x79\x27\x75\xb1\xd5\x49\x15\x09\xe5\x0c\xc1\xdb\xff\x26\x75\x63\x2a\xff\xdb\xf5\x34\xb1\xd8\x59\x58\xa9\x0c\x74\x58\x33\x52\xc5\x96\xe4\xb0\x2d\xa4\xff\xdf\x36\x87\x49\x16\x46\xa6\xda\x66\x8c\xca\xe3\x29\xa5\x9d\xd4\x3c\x7b\x0c\x5e\x65\x9b\xfe\xe9\xe6\xae\xff\xf7\x55\x2a\x5b\xde\x07\x1d\x0a\xb7\x81\x5b\x73\x85\xcb\x8e\x24\x0e\xdc\xaa\x92\x91\x5a\x39\x95\x06\x5d\x06\x17\xa9\x21\x98\x5d\x02\xe8\x9b\xd4\x48\x0a\x83\x39\x04\x23\xa9\xed\x50\x37\xc0\xd9\xff\x71\x3d\xda\x21\xdd\x30\x88\x2e\xec\x1a\xcb\xe2\xf6\x60\x99\x29\x6d\x78\x8f\xfe\xcf\xeb\xa9\xa4\xb1\xf7\x51\x55\xb6\x14\x42\x86\x12\x4b\x18\xa8\x28\x40\xc0\xfa\xa4\x0d\xfa\x7e\xb4\xb2\xcf\x16\xff\x2c\x0e\x18\x04\x04\x89\x53\x72\x3d\x1f\x07\x01\x53\x81\xda\xaf\xaa\xcc\x99\xe2\xac\x0a\x25\xb8\x86\x28\xbf\xa3\x64\x89\x16\x39\xba\x84\x34\x8b\x66\x1e\x63\x13\xae\x96\x67\xd7\x83\xaf\x0a\x5c\x40\x5a\xc8\x4f\x9a\xe1\x6e\x23\xe4\xe9\xb3\xe3\x90\x46\xc5\x24\xad\x3a\x09\xe2\x9a\xa2\x3a\xf8\x34\x5a\x76\xbe\x21\x98\xaa\x68\x89\x33\x62\xb6\x89\xe1\xaa\x4b\xd5\x41\x2d\xf2\x64\x59\x4c\xb9\x03\x1f\x0a\x2e\x36\x3b\x26\x86\x6c\xfe\xc9\x2b\xf8\x84\x0b\xd2\x03\x33\xd4\x7e\x2c\x64\x49\x51\x9a\x7c\x3f\xb2\x62\xa7\x0c\x28\x37\xcb\x14\x29\xfb\x0e\x90\x82\x81\xdc\xb6\xcb\x73\x1d\xa0\xb9\x81\x7c\x61\x17\xcd\x84\x9f\x48\x45\x7a\xe4\x91\x02\xce\xa9\x35\x71\xc9\x06\x4d\x9c\x67\x52\x02\x65\x26\x33\xeb\x61\x36\x58\x20\x20\x2c\x69\x6a\x14\x37\x14\xf0\xe3\x2b\x4e\x0d\x33\xa5\xdc\x33\xa9\x73\xc8\x63\x52\xda\x35\x15\xe5\x88\xc2\x64\xa7\x56\xa4\x8e\x0a\x76\x91\xb2\x87\x33\x6e\xb6\x74\x91\x69\xf6\xb6\x6e\x8c\x03\x73\x96\xd0\x27\x96\x2b\x07\x97\x44\x5f\x95\xd1\xdb\x1c\x94\x51\x7b\x04\x88\x96\xc8\xf6\xe0\x19\x3e\x7b\x51\xc5\x44\x96\x1d\x20\xa1\x8d\x2a\x8f\x6b\x70\x96\x41\x40\x9c\xa6\x9e\xb9\x1f\xd3\x48\x62\x27\x80\x8a\x6b\x6d\xca\xd5\x71\xe6\x19\xe3\xd0\xee\x2d\x63\x52\x82\xe5\x36\x07\xb8\x1e\x91\x6b\x74\x15\x4a\xb3\xfc\x4d\x18\x0e\xbd\x7b\x0b\xdc\xc7\x2d\xc5\xf8\x64\x15\xcc\x5c\x52\xaf\x5b\x71\x89\xc3\x8c\xbc\x1d\xc6\x94\x12\x16\x4c\xe1\x42\x47\x83\xc9\xf2\x3f\x68\x9f\xed\x43\x3c\x12\x15\xb3\x1d\x90\xf6\xc3\x59\xa5\x64\xd8\x43\x3d\x84\xdd\x1b\x22\x8f\xe6\x69\x9f\x70\x7e\x20\x5b\x44\xcc\xac\x1b\xee\xf1\x2a\xc2\x6a\x66\x0b\x4b\x16\xb1\x24\x50\x43\x35\xd9\x65\x64\x3b\x2b\xb9\xb1\x85\xd7\xc2\xc3\x34\x36\x8b\x2e\x01\x4d\x2b\xa7\x99\xf7\x5e\xf9\x6a\x47\x48\x34\x83\xe7\x3a\x8c\x1e\xb0\x34\xf6\xe4\x7d\x86\x9b\x9a\xa4\xdb\x3c\x5e\x82\x05\x70\x14\xfc\x22\x0b\x4a\x32\xe9\x5c\x2d\xf5\x55\xea\x06\x3a\x7b\xda\x97\xad\xba\x14\x82\x6d\x1a\x23\x32\x8b\x24\x02\xa6\xc9\xb2\x42\x29\x87\xb1\x59\xfc\xce\xd2\xec\xd3\x64\x2b\xab\xb6\xd4\x9c\x5a\xea\x3e\x0e\x25\x5e\x8f\xb4\x70\x16\x47\xc8\x38\x55\xb3\x21\xbb\x3e\x52\x1c\xa9\x28\x6a\x4a\x2b\x46\x6e\x86\x58\x49\xd5\xae\x85\x5f\x88\x1d\xc8\xf5\xf2\x9c\x5b\xd2\x21\xd9\xca\x45\x97\xd5\x02\xcd\x76\xca\xa1\x5a\x24\xa7\x87\xe5\x62\x75\x31\x4c\x0d\x87\x26\xe6\x14\x10\x68\x43\xf3\x56\x0f\x72\x6b\x90\x65\x0a\xc8\x3f\xc2\xca\x85\xb9\xd9\x69\xad\x4c\x96\xc3\xe2\x25\x44\x65\xa0\x9b\x57\xea\x62\x4d\x73\xb2\x4f\x4a\x00\xcd\xc5\x85\xe6\x2c\xdf\x1f\xb9\x80\x3d\x1f\x53\x49\x7c\x64\x08\x06\x11\xec\x23\x1b\xcf\x0a\x9c\x57\x0c\xdf\x28\x9b\x4b\x6e\x14\x24\xa2\xb8\xd2\x7a\x76\xed\x92\x2d\x86\x9c\x9f\x60\xa1\x1f\x88\xee\xba\x4f\xf3\x53\xd3\x62\x28\xc5\xac\x65\x95\x9a\x6a\x3f\x78\x8b\xad\xe0\x48\x01\xe0\xee\x88\x4c\x36\x24\xaa\x59\x5c\x36\x5c\xe5\x73\x89\x8a\x2b\x95\x7c\xc5\xe5\x14\x2d\x8d\x37\xb6\x36\x5b\xea\x88\x72\x05\x32\xab\x94\x9e\x6a\x74\x45\x89\xcf\x72\x3c\x11\xd1\xb5\x74\x5d\xe5\x76\xac\xea\xcd\x2b\xf8\xec\xda\x0a\x96\xd0\x99\x36\xe5\xab\x43\xc2\xb9\xcd\x66\xf8\x52\x11\x07\x11\x8a\xd3\x75\x93\xb9\xd1\x9b\xf2\x2e\xc2\x68\xfd\xa4\xaf\xf2\x8b\xa5\xe0\xa4\xbd\xe8\x4a\x01\x01\xdd\x68\x39\x3a\xae\x4c\x1e\x12\x46\x46\x5f\x2d\xc3\x52\x8d\x36\xc4\x95\x2d\x62\x1b\x5b\x37\xb7\x15\xe3\x2d\xa7\x84\x79\x7d\x4a\x78\x4b\x1a\x7d\x75\x95\x4c\x7c\x8d\x89\x62\x67\x21\x63\x20\x35\x6b\x91\x9f\x63\xa1\xec\xa9\xb3\x44\x7b\x98\x06\x56\x3c\x4f\x3b\x4a\xf0\x27\xd7\xee\x0e\xc1\x21\x21\x5a\xa2\x01\x00\xb9\xdd\x44\x54\x05\xb7\x3f\xef\xcc\xcb\x61\x95\x1e\xe8\x1b\x12\xc2\x6a\xa3\xee\xbe\x74\x1b\x15\x6a\xda\x22\x5d\xf5\x2a\x57\x09\x1c\x80\x50\x35\xbc\x41\x48\x0f\x9b\x91\xa0\xa1\xbf\xb5\x43\x4a\xa5\xe7\x5b\x4e\x96\xcd\x25\x96\x8c\xdd\xf3\x7b\x49\x90\xa2\x68\x07\xd5\xa4\x14\xe5\xdb\x72\xc5\xb7\x62\xf9\xf5\x99\x27\x26\x35\x78\xdb\x58\xe1\x4d\x8f\xcd\xb2\x37\x91\x7c\x11\x1f\xa6\x39\xb6\x6a\x7c\xab\x16\x4a\x73\x3d\x10\x0d\x03\x31\xe0\x7b\xd1\x92\xbf\x4d\x5e\xd7\xc9\x63\x28\x41\xb6\xd9\x75\xb7\xa1\x54\x59\x46\xe5\xad\xda\xb9\x94\x2c\xa0\x5f\x2d\x00\xa2\x2b\x83\xd4\x08\xee\x09\xd7\x21\x4e\xcd\xdc\x5a\x1c\x66\x9f\xfb\x39\xe6\x39\xd7\x80\xe4\xef\xa8\x7c\x86\x85\xab\xba\x3c\x38\x01\x1b\x47\x5f\x21\x5f\x7a\x2a\x6b\xcf\x96\x0f\x6d\x9f\x69\x38\xfb\xd2\xda\x11\x7f\xef\xf3\x55\x7a\xd5\x82\xdf\x52\xbb\x3a\xa2\x5e\xae\x8e\xa8\x97\x4b\xbc\x22\x49\x6d\xe6\x40\x4b\xb6\x13\x1d\xf9\xc6\xff\xb5\x3a\xd5\xdd\x6d\x20\xaf\x3a\x4a\xc1\x30\x21\x97\x75\x24\x9d\xa3\x53\x8b\x51\xe7\x01\x63\xe2\x61\x1a\x11\x9f\x25\x98\xd4\x31\x4e\xfd\xe4\x86\xcc\x44\xa5\x7f\x9d\xcc\x45\x83\x98\x97\xc9\x85\x64\x4e\x1a\xd1\x1d\xc6\x9e\x22\x33\xde\x52\x6c\xa0\xfa\x2d\x35\x41\xed\xef\x73\xfd\x15\x49\x16\x35\x5a\x7a\x7f\xed\x58\x48\xe2\xcf\x2b\xd9\xbc\x3f\xc7\xa2\x84\x7e\xb0\xff\x2d\xc4\x1d\x71\xc6\x59\xa6\xc8\x19\xa6\xa6\x97\x82\xd4\x10\x1e\x22\xab\x00\x6e\x38\x4f\xcd\x66\x09\x47\x6c\x15\xd7\xd9\xc7\xa3\x9b\x36\xbc\x65\xd3\xf6\x23\xe8\x3a\x72\xab\x9f\xaf\xd7\xb1\x90\xf0\x06\x29\x63\xf7\x4b\x1e\x90\xde\x13\x59\xb9\x1c\xf9\xbb\x58\x3d\x3b\x9c\x0d\xbf\x86\x25\x42\x5a\x4e\x50\x0a\xcb\x81\x0e\x15\x8e\x89\x5c\x63\x1c\x5d\xa0\x98\x27\x6a\xd9\xa5\x38\x5a\xc8\x5d\xc5\x96\xe5\x3f\x4c\x0d\xf9\xcf\xa4\xe4\x9a\x63\x59\x82\x78\x70\x9f\x65\xdd\xb7\xe4\xb8\x7b\x4e\x54\x3d\x67\x03\x95\x06\xe8\x2c\xab\xb1\x84\xee\xea\x56\xb0\x34\xfb\x3a\xfb\x5c\xd1\x4f\x5d\xfa\x49\xdc\xf7\x1f\xbe\x44\xed\x09\xee\xb3\x60\xe0\x30\x74\x26\x52\x04\x3b\xf9\xda\xc0\x3d\xb3\xaf\x47\xe9\xfa\xc5\xf6\x5a\x65\x1a\x53\x74\x35\xeb\xcc\x2d\xfe\xbd\x5f\xa0\x88\xa4\x5e\x24\xa0\x33\xb2\x34\x21\xf0\xb0\x02\xe6\x8b\xcd\x55\xfa\x0a\xe0\x68\x2f\x8c\x6a\x1b\x79\x10\xe5\x7c\x03\x6f\xa3\xaf\xdd\x34\x0a\x96\xaf\x34\x19\xc3\x03\x63\xce\xbe\xd4\x63\x04\xf4\xf2\x00\xc0\xb6\x99\x01\x60\xa3\x0a\x99\xe0\x04\xe9\x4c\x92\xc4\xf2\x2e\x46\x46\xce\x8e\xf4\x93\xb3\x69\x01\x01\x5e\x5a\x9e\x3d\x5b\xb2\x39\x34\x1b\xd4\x7e\xcb\x13\x32\xd3\x3d\xd0\xa0\x18\x9b\xa5\x78\x90\x72\xac\xdd\xab\xe4\x8e\xfa\xe9\xe5\x1c\xbb\xf9\xa5\xb9\xc6\x89\xed\xb4\x00\x70\x32\xe4\x30\xab\x6c\x20\x46\x48\xa3\x46\x1b\x2b\x94\x43\xcf\x2e\xc5\x39\x72\x3b\x87\x22\x07\xb2\xbb\x1f\x0f\x91\xc9\x2f\x7d\xab\xfc\xde\x08\x3a\x7f\x73\xe0\xbe\x88\x84\xc4\xcb\x8a\x3a\x0a\x80\x4f\x31\x80\xee\x2b\xaa\x85\x10\xb5\x49\x41\x49\x24\x9c\x74\xb8\x3a\xc9\x94\xc0\x0d\x96\x05\x18\x19\xa4\xfc\xa6\x79\x74\x68\x1c\x1d\x98\x46\x46\x79\xc0\x58\x62\xb8\x94\x0d\x4b\x06\x33\x4d\xdb\xee\x2a\x71\x9a\x4b\x1a\xa5\x38\x9f\x8b\x6b\x65\x9f\x4a\x1e\x8b\x76\x0d\x45\x1b\xb0\x60\x3d\xb2\x31\x15\x76\x9c\x55\x07\x74\xfb\x68\x49\xef\x17\x53\xb1\xb6\x48\x96\xb4\xbe\xa7\xa6\xb8\xd7\x22\xf6\x85\x64\xa3\xd8\x70\x47\x8c\xb7\x40\xf4\x16\xda\x8e\x36\xd6\xa9\xeb\x7a\xe0\x11\xa4\x31\xec\x08\xe9\x21\xba\xf2\x16\x5a\xa5\x6a\xe9\x05\x90\x12\x2a\x2b\x1b\x83\x6b\x95\x4f\x6e\x8b\xe7\x41\x01\xc0\x1e\x4b\x86\x55\x50\x64\x83\xf3\xc9\x38\x8f\xec\x24\x9b\xf2\xa5\x40\x73\x8a\x19\xe1\x8e\x4c\x3d\xb7\x42\xa9\x1a\x07\x95\x9c\x18\xa6\xa7\x8e\xe9\xf7\x59\x8b\x48\x5a\x0c\xd9\x76\xfd\xe6\xb5\xba\x5e\x49\xa7\x04\xbe\x59\x7e\xc0\xd7\x50\xc7\x98\x5d\x8d\x3d\x6d\x15\xe7\x68\x2c\x27\xa8\x8c\xcc\x88\xaf\x41\x39\x4e\xa2\x26\x0f\xd0\x28\x1c\xb2\xfd\x3c\x74\xde\x83\xb6\x7e\x2e\xa0\xf4\xb2\x01\x26\xd6\x4a\x39\x96\x15\xf1\x7a\x9d\xbd\xbb\x44\x9f\x43\x73\xc2\x6d\x1f\x42\xb1\xfc\x33\x07\x07\x08\x72\x87\xa8\xf4\xa3\xe0\xfb\x0c\xcc\xb8\x68\x07\xb3\x02\xc8\x8e\xf8\xe5\x9e\xd0\xea\x28\x14\x05\xf9\x05\x29\x68\xba\xab\xc5\x29\x13\x5a\x8a\x2e\xd4\x48\x37\xd3\x11\xce\x1c\x43\xe7\x41\x76\xcc\x69\xe2\xc6\xae\xc9\x48\xc0\x79\xb0\x49\x5b\x81\xc3\xc4\x37\xb1\x9c\x5a\xe6\xb8\x8e\xa3\xe8\x18\x6d\x34\x76\x8a\x83\x00\xab\x52\xd7\x2a\x5d\xa8\x2a\x30\xc9\x48\x38\xc5\x31\x05\x04\xc7\xa2\x79\x67\x02\x4d\x54\x15\xb2\x66\xab\xd1\x11\xa3\x93\xb0\x38\x12\x26\x04\x8a\x90\x8b\x69\x11\xa6\xb8\x8f\x56\xb2\x88\x32\x3f\x64\x74\x55\xdb\xd9\xdc\x22\xc2\xd9\x51\xc0\x59\x3c\xb1\x30\x93\x3e\xb0\xf0\x4c\x1b\x5c\x37\xad\x28\xa9\xee\x63\x28\x57\x05\x90\x78\xe6\xbc\xc0\xb3\x4c\x3b\x0e\x7b\x73\x43\x9f\x72\x42\xe8\xa2\x64\x27\x3d\x8f\xb0\x4c\xd5\xd2\x49\x68\x44\x65\x02\x4b\xad\x9d\xc4\xb8\x62\xc0\xb1\x24\x49\x6a\xd6\x39\xa4\xb0\x66\x3b\xa0\x67\x59\x9c\xe9\x2a\x02\x4b\x1c\x96\x24\xcf\xc2\x76\x70\xd2\x31\x4e\xd2\xf6\xa4\x8f\x0d\x21\xfc\xed\x92\x21\xde\x1c\xce\xce\x49\x5d\xd2\x4c\x8c\x91\x8b\x38\xdd\x0d\x96\x3a\x29\xcc\xf1\x79\x4f\x64\xd0\x04\x06\x41\x80\x12\xad\x06\x4a\x59\xca\xf7\x74\xe4\x5a\xca\xe0\x75\x85\x51\xd9\x89\x9c\xaf\xc5\xd9\x21\x71\x92\x68\x41\x4b\x1f\xcb\x08\x67\x0b\x22\x60\x08\xf0\x29\xf5\x39\x49\x1b\x43\x9e\x57\x9c\xb2\x20\xdb\xa8\x7b\x5a\x79\xc7\x81\x07\x56\x62\x2a\x59\x06\x2a\xfa\xdf\x1d\x58\xbc\xe4\x81\xa3\xfe\x47\x76\x48\x56\x95\x66\xe5\x01\x74\xa4\x5b\xa9\xee\x7f\xb9\xfe\xb9\xb4\x20\xcf\x98\x5c\x47\xea\x79\x80\xcb\x23\xd7\x3a\xb0\x25\x46\xee\xf2\xc0\xaa\xbb\x68\x60\xca\x2e\x57\xd5\x6c\x15\x51\x18\xb4\x32\x15\x97\x7b\x7c\x26\xea\xef\x83\xb5\x6a\x8a\x56\x81\x66\x6c\x58\xa9\x0d\x90\x79\x59\x1f\xf4\x8b\x35\x22\xa9\x84\x06\xaf\x3c\x0b\xe1\x83\xf4\xbf\x8c\x53\xef\x69\x63\x16\xdf\x1d\x5b\xb4\x30\x48\x26\x97\x62\x0f\x0d\x25\x49\x3b\xe6\x32\xb0\x4a\x37\x69\x6d\x60\x20\x94\x06\xf7\xb4\x05\x8f\x92\x24\xfc\xc6\x27\x05\x8e\xa8\x72\xa4\x50\x26\x86\x66\x0f\x3e\x86\xa6\x7f\xdf\x70\x60\xff\x75\x73\x34\xbc\x6c\x21\x87\x81\x91\x33\x5b\x69\x10\x3b\xb2\xaa\xab\x95\xb3\xab\x28\xf6\x85\xd5\x80\x9f\x32\xd6\xd1\x47\x73\x8d\xed\x0f\x39\x22\x24\xce\x96\x51\x5d\x69\xf4\xc8\xad\x53\xa5\x86\x2c\xde\x54\x1c\x05\xd5\x81\x70\x93\x8f\x3e\x3b\x72\x62\x99\xbf\x3d\x40\x2f\x63\x16\xb3\x7f\x5c\xca\x93\xda\x2a\x1c\x87\x88\x8c\xf4\x9b\x67\x74\xb9\x39\xa3\x06\xf3\x44\xea\x90\xaa\x0a\xed\xba\xf3\xa9\x54\xb5\x16\x76\x15\xf5\xa0\x24\x0e\x3e\xe1\xe0\x4e\x8b\xbb\x0c\xf7\x04\x52\xa9\xf2\xc6\xc1\xd5\xff\xfb\x7a\x20\x61\x49\x14\xc9\xe2\x92\x5a\x68\x51\xc5\x71\xd6\xd1\x43\xc4\xa2\x60\x13\xd2\x96\x91\x5d\x3a\xdb\xe1\x5e\xd5\x19\x95\x2d\xe1\x62\xe2\x52\xec\xa5\xc5\x0d\x09\x99\x6b\x70\x22\x75\xa1\xdc\xcb\x17\xc5\xdc\x4f\x67\xcf\xfb\x23\xc2\x10\xc5\xa6\xe3\x2a\x60\x54\x4f\xa5\x4e\x23\x58\x3b\xbb\xfd\x5f\x54\xab\x2c\x2d\x2d\x23\x25\xa4\xa5\xc8\x8b\x75\x6c\x89\xf7\xcb\xe7\xac\x9c\x8a\x05\xba\x15\x59\xc0\xdb\x5a\x2c\x53\xd7\x46\x3e\xab\x22\x80\xef\x8a\xcd\xdb\x63\x93\x58\x74\x8b\x9a\x1a\x37\x2f\xe1\xff\xb3\x2a\x8c\xb6\x64\x2b\x20\xf6\x52\xc2\x4c\x85\xb3\x55\xa3\xc2\xd3\x76\x28\xe6\xff\xdd\xda\x0d\x56\xa9\x19\x33\xb2\x0b\x25\xe3\x28\xac\xad\x62\x2c\x0e\x53\x9d\x6d\xfe\xaa\x39\xc1\xd6\x05\x27\x26\x88\x65\xf4\x4d\x91\xae\xae\x8c\xfe\x9b\x26\x63\xfb\xb6\xec\x9c\xb0\xca\xcc\xbd\x45\xb5\x74\x3c\x44\x85\x80\x65\xa4\x16\xcd\x76\xeb\x5e\x33\x2c\x49\x2f\x7c\xd4\xc2\xe1\xde\x91\x38\x33\x63\xac\x0d\x59\x1a\x4b\x06\x8a\x26\x48\xe5\x7e\x6c\xac\xbf\xc0\xf7\x0e\x7e\x71\xb5\x85\x6a\x19\xec\x3f\xe1\x26\xbf\xff\xf6\xc6\x06\xfc\x7f\xeb\x6c\xa7\x05\xec\x70\x75\xb1\xc4\x5e\xda\x0b\x1a\x8e\x05\x4e\x61\xb2\x92\x0d\x7b\xaf\x70\x96\x9e\x8a\x04\x63\xd5\xce\x7c\xc2\x2d\x4a\x86\x42\x4a\xec\xa8\x40\xc6\x0c\x6e\xb0\x34\xf9\x32\x59\xd1\x1c\x89\x03\x61\x91\x2d\x27\x45\x01\x7e\xb5\x22\x33\xbd\x0a\x14\x05\xda\x9b\xa8\x30\x77\x15\x48\xd8\x52\x20\x1b\x23\x35\x17\x4d\x7b\xb8\xc2\xd0\x58\x1c\x71\x48\xe4\xa0\x8c\x93\x4c\x3e\x76\xf2\xdf\xae\xe0\xf4\x68\x55\x5c\xf1\x8a\x1e\x91\xc2\x5e\xe2\x0d\x85\xf6\xf0\xce\x0e\xbf\xe5\xc5\x1d\x74\x2c\xbb\x51\x3f\xb4\xaa\xc1\x47\xc4\x0b\x1c\x0e\x07\x61\x15\xe4\xde\x27\x87\xb3\xab\x48\x5b\x31\x8e\x65\xae\xbd\x10\x20\xcb\x48\xa9\x58\x85\xb6\x5e\xeb\x49\xc2\xbe\x42\x1b\xf2\x35\x96\xe2\x4c\x04\x73\xfa\xef\x13\x5a\x41\x66\x6c\x86\xb7\x1d\x19\x14\x15\x65\xa3\x26\xa4\xfe\x5b\x61\x2d\x16\x76\xe6\xb0\x60\xc9\xa3\xa7\xca\x4e\x96\xcf\x38\xaa\xba\xaf\x28\xd5\xb3\x95\x3e\xaf\xab\x2a\xeb\x55\x6d\x71\x5f\x57\x30\x53\xb2\xec\x9a\x54\x51\x49\x87\x0b\x72\xcf\x03\xec\x6b\x87\xf4\xe1\x49\x42\x30\xd8\xbd\x0f\xfa\x85\xbd\x9d\x19\x96\xe1\xec\xe1\x34\xea\xf5\x59\xee\x97\xf4\x83\x0b\xaa\xd8\xca\xde\x5d\xaf\x3b\x63\x82\x50\xf9\x01\xb6\xd7\x40\x40\x57\x61\x17\x69\x49\x05\x88\x24\xc8\x23\x89\x6d\xa9\x14\xd1\x9d\x00\x56\x19\x29\x9a\x57\x23\x86\x87\x69\x57\x24\x0d\x88\x4d\x21\xca\x5d\xb2\xd5\xbe\x08\x63\x54\x84\x83\xf0\x25\xd1\xc4\x38\x2c\x8d\xca\x0b\xb1\xe9\xa2\x6e\x9d\x42\xd1\x35\x8b\xab\x35\x8b\x29\x1f\x94\xba\x23\x46\x09\x2c\x8a\x01\xe7\xd5\x0a\xb0\x1c\x6c\x5a\x3b\xf2\x62\xdb\xd3\x0f\x81\x07\x76\x66\xbd\xb7\x6c\x82\x8e\x0a\x0f\x0a\xaf\x74\x24\x03\xa4\xa8\xb4\x01\x7e\x06\x8a\x79\x2c\x51\x95\x89\xca\x0f\xab\x0a\x53\xd5\x36\x57\x52\x42\xcc\x17\x47\xa3\x68\x52\x0b\xd6\xd7\x32\xec\x7b\x89\x96\xb9\xd6\xcf\xa0\xc2\xf9\xce\x88\x42\xf7\x1c\xfc\x02\x45\xda\x13\x01\xa5\x1f\x3d\xd2\xe5\x37\x49\x58\xad\x9a\x89\x2d\x6a\x46\x89\x2f\x8b\x4c\xa8\xed\x88\xbe\xa5\xb9\x01\x05\x19\x80\xf7\xcb\x72\x6a\xc9\xdc\xd4\x48\x2d\xb4\x9c\x75\x88\x21\x3c\x4a\x77\xa9\x41\x30\x0a\x8e\xea\x8b\x29\xd4\xcb\x73\x61\x72\xb9\xa7\x28\xa2\x1e\x4c\x78\xb8\xd4\x4e\x54\x0b\xae\xe7\x28\xc2\x27\x16\xae\x12\x2f\xd1\xa3\xb5\x45\xd3\x25\xc0\xdb\xff\x44\x96\x75\x69\x2d\xaf\xf2\x2e\xf7\xdd\x4d\x4b\xc5\x33\xd9\xaa\x50\xa0\x7b\x9f\xd6\x05\xeb\x62\x8f\xb3\xc9\x3e\x3d\x27\x0f\x02\x73\x23\xcb\x20\xd9\xce\x89\x31\xc7\xc1\x47\x9c\x7e\xa2\xba\x13\xe2\x7d\x4e\x0b\x8a\x80\xa5\x9d\x3d\xec\xff\xc4\xad\x7b\xf4\xf0\x20\xc5\xf8\x10\xff\x95\x74\xf0\x87\xad\xac\x39\x1d\xeb\xaa\xb8\x5e\xdc\xe7\xad\xc7\x0e\x15\x4a\xeb\xbe\xfa\xd2\xf6\xae\xfa\x98\x5c\x6e\x75\x2e\xcb\x21\x09\x7d\x38\x2e\x9a\xcb\x7a\x51\x96\x32\x6c\x4d\xe9\x95\x54\x88\x92\x53\x08\x9a\x2d\xb2\x14\xbb\x5d\xef\x73\x75\x20\xc9\xc0\xdd\x3b\xec\xf5\x5d\xce\xbd\x80\x5f\x46\x14\x83\xc1\x38\x92\xaa\xf9\xb8\xf6\xd9\xd0\xb2\x48\x5d\x4b\x6a\x25\x90\x91\x1c\xe6\x3f\x62\xc1\x97\x62\x03\x6a\x43\x21\xf7\xb1\x8b\xed\x60\x46\xfd\xe4\x4b\xea\x4e\x51\xd0\x7d\x43\x78\xd6\x2a\x34\x71\xa9\xfd\x34\xfc\xc8\xaa\xce\x72\xbb\xf2\x6b\x1e\x78\xef\xe0\x28\xc2\x8f\xa3\x43\xc9\x13\xe5\xc0\xa9\xa7\x23\x53\x18\x73\xeb\xaa\x1d\xa6\x7d\x9b\xf0\xf7\x9c\xaf\x6a\x72\x8a\xf4\xd4\x92\xc9\xeb\x34\x7d\xc3\xa1\x49\x66\x3b\x72\x5f\x16\xf7\x1c\xe4\x82\x20\x0d\x82\x5d\x1e\x94\x39\x4c\xc3\x44\x71\xad\x1f\x35\x06\x93\x48\x2f\x8c\x80\x83\x82\x48\x9c\x85\x7c\xc4\x98\x91\xe7\xd9\x83\xab\xda\xb3\x25\x58\x74\xeb\xd5\xd2\x53\x9b\x03\x40\x49\xac\xd0\xcf\x8a\x17\x72\x09\x97\xe7\xdc\xc8\xa5\x7e\x9c\x24\xa8\xcd\xb7\x9c\x80\xb5\x75\x42\x65\xc6\x11\x20\xb8\xa0\x58\x1d\xd7\xa9\x18\x8a\x29\xec\xd8\xc0\x2e\x66\x19\x83\x79\x11\x8d\x30\xcc\x31\x4b\x96\x62\xc1\x25\x2d\x8e\x9c\x51\xa1\x22\x21\xab\xb8\xd7\x8a\x99\x50\x59\xc9\xa1\xca\x85\x47\xc1\x8b\xe6\x96\xe0\x55\x6e\x13\x4a\x15\x60\x89\xb7\x89\xb5\xae\x8f\x9a\xf3\x82\xdf\x0a\x6a\x1e\x29\x2c\x09\x56\xf0\x56\x1f\x94\x70\x2e\xcf\x73\xdc\x7c\xb7\xf9\xa9\x55\xc5\x63\xca\x4b\x99\xb6\xaa\xc0\x0b\x45\x04\x09\xc9\xb9\x2e\x09\x4d\x29\x88\x63\xca\x23\x23\x97\x21\x05\xb6\xc3\xb5\xfa\xda\x27\x81\x6b\x58\x90\x00\x62\x1e\xc9\xa4\xd2\x34\x85\xa5\xc8\xd4\xe8\x19\x85\xb2\xbc\x75\x83\xf2\x1a\xda\xaf\x5c\x9e\xab\x0d\x6e\x9f\xf3\x38\x38\x66\x19\x3f\x31\x96\x29\x76\x93\xb3\xf2\xc8\xe0\x8b\x48\x05\xd8\x41\xe9\x32\xa2\x32\x85\x1d\x60\xc4\x3f\xe3\xe4\xed\x3d\xac\xd2\x6c\x69\xf3\xbd\x03\x5a\x42\x8c\x3e\xc6\x78\x79\x1e\x45\x41\x4f\x9b\x89\xda\x12\x2d\x8f\xa8\xab\x33\x71\xb2\x03\x46\xaa\xea\x83\x63\xa4\x3e\xf8\xd2\x26\x2b\x28\xc5\x5c\xf7\x60\x21\xe6\x9e\xe6\x65\x45\xb8\x7a\xa8\x12\x7b\x6c\xbe\xf0\x16\xf7\x1e\xe8\xb2\x9c\xf6\xb6\x2a\x47\xb3\x4a\x73\x33\x14\x8a\xb3\xbf\x96\xa9\x37\x1c\x9b\x39\x71\xb3\x8b\x32\xa9\x79\x12\x69\x47\x31\x23\x95\x65\x44\x20\x82\x9c\xaf\x51\xc7\x02\x8e\x64\xfc\xac\x5a\x62\x56\xb0\xc4\xac\xb8\xa4\x6e\xd8\xac\xb6\x8c\x35\xa5\x82\x47\xd7\xa9\xa0\xed\x8f\x47\x71\x70\x8d\x0d\x11\x05\x57\xed\xfc\x41\x98\x6c\x49\x72\xd8\x91\xb4\x19\xa7\xfd\xb3\x85\xca\x55\x8a\xd5\xea\xe4\x0a\xaa\x5b\xd6\x30\x97\x85\xf2\x0b\x72\x03\xd9\x91\x6a\x66\x97\x47\x9f\x5d\xab\xce\x38\x3e\xcb\xc4\x38\xf7\x90\xd3\x72\xd6\x57\x79\xab\xd0\x54\x80\xb4\xd2\xec\x85\x22\xd2\xda\x82\xcb\x2a\xcb\x26\x15\x91\x08\x8a\x95\x38\xfa\x6a\xa5\xcd\xc5\x45\x35\x62\x5d\x0a\xa3\x47\xc6\x99\x1a\x1f\x56\xb7\xa5\xee\xab\xef\xc8\x41\xa2\x59\x8d\x2e\x13\x2a\xac\x50\x2e\x28\x1d\x23\xae\x31\x3e\x14\x93\xe3\x06\xce\xad\x28\x94\x3a\xa2\x88\x9a\x95\x9b\x94\x60\x95\x9a\x73\x9a\x09\xe9\xbb\x52\xaf\xca\xef\xe6\x05\x4c\x58\xd9\x9a\x72\x84\x09\x1f\xaf\x96\x3f\xe7\x83\x18\x44\x99\xa9\x0d\xca\x70\x52\xdb\x8e\xa2\x12\x1f\x52\xf3\x5b\x1b\xfa\x83\x6a\xbf\x58\x95\xa2\xf9\x36\xed\x37\x07\xb4\xae\xe2\x41\xb2\x27\x88\xe2\xb2\x94\x99\x72\xda\x55\xb1\x02\x7d\x1d\xe1\x67\xde\xf9\x2c\x47\x94\xf0\xba\x68\xfb\xdd\x2a\x37\x6a\x5f\xeb\x72\x1c\xef\x83\xe0\xca\x07\x82\x4b\x75\xc8\x5e\xf2\x74\xed\x8c\xea\x04\x2b\xe1\x15\xbb\x55\xd0\x8f\x83\xfb\x48\x86\xbf\x11\xe4\xbf\x2e\xc4\x2c\xe3\x68\x2f\xc6\x1e\xa6\xcb\xf3\x14\xa2\xd3\xc1\xcf\x35\x85\x1d\xd7\x30\x52\x42\x9e\xbf\x15\x72\x44\x84\xa8\xf6\x62\x45\xbd\x18\x21\x02\x4e\x56\x40\x6b\xf2\x4d\xd1\x7f\x1d\x61\xff\x65\xd7\x16\x61\xd7\xcf\x3a\x71\x9d\x7d\x02\x0e\x88\xe4\x2c\x2c\x8d\xa0\x88\x95\xb0\xb2\x33\xd7\xf0\xe0\xc8\xe8\x5b\xbf\x5a\xc0\x9c\x62\x9e\x51\x55\x77\x4e\xca\x48\x05\x5f\xb4\x7c\xb2\xa9\xeb\x61\x94\x15\x49\x6d\xf6\x22\xd5\x3c\xc4\xe7\x19\x41\x49\x1c\xc1\x1c\x95\x1d\x5d\x6f\xa9\xd0\x02\x32\xa7\x5a\xa1\x70\x55\xac\xd2\x96\x92\x5f\x00\x32\xa5\x17\x6c\xc0\x21\xc5\xd9\xf3\x96\x7f\x5b\xa9\xe7\xd9\x8a\xe3\xf6\xe9\x0e\x48\xbb\x43\xb1\xfa\xbc\x2b\x4c\x3d\xbc\x50\xb6\x02\x60\x3f\xf9\xf1\x77\x8f\x57\x37\x01\x94\x2c\x57\xee\x16\x62\x9c\x82\x53\x4b\x73\x31\xf5\x27\xaa\x84\xb2\xc3\x4b\x46\x93\xd5\xbb\x43\x24\xb5\xdb\x30\xb5\xdb\x38\x48\x4d\x2c\x11\xfa\xcf\x76\xbe\x97\x27\x18\xbd\x79\x21\x8d\xba\x9c\x19\xa4\x06\x4c\xb4\xe5\xe5\x39\x4a\x89\xd8\xb7\x7d\x4a\xce\xa4\x6f\xa3\xc9\x24\xa1\xe4\x11\x44\x82\x28\x95\xe4\x09\xfe\xd9\x46\x2a\xa5\x5d\xc3\x97\x6a\x41\xb4\x04\x99\x4c\x61\x11\xa0\xd2\xcf\xef\xa1\xaf\x4d\x07\xa0\x2e\xca\xfa\x4a\x8b\xb0\x1c\x7d\x6f\xcd\x95\x60\x15\x1e\xa5\xd2\x1c\x89\x76\x48\x70\xd0\x07\x81\x53\x50\xd9\x1f\x4f\x91\x04\x51\x8e\x19\x0f\x52\xe9\x12\xd5\x76\x22\x4c\x0b\xc8\x1f\x18\x24\x55\x8e\x8c\x64\xe5\x96\xa9\xcb\xd5\x08\x38\x3f\xcc\x6a\x04\x67\xa7\x83\xaa\x8e\x72\x9b\x98\x93\x2b\x01\xc5\x87\x55\x01\x91\xf3\x39\x4e\xc8\xc0\x44\xd2\x92\x5d\x1f\x60\xbb\x84\x0a\x3a\xbd\xd0\x3d\x4a\xf9\x26\x84\x27\x12\x14\xf5\x4e\x32\xe1\x98\xcf\xce\xa7\xc6\x33\x49\x18\x04\xa5\x67\x58\xd1\x76\x06\xae\x6c\xc8\xcc\x63\x1c\x70\x1c\x03\x0c\x0d\x18\xb9\x8a\x55\xac\xfc\x15\x5d\xd3\xa4\x6a\x06\xda\xfa\x23\x7e\xb1\x75\xf8\x4e\x27\xbe\xf2\x9c\xd4\xb2\x3f\xf4\xc8\xae\x56\x1e\xc8\xe5\x1d\x65\xa0\x65\x85\xed\x46\x85\xe6\x17\xb1\x12\x41\x0a\x29\xac\x2e\x37\x45\x70\xd7\x14\xd9\x28\x37\x38\x08\x11\x44\x92\xc3\x55\x82\x16\x57\xe3\x40\x9e\x89\xf3\x4e\xed\x58\x8c\xbe\x2d\xef\x26\x9c\xa3\xef\xd5\x88\x90\x0c\x85\xbc\x73\xb5\x6d\x83\x55\xb7\xc4\x81\xc8\x60\x39\x4e\xaa\x71\x27\xb8\x21\x75\x13\x74\xba\xdc\x0b\x77\x66\x05\x6b\xdd\x4e\xb8\xaa\xb9\x8e\xb2\xea\x66\x3d\xb1\xaa\x6d\x58\x13\x35\x2e\x76\x7e\x67\x05\x2f\x3d\xf1\x36\x58\x4a\x00\x66\x8d\xa2\xf2\xb0\x04\xac\x28\x5b\xa1\x69\x29\x92\xdd\xab\xba\x99\x13\xa7\xc8\x84\x04\x61\x9f\xd5\x44\x67\x8b\xab\x41\x38\xa7\x3a\xd9\x49\xb6\xcd\x3c\x47\xdd\x94\x95\x6b\x26\xef\xab\xfb\x22\xdb\x9a\xac\x00\x3b\x67\x3b\xae\xa0\x84\x34\xa8\x21\xac\xc2\x59\x31\xc6\x11\x57\xd9\x63\x35\xfd\x2d\x63\xea\x8d\x9c\x8f\x96\x67\x9f\x23\x8f\xa8\xd2\x52\x5d\xb2\xcc\x01\x8b\x2d\x9a\xa9\x98\xe3\xde\xd7\x97\x96\xc4\x01\x36\x61\x3d\xd7\x50\x56\x21\xc7\xa6\x6b\x34\xa2\xf2\x39\xa0\xb7\x29\x4d\x64\x14\xc4\x0e\x7c\x46\x6f\xee\x8b\x9e\x7a\xdf\x91\xa8\x2e\x13\x59\x66\x3a\xbc\x07\x1b\xa7\x5c\x74\x32\xeb\xc2\xfb\x21\x5c\x85\x62\x1a\xac\x67\xd5\xc2\x76\x2e\x51\x20\x99\x04\xf9\x4f\x70\x96\xee\xb8\xd2\x1b\xa7\xda\x39\xec\x7c\x8d\x6a\x3b\x8a\x65\x77\xa3\xa9\xe1\xe7\xa5\x8f\xcd\x22\xee\x3a\xa0\x95\x0f\x21\xc5\x70\x55\xb5\x2d\x73\x9c\x99\xfa\xd5\x37\x4c\x37\xdc\x7c\xf3\x46\x67\x2b\x1b\x2f\xed\xab\xef\xa8\xc1\x28\x9c\x17\xbe\xcb\x66\x56\xc6\x88\xfa\x09\xca\x35\x55\x47\xef\x72\xb1\xdb\x7b\x38\x0f\x82\x64\xb4\x9d\xf9\xcf\xd8\x79\x53\x9e\x38\xcd\x1a\x70\x5d\x00\xd2\x0e\xc9\x52\x77\xa0\xee\x91\x8e\xa1\x94\xcc\xd9\xf9\x74\x84\xa4\xd6\x57\xe2\x2c\x87\x78\x1b\xdc\x54\x61\x26\x89\x83\x04\x72\x2c\xb3\xaf\x98\x77\x89\x73\xc6\x09\x29\x3e\xd2\xf1\xda\xe6\xd8\x97\xed\x62\x38\x1d\xd3\x72\xd7\x51\xac\x30\xcc\xe0\x04\xe0\x44\xf0\xc5\xed\xef\x47\xe0\x7e\xf4\x05\xc7\x1d\x2d\xd9\xce\x7e\xa6\x78\xc2\xde\xf5\x17\x93\x39\xce\x4d\x6f\x8d\xde\x3a\xe8\xc5\x45\x4c\xe3\xd9\xad\x29\xda\xf6\x12\x26\x80\x0e\x02\x02\xbf\x3a\x64\x3c\x20\xe3\x16\x3e\x40\x9c\x81\xc1\x91\x6a\x8b\xbf\x25\x99\xac\x10\x65\x5c\x6e\x68\x52\xa1\xa3\x86\x9b\xf4\xca\xbd\xcd\xa5\x25\x11\xca\x60\xd3\x72\x6f\x40\xe9\x43\xde\xa8\x72\xad\x4b\xb5\x6d\x1f\xa8\x51\x46\x89\x81\xeb\xa5\x75\xa4\x2f\xcd\x60\xbf\x42\x5d\x2f\x28\x1e\xd1\x06\xbf\xfc\x6b\x31\x15\x52\xbe\xdb\x2f\x37\x47\xb9\x36\x1a\xd2\x72\x48\x51\x0d\x2c\x42\x9d\x95\xa3\xb4\x72\x2e\x38\x73\x99\x8e\xdf\x4c\x52\x2a\xaa\xbb\x0e\x91\xd9\xa5\x58\x76\x54\x64\xf6\x89\xda\x0e\x11\x07\xa8\x5b\x7b\x4a\x6c\xd5\x38\xf0\x10\xa9\x5c\x9e\xb7\x5c\x1c\x57\xde\x71\x94\x59\x28\x2c\x65\x8c\xc5\x6d\x26\xd1\xe9\xc4\x56\x66\x0b\xed\x73\x53\x4e\x9e\x58\xe2\xb7\x4f\xac\x49\x70\xa9\xc8\x7b\x0d\x46\xdc\xdd\xd1\xc8\xda\x62\x2b\xf5\x20\x2a\x59\xab\xfc\x00\x47\xbe\x37\x38\x72\x9e\xf8\x14\x0a\x2c\xf1\xae\xac\x45\x94\xf2\x1d\x78\x6b\x65\x88\x51\xa0\x83\xea\x8d\x76\xf9\x88\x4e\x0b\xb5\xbe\xcd\x74\x2a\x0e\x55\x3f\xc6\x24\x2e\x89\xcb\xc8\x64\xa4\xae\x01\x9b\x9a\xea\x88\x43\xc1\x98\xf5\x28\x12\x82\xe3\x5e\x3d\xe2\x6e\x39\x0f\x38\x4b\xb8\x77\x0a\xf6\xc7\x64\xde\xb8\x90\x1d\xfc\xc3\x59\x26\x24\x66\xa6\x32\x22\x4c\x6d\xc7\x35\x51\x75\x30\x9b\xac\x4f\x28\x8d\xd6\xa3\xa0\x08\x26\xd1\x3e\x36\xcd\x09\xc1\x9c\x5e\x49\xf3\x2a\xb5\x33\xe4\x25\x0f\x16\x25\xa7\x97\xb2\xf3\x97\xe7\x31\x92\xab\x25\xce\x1c\x9a\x5b\xea\x5e\xb6\x23\x65\x2f\x7f\xf2\xe3\xef\x9e\xac\x0c\xcf\x7b\xab\x24\x28\x2a\x7e\x2a\x87\x8d\x63\xb3\xb7\xab\x34\xa8\x43\x5d\x9b\x83\xdf\x77\xd1\xc3\xf3\x4c\x48\xf7\xce\x77\xc6\xd3\x4f\xd6\x01\xfd\x7b\x5b\x5f\x55\xbf\x39\xd0\xcc\x79\xe0\x98\x1d\x4b\xd9\x11\x87\x01\xb5\x1a\x58\x14\x42\xa6\x7e\x0e\x90\x62\x71\xf0\xe2\x81\xa8\x29\x56\xfd\x7b\xb8\xc3\x16\xac\x03\xe9\xf7\x36\x1b\xd2\xd9\x30\x0e\x79\x8a\x4b\x6d\x09\xa2\x25\x3b\x65\x36\x42\x82\x22\x0c\x1b\xcb\x84\x5a\x20\xb1\x8c\xc8\x37\x2e\x64\xbe\x1d\x09\xd0\x3a\x83\x9d\xc4\xe4\x25\x50\xd5\x4f\x45\xa7\xb6\x94\x97\xf0\x39\x8d\xbe\xd0\x72\xb0\x21\xe6\x05\x53\x45\x0b\xc6\x00\xda\xc3\xd7\x64\xd9\xe0\xcd\xdc\xe2\xdb\xab\xb5\x89\xba\x9e\xac\x63\xe8\xf7\xb7\x5c\xba\x42\x21\xdd\x14\xc4\xd9\xa4\xe6\x52\x37\x7f\xb4\x39\x85\x75\x28\xf8\x7b\x67\xba\x98\x8a\xa3\x22\xd1\x20\xb0\x9d\x17\x8e\x34\x11\xf2\x74\x52\x19\xab\xdd\x51\xb0\x5c\x9e\x85\xdc\xa2\xd8\xbd\x92\x35\xef\x77\x3c\x86\xe5\xc8\xa9\x4f\x71\xf4\xd5\x30\x87\x75\x12\x27\xdf\xfb\x0d\x97\xe7\x29\x87\xe5\x7b\xba\xfb\xd2\x43\x75\x13\x72\xf2\x55\x4b\xe0\xa8\x6a\x61\xa0\x05\x07\x3a\x8b\x76\x5e\xc1\x95\x8c\xe8\xa2\xd0\x9e\x6e\x50\x37\x70\xf2\xe8\xe4\x08\x23\xad\x2d\xd3\xb6\xe4\xf9\x78\xac\x6b\xad\x3d\xd0\xde\xae\xca\x38\x36\x1a\x18\xb8\x26\xef\x92\xb9\xb8\xd3\xce\xa7\x1a\x07\x86\xc1\x96\x77\x25\xec\x73\x13\x5b\x52\xf4\xe6\x24\x29\x5a\x4b\x65\xb0\x72\xf8\xf8\x27\x63\xd2\x9c\x70\x1f\x40\x44\x4a\x29\xb9\xa2\x3b\x94\xdc\xb6\x9e\x7d\x72\x43\xfc\xfb\xd6\xb5\x49\xa7\xa5\x2a\x29\xce\x67\x30\x2e\xad\x3a\xc8\x9b\xf9\x5b\x17\x23\x1d\x23\x42\x42\x4b\x21\xd2\x28\xd3\xbe\xfc\xe8\xf1\xea\xa3\xe7\xa9\x92\x15\x11\x7c\x2f\x4c\xec\x27\xeb\x70\xef\x7d\x15\x09\x45\x19\x86\x23\x6a\x7c\x73\x48\xeb\xb0\xf0\xbd\x0d\x29\xe1\xfa\xc3\x77\xd1\xca\x2b\xcf\xc1\x3d\xae\x97\xa2\xe4\x77\x52\xcb\x9b\xa3\x5e\x19\xf1\xf7\x37\x6a\x56\x2b\x74\x43\x9f\x94\xb4\xf9\x6e\x73\xa8\x2b\x4b\x7e\x5f\x42\x14\xa9\x2f\x47\x60\xe1\x2d\x4b\x8c\xea\xc7\xd6\x41\xc1\xb7\xd7\x2b\x3d\x57\x81\xf1\x6e\x44\xb4\xb2\x46\xaf\xe6\x68\x87\xcd\xdf\x05\x9a\xdd\x61\x19\x56\x86\xd0\xd5\x78\x92\x6c\xee\xee\x91\x25\x42\x16\xc4\xed\x36\xfe\xe9\x0d\xf6\xc4\x32\x8a\xc8\xaa\xe2\x2d\xd5\x32\x57\x1c\x64\xb9\xaf\x5a\xcc\x33\xb0\x03\x65\x1d\x74\xb8\xbf\xa2\xcc\xb1\xca\x8e\x4b\xee\xbc\x83\xa7\x14\x8e\x4c\x7e\x6d\xa1\x7c\x2f\x05\x4a\xcf\xa5\xd2\x7b\x0e\x96\x37\x97\xe8\x06\x7b\xe8\x87\x42\xaa\xeb\x6a\x98\xe7\x52\x54\xed\xc6\x5b\x15\x9d\xd2\xf5\xbd\xc1\x42\xfb\x61\x7d\x6f\x58\x5f\xbb\x53\xb3\x94\x3b\x8b\xff\xa7\x37\x18\x77\x3f\xac\xf4\x4d\x94\xdc\x14\x10\x31\xdf\x3f\x20\x7a\x7a\x83\x71\xfa\xc3\x16\xdc\xb4\x05\x49\xf5\x05\x8e\x11\xfc\xa3\xe9\x8b\xb5\xa1\xfc\xc3\x16\xdf\xbc\xc5\x0a\xd2\xf9\xc6\xac\xde\xca\x9b\xef\x36\xd7\x7d\x6d\xed\x87\x65\xdd\x6b\x75\x92\x68\x10\x2e\x4e\x24\x0e\x7e\x79\xc0\x6d\x4e\xb0\x73\x71\x77\x8d\xf4\x16\x82\x17\x1e\x48\x46\x18\x26\x7a\x1c\xf6\x0f\xfe\xf0\xa5\x36\xe7\xc1\xf7\x0e\xb6\x7d\x11\x4f\xd7\xf6\xee\x2d\xa9\xa2\xc5\xfd\x6d\x42\x1e\x67\xfe\xec\xd6\x39\x04\x4d\x86\x8a\xf2\x61\x3b\x8a\xfd\x4a\x6c\x94\x14\x2c\x05\xe9\xb2\x76\xcf\xab\xc2\xb0\x7e\x54\x92\x23\x9f\x46\x43\xbd\x90\x04\xfc\x4e\xdc\x8b\x7e\xb5\x7e\x28\x6a\xc0\x85\xf4\x56\x5e\xb4\x1f\x88\x61\x89\xa3\x7e\x10\xb1\x1e\xbb\x00\x3f\x70\x3f\xf4\xc3\x29\xef\xc9\x0e\x21\xa0\x9a\x5c\x2f\x8f\x30\xa5\xd8\x2f\x8d\x76\x9e\x86\x14\xa3\x6b\x94\x71\x42\x27\x1a\xe2\x74\xa8\x2a\x2e\xd1\x31\x9f\x54\x97\xfb\x3c\x16\xfd\x74\x1d\xcd\x45\x82\x02\x1b\x09\xb7\x97\xea\xbc\x4e\xa2\x6b\x9c\x3c\xb0\x4b\xfd\x74\x06\x56\xc2\xa0\x20\xbc\xb3\xbd\xc5\x6b\xff\xc1\xfb\x5f\xb3\xf8\x1c\x87\x18\x6e\xef\x2c\x79\xba\xf6\x47\xfc\x03\x4c\x36\xc3\xd2\x7a\x07\x0b\xfa\xe9\xda\xa1\xf1\x0f\x30\x6d\x69\xf4\x3d\x39\x78\x9e\xae\xf3\x1f\xfe\x11\xd6\xe3\x88\x73\xa1\xf2\xe6\xbb\xcd\x45\x58\xe7\x4a\xbc\x7b\x6d\xe8\xf3\x24\x49\x69\x35\xdd\x9d\x56\xd7\xb9\x07\xbc\x4f\xb7\xca\xf2\xc6\x95\x2b\xdc\x64\xc7\xb9\x8d\x2c\xbc\xbf\xcf\x82\xaa\xa5\xfd\x48\xb0\x6d\x43\xe4\xbd\xff\xe1\xe0\x3e\x0b\x54\xf2\xe7\xdc\x66\x2f\x24\x8b\xb5\x9f\x83\x8b\xb9\xa0\x4b\x2b\x69\x6f\x57\x56\x94\xba\x5c\x0f\x60\x25\x7e\xe3\x72\xc4\xa8\x59\x99\x57\x6b\xd4\xf6\x3d\xa6\x78\x44\xa3\xae\xa3\xe8\xbc\x3f\x30\x24\xa5\xd7\xe1\x51\x85\xaa\x3b\x8a\xe4\x00\x89\x75\x92\x60\x72\x5f\xe9\x0d\x45\xa9\x74\x16\x35\x4f\x14\x48\x49\xd2\xce\x50\x1d\x14\x45\x51\x05\x93\xfb\x09\x4b\xac\x43\xe5\x5e\xa6\xc4\x33\xc7\x69\x79\xac\x57\x65\xeb\x7a\xed\x2e\x4e\x3c\x79\xb6\x03\xec\x35\x41\x31\xda\xb1\xb2\x2b\x65\x8a\x22\x9f\x38\xd7\x1c\xa3\xea\xfc\x11\x05\x73\xea\xde\xb9\x0e\xa0\xc1\x71\xb4\x23\xf3\xb8\x56\xaa\xa0\xee\x82\x1d\xce\xef\x09\x57\xfb\x3b\xf1\x2d\x25\x7c\xb9\xaa\xd5\xde\xf7\x2b\x5f\xed\xf2\x05\x7b\xac\x76\x88\xaf\x89\x9d\x7d\x8b\xb8\xf1\xb2\xb8\x14\x47\x6f\xd7\xf5\xda\xc5\x8d\x56\x9b\x33\x47\xdc\x5c\x07\xc7\x56\x2f\x1b\xb8\x1d\x23\xba\x58\xbb\xd2\xfe\x5e\x45\xa4\x51\x7f\x83\x6a\xaf\x5f\xc5\x94\x27\x94\x12\x7e\xbf\xeb\x47\x33\x8e\xaa\xb6\xba\xe5\x68\xfe\xdb\xd6\x97\xd6\x0d\x5d\xbb\x07\x7f\xd8\xd0\xf7\xa1\x20\xf8\x79\xcc\xba\xe6\x6a\xc2\xdc\x51\x3b\x5c\xdc\x54\xb7\xe1\x87\xad\x3d\x9d\x57\x23\x6a\xdd\xb5\x77\x08\x98\xfc\xed\xd9\xf9\x86\xaa\x12\x3f\xec\xf9\x2d\xf6\x3c\x54\x47\x82\x42\x37\xef\xa9\x53\xea\x16\x34\xe5\xee\x8b\xa8\xd6\x5e\xe5\x1f\x88\xea\x36\x44\x45\x0a\xe7\xaa\xdc\x64\x8c\x7c\x7f\xfa\x23\xd7\xcd\xaf\x6e\x6e\xf4\xda\x77\xfd\xc3\x46\xbf\x17\x60\x40\x50\x4f\x86\xf8\x6f\x94\x7e\xe6\xce\xa3\x2a\x3f\xfb\xe0\xdb\xf3\xcf\xee\x25\xfd\xec\x62\xed\x55\x2f\xbc\xdc\x6a\x55\xf7\xb4\x87\x7b\x91\x2c\x65\x6a\x12\xb1\x5d\xd8\x31\xb7\xb9\xa6\xfd\xe5\xfc\x74\x55\xf2\xc7\x84\x6d\xb6\x5a\xf1\xc1\x2e\xb7\xcf\xa8\x74\x36\x59\xb1\x5a\x5c\x5e\x58\xab\xa3\x85\xee\x50\xee\xc0\xf5\x34\x7b\xcb\xa5\x47\xca\x3c\x6a\x93\xab\x41\x1b\x1c\xdb\x01\xea\x7e\x6e\xc6\x0e\x30\xe3\x92\xfc\x1c\x5d\x51\x9b\x9e\xf6\x05\x51\x71\x91\x37\x6e\x52\x19\x19\xbf\x95\xee\x7d\x95\x30\x91\x55\x4e\xb2\xa3\xa1\xd4\x76\xbe\xa0\x0e\xa2\xf3\xc9\x8d\xf0\xbc\x36\xa8\x12\x4b\xba\x66\x3b\xde\xdf\xda\x72\xb6\x16\xa9\xf6\xe6\xdc\x84\xff\x15\x37\x3d\xc0\x3a\x95\x6a\x65\xfa\xed\x70\x4f\x51\x43\x6f\xb2\xca\xc6\xb8\x5c\xc3\x6e\x01\x41\xdd\xc5\xba\x54\xef\x47\x85\x07\xbb\xb2\x11\x59\x0d\x56\x85\x17\x49\x6d\x6c\x64\x08\xe3\xb1\x58\x0d\x06\x1c\x31\xab\x65\xc2\x91\x23\x25\xfe\xcb\x73\x1c\xb3\xe9\xa4\x1f\xad\xb0\x0c\x4c\x60\x7c\x1f\x2a\xad\xe4\xc5\xc2\x95\x5e\x37\xc6\xca\x26\x33\x81\x03\x8a\xbb\xaa\x46\x5a\xed\xac\x7a\x5e\xae\xdf\x20\x29\x97\xe7\x2d\x89\xcb\x31\xd9\x05\x14\x29\xd4\x19\xa7\xdb\x51\xa1\x2b\xa3\xf6\xd8\x84\x7d\x2c\xc5\x8a\xb3\xa2\x1f\xb6\x3b\xf8\x26\x1c\x27\xc1\xf1\x81\x6d\xf2\xbb\x21\xb8\x70\xfb\xbb\x63\x7a\x19\x2e\xa3\x08\x5e\x6a\xab\x73\x49\xef\xcf\x95\x31\xa3\x09\x02\xb7\x5c\xc5\xc9\x46\x05\x12\x7a\x69\x59\xab\x30\xbd\x75\x57\xcc\x79\x8c\x76\x53\xf1\x7b\x91\x63\x78\x71\x43\x49\x99\x7f\x8f\x97\xaf\xb0\x88\xa3\xd8\xda\xb6\xdb\xe0\xea\x72\x16\x77\xf4\x76\x96\xdb\x5f\xce\xa2\xcb\xbc\x8e\x7b\xfc\xbb\x5c\xe6\x7b\xba\xe3\xe6\x3c\xe6\xaa\xa6\xfb\xdd\x1d\xbb\x17\xeb\xd8\xcb\xbf\xcb\x05\xe7\xa4\x28\xa8\x86\xb7\x9a\xd8\xee\x98\x8d\x7d\xe2\xa6\xdd\x8d\xf4\xd7\xe1\xa0\x7f\x9f\x3b\x41\x51\x77\x22\xde\x6c\xa3\xbc\xb9\xc2\xee\x6e\x4b\x7c\x9e\xeb\xe6\x37\x36\x97\x7f\x9d\xb3\x4b\xfd\xf0\xad\x1a\xcf\x14\x4b\xd9\xcc\xd9\x4d\xb2\x71\x27\xce\xe6\xc7\xd6\x39\xbb\xcb\xc7\xb6\x3b\x3b\x47\xd1\x27\x26\xb9\x3b\xb3\xaf\x73\x76\xf7\x73\x04\x7f\xa4\xfa\x2e\x39\xbb\xb7\x5f\x86\x75\xce\xee\x7e\x3c\x48\xff\xc8\x7c\x63\xce\xee\xf6\x12\x49\xdd\xfc\xd9\xd6\x20\x9e\xad\x03\x0d\xbc\xdc\xc1\xa0\xb6\x15\x4a\xf8\x31\x6a\xa5\x57\x27\x25\x4c\x48\x27\x8a\xdc\xcf\x34\xe6\x5e\xd5\x65\xea\x77\x2a\xb4\x32\x44\xa7\xe6\xa7\xc3\xf9\x50\x03\xe8\xad\x2c\x15\x7b\x28\xc5\x01\xb9\x2d\x9e\x72\x1a\x7c\x29\x8e\x7a\x2d\x78\xea\xd7\x4b\x28\xc4\xaa\x76\x27\x4a\xaf\xa0\x2f\x34\x64\x5c\x9a\x30\x02\xae\x34\x87\xe2\x65\x89\x27\xd4\x1e\x2c\x6d\x60\x35\x5f\xb9\xb3\xa7\x32\x39\xb5\x7e\x59\x4a\xb3\xbb\x1d\x1c\xc0\xb1\x1d\xe2\x4f\x2a\x13\xec\x1a\x11\xb6\xf2\x69\xa8\x7d\x86\x33\x20\x31\x98\x29\x8a\xd2\x96\x76\xd1\xcb\xfe\x52\x67\xbb\x65\x0a\x76\x1d\x12\x37\x24\x96\xcb\x73\xce\xad\xaf\x10\x52\x45\x14\x06\xf7\x6a\xc8\x66\x0e\x43\xa0\xa0\x5c\x84\x1d\xa9\x55\x2b\xd5\xee\xaa\xae\x75\xa6\x58\x47\x2f\xc9\xe1\x63\xb0\x50\x9a\xd5\x92\xc0\xb5\x79\xfd\xd6\x2d\x59\x6e\xdd\x32\xcc\x18\x27\x5b\x1c\xcf\x69\xa3\xd0\xb9\x6e\x29\xfd\xf4\x1f\xe1\x0e\x9e\x73\x13\xe5\xf7\xe8\x03\x74\x7f\xb3\xcc\xb4\x67\xfc\xd3\xbf\xfb\x65\x41\xa9\x1c\x8d\x70\x7d\x3f\x97\x09\xb9\xbb\xde\x26\xa4\x8b\x26\x7f\xff\x45\xfb\x7b\xdd\xb0\xe4\xce\x63\xe3\x77\x0b\x33\x3d\x8b\x7f\xff\xe5\x2b\xf9\x5d\x23\x35\xef\xb0\x03\xee\x7b\xb8\xe4\x4a\xd7\x35\xfd\xfd\xd7\x55\xd2\xdf\x2f\x1a\xe2\x4e\x0b\x87\xbc\x5f\x97\x93\xe9\xbe\xe5\xf7\x60\xdf\xea\x66\xc0\xe1\xef\x27\x7f\xcf\x4b\xd8\x1c\xd6\xe6\x62\xae\xbd\x72\x54\x7a\xe2\x55\x21\x97\x5a\x99\xa9\xd6\x5d\xc3\x21\xb1\x5a\x77\xbe\xe1\x8c\x18\x32\x1e\xc3\xcc\x41\x7a\xdd\xaa\x20\xcb\xf1\xb1\xc2\xae\xa9\x91\xb8\x7a\xb5\x39\x84\x7a\x8b\xfd\x34\x8e\xe8\xd7\x96\xd1\x64\x45\x4f\x84\x86\xa2\x60\xaf\xed\x88\xdb\x00\xe4\xa7\xd0\x69\xac\x56\x02\xd1\x6a\x55\xb7\x30\x01\x0d\xa6\xf2\x96\x8d\xc7\x85\x48\xca\x47\xc5\x55\x0b\x40\xc0\x03\x37\x80\x3b\x08\x17\x32\x72\x1b\xd4\x5e\xe4\x10\x47\xdf\x32\xee\xd0\x32\x27\x3f\x35\x9a\x0c\xfc\x72\x7e\x93\x16\x1a\x39\x36\xc7\xe2\xc3\x34\xf5\x5b\xdc\x1e\xa6\x5d\x76\x83\x08\xbb\x5c\xe2\xa8\x3c\x67\x16\x1f\x72\xf6\x26\xd4\xfd\x75\xed\x94\x8d\x8f\x38\x7c\x9d\x47\x5c\xc2\xcb\x2e\xa1\x60\x5b\xff\x0e\xf2\x02\x37\xe9\xad\x06\x6b\xba\xd8\xac\x76\x0f\x99\x65\xa4\x6d\x87\x12\x9e\xb5\x9f\xbe\xd7\xf7\x53\xc1\x5b\x7e\xc4\x76\xdd\x9c\xd7\xa3\xf7\x7c\x5e\x11\xf6\xe1\x3b\xd8\xc2\xcf\x1e\xbf\xe7\x33\x64\x65\xd8\x77\xb2\xc8\x37\xa7\xfe\xe4\x7d\x9f\xba\xe4\x4d\xe3\xbf\x84\xcd\x77\x9b\xf3\x5d\xe7\xd4\xfe\x23\x5d\xe7\x75\x1e\x39\xbe\x23\xad\xaf\xb3\x77\x69\x9f\x59\xbd\xaf\x74\xd9\x4a\x4f\xe0\x4d\xad\x8e\x49\x1c\x5c\xcb\xd5\xa9\xcd\xad\x04\x21\xf9\x6f\x7d\xb5\x69\x7a\x0f\xaf\x36\xd5\xd5\xbc\xa1\xe4\xd6\x3f\x12\x39\xd9\x0d\x08\x37\x73\x97\xdd\x80\x70\x2b\xee\xa2\xb4\xce\xfe\x6b\x39\x5c\xdd\x95\x93\x4a\x9e\x2d\xa6\x8e\x7b\x09\xac\x08\x98\xd0\x64\x69\xf6\x94\xf3\x98\xed\x46\x76\x4b\x47\x98\xba\xdb\x84\xd2\xae\x85\x72\xbb\x5a\x0e\x54\x47\xdf\xe0\x78\xea\xb7\x0c\x51\x32\xc8\xca\xa6\xfe\x3d\xc7\x66\x55\x4d\xac\xac\x5b\xde\x57\x35\x11\xba\x3c\x97\x40\x3a\x58\x90\x30\xd9\x51\x1f\xe1\x3a\xe9\xa6\x79\xa2\x38\x22\xc7\x9b\x98\x71\x57\x38\x2a\x1f\xcb\xc3\x34\x13\x25\x1a\x75\x6f\xaa\xdd\xe2\x04\x1a\x9b\x70\x6b\x7e\x3a\xcc\xe4\xb0\x40\x24\x08\x1e\x1e\x25\x86\x47\x49\x8e\x54\x27\xa3\xb4\xce\xb1\xab\x4b\xad\xdb\x53\x30\xa2\xfe\x2d\x38\xb8\xe6\x93\x5d\x44\x06\x60\xc7\x76\x7b\x7a\xeb\x57\xb5\x38\x4a\x3c\x31\x56\x24\xbd\x17\x21\x84\xc5\xe7\x87\xca\x82\xa9\xdf\x21\x94\x97\xf0\xb2\x1b\x91\x48\xde\xac\xc2\xdc\x72\x89\x4b\x0f\xe0\xb2\x5d\xa9\x12\xcd\x63\xf9\xde\x39\x41\xce\x29\xd4\x74\xc7\x18\x92\x3b\x25\x88\x44\x65\x1d\xa7\xbe\x87\xf3\x23\x8c\x8a\x0b\xe1\xc6\x98\x4d\x49\x9b\xef\xb6\x46\xc9\xeb\x02\x50\x6d\x5f\xb3\xa4\x20\xeb\xe1\x7b\x38\x2f\xcd\xeb\x03\x46\x57\x5f\x15\x9c\xdf\x4b\xef\x6f\x36\xe6\xe6\xac\x42\x58\x05\x30\x50\xdd\x76\xb3\xf9\x3a\x0f\xbf\x09\x1f\x69\xbf\x12\xef\xc7\xbb\x5f\xcb\xac\xe3\xdd\xaf\xcb\x79\xc7\x78\xa4\xf9\x2a\x71\x30\x56\x39\xd2\x7c\x45\x68\xc2\xc7\x06\xb3\x72\x02\x1c\x6f\xbe\x62\x36\x8e\x74\xa4\xf9\x2a\xb9\x01\xe7\xdb\x36\x9b\xdf\x10\x9a\x2f\xdb\xcd\x69\x45\x06\x77\xbf\x1c\x84\x03\xad\xef\x7c\x7c\x97\xde\x56\x34\xf4\x4e\xbd\xad\x49\x2c\xd2\x02\x67\x73\x73\x39\x56\x2b\xb3\x13\xea\x52\xbc\x46\x1f\x8f\xf5\xb8\xce\x3b\xce\x7b\x08\x13\xe9\xaa\x47\x91\x7d\x8f\x22\x47\x7b\x5c\x91\x46\xa4\x5e\xf2\xb8\xa2\x38\x77\x98\xa9\xc6\x81\x72\x70\x92\xf2\xae\x95\xc1\x67\xab\xa9\x3e\x7b\x2a\x6f\xb9\x8c\x8d\x03\xad\x48\xe9\x5a\xf7\x08\x19\x4a\x94\x99\x5a\x47\xf5\xd4\x64\xc0\xdd\x46\x5e\x62\xde\xf9\xe3\xdd\xaf\x48\x2f\x2e\xf7\x19\x21\xbf\x2d\x25\xed\x9e\xb3\xcc\x1c\x97\xcb\xc4\x79\xe9\x9e\x2b\xbd\xad\xfb\x95\x20\x2e\x31\xde\x76\x71\xce\x63\x68\xf7\xb0\x90\x2b\xdb\xb0\x24\xbe\xed\x42\x5a\xa9\xa8\x77\x5e\xf4\x95\x95\x56\x96\x94\x68\x2c\xba\x34\x74\xcf\x69\xa6\x16\x7b\xf7\x35\x2e\xdd\x4b\xb2\xa1\x48\xad\x57\x6d\x45\x66\xaa\x79\xab\xed\xf6\x50\x78\xc5\xaf\x79\x5f\x89\x5c\x8a\x2b\x22\x73\x0e\x63\x70\xb5\x3a\x44\xae\x23\x34\x65\xca\x23\x92\xae\x2d\x2b\xd5\xa7\x3c\x59\x55\x01\x52\x40\x91\xad\xd8\x76\x73\x48\xfd\x84\x31\x38\xd9\x2d\x5c\x1d\xa0\x25\x72\x49\x8d\x1b\xed\x6f\xdb\xf8\xe2\xc0\x37\xd4\xc4\xa8\x07\xd7\x08\x84\x99\x03\x2f\x17\xce\x2e\x79\x01\x39\xc4\x9b\x5f\x50\xe0\x9b\xdf\x1c\x19\xc0\xca\xfe\x3b\x2a\xc6\x65\xc5\xaa\x79\x9f\xeb\x11\xaa\x4b\x91\xde\xf5\xb6\x29\x0e\xb2\xe2\xd7\xfd\x37\x6a\xbd\xdf\x2a\xf5\x1c\xd2\x6a\xfe\x47\x55\xf0\x0d\x77\x61\x85\xda\x65\x55\x69\x2e\x56\x32\xd1\x1a\xf3\xac\x46\xb2\xc7\xc3\xf2\x87\x04\xeb\x26\xda\x05\x86\x0e\xa7\xb0\x27\x01\xa6\x46\x72\xf9\x98\x60\x39\x9a\xd1\x5c\xa7\x25\xcf\x54\x79\x0e\x09\x0c\x6d\xf4\x28\x0c\xb2\xdc\x5b\x68\xb7\x84\x13\x1c\x18\x96\x06\x6b\x77\x43\xf5\xbb\x14\x29\x48\x4f\xb9\xf0\x5c\x92\xca\x8f\x5d\x6c\xcb\x2d\x9e\xf6\x24\xf9\xf0\x4f\xb5\xdf\x22\x3c\x7a\x54\xda\xae\xae\xda\x7d\x57\xd1\x2e\x68\x34\x3f\x49\x50\xa3\x04\xf7\xe0\x11\x89\x53\x0b\x66\xd2\x8d\xc7\x95\xd8\x36\xcc\x62\xf9\xd0\x94\xf6\x0e\x00\x16\x05\x85\x76\xde\x77\xd4\xe1\xd9\x1d\x91\x07\x57\x28\x12\xea\x6f\x20\x2b\x03\x6b\xb6\xbd\x61\xb4\xe6\x66\xe2\xba\x5c\x99\x12\xc4\x91\x94\x38\x57\xde\x49\x8d\xb3\x55\xa1\x8f\x69\xf6\x51\x67\xd8\xe2\x8c\xff\x52\x4c\x97\xe7\x49\x8d\x46\x6a\x73\x52\x48\x4e\x79\x40\xb5\x6e\x69\x61\xa7\x8f\xec\xf4\x89\x28\xcc\x5e\xdf\xfb\x26\xb3\x44\x19\x7c\x76\xdc\xaf\xa4\x95\x98\x76\x3e\xa1\xac\x7e\x76\x92\xda\x52\xd9\x4d\x12\x9a\x6f\x4f\x20\x3d\xbb\x89\x84\x3a\xcb\x07\x4b\xf0\x08\xaa\xed\x03\x1c\x90\x01\xea\xfe\x88\xfb\xf3\xf1\x1a\xd2\x12\x73\x4f\xb5\x4b\xd9\x35\xc9\xb8\xbc\x8a\x72\x9b\x49\xca\x72\xb5\x21\x08\x28\xa3\xc2\xbf\x5d\x79\x11\x1f\xa6\x11\x77\xec\x65\x14\x52\x51\xda\xea\xd7\x8a\xe3\x76\x78\xc4\x20\x52\x18\x3d\x55\x17\x9d\xc7\x61\x8f\x32\xe1\xea\x0a\x27\xa3\xaf\x76\xf7\x14\x6e\xb3\xb0\x0b\x8d\x11\x55\xc1\xe1\x12\x92\xa2\x06\x59\xbf\x3a\x0b\x4f\x4d\xfa\x35\x2c\xf6\x90\xdb\xe5\x79\xcd\x59\x27\x9f\xf2\xe2\x7c\x4d\x70\x04\x1e\x11\x5e\xcf\x1e\xdf\x00\xcf\x6b\x2c\xff\x70\x53\x2f\x92\xae\xc6\x5a\x96\x2b\x43\xa8\xb2\x5d\xd9\xe8\xb8\xf2\x64\xb5\xe3\x29\x04\xbb\xb1\x00\x4e\x20\xb2\x62\x37\x62\xd7\x4d\x0e\x1e\x9e\xca\x1c\x1c\x8e\x31\xd8\xd5\x6b\xe2\x70\x0d\x04\x8b\x23\x15\x10\x54\xfa\x29\x76\x3b\x9b\xd3\x83\x5a\xfa\x23\x5c\x3a\xb2\x63\xda\x8f\x95\xd6\x63\x2d\xe1\xf2\x9c\x62\x0b\x57\xf9\x6a\xf5\x2a\x5f\xed\x48\xf8\xe5\xf1\xda\x2c\xa2\xb6\x38\x19\xff\x91\xf6\x29\xcb\xfd\x8c\xd5\xfd\x0d\x06\x4b\xa9\xc8\x51\x86\xda\xfd\xf9\xe2\xd5\x0b\xf7\x2d\x99\x58\x52\x21\xf2\x2d\x7f\xf8\xe0\x2f\x0f\xdc\x9f\x3f\x7c\xe0\x89\x6e\x6a\x54\x4e\x69\x54\x7b\xa3\xbd\x03\x47\x9b\x2e\x86\xe7\x66\x53\x94\x0a\x79\x7b\xcb\x2f\x4f\x69\xf4\x85\x35\x92\x72\xac\xd1\xe7\xbd\xa7\x70\xbd\xd1\x47\x87\x73\x14\xd9\x78\x3d\xe1\x35\xad\x3e\xf1\xd1\x7e\x46\xf2\xcc\x66\x54\x57\x5f\xf8\xc5\xbe\x4d\xe9\xb3\x5e\xf7\xd3\xdb\xfc\x37\x7b\xbd\x9a\xee\x55\x17\xdc\xac\x0b\xce\xd7\xdb\xfc\x72\xdf\x06\x1e\xaa\x1b\x67\xf3\xf1\xe1\x64\xd7\xab\xda\x5f\x3f\xb3\x51\xd4\xeb\xaf\xff\xf3\xd5\x28\x0c\xc9\x6a\x27\x65\xf5\x91\xc3\x66\xb0\x0b\x4e\x68\xf6\xe8\x84\x66\xe6\x52\xd6\x56\x2b\x42\xbc\x6a\xf4\xac\x6f\x03\xc7\x23\x6d\x9e\x9e\xd0\xe6\xc9\x4f\x37\x16\xe9\xa0\xcd\xe3\x13\xda\x3c\x3a\xa1\x4d\x3b\xa1\x4d\x3e\x61\xee\xe9\x84\x36\xf1\x84\x36\xa7\xac\x33\xbf\xbd\xcd\xc5\xe3\x13\xda\x3c\x3a\xa1\x4d\x3b\xa1\x4d\x3d\xa1\x4d\x39\xa1\x4d\x5f\x43\x39\x42\x1b\x17\xf1\x84\x36\x72\x42\x1b\x3e\xa1\x0d\x9d\xd0\x26\xbc\xbd\xcd\x93\x3e\xaf\xd4\x8e\xb4\x89\x27\xb4\x91\x13\xda\xf0\x09\x6d\xe8\x84\x36\xe1\x2d\x6d\xfe\x7a\x9c\x8d\xe7\xe3\xaf\xbf\x3d\xce\x74\xaf\x36\xe4\x6c\x7f\x3d\x1e\x27\xa5\x97\xc7\x5f\x7f\x75\xfc\xf5\xc5\xf1\xd7\x4f\x8f\xbf\x7e\x72\xfc\xf5\xa3\xe3\xc4\xf2\xd9\x96\xa6\xec\xef\x3f\x7a\xeb\xbe\xc9\x29\xd2\x9c\x4f\xd2\x0c\x4f\x36\x1b\xfd\xf6\x50\x95\xe5\xd5\xeb\x4f\x0e\x5f\xa7\xd5\x1e\x7f\x7a\x82\xb2\xfc\xdd\xaa\x0d\xb7\xad\x46\x53\x87\x48\xab\x45\xfd\xfd\x1a\x1d\x49\xda\x6e\xb4\xe0\xa2\xcd\x36\x5f\x1e\x7f\x6d\x58\x68\xbd\x77\xbf\x3f\x44\x41\xbc\xd2\xec\xbf\x3f\xdc\xfa\xf5\x4a\xfc\xeb\x7a\x12\x71\xd5\xc7\xbf\xae\x26\xb1\xd9\xe6\xcb\xe3\xaf\x6d\x94\xb4\xa2\xb0\x7f\x3d\x1c\x65\x5a\xcd\xf1\xb3\x2b\xe5\xd4\x07\xd9\x56\xcb\x74\xd5\xe6\xa2\xef\x69\x5d\x6d\xd9\x67\xab\x7d\xa7\xba\x1a\xea\x55\xa3\xc7\x5d\xcb\x51\x5c\xa1\xba\xab\x46\x8f\x96\x46\x69\xc5\x95\x9f\x1d\x52\xea\x66\x1f\x26\x8d\xf2\x6a\x42\x9f\xaf\xc0\xa5\x5f\x2f\xdc\xe7\x87\x7d\xc8\x6a\xe1\x3e\x3f\x04\x9f\x7e\x0d\x4e\x3f\x5f\xa1\xcf\x1b\xa4\xc3\x17\x37\x0c\x64\xb5\xb4\x5f\xbc\x21\x5a\x57\x4b\xf1\xc5\x9b\x03\x59\x71\xed\x17\xeb\x81\xd0\x6a\x45\xbe\x3c\x44\xa9\x5d\x13\xc5\x23\xad\x16\x62\xc9\xab\xd1\x7e\xb9\x22\x96\xb5\x9c\xf9\x72\x45\x2c\x6d\xa5\x31\xbe\x5c\xd1\xca\x9a\x0a\xbe\x5c\x91\x4a\x5d\x4d\xff\xcb\x53\xf6\xfa\xcb\x43\x81\xb4\x56\x6e\x5f\x1e\xee\x40\x5c\xed\xe2\x97\x87\x16\xc0\xe6\xaf\x97\x0d\x5a\x71\xc5\xc1\xda\x77\x1d\x10\xb7\x06\x78\x9c\x9a\x0e\x1a\x2d\xf2\x79\xd5\xe6\x4f\x6f\x18\x33\x2b\xaa\xfd\xaf\x57\xf2\xe8\xc9\x4f\x37\x2c\x9a\x83\x36\x8f\x4f\x68\xf3\xe8\x84\x36\xed\x2d\x6d\xfe\x70\xfc\xf5\x6f\x36\x5e\x3f\x3b\xb4\x96\xf6\xbb\xbf\x22\xb5\x37\x9a\x3d\x39\xad\x59\x3b\xad\x59\x3d\xa1\xd9\x95\x89\xb6\x62\xa6\x67\x6b\xb3\xe0\x58\x9b\x47\x27\xb4\x69\x27\xb4\xa9\x27\xb4\x29\x6f\x6f\x73\x84\xe1\x9e\xbd\x81\x07\xb7\xfa\xf8\xea\xf8\xeb\x8b\xe3\xaf\x9f\x1e\x7f\xfd\xe4\xf8\xeb\x4d\x76\x7d\x76\x0a\x2b\x1e\x34\x2a\xa7\x50\x0a\x6f\x36\xfa\xf3\x0d\x74\xb2\xfa\xdc\x9f\xd7\x74\x72\xac\xcd\xa3\x13\xda\xb4\x13\xda\xd4\x13\xda\x94\xb7\xb4\x19\x8f\xbf\xfe\xea\xf8\xeb\x8b\xe3\xaf\x9f\x1e\x7f\xfd\x64\xe3\xf5\xab\x43\x21\x79\x83\x6e\x7f\xf5\x26\x7e\xdd\x7a\xff\x6c\x4b\xdb\xce\x6f\xbe\x5f\xe9\xc7\xbf\x1c\x6a\xe3\x05\x4e\xad\x29\xf5\xb0\xd9\xe2\x33\x7a\x5b\xb3\x47\x27\x34\x93\x53\x1a\xf1\x49\x1f\x7c\xb2\xd9\xe8\xaf\x6f\x59\x03\x95\x1f\x8f\x7f\xba\x52\x47\xeb\xcd\xba\xde\x70\x93\x01\xae\x37\xdc\xe4\x82\xeb\x0d\x37\x59\xe1\xb0\xe1\x1f\x4e\x68\xf3\x9b\xed\x36\x30\xdb\xbf\x3d\xe2\x53\x3d\x6c\xb3\xe5\x58\x3d\x6c\x73\xd4\xbb\xba\xf8\x12\xde\xf6\x41\x3a\xe1\x83\x74\xea\x07\xf9\x84\x0f\xf2\x09\x1f\xe4\x53\x3f\x28\x27\x7c\x50\x4e\xf8\xa0\x9c\xfa\xc1\x78\xc2\x07\xe3\x09\x1f\x8c\xa7\x7e\x30\x9d\xf0\xc1\x74\xc2\x07\xd3\xa9\x1f\x2c\x3f\x5d\x69\xf7\x9b\x7b\x5c\x1a\x6e\x39\xe7\xaf\x75\xb6\xed\xa1\x5f\xae\x7b\xfc\xf6\x88\x0b\xfe\xb0\xcd\x96\x1f\x7e\xb9\xa3\xf1\x6d\xfd\xb4\x13\xfa\x79\x74\x42\x3f\x8f\x4e\xe8\xe7\xf1\x09\xfd\x3c\x7e\x7b\x3f\x4f\x0f\x78\x7e\xdb\x33\xb3\xdc\x46\x76\x52\x43\x39\xb5\x61\x3c\xb5\x61\x3a\xb5\x61\x3e\xb5\xe1\xd3\x9f\x9e\x64\xb4\x5e\x6b\xba\x6d\xb9\x5e\x6b\xb8\x6d\xbe\x5e\x6b\xb8\x6d\xc3\x5e\x6b\xb8\x6d\xc8\x5e\x6b\xb8\x6d\xcd\x5e\x6b\x78\x04\x61\x1f\xb6\xdc\xb2\x6b\x0f\xdb\x6c\x19\xb7\x87\x6d\xb6\x2c\xdc\xc3\x36\x9b\xb8\xf9\xfa\x96\x6d\xda\xba\xd7\x1b\x6e\xa3\xec\xeb\x2d\x37\xad\xde\x25\x7e\xf5\x36\xc4\x81\x40\xd8\xdb\x1a\x99\x3b\xef\x34\xca\x7b\xa3\xed\x51\xd2\x7b\xa3\xe5\x51\xda\x7b\xa3\xe5\x51\xe2\x7b\xa3\xe5\x51\xea\x7b\xa3\xe5\x51\xf2\x7b\xa3\xe5\x71\xfa\xbb\x6a\x7a\x84\x00\xaf\x1a\x1d\xa1\xc0\xab\x46\x47\x48\xf0\xaa\xd1\x31\x1a\x7c\x73\xf7\x8e\x11\xe1\x9b\x2d\x8f\x52\xe1\x9b\x4d\x8f\x91\x61\xf7\x09\x7c\xfb\xb6\x0c\x01\xf3\x30\x9c\xd0\xec\xc9\x69\xcd\x9e\x1e\x6b\xf6\x15\x7d\xf8\xe0\xc9\xcb\xaf\xbf\x7e\x74\xf6\xcd\xc5\xab\xe7\x2f\x9f\x9e\x3d\x79\x39\xbc\x7c\x71\x36\x7e\xfb\x72\xba\x78\xfd\xfc\xc5\x57\xc3\xe3\x47\xaf\x2f\xec\x9f\x4f\x1f\xdb\x3f\x2e\x86\xe1\xf9\x37\xaf\x9f\xbf\x7e\xe0\xfe\xc3\x57\x6a\xc5\xf5\x77\x07\xbf\xe9\x3f\x18\x2e\x9e\x4d\xf6\xf4\xea\xf9\x57\xbb\x69\xdf\xcb\xd5\xdf\x9f\x3e\x1e\xf0\xea\x81\xfb\x0f\xf0\xb3\xf3\xf5\xa1\xfd\x73\xff\xc8\x67\xbd\x45\xd9\x6a\xf0\x79\x6f\x10\xb7\x1a\x7c\x79\xf6\xe5\xa3\x27\xdf\x4e\x17\x67\x5f\x3e\x7d\x7e\xf1\xea\xc2\xc6\xaf\x3c\x91\xae\xff\xe2\x17\x67\xbf\x78\x72\xf1\xf4\xf9\x30\x3c\xba\xf6\xf1\x76\xbd\xe5\x2f\xcf\x3e\x3d\xfb\x78\xda\x9d\x7d\xfa\xd5\xab\x47\xf3\xc5\xd9\xa7\xf6\x81\x4f\x9f\x3c\x7f\xf5\xe4\xdb\xaf\x9f\x0d\x17\xdf\x9d\x7d\x3a\x3d\x1f\x9e\x5e\x9c\x7d\x7a\xf0\x4d\xed\xf1\xa3\xb3\x8f\xec\x27\x1f\xd9\x4f\x3e\x3a\xf8\xc9\x47\xf6\x93\x8f\x96\x9f\x9c\x7d\xf4\xea\xf9\x8b\xaf\xfa\x10\x56\x7b\x77\xe7\x21\x6c\xae\xe8\x9d\x7b\x5c\xb6\x60\xb5\x89\x77\xee\x71\x6b\xcf\xa2\xdc\xdb\x27\xee\x4e\xfb\xc0\xb6\xf7\xb7\x1f\x7f\xbc\xf7\xd5\xfb\x53\xef\x71\xb5\x58\x1f\x9f\x7d\x6c\x7d\x7d\x6c\x7d\x7d\x7c\xd0\xd7\xc7\xd7\xd7\xe7\xec\xe9\xd9\xc5\xd9\x57\x67\xe3\xd9\x93\xce\x14\x67\x17\xf6\xe3\x0b\xfb\xf1\xc5\xc1\x8f\x2f\xf6\x34\xfb\xf2\xa2\xaf\xd0\x8a\x67\x6e\xf3\xf1\x97\x67\x2f\xad\xed\x4b\x6b\xfb\xf2\xa0\xed\x4b\x9b\xf4\xcb\x37\x29\xe3\xdd\xbe\xd7\x79\xe2\x9a\xa0\xbf\x6d\x2f\xdf\x9e\x7d\x6b\x6d\xbf\xb5\xb6\xdf\x1e\xb4\xfd\xf6\xda\x70\x57\xdc\x77\x9b\x0f\xcd\x67\x7f\x3d\xfb\xab\x35\xfb\xeb\x9b\xfd\xbe\x69\x4b\x69\xbf\xff\xe5\xec\xd7\x67\xe7\x67\xff\x72\xf6\x6b\xeb\xfd\xd7\xf6\xb3\x5f\x1f\xf4\xfe\xeb\xfd\xe6\xfd\x0b\x96\xf6\x1d\x45\xd5\x35\x15\xfc\x4e\x63\xd8\x14\xc0\x77\xee\x71\x4b\xb2\xf0\xfd\x0d\xfa\x8f\xcb\x3a\xac\xf6\xf8\x37\x67\x7f\x38\xfb\x83\x75\xf7\x07\xeb\xee\x0f\x07\xdd\xfd\xe1\xbe\x74\xc5\x4a\x92\xfc\xf6\x7e\x78\x7a\x4d\x5c\xbf\xbd\x33\xbf\xae\xd5\xcf\x6f\x6f\xcf\x45\x6b\x09\xf7\xdb\xb7\x72\x48\x5c\xb1\xf8\xf2\x9b\xdd\x5f\xbf\xd9\x5d\xbc\x38\xfb\xf6\xc5\xf3\x10\x3e\xfa\xe5\xd9\xc5\x8b\xa7\x8f\x5e\xef\xce\x2e\xbe\xd6\xff\x74\xae\xcd\x9b\x4b\xfb\x8b\xb3\x5f\x9d\x7d\x7a\xf6\xfb\x3d\x82\xb8\x85\xd4\x3e\xfb\xf4\xf5\xa0\x5f\xfa\xf4\x63\xfb\x8a\xac\x74\xcb\x27\xf7\x8f\xb8\xd6\xe8\xe7\x93\x77\xe6\xfb\x15\x97\x7e\x72\x8d\x8d\xc3\x8a\x80\x3e\xb9\x06\x21\xc2\xe6\xb0\x36\x19\xb7\xac\x38\xf7\x93\x3b\xc8\xe3\x15\x7c\xfc\xe4\xad\x94\x44\x6b\xf2\xfb\xe4\xfe\xa9\x81\x37\x57\xe4\x54\x59\x72\x23\x3a\x5e\x3a\xf9\xc2\x1a\xb4\xd5\x54\x7e\xf7\x8e\xe4\x40\x65\xc5\xe1\x4b\x97\x8f\xce\x1e\x59\x97\x8f\xac\xcb\x47\x07\x5d\x3e\xb2\x2e\x1f\xed\xbb\x7c\x74\xd0\xe5\x8a\x31\x7e\x77\x4f\x60\x65\x73\xf6\x77\x00\x22\x9b\x7d\xbd\x13\xe2\x8c\x61\x25\x7a\x7e\xf7\xa6\xbe\x49\x2b\xc1\xf6\xbb\x37\xf1\xa0\xac\x28\xe9\x77\x6f\xa5\xf1\x6b\x81\xac\xaf\x2c\xcf\xe6\xdd\x08\x23\xac\x18\xf6\xb3\x77\x24\x8c\xba\x5a\xf3\xcf\xee\x87\x30\xea\x4a\xa4\x2d\x1d\x7f\x7d\xf6\xe2\xec\x9b\xb3\x17\x8b\xde\x3f\xda\xf6\xf6\x44\x54\x36\xfb\x5a\x1a\xac\x24\xe9\x67\xd7\xa0\x2c\x6d\xb6\xf8\xfc\xad\x2d\xb6\x64\xed\x91\x9f\xbc\x13\x71\x73\x5a\xc9\x8a\xcf\x6e\x2f\xc3\xf3\x26\xa9\x6e\xd3\x77\x5d\x89\x94\xcf\x4e\x46\x03\x5c\x36\x7f\x7c\x9f\xf2\x7f\x93\x5b\xbe\x78\x2b\x8b\xfe\xdb\x02\x5b\xb6\x1a\x7c\xd7\xa9\x69\x73\xf9\x2f\xfb\xd2\xae\x64\xcb\xe7\xef\x28\x05\xca\x6a\xd0\x9f\xbf\xa3\x10\x88\xab\x59\x7e\x7e\x3f\x42\x20\xae\x94\xe7\xe7\x77\x66\xec\x23\x83\x7c\x27\x06\x5a\xd3\xc0\xe7\x77\x80\xd3\x2b\x52\xfb\xfc\xed\x20\x68\xc5\x03\x9f\x9f\x0e\xa7\xd3\xe6\xca\xde\x23\x03\xad\x15\xf2\x17\xef\x48\xbb\x6b\x2f\xd4\x17\xef\x48\xbb\xb2\xd9\xe3\x3b\xd2\xee\xda\x96\xf8\xe2\xce\xb4\xbb\xdd\xd7\x5e\xe7\xac\xf6\xf3\x8b\x7b\xf1\xb6\xc5\x15\xf6\xf9\xe2\x0e\x10\x7f\xa5\x53\xbf\x38\x99\x52\xd7\xf2\xef\x8f\xdf\x97\x49\xfd\xc7\xbb\x9b\xd4\xab\xfd\xf9\xe3\x75\x8d\xbf\xda\x9f\x3f\xde\x41\x4a\x6c\x7e\x66\x5b\x4a\xac\x49\xe7\x8f\xb7\x90\x12\x2b\xe6\xf8\xe3\xdf\xc2\xcc\xba\x11\x04\xbd\x13\xf0\x8d\x2b\xf9\xba\xf9\x8d\xbb\x0a\x92\xbc\x5a\xab\xcd\x4f\xbc\x23\xe5\xae\xd1\xd6\xe6\x97\xd6\x58\x79\xed\x84\xd9\xfc\xf1\xed\xf9\xe0\x16\x23\x5b\x42\x41\xa7\x6f\xcc\x67\x9b\xce\xbd\xcd\x9f\x7c\xbe\xe9\x17\xdd\xfc\xc9\x36\x00\x3f\xbd\x8f\x77\x03\x14\x72\xfa\x0e\xed\xfd\x9d\xa7\xd3\xde\x2d\xc4\x8d\xac\xc4\xf6\x66\xaf\x47\xdc\xe2\xa7\xcf\xe6\x14\x81\x74\x7a\x6f\xf7\x29\xa1\x4e\x5f\x88\x5b\x78\x86\xda\x4a\x01\x6d\xf6\xfa\xc5\xed\x49\x7f\xd3\x00\xd9\xfc\xc5\x77\x5b\x9e\xdd\xcd\x5f\x74\x13\xe5\x16\x04\xfb\x9b\xad\xa9\xff\xe9\x9d\x5d\xa0\xab\x61\xff\xe9\x9e\x70\xc2\x4a\x81\xfe\xe9\x1e\x71\xc2\x9f\xee\x03\x4d\xfd\xe9\xed\x5c\xb8\x22\x9c\x3f\x7d\x0f\x6c\xb2\xda\xd5\x3b\xe9\xd2\xfb\x75\xb7\xaf\x59\xe6\xce\x83\x3a\x62\x8a\xad\xf4\xde\xe3\xb3\x6f\xce\xa6\xdd\xcb\x57\x2f\xee\x3f\x7e\xb0\xda\xfe\xeb\xdf\xba\x8d\xc9\x78\xfd\xb7\xdf\x9d\x3a\xa1\xcb\xad\x86\x4f\xf6\x6c\x76\xff\x7b\xb9\x1a\xfe\xc5\x29\xac\x7c\xff\xe3\x58\x81\xf9\xdb\x8c\xe3\xc8\xf6\xac\x64\xd8\xee\x4c\x11\xdc\x8b\xc3\x18\xe7\x3d\x4e\x63\xc5\xaf\xb7\x94\x68\xf7\x4c\xd8\x2b\x35\x72\x87\xe1\xdc\x86\x47\xef\xd0\xfd\x77\x5b\x72\xfc\x0e\x7d\x5d\x6e\xed\xc2\xab\x7b\x5f\xda\x1b\xbc\xc7\xaf\xbe\xaf\x64\x93\x57\x77\xd7\x8e\x2b\x02\x78\x75\x2f\x3e\x8c\xb2\xf2\x61\xbc\x3a\x21\xfa\xb2\x82\xfb\x1b\x8d\xef\x7b\xa7\x56\x64\x7a\xe4\xbb\x77\x0e\xe7\xdd\xe6\x23\xf7\x1e\xe1\x3b\xf2\xad\x3b\x04\xfd\x6e\x35\x95\x77\xa2\xa3\xb5\x75\xfb\xdd\x3d\x41\xcc\x15\xe1\x7f\x77\x77\x57\xe1\x8a\x21\x2f\xef\x69\x1f\x57\x22\xe4\xf2\xee\x9b\xd6\xfb\xfa\xe0\xd9\xcb\x17\x93\xfe\xf7\xe9\xc5\xb3\xd7\x3f\xff\xd9\x07\xaf\xe7\xaf\x7e\xee\xfe\xff\x00\x00\x00\xff\xff\x6d\x13\x60\x05\xe2\x1d\x01\x00") func fontsRobotoRegularWebfontSvgBytes() ([]byte, error) { return bindataRead( _fontsRobotoRegularWebfontSvg, "fonts/roboto-regular-webfont.svg", ) } func fontsRobotoRegularWebfontSvg() (*asset, error) { bytes, err := fontsRobotoRegularWebfontSvgBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "fonts/roboto-regular-webfont.svg", size: 73186, mode: os.FileMode(509), modTime: time.Unix(1492020681, 0)} a := &asset{bytes: bytes, info: info} return a, nil } var _fontsRobotoRegularWebfontTtf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xb4\x7c\x07\x7c\x14\xd5\xf6\xff\xb9\xd3\xb6\x97\xd9\x9a\x9e\xdd\x6c\x1a\xd9\x24\x1b\x76\x13\xc2\xd2\xa5\x17\xc1\x48\x91\x00\x8a\xf4\x0e\x02\x2a\x45\xa5\x08\x28\x45\x8a\x52\x04\x89\x80\x28\xa8\x20\xe8\x9d\x4d\x78\x2a\x82\xa0\xb2\x08\x28\x3c\xf5\x3d\x63\x41\x11\xeb\x63\x09\x36\xfc\x3d\x7d\x94\xcc\xfc\x3f\xf7\xce\x6e\x0a\x82\xfa\xde\xe7\xf3\x27\xec\xee\xec\xcc\xec\xcc\x3d\xe5\x9e\xf3\x3d\xe7\x9e\x33\x80\x00\xc0\x8e\x00\x38\x28\xe9\xde\x7d\x60\xdf\x09\xdc\x6f\xef\x01\xa0\x76\x00\x90\xd6\xa3\x6b\xb7\xee\xcc\x45\xf4\x01\x00\xaa\x04\x80\xc2\x1e\x15\xb7\x0c\x78\xb5\xc3\xe2\x4e\x00\x68\x09\x80\x79\x78\x8f\x01\x83\x3a\xe7\xbe\xe5\xf9\x10\xc0\xf2\x0d\x00\x8c\xb8\x65\x40\x20\xf8\xf2\xaf\x57\x57\x02\x58\xbb\x92\xef\xa3\xa7\x8e\x9c\xfe\xed\xbb\x9d\x0b\x00\xac\x3b\x00\xd0\x57\xa3\x67\xdd\xe3\x31\xbd\x22\x96\x00\xd8\x96\x01\x40\xeb\x71\xd3\xc7\x4f\x1d\x50\x13\x78\x0e\xc0\x76\x18\x80\x19\x3b\x7e\xe4\xdd\xd3\x01\xc0\x0a\xe0\xcc\x07\x00\xed\xf8\x29\x73\xc7\x3d\x36\x6f\x36\x0f\xe0\x2c\x01\x58\xe3\x99\x30\x76\xe4\x18\x3e\xbc\xa4\x14\x60\x47\x05\x00\xb4\x9a\x30\x61\xec\x48\xcb\x83\x42\x57\x80\x1d\xe4\x7a\xd9\x13\xa6\xde\x33\xe7\xd8\x03\xfd\xbf\x06\xd8\xb1\x07\x80\x7d\x7e\xca\x5d\xa3\x47\x4e\xfd\xb4\xcf\xeb\x00\xcf\x0f\x04\x40\xb5\x53\x47\xce\x99\xce\x68\xd0\x76\x80\xdd\x85\x00\xe0\x99\x36\x72\xea\xd8\x3e\xdd\xef\xdf\x03\xb0\xfb\x66\x00\xb6\xdf\xf4\xbb\xee\xbe\x27\xe5\x81\xe0\xb3\x00\x7b\x9f\x04\x60\xbe\x9d\x3e\x73\xec\xf4\x2f\x5b\x56\x66\x03\xe0\x25\x00\xc8\x3e\x7b\xec\xa8\x71\x17\x6e\x19\x30\x04\x40\xda\x04\x00\x02\x00\xe5\x1e\xbc\xdb\xfe\xe9\xbf\xd3\xcf\x1e\xaf\x84\xc8\xe7\xdf\x17\x3c\x79\x92\x1e\x31\x93\x51\x91\x3d\xc0\x00\x0b\x08\xbe\x05\x04\xdf\xc1\x77\xc0\xc0\xbf\x20\x06\x08\x38\x7a\x44\xbd\x8a\x1e\x4a\xa0\x03\x30\x5d\xbb\xdf\x3c\x10\xcc\x53\x46\xde\x33\x0d\x52\xe8\x71\x50\x14\x7a\xbc\xe9\x36\x9a\x3c\x76\xe6\x34\xd0\xc6\x7f\x49\xae\xc3\xd0\x2b\xe9\xd9\x27\x01\xb1\xb9\xf4\xdc\x52\x98\x09\x33\x61\x0e\xac\x86\x27\x61\x37\x60\xd8\x8f\x1e\x40\x8b\x60\x37\x5a\x86\xd6\xa2\x3d\xe8\x4d\x74\x16\x5d\x64\x38\xa6\x03\xd3\x95\x19\xce\x60\xe6\x0c\x73\x81\xb9\xc8\x5c\x60\x8d\xb0\xba\xc9\xdf\x93\x80\xe3\x7f\xbb\x1b\xff\x18\x8e\xb9\xc0\x5c\x60\x38\x7a\x7d\xf2\x87\x60\x28\x18\x80\x87\x30\x38\xa0\x0d\xe4\x40\x3b\x70\xc1\x36\x70\xc1\x11\x70\x01\x0b\x59\x0a\x86\xc1\xca\x8f\x30\x54\xf9\x02\x58\x30\x2a\xdf\x41\x27\xe5\xff\x60\x84\xf2\x23\x20\x58\xa6\x7c\x01\x0c\xf4\x52\x7e\x80\xa1\xca\x79\x28\x01\x8b\xfc\x23\x88\xf2\x8f\x90\x2e\xff\x08\xd9\x4a\x14\xca\xc1\x01\x5d\x95\x33\xd0\x5d\xa9\x83\x1e\x4a\x1d\xf4\x54\xea\xa0\xb7\x52\x07\xfd\x95\x3a\x18\xa8\xd4\xc1\x20\xe5\x3b\xa8\x54\xce\xc3\x10\xe5\x1c\xdc\xae\x9c\x83\x45\x4a\x14\x16\x2b\x51\x58\xa2\x44\xe1\x21\x25\x0a\x0f\x2b\x51\x58\xaa\x44\xe1\x69\xe5\x0c\x3c\xa3\x9c\x81\x1d\xca\x19\xd8\xa9\x9c\x81\x67\x95\x33\xf0\x9c\x72\x06\x76\x29\x75\xb0\x5b\xa9\x83\x17\x94\x3a\xd8\xa3\xd4\xc1\x5e\xa5\x0e\x6a\x94\x3a\xd8\xa7\xd4\xc1\xdf\x94\x3a\x78\x59\xa9\x83\x57\x94\x3a\x78\x4d\x39\x0f\x07\x94\xf3\x70\x50\x39\x0f\xaf\x2b\xe7\xe1\x90\x72\x0e\xde\x50\xce\xc1\x5b\x4a\x1d\x7c\x22\xff\x08\x9f\xc9\x3f\xc2\x19\x99\x50\x34\x54\x79\x83\xbe\xbf\x0b\x0c\x0c\x06\x33\x2c\x93\x4f\x83\x00\xe5\xca\x17\x10\x56\xbe\x81\x36\xca\x05\x68\xa7\x7c\x0e\xdb\x94\xcf\xe1\x88\xf2\x39\xf0\x50\xae\x9c\x82\xb0\xf2\x3d\xb4\x53\xde\x83\x6d\xca\x7b\x70\x44\x79\x0f\x34\x30\x48\x39\x04\x43\x95\xf7\x61\xaa\x32\x11\xe6\x29\x53\x61\x99\xd2\x15\x9e\x57\xf6\xc0\x7e\x65\x3b\x70\x60\x04\x07\x74\x02\x11\x06\x29\x5f\xc1\x08\xb0\xd3\x3d\x16\xe8\x04\x46\x18\xa4\xd4\xc1\x08\x30\x83\x19\x74\xca\x57\xf4\x3c\x93\xf2\x77\xe8\x04\x36\xe8\xa5\x9c\x87\x41\xca\xc7\x30\x58\x39\x4f\x7f\x33\x55\x79\x11\xe6\x29\x27\x61\x99\xf2\x14\x3c\xaf\xbc\x01\xfb\x95\xc3\xf0\xb9\xf2\x0f\x3a\xf6\x6f\x41\x80\x22\xe5\x07\x68\xad\xfc\x00\x55\xca\x0f\xf0\xa4\xf2\x03\x6c\x51\x7e\x80\xad\xca\x0f\xe0\x00\x1e\xac\xa0\x07\x6b\x7c\x14\x36\xe8\xae\x9c\x83\x1e\xca\x39\xe8\xa9\x9c\x83\xde\xca\x39\x18\xa8\x9c\xa3\x77\xd8\xa5\x9c\x83\xdd\xca\x39\x78\x41\x39\x07\x7b\x94\x73\xb0\x97\xf2\xeb\x1c\x7c\x04\x56\xf8\x18\xac\xf0\x29\x58\xe1\x34\x58\xc1\x00\xdd\x95\x0b\xd0\x43\xb9\x00\x3d\x95\x0b\xd0\x5b\xb9\x00\x03\x95\x0b\xb0\x4b\xb9\x00\xbb\x95\x0b\xf0\x82\x72\x01\xf6\x28\x17\x60\xaf\x72\x01\xde\x52\x2e\x00\x0b\xbd\xc0\x02\x83\x41\x84\xa1\x20\x02\x82\x5e\x60\x02\x01\x2c\xca\x12\x10\x95\x25\x90\xae\x2c\x81\x4f\x94\x25\xf0\x99\xb2\x04\xce\x28\x4b\x28\x1d\x17\xa0\xb5\x72\x01\xaa\x94\x0b\xf0\xa4\x72\x01\xb6\x28\x17\x60\xab\x72\x01\x10\x94\x02\x0f\x7a\x30\x40\x36\xe4\x42\x1e\xe4\x43\x0b\x28\x86\x00\x04\x21\x04\xa5\x50\x06\xe5\x10\x86\x36\xd0\x0e\xda\x43\x07\xe8\x05\xfd\x60\x10\x0c\x81\xa1\x70\x3b\x0c\x87\x45\xb0\x18\x96\xc0\x43\xf0\x30\x2c\x85\xe5\xb0\x02\x1e\x81\x95\xb0\x0a\xd6\xc2\x7a\xd8\x00\x8f\xc3\x46\xd8\x04\xdb\xe0\x10\xbc\x01\x47\xe0\x23\xf8\x18\x3e\x85\xd3\xc0\xe8\x2e\x90\x19\xa9\xa9\xd0\x6e\x02\x0f\xa4\x03\x28\x9f\x2a\xcb\x94\x53\x4a\x54\xb9\xa0\x3c\xab\xec\x84\xff\xe2\x9f\xfc\xdd\x7f\x73\xf6\x8d\xff\x29\xdf\x2a\xe7\x94\xe3\xca\x2f\xff\xc3\x2f\xbf\xfe\xaf\xce\xae\x6b\x76\xcf\xf3\xca\x87\x00\xca\x52\xe5\xbc\x12\x53\xbe\xfc\x0b\xbf\xfe\x5e\x7d\x81\xe3\x9a\xfd\x3f\x2a\x7f\xc4\x07\x5b\xf3\xd1\x2a\xdf\xd0\x4d\x31\xfe\x22\xdf\x45\xe5\xdb\xeb\xde\xef\xfc\x9f\x8f\xe9\x0f\x46\xfb\x1d\xa1\xf1\x3a\xfb\x63\xca\xc7\xf4\xf3\x19\x65\xf8\xb5\x54\x2b\x08\xec\x4d\xbe\x05\x95\x90\xdc\x64\x0c\xca\x45\xe5\xa1\x86\xed\x7f\x29\xe7\x94\x67\x9a\xfd\xf6\x16\xe5\xdf\x44\x82\x4d\xa5\x28\x4f\x53\x4e\x29\x9f\x2b\x33\x00\xc0\x02\xa0\x3c\x7f\x83\x91\xae\x57\xf6\x2a\xcf\x29\xcf\x29\x92\x52\x03\x56\xfa\x07\xb2\x42\x8f\xbc\xa3\x1c\x52\x5e\x02\x50\xe6\x2b\x0f\xc8\x3f\x53\xce\x59\x94\x9f\x94\x6a\xe5\x48\xfc\x97\xfb\x94\x0f\x94\x7f\x02\x28\x1f\x34\xb9\x5a\x8b\xf8\xe7\x37\xca\xbf\xe3\x5b\xe3\x7e\xaf\x59\xca\x87\xca\x17\x84\x7a\xca\x01\x73\x7c\xdf\xcc\xf8\xe7\xf7\x0d\x67\x1d\xb9\xc1\x88\xbf\x6b\xd0\x25\x73\x93\xdd\xa2\x52\x47\xaf\x27\x2a\xef\x2b\xe3\x95\x7f\xfd\xee\x57\x53\x94\x37\x94\x43\xca\xc7\xca\x21\xe5\x28\x88\x60\x23\x9a\xa1\xa4\x80\x89\x1e\xfb\x44\xb9\x10\x3f\x6b\x92\xf2\xb5\xf2\x14\x88\xca\x4f\x4a\x4c\xf9\x4a\x79\x8a\xee\x34\xa9\xf7\x6b\xaa\xbf\x0d\x57\xfd\xbe\x51\xca\xd7\xea\xa1\xf2\xe3\xf5\xc7\xdf\x70\xfc\xe7\x1b\x1e\xf9\x93\x79\x45\x78\xab\x5c\x6c\x7e\x2d\xf5\x6a\x09\xae\xff\xf7\xff\x9a\x5f\xef\x3a\xc7\x6f\x68\x1f\x94\x9f\xfe\xe7\x7b\x5e\xf8\x93\xe3\x3f\x5f\x7b\x75\xa5\x2e\xfe\xdd\x0a\x09\x9b\xd0\xe4\x1a\xca\xc0\x86\x4d\xdb\x0d\x2f\x6a\xa1\xdc\xfa\xa5\x39\xff\x95\x61\xcd\xee\xf2\xd1\x1f\x8f\x59\xf9\xe4\x8f\xc7\x7d\x83\x5f\xfe\xf4\xbf\xf0\x4a\x29\x55\x86\x2b\x83\x94\x41\xca\x38\x65\x12\x68\xe8\x1f\xc8\xad\xe9\x91\xb5\xca\x3c\x65\x14\x80\x62\x51\x8c\xb2\x47\x39\x08\x00\xbc\xf2\xbe\x32\x49\x79\x98\x1e\x3d\xdc\xec\x2a\x4f\x2a\xc7\x94\xbd\xcd\x35\xf8\xda\x39\xa2\x1c\x6f\xd8\xda\xa9\xbc\xa4\x1c\x54\x5e\x54\x0e\x2a\x1f\x50\x4e\xda\x00\xe4\xd9\xf4\xc8\x89\xf8\x19\xaf\x29\x31\xa5\xad\x12\xbb\xee\x88\x2f\xfc\x91\x64\x55\xfb\xf7\xbb\xbd\x73\xff\x84\x0b\x9f\x43\x33\xdb\xd0\xa0\xe9\x0c\xb4\x02\x0b\x58\x00\x81\x48\x31\x40\x3a\xa4\x03\x82\x1c\xc8\x01\x06\x72\x21\x17\x58\xc8\x83\x3c\xe0\x20\x1f\xf2\x81\x07\x3f\x14\x12\x1c\x00\x45\xa0\x81\x62\x28\x06\x2d\x04\x20\x00\x3a\x28\x81\x96\x20\x40\x10\x82\xc0\x41\x08\x42\xa0\x87\x72\x28\x07\x03\xb4\x86\xd6\xa0\x81\x30\x84\xc1\x08\x6d\xa0\x0d\x98\xa0\x2d\xb4\x05\x33\xb4\x83\x76\x60\x81\xf6\xd0\x1e\xac\xd0\x15\xba\x82\x08\xdd\xa0\x1b\xc1\x3f\xd0\x1d\xec\xd0\x13\x7a\x82\x03\xfa\x40\x1f\x70\x42\x05\xdc\x0a\x4e\xe8\x0f\xfd\xc1\x05\x03\x60\x00\xd8\x60\x10\x0c\x02\x37\x0c\x81\x21\x90\x04\xc3\x60\x18\x24\xc3\xed\x70\x3b\x24\xc1\x1d\x70\x07\xa4\xc0\x72\x58\x0e\x2c\xac\x80\x55\xc0\xc3\x6a\x78\x0c\x04\x58\x0b\x6b\x81\x83\x75\xb0\x0e\x04\x58\x0f\x9b\x80\x83\x2a\xd8\x0a\x1a\xd8\x06\xdb\xc0\x02\x4f\xc3\x73\x20\xc2\x2e\xd8\x05\x76\xd8\x0d\x7b\xc1\x01\xd5\x50\x0d\x4e\xa8\x81\x57\xc0\x05\x87\xe0\x10\x24\xc1\x61\x38\x0c\x36\x78\x03\xde\x80\x24\x38\x02\x47\xc0\x02\x9f\xc0\x27\x80\xe0\x33\xf8\x0c\x10\x9c\x81\x33\x80\x80\x81\xd6\xc0\x03\x0f\x08\xf4\xa0\x07\x44\x79\x6a\xa4\xde\xc0\x49\x39\x6b\xa4\x9c\x35\x42\x36\x64\xc7\x39\xeb\x82\x02\x28\x00\x17\xe5\x66\x1a\xe5\x9d\x0b\x4a\xa1\x14\x5c\xd0\x0a\x5a\x41\x32\xe5\xa0\x96\x72\xd0\x4d\x39\xa8\xa3\x1c\x4c\xa2\x1c\x34\x51\x0e\xea\x29\x07\xcd\x94\x83\x2c\x74\x87\x9e\xc0\x41\x6f\xe8\x0d\x1c\xe5\x1a\x4f\xb9\x26\x50\xae\xf1\x30\x10\x06\x02\x07\xb7\xc1\x6d\xa0\x81\x4a\xa8\x04\x2b\xe5\xa0\x48\x39\x98\x42\x39\x28\x52\x0e\xa6\xc2\x5d\x70\x17\x38\x61\x11\x2c\x05\x86\x72\xd3\x45\xb9\xe6\x82\xcd\xb0\x19\x5c\x94\x77\x6e\xca\x3b\x3d\xe5\x1d\x0b\xbb\x60\x2f\x70\x94\x6b\x3c\xe5\x9a\x00\xaf\xc1\xeb\x60\xa5\xbc\x13\x29\xd7\x44\x78\x13\xde\x04\x17\xbc\x05\x6f\x01\x47\x39\xa8\x87\x0f\xa1\x16\x9c\x14\xd5\x21\xca\x4d\x23\x45\x77\x2a\x4f\x8d\x94\xa7\x46\x60\x20\x89\xf2\x14\x9a\xf0\x94\xa1\xdc\x64\x29\x37\x39\xc8\x89\x6b\x65\x08\x74\x50\x0e\xed\xc1\x06\x5d\xa1\x3b\x24\x53\x0d\x4a\xa3\x1a\x94\x0e\x15\x30\x00\x32\xa8\xd6\x64\x51\x9a\x7d\x30\x0c\xee\x80\x6c\x58\x0e\x9b\x20\x0f\xaa\x60\x1b\x94\x53\x4a\xda\x51\x4a\x3a\x43\x35\xbc\x02\x3d\x28\xea\xec\x4b\xc7\x5a\x01\x1f\xc1\x67\x70\x2b\x1d\xd3\xe0\x86\xf8\xb2\x18\xda\xfd\x85\xf8\x12\x00\x4d\x99\x38\x7e\x64\xb3\xe8\x92\xa3\x9f\x5a\x40\x60\x8b\x7f\x72\x34\x8a\xbd\x19\x10\xc5\xe0\x2c\xe7\x41\x8f\x02\x0f\x1c\xbf\x99\x0f\x01\xa0\x4c\xf5\x93\x7d\x1f\xc6\x31\xf1\x10\x57\xfd\x77\x16\x98\x1f\x2b\xc0\x43\x2c\xaf\x87\x7c\xef\x71\xd7\x5d\xe3\xa1\x13\x98\xae\x70\xc2\x38\x79\x1c\x80\x76\x36\x33\xc0\x03\x68\xdb\x2d\x08\x80\x6b\xc3\x63\x7a\x1e\xf9\x39\x1b\x7f\xa5\xa9\x11\x37\x7c\x46\xe3\x69\xf2\x9d\x03\x62\xf5\x0a\xc1\x43\xe3\x20\xe2\xb9\xe7\x83\x82\x06\xa0\x39\xcc\x51\xe6\x33\x8f\xde\xe3\xf0\xa4\x78\x32\x3c\x59\x9e\x5c\x4f\xc0\xd3\xc6\x73\xa7\x67\x8f\x37\x2b\xe7\xea\x15\x8e\x52\x4a\xce\xf6\xc0\x53\xa8\x7f\xfc\x6c\xf0\x58\x3d\x49\x9e\xb4\xf8\xd9\xe1\x86\xb3\x11\xe1\x91\xf2\x6f\xe5\x6b\xe5\x4d\x65\xba\x72\x73\xbd\x52\x7f\xfe\xec\xdb\x67\xdf\x3c\x7b\xe8\xec\xeb\x67\x5f\x3b\xfb\xca\x59\x7c\xf6\xb9\xb3\x8b\xcf\x96\x7f\xf1\xe6\xa7\x31\xfe\xdb\xf8\x08\xff\xf2\x3f\x24\x40\xc3\x4f\x50\x73\x76\xc5\x77\x02\xb0\x1c\x2f\x68\xb4\x3a\xbd\xc1\x68\x32\x5b\xac\xa2\xcd\xee\x70\xba\xdc\x49\xc9\x29\xa9\x69\xe9\x19\x99\x1e\x6f\x96\x2f\x3b\x27\x37\x2f\xbf\x45\x81\xbf\xb0\xa8\x38\x50\xd2\x32\x18\x2a\x2d\x6b\x55\xde\x3a\xdc\xa6\x6d\xbb\xf6\x1d\x3a\x76\xba\xa9\x73\x97\xae\xdd\xba\xf7\xe8\xd9\xab\x77\x9f\x9b\xfb\xf6\xbb\xa5\xe2\xd6\xfe\x03\x06\x0e\xba\x6d\x70\xe5\x90\xa1\xc3\x6e\xbf\x63\xf8\x9d\x23\x46\xc2\xc3\x4b\x97\x3f\xb2\x6e\xd3\xd6\x67\x9e\xde\xf1\xec\xce\xe7\x76\xbd\xb0\x7b\xcf\xde\x97\x5e\xc4\x52\xf5\xbe\x9a\xbf\xbd\xf2\xf2\x81\xd7\x0e\xbe\x0e\x33\xc7\x8c\x9d\xf8\xf9\x9c\xed\xd3\x27\x7f\x33\x6b\x12\x2c\xdb\x0c\x77\x03\x8c\xa7\xde\x01\xa6\x3c\x00\xcf\xef\x7f\x70\xf4\x34\xb2\x3d\x75\xde\x99\x51\x8b\x1e\xda\xf8\xe6\x5b\x1f\xd6\x7e\x7a\xfa\xa3\x8f\x5f\x85\x37\x8e\xc0\xd7\x67\xbf\xfc\xee\x5f\x30\xf7\x93\xcf\x60\xc9\xca\xc5\xab\x56\xac\x79\xf4\xb1\xd5\x1b\x1e\x87\xf5\x4f\x6e\xa9\x82\xe8\x51\x02\x54\xef\x8b\x93\xc9\xb5\xe1\x5f\x82\x2a\xd8\x09\x6b\xe1\x29\x78\x08\x0e\x40\x14\x8e\x43\x14\x4e\xc3\x16\xd8\x0e\x12\x1c\xa2\xdf\x37\xc2\x7a\x78\x8b\x5a\xbd\x57\x61\x0d\x74\xe5\x45\x0c\x85\x18\xec\x7d\xf0\xcd\x15\x95\xb8\xf7\xac\x21\x18\x7c\x1d\x93\xb0\xe0\xaf\x6c\x3f\x84\xee\x9b\x37\xc4\xf3\x4f\x8c\xec\xc5\x49\x45\x18\x15\x7a\x3e\xc5\x46\x7f\x11\x66\x0a\xfb\xf4\xaf\xec\xe6\x1b\xe2\x2d\xc2\x6c\xe1\xc4\x24\x0f\xee\x54\x51\xe9\xc5\x9d\x86\x14\x61\xae\x90\xfc\xd4\xeb\xf3\xde\x57\xf9\x79\xea\xc9\x21\xa9\x7d\xfa\x57\x56\xd6\xa7\x7e\x3f\x24\xd5\xe7\xc5\xbc\xbf\x12\x77\x9f\x35\x84\x1e\x18\x32\x24\xa9\x08\xf3\x85\xa6\xdb\x87\x16\x61\xa1\x50\xca\x42\xcb\x2a\x2a\xb1\x67\xd9\xed\xb7\xa7\x62\x18\x52\x84\x35\x85\x52\x36\xdd\xd5\xa9\x61\x97\xb6\xd0\x26\x7a\xc2\x81\x22\xac\x2b\xf4\xcc\x23\x37\x39\x92\x7a\x72\x88\x07\xb3\x39\xbd\x7c\x1e\xcc\xe5\xf6\xc6\x50\x51\xb9\x62\xec\x8a\x91\x1e\xb2\xd1\x3a\xd5\xeb\x1d\x92\xba\x82\x7e\xeb\xaf\x7e\x23\x37\xd4\xab\xa3\xb3\xa6\x5a\xbd\x43\x8a\xb0\xa1\xd0\xf3\x01\x25\xc7\x58\xe8\x09\x60\x8d\xff\xf6\x4a\x8f\xa7\x87\xaf\xfb\xc8\x49\x9e\x4a\xcf\x98\x51\xea\x25\xc8\x79\x26\x72\x67\x4f\x38\xe0\x59\xe1\xe9\xb1\xa2\xfb\x48\xdf\x0a\xcf\x0a\x1f\xbd\x9d\x8f\x5c\x1c\x77\x6a\x9d\xea\x1d\x92\xea\x23\x3b\x70\xa7\xb1\xe4\xcb\x90\x22\x6c\xa6\x77\x6a\x5f\x9b\xe4\xf5\xa6\x7a\x6a\x57\xf4\xe9\x5f\xe9\x59\xe1\xeb\xe5\xc1\x30\x28\x3e\x36\x2f\x3d\xcd\x52\xe8\xf3\xd4\xc6\x6f\xee\xf3\x54\xf6\x19\x90\xea\xc5\x68\x48\xe5\x0a\xcc\xe5\xf6\xf2\xad\xf0\x79\x56\xf4\x5a\xe1\x1b\x49\x7e\xa0\xfe\x84\x7c\x14\x61\x2b\x11\x83\xcd\x5f\x84\x45\x42\x00\xd9\xb0\x5d\x43\xc0\x0a\xf2\xe1\x1b\x39\x69\x44\x53\x4a\xc8\x4f\xed\x85\x9e\x15\x9e\x15\x4b\x09\xdb\x7a\x8f\xf1\xad\xd0\x60\x4f\x45\x65\xbb\xd4\xc3\x43\x8a\xb0\xa3\xb0\x1a\x3a\xa1\x4e\x9d\x3b\xa3\x3e\xaf\x58\x61\x34\xd0\x77\x72\xf2\xa0\x4a\xf2\xde\xbf\xd2\x37\xca\x83\xc1\xd7\x39\x75\x94\x07\x23\x5f\xe7\x21\x1e\xdc\xa9\x7f\x65\x04\x3c\xd0\x65\x74\xe7\x08\xf2\xa0\x2e\xa3\x3b\x63\xcf\x68\x9c\x3c\x36\x2d\x71\x2f\x67\x21\x46\x5d\x46\xfb\x30\x74\x19\xed\x2b\x52\x67\x21\xb1\x02\xc4\x9a\x77\x05\x60\xc6\xf0\x83\x80\x25\x88\x42\x42\x10\x68\x17\xd1\x70\x29\xdf\x07\x25\x81\xff\xac\x5d\x84\x65\x52\xbe\x0f\x82\xc4\x92\xdd\x3c\xd9\x1d\xd1\x08\xa9\x57\xdb\x45\x10\xd9\x1f\x12\xbd\x62\x8e\x57\xf4\x76\x65\x3c\x72\x36\xda\x24\x4f\xe0\x07\x5d\x7e\xa1\x2b\x77\x92\xce\xfa\x17\x00\xd0\x0c\x1e\xd3\xeb\x86\x20\x02\x00\x7e\x09\xe9\x63\x11\x9e\x01\x3f\xc2\xda\x00\xe6\x6a\x31\x04\x25\x8d\x21\x86\x19\xfa\x21\xe9\x90\x1f\x24\x1e\x89\x36\xcc\x85\x4b\x5a\x86\xca\x42\x4e\x56\x0c\x89\x2f\x1c\x3d\x1a\x7d\xf7\x5d\x74\x86\xfd\xe0\x6a\x31\xb9\x6e\x05\x67\x65\xfa\x08\xc4\x2f\x19\xa0\x03\x60\x08\x60\x21\x54\xc3\xe8\x41\xcb\xf9\xb1\x36\x88\xb0\x31\x80\x51\xad\xc4\x19\x62\x98\xb3\x4a\x1a\xe4\x97\xf4\x86\x98\x64\x42\x7e\x89\x23\x57\xe6\xc3\x92\x5e\x23\xda\xb0\x21\x0c\x25\x2d\xed\xe5\x62\x48\xd4\x84\xe8\x7b\x05\x8a\x8e\xfd\x27\x8a\x8e\xe5\xac\x3f\xa1\x24\xf9\xe2\xe5\xff\x20\xab\x7c\xf1\x32\x30\xd0\x1d\x80\x7b\x9a\xc7\x90\x0a\x99\x68\x30\x44\x52\x00\xfc\x11\xa7\x2b\x39\x14\x0a\x45\x34\x0c\xf8\x23\x5a\x83\x31\x14\x0a\xd5\x00\x4a\xd1\x98\xfc\xd5\x8c\x98\x96\x9e\xed\x0e\x49\xc0\xc7\xaa\x1d\xee\xa4\xd4\x6c\x77\xb0\x86\xe7\xe8\x21\xd6\x9a\x91\x49\x0e\xf1\x7c\xac\x5a\xd0\xe9\x4d\xd9\xee\x20\xc2\x9e\x00\x4e\xa9\x95\x92\xed\x31\x9c\x6c\x95\x5c\xc8\x2f\x39\xed\xb1\x88\xd3\xa5\xf7\x57\x77\x72\xda\x75\xfe\x6a\xad\xd3\xa5\xf5\x4b\x1a\x7b\x0c\x6b\x02\x92\xd6\x1e\x8b\x68\xb4\xe4\x98\x86\xd3\xf9\xb1\xd3\x2a\x19\x90\x5f\x32\xda\x63\x92\x17\xf9\x71\xab\x94\xfd\x1d\xde\xfb\x65\x3f\x38\xfd\xfa\xfd\x1d\xde\xf9\x65\x1b\xd9\xc0\x29\xd6\x6a\x26\x45\x63\xf7\x57\xb3\xf4\x5d\x20\xef\x38\xd9\x5a\xad\x4b\xd6\xda\xfd\xd8\x65\xad\xd6\xbb\x0c\x76\x72\xa9\x6a\x93\xd3\x68\xf7\x57\x5b\xe9\xbb\x48\xdf\x1d\xe4\x9d\x9c\xe3\xa6\xe7\x24\x5b\xab\x93\xe8\xaf\x52\xac\xd5\xa9\x89\xeb\xa4\x25\xae\x93\x4e\xce\xa9\xce\x48\x9c\x99\x49\xf6\xb3\x9d\xac\x0c\x4b\x48\xb5\x8a\x84\x17\xc4\xba\x17\x5f\xf3\x0f\x77\x4a\x21\x82\x28\xf3\xda\xbd\x65\x5e\x7b\x88\x25\xaf\x90\xd3\x47\x5f\x3e\x3b\x79\x95\x7b\xed\xbe\xee\x48\xdb\x55\x01\x94\xd6\x7f\x63\x7f\x50\xfa\x6f\xec\xff\xf6\x57\x5d\x4f\xff\x56\xb1\xa9\x42\xa9\xd8\x58\x51\x0d\x4a\x57\x05\x6d\x5e\x89\x6e\x5f\x8d\x9e\x92\x47\x90\xd7\x6a\x79\xc7\x4a\x79\x1c\xda\x4c\x5e\x2b\xd1\xed\xaa\xbe\xcf\x54\x4a\x38\xa7\xb0\x05\x0a\x61\x13\x44\x0a\x00\xfc\x38\x2f\x24\xf1\x42\x2c\x52\xc0\x13\x8e\x16\xb4\xd0\xf9\x23\x22\x03\x7e\xec\x08\x49\xa9\x42\x2c\x22\xa6\x92\xdd\xa2\x4d\xe7\x47\xb8\x28\x80\xcd\xb5\x52\x86\x21\x86\xc1\x53\x2b\x4a\x8c\x35\x86\x33\xac\x92\x88\xfc\x92\xc3\x14\xc3\x2d\xc8\xbe\x7c\x53\x0c\x3b\xac\x92\x16\xf9\x71\x52\x50\xca\x36\xc4\xb0\x3b\x28\x15\x23\xbf\xd4\x22\x43\xb4\x61\x63\x18\xe7\x8b\xd5\x06\x3e\xd5\x9b\xed\x0e\x4b\x5a\x87\x68\xc3\x59\x61\x90\x52\x79\xd1\x56\x03\xc8\xec\xce\xce\x76\x87\x89\x3e\x86\x1c\xae\x50\xb0\x55\x59\x69\x6e\x5e\x31\x2a\x2b\x6d\x55\x5e\x16\x72\x66\x20\xa7\xaf\x34\xd7\x97\x25\x38\x1d\x2e\x77\x06\x72\x3a\x04\x8d\xd3\x57\x56\x8c\x66\x32\xaf\x57\xcd\x78\xf0\xb1\x85\x6b\x4f\x9c\x3a\xf8\xec\xd6\xe7\x5f\x3d\x32\x7f\xfa\xac\x7b\xe7\x6e\x3d\x79\xf4\x54\xcd\x96\x3d\x9f\xa1\xe7\xf9\xcd\x8b\xef\x9f\x3a\x64\x61\xb0\xfd\xbb\xbb\x77\xbe\xe7\xfc\xfc\x4c\xd2\x8f\xc7\x97\x3d\x7f\xff\xe4\x91\x73\x5a\x75\x8e\xee\xda\xf3\x8e\xfd\xf0\x21\xdb\x47\x00\x3c\x4c\x50\xea\xf8\xc5\x7c\x14\x4c\x44\xc3\xa1\x08\xda\xc2\x0a\x88\xf8\xc9\x6c\x6d\xa9\x89\x45\x38\x06\xfc\x52\x92\x26\x56\xd3\x3a\xdb\xcf\x99\xfc\x52\x6b\x4d\xac\x46\x34\xd0\x4d\x51\x13\x43\xb8\x5d\x00\x43\xad\x64\xb6\xc7\xb0\xd9\x2a\x39\x90\x9f\xe8\x28\xd6\x5a\x25\x0f\xf2\x4b\xc5\xf6\x18\x2e\xb6\x4a\xa5\xc8\x2f\xe5\xdb\x63\x52\x7b\xc2\x2e\xb3\x68\xab\x36\x70\x69\x99\x84\x0d\xa5\xc5\xa2\xad\x3a\x3d\xdb\x9f\x91\xed\x0e\x83\xd4\xba\xa5\x68\x93\xd2\x32\xc3\x61\x29\x49\x14\x6d\x52\x7a\x46\x98\x70\xa4\xac\xb4\x55\x28\xe8\x4a\x47\x0e\xc1\x97\x95\x5b\x4e\xb9\xd3\x1e\xa9\xec\xb0\x23\x37\xca\xf9\x83\xe3\x13\x76\x2c\x5f\xbe\xe3\x99\x65\x2b\x76\xae\xbd\xf5\xe6\x5e\x15\xb7\xf6\xee\x53\x31\x9a\x79\x7b\x6a\x7d\x18\xdd\xb9\x63\xf9\xb2\x9d\x3b\x96\xc6\x0f\xf4\xef\xd5\xfb\x56\xae\x4f\xdf\x05\x2f\xee\x5d\xd8\x77\xc1\x9e\x3d\x0b\x7a\x8f\x1f\xd7\xa7\x6f\xef\x89\x13\x7b\x5f\x4d\xe6\x66\x76\xb9\xb2\x7a\x57\xbf\x05\x7b\xf7\x2e\xe8\xb7\x70\xcf\x9e\x85\x7d\xc6\x8f\xef\xd3\xaf\xf7\x84\x09\xbd\x09\x7a\xeb\xa4\xd4\x71\xef\xf1\x51\xf0\x42\x21\x84\x61\x31\x44\x52\x89\x65\xc8\x24\x8c\xcb\x61\x63\x11\x1d\x61\x5c\x39\x1b\x43\xb8\x0d\x65\x51\x96\x21\x56\x2d\x64\x81\xd6\x2f\x15\x19\x62\x38\x4b\x65\x8b\xd1\x12\xc3\x46\x95\x6f\x4e\x4b\x4c\x6a\x8b\xfc\x52\x91\x20\xda\x30\x1b\xc6\xa5\x62\x8d\x2e\x33\xa7\x85\x35\xdb\x1d\xc6\x46\x1b\xce\x0f\x63\x87\x18\x11\x53\xd3\xc2\xe1\x30\x48\x39\xa9\xa2\x0d\xa7\x85\x71\xb9\xb8\x0f\x04\x63\x52\x8b\x12\x55\x7d\x4a\x5b\x95\x53\xb5\x09\x05\x5d\x4e\x87\x60\x41\xa8\x03\x2a\x0b\x39\x04\x8d\x5b\xe3\xcb\x33\x23\x5f\x56\xb6\xca\xa0\x72\xa4\x31\x23\xbb\xc3\xe5\x2e\xef\x80\xca\x28\xaf\x3a\xad\x5a\xd9\xef\xe6\xb7\x5e\xd8\x7a\x74\xe2\xf8\xa9\x68\x60\x8b\x62\xdc\xaf\xf7\xab\xcc\xb7\x83\x2a\xde\x9c\xf0\x89\xac\x44\x57\x2f\xed\xb9\xb2\x83\xbc\x31\x7f\x58\xdb\x05\xad\x5a\xad\x08\xb7\x18\xd9\xef\xd6\x4a\xb4\xec\xbe\x97\x6f\x1f\x5d\xd5\x7f\xd7\xcb\x7f\x5b\x38\x6a\x4d\x9f\x0a\x79\xfc\x4d\x5b\x2b\x97\x9c\x1d\xf2\x05\x3f\xae\x5d\xc7\xef\x5e\x9e\xb1\xb6\x65\x31\xaa\x4e\xef\xfa\x00\xb3\xb7\xec\xee\xae\x77\xe6\x0e\x69\xd5\x7e\xf8\x0c\x75\x1e\x56\x70\x99\xc8\x45\xed\x77\x0b\x62\xbd\x89\xe9\xd6\x71\x7e\x84\x85\x84\xdd\xa6\x2f\x4d\xa3\xc1\x86\x92\x96\xa9\x88\x38\x03\x62\xa2\xb9\x4c\xa4\xfb\xe9\x0b\x35\x71\x8c\x60\x89\xdc\x92\xd9\x22\x8c\x01\x11\xec\x80\xb0\x8d\x32\x9a\x98\x7b\x3b\xf2\x53\xab\x62\x85\xf2\x4c\x24\x30\xa2\xd3\x6a\x73\x6b\x7c\xb9\xb0\x04\x75\x78\x49\xc8\x5d\xfe\xce\x89\x15\xb9\xc2\x4b\xf2\x9b\x4c\x77\x1d\x5a\xc1\x14\xdf\x81\xee\x99\x2c\xe7\xcb\x3b\x4d\xf2\x4e\x39\xff\x9e\x29\x77\x30\x45\xe4\xda\x82\xdc\x92\xc9\x6c\x7a\x6d\xb6\x56\x32\x35\x5e\xbb\x95\x4d\x2c\xb3\x32\x79\xe5\x21\x17\x88\x4e\x2b\x68\x7c\xc2\xd2\x93\xff\x78\x30\x57\x78\x11\x75\x94\xdf\x78\x51\x90\xb7\x4c\x44\x5f\xa2\x3b\x4c\xe8\x36\xf4\xf5\xb4\x29\x77\xd4\x7f\x20\xcf\xd2\xc9\xf7\xd6\xff\xe3\x0e\x3a\xee\x34\xe6\x4e\x76\x30\x8f\xc1\x0c\x1e\x88\xb0\xd4\x21\x5a\x02\x98\xa9\x95\x78\x7b\x4c\xb2\x22\xbf\xc4\x33\x8d\x3e\x8a\x67\x43\x6c\x8e\x9b\xb7\x6b\x0c\x28\xcf\x9e\xd6\x12\xe5\xeb\xb7\xeb\x51\x4e\x89\xfc\xc1\x1b\x8b\xf7\xe1\x25\x47\xb9\xc0\xe6\xbb\xd0\x6d\xf2\x8e\x69\x4f\x0e\x91\x2f\x8e\x40\x99\x72\xec\x0e\x44\xe2\x9a\x7e\xb0\x96\x2b\xe5\xfe\x06\x06\xe8\x4f\xbd\xa4\x26\x24\x21\x6d\x0c\xf3\xc1\x08\x20\x62\xd9\x40\xaf\xf3\x47\x10\x90\x4d\xc4\x12\x23\x67\x0c\x60\x7d\x2d\xf1\xc5\x3a\xe2\x3b\x83\x11\x9d\x9e\x1c\xd3\x69\x74\xfe\x88\x5e\x47\x36\xf5\xa0\xf3\x13\x4f\xaa\x1a\x6c\x31\x24\x7a\x9d\x5e\xd1\x27\xf6\x43\x6b\xa3\x68\x8d\x3c\x23\xca\xdc\x11\x41\xcf\xc9\x43\x22\x72\x19\x7a\x47\x95\x4f\x89\x2c\xa3\xb6\xf0\x39\xf0\x90\x73\x03\x59\x5f\x4f\xce\x25\xdd\xa3\x8f\xcb\x32\x6a\xf7\xcc\x5e\xf9\x94\x7a\x1d\x1f\x93\xc2\x98\x98\x1a\x60\x21\x8b\x5c\x47\x42\x6c\x8c\xbc\x10\xe6\x02\x12\x20\x7f\x0d\x6b\x24\xd7\x95\xf8\xc4\xd8\x9c\x3e\x74\x9e\x49\xd9\xbc\x99\xfc\x76\x3b\x00\x1a\x07\x27\x80\x85\x16\x4d\x50\x48\x62\x83\x5c\x82\x68\x0d\x6b\x88\xd1\x97\x7a\x09\x82\x3d\xb6\x47\x4f\x9c\x20\xbf\xb7\x2a\x8b\x59\x37\xc5\x31\x22\x44\x10\x95\x15\x17\x88\x9f\xe7\x46\x21\x64\x65\x46\x3c\x57\xbf\x7d\x9e\x50\x74\xe9\x1f\x14\xf7\xcc\x50\xea\x38\x6b\xdc\x9e\xb6\x81\x88\x81\xdc\x48\x64\x13\x96\x94\x0c\x3a\x4d\xb5\x99\x86\x46\x9b\x69\x88\x49\xe9\x71\xeb\x28\x19\xb8\x30\x95\xbb\x68\xb5\x85\x82\xb6\x64\x64\x65\x7c\x59\x8c\x3a\x71\xcb\x44\xd5\xb2\xcd\xb8\x54\xfb\xd1\xa5\xdf\x3e\xfa\xe8\x72\x74\xc5\xa2\x45\x4b\x97\x2f\x5a\xb4\x8c\xf1\xa3\x21\xc8\x85\xfc\xf2\x87\xf2\x79\xf9\x39\x39\x26\x7f\x84\x0a\x7e\x38\xf8\xc6\xe1\xd7\xd1\x0b\x07\x0f\x1d\x3a\x48\xe8\xd8\x0f\xc0\xec\xe2\x31\xf0\x04\x8d\x71\xc4\x56\x31\x64\x44\x88\xb1\x7a\x0e\x07\x08\x5e\xa1\x62\xe1\x28\x2b\x22\x1c\x4b\x04\xce\x21\x9d\x9f\x48\x88\x32\x35\x47\xf4\x89\xfb\xd1\x8f\x51\xee\xc2\xea\x56\x97\x2b\xb8\x9f\xc8\x35\x47\x02\x70\xb9\x7c\x14\x52\xe0\x2e\x88\x98\x09\xa5\x06\x36\x46\x15\x5a\x72\xb1\xb1\x88\x8b\x5e\xc5\x95\x42\xb4\x2b\x55\x05\x3a\x56\x0a\x74\xec\xc8\x2f\x09\x86\x58\x44\xb0\x93\x13\x04\x93\xce\x1f\xb1\x0b\x64\xd3\x6e\xd6\xf9\xa5\x34\xe4\x97\xec\xc9\xa2\x2d\xc2\x1a\xf4\xd4\xdc\x19\xcc\xa2\x0d\x5b\xc2\xd8\x25\x46\x04\xb0\x87\xa9\x63\xc8\x05\xd5\xca\x69\x90\xdb\xeb\xf4\x96\xa1\x84\x29\x73\xfa\x46\xf2\x88\xfb\xee\x48\x6c\xd5\x02\xf9\x41\x86\x39\x70\xb5\x02\x7d\xbe\x70\xd8\x82\x89\x1b\xd7\x1c\xe4\x74\x07\x10\x7c\x2b\xcd\xfe\x71\xb9\x7c\x27\xbf\x79\x29\x63\x5b\xf3\x7c\xe5\xd4\x0d\x55\x2b\x55\x1d\x1b\xa3\xd4\xb1\x57\xf8\x28\x14\xc0\xa3\x10\xc9\x27\xb4\xf0\x6c\x2c\xc2\xe7\x93\x61\xf1\x48\xe7\x8f\xa4\x11\xb2\x1c\x6c\x2c\xe2\x48\x23\xfb\x1c\x49\x3a\x7f\x8d\xc9\x98\x9f\x66\xf2\x4b\x26\x22\x56\x3f\x11\x2b\x71\xfe\x04\x1e\xb8\x83\x98\xa1\x68\x40\xca\x31\xc4\xb0\x48\x10\x42\xa6\x21\x16\x11\x33\x29\xa8\x30\xea\xfc\x52\x21\xf2\x4b\x22\x23\xda\xaa\xf9\xb4\xac\x7c\xea\x01\x8d\xbc\x68\x93\x20\x27\x1c\xc6\x26\x11\x67\x85\xb1\xc3\x26\x25\x67\x86\x9b\xe3\x02\x3f\x2a\x53\x37\x28\xa9\x79\xb9\x71\x5b\xaf\x21\xc0\x80\xf3\x65\x65\x8f\x61\x0f\xac\xba\x7f\xde\xea\xf9\xcb\xf6\xec\x59\x3c\xf5\x81\xb9\x77\x3f\x72\x90\xe1\x2f\x1d\x3f\xf1\xd3\xd4\xa9\x8b\xa7\xca\x57\xde\x79\x5b\xbe\x82\xee\x13\xee\x5e\xb6\xec\xa1\xa5\x0b\x37\x2f\xbe\x77\xde\xa2\xa5\xd3\x85\x9d\xff\xfa\xe8\xed\xa1\xd5\x01\xff\x2b\x33\xdf\xfe\xe6\x23\x35\x23\x59\x0e\xc0\xf5\xe7\x31\xe8\xc1\x02\x95\x10\xd1\x25\xb4\xa5\x06\x0c\x3a\xc6\xe4\xc7\x5c\x48\x02\x36\x86\x85\x20\xc2\xd6\x00\xd6\xd5\x62\x63\x90\x28\x31\x66\x83\x11\x2d\x35\x15\x5a\x41\xe7\x8f\xe8\x28\x54\xd5\x11\xab\x21\x12\x68\x6f\x00\xd1\x86\x51\x18\x33\x22\x36\x53\xdf\x8e\x42\x62\xc8\xe9\x13\x7d\x24\x88\xc8\xd3\x94\x33\x8b\xde\x3b\x7e\xfc\x88\xdc\x15\x1d\x10\xec\xa8\xe2\x2e\xf6\xe7\xab\x6d\x36\xcb\x18\x55\x6c\x66\x5e\x40\x41\x2a\xa3\x2d\x4a\x1d\x67\xe7\x31\x64\xc2\x5b\x10\x49\x6f\x90\x51\x7a\x83\x8c\xac\x44\x46\x76\x2e\x56\x6d\x4e\xb7\x6a\xfd\x35\x6e\x43\xba\xd5\xe4\x97\xdc\x5c\x8c\x22\x6d\x4b\x6d\xb5\xd5\x02\x66\xbf\xc4\x58\x62\x54\x36\x29\x86\x04\x74\xc6\xb9\x29\x48\x32\x5b\x8a\x8f\x83\x64\x31\x17\x1f\x27\x60\xba\xe3\xb3\x97\x6e\x21\x18\x9a\xc7\x16\x2b\xb6\x1e\xc6\x66\x2b\xb6\x1f\xde\xdf\x71\xf2\x6f\x63\xc0\xe9\x37\x54\x3b\xcc\x76\xbb\x3f\xe2\x30\xdb\x49\x48\xe6\x13\xcc\xa2\x2d\x0c\xd8\x51\x8c\x22\x56\xbb\x43\x05\xb6\x48\xd2\x12\x33\x9e\x1e\xc6\x29\xa2\x24\xda\x88\x26\x9b\x79\xd1\x16\x01\x6d\x4a\xf8\x1a\xb1\xfa\xb2\x04\x4d\x9e\xdd\xeb\xf4\xb2\x1d\x50\x79\x2b\x9b\xd3\xc1\xf8\xb2\x72\xb7\x30\x91\xe5\x53\xe7\xad\x58\x79\xff\x3d\x13\x92\x76\x0c\x64\x3e\xa9\x3f\x55\x52\x3c\xa3\xf7\xf1\x7f\xd5\x7d\xf9\xea\xaf\x68\xae\x30\x7b\x31\x7e\x62\x65\x4d\xf7\x9e\x22\x9b\xf9\x92\x3c\x3e\xab\x88\x61\xe4\x5f\xbf\x3c\x2d\xff\x7a\x42\x95\xe1\x12\xa5\x8e\x2b\xa7\x73\x33\x0f\xa6\x42\x24\x89\x70\x2b\x23\x61\x87\x0c\x6c\xac\xc6\x96\x9d\x44\x60\x9c\x8d\xcc\xfc\x7c\x6a\x92\x52\x89\x49\x0a\xe2\x54\x2b\x61\x8a\xe4\x34\xc4\xa4\x16\xc8\x2f\x79\x53\x29\x66\xb3\x25\x11\x28\xe2\x14\x25\xad\x86\x50\x92\x4d\x60\xad\x33\x8c\x6d\x22\x99\x99\x06\x1b\xd6\x86\x31\x27\x62\x4d\x98\x9a\x2e\x32\x39\xdd\x9a\x62\xe4\xcb\x12\xd2\x51\x07\x14\x0a\xaa\x24\x81\xbd\x29\xc1\x4b\x50\xeb\x7f\xf5\x59\x57\x52\xd0\x72\x72\xcf\x27\x0f\x75\xda\x79\xe7\x5b\xe7\x7e\x3b\x55\x2b\x9f\x3b\xb2\x7b\xe1\xdc\xa5\x8f\x3d\x38\x76\x75\x0e\xd3\x16\xb9\x50\x12\xba\x3d\x2b\x65\x63\x72\xe6\xe5\xe3\xee\xd6\x1d\xe5\x8b\x7f\xff\x4a\xfe\x1a\xb5\x42\x9a\xe3\x9f\x9e\xdc\xf4\xe8\xfe\xfe\x5d\xa9\x5e\xf4\xa5\x76\x08\x83\x11\xe6\x42\x44\x4b\xb0\xbd\x26\x44\x6d\x35\x51\x53\x84\x4d\x01\xc9\xac\x06\x48\x1d\xf7\x5c\x5a\x4c\xe3\x22\x6d\xb1\x19\xeb\x0f\xf3\x92\xc6\x79\xc9\x8c\xf9\xc3\xd5\x82\x86\xb7\xfb\xb1\xd6\x5a\xad\xd3\xea\xed\x54\x75\x1b\xc5\x1a\x11\x34\x3c\x91\xae\x24\xe8\x8a\x8b\x51\xb5\xa0\xd1\xea\xe2\xa1\x0b\x02\x09\xb4\x14\xaf\xa9\x6e\x07\x18\x56\xe3\x2b\x4f\x41\xf6\xbe\xec\x27\xf2\x7f\x5e\x6d\x61\x8d\x5a\x0b\x2e\x7e\xc0\x3b\xab\xaa\xe4\xa3\x72\xaa\xfc\xdc\x96\x2d\xa8\x92\xc9\x40\x0c\xc1\x8f\xe3\x94\x3a\x2e\x85\x8f\x82\x1b\x7c\x10\x80\x85\x10\x71\x12\x09\xa5\x26\xa0\x63\x11\x1b\xab\xc9\xf3\x3a\x75\x26\xbf\x94\x47\x68\x28\xa1\x12\x4a\x32\xc4\xb0\x40\x8c\x09\x09\x30\x92\xac\x52\x06\xf2\x4b\x36\x43\x0c\xdb\xac\xd8\x48\x76\x17\x18\x62\xb8\x20\x20\x19\x0d\x31\xa9\x25\xf2\x4b\x05\xd9\xa2\x6d\x9f\x8e\x75\xa6\x7a\x2d\xd4\xc2\x10\x51\x4a\x36\x08\x87\x71\x9e\x28\x59\xd8\x70\x18\x17\xd9\x24\xa3\x10\xfe\x3d\x78\x6c\x30\x28\xe5\x4d\x24\xd6\x54\x7a\xe3\xd6\xcf\x9f\xfa\xc0\xf7\x6f\x1d\xfe\x65\xe1\xd4\xf9\x1b\xe5\x4b\x1f\xd4\xca\x57\xa2\x9b\xe6\xdf\xbf\x79\xeb\xdc\xfb\x9f\x68\xb1\x78\xd2\x84\x25\x4b\xc7\x4f\x5c\x84\x56\xdc\x7f\xa0\xb0\xe0\x85\x99\x87\xdf\x7f\xff\xf0\xcc\x17\x0a\x0a\x0f\xdc\x7f\xe2\xc3\x0f\x4f\x3d\xb0\x6a\xf5\xfd\x73\x36\x6f\x66\x0a\xee\x7a\xf8\xe1\xbb\xa6\xac\x5e\xae\xea\xeb\x00\xa5\x8e\x43\x8d\xfa\xaa\x4f\xf8\x4d\xea\x4d\x72\xd8\x58\x4d\x52\x86\x9e\x35\xc5\x5d\x68\xa3\xbe\xa6\x52\x17\x8a\xbd\x6a\x0a\x81\xe8\x6b\x2a\x88\x36\xc9\x64\x0e\x13\xc4\x5c\xad\x17\xd9\x24\x4a\xba\xa8\x17\x6d\xd8\x14\xc6\x49\xc4\xf8\xe0\x0c\xaa\xbb\x39\x22\x06\x4a\x3a\x84\x82\x90\x8c\xac\xe0\xcb\xca\xcd\x2b\xcf\x40\x34\x88\x20\x80\x39\xee\x77\xcb\x55\x92\x07\x20\xcd\x81\x6f\x90\x46\xfe\xfa\xdb\xbe\xdb\x3a\x66\xb4\x5d\x30\xe0\xd1\xbd\x2d\xd7\x0d\xfd\xc7\x7f\xa2\xab\xe6\x4e\x7d\xcc\xb3\x6e\xd5\x94\x4d\xec\x07\xa7\x51\x92\xfc\xb5\x5c\x27\xef\x94\xbf\x96\xdf\x4b\xcf\xd8\x98\x99\xfc\xe9\x47\x9d\x7b\xf4\x42\xfc\xb7\x8f\xef\x1f\xde\x6b\xfe\xa1\x23\x6f\x10\x5a\x29\x26\xe1\x5a\xd1\xdc\x48\x51\x23\x2a\xa1\xc0\x82\x60\x12\x2d\x75\x25\x5c\x90\xf8\x62\x2c\xd0\x0f\x9a\x1d\x89\x67\x45\x28\x3a\x89\x46\x4f\x9c\x60\xa7\x10\x8c\xc2\xc0\x68\x59\x46\xd3\xb8\x56\xc0\x83\x0e\xf2\x01\x0b\x01\x49\x43\x2e\xa3\x0f\x60\xa1\x16\x23\x15\xd1\xb1\x41\x9a\x2d\xd0\x09\xcd\xc0\x96\x81\xbc\x8d\xee\x1e\x7d\xbc\x55\x34\x01\xb9\xb8\x69\x27\x4e\x00\x82\x1e\x30\x98\x9d\xcd\x7e\x09\x3a\x00\x7b\x19\x72\xf2\x1a\xa7\x9b\x77\xf6\x60\x4b\xea\xdf\x1f\x34\x88\x09\xa0\x0f\x36\xa0\xfb\x8e\xc7\x6c\x82\xfd\x9b\xe3\xaa\xfc\x36\xa1\x8d\xec\xa7\xec\x69\x4a\x53\x8a\x8a\xd2\x38\x95\x22\x8e\x52\x14\x27\x80\x4c\x13\x54\xe6\x75\x6e\x62\x3b\x5f\x7d\x9d\xed\x8c\x36\xee\xd8\x81\x9e\xda\xb1\x43\xf5\xc1\xcb\x60\x30\x7b\x56\xbd\x67\x79\x59\x4e\x79\x59\x5e\x4e\x19\x72\x2e\x63\x6e\x1b\x34\xa8\x7e\x37\x5b\x39\xf8\xc8\x0f\xa2\xe0\x38\xff\x96\xfc\xf0\x06\x60\xa0\x3d\x00\x3b\x8b\xea\x4b\x06\x4c\x53\xa3\x2f\x29\x4d\x9f\x40\x1f\x5c\x73\xf4\x91\xd9\x14\x7d\xa4\x22\x3f\x36\x05\xa5\x0c\x5b\x0c\x1b\x83\x24\x90\x8f\xc3\x11\x1a\xb4\x66\xa4\x12\xe0\x61\x75\x85\xc3\x61\x6c\x17\x23\x7a\x51\x47\x21\x88\x2b\x8d\x18\x6e\xc1\x18\x07\x1f\x89\x59\x62\x46\x4e\x5f\x07\x54\xde\x08\x3e\x08\x3b\xdb\xb3\xb1\x9a\xe8\xa7\xab\xee\x69\xe5\x8e\xa2\x92\x71\xa3\x07\xce\x98\x38\x6c\xe1\x01\xe4\x3d\xc5\x8d\xda\xfe\xe6\xf1\x9a\x07\x6b\xa7\xb7\xba\x6d\xd8\x63\xd3\x6f\xbf\x77\xfe\x90\x49\x33\x47\x8f\xb8\xb2\xe3\xbd\xf7\x08\xff\x66\xca\x6d\x85\x23\xfc\x46\x08\x41\x17\x78\x55\xf5\xb9\xd8\x12\x92\x32\x34\x31\xba\x2d\x95\xf3\x31\xdc\x32\x50\x53\xa0\x01\x2f\xe7\xc7\x37\x05\x24\xa7\x26\x86\xb3\x03\x12\x4b\xc2\xf0\xae\x74\x3e\xe4\xd9\x63\x38\x8f\x1a\xef\x1a\xc1\x0e\x99\x9c\x5f\xea\x16\x37\x7b\x6f\x5e\x9e\x41\xcc\x9e\x19\xb7\xb7\xe2\x0e\x87\xa5\x54\xf6\x12\x4e\x39\x0c\xd5\x29\xa9\xed\x3b\x10\x53\x86\x1a\xb6\xa8\xdb\xca\x23\x33\x08\xe5\x87\xc3\xd8\x2b\x76\xd2\xe9\x58\x31\xbb\xa0\xb8\x65\x59\x1b\x62\xff\x05\x9b\xa4\xc9\x22\x0c\xd1\x15\x88\x36\x5c\x14\x96\x6e\x2a\x57\xd3\x1b\x4e\x11\x27\x13\xd6\xd8\xc0\xeb\x01\x56\x20\xfe\x8b\xc6\x9c\xb9\xe5\x29\x88\x3a\x83\x10\x2b\xd0\xb9\xa4\x9e\xc0\x80\x37\xd8\xaa\xdc\x6d\x46\x3e\x0f\x20\xf5\x40\x6e\xab\x72\x3b\xf5\x18\x33\xed\xe8\x5d\x74\x0f\xba\x1f\x6d\x10\x75\x67\x3e\xef\x35\xc9\x1d\x7c\x74\xc4\xbc\x15\x36\xf7\xb7\x3b\x27\x2e\xec\xc3\x09\x21\x5d\xfb\xd0\xfd\xeb\xb5\x56\xf9\xb0\x8c\xe5\x77\xe5\xe5\x16\x1b\xaa\x40\x6d\x2a\xf7\x75\xc8\xed\xf2\xf7\xd1\xf2\x12\x79\x24\x33\xdd\x70\x53\xef\x4e\x93\x0a\x11\x62\x02\x29\xe1\xcc\x79\x4b\xd0\x19\xf4\x1c\x63\x93\x8d\xf2\x80\x5a\xf9\x9d\x01\x37\x57\xdc\xf2\xf3\x11\xc4\xa2\x70\x69\x2b\xae\xfe\xe5\x69\x03\xbe\x7e\x09\xcd\x47\x2f\xc8\x41\x79\x95\xbc\x4c\xee\xe3\xf7\x4d\x2e\x08\xa0\x5f\xd0\xcc\xd5\xeb\x5b\x76\x34\xa6\x5a\x99\x14\xa3\xf9\x34\x91\x8f\x03\x80\x4f\xe1\x31\x68\xc0\x00\x85\xea\x9c\xc5\xac\xea\x65\x6a\x04\x2d\x20\x93\x5f\x12\x88\xa6\x1b\x03\x34\x46\x92\x10\x71\x0c\xfa\x70\x49\xcb\x10\x0a\x21\x1f\xeb\x65\xed\x5e\xd6\xe7\x60\x42\xbb\x98\x82\xe3\xcb\xea\xb7\xae\x78\x1b\x9d\xff\x49\xe0\xf1\xe5\x0a\x34\x5b\x5e\xce\xa4\x31\x1b\x81\x85\x1a\x00\xee\x25\x1a\x17\xba\xc1\x03\xa3\xe3\x96\xc1\xc2\xc6\x54\x67\xe6\x21\x56\xd0\x4d\x6f\x45\xad\xa0\x97\x4a\xdd\x42\x5c\x41\x10\x5b\x54\x3d\x36\x18\x62\x38\x8d\xb8\x02\xde\x10\x93\xb2\x90\x5f\x4a\xb3\x88\xc4\x39\x83\xe4\xb6\xd0\x98\x92\x58\x40\x6d\x18\x7b\x88\x15\x28\x69\x19\x12\xbd\x41\xae\xd1\xde\xe7\x78\x55\xfb\xee\x2d\x4b\x6c\xd4\xa0\xd3\xdf\x20\xe6\x81\xb1\x4b\x36\xca\xf5\x67\xe4\x17\xd0\xa0\x87\x1f\x9f\xb7\x48\x5e\x8d\x3a\x4e\x5b\xb1\x61\xa5\x7c\x9e\xc7\xd1\xe8\xc8\x27\x72\xd2\x4e\x3c\x7c\xec\x1f\x9b\x1f\xba\x6f\xe1\xda\xcd\x73\xa7\xcc\xba\x97\xcc\xe5\x59\x4a\x1d\xf7\x1a\x1f\x05\x1f\x0c\x87\x88\x17\x12\x21\x81\x37\x31\x29\x55\x20\x42\x68\xb3\x70\x64\x9f\xc5\x40\x26\x6a\x36\x25\xc9\x6e\x88\x61\xbb\x55\x4a\x46\x7e\x82\x2c\xd3\xad\x31\xac\x0d\x4a\x39\xc8\x2f\x25\xdb\x45\x1b\xf6\x86\x41\xb2\xb8\x44\x9b\xa4\x4d\x0f\x27\xe0\x46\x2b\xb7\xcb\xe9\x70\x6a\x68\xa6\x8c\x71\x8a\x0e\x1b\x71\x54\x21\xb7\xc3\xe9\xd0\x08\xbe\x2c\x98\x85\xca\x7f\xfb\x6d\xed\x6a\xe6\x60\xcd\x8e\x9d\x47\x8e\xec\xdc\x51\x73\x90\x79\x74\xfd\x2f\xbf\xc9\xc7\x99\xdb\x10\x8b\x4c\xe8\x4e\xb4\x64\xe1\xfb\x82\x20\x3c\x11\x91\x7f\x8d\xca\x57\xde\x96\x7f\x95\x9e\x14\x78\xe1\xe8\xc3\x2b\xd0\x70\x60\xa8\x5c\xea\x78\x0c\x3a\xb0\x43\x49\x5c\x2a\xfa\x84\x54\xec\x44\x14\x8e\x44\xee\x01\xeb\xad\x04\x6c\x50\x7b\xe2\x54\x4d\xb6\xe8\xf5\xd0\x1c\x81\x37\x2f\x14\xb4\xb5\x47\xa5\x8c\x1f\xd5\xa0\x43\x28\x03\x0d\x95\x9f\x95\xbf\xba\x7c\xf9\x44\x2c\x76\xe2\x32\x8f\xe5\xed\xf2\xf9\xb7\xe5\x98\xfc\xcc\x66\xa4\x7f\xef\xf8\x29\xa4\x57\x6d\x22\xb9\xf7\x7d\x3c\x06\x03\xf4\x88\xdf\x59\x97\xb8\x33\xc7\xc6\x6a\x78\x55\xf5\x78\x96\xaa\x1e\x19\x44\x22\x7c\xa7\xa1\xbd\x8e\xd5\xf9\xb1\x3e\xa8\xc6\xf1\xf1\xe0\x5d\x0d\xdc\xd5\x57\x0d\xfb\x5a\xbd\x9e\xa9\xaa\x1f\xcb\x22\x1e\x57\xc9\x2d\xaa\xea\x7f\xdb\xdc\x78\xdf\xd9\x94\xe6\x4e\xea\x7d\x1b\xef\xa9\xe5\xe9\x3d\xb5\xac\xea\x63\xae\x77\xcf\xf8\x0d\x0d\xd7\xdc\xb0\x86\x7d\xab\x9e\x61\x36\xd5\x4f\x20\x37\xd3\x57\xd5\x3f\xa0\xde\x6b\x8e\x52\xc7\xfd\x83\x8f\x82\x07\x66\x43\x24\x03\x54\xa6\xaa\x0a\x62\x64\x63\x11\x23\x55\x10\xa3\x56\xe7\xaf\x49\x4a\xce\xe0\x9a\xab\xbf\xd5\x10\xc3\x56\x9a\x3b\xc7\xba\x20\x85\x04\x9a\x60\xc4\x45\x93\xb7\xae\x24\x9d\x9f\xce\x01\x97\x55\xb4\x49\x5c\x46\x38\x8c\x53\x45\x2c\x84\x41\x4a\x22\x7a\x94\x1a\x96\x8c\xc9\xa2\xad\x09\x66\xe5\xdc\x1a\x1f\x35\x41\x4e\x51\x75\xfc\xa2\xb7\xcc\x2b\x0a\x9c\xcf\x03\x73\x50\x87\x2b\x97\x51\x06\xcb\x1c\xd0\xbd\xb4\xf3\xb9\x77\xbf\xc1\x0f\x6c\xcd\x92\xdf\x60\xb8\x52\x59\x79\x57\xbe\x22\xbf\xc0\x74\x46\x85\x48\x87\xfa\xfd\xfa\xa6\xb0\x60\xc7\xe5\xc3\xf2\x07\x6f\x5e\xe9\x5c\x80\xfa\x54\xd5\x9f\xaf\x78\x18\xf5\x53\xf9\xc9\x23\x2a\xc7\x8e\x71\xeb\x11\xc7\xa8\x98\x0f\xd5\xe8\x59\xca\x51\x7d\xa3\x14\x0d\x74\x5d\x04\x1b\xd4\x94\x32\xa7\xc2\x9b\x84\xfc\x42\xa2\x57\x0c\x89\x3e\xd1\x2b\xd6\x44\x99\xb7\xa2\xd1\xfa\xf6\x3c\xae\x9f\xc6\xac\xbd\x5c\xc1\x2c\xae\x9f\xa7\xf2\xf4\x75\x00\xb4\x84\xe6\x2d\xbc\x4d\xe4\x77\x83\x7c\x87\x18\x12\x5f\x3f\x4a\x8c\x91\xfa\xdb\xce\x4a\x1d\xfb\x16\x8f\xc1\x4e\x74\xce\xdc\x10\x67\x99\x1b\xe2\x2c\x1d\xbd\x94\x23\x80\x6d\xb5\x34\xdc\x8d\xc7\xba\x06\x55\xe9\xd5\xb8\xc7\x4c\xbc\x04\x2f\xda\xb0\xad\x69\xac\x23\x86\x44\x87\xe0\xcb\xca\xcb\x2d\x2b\xed\xcc\x1c\x5c\x3e\x6f\xea\x8a\xe8\x6f\xd1\x0f\x1e\x98\x8d\x1e\x11\x96\x3e\xb4\xee\x7e\x2e\xfd\xca\xd7\x6f\x7d\x3b\x79\xdc\x21\x6d\x5c\x07\x79\x0f\xb5\x87\x09\x9e\xe9\x1a\x79\xc6\x9a\x28\xcf\x58\xc2\x33\x4b\x43\x4a\x85\x09\x4a\x56\x62\x7e\x59\x13\x35\x7b\x18\xa9\x31\x09\xa1\x30\x84\x42\x6e\x1d\xd2\xf8\x90\x4f\xac\x89\x6e\x62\x74\x9f\xb2\xf5\xef\x30\xc3\xd9\xba\xfa\x9f\x77\xf3\xb8\xfe\x01\x66\x09\x5f\xdf\xad\xde\xc9\x33\x8f\xd5\xdf\x15\xd7\xff\x02\x9a\x2f\x89\x5b\x7b\x72\xa7\x38\x0f\x85\x04\x0f\x23\x2c\xd5\x78\x96\x6f\x48\x94\x50\xe1\x38\x6b\xa2\x8c\xc4\xe3\xcb\xe7\x1b\xe7\x92\x40\xe2\x69\xb1\xc1\xa6\x6b\x8c\xa1\x06\x4a\x12\x99\x4b\xd1\x10\x93\x2c\x96\x18\x16\x55\x66\x6a\x88\x2a\x5b\x25\xbd\x25\x86\xf5\x01\x6a\xdb\x45\x0b\x65\x2b\xd6\x8a\xd5\x0c\x6f\x34\x11\x7f\xac\xa7\x69\x42\x09\x01\x4d\x97\x98\x29\x3c\xa1\x94\x22\xa2\x1f\xf6\x3c\xe4\x43\x1a\xbb\x58\x73\x15\xbd\x27\xa0\xf7\xae\x46\x1d\xbc\x9c\xbf\x58\x2e\xe0\xed\x3c\xbe\x32\x92\xdb\x76\xb9\x82\xe9\xc4\x54\xa0\x2b\x77\x71\xab\x51\x7d\x75\xfd\x61\x68\xa6\xa7\xdd\x7f\xa7\xa7\x4d\x95\xd3\x60\x95\x38\x75\x94\x74\x75\x8d\x06\xf7\x0c\x8d\x01\xb5\xf1\x01\x49\xac\x2e\x31\x9c\x72\xa2\xae\x48\x43\xd4\xf5\xa0\x10\x8d\xd6\x77\x11\x78\x7c\xe5\x49\x86\x1b\x75\xb9\x82\x1b\xc7\x5c\x79\x52\xcd\x9b\xf1\xcc\xb5\x79\x33\x21\x91\x37\x13\xfe\x8b\xbc\x19\x01\x18\x04\xcd\x7b\x49\xbc\x69\x0b\x05\x6d\x65\x62\x29\x43\xdc\xc2\x0c\xd4\x11\x14\xa4\x45\x7d\xe4\x7d\xf2\x7f\x14\xf9\x8d\xe8\xc9\x3d\x2f\x7f\xf4\xf1\xdf\xf6\x9c\xa4\x5e\x40\x8f\x46\xc9\xdb\xe4\x7f\xcb\xf5\xf2\xbf\xe5\xa7\xd0\x08\x64\x38\xa1\x00\x28\xef\x20\xfe\x18\x02\x05\x8e\x41\xdc\x0f\xbc\x4b\xf3\x22\x76\xe8\xdc\xd4\x2a\xda\xd9\x58\x8d\xce\x40\xf5\x51\xd7\xdc\x1d\x18\x82\xc4\x23\x58\x90\x9f\x3a\x64\xe2\x11\x24\xbb\x41\x6c\xe6\x7c\x39\x9f\x37\x19\x35\xf8\x5b\xa6\x28\x86\x18\x59\x8e\xc9\x9b\xd0\x84\xf5\x6b\xd7\xad\x93\x37\xf1\xf8\xa7\x23\x6f\x7f\x5f\xff\x0a\xf3\xd5\xb6\xb9\x73\x9f\x56\x73\x8c\x49\x7c\x5b\x3e\x0a\x76\xf0\x42\x3f\x88\x88\x84\x57\xee\x04\xaf\x32\x08\xaf\xb2\xe8\x00\x1c\x06\xba\x28\x95\x12\xe7\x95\x0f\xf9\xa5\x14\x87\x68\x8b\x98\x45\x8e\xe0\x5b\xad\x28\x19\x4c\x04\xcc\xb9\x45\xc2\x40\x73\xc2\x9b\x52\xfe\xd1\x75\x03\x1a\x05\xdd\x88\x8b\x63\x86\xfe\xb6\x54\xbe\xd0\x7a\x6e\xa7\x1b\xb3\x72\xf5\xc5\x81\xb1\x07\x11\x72\xbb\x6f\xcc\xcf\xef\xf9\x97\x20\x05\x7c\x30\x36\xae\x6d\xd6\x78\xe4\xee\x63\x63\x35\xc9\xa9\x94\xa5\xc9\x84\xa5\x2a\x32\x48\x21\x21\x5f\x10\xa7\xa8\x51\x5f\x66\x90\x84\xba\x98\x57\xc1\x81\x23\x45\x9d\xf2\x46\x11\x8b\x61\x90\x92\x41\xc5\x3b\xa9\x14\xef\xf8\x1a\x59\x1e\x8f\x6f\xd3\x91\xc3\xe5\x76\xfa\x8a\x11\x5d\x30\x6a\x26\x02\xcb\x8f\x57\xef\x9d\x3e\x67\x62\x46\xce\x3b\x79\xae\x15\xf7\xc8\x6b\x51\xab\xe7\xd6\xad\xd9\x28\xff\x8d\x7f\xe9\x9f\x27\xa6\x3f\xdb\x32\xef\xa5\x07\x97\x77\x9d\x92\x95\x94\xb5\xa4\xfb\x43\xb3\x1e\xad\x5f\xce\xda\x16\x2c\xba\x7f\x29\x20\x1a\xd3\xaf\xe5\xa3\x50\x04\x73\xae\x9f\x43\x14\x09\x65\x69\x6c\x2c\x92\x26\x92\x7d\x69\x49\x04\xf3\x14\xd3\xd5\xc5\x4c\x43\x0c\x17\x26\x56\x17\x33\x55\xb3\x9f\x1c\x94\x72\x88\xd6\xb8\x83\x41\x29\x40\x84\x98\x29\xda\x6a\x78\xa3\xe8\xcb\x27\x73\x3f\x47\xc4\x8e\x30\x48\x69\xbc\x68\xab\x06\xb3\x3b\xe7\x77\x6b\x88\xb9\xd9\x65\xa5\xd9\xa1\xa0\xdb\xa5\x49\x40\xa3\x86\x45\x44\x8e\x98\xe0\xf2\xd2\x71\xcc\x81\x53\x9b\x36\xbc\xf8\xf8\xa1\x7f\xc9\xf5\xc8\x7d\xe6\xc7\xd5\xcb\x11\x73\x60\xd7\xd6\x75\x5b\x76\x1f\xfa\xee\x27\xf9\xec\xb9\x4f\x9f\x7f\x06\xa1\x2d\xc2\xca\xb5\xf3\xa7\x8c\x59\x5a\x5c\x5e\xfb\xf4\xee\x6f\x16\x2f\xd8\x29\x08\xc2\xc2\xad\x0f\x4d\xbe\x73\x41\x49\xf8\xcc\x0e\x5c\x3b\xeb\xee\xd7\x79\xd5\xce\x65\x01\x70\xab\x29\x46\x6e\x03\x11\xa1\x61\x76\x00\x4b\xc2\x4f\x1a\xd6\x0a\xb5\x64\x1e\x44\x78\x9a\xed\xe5\x59\x9d\x3f\x22\xd0\xe5\x57\x01\x74\xfe\x26\x11\xa2\x57\xf4\x89\x59\xdc\x14\xb9\x30\xca\x3b\xab\xaa\x2e\xd7\xf1\x4e\x7a\xfd\x75\x4a\x1d\xf7\x19\xb5\xa3\xe5\x10\xb1\x10\xfe\x0a\x71\x9b\x8c\xf5\x0d\x66\x94\xc4\xcc\xac\x95\x5c\x8c\xe6\x41\x88\xe1\xd4\xb1\x34\x81\x4c\xcd\x43\x48\x6c\x74\x44\x9c\x2f\x2b\x7b\x5d\xf4\xc0\xe6\xa7\xdf\x8e\xca\xef\x5c\xfa\x49\xfe\x10\x7d\xc8\x9e\xbe\x9a\xb3\xf3\x85\x17\x76\x92\xcf\x1f\xae\xd6\xab\x74\xb9\x00\xb8\x4b\x14\x0b\x79\xe3\xd9\x50\x20\xf7\x14\x42\x04\xff\x50\x90\x23\x81\x2e\x91\x07\x0a\x21\x77\xa8\x9c\x60\x7e\x57\x2d\x9a\xe3\x15\xbc\x68\xce\x87\xf5\x5f\xef\xe2\xf1\x95\xfd\x77\xdf\xcd\x75\xbf\x5c\x01\x08\x5a\x01\x08\x7f\xe7\x31\x38\xe1\x03\x35\xef\x13\x31\x5b\x1c\xa1\x50\x88\x5e\xb6\x06\x09\x1a\x62\xdc\x43\x08\xbb\x28\x41\xc8\x10\xc3\xc8\x2a\x19\x91\x9f\x2e\x40\xb9\xd5\x98\xee\x8d\x3d\x3f\xcf\xa6\xa9\x2c\xb0\x62\xe7\x61\x33\x46\x56\xcc\x1c\xde\xdf\x7e\xdb\x0f\xaf\xa8\x49\x4b\xa1\xd8\x8c\xf9\xc3\x92\xdd\x75\x89\xc7\x8e\xc3\xfb\xdf\x9c\xf8\xc3\x13\xf4\x74\x4b\xb1\x19\x5b\x0f\x4b\x5a\xf7\x25\x1e\x6b\x0e\xef\xef\x30\xee\xe7\xb7\xd5\xd0\xd0\x68\xc5\x86\xc3\x3c\x36\x59\xb1\xf9\x30\x0b\xfb\x18\x5e\x6b\xb0\xda\xd5\x55\x7a\xd4\xc9\xc8\xf0\x82\x46\x6b\x30\x5b\xac\x76\x87\xf3\xda\x05\x7c\x09\x9c\xa2\x2d\xc2\xe9\x44\x35\x3a\x0e\xd9\x33\x11\x61\x80\x3b\x54\x6e\x0f\x21\x1f\xca\xf3\x69\x90\xaf\xd5\x91\x33\xa9\x42\x1e\x32\xbc\x88\x4c\xf9\x42\xfa\x27\x51\x79\x3b\x96\xbf\x4c\x11\x92\xe5\xcf\x30\x8f\xaf\xf6\xfc\x1b\x7a\x99\x7d\xe5\x6a\xcf\xd7\x5e\x63\x5f\xb9\x5c\xc1\x5e\x5c\xbc\xf8\xaa\x99\xe0\x10\x00\xae\x96\xfa\xa2\xdc\xb8\x75\xd0\x86\x68\x22\x3a\xee\x8b\xd4\x48\x8b\x21\xbe\x86\xd3\x53\x5f\xa3\x43\xea\x7f\x9f\x0e\x75\x46\x1f\xcb\xc1\x0b\xa8\x3f\x1a\xf8\x83\x1c\x44\x1f\xd7\xc9\xcf\xc8\x4f\x33\x67\x98\x0f\xea\x8f\x31\xad\xeb\x8b\xeb\xb3\x98\xce\xf5\xaf\x03\x22\x71\x1d\x77\x8a\xc7\xa0\x25\xc8\x5e\xd3\x20\x5b\x36\x84\xb0\x2e\x80\x35\xb5\x14\xc9\xeb\x09\xa2\xd7\x50\x0f\x07\x12\xa8\x1b\x84\x52\x1d\x0a\x21\xd1\x27\x3a\xbe\x44\x0f\xa0\x07\xbe\x94\xd1\x11\x1e\xd7\xa7\x31\xdf\x5c\xad\x90\x81\x31\xa9\xba\x33\x12\x80\x9b\x4a\x75\xa7\x38\xe1\xfb\x13\xd8\x96\x55\x01\xb4\xaa\x40\x1a\x35\x3b\x2e\x71\x44\x57\x05\x5a\x00\x83\xbc\x65\x5e\x27\xf2\x3a\x47\xb2\xfa\x7a\xc4\x9e\xbd\xfa\x0b\x5b\xbc\x96\x5b\x5c\xb5\xea\xca\xec\x38\xae\x58\x23\x1f\x63\xac\xc2\x42\xd0\x40\x19\x60\x4d\x80\x58\x1b\xcc\x05\x24\x86\x4d\xe4\x90\x6a\x34\x46\x30\x70\x7e\x82\x8a\x78\x43\x2c\xf1\x8d\x0d\x26\xa6\x9a\xe8\x75\xfa\xc4\x90\x73\x0d\x7a\xf0\xc0\x01\xf9\x98\xe6\x95\xaa\x4b\xf3\xab\x00\x41\x9e\xb2\x98\xbd\x29\xb1\xe6\x05\xcd\xd7\xbc\x88\x48\xf3\xf6\x33\x23\xf6\xf3\xf8\xd2\x3f\x00\x81\x41\x3e\x86\x56\xd1\x31\x74\xa0\x63\xa0\x93\x3d\x40\xe2\x04\x3a\x06\x4d\x2d\x66\x83\x35\x82\x7a\x63\xc1\xaa\x2a\x73\x00\x0b\xd6\xc4\x60\x34\x89\xcc\x90\x3b\x24\xfa\xca\xbc\xa2\xd7\x70\xf0\x20\x5a\x24\xcf\xdf\x22\x2c\xaa\xfa\x4f\x4f\x95\xce\xf6\xcc\x27\x6c\x12\xe5\x61\xc3\x1a\x5c\x9c\x6d\x25\x2d\xed\x34\xbc\xce\xf3\x69\xd8\xf6\xc8\xff\x30\x2a\xd8\xf7\xac\x55\xb0\x3e\xc3\x7c\xc2\x7c\x54\xdf\x02\x3d\xd3\xbd\xbb\x7c\x87\x7a\x0d\x4e\x19\xc7\x6e\xa3\x75\x97\x29\x4d\xf0\x1c\xd9\x68\x42\x5c\xc8\xeb\xf4\x72\x6c\xd5\xd5\xb1\x9b\xe9\x6f\xfa\x73\xaf\xa1\xf3\x7c\x14\x38\xc8\x02\x75\x01\x84\xd5\x83\x95\xf3\x23\xcc\x53\xee\xb2\x46\xd0\x73\x7e\x49\x50\x07\x52\x1e\xb2\xfb\xfa\xb3\xdf\xbd\xb4\x95\x3f\x24\xc8\xbf\x12\xff\x36\x49\xa9\x63\x7f\xe1\xfa\x81\x0f\x8a\x61\x69\xbc\x42\x80\x86\xc2\x79\x5c\x2c\x62\x47\x40\x63\xa8\x88\x96\xae\x82\x69\x8d\x3a\x7f\x0d\x5b\xe8\xb5\x13\x4c\xab\x89\x21\x1c\xa0\x93\x3f\xdb\x10\xc3\xd9\x56\x6c\x20\x9e\xc1\x64\x8d\x61\x53\x40\x32\x58\xc9\x2e\x9a\xfb\xe5\x0a\x82\x41\xc9\x6d\x88\x49\x25\xc8\x2f\x65\x18\x44\x5b\xc4\xee\xcd\x23\xae\xdd\x2d\xe2\xd4\x30\x48\xac\x57\xb4\x49\xee\x0c\xd5\xd7\x5b\x5c\xf1\x44\x6f\xdb\x86\x74\x55\x5e\x69\x59\x69\x39\x4d\x66\x89\x0e\x97\xdb\x57\x8c\xe2\x39\x9b\x78\xda\xd3\x97\x25\x4c\xba\xf2\x51\xed\x3d\x93\xee\x9c\x7d\x80\x99\x3e\xeb\xd5\x57\xce\x1a\xad\xef\xe8\x0d\xa8\x5c\x1a\xb7\x4b\x8a\x0e\xad\x9c\xbc\x27\xe5\xf3\xd9\x6b\x50\x49\xd5\x4b\x93\xef\xbc\x6b\x64\x57\x41\xe0\xef\x1a\x3e\xea\x35\x5c\xff\x5b\x9b\x29\xa5\x2d\xfb\xe4\xf6\x9b\xb8\x77\x7d\xcf\x81\xd3\x7a\xe0\x39\xc0\xc0\x1a\xa5\x8e\xf3\x0b\x49\x20\x42\x66\xc2\xd7\x47\x4c\x84\x17\x4e\x21\x16\x11\x08\x2f\xd2\xc8\x06\x5d\x5b\x13\x10\xf1\x8b\x1e\xca\x00\x9b\x0a\xea\x45\x73\x0c\xdb\xac\x52\x52\xbc\xa0\xcb\x8b\xfc\x92\x4d\x14\x6d\xd8\x1a\xc6\x49\xa2\x24\x50\x18\x93\xe6\x54\x77\x08\x22\xb5\xc4\x04\x8a\xd3\xb5\x07\x51\x5d\x4f\xc9\xd3\xd8\xe3\xb9\x5d\x75\xfd\x61\x4d\x34\xb4\x71\xec\xb1\xb3\x5f\x46\x27\x6f\x2d\x4d\xca\xce\xbd\x7f\xf8\x23\xcb\x96\xaf\x1c\x36\x2f\x47\x48\xaa\x7f\xba\xe7\xcd\xf2\x61\xf9\x8a\xf3\xbc\xfc\xe5\x80\x5b\xd7\xa0\xb2\x8a\xa1\x47\x9f\x71\xee\xaf\x1b\xd2\x27\x3e\xa7\x95\x3a\xf6\x22\x95\xeb\x8d\x72\x1b\xe8\xaf\xe6\x36\x2c\xcd\x73\x1b\x5c\x22\xb7\xa1\x4f\x8d\xd7\xbf\xd8\x9a\x3b\x70\x82\x5a\x12\xb9\x0d\x41\x23\x68\xb2\x98\x91\x57\xea\x0e\xcd\xb9\x17\x31\x91\x95\x93\xab\x1e\x5a\xf2\xe4\xa8\x0d\x12\x83\x1e\x58\xf4\xc2\x85\xcb\x8c\xb6\xe0\x5f\xa8\x6c\xfa\x94\x2d\x3c\x2f\x8c\x7e\xe4\x8b\xa7\x0b\x9e\xfd\x7c\x6e\xa5\xc0\xf3\x0f\x4f\x98\x82\x50\x29\xd1\xcf\x51\x4a\x1d\xfb\xef\xb8\x4c\xa6\xaa\x98\x5b\x75\xab\x44\x26\x5c\x42\x26\x1c\x95\x09\xa7\x6d\x2e\x13\x55\x18\x58\x13\x4c\x64\x3d\x0c\xe6\x18\x36\x04\xa8\x64\x92\x6c\xc4\x22\x5b\xc2\x61\x6c\x10\xb1\x31\x0c\x92\xd3\x40\xb3\x84\x12\x97\x96\x88\xb7\xcb\xac\xb6\x50\xd0\xe5\x26\x71\x41\x5e\xd3\x54\xbb\xa8\xc6\xdf\xa3\xbe\x38\x7e\xe7\xba\xd2\xe8\x76\x77\xd9\xe6\x71\x47\xcf\x46\x1f\x5e\x55\x39\x27\x37\x77\xee\xa0\xd5\x4b\xd1\xff\x39\x11\x8f\x3a\x75\xef\xc2\x0c\xb8\x74\xee\xa1\x9b\xfb\xa1\xcc\xf3\x3b\xa2\x15\x3d\xd1\xa5\x2e\xb7\x9c\x7f\x8d\xe6\xc2\x95\x3a\xf6\x7b\xae\x1f\xb8\x20\x13\x46\x42\xc4\x41\xc8\x31\xb1\x71\x72\xd2\xd9\x58\x4d\x92\xce\xd1\x90\x42\x50\xc9\xd1\xdb\xe8\x82\xad\x9e\x4a\x85\x46\x34\x84\x88\x64\xbd\x68\xab\xd6\x71\x26\x07\xc1\x5a\x1a\x51\xb2\x8a\x44\xc7\x4c\x0e\xd1\x86\xc5\x30\xd6\x89\xd8\xaa\x0a\x08\x42\x41\x5b\x3a\xf2\x6a\xa8\x6e\xd1\x94\x66\x16\xd8\xdd\x5e\x75\x8a\x8d\x46\xf6\x03\xa7\xcf\xd6\x77\x66\xd9\x4d\xcb\xc7\x6c\x2c\xef\xdb\xe6\xf5\xa5\x5f\xc9\xff\x7e\x8f\x41\xbf\x3c\x70\xdf\xe8\x95\x8c\xb6\xf0\x5f\x28\x24\xff\xe7\xb3\xfb\xf9\x27\x8f\x87\x83\x0b\xc3\x37\xa3\x22\x34\x8b\x4f\xb9\xe7\xc9\xe7\xa8\x9e\xb5\x06\x60\x8e\x0b\x45\xe0\x86\x4a\x88\xb8\x28\x9e\x42\xe0\xc7\x22\xad\x2f\xc4\xf6\x20\xb1\x06\x02\x81\xfb\x49\x01\xec\xa2\xb5\x1b\x4e\x43\x0c\x5b\x83\x4d\x2a\x08\x23\x2e\x27\xd5\x4a\x82\xaf\x92\x89\x9f\x31\x21\x9a\x97\x24\x93\x44\x47\x09\x08\xa9\x8b\x3e\x0d\xcb\x75\xea\x92\x6c\xeb\x5d\xfb\x9e\xce\xea\x56\x90\x64\x0b\xa5\xdd\x36\xf0\xcb\x2f\xa3\xec\xf3\x6b\x97\xef\x3d\x68\xd0\x3f\xce\x09\xe3\x47\x2d\x5f\x7b\xb5\x92\x7d\x5e\xcd\xfb\x8f\x91\xfb\xb0\xf5\x5c\x3f\x48\x07\x3f\xcc\x8a\xe7\xe1\xbd\x42\x2c\xa2\x45\x10\x9f\x07\xf9\x02\x35\x5b\x0e\x2e\x86\x70\x21\x65\x78\x86\x81\x16\xd0\x11\x24\x93\xdd\xa0\x3f\x5a\x53\x0c\x6b\x03\x52\x11\xb1\x64\xc4\xa3\x13\x7e\x63\xb7\x58\xcd\x39\x4c\xa9\x44\x04\x5a\xa2\x39\x20\xa5\xaa\x02\x90\xf2\x4d\xa2\x4d\xd2\x24\x85\x9b\x28\x53\xb9\x9a\x5b\xb8\xfe\x1a\x4e\x5c\xb1\xc6\x7c\x73\x7c\xfc\x93\xa5\x49\x5b\x2e\x7e\xd3\x6f\x5f\xb7\x60\xd9\xe3\xbd\x1e\x5d\x5c\xb6\x7e\xc4\xdb\xdf\x44\x57\xac\x1a\x32\x27\x2f\xf7\xbe\xdb\x56\xad\x8c\xab\xd8\x80\x7e\xab\xae\x1c\x7e\xef\x0b\x7f\xce\x13\x19\x39\x8b\x1f\xbe\xaf\x6b\x37\xe4\x89\x3d\x73\xf4\xd6\xde\xe8\x62\xb7\x5b\x2f\xbc\xaa\xfa\x5f\x00\x0e\x84\x24\xb0\x43\xdf\x38\x3e\xd1\x87\x54\x5b\x66\x21\xb6\xcc\xd2\x68\xcb\x1c\x0d\x73\x9f\x09\x92\xe9\x6f\x88\xdb\x31\x27\x09\x9d\xed\xd4\xe3\x83\x64\x81\x38\x86\x4c\x58\x2e\x97\x53\xf4\xa9\x35\x1f\x1a\x71\x4d\xb4\xf5\x33\xa3\xf7\xbe\x11\xbd\x7b\x66\xff\x87\xfc\x42\x52\xfd\x63\xfd\x06\xbf\xf7\x71\xfd\x50\xe6\xf9\x87\x17\xf6\xed\x7c\xf5\x4b\x2a\x8b\x6d\x00\x68\x8c\x90\xa4\xd6\xf2\x26\xe2\x53\xa2\x31\x7f\x61\x61\x49\x0c\x89\x6c\x59\xc8\xb9\x2d\x1a\x8d\x72\x6d\xae\x1c\xe5\x6f\x39\x7e\x9c\x5c\x53\x79\x5d\xee\x83\x66\x0a\x49\x60\x01\x3b\x84\x80\x8a\x95\x48\x93\x13\x68\x81\x2d\xf1\xf6\xd6\x80\x24\xea\xd4\xa0\x57\x53\x8b\xad\xaa\x40\x6d\xc1\x78\xfa\x93\x55\x85\x91\x48\xfc\xe4\xda\xcb\x42\xce\xce\x66\x73\xa9\x78\x53\xdf\xe8\x9e\x27\x32\x43\xef\x46\xe5\x3b\xaa\x78\x4d\xe5\x68\x6e\xdd\x95\xa9\xcf\xed\xd3\x09\x4a\x34\x4a\x78\xfb\x28\x00\x97\x26\x24\x81\x11\x6e\x6a\xc4\x7e\x3c\x22\x3e\xd8\x00\xbc\x9a\xf8\x89\xb0\x06\x9a\x7e\xa1\x2c\x36\x51\x16\x1b\x55\x77\x61\xa6\x39\x20\x43\xdc\xda\xc4\xb3\x3f\x3a\xe4\x43\x3e\xf1\xd1\xe8\x7c\x94\x7f\x41\x5e\x8d\x9e\x3b\x27\x6f\x5f\x28\x24\x5d\x9d\x83\x76\xcb\x8e\xfa\x08\xfa\x45\x36\x01\x6a\xc2\xc3\x34\x68\x80\x07\xd7\x4f\x99\x6d\x8b\x0a\x49\x97\xce\xa9\x7a\x20\xdc\x45\xfd\xc1\xe4\x38\xb6\xb0\xa6\x84\x42\x94\xf5\x54\x1d\xb0\x31\x24\x65\x0a\x31\xec\x0c\x26\xbc\x80\xcf\x10\x93\x18\x4b\x0c\xfb\xe8\x72\x14\x0d\x6b\x53\xd4\x8a\x52\xab\x21\x46\xdd\x81\x8f\xa1\xca\x20\xa5\x10\xa5\xd0\x85\xb1\xa8\x5a\xd2\xcc\x66\x89\x15\x37\xd5\x12\xf7\x35\xba\xd2\x54\x6b\xb0\xb9\xec\x99\x29\x53\xaa\xf2\x42\xcf\x4f\xdf\x79\x38\x3a\x6d\xea\xd8\x79\x86\xa3\x33\x26\x0d\xbd\x27\x93\x6b\xb3\xba\xef\xa0\x31\x63\x6e\x9f\xf2\xf5\x37\xf5\x73\x99\xe5\x4f\x3d\xb4\x72\xb2\xb6\xfe\x56\x66\xf9\xa6\x55\xbd\xbb\x5c\xfd\x02\x12\xfa\x4d\xe7\xb6\x1d\xfa\x35\xea\x77\x03\x55\x44\xc9\x9b\x68\x36\xa5\xe7\x1a\xd5\xb6\xab\x44\x10\x37\x70\xad\x82\x5f\x3b\x68\x32\xd4\x56\xcf\x4c\x78\xe9\x70\x74\xc6\x3d\x83\x16\xe7\x71\x6d\xb6\xdf\x76\xe7\xc9\xda\xfa\x41\xcc\x73\x6b\xe6\xf4\xef\x71\xb5\x8e\xe8\xf7\x48\xa5\x8e\x2b\xe0\xfa\xfd\xbe\xb6\x0a\xfd\xb5\xda\x2a\xce\xa0\xe6\x88\xa8\xd1\x86\x74\xe4\x00\x5f\x16\x34\xaf\x1a\x1d\x89\xb8\x2f\xbe\x44\xbc\x7c\xf5\xec\x59\xf9\x4a\xf4\xb1\x35\xab\xd6\xae\x5b\xbd\xea\x31\x46\x74\xfd\x84\xca\xe5\x13\x3f\xbb\x2e\xca\xef\xa2\xb2\x9f\xf7\x9c\x3d\xbb\xc7\xb5\xfb\xab\xaf\x76\xab\x36\x70\x8d\x3c\x82\x6b\xc1\xf5\xa3\x7e\xf4\x0e\x88\xc3\x1a\x12\x99\x36\xb0\x2a\x4d\x88\x61\x08\x24\x1c\x8e\xa8\x4e\x10\xc6\x4e\x93\x7d\x4d\x31\x8d\x18\x67\x58\x92\x28\x99\x04\xe2\x6f\x9c\x26\x15\xd3\xa4\xa9\x98\xc6\x1e\x67\x5c\x03\xa6\x49\x46\xcd\x31\xcd\xc6\xcc\xb2\xad\x13\x8f\x7f\x71\x36\x3a\x66\x63\x59\xce\x9c\xc1\x2b\x1f\x7d\x6c\xd5\xa0\x39\x39\xf2\x08\xfe\xd3\x95\xfd\xfa\xcb\x6f\xc8\x97\x09\xa6\xe9\xd2\xa5\xfe\x47\xa6\xba\x4b\x9f\x93\x4f\x3b\x5f\xf9\xbe\x6f\x17\x4a\xc3\x28\x79\x04\x7b\x3e\x4e\xc3\xd8\x78\x74\x4d\x68\x68\xb4\xe3\x69\x2c\x71\xf0\xd7\x60\x00\x83\x5a\xf0\x9c\xb0\xe1\x76\x6a\xc3\x09\x25\x86\x06\x0c\xa0\x15\xa9\xe1\x76\x5a\x54\x0c\xa0\xbd\x16\x03\x94\x87\x44\x9f\x78\x7d\x0c\x30\xfa\xf1\xd2\xf4\xc7\xa3\xa5\xab\x87\x1d\x3d\x1b\x5d\xba\xf2\xd6\xbb\xf3\xf2\xee\xbe\x65\xd5\xb2\xb8\x81\xee\xd3\x73\xc1\xe5\x5c\x46\x68\xdf\x81\x60\x80\x77\x7a\xde\xc4\x64\xb5\xef\xfe\xe3\x6b\x71\xbd\x65\x76\x73\xfd\xc0\x42\xb4\xa4\xc1\x0a\xaa\x92\x30\x68\x63\xb4\x6a\x49\x5d\x39\xa3\xa5\x40\x64\xda\x59\x54\xc6\x83\x84\x0c\xd7\xea\xa8\x5b\x93\xa7\xea\xa7\xbd\x78\x69\xa5\x2b\xdf\x94\x3a\xb6\xdf\xe4\x74\xae\xcd\xd6\x81\xc3\x35\xdc\xcb\x42\xef\x2e\x57\xaf\x90\x7b\x4e\x55\xea\xd8\xe3\x5c\x3f\x28\x82\xd9\x37\xc8\xfd\xa0\xff\x25\xf7\xe3\xb6\xc6\xd4\xd4\x4f\xa1\x68\xab\xe1\x0d\x22\xad\x15\x23\xf0\xde\x97\x48\xfd\x98\xdd\x39\x85\x89\xd4\x8f\x6a\x6a\x13\xe5\xe3\xd7\x4f\xfd\xc4\xb3\xef\x53\x99\x03\xfc\xda\x51\x13\x67\x8f\x5e\x11\x7d\xfb\x6c\xcd\xc1\xe9\x93\x11\x73\x60\xf6\xa8\x89\xe3\x86\xae\x38\x79\x2c\x76\xe0\xef\xb3\x67\xa0\x5e\xc2\xc4\x91\x83\xba\xdd\x34\x30\xd3\xbf\x6e\xc1\x92\xfd\x23\xef\x58\x2c\x08\x42\x8f\x19\xb7\xdf\xd4\xa9\x77\x7a\xe1\xc6\x05\x8f\x46\x26\x8e\x59\x22\xc4\xf3\x3e\x4a\x1d\x33\x89\xef\x08\x6e\x18\x01\x11\x3b\xa1\xdd\x28\xa8\xda\x8f\x79\x15\xab\x68\x82\x89\x5a\x53\x8e\x90\xdd\x80\x57\x12\x0b\x47\xae\x86\x5a\x53\x97\xae\x39\x5e\x31\xda\xd5\x09\x00\x22\xb6\xa8\x78\x45\x54\xcb\xc6\x54\x5d\xa1\x78\x2b\xb7\x4c\xcc\xda\x13\x3d\x79\xb2\x63\xa9\xd8\xc2\x9a\xe2\x1a\xe4\x9f\xb3\x9a\x7d\x7e\x2d\xe2\xe5\x2b\x6b\xeb\xef\xba\xb9\x83\x56\x58\x6a\x73\x3f\x56\xc5\x3c\x46\xc6\xfa\x88\x52\xc7\x5e\xe5\xda\x80\x1d\x06\xaa\x33\x55\x4d\x9f\x0a\x89\x01\xeb\x43\x09\x9b\xd6\x3c\x91\x84\x8d\x56\xc9\x64\xa1\x48\xc6\x99\x48\x29\x89\xb4\x54\xcf\x4c\xb4\x46\xa0\xa9\xf9\x26\x09\xa6\xf2\x06\x68\x9b\xfb\x48\x74\xdc\x94\x89\xcb\x7d\x51\xc9\x14\x7a\x6a\xa2\x74\x14\x1d\x60\xe6\xd7\x2f\xdc\xbb\x68\x50\x3f\xd6\x78\xe5\xe8\x53\x83\x87\x7f\x45\xc6\x55\x0c\xc0\x7e\xc3\xb5\xa1\x15\x1c\xf1\x1c\x13\x6a\xc8\x31\x61\xa1\x56\xd2\xd8\x62\xd7\x4d\x35\x91\x80\xbc\xf8\x04\x02\x51\xb0\x5f\x3a\x2e\xcf\xdc\xc0\xb5\xa9\xe7\x6f\xbe\x99\xb9\x72\xe5\x28\x95\x4d\x11\x00\xff\x19\xd7\x06\x9c\x30\x47\xcd\x35\x61\x73\x88\x5e\x5a\x12\x8c\xa1\x3f\xc9\x31\x75\x78\xfc\xe2\x36\x35\x39\xc4\x59\x69\x32\x49\x7b\x09\xdb\x0e\x43\x35\xc7\xdb\xec\x6a\xdd\x40\x62\x8b\xd6\x0d\x18\x91\x68\x93\xcc\x4e\x62\xb6\x68\x46\x88\x6d\xcc\x08\xd1\x71\xda\xe3\xa3\x65\xf3\x2c\x88\xf5\x15\x1d\xa9\x76\x0b\x69\x1f\x6f\xfd\x24\x53\x48\xdf\x7d\x44\x3e\xba\xed\xfd\x22\xc1\x7f\x6a\x1b\xd7\xa6\xbe\x62\xf1\x62\x06\xd7\x57\xac\x5d\xcb\xe0\x2b\x47\x99\x75\xaf\xa0\x97\xeb\xa7\x42\x82\x47\xff\xe4\xda\x5c\x93\x0f\x42\x7f\x9c\x0f\x4a\xa5\x8e\xdf\x80\x8a\xd1\x44\x79\xfb\xd7\x5f\x7f\xf7\x9d\xbc\x1d\x4d\xfc\xea\xa7\x9f\x18\x1f\xe3\x96\x67\xa0\x35\xf5\xb1\xfa\xcf\xd1\x13\xf2\x78\x40\x90\x22\xf7\x61\xcf\x51\x5e\x95\x82\xca\x7e\x3e\x84\xf5\x01\x49\x24\xd0\xd5\x15\xc0\x7c\xad\x24\x18\x29\x77\x1a\x0b\x8a\x40\x8c\xb0\x66\x4b\x23\x9d\x28\x44\x61\x67\x6e\x5e\x79\x2e\x51\x83\x8e\x28\xe5\xb3\x6f\x7c\x02\xd2\x9f\x96\xc3\x2d\x9e\x58\x94\xd4\xdb\xe1\x10\x06\x18\x3a\x56\xa4\x06\xb8\x36\xf5\x83\x97\xb1\x2d\xaf\x78\xa6\x3e\x6d\xe0\xab\x90\x30\xbd\xeb\x0c\x42\xe3\x70\x00\x76\x3f\xd5\x83\x66\xf9\x22\xf4\x5f\xe4\x8b\x86\x33\xbd\xea\x5f\x67\x43\xf5\x12\x33\x63\x05\xeb\x78\xf2\xe1\xab\xdf\xc5\xf3\x45\x1d\xe5\xf5\xcc\x36\xa1\x3d\x64\xc0\x40\xc0\x49\x81\x1a\xb7\x5a\x4c\x02\x01\x09\xf1\x31\xac\x0b\xd4\x68\xe9\x0e\x5a\x2f\x93\x4a\x71\xa2\x83\x28\x7e\x90\x56\xc6\x38\x52\xe9\x44\x04\x09\xdc\xa2\x4d\xb2\xa7\x86\xe9\xe2\x9a\x35\x8c\x75\x36\x89\x37\xa9\x38\x9c\x3a\x22\x3a\x29\xd3\x51\x63\x92\x5d\xa3\xe6\xd8\x3b\x4e\x1a\xbf\xe3\xad\xfc\x69\xb7\x0f\x1a\x34\x68\xd0\xed\xd3\xf2\xdf\xda\x31\x9e\xc9\x5c\x77\xff\x8c\x53\x2f\xfc\x58\x7e\xaf\x6f\xdf\x92\x53\x13\x9f\x2a\x2a\xde\x3e\xfe\xe4\x92\xea\xec\x59\xe5\x3f\xed\x3e\x39\x7d\x1e\x1d\xf3\x4b\xf2\x45\xd4\x97\xe6\xa2\xd2\xa0\xf9\x12\xa6\x29\x46\x5f\xf1\xb4\x94\x18\x12\x5f\xda\x2a\x5f\x14\x5e\xbf\xd4\x99\xfe\xce\x29\xaf\x67\x66\x25\x68\xcd\x08\xd4\x80\x4a\xab\x3b\x20\xb9\xf8\x18\x36\x07\x6a\x2c\x8d\xb4\xb2\xb5\x58\xaf\xae\x1d\xdb\x54\x5a\x53\x59\x51\x8d\x36\xdc\x54\x97\x08\xad\x2e\xe2\xc5\xb0\xd9\x26\xe9\x6d\x84\x56\x77\x07\x44\x49\x55\x49\x23\x11\x07\x8d\xcc\x9d\x34\x42\x17\x34\xce\xa9\xc3\x87\x0e\x1f\x3e\x74\xf8\xd4\x16\x6f\xee\x1c\x3b\x65\xca\xd8\x9d\x6f\xfe\x9a\x5d\xbd\xe4\xe4\xe4\xa7\xfc\x2d\x9e\x9a\x7a\x6a\xc9\x3e\xdf\xbd\xe5\x3f\xbe\x70\x6a\xc6\xfd\xeb\xe6\x4d\x3f\xb9\xfb\xa7\x72\x40\xb0\x10\x3d\xc6\xfd\xc4\xfa\x20\x99\x8c\xd7\x1a\x90\x74\x5c\x0c\xbb\x02\x12\x4b\x54\x2f\x85\x12\x1c\xef\x12\xa3\x73\xd4\x1e\xa3\xb8\xd1\x98\x4c\xd0\xa0\x95\x16\xe4\x58\x45\x5b\x04\xec\xc9\x61\x3a\x56\x49\xe3\x08\x87\x31\x6b\x8b\x08\x46\x53\x38\x9e\xf6\x21\xae\x4c\x75\x10\x6e\x35\x4c\x52\xdd\xec\xc2\x17\x96\x54\x3e\x3e\xa8\xcd\x88\xd2\xce\x23\x57\xbd\xb8\x68\xe8\xba\x41\x6d\x47\x05\xbb\xdc\x89\x3e\x5d\xf6\x46\xb7\xee\xa1\xe2\x99\x7d\x6d\xcb\x4f\x74\xee\x5d\x52\x32\xa9\x8f\x8a\x75\x1e\x95\x57\xa0\x41\x5c\x1b\x1a\x63\xe4\x02\x45\xe4\x12\xf7\xc7\xb1\x85\x3d\x1e\x5b\x3c\x1a\x8d\x46\xe5\x15\xec\x07\x57\x8b\xb9\xaf\x4e\x9d\x02\x04\x93\x15\x03\x5b\xcf\xe7\x82\x0f\xa6\x03\xf6\x04\x6a\x5c\x7a\x9a\x12\xb4\x04\x6a\x78\xba\x75\x4d\xce\xc4\xa3\xae\x84\x67\xd2\xeb\x13\x3f\x19\x4f\xa2\xa4\x5a\x62\x44\x7e\x04\x35\x67\x7a\x44\x1b\x4d\x74\x81\xe4\x22\x9b\x19\xde\x70\x18\x5b\xc4\x6a\xbd\x21\x99\x06\x91\xbc\x4d\xe2\x34\x89\xcc\x8a\xda\x5e\x65\x41\xd7\x66\x56\x5c\xb4\xc5\x2a\x97\x99\xfc\xfa\xbe\xa3\x5b\x0e\xb1\x4c\x75\x22\xb3\x12\x61\xd9\x13\x6b\x8f\xfe\xed\x20\xa3\x2d\x78\x1b\xf9\x72\xbf\xf9\x22\xe9\xc3\x47\xf9\xc6\xd4\xca\x7d\x27\x92\xcf\x5d\xc8\x46\xd9\x54\xff\xba\x03\x70\x83\xf9\x28\x64\xc1\x7c\x88\xa4\x81\x9a\x7c\xc0\xc9\xc1\x88\xc0\x80\x5f\x32\xb3\xb1\x1a\x40\x69\x82\xc9\x8f\x6d\x6a\x31\xb5\x23\x58\x6d\x48\x13\xb4\x7e\x84\x7d\x01\x9c\xd5\x10\xcc\xdb\x82\x11\x67\x16\x0d\xe6\x1d\x3a\x7f\x24\x8b\x06\xf3\x59\xa0\x23\xef\x69\x8d\x3d\x80\x7a\x6b\x4c\xca\x46\x7e\xc9\x99\x25\xda\x24\x31\x99\x26\x5e\x24\xc1\x1c\x47\xbb\x21\x96\x0a\x3f\x41\xa8\xd3\xee\x75\x7a\xdd\x0e\x41\xe3\xd5\x78\xcb\x42\x1d\x50\x59\x5e\xf7\xad\xfa\xb3\x07\x8e\x7d\xc6\x31\xaf\xcf\x1f\x35\xfa\x1e\x3d\x7a\x5a\x1e\x2d\x64\xa6\x33\x5f\xa0\xab\x25\xfa\x92\x12\x81\x19\x5f\x85\xcc\xef\xc6\xde\xdf\x23\xcc\x9a\xb9\xe1\x21\xf9\x62\xd5\x86\xa1\xcf\xb4\xdd\xbc\xd9\x74\x64\xfc\x06\x55\x27\x26\x28\xdf\xf2\x43\xb9\x9f\x69\x25\xeb\x5c\x50\x9b\xa0\x52\x7d\xa1\x90\x94\xc7\xc5\x70\x51\x40\x32\x71\x6a\x05\x2b\x57\x2b\x65\x5b\x68\xf2\xb2\x00\xf9\x25\x97\x45\xad\x52\xcd\xe6\x44\x5b\x35\xd2\xe8\x7c\x44\x40\x05\x62\xb5\xde\x9a\x96\x45\x36\x5d\xb6\x6a\xd1\x4e\xc5\x06\x52\x5e\xa6\x68\xab\x4e\x01\xf5\x40\x91\x58\x8d\x34\xf6\x64\xb2\x69\xb2\x55\x6b\xf5\x56\x1b\xc5\x3f\x1d\x91\xda\x34\x97\x57\x1e\xc7\x6d\xe5\x6e\x8d\xda\x30\xe7\xd6\xa8\x8e\x38\x4f\x13\x5f\xca\xa4\x2b\x99\x13\x56\x04\xcb\xc2\xad\xd6\x3e\xb2\xa6\x77\x64\xc4\xc8\x48\x9f\xb5\x2b\x1f\x2f\x0d\x97\x95\xac\x5e\xf9\x50\xdf\x57\xc7\x8e\x7d\xb5\xcf\xa2\x7e\x3f\xef\xd9\xfd\xf3\xcf\xbb\xf7\xfc\x3c\x7d\xe5\xcd\xfb\x46\x8f\x3b\xd0\x6f\xc3\x23\x6b\xcb\xdb\x77\x68\xbd\x61\xe5\x13\xfd\x5e\x1d\x3b\xaa\xfa\xe6\x35\x8f\x2c\xed\xd0\xf9\xa6\xf6\x4b\x98\xfb\x0e\xc8\xbf\x21\xdd\x81\xfd\x48\x2b\xff\x87\xc8\x3e\x23\x5e\xc7\xe5\x82\x7b\xd4\xfa\x89\xc4\x9a\x42\x8d\x55\x34\x83\xc9\x8f\x75\x21\xc9\x4a\xd0\x74\xb0\xc6\xe1\xa4\x3b\xf8\x90\xe4\x60\x09\x4c\x42\xd8\x4d\x20\x21\x31\x44\x26\x43\x0c\x6b\x83\x11\x13\x2d\xbb\x30\x19\x74\x7e\x2c\x04\x23\x66\x13\xf9\x66\xb6\xea\xfc\xd8\x11\xa4\xa1\x83\xc9\x9c\x58\x97\x70\x36\x5b\x97\xf0\x3a\xe9\x9f\xe8\x13\xbd\x65\xf4\x2f\xe3\x2b\x34\x1e\x4d\x38\x2b\x0f\x47\xad\xe5\x07\xd1\x02\xf9\xc1\xa8\xbc\x1c\xcd\x96\x97\xa3\x72\x1e\xd7\x4f\x64\x36\xd6\x07\xab\x96\x56\xc9\xa7\x51\x4e\xd5\xd2\x2a\x55\xae\x8f\xc9\x17\xd1\x6d\xf1\x1e\xde\x2c\x68\x6c\xdd\xfd\xa3\x79\x2e\x86\xc4\xc7\xc8\x3c\xbf\xc8\x26\x5d\x3d\xc7\x1e\x63\x7e\xad\xd7\xd3\x6b\x0d\x97\x45\xee\x01\x3e\x0a\x21\xe8\x06\x4f\x83\x5a\xe4\x4c\x62\x37\x91\xe2\x3d\xd1\xa4\xf3\x63\x5f\x40\xf2\x13\x17\xd7\x9d\xde\x21\x37\x28\x95\x1a\x62\x38\x3f\xa8\x56\x3c\x13\x4f\x54\x6a\xa5\x5d\x84\x6a\xb4\x8c\x3d\x64\x77\xb1\x21\x86\x8b\x03\x92\xc7\x10\xc3\x1e\x2b\x36\x91\x5d\x66\x2b\xb1\xef\x92\xc9\x1a\x93\x7a\x10\xbf\x25\x10\x1b\x19\x0c\x87\x71\xb1\xd8\x49\x2f\xea\xdc\x3e\x7f\xcb\x70\x9b\x4e\x5d\x88\xfa\x78\x6c\x52\x52\x3a\x31\x16\xa2\x5f\xb4\xfd\x4d\x30\x7a\x72\xf3\xdb\x74\x69\xd6\x4c\x97\x1d\x0a\x72\x0d\x13\xa7\xa1\x03\x33\x51\x1d\xdd\x91\x69\xd2\xb0\x59\x4e\x0f\xbb\x69\x31\x68\x1e\x4d\xa5\x0f\x1f\x3e\xb8\x6b\x57\x64\x3c\x1b\x43\x1c\xc7\x1e\xd8\xba\xf2\xb1\xc7\x1f\xfe\xc7\xff\x7d\x31\x62\x70\xb7\xee\xf2\xaf\x5f\x7e\x2e\x7f\xc0\x33\x07\xde\x58\xba\x7c\xcb\xa3\xef\xfe\xf8\x55\x74\xd9\x07\xad\x7b\x7b\x7b\x56\xac\x3b\x11\x18\x90\xdd\xab\x17\x93\x37\x6c\x55\x8b\xe0\x23\x23\x9f\x3d\xfe\xc5\x09\x61\xd6\xd6\xd9\xc3\x46\x8f\x6e\xd3\x6d\xdf\x4b\xc3\x57\xe6\x87\x96\x8d\xda\xf3\xd6\xc9\xcf\x04\x66\xcd\xd2\xd9\xc3\x86\x8d\xed\xd8\x71\x7f\xf5\x98\xf1\x6d\x45\x97\xd1\x31\xba\xdb\xb0\xc9\x1d\x8d\xc9\x16\xfb\x18\xc2\xef\xdd\xdc\x39\x76\x58\x5c\x76\xad\x20\x51\xc1\x21\x81\x9e\x02\x6e\x75\x5d\xb6\xc1\x6c\x4b\xac\x91\x62\x5d\x5a\xd1\x61\x6c\x90\x67\x59\xc8\x19\x2a\x0b\x39\x77\x9f\xbe\x72\x9a\x3b\x77\xec\xd8\xb1\x63\xc0\x42\xa5\x52\xc7\x7f\xcd\x1f\x01\x03\xb8\xa1\x0c\xb6\xa8\x58\x55\xb2\x68\xe2\x95\xb7\x4e\x4d\xac\x26\xe4\xd7\xb1\x26\xbf\x14\xd2\xc4\x22\xfe\x10\x91\xae\x3f\xa0\xf3\xd7\xa4\x65\xd3\xbd\x69\x9a\x58\x24\x9b\x66\x94\xb3\x3d\x24\x14\x68\x45\x57\x52\x8c\x76\xb0\x72\x7e\x82\xb1\x93\xd4\x76\x51\x9c\x6f\x95\x8a\xd5\xc2\xee\x12\x7b\x0c\x67\x06\x71\x89\x55\xb2\xa9\x95\xad\x56\xce\x2f\x95\x23\xbf\x54\x9c\x2f\xda\xfe\xa6\xb3\x38\xd9\xec\xb4\x10\xb5\x12\xd9\x7e\xd1\xb6\x4f\x30\xda\x32\x21\xde\x11\x49\x6b\x19\xd4\x8a\x06\xbb\x95\xc4\xfc\xa2\x95\x84\xfc\xf1\xb6\xd2\xeb\x59\x7e\x5f\x56\x6e\x25\xda\x8a\xf2\x51\x1e\xda\x2a\x8f\x94\x3f\x95\x3f\x96\x47\xcd\x45\x83\x7f\xfd\x37\xaa\x94\x9f\xff\xf7\xaf\xf2\xae\xaf\x0f\x3c\xb5\x45\xe2\x98\xb5\xc3\x86\x0d\x1f\x37\x6e\xf8\xb0\xa1\x6b\x19\x0e\x6f\x79\xea\x00\xf3\x09\x6a\x8b\xb0\x5c\x21\x47\xe5\x23\x72\x3f\x14\x41\xed\xe4\xdf\xe4\xf5\x68\x0a\xd2\x21\x0d\x9a\x24\x3f\x2e\x1f\x9c\xbd\xb7\x76\xeb\x06\xe1\xce\xc1\xab\x66\xce\xb9\x77\xe5\x6d\xa3\x84\x8d\x5b\x3e\x24\x72\x9a\xc3\xd4\xb0\x76\x5a\xfb\xe6\x87\x7b\x41\xed\x60\xd1\xf2\x31\x9c\x11\x90\xb2\x35\x31\xdc\x22\x50\xc3\xc6\x81\x8a\x9a\x3b\xf5\x5a\x62\xd8\x6b\x95\xf2\x90\x5f\xe2\x52\x83\x41\xc9\x61\x89\xd1\x9c\xa9\x97\x20\x15\xa3\x99\xd6\xf6\x47\x0c\xd6\x0c\x82\x03\x1c\x36\x9c\x14\xef\xd5\x90\xdc\x04\xc4\xb4\x10\x25\x07\x84\xc3\x92\x96\x15\x6d\x11\x83\xd1\x1e\xbe\x76\x45\x28\x80\x72\xff\x70\x39\x68\xce\xae\xed\x8f\xb4\x6b\xd3\xa5\xd7\xd3\x48\xd8\xb5\xf2\xe1\x27\x8d\xe6\x17\xb5\x7a\xd6\x3b\xa3\xef\xec\x45\x7b\xdb\xb4\x0b\x4d\xb5\xad\xe8\x33\x80\xdd\x34\x6d\x4e\x69\xc7\xae\xad\x5a\x9a\x84\x51\x8b\x56\x3f\x2c\x1f\x0d\x56\xfa\x9d\x25\x29\x81\x0e\xf7\x4d\x2b\x2a\x69\xe7\x9b\xd6\x59\xb5\x2d\xa3\x60\x16\x3b\x99\x5d\x07\x02\x98\x68\x85\x79\x88\x45\xbe\xf8\xc7\x28\x94\xb7\x5e\x01\x65\x7d\x5e\xfc\x13\x5d\xb1\xa3\x87\xe4\x19\xf2\x4c\xf4\x50\x7c\x03\x10\x2c\x40\xb3\xd9\x37\xd9\x2c\xe0\xa1\x24\x51\x6d\x9e\xe8\x6c\xa4\x21\xe6\xef\x9a\xd9\xa0\x49\x33\x1b\xb1\x8a\x0b\xd8\x2e\x47\x99\x79\x3b\xe5\x41\xea\x23\x4b\xfe\xf7\x1e\x43\xae\xd9\x9c\x08\x42\x5b\xd8\x7d\xbd\x59\xd1\x32\x44\xf5\xbf\xa5\x26\x16\x69\x49\x67\x45\xcb\x24\x9d\x1f\xe7\x07\x6b\x52\xda\xd2\x03\x29\x0d\xfd\xd4\xd7\xcc\x86\xa0\x3d\x86\x43\x41\x1c\xb4\x4a\x85\xc8\x8f\xcb\x83\x52\xb6\x3d\x86\xd3\x83\x74\x96\x64\x37\x9b\x14\xc4\x38\x16\x06\x45\x5b\x35\x9d\x14\xee\x30\xce\x16\xb1\x27\x0c\x52\x4b\x8b\x68\xc3\xbe\x30\x0e\x89\x35\x82\xd1\x06\x1e\x72\xa8\xad\x0d\xa7\xff\xc1\x14\x41\x37\x28\x94\xf1\xa3\x64\x14\xa2\x26\xce\x8f\xae\x3b\x51\xfe\x0f\x55\xca\xbb\xc8\x44\x41\x79\x28\x69\xd3\xde\xce\x1d\x3b\xb7\xd5\xe8\x9f\xd0\x71\x5d\xfa\x6e\xdb\x74\xd3\xb0\x5b\x46\x2d\xbe\xce\x4c\xf9\x55\xde\x40\x67\x8a\x16\x4d\x94\x37\xd6\x0f\x63\xfb\x2f\x9e\xdf\x61\x78\x66\xca\xa4\x3e\xad\x5b\xdc\xe4\xb4\x3a\x6f\x2d\x68\xd5\xb3\xab\xfc\x22\xfa\x27\xea\xd8\xba\x57\x5b\x40\x70\x3f\x9f\xc1\xde\x4c\x6d\x5b\x06\xc4\x4d\x19\x1f\x6b\xd8\x68\xba\x58\x5d\xe6\x75\xde\xcf\xbc\xcf\x67\xac\x5d\x4b\x74\x6e\x21\x7b\x88\x99\xc7\x47\xa9\x9c\x7a\x43\x83\x68\x22\x16\x02\x62\x75\x1a\x75\x21\x45\xe5\x7f\xa6\xca\xff\x26\xcc\x4d\x46\x7e\xc9\x66\x14\x6d\x92\x8e\x0d\xc7\xd3\x59\x92\x00\x8d\xd8\xda\xd9\xa4\x07\x5d\x9d\x4d\x0b\x37\x4d\x1c\xbf\x61\xfd\x84\x49\x1b\x17\xf7\x2a\x2b\xed\xd1\x33\x54\xd6\x8b\x3b\x3c\xa9\xaa\x6a\xd2\x94\x0d\x1b\xa6\x94\xf7\xec\x59\x5e\xde\x27\x8e\xa9\x47\x03\xc7\xfe\xc6\xfd\x02\x06\xb0\xc0\x10\xa0\x81\x2c\x1b\x4b\x34\xed\xb2\x7f\xd4\xb4\x6b\x6d\x68\xda\xb5\xfc\x41\xd3\xae\xf8\xbb\xa6\x5d\x54\xe6\x75\x8e\x46\xf3\x24\x34\x4e\xde\x2c\xc9\xcf\xb3\x5d\x98\xd7\x37\xa3\x2a\x79\xec\x66\x79\x34\xda\x52\xdf\xbd\xaa\x8a\x62\xd8\xd9\x4c\x15\x73\x82\x7f\x1b\x52\xc8\xa8\xcc\x01\xc9\xa0\x51\x63\x12\xcd\x75\x7a\x3b\xb1\x39\x28\x25\x9b\x1b\xdb\x3b\x2d\x34\x70\xfc\x83\x5e\x4e\x09\x84\x66\xcd\x14\x96\xdf\x75\x72\xce\x16\x9e\x5f\xb5\x74\xd3\x90\x7b\x9e\x60\xd0\xc4\x7a\x8c\x8a\xbb\x15\x86\xdb\x74\xe9\xb5\x9d\xfb\x78\xf4\xca\x85\xf7\x54\x4c\x9f\xb8\x54\x58\xb4\x08\x09\xed\xfa\x14\x04\x3b\x74\x0a\x92\xf1\x4e\x67\xd6\x30\xdf\xf0\x47\xa1\x00\x56\x42\xbc\x5f\x53\xd3\xb4\x5f\x13\xe7\x07\x24\x5e\xd3\x34\x2b\x47\x79\xad\x51\xbb\x37\x91\xda\xbd\x69\x6e\xd2\xbd\x89\xc5\xa0\x94\x63\x21\xee\x27\xa2\xcd\x49\xac\xd2\xd3\xd6\x4d\x06\x89\x36\x9c\x42\xd7\xd5\xd3\xf2\xc3\x61\x9c\xa3\x3e\xd1\xc1\xc8\x8b\x36\x9c\xd3\xd8\xc1\x89\x33\xff\x7a\xff\x26\x51\x9f\xe9\xe8\x99\x3e\x1d\x7b\x0e\xec\xd5\x6b\xc9\x92\x2e\x37\xf5\xea\xd6\xba\xdb\xd3\x8c\xb0\x6b\xfe\x63\xcf\xf7\xe8\xd0\xfd\xe6\x9a\xb5\x0b\xf6\xb1\x33\x85\xe2\x70\xdb\x92\x0e\xe1\xf9\xe1\x52\x7f\x9b\x92\x7c\x61\xf8\xec\xd9\xd3\xca\x87\xa5\xb8\x47\x74\xbd\xeb\x81\x7b\x08\x0f\x16\x73\xaf\x31\xd9\xb4\x66\xa1\x50\x9d\x1b\x35\x70\x83\x9a\x05\x89\x25\x2e\x83\x51\xeb\x26\x53\x51\xc8\x8d\x16\xbf\xfa\x1d\x23\x5f\xe4\x5e\x43\x7a\x41\xbe\x0a\x08\x9e\x90\x47\xb0\x17\x69\x3e\xe4\xf6\x66\xb9\x32\xb6\x21\x57\x46\x93\xda\x6a\x0a\xc9\xa9\x2e\x6e\x39\xaf\x97\x31\x73\x23\xbf\xa4\x73\x36\xcb\x98\x09\x26\xd1\x26\x99\x1d\xe1\x78\xce\x4c\x5d\x3d\x6d\xcc\x99\xe5\x89\x4f\x1c\x61\xee\x1a\x33\x6a\xae\x27\x2a\xe9\x0a\x17\x0c\xe8\x39\x35\x5f\x1e\xc1\x7f\x5a\x3f\x3f\xf2\x60\xcf\xee\x6c\xde\x95\xa3\x53\x3a\x76\xf6\xfa\xe4\x96\x6a\x5e\x03\x80\xed\x4a\xeb\x32\xcb\xe3\x75\x67\x6a\x53\xbd\x81\x52\xcc\x19\x41\xc3\xf9\x31\x67\x95\x04\x82\x58\x03\x98\xb3\xd6\x80\xba\x0f\x02\x24\x9c\x06\xb5\x07\x8c\xcc\x0b\x5f\x16\x74\x24\x56\x3f\x39\x3a\x30\x26\xd7\xb3\x9f\xfd\x1d\xf1\x97\x2b\x18\x2d\x62\xe9\x7d\xb6\x33\xd3\xd1\x78\xb6\x6b\xa3\x8f\xd0\xc7\x6e\xdc\x44\x4e\xd0\xd3\xf6\xa3\xcc\xf4\x7f\xfe\x53\x9d\x4b\x72\x5f\xf4\x12\x7d\x7a\x63\x07\xb5\xce\x48\x12\x34\x31\x12\xea\x42\xdc\xbd\x5b\xe9\x23\x06\x8c\x76\x35\x1f\x6d\x64\x45\x9b\xa4\xd5\x91\x29\x23\x80\xda\x62\xa3\x89\xaf\xd8\xaa\x78\xb3\x3c\x14\x57\x9a\xd9\x3d\x2b\x7b\x0e\xf6\xac\x34\xde\x74\xdb\xd6\x75\xf2\xfe\x96\x2d\x4b\x72\x35\x4b\x4b\x0d\xfd\x2b\x46\xcc\xa4\xf7\xbd\x93\x79\x02\xad\xe4\xa3\x6a\x1d\xb3\x6a\x22\x35\x31\x5a\xcc\xd2\xe0\x23\x2d\xd7\xf5\x91\x39\xa2\x4f\xbc\x13\x15\xbd\xc8\xe7\x3f\xec\xbe\xfa\x4f\x66\x0d\xc5\x2a\xd5\xac\x3f\x5e\xa3\xdb\x1a\xe2\xa5\xb9\x3c\x5d\xf6\x17\xf9\xc6\xd5\x17\x4b\xe3\xea\x8b\xe5\x3a\x15\xba\x7f\xf0\xcc\x8e\x39\x07\xb6\x6c\x3d\xf0\xda\x96\xad\x07\xf7\x56\xde\x36\x60\xc8\xd0\x81\x03\x2b\x39\x74\xef\xfa\xd7\x5e\x5b\x7f\xef\x86\x57\x5f\xdd\x50\x39\x71\xd2\xe0\x7b\x07\x4e\x9e\x3c\x90\xd8\xcc\x69\xb0\x89\x5d\xcc\xee\x53\xf1\x43\x39\x62\x43\xc8\x89\x42\xea\xc7\x34\x50\x94\xf5\x28\x4f\xfe\xe4\x68\x62\x63\x13\x5a\x8d\xd6\xc8\xf7\xdb\xe5\xfb\x1b\x36\x88\xdf\x7e\x05\x80\xff\x8a\x3f\x42\xfb\xe6\x1c\x90\x0c\x8f\x43\xc4\xd6\xd0\x19\xef\xb0\x59\x3d\x87\x03\xd8\x12\xa2\x9d\x56\xa6\x60\xc4\xe9\xa0\x71\xb8\x41\xd7\xd8\x35\xaf\x51\x93\x33\xbf\x63\x22\xc1\xd2\x36\xe4\xc7\xae\xa0\x24\xaa\x86\x30\x95\xcc\x37\x8e\xb8\x0c\x5d\x38\x8c\x6d\x62\x8d\x46\xab\x37\x38\x29\x6a\x75\xd8\xd4\x15\x3e\xa7\x28\xe9\x85\x70\x18\x83\x2d\xc2\x6a\x93\xc2\xe1\x86\xe2\x75\x55\x16\xf4\x79\x27\x6a\xcb\xb4\xd3\x57\xe6\x2d\x0f\x89\x79\x9a\x57\x50\xd1\x8b\x69\xea\x53\x4d\x6e\x45\xcf\xee\x9d\x3f\x7f\xb7\x7c\xe7\x8b\xbf\x08\x26\x3e\x4f\x95\xd9\x95\xb5\xf4\x19\x26\xcb\x18\x5f\xfd\xa5\x45\x9b\x36\x2d\x42\xad\x90\x0b\x58\x4a\xf7\xbf\xe3\x74\x67\xc3\xae\x78\x77\xb0\x33\xae\x17\x35\x26\x4f\x12\x63\xf2\x13\xbb\x18\xf1\xd0\x70\xd3\x93\x7d\x0d\xcd\x39\x37\xa0\x39\x5b\x5d\x0d\xf2\x99\xe9\xca\x26\x91\xbc\xd5\x12\x23\x5c\xc8\x6d\x46\x7e\xb6\x88\x0d\xb4\x24\x57\x13\xc6\xe9\x62\xb5\xc9\xe1\xd4\x52\x4e\x78\x9c\xa2\x6d\x1f\x27\xe8\xad\x2c\x09\xee\x25\x48\x8a\xcf\x81\xdf\x31\x42\x87\x6e\xec\x35\x08\x4f\x5a\xa8\x3c\xf9\xf0\xfa\x0e\xe4\x1a\xee\xa0\xb7\xaf\xef\x4f\x38\x58\x08\x20\x6c\xe3\xdf\x86\x02\x28\x86\x30\x74\x80\xcf\x20\x52\x0e\xe0\xc7\xe1\x00\x2e\x0d\x49\x6d\x34\x31\x1c\x0c\x46\xda\x84\x09\x07\xda\x94\xfc\x81\x7b\xc1\x8e\x00\x8d\x7b\x1a\x3d\x11\xc2\x1d\xff\xba\xc3\xc1\x39\x56\x12\xef\xe0\xb6\x41\xa9\x95\x25\x86\x5b\x06\xa5\x4e\xcd\x3c\x50\x24\x2d\xdf\x1f\xa6\x3e\x48\xca\x2a\x0e\x87\x71\xb9\x58\x53\x58\x14\x28\x69\x43\x79\xda\x26\x2c\xda\xa4\x80\x3f\x1c\xc6\xf9\x22\x6e\x1f\xfe\x9d\x87\x8a\x64\x16\x16\x5d\xdb\x8e\xfe\x67\x5e\x4a\x77\x1d\x55\x5c\xf8\x27\x9e\x0b\x3d\xaa\xca\x64\x70\x53\x3d\x65\xef\xfe\x23\x77\x56\xbf\xef\x3a\xda\xab\xf6\x4a\xce\x62\x5f\xe0\xda\xd2\xde\xcf\x29\x10\x49\x23\xf0\x2d\x55\x1f\xc3\x49\x01\xc9\xca\xc5\x22\xd6\x24\xc2\x39\xab\x23\xde\xf9\x09\xf4\xc1\x2d\xd8\xa4\x76\x7e\x0a\x6a\xe7\xa7\xa6\xa1\xf3\xd3\x69\x55\x3b\x3f\x53\x4d\xa2\x2d\xc2\x19\x58\xc2\xc9\x0c\x31\xa2\xb7\x26\x51\xc0\x92\x4a\xf3\xaa\x82\x93\xf2\xc8\x5d\xda\xaa\xbc\x03\x2a\x0b\x99\x91\xc6\x8c\x9c\xcd\xa2\x46\x54\x16\x72\xce\x5c\x79\x6f\x59\x52\x94\x29\x19\x3b\x66\xc0\xf4\x49\x43\x1f\x3c\xc0\x32\xb1\xea\xa3\x9f\xa0\x1e\xa7\x4c\x0b\x3e\x9c\x59\x76\xdb\xed\x6b\xa7\x0f\x9b\x35\x7f\xf0\xa4\x99\xa3\x47\x08\xdb\xdf\x3c\xce\xf9\xdf\x7f\x1f\x68\x45\x22\xed\x2d\xd4\x64\x81\x86\x3e\xb1\x34\x70\x6d\x77\xa1\x29\xd1\x5d\x88\x8d\x01\x84\xc5\x00\x31\x2d\x20\x21\x13\x45\x52\x4d\x1a\x0c\xcb\x43\x76\xf2\xd9\xb4\xcb\x70\x0b\xfb\xdd\x4b\x5b\xdf\x6b\xda\x6a\xa8\x49\x13\xe4\x5f\xaf\x72\xb4\xdf\x50\xbd\x6f\x06\xed\x69\xb4\xfe\x61\x57\x63\xc3\x4d\xaf\xd7\xd5\xc8\xda\x43\x6e\x74\x6d\x6b\x63\x88\x62\x89\xa6\x0d\x8e\x68\xa4\x8a\x2b\x12\xf7\xed\x09\x1a\xb0\x82\xe3\xf7\xf7\x15\x1b\xef\xeb\x0c\x48\x2e\x7a\x5f\x51\xb4\x61\x7b\xd3\xfb\x96\x95\x87\xdc\x4e\x5f\x9e\xe6\x1a\x82\x97\xfe\x3a\xe7\x3f\xdb\xd7\xad\x1d\xd1\x94\x64\xe1\xa6\x94\xef\x7f\x48\x5e\xbf\xfe\xca\x69\x66\x63\x13\x7e\x0f\x04\x0d\x7d\xe6\xd5\x83\xd7\xde\x3f\xad\x81\xdf\xce\x80\x64\xe6\x63\xd5\x49\x66\xa7\xd6\x2f\x19\x78\xb5\x62\x4c\x5b\x5b\x93\xaa\x06\x68\x69\xf4\x61\x09\x22\xf2\xd7\xd8\xd4\x18\xc1\x4b\xf4\x48\x4b\x17\x64\xb0\x28\xee\x63\x0c\xc8\x99\x91\x49\xa2\x2d\x9b\x4d\xe2\x69\xa2\x09\xa5\x89\x36\x9c\x41\xfb\x65\x53\xc3\xd8\x6c\xc3\xda\xa6\x44\x51\xcf\xd8\x98\xa1\x27\xd3\xef\x1a\xfa\xee\x9c\x35\xac\xf5\xf3\xa5\x2d\xda\x4d\x99\x3d\xb4\xc7\xe6\x90\xbf\x0d\xd7\x8c\xd0\xdb\xef\x58\x3e\xfc\xa6\x80\x67\xf8\xa2\x3b\x6e\x2a\xbe\xf2\x29\xb3\x11\xb8\x38\xad\x26\x2a\x63\x0b\xd8\x61\xc2\xb5\xd4\x1a\x1b\xa8\xd5\x06\xb0\x35\x24\xe9\xf4\x31\x2c\x06\xe9\x22\xa8\xb6\x56\x32\x18\x69\xab\x8f\x95\xe0\x78\x63\xbc\x5e\x49\x4b\xec\xb8\x31\x1c\xc6\x56\xb1\x9a\x41\x66\x0b\x21\xd0\xae\x2e\x02\x81\x84\x8c\xf1\x95\xd0\x46\x49\x85\x28\x11\xe4\xb3\x09\x21\xa3\x4e\xcf\x22\x43\x9f\x77\xba\x61\xf0\xdd\x8e\x1d\xbb\xf2\x11\xb3\x11\xad\x3d\x76\xac\x61\xdc\x2b\xe9\xb8\xdd\xe0\x83\x19\x37\xd4\x4e\xec\x0c\xd4\xa4\x6a\xc0\xc1\xf9\xb1\x97\x2e\xeb\x38\xe2\x2b\x07\xc6\xda\x9a\x24\x55\x50\xea\xa3\x12\x12\x52\xca\x41\x7e\x29\x23\x49\xb4\xed\x63\x90\xde\xe2\x34\x50\x33\x19\x57\xec\xf8\x23\x12\x8c\xe1\x6b\x55\xfc\x06\x21\xde\xb5\x5a\xff\xf7\xb9\x83\x07\xcd\x99\x7d\xdb\xe0\xb9\xe3\x3b\xf8\x0b\xda\xb5\x2b\xf0\x77\x68\x3a\x03\x18\xfb\xc0\x99\x33\x06\xdd\x36\x65\xca\x6d\xfe\xf6\x6d\x8b\x8a\x3a\x74\x00\x46\xb9\x00\xa0\x19\xc9\x63\x2a\x9b\xf9\x10\x31\x12\x1a\x21\xd4\xbc\xc9\xd3\x6c\x35\x12\x5a\xcd\xda\x58\x0d\xaf\x35\x36\xf4\x7b\xaa\xfd\x77\xea\xa3\x0e\xb1\xce\x53\x2b\x4a\x46\x2b\xb1\x11\x92\xce\x1a\x8b\xe8\x8c\x89\x48\xb0\xba\x93\xce\x40\x5c\x91\x95\x3e\x87\x06\x9b\x42\x92\xd6\x4a\x9b\x66\x68\x37\x12\xc7\x13\x82\xed\x84\x60\x1f\xf2\x3a\xbd\xf6\xf8\x8b\xf5\xb2\xc8\xcb\xe6\x39\xd8\xe9\xec\xdb\xf5\x7d\x1d\x4c\xbf\xfa\x57\x5c\xcc\x1b\x57\x1f\xb4\xd4\xff\xe3\x04\x6a\x89\x0e\x65\xf2\x3c\xae\x92\x8b\xab\xea\x2f\x6e\x46\xc3\xe5\xa7\x19\x91\x39\xca\x10\xdb\x3c\x4b\xee\x46\xfb\x7e\xd3\xa1\x08\x1e\x51\xeb\x01\x6b\x72\xa8\x4c\xae\xd7\xd0\x89\x8b\x02\x35\x19\x71\x00\x5c\xdc\xb4\x9f\x93\xcc\xa4\x02\x7b\x0c\x17\x34\xb4\x76\x26\x59\x89\xd5\xa6\xc5\x10\x5e\xab\x68\x7b\xd9\xc8\xd9\x53\x33\xb2\x73\x8a\xd4\x55\x03\x29\x37\x8f\x5a\xeb\x0c\xd1\x16\xc9\xce\x2b\x08\x87\xc3\x92\x31\x47\xb4\x55\x6b\xec\xae\x24\x35\x17\x48\x3b\x3c\x21\x9e\xf3\x6b\xd2\x23\xec\xa2\xe9\x8e\x6b\x40\x35\x6d\x18\x46\xd9\x5c\xd3\x8e\x61\x4e\xfe\xf8\x97\xdf\xe4\xe3\xe8\xef\x4d\x00\x77\xa2\x7f\x58\xbe\xf4\x49\xf3\xe6\xe1\x93\xf2\x05\x34\xbc\x7e\xe2\x35\x70\x3c\xde\xf3\x74\x9f\x26\x8b\x5a\xdc\x81\x7f\xdc\xd1\x8b\xad\xd4\xdc\xff\x49\x53\xaf\x8d\xc4\x56\x34\xf9\x67\xa2\xf8\xba\x69\x7b\x2f\x22\x2e\xa1\x49\x8f\xef\xd5\x7d\xb4\x3e\x3d\xd1\xe9\x4b\x7d\x41\xc3\x98\x32\xe8\x98\xfe\xb4\xcb\xf8\xaf\x0c\xe8\xda\x61\x10\x07\xd1\x64\x18\xf5\x4f\xc5\x9d\x43\x7c\x1c\x82\x43\xf5\x0c\x8d\xfc\xe9\x09\x06\x70\xc0\xad\x7f\x36\x16\xe7\x9f\x8d\xc5\xf5\x47\xcc\x49\xb8\x90\xa6\x0c\x3a\xa6\xfa\x8f\xc6\xa1\xc5\x7d\x07\xf5\x1b\xea\xd8\x4c\x71\x4b\x3a\xf1\x4f\xa4\x67\xa4\xe6\xd4\xd4\x68\x4e\xff\x70\xa8\xd5\x46\x1d\x68\xfd\x92\xc5\x18\xc3\xba\x66\xf6\xf6\x77\xa3\x56\x93\xf2\x4d\x07\xfd\xf4\xe9\x2b\xa7\x1b\x47\xdc\x8d\x66\xea\x01\x18\xe5\x0c\x00\x5a\xa2\xc9\x02\x0e\xb4\xc4\xcb\xf2\x24\xb6\x11\x18\x5a\x0f\x4a\xbb\x5b\xf8\x5a\x5a\x1f\xa7\x27\x91\x1a\x2f\xda\x22\x0c\x47\xd0\x0f\x2d\xda\x24\x50\x42\x0c\x89\x59\x44\x5f\x52\x8e\x52\x45\xb9\x74\x4e\xed\x10\x66\xe0\x75\x00\x66\x82\x26\x03\x58\xd0\x26\x9e\xaa\x16\x5f\x9a\xd7\x35\x04\xc2\xfa\x78\x82\x21\xc2\xf1\xda\x70\x9c\xf7\x21\x91\x42\x85\xd7\x8f\x1e\x6c\x00\x07\x8d\xa2\x07\x46\xf9\x19\x80\x19\xac\xe9\x09\x5a\x30\x92\xeb\xd2\x2a\x18\x3d\xbd\xae\x29\x80\x75\xb4\xb8\x93\x36\xd7\x1b\x75\xa2\x2d\xc2\x32\x9a\xf8\x60\x13\x72\xb4\x8b\x21\xd1\xa2\xca\xaf\xe8\x68\x42\x70\x97\x0e\x25\xfa\x9a\x59\xe5\x1d\x00\xe6\x01\x8d\x89\xae\x89\x18\xa0\x53\xfc\x39\x68\x3c\xe1\x08\x04\xb0\x36\x44\x1f\xc2\xa2\x0b\x26\xda\x5c\x9b\x2e\x8a\xa8\xcd\xb8\xb4\xc9\xd9\x98\x68\xc4\x66\xcb\x42\x4e\x72\x4f\xe2\xd9\xca\x4e\x27\x1d\x4d\x3f\x4d\x78\x7f\xe9\x35\x4a\x57\x37\x55\x06\x50\x00\xc0\xeb\x78\x4c\x63\xe6\x3b\x54\xfb\x2e\x99\x13\xcf\xb5\x71\xb3\xb1\x1a\x04\x46\xd6\xe4\xc7\x29\x6a\xaa\x2f\x29\x48\xc3\x68\x23\x4d\xea\x99\xe9\x63\x44\x23\x66\x6a\xca\xcd\x29\x3a\x7f\xc4\x48\x17\x03\x8d\x24\xdc\x32\xd3\x10\x33\x51\xe0\xa8\x26\x1c\x12\x8f\x1a\x68\x81\x44\x7b\xc3\xc3\x06\x88\xe2\x14\x3c\xdf\xf8\xc4\x01\xf9\xa6\xa8\xfa\xcc\x01\xe4\x90\x2f\x30\x1b\xab\x98\xf9\x0d\x8f\x1e\x60\x36\xca\x6c\xfc\xe9\x03\x72\x7a\x55\x62\x3e\xf2\x48\x33\x10\x0c\x90\x09\xab\x7e\xd7\x11\x8c\x93\x03\x92\x8d\x8f\x55\xa7\xd9\x92\x89\xf2\xf2\x0d\x35\xf5\xf1\x16\x61\xa3\xc1\x5f\x93\xa9\xfa\xe0\x4c\x2b\xd1\xe6\x1a\x97\xfa\xcd\xd5\xd8\x3e\x4c\x4c\x7d\xa6\x41\xb4\x49\x8c\x2e\x1c\x96\x38\x97\x68\x93\x58\x6d\xb8\x69\x13\x31\x4e\x16\x71\x66\x18\xa7\xd1\xfa\x41\x0b\x09\x97\x5d\xd7\x34\x16\x5f\x0f\x39\x35\x36\x1b\x73\xd7\x80\xa6\xe6\xcd\xc7\xcd\x50\x13\x9d\xe7\xb4\x17\x59\x53\x4e\x65\xe6\x81\xf6\xd7\xed\x46\xf6\x5e\xaf\xd2\x34\xeb\x9a\x67\x9c\xfe\x49\x43\x32\x45\xec\x37\xec\x4a\xee\x48\xe6\xde\x5f\x69\x4d\x66\x6b\x69\xbf\x51\x62\xdc\xa1\xff\xef\xe3\xa6\xf6\xfc\x86\xe3\x46\x05\x74\x76\xff\x95\x91\x33\xa7\xe2\xb3\x3f\x31\xf6\x3b\xe8\xd8\xb3\x6f\x30\xf6\x9c\xeb\x8d\x3d\xb7\xc9\xd8\x3d\x7f\x81\xe7\x09\x6b\x71\xc3\xf1\xf7\x57\x4d\xc8\x5f\x1a\xff\x95\xb8\x77\x48\x8c\x7f\x22\x1d\x7f\x00\xee\xbb\xce\xf8\x71\x8b\x80\x94\xc5\xc7\xaa\x0b\xb3\x5a\x68\xfd\x52\x26\xdf\xf0\x54\xaf\x38\x41\x69\xc8\x5f\x13\x50\x67\x47\xc0\x4a\x40\x6a\x4d\xae\xfa\x2d\xb7\x91\xd8\x96\xc8\x2f\xe5\x04\x44\xdb\x3e\x83\x98\x94\xc9\xb5\xa0\xd0\xb5\x05\x27\xda\x70\x20\x8c\xb3\x44\x9c\x16\xfe\x13\xe2\xaf\x33\x4d\x6e\xc8\x87\x16\xd7\xcc\x9a\xbf\xa4\x8a\xae\xe6\x73\x89\x8b\xf3\x25\x2b\xfe\x7c\x61\x1f\x8c\xb8\x1e\x67\xd2\x02\xd8\x13\x92\xd2\xf5\x31\xec\x6d\x28\x91\x6f\xe4\x8a\x94\x69\xa4\x65\xb1\x24\x4a\xf7\x19\x69\x6a\x29\xc1\x0f\x02\xe5\x3d\x99\x44\xf8\x62\x12\xf7\x57\x84\xaf\x3a\xcf\x1b\xd2\x5c\x78\xfa\xca\xe9\xbf\x24\x78\x45\x75\xb2\x08\x2a\xe1\x4b\xf6\x4b\x6e\x2e\x18\x00\xec\x3a\x54\xae\x43\x6e\x1d\xd2\xe8\x50\x25\xea\x21\xbf\x3a\x1f\x75\x47\x3d\xe6\xcb\xaf\xa0\x9e\xf3\xe5\x57\xe5\xfd\xe8\x4e\xd4\x0f\xf5\x9b\x2f\x57\xa3\xbe\xf3\xe5\x88\x1c\x99\x8f\x6e\x96\x6b\x54\xdd\x7f\x9a\x67\xf8\xef\x21\x19\x72\xa0\x25\x8c\x8d\x77\xf4\xb7\x48\x70\x28\x8b\xe8\x7e\xb0\xa1\xff\x3d\x85\x2e\x04\x12\xfe\x48\x21\xe4\x57\x1b\x04\x9c\x61\x5c\x28\xee\xd3\x88\x0e\x2e\x33\x97\x00\x62\xb3\xfa\xcc\x9f\x16\xa2\x68\x93\x1c\xee\x30\x51\x8e\x88\x3e\xa3\x65\x38\x1c\xc6\x5c\xe3\x13\x4f\xbc\xb4\xfa\x9a\x40\x5e\xf2\x25\x2b\x37\x4f\xe3\x2b\xa7\x75\x0c\x99\x08\x15\x23\xca\xb0\x0c\xa4\xb2\x2f\x37\xa0\x4e\xf8\xe1\xbb\x7a\xde\xba\x61\x49\xdf\x41\x84\x71\x83\x36\x76\x1a\xb6\xe1\x91\x81\x43\xa2\xb9\x3e\x81\xf1\x04\x1f\xe8\xb9\xe7\xe4\xce\xc2\x49\x1d\x5e\xfe\xc8\x9b\x21\x24\x98\x18\x2a\x5e\xfe\xf9\xc0\xaf\x1e\x54\xf9\xd8\x22\x7f\xf3\xf9\x81\x17\x56\x0c\x5a\x5b\x8a\xd8\xf5\x2d\x0a\x15\x38\x56\x7f\x6f\x56\x16\x65\x6b\x9f\x87\x83\x88\xfa\x1b\xda\xe3\xad\xc9\x02\x11\x5c\xd0\xe1\xf7\x5d\xde\xd8\x15\xa0\x25\x32\xbf\x6f\xf4\x4e\x8a\x57\xe5\x46\x2c\x36\x67\x38\x7c\xfd\x66\x6f\x6a\x70\x9b\x75\x7c\x7f\x49\x8c\xec\xef\xda\xbe\x85\x52\x6a\x51\x1b\xc7\x93\x41\xc7\xd3\xf6\x7a\x5d\xe7\xff\xf3\x60\xa8\x15\x6d\xde\x7e\xfe\x2e\xb5\x9c\xbf\x1b\x0e\x5f\xd8\x88\x8f\xd5\xf1\xf4\x04\x11\x52\xae\x3f\x9e\xd4\xeb\x8d\x27\xad\x71\x3c\xae\x1b\x32\x27\x61\x19\x9b\x8d\xe9\xff\x54\x6b\xf8\xfb\x31\x0d\x49\x00\xe3\xff\x47\xdb\xb7\xc0\x47\x51\x9e\x7b\xff\xdf\xb9\xec\x7d\x93\x99\xdd\x4d\x36\xf7\xec\xe6\xb6\x84\x4d\xb2\x9b\xdd\x04\x12\xc2\x35\x21\xd1\x2a\x02\x62\xd5\x68\x15\x0c\xb7\x04\x44\x88\xdc\x44\xda\x53\x01\x51\x11\x41\x11\x2c\xc7\x5b\xab\xa0\x55\x01\xab\x33\x9b\x15\x91\xcf\x7a\xf0\x12\xc4\x62\x6d\xcf\xf1\x48\x3d\x62\xbd\x54\x8f\xba\x42\xfd\xb0\xad\x9e\xb6\x90\xcd\xf7\x9b\x77\xde\xdd\x6c\x36\x09\x60\xfb\x9d\xf0\x1b\xde\x99\xcd\x66\xe6\x7d\xfe\xef\x33\xef\xed\x79\x9e\xff\xc3\xb3\x3a\xd9\x21\x23\x8b\x66\x03\x1a\xda\x6a\x8e\x80\x92\x1d\x56\x9d\x16\x6d\x3e\x93\xf0\x67\x64\x55\xd4\x26\x31\x59\xb6\x98\x92\xa5\x13\xe0\xe7\xda\xa8\x0d\x31\x51\xf1\x7c\xe2\x57\xb3\xb3\x64\x87\x9a\x69\x18\xb1\xda\xfa\x3b\x3d\xa8\xd6\x6f\x1d\x3f\x7d\x7c\x68\x95\xaf\xa5\x2f\x2d\xa7\xc7\x7c\x1b\x0b\x61\x82\x1d\x75\xe9\x51\xdf\x19\xc9\xa8\xef\x4c\x16\xf5\x1d\xe1\xcc\x76\xba\x17\x38\x34\xf2\x9b\x9a\xcd\x06\xc2\xbf\x6d\x6c\x5e\x3b\x10\x04\x2e\x18\x06\xe6\xb7\x78\x0c\x10\x3a\x28\x4f\x65\x16\x2e\x4e\x99\x37\x47\xad\xfa\x16\x9f\x95\x8f\x45\xf9\xac\x01\x5a\x9b\xec\x44\x48\x93\xca\xd9\x43\x21\xc5\xa6\x47\x08\x19\xad\xcc\x05\x99\xc6\x86\x24\xe2\x9b\x86\x52\x89\x3c\xd6\x4b\xec\x5f\x10\x21\x7e\xe6\x8b\xf8\x9f\x89\x7d\xc7\x8e\x1d\x3b\xe2\x7f\x16\x95\xf8\xf1\x93\xbf\x7c\xe9\x44\xfc\x75\xf2\xf6\xc3\x37\x2e\x7f\x44\xf7\x0b\xbe\xb3\xff\x84\xd0\x6d\x70\xc2\x87\xd5\xac\x56\x12\xf4\xd9\xa9\x52\xca\x42\xb9\x75\xc6\x45\x9f\x95\x32\xcc\x69\x1d\xb1\x51\x8a\xf5\x58\x8c\x1e\x93\x5f\x2d\xb4\xc6\x94\xc2\x00\x0d\x01\x31\xea\x64\x23\x76\x46\xc5\x58\xe8\x93\x1d\x3d\x82\xcb\x49\x3d\xfb\x2c\xb2\x2a\xb9\x1b\x99\x4f\xad\xe2\x6c\x54\x4a\xe5\x88\xd1\xee\x62\x94\x35\x89\xfd\x95\x2c\x17\xb2\x52\x83\xf8\xea\xeb\x50\x5f\x97\xd8\x8a\x96\xef\x3c\xf1\xfc\xae\x5f\xad\x27\x3f\xf8\xf7\xc8\xf7\xd5\xf2\x2a\xff\x86\x09\x4b\x16\xc6\x7f\xbe\x75\x61\x73\xd7\x3a\x61\xdc\x87\x7f\x7f\xfa\xc9\xd5\xef\x37\xce\x8a\x7f\x7a\xd7\x93\x7b\x2b\x8b\x1e\x29\x08\xce\x99\xfe\x7d\x52\xbc\x7d\xe6\xef\xa7\x5d\xbb\xe4\xc9\xfb\xa9\x3b\x3c\x78\x3d\x26\x5b\xfc\x08\x1e\x94\x23\x88\x07\x75\xdb\x87\x4e\x3a\x55\x29\xc4\x22\x52\x32\x2a\x5b\x1a\x88\xca\xae\x29\x92\x12\x51\xd9\xb5\x14\x87\x0a\x6b\x4c\xa9\x60\x51\xd9\x6c\xcf\xc5\x2a\x69\x1f\x51\x7d\x15\xaa\x42\xd4\x73\x5a\x0d\x69\x4a\x0c\x9d\xb4\xa7\x42\x56\xbd\x25\x8d\x8d\x6a\xbe\x55\x76\x3c\x27\x15\x95\x96\x95\x6b\xa3\xb7\xe2\x92\xa9\x8b\x0e\x5f\xa4\x75\xd4\xf9\x7a\xa0\xb6\xdd\x39\x34\x50\x7b\x18\xb7\x1c\x7d\xbf\x77\xb8\x50\x6d\xc3\x89\x83\x83\x42\xb5\x7f\xa4\x75\x72\xea\xd0\x78\xed\xd5\xaf\x0d\x0a\xd6\x16\x9b\x0d\xf1\x6f\xcf\x5c\xc1\x42\xb6\x93\x58\xbd\x4f\x7d\x93\x82\xd8\x99\x8a\x55\xd9\x48\x58\x55\xa6\x63\xe5\xb5\xc6\x14\xef\x50\xac\xbc\x0c\x2b\xdf\x50\xac\x12\x18\x95\x55\x55\x07\x75\x8c\x22\x39\x35\x01\xfa\x06\xfe\x23\x38\xa5\xb8\x2f\xd1\xd7\x75\x64\x9c\x92\x21\xed\xbb\xf5\x7e\x78\x24\xa0\x58\x54\x3b\x7f\x79\xf2\xdd\x66\x58\x19\x0c\xf0\xa0\x12\x75\x78\x24\x15\xab\xea\x91\xb0\x0a\x0d\x60\x55\x4f\xb1\xa2\xfc\xad\x43\xb1\x1a\xcd\xb0\x0a\x32\xac\xc6\xa4\xe8\xd5\xe8\x14\xbd\xda\xaf\xe9\x95\xaf\xb2\x3a\x01\x5a\x79\xc5\x3f\x0c\xda\xc0\xfe\xfa\xf9\x28\xd8\x3d\xfa\x20\xb1\xf8\x9c\x2a\x26\x74\xea\xa3\xc6\x99\xea\x84\x96\x0d\x60\xe7\x80\x07\x75\x98\x84\x23\xa9\xd8\x35\x8c\x84\xdd\x84\x04\x76\x4a\x4d\x40\xf5\x89\xb1\x9e\x5a\x5f\x8d\xc9\xaf\x96\x69\xd3\xea\xc9\x14\xcc\x7a\x6b\x4c\xa9\x0b\x29\xf5\x43\xf1\xac\x97\xa2\x5e\x7d\x6a\xed\x0d\x28\xf5\x14\xdc\x88\x30\xba\x29\xa4\xc3\x1b\xf5\xeb\xdb\xc4\x53\x88\x5f\xcd\xf7\xca\x8e\x1e\xa9\xc8\x57\x53\xe6\x6e\x54\x5d\xda\x7a\x34\x23\x47\x83\x74\x42\x8e\xec\x88\x40\xc3\x54\x77\xa6\xa3\xb0\xaa\x35\x92\xec\x50\xea\x1a\x15\x9f\xac\x78\xcf\x0b\xe4\xe1\xf6\xfb\xcf\x07\xef\x85\x69\x53\x73\xfb\xb9\x81\xdf\x90\x32\x31\x3f\x53\x95\x40\x5f\x60\xef\xf8\x51\x78\x50\x86\x00\xc2\xd8\x9f\x8a\xfe\xa8\x91\xd0\xaf\x4e\xa2\xef\x0d\x28\xc1\xb0\x5a\x62\x89\x29\xb5\x21\xa2\xd4\x51\xe4\xcb\xad\x31\xa5\x7c\x08\xec\x3d\xde\x72\x68\x2d\x64\xd3\x7e\xa9\x2b\xb4\x5f\x47\x5c\x71\x49\x4a\x58\xfb\x72\xd0\x16\x53\x82\x01\x35\x6c\x8b\xa9\xf5\xc4\xaf\x06\xcb\x28\xfa\x26\x1a\xf3\x16\xd6\x7b\xca\xea\xe1\x90\x3f\x2f\x85\x0e\xa7\x62\x4b\xea\xc3\x59\x23\xe3\xbb\xe8\xf8\x2d\x49\x44\xd7\x1e\x1f\x19\xd4\xeb\x8f\x1c\x39\x53\xc9\x3a\x83\xdb\xb5\xf5\x00\xc3\xd3\x70\x11\xed\x33\xc7\xa2\x05\xaf\x7c\xb7\x5e\x53\xa9\x0f\x44\x9b\x74\x63\xc6\x94\x40\x34\xc0\x8c\x19\x53\xcf\xd1\x93\x56\x11\x7f\xb4\x41\xd7\xe8\x06\x49\x9d\x48\xfc\xd1\x90\x7e\x15\x4a\xeb\x65\x5b\x89\x5f\x9d\xd8\xa0\xf7\xae\xa6\xfa\x80\xbe\x7e\x1c\x56\x97\xa7\x34\xc9\x0e\x35\x54\xf5\x5d\x7b\xd8\x91\x7c\xe1\xce\xa3\xd3\xf5\x0f\xb1\x9d\x9c\xab\x03\x16\x8c\xe9\xf6\x14\x1e\xe3\xfa\x4f\x18\x7e\x24\x4c\xa7\x16\xfb\x66\x3c\x83\x48\x15\xe0\x57\x2a\xc2\x6a\x88\xa7\x66\x75\x0d\x7e\x6d\x2e\x6a\xe2\x63\xca\xe4\x50\xb4\x29\xbf\x4a\xb2\xfb\x95\x31\x61\xb5\x49\xd4\x59\xaa\x5a\x28\xd6\x01\x6b\x4c\x09\x0c\xe5\x5d\x09\x48\x9a\x62\x2a\x42\x48\x2d\xb0\xc5\x94\x71\x21\xa5\x40\x52\xc7\x6b\xb3\x56\x6b\x4c\x9d\x4a\xfc\x6a\xbd\x55\x76\x44\xa4\xaa\x90\xb6\xd0\x2a\x90\x55\x67\x65\x63\xa3\x32\xde\xd1\x93\x9f\x4d\x97\x65\x50\x43\x55\xba\x27\x66\xbe\x1c\x41\x49\x25\x45\xbc\x49\x76\x44\xac\xf6\x11\x5d\x71\xf5\x70\xdf\x34\x82\x89\x8a\x21\xb8\x93\x04\xe3\xc4\xb8\xcf\xde\xff\xef\xce\xb9\x9d\x6b\x5f\xe4\xc4\xff\xfe\xb7\xe5\xcf\x86\x26\x3f\xbb\xe0\xd8\xe7\x7d\x4d\x1c\xf9\xe9\x43\x9d\xb7\x4d\x6f\xa9\x7f\x71\xcb\xa6\xdf\x36\x37\x7c\xf8\xe8\xde\x17\x7a\xe7\x77\x4c\x7b\xc2\xff\xc9\x9a\x3b\xb8\x83\x1c\x39\xb3\x66\xdd\x8d\x9b\x49\xf0\x67\xbf\xb8\x7c\xf1\xcd\x4b\xa7\x3b\x0c\x9b\x9f\xbb\xf4\x92\x8b\x2f\x8b\x9f\xf9\xf4\x26\xf1\x91\xc3\x63\xc3\x9b\xab\xa6\x77\x5c\x3d\x63\xc9\x33\x3b\x2e\xba\xf6\xca\xc6\x77\xbb\x89\x49\x2c\x5e\xfb\xe0\x1e\x1a\x93\x1d\x6f\xa5\x5c\x28\xc3\xd9\x7b\xc8\x3f\x65\xef\xc9\xfc\xe7\xec\x3d\x94\x3a\x65\x38\x1f\x6f\xa1\xb4\x84\x4b\xb7\xf7\x74\x9c\x3e\xf1\xd2\xd7\x42\x2a\x87\x8a\x18\xef\x7b\xfa\xe4\xdf\xc9\x95\xa9\xc6\x1e\x4a\xa8\xf2\xd1\x63\x29\x6c\x2a\x5b\xfe\x8b\xd4\xf5\xed\x18\x6c\xe5\xe1\x75\x0e\x12\xf1\x63\x64\xd3\xbd\xac\x25\xe9\x2c\x24\x25\x7c\x2c\x5a\xa8\xb3\x90\x14\xf2\xc9\x6d\x2d\x8b\x23\xa6\x14\x50\x16\x92\x22\x36\xc9\xaf\x20\x7e\xd5\xa2\x8d\x39\xee\x1c\xea\x93\xb0\xdf\x2c\xd8\x5d\xb9\x79\x34\x90\xc9\xe8\xf8\x6e\x84\x24\x74\xae\x78\x76\x56\x92\xdb\xb5\x59\xa2\x72\x16\x6a\x12\xe1\x55\x43\xfc\xdb\xbe\xe7\x13\xfc\x24\x09\x39\x7f\x4f\xb9\x56\xca\xd0\x79\x2e\xb6\x95\xf2\x11\xd8\x56\x2a\x18\xdb\x0a\x95\xcf\xe3\x2d\xd3\x09\x57\x7a\x24\xb9\xa4\x94\xbe\x34\xdf\x91\x73\x85\x4e\xf2\xce\x4e\xbc\x72\xaf\xbe\x43\x39\x32\xfd\x0a\x79\x3d\xe1\xab\x40\x65\x34\x18\xa9\x8c\xa3\xd0\x9d\x2e\x63\x05\x1f\x8b\x7a\x75\x19\xbd\x9a\x8c\x95\x49\x19\x3d\x54\xc6\x12\x26\xe3\xe8\x41\x6d\x59\x22\x3f\xaf\xb7\x65\x61\xb1\xde\x98\x3d\x92\x9c\x5f\xf0\x5d\x84\x4d\x4e\xcf\xce\xde\xa6\x0f\xe8\x13\xb3\x45\x67\x69\x55\xfe\x0b\x7d\x4a\xd6\x77\x37\x6b\x58\x81\xb5\xeb\x9b\xc8\xa6\xcc\x8c\x3e\x6c\x48\x97\xda\xcb\xc7\xa2\x05\xba\xd4\x05\x7c\x4c\x71\x07\x94\xb2\xb0\x9a\x63\x89\x29\xe5\xa1\xc4\x52\x51\x83\x20\x3f\xd4\xe3\xb6\x68\x63\x7e\x9e\x8d\xd2\x03\x94\x11\xbf\xea\xb3\xc5\x7a\x0a\x7d\x65\x26\x7f\x92\xb0\x3f\xcf\x2d\x3b\x54\x73\x01\xf5\x0b\xeb\xb1\xbb\x04\xaf\x06\x89\x4f\x8f\x35\x35\xeb\xf4\x07\x67\xc1\x21\x9c\x95\x84\x80\x72\xd9\x0f\x0b\xc3\x8a\xe3\x3f\x66\x08\x90\x45\xc7\x87\x05\xe1\xe4\x91\x23\x7d\x9b\xf5\xa6\xff\xeb\x91\x23\xe0\xfa\x5f\x00\xc8\x6c\xf1\x28\xb5\x9d\x55\x26\x6c\x67\x84\xd9\xb8\xce\x6d\x38\xbb\x80\x1a\xce\x7a\xc5\x5e\x43\xfc\xdb\xd3\x93\x84\x71\xa7\x0f\x83\xc3\x03\x00\xd7\x22\xbe\x3e\xd8\x6e\x46\xce\xdb\x6e\xf6\x40\xef\x8b\xba\x83\xee\xb8\xd3\x87\x85\x5f\xa6\xd8\xcd\xde\x04\xb8\x90\xf8\xf5\x60\xbb\x19\xf9\x4e\x76\xb3\x3a\x66\x37\xeb\x15\xbe\x64\xce\x32\xd9\xb4\xd2\xd4\x6e\xf6\x04\xc0\x5d\x29\xee\x67\x76\xb3\x66\x66\x37\xa3\x7b\x3b\x66\x3d\xa4\xc8\x14\xa2\x91\xa0\xff\x88\xe5\xec\xea\xe3\x39\xbd\x45\xc7\x85\xaf\x8e\x1c\x39\xed\xa0\x92\x7d\x45\xf7\x68\x2e\xec\x3f\x21\x04\xc5\x3f\xc2\x83\x6a\x2c\x67\xac\xd0\x65\x7c\x4c\xf1\x07\x54\x9e\x91\xce\x08\x3a\xa3\x4a\x4d\xca\xe4\x88\xc6\xc5\xe4\x5b\xa9\xcf\xa1\x36\x72\xf8\xbc\xb2\xe3\x39\xde\xe6\x72\x17\x19\x35\xad\xca\x97\x95\xac\x46\xa8\xfe\x32\xd9\xa1\xa0\x51\xe1\x65\xd5\x60\x6c\x6c\x54\x24\x47\xc4\x62\x75\x6b\x63\xb6\x2c\xab\x2e\x46\x93\x46\x73\x98\x8c\xad\x21\x3e\xd1\x57\x5e\x43\x7c\x63\x8b\x88\x7b\xac\xdb\x98\xed\x48\xa3\x0d\xa1\x41\xb4\x17\x12\xd7\x3b\x57\x3f\x52\x27\x98\x2f\x9f\x1a\xff\xe0\x12\x02\xdf\x65\x55\xe3\x67\x6c\x9b\xf4\xde\x25\xaf\xce\xe9\x8a\x7f\xf4\xbb\xf7\xe2\xb1\xde\xc7\xb7\xdc\xb6\xa7\x74\xd7\xea\x5b\x77\x91\xff\xf8\x94\x14\x5c\x34\x5e\xbc\x41\x69\xfe\xf9\xc2\xed\xd9\x25\x19\x8f\x3b\x9b\x6b\xfe\x65\x61\x77\x57\xfc\x8f\x8f\xbd\xff\x4d\xfc\x0d\x92\xf3\x9b\x8d\x6f\x7c\xfa\xcc\x7d\x4d\x97\xd2\xbc\x00\x94\x83\xc5\xe0\x80\x13\x3e\xdc\x36\x02\x0b\x8b\xe2\x0d\xa8\x79\x62\xac\xa7\x2c\xcf\x6b\xf2\xab\x6e\x96\xd1\x85\x1c\xa3\x94\x2c\x9c\xa4\xf8\x3c\xc7\xe4\xa8\x4b\x9f\x11\xba\x02\x51\x9f\x7e\xe6\xa0\x4e\x87\x56\xe2\x57\x0a\x29\x81\x47\xb4\x48\x5f\xf7\x68\xef\xa4\x95\xc8\x8e\x88\x21\xd3\x4b\xd7\x8f\x5e\x22\x3b\x14\x5f\xa3\x92\x27\x2b\xae\x11\xc8\x5b\xf8\x61\x56\x32\x83\x09\x5d\x6e\x48\x77\x5c\x4a\x27\x78\x11\xf3\x06\x9b\x0e\xc0\xeb\x7c\x2f\xe2\x47\xb0\x43\x5b\x1b\xb6\x31\xcb\x41\x76\xca\xf8\x92\xb0\x67\x0d\xb0\xaa\x25\xed\x59\x4e\xba\x5a\xcb\xa4\xd6\xc3\xa8\x20\x59\x1d\x32\xb3\x0f\x0c\x62\x7f\x49\xd9\x44\x19\x96\x02\xe6\x51\xed\x3d\x7e\x67\x04\x1e\x18\xe1\xa0\x36\x20\x36\xa5\xb0\xc1\x24\xea\xfc\x3e\xb3\xc1\xb5\x0d\xcb\x52\x73\x56\x1b\x5c\x54\xb0\x16\x14\xd2\x10\x1d\x93\xac\x16\x15\x9f\x93\xb1\x86\x0e\x77\xc3\xd3\xd6\x1c\xd6\x87\xb9\x91\xc8\x6b\xb8\x7d\x29\xfb\x17\xb4\xde\x06\x03\xec\xc8\x46\x19\x66\xb0\x7a\xe7\xa5\xf4\xf8\x89\x01\xdc\x6d\x8d\x29\x6e\xdd\xbb\x37\x61\x7f\x73\x27\xb1\x2e\x94\x9f\x13\x24\xd9\x95\x6d\xd5\x29\xbb\xa8\x67\xd1\x50\xd0\x07\x6f\x2e\x0c\x0b\x7c\x8f\xde\x21\xdd\x3d\x02\xf4\xfc\x87\x6c\xd4\x72\x0c\xe2\xe2\x49\xc8\xe1\x80\x1d\x5e\x04\x70\x2b\x93\xa3\x3c\x21\x47\x15\x1f\x53\xf2\x03\xaa\x4b\x8c\xf5\x14\xb9\xf2\x4d\x7e\xdd\x71\x3d\x98\xc8\xd1\xa8\x94\x48\x8a\x57\x7b\x5b\x32\xf4\x77\x24\x23\x90\xd8\x29\x28\x91\xd4\x51\xba\xc4\x8a\x5b\xfb\x82\xee\x59\x46\x0d\x72\x6e\xad\x93\x11\x64\x6b\x3e\x25\x62\x81\x9a\x2f\xd0\x2c\x05\x8a\x2b\x91\xe8\x6a\x90\xec\x23\xae\xf9\x87\x85\x61\x73\xda\x6b\x53\x3b\x12\x1e\x7f\x4f\x79\x7b\xfa\xe4\x54\x50\x04\xa6\x93\x47\x61\xa7\xec\x3e\x94\x6b\xd9\x9a\xe0\xf7\x49\x52\xfb\x64\x50\x1b\x5c\xe6\x20\x1b\x9c\xc3\x1a\xeb\xc9\x70\x68\x23\xb8\x6c\x4b\xf2\x2f\x9a\xac\xb1\x9e\x52\x53\x8e\xc9\xaf\x7a\x6c\x31\xc5\x13\x50\x4b\x6d\xcc\x10\x27\xcb\x8e\x1e\xc1\x9a\x55\x30\xec\x8b\x96\x5c\x7f\x27\xe4\xd4\x86\xeb\x41\xb2\x6e\x3d\xfe\x58\x42\x3a\xf2\xb3\xe3\xe9\x02\x7e\x72\xe4\x48\x5f\xc6\x80\xee\xbe\x4f\xfd\x2b\x78\x5c\x80\xa8\x50\x2d\x44\xd8\xd8\x54\x03\xc6\x75\x46\xc3\x33\x4c\x94\x8d\xc8\x6c\xd1\x59\xf5\x85\x63\x8a\x49\x4f\x38\x6c\x09\x0d\xe4\x31\xa4\xd5\xd0\xc6\xa3\x0b\xf8\xcf\xfa\xf6\x1d\x3e\x7c\x98\xbb\xfc\xc5\x17\xe3\x73\x8e\x1e\xe5\xc3\x47\x8f\x52\x7d\xba\x59\x18\x2d\xbc\xc0\x6c\x73\x5d\x09\xdb\x5c\xca\x5c\xfe\x5c\xb6\xb9\xec\x46\xa5\x4a\xde\x6f\x12\xb2\x64\x77\xc2\x38\xa7\x5a\x68\x64\x47\xaa\x79\x4e\x2d\x0c\x52\xe3\x9c\x6a\xb4\x34\x26\x95\x86\x99\xe7\x74\x08\x07\xcc\x73\xee\xb0\x3e\xec\x64\x0d\x10\x5a\xfa\x4a\x35\x28\x1b\x3a\x6b\x2e\x5a\xdf\xd5\x3e\x3b\x7e\xe6\xa3\xf0\x35\xa3\x2f\x5c\x3f\xff\xba\xce\xde\x51\x95\x06\x32\xad\xb0\xa5\x7c\xeb\xbd\xcf\xe6\x34\x78\xb7\x6e\x2f\xf5\x18\x74\x68\xb3\x5d\x3f\x79\xfb\xa2\x2f\xb6\x6a\xf0\xca\xd2\x8e\x37\x2f\x38\xf5\x93\x1f\xfc\x6b\x90\xdb\x2d\x39\xfe\xb0\x37\xbe\xca\x66\xfd\xe8\xe9\xec\x99\x5b\x03\xd4\x6e\x41\x39\x73\xc4\xa3\x70\x22\x07\x1d\x23\xb2\xe6\xe4\x9e\x9d\x35\x27\x2f\x11\x71\xe4\xca\x6a\xd4\xa6\xb7\x3d\x72\xb6\x3b\x47\x8f\xe1\x3f\x37\x85\x0e\xed\xa6\xd3\x78\x74\x56\x52\xd3\xdd\x10\x32\x1d\xe1\xaf\x49\xdb\x9d\x5e\xef\xd7\xff\xf9\x7a\x9b\x79\xd9\xd1\x23\xbb\xb2\xf4\xfa\xd2\x14\x52\x36\x87\x9a\x4d\xcd\x19\x67\xad\x37\xb5\xf1\xa5\xf3\xff\xcc\xd1\x77\x97\x87\xd4\x9c\x3f\x95\x62\x2b\xd2\xeb\xfe\x35\x9c\x28\xc0\xe2\x11\xeb\x5e\x78\xf6\xba\x17\xa5\x61\x1e\x95\xb3\xdd\x79\x05\x49\xd0\x15\x9b\xac\xe6\xe4\x9e\x53\x88\x64\x77\x9d\x26\x08\xf3\xb5\x1e\xa6\x09\x0a\x07\x6c\x83\xba\x1c\xfb\xe1\x84\x1b\xf9\xf8\x61\xba\x24\x59\xda\x24\x32\x37\xac\xba\x2c\x31\x25\x27\x34\x20\x58\x41\x52\x30\x97\xe7\x98\xac\xba\x6d\x69\x12\x2a\xf9\xda\xc7\x39\x36\xea\xf4\x9f\x6f\x4b\x15\x5a\x1b\x98\x72\xb4\x35\x85\x6c\x38\x0f\xd1\x74\xe3\x61\x9a\x64\x1d\xc7\x4f\x1f\x1f\x46\x2c\x2f\xb3\x1f\x52\x9e\x20\xf1\x75\x64\x21\x0f\x13\x87\x32\x05\xe5\x27\x99\x82\x0a\x88\x5f\x35\x88\xb2\x83\xa1\x7c\xde\x9c\x41\x74\xba\x3f\x22\x71\x10\x5b\x04\x0c\xa1\x0f\x12\x9e\x4c\xd1\x9f\x07\xe2\xd7\x09\x61\xc6\xed\x7a\x79\x0a\x27\x5d\x0a\x1d\x9d\x42\x52\x19\xe9\x54\xce\x11\x0a\xa5\xf3\xd1\xd1\x5c\xcc\x3a\xbb\x2e\x63\xa2\x53\x0d\x05\x09\xfa\xa9\x74\x7e\xdd\x34\x2e\xba\x07\x7a\xeb\x77\xce\x1d\x86\x8a\xce\x78\xa0\x6f\xef\xd4\x0b\x47\xe6\xa2\xe3\x19\xbe\xfb\xa9\x35\xb9\x10\xab\x10\x71\x6b\x5a\x92\x1f\x56\xb3\x2d\x31\x25\x2f\x34\x04\xf0\xa2\x80\x92\x7d\x2c\x61\x39\x16\x35\xcc\xb5\x45\xa6\x41\x64\x2b\xcf\xbc\x80\x5a\x68\x8b\xa9\xc5\xc4\xaf\xe6\x66\xcb\x8e\x88\x45\x26\xda\x5c\x3f\x4f\x8e\xf0\x02\xb5\xce\x9f\x7f\xc3\x24\xbc\x2f\x47\x6a\x9b\x78\xfc\xf8\xe9\xe3\xc3\x35\xcd\xbb\xba\xbf\x08\x87\xae\xfe\x13\xc6\x19\x34\xef\x5f\x39\x36\xea\xf1\x66\x94\x29\x38\x99\xfe\xcf\xc8\xb1\xec\x42\xba\xef\x07\x1f\x8b\x5a\x33\xb2\x04\xdd\x3a\x4c\x94\x8a\x64\x1e\x40\x96\xfe\x2f\x93\x8e\x67\x91\xcc\x22\x4a\x34\x6c\x36\xfb\x15\x29\xd4\x33\x39\xd3\x6e\xf6\xd3\xb5\x50\x51\x8e\xec\x50\xb3\x04\xca\x82\xa3\x38\x1a\xa1\xbb\xcf\x15\x35\xaa\x46\x4d\xe4\xe2\x94\x74\x8d\x03\x2e\xa6\x5e\x96\xf5\x21\x95\x8c\xaf\x8b\xd4\xff\xad\xf5\x9e\x19\xfc\x5d\x49\xa7\xd3\xc5\xd7\x6c\x68\xf9\x5b\xfc\x8d\xde\x57\xf6\x4c\x58\x3b\x6e\xc2\xda\xf1\x7b\x0e\x71\x93\x49\x90\x98\xc9\x34\x9b\x99\xb9\xa2\x5a\xac\x64\x1a\x31\x1f\xfb\xd4\x6c\x16\x6e\x31\x59\x3f\x79\x87\xcd\xcf\x0c\xff\x23\x4c\x47\x09\x82\x68\xc4\x76\x44\x3c\xda\x8a\x26\x2f\xac\x56\xf0\x31\xc5\x19\xa2\xa3\xaa\x62\x09\xab\xd5\x7c\x4c\x19\x1b\x8a\x86\x32\x3d\x9a\xec\xa1\x81\x4c\xda\xa5\x56\xea\x01\xa4\xad\x52\x24\x47\x4c\xa9\x0d\x29\x92\x44\x07\x5b\xbb\x55\x4f\xa1\x5d\x59\x2a\x3b\x54\xc1\x43\xe3\x13\x54\x63\x61\x63\xa3\x12\x76\xf4\x64\x5a\x9c\x79\x7a\xe7\xcd\xba\xed\x0a\x8f\xec\x50\xdc\x1a\x2c\x6a\x76\x61\x63\xa3\x5a\x1d\x4a\xd2\x12\xea\x23\xef\xc8\xfb\xae\x69\x13\xf0\xf2\xc4\xfe\x83\x36\x02\x6f\x38\x32\x79\xca\xcb\x4b\xd2\x76\x20\x6e\x3d\x3a\x65\xf2\xe1\x5b\x52\x67\xe6\xbc\x3b\xb1\x23\x43\x87\xe2\x1b\xe6\x76\x2c\x4d\xdd\x90\x58\x74\xdd\x75\x8b\x52\x67\xea\x9d\x03\x7b\x6e\xba\xef\x82\x8d\xae\xf5\x25\x5c\x36\xd8\x7b\x41\x31\x07\x14\x7b\x58\xb5\x58\x62\x4a\x46\x88\xba\x6a\x6b\xab\x7f\xbd\x77\x34\xea\x59\xa9\x14\x83\x44\x13\xb6\x48\xb6\x18\x75\xbd\x38\x0b\xad\x3d\xcf\x94\x7d\xc0\xbf\xe1\x4f\xd4\xd1\x38\xc5\xbb\x61\x2c\xf3\x35\x26\xd8\x27\x7c\xca\xcb\xe2\x09\x98\xe0\xa7\xf9\xa6\xc5\x70\x94\x63\x81\xc7\x74\x73\x23\x2a\xd2\x90\x5b\xd5\x92\xa0\x68\x63\x60\xb3\xa1\x65\x9f\x3e\x96\x08\x9f\x26\xdd\xad\x41\x70\x87\xf0\x31\x3f\x41\xfc\x33\x9c\x98\x01\xca\x75\x2c\xc6\x7a\x24\x83\xdd\xe4\x57\x79\x31\x41\x3d\x1a\x75\xea\xf3\x73\x27\x1d\x1d\xa2\x16\x7d\x5a\x4e\x29\xfa\x9c\xb2\x43\xe5\x69\xdf\x25\xd9\xe9\x82\x5f\xe5\x0d\x2c\x7c\x69\xb8\x59\xf8\x1d\xe9\x2b\xd4\xd3\x83\x17\xa4\xa9\x1c\x11\x18\xc4\x00\xf1\xcf\xfc\x6e\x0f\xb7\x49\xf8\x9c\x2f\x05\x0f\xf7\x10\xde\x89\x01\x12\x83\x3d\xc2\x44\x6e\xd3\x43\x0f\x81\x60\x2b\xb7\x49\xec\x3d\xe7\xf7\xb7\x8a\x0d\xec\xfb\x33\xf9\x33\xe4\x52\x9a\x6f\x3d\x99\x83\xdb\x34\x90\x83\x5b\x64\x39\xb8\x45\xa2\x6b\x81\xf6\xd7\xce\x30\x9f\x35\xf3\xd1\x8e\xf1\xfc\x99\x03\x64\x7e\x7c\x67\x84\xe5\x6d\xe7\xfb\xce\x72\x9f\x11\x73\xb6\x8f\xef\x7d\x94\xef\x23\x57\xbe\xf6\x72\xfc\x09\x76\x9f\x7e\x42\x2e\xc5\xdf\xce\x3b\x27\xb8\xdb\x99\xb8\x4f\x3f\x31\x7e\xfd\x61\xfc\x73\x70\x9a\x4c\xdc\x83\xb4\x2e\x56\x34\x53\x6d\x33\x84\x59\x85\x14\x93\xee\xbe\xad\xcb\xa6\x88\xba\xde\x5b\x59\x96\x22\x26\xa6\x62\x94\x29\x2b\x2d\x75\x92\x4b\x88\x1c\x4e\x0a\xbe\x31\x45\x78\x06\x81\xf6\xcc\x3e\x6e\xf7\x39\x9f\xa9\x07\xe3\xd0\x67\x5a\xd8\x33\x99\x28\xda\x33\x0d\x89\x84\x4d\x09\x78\xc2\x49\xe1\x4e\xa5\x00\xc5\xe0\xe2\x30\xb3\x5f\xe6\x6e\x23\xff\xdf\x9e\xa9\x43\x39\xf0\xcc\xb7\xc7\xf7\x3e\xfa\x7f\x49\xeb\x2b\x07\xe2\x2a\xb9\xe4\xe0\x81\xb8\x4a\x7d\x81\x38\x37\xe7\xe3\x3f\x86\x5d\x5b\x4b\x59\x03\x51\x81\xb6\x0f\x2b\xa8\x77\x14\x8e\x45\x4d\x94\x44\x80\x15\x6a\x26\x53\xbb\xd4\xb8\xee\x3b\xbb\x67\xcf\xb9\xb1\x7b\xce\x9c\x6e\xee\xf7\xe3\xdb\xbb\xbb\xdb\xc7\x5f\x75\xc3\x52\xda\x7f\xed\x02\x84\x5e\x9a\x8f\x5d\x5b\xaf\xb5\xb2\x18\x0a\xc1\x14\xa6\xde\xf7\xaa\x68\x0e\x85\x52\xb2\xb3\xdb\x52\xe7\xb7\xe9\xdb\x89\x03\x19\xd1\x58\x47\xa5\xe7\x6d\xff\xb6\xf7\xc3\xde\x5f\xd1\x1f\x4d\x9e\x25\xb8\x9f\xf3\xd1\x38\x71\x2f\x88\x62\x4c\x74\x45\x16\x3d\x0f\x86\x76\x1f\x11\x3a\xf1\xbe\x9e\x92\x9a\x27\xa5\x4b\x18\xef\x0c\x57\x98\xa0\x9b\xa1\x7e\x9e\xf7\x73\xce\xc1\xf7\x51\xb8\x10\xbb\xd5\xc0\x7d\x88\x76\x1f\x16\x8e\xde\x3e\x34\xfc\x5c\x7f\x07\x66\xf4\x9f\xe0\xdf\xa1\xb9\xc6\xff\x07\x11\x1f\xf4\xd4\x8e\x34\xd2\x41\xb1\x86\x55\x99\x8f\x29\x52\x28\x0a\xe2\xb3\xd8\xe9\xdc\x18\x7c\x4c\xc9\x0f\x45\x45\x81\x7e\xe0\x0e\xd3\xe8\x92\xac\x50\x4f\x86\xcf\x62\xf2\x53\xea\x0a\xee\x98\x6a\x18\x1d\x0a\x51\x33\xa4\xab\x30\x14\x8a\xe4\x72\xda\x74\x20\x37\xdf\xec\x57\xb2\x43\x11\x2e\x57\xbb\xe2\x60\xf6\x2b\x42\x48\x9b\x23\x69\x3a\x52\x95\x92\xf8\xda\x5e\xf3\x06\x54\x3b\x4b\x7c\xfd\xa7\x8f\x5f\xbe\x46\xcf\x21\x93\x41\x13\x5f\xdb\x25\xc5\x7a\xe8\xe0\x37\x33\x0f\x7d\x86\x2c\xbf\x55\xb1\x4a\x3d\x36\xab\xdd\xe9\x57\x24\xa9\x27\x53\xca\x70\xfa\x23\x36\xab\x3d\x25\x5b\x72\xa6\x44\x73\x61\xab\xb6\xcc\x9a\x1a\xd2\x63\xb5\x65\x4a\x29\xd9\x92\x3d\xd4\xfc\xa9\xd3\xce\x97\xd6\x87\xd9\x50\x9b\xa0\x9e\x67\x94\x65\x46\xc3\x00\xb5\x2b\xea\x67\x6c\xdf\xbe\x9d\xe4\x7f\xde\xb4\xaa\xd9\x39\xe6\xc6\x86\xed\xfb\xc8\xc9\xb8\x8b\x9c\x8c\xe7\x73\xc2\xbe\x1d\x8d\xdd\x75\xce\x86\x1f\x4e\xf8\x3c\xfe\x09\xf9\xf8\xa1\x4d\x0f\x65\xfe\x85\x94\x4a\x99\x8f\x48\xce\xb7\x9e\x96\x1f\xda\xf4\x90\xb8\xf9\xd7\xb2\xfc\xd3\x4c\x89\x78\xdf\xd1\xe7\xc4\x9d\xfc\xbf\x0a\xd7\xd1\xfc\x44\x6e\xac\x61\x6c\x08\x66\x7b\x38\x1c\x85\x6e\x71\xe7\x93\x3c\x2b\x06\xb3\x3f\x62\xca\x74\x86\x42\x21\xca\x09\x63\x38\x16\x15\xe9\xc0\x32\x7c\xe6\x22\xad\x9b\x31\x11\x7f\xd4\xad\x0f\x45\x6e\x1a\xbf\x13\xcd\x1c\xe0\x8d\x91\xb4\xe5\x88\xc5\xce\xb6\xc2\xbc\x94\x61\x9f\xc8\x61\x67\xd8\x19\x96\x4b\x65\x1f\x5f\xca\x1b\xe5\x4e\xb2\xee\xde\xd9\x64\xc2\xca\x5d\x86\xdd\x4b\xaf\x35\xec\x0c\x3f\x6c\x10\x67\xcf\x9a\x15\x6f\x24\xaf\xc7\x1b\xb9\xdc\xf8\x5a\x72\x7b\xdf\xe7\xe4\x4a\x2e\xfe\x24\xe9\xe4\xe2\x3a\x3f\x0b\x00\xa1\x41\x68\x00\x8f\x7a\xfd\x3d\x8a\x12\x8b\x36\xc8\xa6\x9e\x33\x72\x8a\x28\x4f\x87\x5f\x56\xb0\x91\xa2\x56\xf6\xca\xda\x0d\x4e\x1f\xd1\xf1\x29\x00\xf8\x77\x68\xbe\x81\x7c\x7c\xae\x67\x1c\x50\x72\xf4\xbd\x66\x55\xce\x0d\x27\xd3\x0e\x58\x02\x8a\x3d\xa0\xd8\xc2\x34\xfa\xd2\xa8\x47\xac\x9c\x3b\xff\x00\xa3\x06\xe9\x91\xcc\xf9\x19\x7e\x7d\x0a\x1b\x50\xf3\xf5\xf0\x95\x84\x26\x5a\xcc\x9a\x26\x9a\x2d\xba\x26\x9e\xbc\xe4\xd5\x02\x5d\x13\x2d\x92\x62\x3b\xa4\x98\x25\xc5\x78\xe8\xe0\x57\x2f\xbf\x32\x9b\x6a\xa2\x51\xea\x31\x19\xcd\x4e\xbf\x62\x93\x7a\xac\x36\x8b\xd3\x1f\x31\x19\xcd\x29\x9a\x68\xb5\x59\xa8\x26\x9a\xac\x9a\x26\x1a\x4d\x56\x5b\x92\xaa\x36\x27\x4b\xe7\xdc\x1f\x39\x01\x02\x91\xc3\x72\xc1\xde\x77\x7e\xd9\xb2\xa1\xbd\xa4\x7e\xcd\xa4\x55\x9d\xbf\xfb\x5d\x2f\xf7\xbd\xc3\xfc\x53\xdb\x57\xed\x3f\x52\x5c\xf4\x68\x56\x51\xd7\x92\x55\x34\x0f\xc2\x99\x76\xdd\x52\xc2\xa1\x01\x10\x7c\x0c\xbf\x15\x83\xf1\x4b\x49\xda\x60\x0e\x28\xb9\xe1\x1e\x97\xd9\x90\xe1\x57\xed\x2c\xb1\xdd\xf9\xa1\x97\xa3\x1b\x37\xf4\x15\x6e\x16\x63\x53\x48\xa6\x74\x38\xbb\x2c\xe9\x09\x1d\xb8\xf5\xc3\xe5\x74\x38\xd3\x4e\x29\xed\xc1\x6b\xb2\x18\xee\xa7\xb2\x04\x10\x26\x21\x5d\x1a\xb5\x3a\xc8\x78\xed\x7b\xe4\xdc\xca\xda\x32\x37\x15\x2a\xe2\xcc\xf1\x87\x42\x21\xa5\x84\xaa\x45\x79\x58\x5b\xd8\x2b\xc5\xba\x37\xd0\xf9\x09\x56\x43\xfc\x4a\x5e\x48\xad\xa6\x7c\x7f\x91\xea\x1a\xed\x77\xd5\x7e\xb3\x3f\x52\x53\xad\x9d\xd6\xe4\x98\xfd\x4a\x35\x75\x12\xe8\x91\xbc\xe1\x0c\xbf\x1a\xb4\xea\x8e\x42\x56\xea\x28\x94\xd0\x9e\x12\xaf\xa6\x3d\xde\x92\xc1\xda\x93\xa1\x94\x48\x4a\xd9\x21\x51\xf1\x4a\x4a\x71\x8a\xfa\x14\x4b\x3d\x9e\x62\xaf\xd3\xaf\x94\x49\x3d\xa5\x65\x25\x4e\x7f\xc4\x53\xec\x4d\x51\x9f\xd2\xb2\x12\x4d\x7d\x22\x9e\xd2\x32\xca\x75\x5c\xac\x9f\xe8\x0a\x54\x93\x80\x5f\x0d\x56\xd3\x05\x15\x54\x7b\xc9\x79\x65\xd6\xf0\x7e\x87\x46\x22\xf1\x61\x35\x30\xbd\xd5\x46\x54\x49\xd6\x8e\x5f\x26\xda\x11\x4f\xa7\xb7\x63\x44\xce\xad\x0c\x87\x07\x35\xa3\x3d\xa0\x94\xe8\x6d\x58\x14\x52\xcd\x62\x4c\xf5\xd6\x86\xfe\x17\x1a\x33\x48\xfc\x89\xf6\x4b\x43\x93\xb2\xb6\x9e\xe5\xd5\xfc\x2e\x08\x72\x79\xe7\xa5\xf7\x23\xbd\x08\x44\xef\x67\x0f\x8c\xf9\xb6\x7f\x4e\xe6\xf8\x6f\x50\x6c\xd2\x7a\x4a\xfc\xe6\x96\x87\x7f\x9d\x28\xfb\x9f\x88\xcb\xc6\x0e\xe3\x16\x00\x26\x70\xd0\x7f\x08\x60\xba\xa9\xef\x17\xda\x47\xfd\x4f\xf4\x3f\x6d\xec\xd0\x7b\xeb\x94\x9f\x2f\xb9\x93\x98\xaa\xdd\x8d\xf4\xe9\x07\x97\x8f\x7d\xdc\xc3\x98\x29\x9c\x41\x9b\xb0\x1e\xcb\xc5\xf7\xd0\x25\x9c\xc1\x64\xd2\x89\x99\xdc\x93\xd8\xc8\x3d\x0b\x03\xbf\x12\x05\xc2\x66\x4c\x27\xf7\x21\xc8\xd5\xa2\x94\x2b\xc3\x2e\x7e\x16\x24\x61\x03\x6e\x14\xd6\xe3\xa0\xb0\x1e\x1d\xc2\x7a\xcc\x17\xd6\x63\xac\xb0\x1e\x3f\x15\xd6\x63\xa3\xb0\x1e\x97\x08\xeb\xb1\x50\x58\x8f\xcb\x38\x11\xbb\x38\x3b\xe6\x09\x12\x2e\x10\xd6\xe3\x7e\x21\x88\x4d\xfc\x5b\x98\x60\xac\xc4\x72\xb1\x06\x2e\xb1\x10\x51\x51\xc6\x6a\xb1\x15\x51\xe1\x17\x88\x0a\x7b\x10\x15\x57\x62\x8d\xf8\x1c\xa2\x5c\x0b\x5e\x12\x16\xa3\x59\x2c\x47\x54\x98\x85\xa8\xd1\x88\xa8\xf6\xb9\xb8\x12\x37\x8a\x1e\x56\x5e\x82\xa8\xd0\x87\x85\x82\x82\x12\x71\x31\x76\x88\x99\xc8\x36\xca\x18\x23\x66\xa2\x59\xf8\x03\x5c\xc2\x1b\xe8\xe0\x46\xe1\x1e\x7e\x3a\x7c\xdc\x28\x58\xf9\x76\x4c\xe0\x1f\x83\xc0\xad\xc7\x2c\x61\x21\x16\x0b\x5b\x70\x8f\x30\x09\x1d\xc2\x16\xcc\x15\x9a\x30\x8f\x7b\x15\x0d\xc2\x16\xcc\xd7\x3e\xe7\x04\x3c\xc2\x39\xfa\x5f\x12\xf2\xb0\x4d\x3b\x37\xc4\x71\x0f\xfd\xfe\x16\xfa\x7d\xad\x9c\xcb\xbd\x84\x7b\x84\x00\x6e\xe0\x5e\x43\x89\xb0\x05\x77\x09\x06\xd4\x18\x32\x50\xad\x95\x82\x01\x79\x82\x01\xb3\xb9\x03\x98\x44\x4e\xe3\x59\xee\x00\xb2\xc4\x65\x58\x47\xf1\x3f\x8d\x6d\xc2\x5c\x5c\x2f\xec\x45\x9b\xa8\xa0\x4b\x38\x8e\x22\xf2\x67\xdc\x2b\x9c\xc0\x6c\xbe\x0f\x7b\x0d\x53\xd1\xce\xff\x04\x6b\xf8\xc3\x98\x2b\xdc\x88\x5b\x34\xec\xe9\x67\xfb\xf1\x43\xee\x34\xd6\x09\xdf\xc3\x3c\x7e\x3e\x6e\xe2\x97\xa0\x9b\xbb\x1b\xb7\x0a\x5b\xf0\x00\xff\x15\x26\x71\x05\xd8\x45\xfa\x70\x13\x57\x8d\x39\xfc\xcf\xe9\xdf\x2f\x35\x34\xe1\x80\xe1\x69\x1c\x30\x7c\x83\x75\xfc\x37\x0c\xf7\x61\x0e\xe3\x86\xfe\x93\x5a\x5b\xd0\x76\x48\x39\xb8\x96\xfe\x0f\xb4\xb6\xe0\x5a\xfa\xbf\xe6\x5a\xfa\x8f\x8a\xf3\x30\x3a\xd9\x0e\x69\x87\x70\x21\xda\xe9\xb9\xd6\x16\x29\x07\x6d\x8b\x17\xf0\x98\xd0\x8b\x3b\x29\xee\xc3\x1c\x86\x97\x31\x8e\xb6\x45\x13\xe6\xa5\x1e\x1c\xdf\xff\x02\xc7\xe3\x01\x8e\xef\x7f\x93\xe3\xfb\x9f\x10\x22\xb8\x30\xa5\x1d\x06\x1f\xdb\x71\x01\x3b\xbf\x6b\xd0\xa1\xb5\xc5\x6e\x3c\xa0\x95\xc6\xa7\xd0\x65\x9c\x88\x0e\xad\x4e\xfc\xdb\xd8\xc7\xbf\x8d\x3b\xf8\xc3\x80\xf6\x46\x25\x4a\x6e\x23\x40\x3e\x01\x48\xb3\x7e\xe0\x6b\x80\x6c\x00\x70\x3d\x40\xdf\x03\x76\x88\x9b\xb0\xc7\xf0\x23\x6c\x25\xbb\x31\x93\x1e\xbb\x30\x93\xfb\x02\x33\xb9\x53\x98\xc9\x1d\xc3\x4c\xee\x79\xdc\x29\xce\xc7\x2e\xed\x6f\xb9\x4e\x2c\xe1\x3a\xd1\xae\xdd\x57\x98\x8c\x19\xa2\x80\x4e\x41\x1b\xc1\xb5\x77\xec\x75\x34\x18\xc7\xa2\xc1\xb8\x59\xeb\x3f\x51\xc5\xfe\xb5\x63\x1b\x59\xc9\x81\x7b\x98\x6f\xe0\x67\xf3\x5b\xf8\x83\xfc\x49\xa1\x46\x98\x25\x74\x0b\xdb\x84\xa7\x84\xbf\x88\x45\xe2\x46\x83\xc5\x70\x85\xe1\xa4\x71\xae\xf1\x45\xd3\x54\xd3\x41\xd3\x1f\xcc\x36\x73\x99\xb9\xcd\x7c\x8d\xf9\x35\xcb\x7d\x96\xc3\xd6\x2a\xeb\x76\xeb\x6f\x6d\x36\x5b\xb3\x2d\x6a\x3b\x69\xb7\xd8\xa7\xdb\xb7\xd8\x23\x19\xa6\x8c\xa9\x19\x3b\x33\xde\xcb\x9c\x98\xf9\x84\x54\x21\x5d\x21\x6d\x97\x0e\xca\xd3\xe5\x75\xb2\x22\x7f\xe0\xb0\x38\x3c\x8e\x59\x8e\x95\x8e\xbb\x1d\xcf\x38\xeb\x9c\x0f\x3a\xe3\xae\x2e\xd7\x5b\x59\x9e\xac\x9f\x65\x7d\x96\x2d\x65\x4f\xcb\xde\x94\xbd\xdb\x9d\xe1\xbe\xc2\xbd\x3b\x47\xc8\x59\x9c\xf3\x78\x6e\x49\xee\x9a\xdc\xd7\x72\x4f\xe5\x5d\x91\x77\x7b\xde\x91\xbc\x6f\xf3\x67\xe6\x2f\xc9\x7f\xad\x20\xa7\x20\xa7\x60\x62\xc1\xd3\x85\x25\x85\x7b\x8b\x32\x8a\xea\x8a\x4e\x16\xe7\x14\x1f\xf2\x8c\xf7\x5c\xe3\xd9\xe8\xd9\xed\xbd\xda\xbb\xda\xfb\x4a\x49\x46\xc9\xc2\x92\x2f\x4a\x33\x4a\xe7\x96\xee\x2c\x8d\x96\x9e\x2a\xcb\x2e\xbb\xa6\xec\xc7\x65\x7f\x2f\xbf\xbb\xe2\xea\x8a\x57\x2a\xe2\xbe\x71\xbe\xb5\xbe\x53\xa3\xa6\x8d\x3a\x54\x39\xaa\xf2\xc0\x68\x6e\xf4\x85\xa3\x77\x8e\xfe\xca\x9f\xe7\x6f\xf3\xaf\xf6\x2b\x55\x52\xd5\xe6\xaa\xcf\xaa\xa7\x56\x3f\x5e\x13\xac\x79\xb4\xe6\x95\xc0\x85\x81\x6d\x81\x77\x83\x25\xc1\xb5\xc1\xfd\xb5\x5c\xed\x9a\x50\x46\xe8\xf1\x70\x73\x1d\xea\x9e\xaa\xef\x1a\xe3\x19\xb3\x77\x6c\xd1\xd8\x6d\x0d\x96\x86\x2d\x0d\xfb\x1b\xfe\xd0\xe8\x68\x9c\xd6\xf8\xdb\x71\xd3\xc7\x3d\xd5\x24\x34\x75\x35\xfd\x69\xfc\x75\xe3\xb7\x4d\x70\x4c\x58\x3a\xe1\xcd\x89\xc1\x89\x0f\x4e\x3c\x39\xe9\xa2\x49\x07\x26\x37\x4c\x7e\x77\x4a\xd9\x94\xe9\x53\x76\x8e\xf0\xef\xf1\x29\x91\x29\x87\xa6\xbc\x3b\xe5\x54\xb3\xab\xb9\xa1\xf9\xea\xe6\xfb\x9a\xdf\x6a\x31\xb5\x34\xb4\x74\xb7\x74\xb7\xdc\xd7\x72\xb0\xe5\xe0\xd4\xd5\x53\x3f\x68\x35\xb4\x3e\xd1\x66\x6b\x3b\x75\xc1\x36\x36\x7f\xfe\x12\x6d\xa0\xc9\x4b\xc1\x81\x80\x43\xb6\xf6\x31\xb9\x92\xf5\xd1\x12\x0e\x83\x07\x11\xcc\x00\x26\xd2\xd1\x54\x3b\x27\xb0\x61\x22\x3b\xe7\x90\x81\x8b\xd8\x39\x8f\x3a\xb4\xb3\x73\x01\x05\xd8\xc2\xce\x45\x54\xe1\x29\x76\x6e\x40\x01\xfe\x93\x9d\x1b\x31\x19\xa7\xd8\xb9\x19\x36\x12\x64\xe7\x56\xb8\xc8\x78\x76\x6e\x43\x05\x99\xc9\xce\xed\xb8\x86\xac\x66\xe7\x19\xf8\x3e\xf9\x0f\x76\xee\x40\x01\x57\xc1\xce\x8f\x20\x9b\x6b\x66\xe7\x6f\x20\xc8\xb5\xa3\x0d\xcb\xb0\x14\x2b\xe1\xc1\x7c\x74\x60\x25\x3a\xe0\xc1\x3c\x2c\x43\x37\x6e\xc6\x72\x2c\x42\x27\xba\xe8\x6f\x2f\xc0\x32\x2c\x43\x27\x96\x60\x01\x3c\x08\x21\x88\x5a\x84\x30\x0b\xcb\x30\x17\xcb\xb0\x12\xcb\x30\x0b\x0b\xd0\x89\x55\x58\x82\x0e\x2c\x1f\xf4\xfd\x71\x83\xbe\xe7\x49\xfb\xe6\x38\x76\xb7\xf0\x59\xbf\x75\x05\x16\x60\x39\x56\x60\x11\xad\xaf\x07\xb5\xa8\x41\x2d\x82\xf4\x2f\xeb\x50\x8b\xa6\x64\xad\x06\xdf\xa7\x3a\xed\x3e\x83\x9f\xb1\x08\x2b\xe0\xa1\x32\xaf\xc4\x72\x74\x60\x3e\x16\xe0\x06\xfa\xbd\xeb\xe1\xc1\x32\x2c\x4c\x93\xbc\x66\xd0\xd5\xe0\xdf\x68\xa8\xdd\x80\x16\x74\x51\xdc\x56\x60\x25\x16\xa1\x83\xd6\x55\x7f\xa6\x56\xff\x95\x58\x41\xeb\x3f\x0d\x8b\x30\x0f\x0b\xb0\x14\x2b\xb0\x00\xf3\xe1\xc1\x2a\x2c\xa5\x4f\x5f\x4e\xeb\xd2\x45\x51\x9e\x82\x6e\x74\x60\x1e\xbb\x1a\xfc\x37\x55\xf0\x0c\xc1\x24\x84\x1a\x04\x69\x7b\xad\x44\x37\xc6\x21\x80\x00\x6e\xa2\xff\x6a\xd0\x91\x72\xaf\x1a\x2c\xc3\x72\x74\x22\x80\x25\x83\xee\xb9\x02\x01\x4c\xc3\xf7\xd0\x82\x56\x4c\xc7\x65\x68\x45\x35\xbb\xe7\xd9\x5a\xe6\x4a\x2c\xc0\x5c\x2c\x4c\xea\x51\x2d\xfd\x8b\x36\x8a\x82\x2e\xc3\x72\x5a\xb7\x7a\x78\x68\xfb\x8c\x43\x10\x21\xfa\xff\x98\x64\x9b\xd5\xd1\x37\x8c\xfe\xf4\x2f\xc6\x7c\x0c\xf7\xf3\x25\x40\x38\xc2\x83\x87\x00\x11\x06\x18\x61\x82\x19\x16\x58\x61\x83\x1d\x19\xc8\x84\x04\x19\x0e\x38\xe1\x42\x16\xb2\xe1\x46\x0e\x72\x91\x87\x7c\x14\xa0\x10\x45\x28\x86\x07\x5e\x94\xa0\x14\x65\x28\x47\x05\x7c\x18\x85\x4a\x8c\x86\x1f\x55\xa8\x46\x0d\x02\x4c\xa7\xc3\xa8\x43\x3d\xc6\x60\x2c\x1a\xd0\x88\x71\x68\xc2\x78\x4c\xc0\x44\x4c\xc2\x64\x4c\x41\x33\x5a\x30\x15\xad\x68\xc3\x05\xb8\x10\xdf\xc3\x45\xb8\x18\xd3\x70\x09\xa6\x63\x06\x66\xe2\x52\xcc\xc2\x65\xf8\x3e\x2e\xc7\x15\xb8\x12\xed\xb8\x0a\x57\xe3\x07\xb8\x06\xd7\x62\x36\xe6\xe0\x3a\x74\x10\x01\x8f\x61\x23\x6e\xc3\x2f\xb1\x13\x5f\xe0\x76\xdc\x8d\xbb\xf0\x53\xec\xc1\xe3\x44\xc4\x66\xbc\x87\x5b\xb1\x83\x18\x88\x11\x5b\x89\x09\x9b\xf0\x2a\x3e\x20\x66\xfc\x0c\x7b\xf1\x0d\xfe\x82\x6f\xb1\x1b\xbf\xc0\x1b\x78\x1d\xcf\x60\x2e\xe6\x61\x1b\xe6\xe3\x28\x16\xe0\x08\x7e\x85\xdf\xe0\x4d\xfc\x1a\x6f\x21\x86\x85\x78\x1b\xbf\xc5\xbf\xe3\x59\x74\xe2\x14\xee\xc5\x31\xfc\x27\xde\x41\x17\x4e\xe0\x8f\xb8\x13\x8b\xb1\x08\xd7\xe3\x06\x2c\xc1\x52\x3c\x8a\x65\xb8\x91\xb6\xcf\x0a\xac\xc2\x4a\xac\xc6\x4d\xf8\x12\x6b\xb0\x16\x37\xe3\x87\xf8\x17\xfc\x08\x07\xb0\x0b\xb7\xe0\xc7\x58\x87\xf5\x38\x89\xaf\x70\x10\x0a\x54\xfc\x1f\xbc\x8b\xff\x22\x16\x62\x25\x36\x62\x27\x19\x24\x93\x48\x44\x26\x0e\xe2\x24\x2e\x92\x45\xb2\x89\x1b\x11\xf4\x60\x3f\x9e\xc7\x6b\x88\xe2\x39\xf4\xe2\x0e\xec\x23\x39\x78\x09\xff\x46\x72\x49\x1e\xb6\x90\x7c\x52\x40\x0a\x49\x11\x29\x36\x74\x2e\xb9\xb9\xbb\xab\xd6\xb8\x6a\xe9\xa2\x60\x30\x38\x55\x2f\xa7\x04\x59\xc9\xae\x9b\x43\xac\x0c\xb3\xb2\x9e\x95\x8d\x5a\x19\x0a\x06\x83\xac\xac\x65\x65\x88\x95\x61\x56\xd6\xb1\xb2\x9e\x95\x63\x58\x39\x96\x95\x0d\xac\x4c\xdc\x6f\x8a\x5e\xd6\xb2\xfb\xd6\xd6\x5a\x16\x2e\xea\x5c\xb5\x7c\xc1\xfc\x8e\x15\x5d\xfa\x47\xa1\x36\xbd\xac\x6f\x13\x5a\x57\x2d\x5f\x46\x2f\xea\xdb\x5a\xb4\xb2\xad\x59\xaf\x47\x5b\xb3\x5e\x8f\xb6\x66\xbd\x1e\x6d\xcd\x41\x4d\xcd\x0f\x90\xfe\xdb\x14\xb2\x15\x17\x2b\xa6\x99\xed\x2a\x21\x77\x5f\xa5\xb6\x19\xfc\xed\x5e\x45\xba\xea\x62\xc5\x35\xab\xdd\xab\xac\xbb\xaa\x50\x31\xf8\xaf\x69\x87\xc2\x7b\x5a\x15\xde\x3f\x55\x11\x3c\xad\x11\xbe\x9b\xf3\xd3\x0b\xd1\xd3\x1a\x11\x12\x17\x06\x4f\x6b\x44\x5c\xc9\x2e\x8c\x9e\xd6\x88\x61\x3c\xbb\x30\x79\x5a\x23\xc6\x2a\x76\x61\xf6\xb4\x46\x4c\x1e\x76\x61\xf1\xb4\x46\xcc\xc5\xfa\x05\x51\xac\xec\x19\x36\x4f\x6b\xc4\xda\xc8\xf9\x55\xbe\x6d\xb5\x7f\xaa\x62\xf7\xb4\x46\x6c\x79\xc9\xcb\x0c\x4f\x6b\xc4\xbe\x25\x79\x99\xe9\x69\x8d\x64\x94\x26\x2f\x25\x4f\x6b\x24\xd3\x9b\xbc\x94\x3d\xad\x11\xc9\x93\xbc\x74\x78\x5a\x23\x72\x71\xf2\xd2\xe9\x69\x8d\x38\x7c\x89\xcb\xab\x14\x97\x1f\x20\x97\x5d\x75\x72\x3a\xf0\xff\x02\x00\x00\xff\xff\xb3\x46\xeb\x4b\xa0\xb1\x00\x00") func fontsRobotoRegularWebfontTtfBytes() ([]byte, error) { return bindataRead( _fontsRobotoRegularWebfontTtf, "fonts/roboto-regular-webfont.ttf", ) } func fontsRobotoRegularWebfontTtf() (*asset, error) { bytes, err := fontsRobotoRegularWebfontTtfBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "fonts/roboto-regular-webfont.ttf", size: 45472, mode: os.FileMode(509), modTime: time.Unix(1492020681, 0)} a := &asset{bytes: bytes, info: info} return a, nil } var _fontsRobotoRegularWebfontWoff = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x64\xb6\x43\x70\xe0\xdf\xdb\xc5\xf9\x8d\xd3\xb1\xd3\x71\xd2\x51\xc7\xb6\x6d\xdb\xb6\xad\x8e\xd1\xb1\x6d\xdb\xb6\x6d\xdb\xe9\xd8\x76\x32\xf5\xfb\xbf\x53\x35\x8b\xb9\xb7\x3e\x75\xee\xb9\x8b\xb3\x79\x16\xe7\x71\x93\x13\x15\x05\x40\x00\x00\x00\x0c\x7a\x01\xd4\xff\xb4\x2e\xf7\xff\xfc\xff\xff\x88\x8a\x2a\xcb\x00\x00\x48\x29\x00\x00\xb8\xff\x61\x0e\xfe\x3c\x2b\x26\x2c\x22\x0a\x00\x20\x83\x00\x00\x50\x00\x00\x40\x0d\x7a\x07\x32\x2f\x26\x2f\xa7\x04\x00\x20\x37\x00\x00\x29\x03\x00\x08\xba\x6d\xbc\x81\xfc\x62\x4a\x2a\x82\x00\x00\xcd\x0f\x00\x80\x2c\x00\x00\xfa\x64\x03\x84\x4b\x72\x4a\x74\x8c\x00\x00\x1d\x0b\x00\x80\xda\x7f\x7f\x2d\x4f\x1f\x91\x46\x36\x06\xf6\x00\x00\x7d\x02\x00\x20\xa1\x00\x00\xb2\x7f\x38\x29\x48\x69\xe4\xea\x4c\x08\x00\x30\xf6\x00\x00\xb0\xff\x07\x7c\x2b\x32\xbd\xa9\xbd\x99\x0d\x00\xc0\x94\x02\x00\x48\x1d\x00\x80\x9a\x28\x35\xd2\x95\x98\x19\x38\xd9\x03\x00\x9c\x36\x00\x00\xd0\xff\x2f\x48\x66\xd6\x1e\xa6\x00\x00\x67\x0c\x00\xd2\x51\x00\x10\x43\x18\xe7\xed\x06\x61\x6e\x62\x60\x0c\x00\xea\x0f\x00\x00\x30\x00\x00\xc0\x0a\xc1\x11\xc4\x6c\x6e\x6e\x62\x00\x00\x1a\xbf\x01\x00\x20\x00\x00\x80\x04\xd1\x1f\x52\xd8\xdc\xc6\xd9\x1d\x00\x34\xc4\x01\x00\xd4\x00\x00\xc0\x4a\x47\xff\x28\x1e\x58\xdb\x19\x19\x00\x80\x56\x25\x00\x80\x4c\x02\x00\xc8\xb2\xcd\xba\x54\xb7\x8d\x81\xbb\x3d\x00\xe8\xb8\x03\x00\x40\xf8\x1f\xa0\x50\x20\x79\xb6\x06\x36\x26\x00\xa0\x93\x0a\x00\x20\xc1\x00\x00\x26\x2b\x25\xea\x55\x69\x6f\xe7\xe4\x0c\x00\x7a\x84\x00\x00\x72\x05\x00\xa0\x87\xd8\x7f\x18\x8b\xed\x1d\x4d\xec\x01\xc0\x00\x09\x00\x80\x62\x00\x00\x41\xdd\x63\x50\x27\x71\x33\x31\x34\x05\x00\x83\x56\x00\x00\x20\xff\xe3\x42\x4e\x49\x03\x00\xfe\x6f\x2a\x93\x3c\xf9\x33\xff\x53\xb1\x56\xa6\xff\x74\xc6\x37\x73\xca\x7d\xdd\x48\xdf\x58\x5f\x7f\x17\xcc\x10\x1d\x12\x49\xdf\x50\xdf\x54\xdf\xd8\x1d\x66\x70\xc6\x2f\x36\x6c\x8f\x63\x40\x8a\x30\x03\x82\x7a\x00\x00\x94\x90\xc0\x87\x00\x00\x70\x5f\xaf\x4a\xf6\xb0\x56\x56\x41\x1b\xee\x61\xcb\xca\x6b\x94\xe6\xca\x02\x1d\xf8\xc5\x02\xb9\xb6\x29\x0f\xb2\x46\x3d\x98\x3a\x7e\x14\x42\xfd\x2b\x42\x58\x66\x31\x34\x20\x2e\xb5\x34\xec\x05\xaa\xbe\x83\x64\x5f\xb4\x30\x20\xc0\x3a\x18\x14\x52\xf9\x97\x61\x99\x2a\x31\x6d\xe8\x6f\x41\xe4\xb3\xe8\x22\x6e\x88\xf0\x2f\xae\x91\x9d\x0e\xa6\x79\x84\x0a\xe5\x9d\x14\xbb\xed\x2c\xaf\x1d\x8e\xe7\xec\xeb\xec\xf7\xed\x38\x72\x0a\x35\x35\xf3\x5c\x41\xd2\x40\xdb\x9f\x45\x1f\x50\x57\x7f\xdc\xc3\xd7\xa9\xa4\x7b\x26\xd1\x22\xd9\x6c\xbd\x9e\x77\x78\x5c\xc2\xd3\xa1\x68\x46\x6a\x05\x37\x85\xc6\xa7\x28\x93\x52\x96\x86\x78\x36\xa4\x94\xfa\x0a\x3c\x55\x8b\x28\x17\x3c\xbb\xce\x79\xae\x64\xd4\xd2\xd8\x46\x32\xae\xab\x6e\x79\x6f\x7c\x6e\xce\x84\xf6\x66\x7b\xe5\x25\xcc\x0d\xcd\xbd\x4b\xc9\xfe\xfd\x3d\x13\xf2\x51\x4d\x3c\xc6\x91\x0f\xd7\x81\x31\x81\xef\x1d\x87\x32\x38\xe6\xf3\x2b\x71\xb0\xcc\x0b\x7d\x2b\x4b\x7a\xab\x68\x08\x4f\x9a\x35\x54\x87\x68\x58\x9c\x5b\xb6\x8a\xc4\x5b\x66\x7f\xcf\xf6\x55\xe0\xca\xb5\xba\x90\xdb\x12\x88\x29\xe1\x78\x08\x66\x5e\xfc\xd2\x6f\x8c\x7e\x31\x1a\x1b\x08\x1f\xf8\xb5\x3a\xc6\xab\x48\xc0\x9d\xac\x1e\x05\xb9\x46\x04\x1f\x22\xb4\x4b\xcf\x0e\x1a\x1d\x50\x70\xeb\x8a\x93\x6c\x54\xa5\x8a\xba\xeb\x6c\x9d\x1d\xc4\xb4\x2b\xcd\x0e\x3b\x1d\x22\x75\x53\x87\xd6\x0d\x92\xd2\x77\x68\x0f\xa1\x1d\x1c\xc3\xd8\x8a\x5d\xed\x7f\x68\x4f\xfc\x07\xb6\x1b\x7e\xc7\x3f\x63\xd7\xf4\xc8\x1d\xd1\xd6\xff\x7a\x00\xe6\xa8\x3c\x88\x80\x51\x75\x4a\xf3\xb9\x2f\xdd\x18\x69\x8e\xbd\xc2\xb9\x27\x07\x75\xe5\xe7\xa1\x95\xec\x1d\x17\x8b\x12\xc1\xfe\x85\x59\x4f\x69\xcf\x2b\x65\xf3\xa7\x26\x5c\x85\x7e\x50\xdc\x65\xe4\x87\xec\x35\x82\xa7\xdb\x6c\x87\xd0\xda\xa0\x8a\x7f\x4c\x0d\xf3\xda\xd5\x02\x73\x46\xa4\x2c\xa9\xa6\x85\xd5\x43\x75\xd7\xf4\xb6\xa8\xc2\x21\xf6\x90\xc7\x19\xf9\x56\x5e\x72\x35\xb9\xa8\x5c\x62\xb6\xd0\xc3\xbf\x40\xdc\xe1\x80\xe3\xbb\x0b\x29\x51\x98\xb9\xd6\xe8\x39\x9e\x0b\xe1\xac\x86\x34\x6b\xab\xdb\x0f\x88\x6c\xbd\x01\x27\xd2\xec\x16\xcb\x1e\xef\xcb\xe5\x2f\x2a\xaa\xee\x48\x9e\x53\x58\xcc\x7e\xc5\x17\x4a\x6d\x70\xad\xba\x23\x50\xc7\x26\xc2\xae\x70\xc1\xa7\xe2\xe4\xae\x32\x13\x3b\xcb\xb5\x0c\xcd\xa7\xa2\xe5\xa9\xda\x70\x2f\x2c\x6d\xf8\x95\x5e\xc7\x12\xb5\x2a\x57\xa3\x0e\xa8\xab\xe0\x9d\x3e\x0c\xf7\x9b\xdb\xdd\x83\xbe\x91\xc0\x18\x28\x02\xab\xff\xef\xe6\xc0\x61\x4b\x56\x1a\x85\xfa\xe0\x3e\xbc\xa4\x8c\x58\x1a\xb1\x0a\x39\xa8\x83\x57\xec\xf1\xaa\x83\x05\xb2\xff\xd9\xbf\x09\x1b\x20\x47\xc8\xf9\xef\x51\x77\x21\x42\xd2\x36\xb9\x2d\xa1\xb3\xa8\xb2\xe5\x1c\xd7\x7e\xee\xf8\x28\x2f\x27\x5a\xfd\xeb\xfe\x2d\x6e\x62\x08\xbb\x37\x0d\xb7\x3c\x83\x59\xd3\x28\xcd\x21\x80\xcc\xb2\x3d\x7b\x11\x6e\x6a\x91\x7a\x6a\x59\x7b\x6a\x41\xc9\x53\x73\xc6\xbc\x5b\x77\x36\xc2\x53\x82\xce\x0a\xa4\x4d\x2f\x4f\xb2\xde\x97\xcd\xe1\x8a\x74\x58\x3e\x9a\x20\x73\xf4\x62\x6f\x0a\xf3\x04\x14\xdd\x21\xfc\x79\x1d\x77\xc3\x96\x20\xcd\x6e\xc2\x26\x6d\x7a\x4f\x12\x7f\xf6\xdb\x71\xad\x46\xd5\x6a\xe3\x42\x1d\x95\xda\x97\xb7\xa4\x04\xd1\x64\x52\xc3\xac\xa3\x75\xe6\xc8\x67\xd6\xe7\x03\x73\xb9\xa7\x44\xbc\xd8\xe4\x89\xa0\x99\xe9\x54\x3e\xb5\x4d\x73\x5a\xc7\x7e\x68\x01\xee\x6b\x64\xec\x56\x69\x4a\xed\x39\x87\x99\x07\x69\xd0\x3d\xfc\x2b\x30\xb3\x63\xb7\x7b\x91\x2c\xfb\x67\x93\x47\x66\x62\x88\x2f\x4f\xa5\x59\xfd\x1c\x76\xe5\xb6\x29\xbe\xdd\xf7\x70\x34\xcd\x54\x6d\xd7\xda\x17\x8c\x6b\xed\x2d\x2d\x59\x49\xac\xda\xfb\x25\x51\x3a\x83\xa8\x6a\xb6\x69\x11\x9d\x7a\x5b\x15\x60\xb7\x2e\x2a\xab\x0f\x90\x4e\x45\xfd\x31\x45\x6f\x8e\x7e\x47\x7d\x72\xbf\x2b\x55\xa2\x35\x15\xb3\x0e\x54\x29\xa2\xd9\xa9\xcf\x7a\x82\x7f\xce\x8a\xea\xd4\x49\xec\xfe\x36\xf4\x2d\xd2\x7a\xce\xcc\xd4\x68\x9e\xe8\x46\xcc\x77\x83\xf9\x57\xf2\x5e\xcc\x7a\xe1\xd4\xae\xe2\x02\x69\xa3\xd4\x96\xb8\x53\xca\x65\xfb\x37\xb3\xa7\xd5\xdb\xe4\x79\xdd\x8e\x5c\x83\x47\x3f\x69\xb0\x01\xca\x67\x72\x1b\x13\x32\xcd\xe0\xd2\xc3\x08\xdc\x68\xa9\x13\x42\x51\x4e\xa6\x3e\xc7\x03\x76\x38\xec\x3e\xf7\x53\x98\xaa\xf5\x4e\xf1\x9e\x65\x7a\x27\xa4\xd2\x7a\xf5\x10\xf5\x3e\xb6\x66\x3d\xcd\xe9\x9f\xb9\xd2\x8c\x4a\x6e\xd5\x92\xd9\x9b\xa4\xc7\xbb\xd8\x23\x99\xb1\xf5\xa7\xc6\xb0\xdc\xbb\x4f\x2d\xb1\x4c\xf6\x02\x5f\x87\x60\xda\xf6\xda\xc1\xe2\x77\xc0\xc1\x75\x90\x28\xaf\xf5\x62\xd9\xf4\xe7\x0f\xb5\xc9\x32\x17\x6a\x25\x5f\x9c\x1c\x86\x89\x2b\xa6\x9a\xb5\xf2\x0c\xb4\xcb\xb8\x62\x73\x93\x2e\x77\xa5\x48\xc8\xe7\x55\x92\x72\x7f\x40\xf2\xc9\x85\xf8\xde\x26\x7d\x6b\x88\xc7\x74\xee\x1f\x44\x73\x70\x35\x74\x1b\xdf\x98\x69\xdb\x5c\x15\x96\xae\xe4\x25\x2a\xd5\xcc\xe4\x2e\xea\x4c\xa8\x0d\xd7\xb6\xa6\xe9\xb9\x75\x44\x55\x30\x57\x56\x3c\xfd\x6b\x28\xce\x2b\xf3\xe7\xa0\xe9\xf4\xc8\x92\xeb\x4d\x23\x4c\x96\xab\x99\xd2\x75\x4f\x82\x27\x01\x57\x04\xcc\x3b\xd3\x0e\xfc\x08\x13\x4f\xe1\xf6\x85\x79\xa4\x9d\xfb\xe6\x12\x20\xd2\x5b\x70\x75\x31\x29\x8e\x19\x3b\xf4\xdc\x49\xa5\xb7\x69\x4b\x98\x2f\xe5\x6c\x21\x0f\xe5\x67\xdd\x7d\xb3\x55\x96\x4e\x07\xc5\xa1\x9c\xa1\x36\xbf\x03\x16\xf4\x7a\xf4\x5c\x88\x71\x02\xa6\x59\x4a\x37\x7a\x74\xbe\x13\x03\x53\xc2\x37\xba\xb0\x44\x98\xa3\x99\x9b\xca\x01\xe5\x07\x9a\xe4\xd7\x5a\x0d\xb6\xc8\x97\x5b\x14\xe2\xa7\xda\x8e\xdf\xb8\x6c\xbf\xd5\x7f\x0d\x1d\x3b\x2b\x2e\x2f\xfe\x48\xaf\x69\x53\x4a\x38\x5c\x5e\x35\x1c\xe8\xaa\x8c\x82\x6a\xbe\x83\xb0\xae\x24\x32\x69\x32\x75\x5f\xfa\xeb\xd7\xe2\xe6\x4c\x5d\xf9\x2b\x61\xe5\xb1\x00\xd3\x59\x38\x44\x23\xa6\x25\x72\x85\x26\x9c\xa1\x66\x3e\xfa\x64\x37\x4c\x63\x21\x3e\x9d\xd9\x36\x7c\x6e\x13\xab\x25\x2a\x93\xaa\x5f\xf3\x3a\x0c\x4c\x99\x20\xa5\x85\x9a\x7f\x6a\xb9\x7f\x89\x77\xaf\x12\xfc\x8d\x7c\x05\x1d\x93\xa8\xf9\x21\xe8\x8c\x05\xb6\x8b\x5e\xe0\xb2\xec\x5a\xa9\x12\xab\x64\xf0\x22\x45\x95\xb5\x20\x66\x60\x90\x52\x43\xe0\x02\xad\x40\xd3\x62\xc4\xce\x76\x6e\x96\x52\x6d\x9b\x52\x6d\x94\x12\xfd\x08\xc5\xea\x32\x45\xea\x31\xda\xa4\x0b\xcc\x11\x17\x44\x83\xbc\x2d\x74\x1d\x3c\x98\x41\x89\xe6\x60\xd9\xf2\x64\x19\xc6\xdc\x6f\xa4\xe5\x2a\x42\xad\x16\x7f\xd0\x12\xfd\x4d\x8a\xd5\x6d\x8a\x9f\x6e\x30\xd9\x25\x50\x02\x56\x94\x0d\x6b\x95\x4c\xf2\x4c\x7b\xca\x52\x27\xe8\xb1\xf6\xeb\x4d\x0e\xeb\x87\x9c\x97\xf5\xf2\xd5\xb8\x33\xfe\x96\xc8\x25\x9a\x4c\x36\xcb\xef\x2f\x88\x8d\x11\x5c\x4b\xfb\x6f\x00\xc9\x03\x11\x34\x17\x84\x53\x93\xd4\x0e\xa3\x94\xfc\x92\x87\xec\x54\x69\xc5\x95\x62\xba\x68\x56\xb1\xc2\x91\xdd\x39\xb3\x0a\xb1\x8c\x90\xec\x14\x75\x89\x69\x2a\xb5\x8c\x89\x89\xdc\xe2\x69\x20\x46\xf0\x6f\x06\xe8\xcb\x00\xb8\xb3\x5d\xc6\x52\x68\x1a\xd1\xb3\x3f\x29\x2c\x78\x3a\x93\x98\x28\xb7\x97\x17\xfd\xda\xf9\x67\x92\xdc\x11\x75\x70\xbf\x28\x5c\xe3\xb4\xa5\x70\x33\x98\x57\x55\xb2\xd8\xda\x9b\x10\xcc\x92\xde\x67\x99\xd4\x17\x52\x7b\x40\xd0\x6d\xb9\x99\xff\xd7\x27\xff\xd7\x3d\x86\xb3\x46\xb5\x06\xfa\x8e\x0e\xf7\x3f\x0c\x76\x27\x24\xa8\xc7\x8c\x62\x0d\xf5\x41\xc2\x99\x3e\xbe\x67\x80\xf8\xbf\x75\x58\x3f\x7f\x3a\x31\x2e\xa0\x62\xb1\xf3\x53\xd3\x9b\x82\x4c\x30\x80\x8a\xfc\xc4\x0a\xca\x65\x86\x1d\x60\x82\x24\x83\x24\x20\x8c\x88\xeb\x43\x05\x0c\xa7\x60\x56\xfe\x2f\xcf\x54\x41\x3f\xb3\xb7\x77\xbc\xb7\x9f\x33\x62\x29\xd5\xdf\x5f\x01\x5f\x90\x49\xcf\x58\xdc\xc8\x50\x5f\x1f\x30\x80\x76\xef\xed\x7d\xe0\xf5\x13\x20\xc2\x1e\x55\x06\x6e\xb7\xee\xef\x17\xb0\x70\x7f\xba\xfb\x36\xd4\x16\x7d\x4a\x19\xe9\xef\xfe\x36\x83\x51\xd5\xd7\xcf\xbc\x9e\x19\xed\xed\x35\x1c\x6a\x07\xa9\x8c\xfe\x01\xd8\xf3\x20\x50\xfd\x2f\x57\x5f\xdf\xd4\x4f\x1f\x0b\x52\x14\x12\xa9\x15\xec\x1f\x43\xc0\x2b\x35\x1c\x94\x5f\x23\x42\x20\x68\xec\x10\x98\xf1\x2d\xe3\x22\xc3\x87\x19\x9c\x69\xa5\x3e\xe7\xb0\xb3\x98\xbf\x94\x80\xb0\x80\xa4\x80\xac\x80\x84\x80\x8c\x80\x5e\x9f\x24\x91\xae\x41\x54\x7e\xfc\x59\xce\x0e\xf5\xf7\x77\xe0\xd4\x1e\xc4\x99\x56\xef\x4f\x70\x95\xa9\x5c\xc2\x5c\xc2\x3c\x42\x30\x15\x9b\x1f\x6a\x53\xd0\xca\x53\x2f\xdf\xe7\xdf\x23\xdf\x88\x9f\x74\x2f\xd7\xf7\xcf\xdf\x3b\x6a\x88\xd1\x7c\xec\x0f\xfa\xdf\x81\xde\x88\xae\x7c\xab\xb7\xfa\x03\x81\x87\x88\xe9\x04\xa9\x3b\x7c\xce\xe7\xa4\xe7\x4a\xa5\xb0\x61\x90\x91\xd6\x70\xf6\x34\x91\xd2\xfc\x01\x3f\x74\x40\x66\xcf\xa9\x2b\xad\x2f\x70\x33\xb5\x37\xb9\x3b\xff\x7c\x80\x06\x08\xf6\xff\xca\x37\xdc\x47\x89\x57\x9c\x67\xac\x77\xbc\x83\x09\x97\x1c\xa7\x2c\xb7\x3c\xc3\x4e\xd7\x5c\xe7\x6c\xf7\x7c\x83\x0c\x11\x1d\x26\x2b\x36\x3d\xc2\x48\x56\x5d\x66\x6d\x76\x7d\x42\x88\x96\x9d\xa6\xad\xb6\xbd\xc2\xcf\xd6\xdd\xe6\xed\xf6\xf9\x02\xf1\x17\xe8\x23\xca\x33\xd8\x43\x8e\x53\x98\x63\xa8\x73\xb8\xfd\x11\x06\x67\x73\x99\xb5\x95\x60\x36\xa9\xd5\x69\x3e\x56\x5f\x34\xa1\x56\xad\xdb\x64\x7a\xf9\xe6\x82\xc3\x6a\xbb\xdd\x6e\xb2\x11\x7d\xe9\xe5\x7a\xbd\x35\x22\x9f\x18\x9f\xee\xd1\x62\x68\x20\xf0\x94\x50\x4f\x1d\x12\xad\x01\x37\x04\x07\x77\x7a\xa8\xbf\x72\xb8\x48\x5f\xb9\xba\x94\x9a\x09\x65\x78\xbc\xbc\x2d\x65\x69\x99\xe5\x73\x72\xb3\x64\xd5\x62\xab\xd7\x53\x97\xb0\xb7\x8b\x1c\x32\x82\x88\xcf\xeb\x35\x2d\xef\x71\x8f\x20\x24\x25\xe7\x64\xa7\xf6\x1d\x14\xe6\xad\x54\xc2\x20\x9d\xc6\xe4\xc6\x3a\x30\x67\x14\xcc\x2f\xa3\xc2\x0f\x07\xe0\xb7\x87\x37\x01\x00\x38\x27\x44\x0d\x90\x01\x14\x01\xf1\x40\x2e\x10\x0c\x74\x02\x43\xc0\x18\x30\x04\x6c\x00\x59\x40\x1e\x50\x07\xf4\xfc\xcf\xa7\x00\x89\xc0\x00\x50\x0e\x54\x01\x6d\x40\x0c\x20\x0c\x81\xec\xbe\xae\xa3\xd0\x21\xab\x25\x80\xb4\x05\x8f\x08\xe6\x3f\xb8\x4a\xc8\xb1\x8e\xd6\x90\x16\x3b\xec\x95\x07\xf1\x63\x70\x29\xca\xd0\x98\x2b\xf8\x10\xda\x82\xcd\x31\x2e\xc2\x01\x84\x80\xdf\x5f\x18\x7e\xbd\x06\x2b\x37\xaf\x50\x3c\x03\x92\x08\x53\xfc\x8f\x20\x2f\x11\x0a\x93\x55\x68\x3e\x33\x17\x57\x83\xd3\x74\x1a\x93\xd4\x78\x5c\xb9\xdb\xa9\xd5\x8c\xd2\x31\x49\x6c\xff\x16\xe4\x14\xeb\xa7\xac\x78\x53\x03\xf0\x5c\x78\x7e\x1e\x15\xd9\x18\x08\xa5\x69\x6d\xfa\x30\xee\xf2\xfe\x05\x0b\x99\x31\x97\xc8\x65\x09\x1c\xf2\xd8\x51\x20\x62\xc9\x70\xf9\x6b\x36\x96\x7c\xcd\x7d\xc0\x84\xbc\x7f\x10\xdc\x73\xfd\x6c\x64\x5e\x78\x58\xe4\xfc\x71\x4a\x04\x7e\x94\xe1\x20\x15\x78\x8d\x35\xd5\x3e\x81\xf8\x16\xb0\xb4\x67\x48\x4f\x5f\x98\x5a\xbc\x4f\xcb\x57\xac\xf8\xd5\xc2\x7c\x6c\x39\x51\xdb\x14\x37\xd7\x19\xc8\x84\xfc\x3a\xc6\xcc\xaf\x64\x65\x03\x9e\xfe\xb5\x48\xb4\x74\xef\x80\x26\x15\x3b\x51\x5c\xc7\x9a\x9a\x5a\xff\x45\x82\xda\x17\x3c\xe6\xac\xa2\xd4\x34\xf9\xb2\xde\xa7\x53\xdf\x70\xa2\x1f\x48\x39\xe5\x0f\xb5\x3a\xa0\xea\x01\x87\x8f\x80\x48\x86\x36\xdf\x42\x32\x4e\x0d\x8f\xfc\x64\x58\x31\x08\x8d\x9c\x80\x0b\xc3\x71\xb8\x39\xf6\x55\xc8\xff\x2a\x8e\x32\xdc\x29\x21\xc9\x75\x10\xd2\x04\x39\x1c\xb7\xd2\x9b\xcb\x2a\xd7\xf0\xcd\x9d\x21\x63\x63\x87\xd7\xff\xa2\x81\xdb\xe7\xd6\x83\x25\xc5\xf9\x32\x1a\xb2\xfe\x13\xd9\x90\xcb\x90\xc2\xef\x87\xb0\xa0\xa8\xca\x6b\x08\xf6\x4c\x17\x35\xe4\x3f\xc5\xf7\x19\xfe\x44\xbf\xc3\xdb\x18\xdf\x2c\xe8\xc6\xab\x55\x61\xee\x94\x26\x17\x04\x06\x55\x68\x4f\x9f\x8d\xcd\xbb\x89\xf0\x0e\xd5\xb6\xe9\x08\x41\x37\xbb\x72\xcb\xd2\x79\x8a\xa9\x77\xdd\xe9\xee\x11\xb0\x6c\x7c\xd8\x01\x01\xa3\xbe\x8c\x99\xf7\x2f\x49\xff\x37\x6e\xea\x6a\x66\x73\x04\x70\x21\x4f\x36\xcf\xef\xfc\xa6\xb3\xd0\x8a\x4e\x4c\xde\x7a\xf2\x85\x9e\x3a\x4d\xe0\x7f\x1b\x2b\xc8\xf7\x37\x80\xe8\xbe\xde\xd4\xf5\x43\x1f\x75\x69\x99\xdd\xe7\x7a\xd2\xb8\xbe\x25\x8d\x5a\xe6\x99\x55\xc7\x42\x2a\x23\xbe\x31\xb1\xb6\x26\x9c\x30\x14\x26\x20\xbf\x72\x3c\x1a\x94\x32\xf7\x37\x61\x2e\x75\xfd\xef\x50\x42\xe8\xf0\x0e\x3f\xce\x04\x0c\x4c\xe1\xa1\x22\xe8\x56\xee\x1c\xde\x5b\x8a\xab\xb7\xc5\xf2\xeb\x36\x6f\x39\x02\xa9\x90\x6f\x8e\x67\xd9\xf9\xc6\xc6\xd1\xf7\xee\x1d\x02\x1b\xa6\xb4\x42\xa6\x67\xea\xe7\x8b\x63\x38\x64\x71\x5f\xc1\x20\x2a\x19\xe2\x50\xf1\xc9\x42\xc9\x02\x92\x55\x1e\xcb\x64\xc6\x6f\xac\x79\xe3\x85\x91\xad\x82\x7c\xe0\xaf\x30\xea\x6d\xe3\x0f\x39\xb1\x29\xc7\xe5\xb1\x2b\x85\xf0\xe3\x01\x49\x7e\x0a\x84\xdf\xfe\x5f\x82\xdd\xba\xc2\x6c\xe7\x4a\xd2\xc4\xd1\xd7\x67\x74\x5d\x22\xbb\xf1\xc6\x98\x44\xce\xcd\x12\x26\x2b\xf0\x09\xbf\x33\x2b\x66\x4b\xab\x28\x2c\x51\xc4\x21\x54\x68\x04\x54\x38\xf3\xe3\x63\x4d\x9b\xd9\xca\x40\xbd\xe6\x2a\x1b\x03\xcc\xc9\xca\x5b\x55\x28\x14\xb7\x28\xb4\x71\x9e\xc2\x24\xd5\xd7\x5c\x76\xf9\x0f\x32\xec\xe6\xe5\x86\xdc\xe4\x54\xf7\x5c\xfe\x4a\xd0\x1a\xd4\x66\xca\x4a\x0f\xca\x7a\xa2\x24\x81\xab\x70\x6c\x12\xae\x86\x8a\x94\xcb\xd3\x10\x95\x73\x06\x50\xf2\xe4\x4b\xd8\x6b\x8c\x15\xa5\x59\x04\x9b\x06\x4a\x71\xed\xa9\xf4\x53\x65\xfc\x4a\x9f\x82\xab\x79\x82\x2e\xbb\xfa\x57\x16\x78\x9e\x31\x70\xf1\x4c\xbf\xee\xbe\xb4\xb3\x2b\xe6\xf8\x29\xbd\xf0\xa8\x17\xf3\xfd\xb7\x7d\x97\x6d\xf3\x1a\x57\xb0\x10\x0a\x88\xa6\x8e\x17\x13\x8b\x37\x27\xeb\x45\x7e\x2c\x32\x09\x1a\xd8\x2b\xc5\xe2\x0f\xd3\xbc\x40\x60\xb7\x25\x64\x5e\xb8\xa8\x2c\xc5\x4c\xbc\xc8\xfc\xe5\xab\x4e\x5c\x5c\xec\x59\xc3\xc7\x53\x31\x4a\x60\x09\x74\xee\x89\xe5\x53\xb1\x21\xf2\x31\xf6\x89\xd5\x2f\x1d\x05\xc5\x94\xa6\x13\x28\x33\xc5\x98\x63\x65\x93\xb1\x0c\x14\x15\xf5\x51\x7a\x67\x93\xb5\x76\x56\xe5\x77\xb7\xcc\x18\x55\x95\xb6\xbc\xcc\x53\xa3\xa7\x63\xf1\xb2\x41\xb1\xc0\xfe\x31\x6d\xde\x35\x33\x1d\xd3\xcc\x7b\xd3\x4e\xc7\xfb\xea\xdf\xb3\x98\x07\x6d\x14\xbc\xcc\x6c\x6b\x39\xe6\xea\xb9\x24\xed\x86\xd9\xd8\xce\xb6\xfb\x70\x25\xc0\x2f\x4d\xab\xf6\x24\x5a\xb8\xf0\xef\x68\xd8\x61\xfc\x0a\xd1\x5a\xd2\x62\xa2\xb6\x8f\x3d\x2a\x6f\x29\x5a\xe3\x71\x2f\xf3\x2c\x99\x01\xd1\xb3\xaf\xdb\x81\x79\xbf\x1c\xda\x79\xc1\xe3\x7b\x47\xf8\x50\xe1\x7c\xa7\x6a\x35\x55\xfd\xe0\x5c\xbb\x3d\xff\xb7\xeb\x76\xe6\x74\xb0\x33\x39\x70\x6f\x68\x97\x42\xf8\xab\x94\x16\xc2\x21\x2e\x2b\x21\x43\x6d\xe9\x2c\x67\x9d\x0b\xf5\x87\x02\xce\x0d\xf8\x2e\x39\xf5\xbe\xdc\xaa\xda\xa8\x0f\x0c\xcf\x8b\x12\xe6\x0d\x5a\xb6\x10\xcd\xa7\x1c\x72\xba\xf7\x5c\x71\xc4\x28\xc5\xcb\xe3\x5b\xca\x67\xcc\x17\x83\xf5\x7d\xad\xd2\x00\x2b\x7c\x05\x79\xc9\x5b\x4e\xbe\x96\xea\xc2\xc4\xca\xfc\xfb\xa3\xc3\x4b\x83\xaa\xaf\x79\x13\x6f\x98\x6d\x1f\x01\x3b\x62\xa5\xd8\xef\x34\xa7\x72\xcd\xbb\xb1\x0d\x71\xb1\xfa\x34\xe1\x09\xff\x70\x4b\x8a\x59\x41\xdb\xf0\xe4\x0c\xa4\x82\x43\x93\xe5\xf0\x52\x50\x70\x95\x2e\x03\x1a\x58\x59\x2a\x0d\x77\x4d\x07\x2d\x7f\x2d\xaa\x40\xcb\x71\x64\x1a\x4c\xf7\xf0\x7f\x04\x0a\xcc\x7d\x4b\x85\x47\xed\xcc\x10\xb1\xd7\x2e\xac\x65\x26\xee\xd5\x60\xb8\xee\x3a\xe9\x10\xd0\x71\xf8\xf3\xe1\xbb\x15\x5f\xb1\xaa\x10\x3b\xbf\x27\x20\x5c\x9d\x84\x17\x11\x24\xbb\xb6\x12\xd1\x7f\xdf\x89\x31\x47\x60\xca\xa2\x0b\x87\x26\x9b\x28\x6e\xf6\x72\x50\x7c\xfd\x62\x8f\xfa\xf8\xf9\x54\x1c\x2c\x94\x65\x65\x25\x29\x59\x61\x6e\x23\x73\xcc\xb9\x0a\xd6\xb6\xa8\xa6\xae\xa4\xa8\x4e\xf8\xde\x69\xe1\xe3\x7e\x90\x34\xd5\xdd\xbf\x4e\xc9\x29\xe6\xee\x70\x7e\xa1\x75\xa5\xdd\xf9\x75\xb3\x41\xc7\x5d\xff\x59\x77\xac\xab\xc5\x6e\x75\xf5\xc8\x66\xed\x7b\xde\xbb\x01\xbf\xe1\xea\x2b\x4d\xc0\x64\xa3\xd1\xae\x7f\x54\x14\x21\xc4\xb3\xbd\xf9\x7a\xc3\xd5\x2d\xc7\x2b\xf3\x7d\x3a\x1b\x3e\x82\x21\x4d\xc0\xd7\xe3\xb4\x33\x3c\xe2\xd6\xb3\xb7\xf6\x1d\xff\x0e\x06\xda\x61\x3e\x5e\x46\x20\x2d\x25\x13\x35\x18\x86\x2b\x4b\x29\xc1\x56\x1f\x2e\x4c\x65\xdf\xe2\xca\xc8\x26\x42\xda\x1b\x9a\x6c\x6b\x6b\x79\xa2\xa8\x4c\xc4\x41\xd5\x48\x6b\x5f\xba\xba\x96\x67\x68\x9b\x6f\xf9\x9c\x2b\x19\x6d\x4e\xd1\x9b\x43\x41\x3b\x05\xbb\x0b\x1a\x53\x8e\x91\x92\x8c\xf8\x57\xc5\x5e\xfd\x70\xde\x72\xb7\x16\xec\xc6\x1c\x51\x58\x2d\x7c\xbf\xba\x45\x6a\xcd\x23\x34\x24\x9d\xd2\x3d\x41\x49\x39\x0e\xd6\x2e\x74\xb9\x28\x61\x7f\xb9\xfe\xfe\x17\x32\x8d\x8e\x7f\x41\xe6\x26\xb4\x21\x78\x2c\x12\x42\xd1\xa1\x7c\x8d\xb6\xba\xbc\xe2\x48\xed\x42\xa0\xa3\xb3\x7b\x69\x0e\x46\xce\xde\x3d\x05\x62\x95\xf6\xeb\x6c\x20\x95\x2a\x4f\xe7\x57\xff\xfd\x0c\x8e\xeb\x5e\x6e\xdf\x00\x19\x4c\xcd\x4c\xa4\xc8\xc9\xea\x5f\xd5\x6a\xf7\x97\xbc\xc3\x61\x28\xcc\x2c\xb6\x13\x41\x8b\x9b\x58\x11\x39\xde\x3a\xf7\xd1\xfc\xad\x0e\x4c\xf8\x74\x6e\x8b\x9b\x58\x01\xa5\x12\x04\xce\x34\xa2\xa9\x53\x37\xc3\xcb\x03\x21\x4c\x9e\xdb\xc1\xfc\xbc\x08\xb7\x6b\x5d\x6e\xf7\xbb\x7f\x7d\x42\x50\x32\x69\x8c\xa1\x7e\xca\xe7\xde\x67\x50\xa7\x78\xbd\x5a\x00\x3b\xa5\x60\x72\xbc\x39\x86\x64\x08\xb7\xb0\x76\xdd\x2a\x5a\xd3\xaf\xfd\x33\x61\x7e\x05\xb5\x90\x7c\x50\xae\x8b\x37\x50\xd0\x8c\x36\x14\xf7\x02\xbf\x82\xa1\xb8\xf5\x42\x4e\xf6\xed\x3f\x65\x32\x9a\x6c\xee\x55\x89\xfe\x6c\x83\xa1\x9a\x05\xcc\xea\xf7\xe1\x13\xda\x7e\x38\x4b\x7b\xaa\x5c\xc2\xca\x35\xa0\xdc\x69\x78\x61\x40\x75\x78\xc3\xae\xd4\x1a\x72\x93\xec\x9a\x90\xb1\x98\xa7\x06\x8b\x19\x81\xfe\xcf\x61\x56\x3f\x64\xfd\x04\x65\x49\xaf\xf9\x75\xfa\x9b\x88\x1d\x6d\xf5\x74\x41\x58\xd8\x70\xf6\x80\xb3\x52\x8e\x60\x4f\xbf\x8c\xb3\x5d\xa7\x90\x8a\x6d\x2b\x55\x44\x9e\xef\x25\x9d\x0d\x44\xe9\x2c\xee\x04\x04\xba\x0a\xc5\xbf\x08\x9e\xb2\x2f\x23\xa1\x06\x35\xd2\xaf\xf2\x7c\x4b\xad\xae\xaf\xbd\x4b\x3c\x8f\x32\x78\xa2\x6e\x5a\x8b\x6d\xf7\xe5\xe2\x6b\x2f\x79\x98\xd1\xf9\x54\xb6\x7f\x8e\xee\xc2\xb4\xe8\x3c\x3f\xd2\x4a\x30\xe5\xd4\xd9\xdc\x53\x79\xdb\x66\x9e\x14\x26\x78\x7b\x1e\x98\x16\x0a\xaf\xba\xba\x3d\x4c\x9f\xde\x64\x55\x1a\x79\x4b\xbe\x65\xfa\x51\x9b\x56\x9e\x08\xb4\x1c\x2d\x8e\xf1\x8d\x4c\xef\xbd\xd9\xa5\xc7\x0b\x2c\xa4\x7d\x52\xf2\x1e\x44\xe7\x6c\x92\xf4\x63\xc6\x1c\xda\xa6\x7c\x26\xa7\x40\x71\xfe\x09\x61\x88\x98\xf8\xfd\xc2\xfe\x5a\x7d\xbb\x37\x7b\x63\xfb\xd0\x9c\x78\x90\xed\x67\x7d\x95\xcc\x47\x42\xcc\x2b\xcf\x20\xc2\x1e\xea\x82\x62\xfe\xc1\x18\x13\xb1\x78\xa8\xa0\x21\xff\x87\x96\x6d\x37\x37\x88\xba\x80\x27\x27\x5e\x4a\xb5\xdb\xc1\x5d\x25\xec\x23\xf1\x2b\xdc\x3e\x3a\xa9\x1a\xa5\xbc\x3a\x77\x45\x66\x85\xeb\x04\x91\xeb\xf1\xef\x23\xc2\xca\x54\xab\x60\xe9\xa0\xd5\x84\xfd\x65\xe7\x3f\xab\x08\x31\x66\xb3\xfb\x26\xae\x8e\x24\xcd\x14\x79\x4d\x4c\x59\x62\x7b\x0f\x43\xda\xc4\x94\x9e\xc7\x6d\x1a\xd2\xbb\x84\xc6\x94\xaf\xbb\x84\xfa\x6e\x1b\xca\xcf\x00\xdd\xbd\xc2\x94\xd9\x9a\xea\x6c\x07\x91\x0b\x1d\xef\x6a\x95\x1e\xde\xa7\x6d\x74\xeb\xad\xb5\x7e\x75\x07\x92\x93\x44\xb4\x78\x39\xfe\xa1\x7c\x41\x69\xf8\xf2\x7e\xe4\x29\xf0\xf7\x41\x88\xdc\x8c\x20\x53\x3c\x13\x94\x01\xc3\xba\x9d\x7f\x0c\x1b\x16\x65\xe4\x1d\xa8\x97\xfa\x1b\x06\x05\x43\x4b\x6f\x1d\x74\x74\x5b\x05\xb4\x5c\x84\x10\x2d\xda\x42\x74\x73\x04\xed\x6f\xdb\x52\x8f\x7a\x23\x73\xdc\x5d\xa7\x30\x67\x21\x5e\x70\xa4\xe7\x45\xd8\xa7\x16\xb3\xf1\x98\x0c\x34\x16\x08\x56\x8b\xf3\x85\xe9\x82\x0a\x82\x0a\xf5\xc8\x38\xd0\xdc\x92\x37\xb1\xe1\xbf\xff\xf1\x3b\xac\x47\xe7\xd2\x36\xe7\x5f\xc1\x89\x54\xb1\x7e\x4c\x5a\x86\xd4\xac\x55\xba\x43\x07\x95\xf3\xcb\x8c\x43\xb0\xfe\x9e\xf2\xa3\xcb\x45\xa3\x14\x3a\x7d\x13\x6d\x97\xcd\xd9\xfa\xad\x8d\x5c\x14\x73\x96\x22\xfa\xa8\xf9\x06\x59\x22\xd7\x54\xbd\x60\xfb\x0f\x35\xd7\xc5\x81\xab\xd1\x36\x62\x7a\xe9\x98\x79\x1b\xde\x77\xf5\xb3\x8f\xfc\xa1\xe5\xd5\x05\x26\x58\xba\x8f\x82\xb9\xb7\x9a\xaa\xf7\xdc\x5c\xd9\xba\x9f\xa0\x5c\x52\x20\x6a\x36\x1c\x72\xce\x7f\x05\x62\xa3\x4f\x3d\xa3\x26\xd6\x87\xce\xd8\x76\x2d\xc0\xb7\x03\xcc\x47\xe6\xd7\xdf\x3d\xbb\x89\xf8\xca\xd8\x17\x10\x5d\xd0\x36\xd1\xa0\xa6\x5d\xc4\x1e\xf0\x75\x7c\x2e\x6c\x44\x82\xe1\x1e\xb7\x2c\x4d\xca\xb7\x34\xbc\x02\x24\x7a\xaf\x58\x55\x7b\xb5\x2f\x1e\x3e\x78\xa5\x14\xfa\xab\xb9\xd5\xe8\x8c\xc3\x71\xa3\x6b\x86\x0e\x33\xd6\x51\x88\x14\x22\xb9\x8e\xf8\x52\x3c\xbb\xc2\x50\x07\x89\xf0\x88\xe9\x23\xc6\x85\x6d\x6a\xa6\xbd\x61\x8e\x10\xe7\xc5\x0b\xc5\xa0\x39\x1d\x87\xb6\x01\x22\x37\x48\xed\x9e\x5a\xfe\x5d\x9c\x16\xd5\xbd\x78\x9b\xa7\x3a\x62\x02\xdc\xf7\x83\x40\xc4\x68\xb6\x6a\xcd\x7a\xe3\xd7\x71\x52\x29\x55\x68\xf4\x07\x45\x98\xa3\xc0\xaf\xee\xaf\xae\xaf\xd2\xed\x42\x5f\xfe\x89\xef\xc7\xfe\x89\x77\xbd\xc2\x0e\x5d\xf7\xd3\x22\x4c\xa4\xe8\xae\xda\xd6\x11\x10\x04\x54\x4d\x23\x94\x71\x4a\x10\x35\x61\x08\xb5\xaf\x2f\xc2\x75\xaa\x48\x6a\x14\x21\x11\x65\x94\xb8\x5d\x14\x88\x80\x0c\xf8\x42\x0c\xb0\xb2\xe7\xf9\x1c\xec\x22\x82\x15\x57\x5e\x5e\xe9\x37\xac\x1a\x0e\x7c\xeb\x02\x14\x3f\x96\x04\x6d\xa1\x7c\x0a\xe8\x32\x3c\x42\x91\x90\xe5\xf9\x5d\xc2\x28\x1d\x52\x1a\xd4\x36\xaa\x08\x1c\x4e\x5a\xd3\x93\x5e\xfc\x79\xe3\xd6\xa8\x8b\x3e\xba\x51\x59\x7d\x86\x98\xc8\xbf\xd9\x68\xad\x46\xac\x7f\xce\xc6\xe4\x37\x15\xe6\x6c\x8d\xf6\xa7\x11\xdc\x15\x94\x88\x2d\xd3\x51\x92\xc2\xc8\xfb\xd1\x84\x7e\xec\x29\x4e\x4b\x7f\xf6\x86\x34\x31\xd3\x8e\xff\x09\x3e\x90\x51\x7e\x3b\x6a\x2a\x66\x89\x78\xd0\x02\x37\xd8\x19\x33\x78\x48\x18\x2a\xc0\x94\xd9\x6a\xbc\x82\x18\x6b\x8f\x89\xf7\x35\xbf\xf7\xd1\x2c\x8b\x61\xb1\xd1\xa0\x6d\x5d\xe1\x61\xb5\x3c\x1a\xae\xaa\xe0\x88\xd1\xf1\x38\x83\xba\x05\xef\x55\x94\xbd\x22\x9c\x43\x80\x8e\xf8\xc1\x4f\xef\xd2\x6b\x92\x06\x20\xcf\x59\x83\x4f\xc0\x1e\x77\xae\xb9\x4f\x67\xd8\x56\x99\xdb\x73\x72\x1a\x07\x52\x3a\xff\xd2\xa0\x8a\xad\x2c\xfd\x98\xe3\xbe\xf9\xab\xec\xaf\x01\xa6\xc9\x30\xab\x21\x00\x4b\x84\x08\xa8\xde\xa5\x2a\xec\x01\xbf\xb9\xfa\xcd\x60\xac\xef\x3d\x95\x5c\x05\xa0\x8a\x41\xf0\xf4\xe1\xcd\x0b\xd9\x51\x14\xb2\x60\x52\xa1\xca\x57\xaa\x4c\xfe\x89\x68\xae\x43\xa0\xd7\x0a\xad\x82\x80\x35\x35\x0e\xc6\x3e\x9a\x32\xc3\x91\xc4\xde\xa8\x85\xbf\x2f\x53\xb7\x7a\x5c\xf6\xa3\x77\xb8\xd1\x65\x79\x2c\xc0\xaf\x6c\x7f\x05\xe8\x73\xba\x9e\xdc\xcc\x30\x99\xd1\x66\x95\xe5\xb8\x1f\xb8\x7c\x82\x77\x29\x74\xbb\x0e\x85\x6b\xa5\xd0\x6d\xd7\x3f\xbc\x65\xa4\x50\xe7\x90\xf2\x7d\x5c\x42\xd5\xe8\xa9\x12\x54\xba\xbb\x4e\x9f\xeb\xf9\xf2\xff\x44\x5c\x01\xd1\xa1\x03\xd5\xad\x8b\x53\x66\x0c\x17\xae\x72\xb0\xb5\x20\x74\xad\xd8\xad\x94\x27\xa5\xb7\x1f\x22\x53\x81\x04\x5b\x46\x57\xae\x12\x53\x16\x83\x4e\x53\x47\x17\x52\x80\x45\x45\xc7\xc0\x42\x32\x35\x29\x2e\x47\x2f\x0a\x09\x28\xee\xca\x02\xb0\x2c\x84\xd1\xd1\x58\x82\x4f\x5d\xb1\x55\x7b\xa7\xc1\xba\x41\xc9\xf3\x17\xb5\xc9\xa9\x3d\x8e\x67\xf3\x56\x1e\xbe\x9c\x73\x2e\xf2\x06\xaa\x91\x7d\x39\xd6\x5c\x22\xaa\xe7\x0d\xb4\x82\x74\x98\x07\xcd\x1b\xe1\x9f\x92\xa1\x96\x93\xc4\x74\x49\xe7\x32\xc1\xa3\x1c\x51\x98\x1d\x89\xa2\xb8\x15\x95\xbc\x25\xa3\x27\x14\xe7\x76\x5b\x8e\x5b\xfd\xb8\x7d\xca\xc2\x34\xd6\xcb\xc4\xce\x74\xca\x48\x8a\x04\x51\xf9\xd7\x7e\xd9\x30\x5e\x3a\x2c\x68\xd0\x8c\x15\x6a\x4a\x5a\x2e\x11\xe5\x17\x15\x2b\xe3\x09\x1a\xb5\xaf\x10\x8f\xd0\xf2\xe3\xac\x17\x16\xb7\x2b\xaf\xf8\xac\x56\x96\x9b\x7d\x6f\xeb\x2e\x7c\xb7\xa2\x4c\xaf\x9f\x77\x51\xe0\xcb\x89\xa0\xf9\x1c\xd7\x8c\xeb\xa9\xfc\x06\x8b\x10\x0d\x3d\xab\xca\x57\x48\x19\x99\x80\xd7\x2a\xd7\x90\x8f\x3c\x16\x5e\x94\x16\x09\x8c\xf1\x1f\xa4\xe0\xdf\xff\x5d\x67\x2c\xaa\x19\x87\x5e\x6a\x41\xfb\x08\x10\x47\xf0\x58\xe8\x98\xb5\xcc\xc0\x66\x74\x1b\x67\x20\xe9\x70\xdc\x1f\xa9\x54\x60\x6a\xb3\x91\x7e\xe6\xed\xf5\xff\xad\x6b\xa9\xa8\x30\x45\xe4\x7c\xb8\x44\xd4\xe3\x7e\xe6\xea\x12\xc8\x6e\x51\xee\x32\x73\x19\xe0\x00\x43\x67\xb8\xa6\xf0\x76\x14\x28\x22\x3c\xe9\xf1\x75\x50\xfe\xfe\xa4\x2f\xd9\x63\xec\x55\xc1\xdb\xc8\x28\x32\x26\x0b\x2b\x26\x6e\x76\x3c\x70\x84\x6e\xb6\x08\xec\xf8\x8d\x37\xc5\xce\x76\xf5\x81\x20\x4d\x62\x92\x27\x0e\x53\xa6\x41\x2b\x1c\x7e\x04\xf6\x2f\xb1\xcf\x8a\x30\x62\xcd\xfa\xca\x99\x59\xe4\x4f\xb8\x29\x03\x31\x89\x88\xf9\xf2\xdb\xaf\x72\xad\xbe\x2c\x0b\xb7\x8a\xe4\x50\x4a\x8a\x72\x8e\x7e\x61\x4c\x5b\xd9\x9e\x36\x18\x6b\x04\x0e\xa8\x66\x32\x68\x46\x48\x94\x5b\x12\xb0\xce\x48\xd7\x57\xd7\x9b\x90\xb3\x3b\xd9\x05\xa8\xed\x77\xc5\xeb\xbf\x23\xdd\x6f\x5b\x04\x76\x04\x73\x3d\x5e\x36\xc7\xfb\x38\xc9\x3b\x1e\x13\x2a\x56\x11\xc1\xb6\x84\x0b\xf3\xa7\x87\x10\x69\x19\x8c\x77\xd1\x04\x77\x6e\xa7\x45\xdf\x6f\x29\x74\x8f\x35\xe6\x66\x96\xbc\x0f\x73\x5a\x19\xd7\xab\x5e\x0a\xbe\xc3\x98\x42\xa9\xb8\x8a\x61\x81\x9b\xfc\xf9\x18\x8d\x97\x53\x06\x64\x15\x71\x32\x65\x67\x70\x96\x14\x9b\x02\x67\x4d\xef\xab\x8a\x47\x98\x1a\xe5\x8a\xca\x1b\x3e\x09\xa6\x4f\x78\x52\x0a\x32\xef\xe7\x26\x0d\x3f\x70\x31\x61\xd9\x45\x31\x32\xfe\xd6\xd9\x32\x69\x14\xdc\x10\x29\xaa\x25\x54\xa9\xe8\x2f\x8d\x9a\x46\x2c\xd9\xeb\xfc\x9e\x0b\x0d\x5e\xb3\xd2\xbe\x44\x12\x60\xc6\x5c\x36\x51\x9c\x41\xba\x15\xfa\xe4\x9b\x49\x6a\xc3\xd6\x39\xec\xe9\xb6\xba\xb3\xd9\x2a\x27\x98\x6d\x78\x10\x6b\xb1\x29\x28\x08\xd2\x56\xff\x69\x9e\x20\xc1\x9f\x23\x9d\x1b\x93\x83\x16\x4f\xa8\x21\x9d\xcf\x5b\x28\xaf\xba\xe9\x5c\x09\x0e\x93\x04\xf9\x47\x35\x57\x9e\xa2\x5f\x7e\xea\x77\x22\x02\x5a\xbc\x42\x6a\x6e\x60\xdc\xd5\xbc\xa3\x3f\xaf\x2d\xbb\x73\x87\x32\x54\x36\xed\xdf\x83\xbb\xdc\x23\x60\xde\x25\x20\x66\x3c\x02\xed\x19\xbf\xe2\x64\x02\xa6\x90\xf1\x47\x60\xe1\xe2\x26\x38\x89\x74\x59\x7e\x51\xf8\x8d\xe6\xe9\x32\xae\xe3\x3f\xe7\x03\x06\x22\xf9\xb3\xf8\xdf\xc9\xd2\x5d\x12\x6e\x34\x99\x1e\x0b\x7c\x7a\x5b\xdf\x1b\xfb\x69\xb0\x6c\xa7\x23\xdb\x3c\xf9\x39\xe6\x9b\x9d\xf6\x7d\xc9\x97\x6c\xd4\xad\x25\xd6\xa7\x8d\x14\x13\xc9\x72\xd9\xed\x41\xd5\x9a\xb5\x35\x46\xaf\xd5\x1c\xef\xdf\x6f\x2b\x9f\x4e\xae\x49\x6e\x9b\x2d\xbb\x37\xef\xd7\x3d\xde\x0b\xe9\x4d\xb0\x47\x76\x6b\xbf\x12\xf5\x9c\x36\x6c\x56\x26\xd5\x3b\xe2\xef\xcf\x87\xfc\x10\xd7\x27\x6b\x9a\x5b\xb7\x8d\xd7\xc1\xa9\xcf\x42\x1e\xb4\x33\x4e\x98\x95\xcd\x99\x7a\x4c\x19\xd0\xcb\x21\xdd\xa1\x41\x5e\x59\x60\x07\x23\x8f\xa4\xc3\x72\x87\xb4\xed\x94\x06\x9d\x21\xdb\x0d\xc1\x38\x39\x88\x2d\x39\x61\x08\x58\x52\x6e\x6d\xeb\xf2\x51\x20\x39\x6b\xa9\x40\x64\xa4\xf4\x17\x92\x96\x0f\x15\x8f\x84\x73\xfb\xac\x4f\xb6\x38\x11\xee\x86\x16\x3b\xaf\xad\x2c\x97\x7b\xde\x46\x62\xdf\x3d\x0f\x5d\xb5\x9c\x6f\xf1\xe4\x9c\xd7\xed\xd7\xbc\xbe\x2d\xb4\x9d\x06\x26\xb9\xee\xd9\x2a\xd3\xea\x34\xfe\x3c\xff\x96\x59\xe9\x99\xf7\x05\xa4\xee\xa8\x3e\xb3\x32\x37\x65\x3c\xb0\x08\xbc\x67\x9f\x37\xef\x4b\x4f\x09\xdc\xae\xf1\x9c\xb6\xfb\x53\x74\xbd\xb0\x0c\x4c\x58\xc3\x16\xd3\x86\x44\x29\x33\xaa\x50\x4c\xd5\x73\x65\x0c\x0d\xca\x85\x61\xf2\x68\x21\x29\x26\xa8\x51\xad\xfa\x19\x91\xd3\x5c\xe6\xa1\x9f\xc2\xd8\xc1\x6c\xd0\xfc\xa5\xc1\x9d\x4e\x2d\x5b\xb3\xc3\xd4\x25\xa0\x40\x3d\xb5\x99\x0e\x4c\xac\x05\x54\x78\xf3\x15\x6d\xe7\xc2\x88\x30\x68\x6a\xc7\x69\x22\x69\xb8\xbe\xd2\xa1\x21\xd5\x8e\x87\x5b\xc7\x48\x75\xe0\x31\x8b\xfe\x69\x33\x2a\x66\x92\xfb\x80\xa8\x91\x10\x96\x79\x93\x35\xcc\xd8\xdd\x65\x51\xa9\x8e\x7c\x71\x1a\x06\x21\x15\x5e\xdb\x16\xb2\xe1\x5b\x3a\x4e\x64\xd7\x20\x3a\xbc\xd9\x14\x67\x0c\xc6\x0c\x16\xc0\x15\x4b\xdb\x16\x49\xe0\xfe\x0a\x13\x30\x06\xfc\x36\x82\xfa\x67\x4c\xeb\xae\xc7\x30\x87\xba\x9d\x17\x84\x10\xe7\xde\x09\x3c\x43\xcf\x77\xd1\xed\x67\x66\x5e\x79\xce\x2d\x23\xce\x2d\xa5\x22\xf6\xa6\xa9\x82\xa4\x44\x23\x43\x2f\xd1\xc4\xa2\xfe\x5c\xea\x85\x5f\x7c\x7e\xa9\x7c\x36\x47\xd9\xf7\xe0\xd7\x86\x1d\x31\xfa\x8c\x91\xaa\x39\x5d\x4b\x4d\x34\x0f\x55\x21\x96\x15\x3d\xc6\xa5\x58\x7b\x1b\x83\xf4\xb0\x0b\x69\x56\xe3\x64\xd6\x20\x71\xde\x85\x70\xf4\x67\x2e\x6f\x52\x33\x73\x6b\x5b\x10\xe6\xa9\xc4\xa0\x34\x51\xa8\x9a\x06\x14\x9a\x14\xec\x26\xe3\x85\xdc\x22\xef\x90\x52\xec\x66\x06\x0e\xda\xb2\xf2\x22\x65\xf1\xf8\x69\xe0\xf0\x69\x3a\xe9\x98\xf9\x12\x57\x65\x33\x3b\xbc\x5c\x94\x15\x60\x5e\x17\xf8\xb7\x14\xfd\xe0\xd2\xe5\x58\xb4\x9f\x88\xd3\xc8\xa2\xc3\xf2\x3e\xae\x9c\xa8\xd1\x73\x3f\x6d\xe4\x40\x1d\xc9\x72\x3f\xc9\x72\x43\xf2\x75\x7a\xb0\xbd\xb3\x2a\x96\xd1\xcf\x7a\x24\x9e\x71\xc8\xaa\x28\x0e\x69\xd2\xb6\xef\xbf\x55\xaf\x60\x62\x29\xcb\x0a\x80\x3f\x34\x45\x89\xa5\x5c\xe4\x15\x98\x32\xb3\x55\x8c\x08\x48\x0f\xb5\x75\xf7\x6d\x26\x90\xec\xdb\xa3\x35\xe9\xef\x10\x78\x8a\xe5\xae\x0d\x85\xfa\x69\x78\x9d\x74\xd0\xa0\x70\x51\x54\xca\xa3\x6d\x39\xf3\x49\x68\x12\x5d\x96\xf6\x2e\xe1\x6d\xaa\x1a\x93\xfd\x7b\xdc\x7c\x3f\xb4\xac\x4a\x71\x53\xa0\x11\x4c\x9f\x30\xf7\xa1\x59\x53\xa4\xa8\xb4\xb3\x5c\xc9\x46\x2d\xf1\xbb\x5e\x8b\x09\x93\x50\xb0\xf2\xb0\x57\x2c\x09\xb9\x4a\x0e\x0f\xd1\xee\x05\x8d\x05\x4c\xe1\x80\xcc\xff\xcf\xaf\xf1\xd2\x9e\xd4\x19\x0d\xd0\xfd\x58\x8a\xc0\xda\xdf\x0d\x5d\x83\x3d\x84\xb1\x00\xee\xfb\x1e\xce\x6b\xd0\x1d\xa2\x24\xe7\x8a\x47\xea\x70\xea\x41\x9e\xdd\xfc\xf9\x09\x68\xbb\x42\x9d\xcf\xdb\x98\xc7\xc2\x47\x1e\xd7\xf0\x56\xe7\xf8\xe5\xf7\xc8\x80\x12\x26\x62\xf2\xbf\xda\x26\x31\xf7\x3e\x1d\x8c\x94\x6e\x3d\xb5\x47\xb6\xc7\xa4\x32\x5b\xce\x48\x57\xbc\xa6\x12\x33\x89\x9e\x1e\xe9\xc5\x94\xd3\x83\x60\x8d\x27\xde\x40\x4f\xb9\x73\xf1\x32\xa4\xc9\xc8\x7f\x5b\x9d\x91\x3e\x92\x04\xe8\x9b\xed\x42\x3d\x2f\xa1\x5f\xc3\x43\xc7\x88\x1d\xbb\x29\x2b\xa5\xe2\xc4\x2c\x59\x45\xab\x4c\x6a\x7a\x1f\x4b\x4a\xce\x44\x5b\x45\x7f\x1f\x58\xde\x60\xbc\xed\x45\xf6\x1e\xee\x08\x3f\xa3\xa6\x35\xbc\xd4\x4a\x74\xa3\xa9\x53\x62\x4f\xc5\x39\xc2\x1f\x6e\x51\x0c\xc7\xc1\xf1\x8c\x20\x63\xca\x89\x77\x1a\xca\x47\x9b\xa4\x03\xad\x89\xd0\x84\x13\x22\x33\xaf\xa0\x19\x09\x7e\x64\xd2\xf0\x47\xc2\x83\xa5\xed\x92\xa0\x85\x83\xcc\xa1\x22\xc1\x76\x09\xbe\x38\xe4\x7d\xcc\x86\xaf\x3e\xa9\xd4\x2c\x5c\xfb\x26\xcb\x9c\xdd\x1a\x38\x67\x77\x2b\x8e\x62\xb0\xf6\x4d\x5b\x00\x3c\x4f\x68\xf7\xb0\x9f\xbb\x58\xb2\xcc\x24\x42\x94\xe2\x02\xc5\x93\x77\x0a\x30\x6f\x6b\x55\xa9\x68\x70\xf4\xe5\x25\xf9\x94\xd0\xfe\x71\xfd\x2f\xab\x08\xd7\xf5\x0a\xe8\xa9\x7e\x79\xb0\xbb\xc2\xae\xe5\x01\xe3\x69\xe6\x5f\xca\x47\x4a\xf9\xe0\xe0\x3a\x59\x31\x8a\x00\x46\x09\xb8\xa0\x62\x43\x27\x1d\x82\xfd\x2b\x7e\x69\x14\x01\xf3\x6c\x81\x9e\xd2\x5e\x71\x45\xb2\xcd\xbc\x51\xce\x59\xc7\x49\xe8\xc6\x55\xb7\x47\x58\x77\xf2\x53\xbb\xe7\xd2\xf0\xd2\xdb\x33\x59\x53\x9d\xc3\x07\xcf\xd0\xda\x5f\x3b\xae\x97\xed\x64\x2d\x3b\xed\x4e\x9f\x09\x78\xa6\x23\xdd\x18\x2f\x0f\xda\xd1\xfb\x63\x03\x5f\x8c\x78\x06\x12\x6c\x42\x87\x14\x42\xa4\x9d\xc4\x4d\x24\x81\x55\x45\x52\xee\x14\xcb\x91\x28\xcd\x41\xfe\x3b\x00\x09\x3f\x25\x19\x64\x13\x36\xd9\x04\xc1\x5a\x4b\x4a\x9c\x0a\x52\x9f\x91\x1b\x10\x02\xfc\x24\x64\xc0\x30\x9a\xfe\x09\xef\x1f\x89\x9a\xf1\x5d\x88\xe5\xa4\x89\x8c\x83\xe7\xec\xbb\x14\xe4\xc3\xbc\x77\xf1\xd6\x68\x40\x76\x18\xd1\x56\xbd\x1f\xc4\x3c\x5a\x05\x63\x62\xe3\x7b\xbe\x34\xad\xe0\xfb\x94\xee\x41\xec\x45\x77\xf8\xbc\x0b\xf1\x91\x68\x83\x66\xee\x16\x1a\x9d\xd6\x0f\xf9\x26\x99\xbc\x66\x97\x7e\x79\x15\xf8\xec\xbb\x7c\xba\x5d\xea\xae\x91\x10\xb4\xda\xa0\xe3\x81\x35\x8a\xb5\x7f\x00\xce\x75\x28\x88\x65\xac\xa5\x86\x11\x4a\x43\x81\x85\x37\xc3\x46\x88\xe5\x53\xc1\xc3\x90\x09\xe4\xbc\xb4\xf5\xe8\xfa\xee\x91\xc8\xe0\x92\x7d\x08\x67\x02\x56\xbd\x1a\x56\xb9\x74\x73\xda\x9e\x69\x5f\xa1\x5f\x87\xb7\x07\x7f\x33\xd2\x11\x08\xd8\xca\xde\x10\x3e\xdf\x57\xfa\x5c\xbc\xec\x61\x9b\xba\x9c\x4e\x6c\x2c\x0f\x18\x91\xaf\xbd\x89\x37\x37\x10\x50\xd2\x76\xd6\xb0\x7b\x1a\xc0\x3f\xf4\xf7\x2b\xcd\x50\xb0\xce\xf7\x7e\xed\x5f\x71\x39\x5d\x56\xed\xae\x57\x34\x23\x3d\x1f\xc0\x1f\x67\x71\x5d\x7d\x94\x08\xfc\xe1\x35\x45\x6d\x1e\xae\x46\x29\x93\xd8\x2a\x4f\xb1\x89\xfa\xac\x2b\x7a\xed\xbe\xff\x39\xd9\xf5\xea\x9d\x71\x6d\xc1\x50\xe7\xa5\x29\x5c\x6d\xb4\xde\x5e\xe2\x20\xe4\x55\x81\xc3\x1a\x5a\x33\x0c\x6e\xe0\x64\x0d\xb3\x3d\xd9\xcc\xe2\x8a\xda\xb3\xf2\x67\x37\xe9\xd9\x4f\xed\x6e\x8c\x1b\x65\x8a\x14\xb7\x2c\x53\x00\xd7\x7e\x57\x1f\x6e\xbf\xd6\x6f\x20\x29\x3b\x8e\xaa\xc9\xd8\x17\x73\x73\x7d\xc8\xf0\xb8\x9c\x65\x50\x1a\xd4\xe9\x77\xfa\x70\x40\x8b\xc5\x6e\x7e\x1d\x4f\xec\x11\xa8\x6d\x9c\xa3\x40\xae\x09\x45\x39\xdc\x45\x42\xf4\x9f\x44\xf4\x39\xdc\x5d\x53\xb2\xb5\xca\xf8\x1d\xed\x51\x61\x24\x7b\xa4\x04\x09\x18\x6b\x70\x91\x64\x7e\xf1\xa9\x12\x1e\x39\xdc\x92\xb6\xfc\xda\x99\xb7\xc5\x81\x98\xee\xd7\x26\xcf\x85\x27\xd0\x4f\x13\x81\xf2\x39\xb9\xae\xb2\x9c\x59\xb7\x1f\xde\x16\x62\x96\x45\x42\xbe\xbe\x22\xba\x0f\xb3\xb7\x9f\x6f\x1d\x35\x99\x27\x5a\xb2\x50\x76\x51\xde\x7c\x17\xac\x9c\x89\x07\x0b\xc2\x58\x78\x5e\x58\xf3\x03\xb5\x0a\x2a\x4a\xad\x7d\x64\x8c\x91\xeb\xe9\x65\xe6\x66\x1e\xc8\x4b\xd3\x42\xe3\x28\x6c\x76\xfb\x0f\x03\x83\x52\x3f\x3f\xc8\xf8\xcd\x0b\x6e\x2c\x8d\x8c\x2a\xff\x4a\x44\xe9\xd0\x54\xf2\xf1\x4a\xab\x63\x77\xa4\x1d\x3c\x88\xbc\x34\x45\x0e\xd1\x80\x4a\x3c\x58\x91\x6f\x83\xa8\x79\xdd\x02\x30\xc4\x5f\x2d\xde\x7d\x98\x3e\xe8\x5f\xcb\x81\xdc\x29\xf1\x37\x0d\x8a\x28\x3e\xc9\x49\x3a\x30\xa9\xdb\xde\x41\x6d\x1d\x21\x35\x56\xc7\xd2\x33\x9f\xd9\x68\x8b\x28\xfa\xec\x15\x57\xc6\x7a\x50\x57\x41\x75\xeb\xf3\xf1\xeb\xe9\xdd\xfd\xb0\x54\x76\xd9\x6d\xe5\xb7\x31\xc3\x6e\x76\xe9\x62\x76\x29\x29\x3b\xed\x06\xfe\x89\x4e\xfb\x15\x6a\xdf\x0c\xde\xf3\x52\x18\x81\x50\x32\xaf\xd2\xf8\xc3\x0e\xa6\x36\xc3\x69\x27\xc6\xec\xa8\xc8\x66\x65\x61\xb1\xe1\x48\xfd\x00\xf6\x9c\x30\x39\xaa\x17\xe5\x21\xef\x0f\x41\xe8\x80\x55\xbb\xa2\x23\x41\x4d\x68\xf3\x0d\x6a\x75\x3e\x14\x23\x3b\x68\xa3\x41\x02\xc3\x9e\x0b\xf0\x87\x2d\x12\x6a\xa6\x21\xc8\xc1\x3f\x64\x7b\xd3\xab\x2c\x90\xdf\x29\x0d\xee\x61\x44\x97\xb7\xb2\x90\x08\x87\xec\x08\x05\xbf\x0e\xdc\xe7\x12\xa1\x13\xe9\xf7\x5f\xfc\xa8\xb1\x73\xef\xdf\x8f\xba\x48\x0a\xf8\xaa\x48\x8c\xdb\xd7\x90\x65\xf9\x51\x62\xb4\x29\xfd\xba\x16\x17\xc9\x54\xf6\x46\x07\x27\x53\xd7\x8a\xd6\x76\x23\x69\x46\x8d\x3b\xe2\xc7\x67\xcb\x35\x13\x3d\xfb\xfe\xd9\xe7\xf3\x36\xd7\xd1\xe7\x89\xfe\x80\x4d\x29\xa4\xbf\x0f\x12\x90\x8c\xe3\xe3\x2e\x6a\x8c\x4d\xe7\x91\x1c\x90\x78\x8b\x96\xde\xe1\x58\x3b\x61\x39\xc5\x4b\x3e\x3b\x24\xb3\xcf\x97\x8b\x4c\xb9\x02\xf3\x39\xa5\x81\x2b\x20\xaf\x8e\x5b\x9e\x57\xf7\xb6\xe6\xb3\xe8\x2b\x39\xce\x1c\x2e\x19\x9b\xfc\x91\x49\x71\xab\x52\x7f\x81\xed\x74\x05\x71\x04\xa6\x19\x09\x61\x91\xcf\xd2\x8d\x2b\x5d\xd7\x27\x19\xab\xa3\x17\xeb\xaf\xf7\xee\x7f\xc4\xe5\x50\x43\x28\xc3\xce\x2b\x9d\x4e\x92\xd9\x9a\x32\x32\x25\x2d\x78\xde\x9a\x86\x1b\x93\x31\xf6\x2d\xb2\x09\x07\x0f\xd7\x78\x04\x76\x62\x67\x88\x54\xa5\x5a\xd6\x47\x98\x6e\xc7\x7a\x29\x22\xab\x00\x8b\x57\x79\x3d\xf7\xed\x24\xe9\xdb\x76\x5b\xb5\x35\xf3\xe7\xe6\xb9\xc4\xad\x67\xa8\xd1\x2f\x4a\x76\xf6\x7a\xe1\xbb\x6a\x64\xf7\xd8\x87\x33\x7a\x1d\x31\xe7\xd7\xbf\x45\x9c\x45\xe7\xd8\x78\xa5\x7f\x84\x0c\x0f\xbd\x19\xd4\xb4\xfb\x44\xde\x09\x45\xbf\x42\x2b\x20\x2b\xb2\x6e\x0b\x9a\x8a\x38\x6b\xff\xca\x13\x17\x1a\x4a\xaf\xcc\x42\xe7\x6e\x25\x62\x8c\xab\x51\xc2\x19\xcf\x06\x75\xa3\x53\x66\x94\xe6\x06\xe2\xaf\x4a\x97\x6c\x36\xf9\x0c\x40\x7a\x37\x48\x7c\xbe\x36\xad\x7c\x63\x79\xa9\xbe\xdc\x75\xe3\xd8\xba\xfb\x8d\xfc\x5c\x90\xd9\x02\xd4\xf0\x57\x37\x84\x24\x94\x05\xb4\x5f\x0f\x5a\xc7\x45\xb4\xd1\x6b\x21\xdc\x2f\xa9\x29\x92\x2c\x76\xcb\x91\x84\xf0\x75\x77\x13\xd1\x44\x04\xdf\x97\xf3\xcd\x5d\xc9\xb1\x9d\x7c\x26\x5b\x09\x9f\x49\xf6\x62\x0e\xe1\x53\x31\x17\xf1\x31\x6a\x3a\x2f\x62\x0e\xdf\x62\x74\x6c\x4f\xb6\x78\x29\x57\xbe\x38\x3b\x4f\x31\x24\x3f\xbf\x9e\x6e\x5f\xe5\x16\x94\xf4\x07\x30\xe3\x2b\xe0\x6c\x9d\xb0\xb2\xbd\x88\x72\x99\x89\x23\xf2\x98\xc1\x14\xc6\x69\x02\xa5\x9d\x5f\x05\x2d\xc9\x9e\xdf\xee\x04\x4f\xce\xca\xc9\x6c\x71\xdd\x99\x5e\x93\xdd\x7e\x97\x83\xf2\x9b\x20\xd9\x5e\x1b\x33\x78\x95\xd4\x62\x1d\x86\xf8\x66\x08\x75\x59\xf8\x10\x8c\x7a\x25\xd3\x5b\x0a\x04\x2c\xe6\xc8\xea\xf2\x59\x7d\x2d\x6e\xee\xb3\x49\x2e\xa8\xea\x94\xd4\x94\x64\x11\x6c\xd5\xda\x26\x7c\x35\x9e\x96\xf5\xe0\x65\x3f\x8a\x97\xcc\x97\xd8\x6a\xac\xf9\x8a\x0a\x78\xf6\xd5\x3b\xd9\x66\x79\x89\x59\x17\x9d\xe8\x36\x1a\xf7\x39\xae\x72\x9d\x2c\xd4\x40\xb5\x2b\xc7\xbf\xda\x8c\x20\x31\xf4\x95\x9a\x0c\xb4\x59\x43\xcc\x98\x94\x14\x4c\x29\x0d\xd5\x47\x78\x00\xe2\x23\xee\xae\x0c\x31\x11\x9f\x91\x48\x21\x88\x2c\x39\x7c\x68\xf3\x01\xe2\x83\xdc\x43\x5b\xfa\x8e\xbf\x83\x7f\xd2\x0b\x3f\x2f\xc1\xda\x9b\x06\x46\x56\x91\x53\x7c\xed\x2f\x38\x86\x92\x8a\x34\xb1\x88\xec\xc5\xf2\x4d\xe1\xb2\x45\xa1\x48\x08\xff\x10\xb1\xd7\x99\x22\x31\xd8\xd9\xc8\x60\xe3\xf5\x78\x96\xda\x39\x63\x38\xfb\x7e\x28\x69\xa2\x2a\xab\xbd\xbe\xbd\xc4\x69\xbe\xfc\x73\x9a\x91\xf3\x38\xd3\xf3\x7e\x52\x07\x45\xb1\x45\x56\xa3\xdb\x63\x3f\x9c\x34\x51\x71\x16\xcd\x5d\x7b\x7f\x5e\x14\x81\x0f\x29\x64\x71\xfb\xa4\x55\x12\xa3\xa3\x8c\xf7\xfa\x40\xf4\x38\xba\x69\xa5\xc7\xec\xc0\xa1\x06\x3c\x68\x4f\x58\x1b\xaf\xf6\x39\x1a\xba\xe9\x57\xca\xc3\x31\xb4\xa8\xf2\x06\xbc\x13\x5a\x1a\xce\xe9\xa2\xfe\x84\x51\x48\x2b\xd2\x33\x89\x44\x61\xf5\x0a\x4d\x55\xfb\x1d\x6b\x7a\x82\x87\xc3\xe0\xee\xf8\x01\x95\x10\xa3\xe3\x0b\xb6\xfb\x6c\x44\x26\x76\x2e\xce\x8c\x7e\x4b\x85\xc3\xa8\xd1\x44\x3a\xf8\xfb\x6d\x32\x1f\x96\x6e\x78\x9f\xf0\x37\x7b\x5f\x70\x1f\xc0\x88\x8a\x68\x50\xa4\x81\x6c\xe0\x67\x24\x74\xd0\x4d\x83\xd8\xb9\x5d\xda\xe3\x70\x61\xf6\xe9\xfd\xd6\xed\xfe\x60\x7c\x3b\xd0\xe1\xca\x13\x59\xf3\xcd\x89\x75\x60\x5f\x04\xa2\x3d\x92\x4a\x83\x46\x9f\x9f\x07\x7e\x4d\xf1\x77\xee\xcb\x40\x34\x5a\xb4\xf2\x96\x5d\x3e\xf5\x6d\xc0\xc5\xfc\xbe\x04\x2f\xef\x1e\xcc\xd1\x6f\xda\x97\xef\x69\xe9\x80\xf0\xfa\x49\xd7\xab\xca\x19\xa1\x54\x5d\x92\x33\x90\xf7\x05\x56\x7b\x46\x6c\xfb\xd0\x21\xc7\x5c\xb2\x1c\x93\x0a\xe6\xa6\x1e\x5e\x99\xb5\xc0\xfe\x6f\x44\x09\x83\xdf\x6f\x40\x58\x27\x1d\x0c\xe8\x03\x4f\xcc\x79\x77\xa6\xbb\xfe\x32\xc1\x87\x35\x41\x4e\x39\xdb\xc8\x01\xdd\x91\x0f\xfe\xf4\xf2\xda\x7c\xae\x31\xf3\x98\x55\xac\xee\xef\x4d\x3e\x92\x08\x0c\xf6\x7a\xbe\xf6\x36\x39\xeb\xb9\x32\xd0\x93\x0b\xbe\xaf\xfe\x4c\x1f\x42\x3c\x9e\x7a\x7f\x7e\xca\x7c\x98\x38\xdf\x64\x71\x6e\x55\x7e\xf7\x49\x38\x73\x2e\xa3\x78\x17\xa9\x17\xa3\xd7\xb8\xa0\x45\x9c\x99\x5f\xd8\x46\xe8\x23\xc9\xa0\x79\x4a\x54\x4e\x19\x39\xb7\xca\xea\x5d\x09\x45\x0c\x0a\x37\x56\x69\x75\xc3\x7d\xfa\xa7\x20\x0c\xe4\x82\xc4\x2a\x88\x4b\xc1\x4e\x35\xd6\xde\x5b\xe5\x98\x8e\x15\x2d\x7e\x91\xb8\xb8\xc6\x3a\xf1\x5a\x2f\xba\x95\xbe\x61\xa6\x39\x86\x7c\xd5\x59\x2a\xca\x21\xfc\x49\xe7\x25\xe6\xf5\x72\xdc\xbd\x9f\x89\x98\xc1\x27\x20\xfb\x6a\x77\x3e\x1d\x43\x6b\x14\x02\xae\xc5\x52\x69\x29\x19\x0a\x03\x49\x27\x41\xe7\x42\x68\xf7\xb3\x93\xfd\xda\x45\xeb\x19\x74\x8c\x8a\x3e\xbe\x05\xa9\x2e\xa5\xbe\xab\xff\xfa\x14\x62\xce\xed\x7d\xcf\x0b\x3d\x5c\xf3\x9d\x20\x9e\x21\x42\xe7\xc0\x5c\x0f\x23\xc0\xe8\x18\xaa\xd4\x81\xe6\xd9\x5d\x88\xb4\x42\xbd\xb8\xcc\x6f\xd8\x23\xc2\x6a\x3e\x1d\x81\xdb\x88\xb4\xfa\xb3\x94\xa6\xc7\xd0\x4b\x6d\x87\x60\x74\xa5\x59\xb0\xfb\x25\x13\x10\x16\xda\xd3\xc1\x54\x9e\x7d\x06\x6c\x0b\xdb\xbd\x09\x96\xd4\xf8\x13\xc5\xd1\xfc\xf1\x76\x4c\x95\x05\x27\x3f\xc6\x9b\x8c\x9b\x34\xee\x54\x42\x5f\xf9\x74\xd8\x50\xfd\x07\xc9\x6c\x46\xc8\x14\x13\x1d\xe8\x0f\x5f\xc3\x48\xe5\x97\x07\x02\x97\x0c\xfe\xe7\x40\x44\x2b\x32\x3c\x27\xe7\x43\xa6\x52\x93\x8e\x66\xab\xfd\x68\x90\x7b\xa0\x5a\xbd\x84\x00\x4d\xfb\xce\x70\xd5\xae\x09\x1c\x56\x98\x7f\x5d\x7f\x50\x04\xe9\x80\xa1\x10\xb2\x21\x70\xb5\x08\xa6\x31\x5c\x7f\x63\x68\x27\x2c\xef\x45\x15\x4c\xa9\x48\xfe\xc7\xfb\xf2\x9c\xd6\xd3\xe5\x02\x62\x7a\xce\x96\xa7\xf5\x9e\x6a\xab\xed\x69\x59\x91\x61\x8e\xfb\x74\x44\xe3\xa4\x07\x91\x84\xd4\x33\xcc\xc1\x53\xfa\xa2\xd1\x75\x9f\xdb\xe5\x9b\x40\x7b\x48\x55\x1e\xb9\x16\xd8\xc6\x85\xc0\x03\xea\x2a\xf6\xa4\xd8\xae\x2b\x3c\x63\x4f\xdd\xc5\xfe\x24\x9c\x63\x2f\xba\x5e\x24\x07\x3e\xd6\x5d\x60\x18\xb0\xec\xda\xfb\xd5\x0f\xeb\x1c\xd6\x6d\x9f\xd1\x69\x7c\xee\x0b\xe9\xc8\xee\x05\x4d\x10\x7e\x0a\xf7\x37\x0c\x37\xd3\x9f\x55\x1d\xd1\xa9\xc6\x7f\x64\x10\xbf\x71\x9f\x55\xb3\xfb\x18\x39\xe5\xc2\x53\xfe\x45\xfe\x85\x50\x55\x94\x80\xfb\x18\xf7\x13\xc6\x07\xfe\x74\x91\xe4\x96\x37\x20\x6e\x65\x92\xc4\x0b\x01\x31\xde\x0f\x36\xf0\x24\x6e\xb0\x8a\xbc\x66\xbd\xff\xeb\xe8\xd7\xa9\xc7\x1b\xcf\xa8\xd3\x0f\x12\x1c\x39\xbf\x50\xd6\xfd\x7e\xb8\xe2\x30\x03\x35\x67\xa4\x0c\xf0\xcc\x3e\x4c\x45\xcc\x27\x34\x5d\x12\x9f\xfb\x45\xd7\x05\xa9\xfa\x2f\xae\xb3\x16\x0b\x7d\xb1\x6f\x32\x78\x88\x4b\x55\x91\x64\x1c\x74\xd0\x49\x74\xda\xa4\xf4\x7c\x7c\xc9\x54\x44\xf4\xa6\x5a\xea\xd4\x21\x90\xab\xa8\x55\x86\x5d\x81\x0c\x0c\x23\x4e\x81\xe6\x57\x86\x59\x2d\x70\x2e\x54\x96\x40\x54\xe6\x40\xd4\x5d\xd7\x3d\x0a\x8c\xf7\xa4\x71\x01\xa6\x17\x7f\x81\x0a\x06\x67\x08\x57\x91\x45\xd4\xdf\x22\x4b\x57\x6a\xbd\x5d\x20\x54\xec\x80\xd6\x40\xce\x84\x8b\xb7\x65\x3a\xf2\xc9\x65\x32\xb4\x5a\xd2\xf2\xe2\xf2\x62\x9d\x3e\x86\xb8\x08\xdf\x89\x20\xb1\xa9\x51\x10\xcf\x1e\xd7\x82\xec\x1f\xfb\x7f\xed\x16\x46\xc7\x97\xa8\xa6\x53\xde\x57\x6b\x33\x78\xd5\x6c\xd6\xae\x9a\x25\x32\x9e\xda\x56\x9d\xd6\x8b\x0f\x5b\x69\x39\x93\x5a\x62\x15\x2d\xbc\x2c\xde\x17\x2c\x07\xef\x13\xf5\xa7\xe9\x0c\xa8\xd9\x6a\x46\xbe\xce\x59\x0a\x0b\x16\xf6\x63\xb3\x65\x72\x9b\x2c\xf6\x2f\x4b\xc7\xe5\xf7\x20\x98\xe7\xfc\xae\x6a\xa3\xa7\xfc\x7d\x9d\xad\xd5\x31\x9c\xc8\x98\xbc\xf4\xda\xc6\x83\x22\xac\xf8\xb5\x9b\xe9\xd2\x0a\x74\x47\x4c\xe0\xad\x6d\x0a\x35\x85\xfa\x89\x5a\x52\x6c\x30\xed\xf4\x02\x7b\x90\x15\x22\x2e\x06\xfc\x42\x09\x69\x58\x09\x97\x07\xe4\xc6\xc1\x12\x86\xcc\x43\x1a\x57\x02\x7b\xaf\x89\x8a\x0d\x23\xa1\x97\x77\x1f\x03\xed\xc3\x37\xc5\x15\x08\x3e\x5f\x22\x07\x0f\x97\x2c\xa7\x22\xa4\xb0\xc3\x9b\xdd\x86\x87\x67\x73\x6c\x98\x13\xa7\x75\x50\x90\xd9\x35\xd7\x2b\x72\x2f\xdd\x2b\x3d\xad\x2f\xfd\x2e\x8d\xae\xab\x26\x50\xf8\x0f\x97\x9f\x7b\xf3\x7d\xc3\xd9\x90\xed\x5f\xe3\x27\xeb\xba\xd6\x81\xd9\x36\xd6\xc4\x4d\x26\xd6\x42\xe1\x23\xac\xd6\x1a\xa2\x9f\x11\x1d\x45\xa0\x62\x15\xa4\xf8\x1b\xb1\x53\xf5\x6d\xfc\x3f\x7d\xf7\xff\xa6\x1c\xe9\xc9\x05\x9f\x9c\x9d\x6a\xd9\xe9\xb8\x5e\x07\x45\xa5\xf3\xdb\x69\xd6\x9f\x8f\x1c\x04\x14\x7d\x68\x69\x72\x59\x0d\xb3\x26\x48\x64\xbb\xbf\x9b\x21\x26\xf2\xdd\x8d\xc1\x17\x18\x27\x9c\x36\x53\x30\xfd\xae\x12\xf8\xca\x04\xec\x3f\x36\x72\xc7\xa4\x6d\x9d\x9c\x9a\xc2\x99\xe3\xf6\x99\xe3\x7e\xca\x90\x48\x49\xa5\xdb\x1b\xfa\x35\xe0\xc5\x78\xae\xfa\x0b\x3e\x11\x16\x48\xb7\xe3\x90\x3a\x52\xd6\x66\xe9\x28\xe0\x01\xf1\x33\xd3\xf9\x41\xe9\x89\x78\xcf\x2d\x56\x0c\x5d\x59\x47\x62\x3d\xb9\xcc\x1c\x8b\xd5\xf6\xdf\x5e\xfd\x66\x7f\x87\x6d\x4b\x2d\x36\xf7\x6a\xb6\x18\x4f\x7b\x8f\xa3\x5a\xaa\xb0\x58\x7a\x0a\xff\x85\x20\x5b\xa5\x2c\x7c\xdf\x2a\xa0\x5e\x7a\xcb\xf2\xed\xed\x1b\xed\x6c\x79\x7e\xc9\xa7\x3f\x7f\x0a\x45\x0d\x40\xce\x1b\x7d\xd2\xbe\x7c\x79\x60\xc0\x42\xa5\x7e\xfd\x68\x94\x00\x4b\x1d\x4e\x28\xc5\xec\x73\x08\x87\x64\xe7\xf8\x29\xd0\xe0\x89\x4a\x04\x8e\x10\x3d\x35\x85\xd2\xcc\x2a\x8a\x7e\x34\x47\x88\x84\xc5\x5a\x5b\x51\x19\xbf\x10\xd1\x9c\xac\x31\xa7\x0d\x73\x97\x8a\x6a\xd5\x92\x18\x6a\xa9\xe2\xb7\xf0\xd3\x1f\xda\x5e\x1d\x01\x3e\x15\xcb\xae\x2e\x96\x4c\x7d\xf2\x0b\xd8\x31\x44\x2d\x33\xdb\x99\x9b\x31\xf2\x16\x71\xb8\x1f\xa7\x62\x5b\x82\x3f\x7d\xdb\xbf\xa3\x7b\xf4\xed\x21\x9e\xdd\xb1\x6d\x77\xd8\xb7\xec\x9b\xbf\xd5\xc2\x5e\xfe\xbe\xbf\x05\x5d\xe8\xfa\xfb\x2b\x6f\x28\xee\xde\x82\x34\xcb\x6a\xbc\xf3\x6a\x5b\x0c\x2b\xc7\x05\xc4\x0f\x61\x2c\x69\x30\x46\x63\x95\xd9\x54\x0e\x04\xad\xbc\xff\x0c\x56\x45\x0e\xba\xc8\x3f\xf2\xc8\xc7\x53\x5e\xc6\xa8\x09\x87\x37\x32\x24\x28\x9e\x12\xba\xc0\x82\x77\x38\xc9\x5c\xcf\x24\x37\xdb\x41\x11\x23\x65\x50\xc6\xd0\x04\x08\xf2\x98\x27\x8f\xab\x3e\xa0\x58\xa3\x8d\xb9\xf6\xc8\xd5\xe7\xf7\x68\xe7\xca\xf4\x1e\xbb\xa1\xeb\x36\x47\x23\xd0\xea\xb9\x0b\xc3\xbc\x68\xee\x20\xf5\xb8\x0b\x4a\x3a\x97\x8b\x46\x21\x38\x70\xf8\xa6\x7a\xec\x33\x84\xbb\xc9\x12\xa2\x1c\xd5\x26\x46\x20\x00\xaa\xeb\x7a\x25\x39\xe6\xb9\x46\xa5\xad\x3d\x18\x38\xd7\xe3\x88\x70\xa9\x4e\x1d\x75\x26\xe3\x29\x24\x6f\x62\x86\xd6\x82\x2c\x02\x24\x13\x8d\x4b\xe7\x90\x77\x08\x47\xce\x48\x6b\x98\x60\x25\xf4\x05\xa6\x89\x34\x31\xc8\xfd\x96\x41\x70\xff\x4c\x65\xe2\x4b\x18\x16\x73\xe2\x6b\x99\x73\xfd\x35\xa2\x5f\x4e\xd2\x23\x48\xff\x63\x27\xf3\xd6\xac\xd7\x83\xdf\x6e\xc6\x5f\xfa\x74\x75\x7f\xa5\xae\xe9\xb5\xd2\xba\xd2\x63\xab\xdd\x74\x34\xff\x5a\x44\xca\xa6\x5b\x6f\xda\xd4\x67\x88\x89\xa8\xe3\x64\xf8\xcd\x95\xa3\x82\xb6\x93\xa0\xd5\xf9\xd0\x8c\xf3\x8e\x98\xfb\x2a\x83\x88\xdf\x6a\x8f\xf4\xe9\xd2\x1b\xcc\xc7\x3b\xf2\x48\x77\xe2\x0a\xfa\x3e\x22\x14\xf2\xf3\x29\x8c\x66\xd2\x44\x83\x72\xbc\x7e\xd1\x54\xe3\x48\xe6\xc2\x9b\x28\x68\x63\xc7\x76\x94\x21\x32\x79\x95\x47\xfa\x60\x60\x98\x3c\x04\x1e\x2b\x45\x9b\x30\x19\xd6\x63\xea\xaf\x86\xc6\xca\xea\x61\x5f\x98\x5c\xe7\xa6\xfb\x65\x66\x84\x2d\x04\x07\x76\x87\xd3\xc9\xa8\xdb\x17\x7e\x87\xb4\xfb\x45\xf3\x90\xd0\x5b\xf6\x47\xc0\x1c\xe8\x03\x4e\x17\xca\xf2\x80\xa5\xc7\xc1\x17\x85\xe3\xa4\x06\x49\xf2\x6e\x72\xaa\x7a\x7b\x4d\x5d\x9d\xc2\x99\xe7\xbe\xdf\x69\x80\x50\xea\x2a\xb2\x6c\x57\x29\x62\xb1\xd3\x6e\x7a\x19\x60\x92\x4a\x5f\xff\x8b\x85\x34\x0d\x7d\x35\xbf\xd9\x0d\x82\x65\x68\x3c\x4b\x77\xf6\x89\x56\x56\xde\x6d\x14\xda\x37\x3c\xf3\xe7\x6d\xaf\xdc\x0f\xfa\xcc\x1a\x3b\x49\xc9\xa8\x79\x33\xf1\x83\x2b\xaf\xbb\x7e\x3b\xd6\x33\x35\x6b\x96\x34\x31\x99\x44\xd6\xcc\xd4\xd7\x13\xfc\x8a\x3f\xe5\x75\xc8\x0e\x5e\x50\xbb\xac\x38\x57\xe7\x84\xde\xe9\x36\x7c\xa8\x22\x78\xd6\xe4\x64\xf8\x2f\x7d\x30\xc8\x70\x3d\xf4\x68\x5c\x58\xe1\x78\xda\x3a\x85\xb5\x3f\x63\xb7\x62\x59\x45\x1f\xa0\x26\x05\x35\x4b\x37\xe7\x5a\x63\x5d\x5f\x14\xf4\xa4\x08\x3e\x65\x77\xea\xd4\x65\xf9\x38\x72\xae\x16\xbb\xea\x7e\x7f\xca\xb8\xf5\x7b\x67\x38\xa4\xca\xa0\x1c\x09\x6c\x10\x35\xbc\x63\x1f\x3e\x18\xed\x38\xf0\xc6\xd6\x18\xbc\xe9\xb7\x1b\x68\xb5\x32\x32\x74\x07\x6a\x01\x6b\x02\x2e\x41\x4d\xdc\xfc\xa9\x74\x68\x2b\xa0\xc1\xf6\x44\x20\xc6\xbe\x44\x52\x62\x0c\x2d\xac\x09\x6a\x89\xed\xbb\xa8\xca\x50\xc1\xa0\x46\x90\x34\xa8\x69\xfd\xd8\x0a\xe8\xb4\x12\xf7\x9a\xe0\xaa\x1f\x91\x52\x1f\x55\xee\xa4\x69\x56\x8b\x89\xeb\x50\x66\x93\xab\x9a\xd8\x3e\xd6\xcb\x03\xef\x38\x35\xd9\x1e\x4b\x53\x4f\x60\x0d\x25\x3a\xae\x3a\xd9\x8b\x2e\x97\xb1\xc8\x6a\xba\x1e\xaf\x91\x35\xdd\xd1\x5b\x84\x95\x9d\xdf\xcb\x4b\x0b\x34\x75\xb0\xc1\x49\x19\x2b\x70\x67\x6e\x77\x4c\x28\xc7\x76\xcd\x2d\x3c\x3f\x4d\x42\xef\xdd\x40\x29\x8d\xef\x48\xa6\x4d\x6f\x1a\x0d\x6d\x10\xa1\x40\x97\xf8\xad\x20\x9f\x73\x86\x77\x2d\x25\x8f\xa1\x4a\xb8\x9b\x7a\x1c\x9e\x5c\x88\x93\x93\x25\x75\xdc\xb4\x19\x9f\xaa\x88\xeb\x90\xfb\x0b\xce\x8f\xf4\x9c\xaf\xc6\x08\x62\x7b\x04\xae\x25\x0f\x6b\xb3\x17\x2c\x2b\x4e\xd6\x96\x54\x25\x5c\xf1\x89\x0d\x05\x33\xfc\x28\x49\x09\x2b\xb4\x54\xa3\xa2\x4b\xe6\xcd\xf4\xe4\x13\x7c\xee\xee\x67\x1e\x51\xa3\xdc\xaa\xb5\x1a\x7c\x06\xd6\x59\xdc\x60\x24\xd7\x67\x1a\x65\xf9\x3e\xa4\xd6\x6b\xde\x32\x1a\x9f\x52\xb6\x72\x7c\xbb\xb9\x6c\x8e\x53\xf4\xae\xfe\x31\xda\x67\xf1\xca\x52\x06\xba\xe4\xe1\x77\x05\xfc\x34\x85\xf7\x2c\xfe\xa1\xec\x8f\xaf\x22\x41\x5f\x6d\x8f\xd6\x2d\x00\x8e\x08\xfb\x44\xba\xc1\x1c\xee\x4f\x5f\x6b\x91\xc9\x78\x86\x93\x93\xb0\xc1\xbc\xb6\x59\x7c\xfb\x33\x54\x6a\x95\x19\xab\xb1\x48\xa6\x81\xa2\xc6\xf5\x7d\x51\x28\xc7\x7b\xdb\xfd\xb0\x78\x7d\xff\x95\x58\x6d\xc7\xe1\x38\x1d\xf9\x3e\xe2\xd1\xa1\x38\x46\x15\xb1\x4b\xdc\x57\x83\x2f\x9a\x55\xa6\xc7\xa7\x2e\x27\xe8\xcd\x27\x70\xc7\xb3\xf7\xf9\x82\xef\xef\x83\x11\xbd\xf4\xec\x48\xd8\x0e\x0e\xbd\xb6\x89\xfb\x0a\xb4\x50\x03\xee\x0c\x86\x42\x5f\x4b\x3d\xc8\x45\xe7\x2e\x07\xed\x00\x8f\x74\x08\x31\xc9\x53\x10\xbc\xbe\x42\xea\xee\x53\x91\x23\x4e\xef\xfc\x3a\x64\xe9\x80\xbc\xc9\x06\x6b\xef\x60\x87\x95\xe3\x95\x6d\xa5\x06\x17\xb6\xb5\xdf\x61\x05\x5d\x67\x73\xe3\xc3\x3a\xec\x72\x25\x3d\xf8\xc3\xae\x7f\x44\x74\x0a\xb4\x63\x4c\xb6\x39\x58\x27\x43\x6d\x8c\xfc\xec\x41\x66\x4e\x36\xdb\x8b\xea\xea\x8f\xda\xc2\x5f\x29\x24\x85\x84\x25\x41\x5b\xf3\x83\xe5\xc9\xee\x47\x91\x49\xa0\x7b\xcd\x52\x87\xa1\xe4\xbb\xb9\x8d\x47\x0a\x3d\x6d\x89\xf7\x25\x25\x96\xaf\xa5\x8d\x08\xd3\x95\x15\x21\xb2\x33\x71\xed\xb6\x04\xbc\xc3\xd4\x3c\xc4\x03\xb6\x1c\xfe\xcf\x99\x3f\x5c\x47\x88\x5a\xcd\x48\x8f\xe8\xd7\x23\x3f\x67\xbf\x65\x2e\x46\xae\x2d\xf7\xf3\x72\xa2\x7f\xbe\xd5\x51\x55\xaa\xc2\x4d\xbd\xf7\xbb\x9f\x90\x0f\xe9\x6d\x32\xe0\xbf\xed\xe5\xb3\xea\xf2\x6e\xbb\x9e\x8c\x84\x76\xcf\xa0\x3d\xa5\x2d\xcb\xa5\x72\xda\xed\x97\x0f\xaf\xf0\xd9\xb9\x1b\x2c\x3b\x53\x5e\x64\xb0\x19\x9c\x15\x4e\xa8\x76\xb9\xd4\x5a\xec\xe8\x1d\x4d\x15\x1f\x8f\x29\x8d\xc4\xfc\x9c\x35\x73\xd7\x1d\x0a\x11\x99\x78\x8a\xee\x31\x2c\xa3\x9e\x38\x9e\xee\xee\x94\xbb\x16\xe0\xc0\x63\xa3\x69\x27\xe6\x7c\x1c\x37\xa9\x47\x7e\xe6\x78\x0c\xa4\x9f\x5a\x84\xbd\x48\x74\x20\x39\x13\x58\xc5\x63\x3c\xf6\xb1\x5f\x4c\xab\x32\x44\x18\xb2\x92\x21\x05\xe7\x32\xa8\x19\x44\x15\xb3\x08\xd3\x5c\x60\xb6\x92\xf2\x1a\xda\xdb\xc3\xf1\xd3\xcf\x43\x6e\x50\x43\xd3\x65\x1d\xf6\x08\x5e\xd3\x22\x6d\x92\xec\xbb\x1a\x6e\xd9\x3e\x53\x29\x48\x6c\x63\x5c\x10\x55\x9e\xd4\x83\x7d\x82\xb9\xd8\x47\x3d\x37\x5a\xc9\xdc\x59\xf8\x45\xe7\xf6\x7e\xbd\x49\xb9\x19\x66\xd5\x85\x77\xe2\xac\x78\x06\xc3\x68\xc3\xbe\x53\xc6\xfd\x87\x72\x04\x33\xd2\x9f\xc4\x0e\xc7\x9f\x84\x7a\xd1\xb5\x98\x51\x6a\x18\x13\x91\x82\xa2\x52\x19\x11\x15\x4f\xd9\x34\xef\xb5\x10\x50\xd2\xe9\x6f\xa4\x69\xeb\x72\x98\x8f\x2c\xa3\x82\xc5\x61\x31\x7b\xf9\x2a\x5b\x07\x69\x97\x53\xff\xa9\xf5\x31\x18\x8f\x2c\x24\x32\x12\x06\xf6\x1c\x83\x7b\x4f\x5a\x5d\x01\x63\x7c\xb9\x52\x4b\x5b\xb9\x4b\x6f\x28\xcd\x8c\x6c\xd4\xdf\x9a\xb6\xb6\xb5\x68\x5a\xfa\x03\xef\xae\x7c\x20\xf1\x77\xfd\xf1\x2a\x91\xf7\xb4\x68\x99\xd5\xa4\xf3\xd7\x6b\x7f\x18\x2a\xd4\x4f\x1b\xca\x1f\x0c\xde\x70\x2b\x8f\x06\xd2\x28\x46\x32\x96\x92\xa9\x3a\x9a\x09\x78\x7b\x7c\x61\x0c\x8f\x9d\xef\x2b\xef\xee\xf6\xe2\x8e\x75\xfa\xf1\x87\xa9\x67\xdb\x72\x67\xa4\x09\x1b\x03\xe7\x90\xfb\x62\x95\xb6\xbd\x20\xc5\x45\xc9\xfb\x42\x75\x43\xbf\x04\x0d\x9d\x84\x43\xab\x16\x8c\x2a\x55\xa9\x65\x8a\x0c\x0d\x0e\xad\x1e\x7d\x38\xde\xaf\x37\xf8\x26\x13\x9c\x5c\xbb\x8b\x09\x5a\xaf\x6b\x92\x1c\x87\x36\x9e\xfb\xee\xfe\xd2\xe8\x50\x96\xd6\x19\x9c\xaf\xc0\x9e\x85\x81\xf5\x87\x98\x9d\x32\xd5\xa5\x91\x44\x17\xf4\x80\x50\xd3\x1c\x08\x3c\x4c\xde\xe6\x52\x17\xbf\x5c\x36\x86\xcb\x2e\xb9\xfd\x79\x5c\x62\xdb\x39\xe1\x3a\x59\xa4\xf3\xfd\xd2\xf8\x8d\xf6\xf1\x66\xdd\x4e\xbb\x8c\xf6\x1e\xb4\x5d\x20\x17\x72\x6e\x16\x40\xf3\x8e\x37\xa0\x02\xbf\x77\xc2\x16\xcc\x30\x9f\x9b\x7b\x0a\x13\xca\x88\x07\x52\xc8\x70\xc1\x8c\x89\x86\x4c\x4a\x59\x5c\xc8\x3a\x20\x31\x30\x79\x01\x4e\xdc\x08\xbe\x96\x8b\x39\xf5\xf1\x72\x2e\x98\xb6\x1e\x7d\x16\x57\xef\x95\x5c\x88\x78\xe7\x79\x18\x71\xd9\x15\x62\x02\x01\x32\x1b\x47\x35\x28\x4b\x7e\x67\xc6\xab\xcf\x66\x53\x74\x57\xf9\xd5\x80\x3c\xcc\x00\x1c\xe8\x0e\x43\xd1\xec\x8b\x3c\xf4\x84\x62\x46\x21\x4f\x47\x74\xfd\x0e\x31\x4a\xa7\xf7\x4a\x3a\xe9\x7a\x6e\x4e\xd8\xf9\x79\x9b\xaf\xfb\xa6\xd3\xef\xed\x88\x18\x0f\xdb\x89\xe8\x55\xdb\x37\x13\x21\x51\xab\x0a\xf5\x54\xca\xb2\xaa\x6f\x40\xae\xde\x25\x8d\xd1\x80\xca\x10\x08\xd8\x52\xaa\x0e\xbb\x37\xac\x8a\x82\xaf\xbf\x81\xf4\xe0\xdf\xc8\x31\xb4\x41\x72\x2d\x9c\x2d\x4b\xcb\xda\xfe\x65\x12\x19\x64\x25\x6d\x36\x1e\x0c\xbc\x30\xc5\x37\xba\x66\xb1\xb9\x13\xaa\x71\x6d\x7d\xbb\x43\xbe\xb9\xbe\xab\xe0\xea\x7c\x9b\x35\x26\xb2\x1b\x08\x58\xb3\xbb\x7e\x2b\xbb\x7a\xeb\xe7\x99\xd8\xce\xf6\xf4\x35\x59\x8a\x1e\xb3\xa3\xa9\xa0\x4b\xd7\x7a\xbe\x9f\x6e\x31\xdd\x9a\x5c\xfe\x48\xfc\xa2\xc2\xeb\x37\x54\x58\x2b\x34\x81\x59\x58\x1b\xf4\x89\xac\x45\xb3\x6e\x29\x69\x3e\xef\x19\xa7\xc3\x3f\x9f\xf8\x9a\x86\xaa\x9d\x8e\x1a\x48\xc7\xb1\x26\xc4\x55\xf5\x95\x97\x02\x53\x57\x0a\x80\x2f\x9b\xaa\x0d\x17\x53\xc6\x99\xc1\xeb\xe0\xa8\xd4\xc8\xef\xef\x82\xe7\x3b\x20\x0d\x62\x81\x6f\x4a\x4d\x07\xcd\x6e\xc3\x31\x80\x58\xea\xe5\x3f\xcc\xcd\x1b\xe9\xe3\x76\x22\xb8\x9f\xed\x03\xcf\xe0\x38\xaa\x67\xb8\xf9\x9e\xac\x57\xc3\xef\xb6\x1c\x8e\xac\xc0\xf7\x39\x7c\xce\x7f\x33\xb1\x93\xe9\xe9\xc9\xbf\xf8\x4a\xb3\xa3\xdb\x50\x72\xf7\xde\x92\xeb\xd8\xce\xee\xd2\x1f\x98\x6a\xd8\x5e\x7f\x75\xc2\xab\x74\x63\xe8\x52\x7a\xd3\xa0\x26\xc1\x6a\xd5\xa5\x2f\xab\x52\x44\xad\xcd\x24\xfb\x75\x6e\xc2\xe8\x17\x45\xcb\xd0\x2c\xc6\x23\x33\x69\x3b\xf8\xd1\x44\xd6\xae\x2e\x10\x0d\x4b\x95\xc8\x8d\x85\xdc\xac\x3a\x75\x11\xac\x36\x87\x97\x84\x37\x1d\x8a\xfc\x24\xa0\x32\x8c\x1e\x94\xd3\x21\xa1\x3d\x45\xbb\xdd\x64\xbd\xb8\x45\xdc\x1e\x5d\x71\xca\xe5\x33\x95\x20\x45\xbb\x41\x9f\xbf\x11\x24\xdf\x53\xf7\x50\x80\x4e\x87\xc8\x4e\xae\xcd\x62\x16\xea\x75\xb8\xd7\x1d\x58\x5e\x51\x02\x7f\xd4\x3c\x8d\xf7\x46\xc9\x09\xfa\x82\xea\x0d\xb7\x1a\x6c\x1e\x37\x60\xca\x55\x60\xb7\xc7\xf0\x27\x82\xab\xb7\x65\x56\xcd\x80\x38\xe7\xe1\x70\xc3\x0e\x6c\x72\x41\x6e\x6d\x28\xb5\x0c\xfc\xe2\x48\x03\x7c\x32\x3c\x84\x19\x07\xf6\x47\x31\x24\x8e\xf4\x45\xa9\xca\x24\x49\x8e\x59\xff\xfd\xea\xa3\x82\x1c\xb6\x40\x22\xb5\x74\xdc\x1d\xa1\xa4\x2e\x2f\x21\x38\x98\x8e\xb0\xd4\xc0\xc0\x26\x90\x4b\xa4\x52\xd6\xb2\xc6\x94\x8a\x6a\x01\x6a\x99\x7e\x10\x87\xbe\xad\x9b\x24\xa9\x25\xa6\x3a\xaf\x1e\xa1\x12\x46\xff\x39\xc4\x03\xd5\xdc\x45\x02\xf3\x78\x3b\x2a\xa9\x8c\x86\x58\xc3\x77\xf3\x00\x1b\x50\xf4\xe1\xa2\xa9\x7e\xf7\x68\x76\x7a\xbd\x63\x60\x89\x50\xb5\xe9\xce\x7e\xd0\x41\x10\x61\x8e\x7c\xc0\x77\x81\x83\x6b\x61\x49\x02\x61\x4c\x14\x66\x8a\x8a\xff\x07\xa8\xc2\x4f\x62\x78\xc8\xf8\xc5\xca\x82\x94\x4e\xc3\x45\xa5\xcc\x46\x57\xfc\x14\x72\x76\xb9\x56\x0f\xa1\x4f\x0b\x57\x0e\xf1\xc3\x6c\x1b\x7e\xfa\x0f\x88\xd3\x51\x57\x2e\x2e\x6c\x2a\x93\x1e\x7f\x6d\x6f\x3e\x61\x47\x1b\xd4\x2c\xa4\xaa\x20\xf2\xf2\x05\x06\x30\x29\x09\x09\xdb\x69\xee\x18\x6e\x70\x19\x22\x22\xfa\xc1\x9e\xcb\x4b\xcd\x0c\x89\x41\x0f\x35\xe9\xbf\x6e\x2f\xa7\xa9\xe5\x39\xed\xba\x71\xfc\x8e\xe0\x43\xfd\x83\x8e\x36\x93\xfe\x96\x13\xc7\x9b\x3f\xe7\xf7\xf1\x21\x74\xce\x5c\xc2\x52\xf3\x99\xa5\x46\x6a\x67\x52\x71\xe7\xda\xc3\xca\xd6\xdd\x26\x07\x8e\xdd\x92\xef\x56\xfb\x6d\x3d\x54\x87\xcd\xda\xfe\x1f\x9b\x3b\xd1\x69\x54\x25\xd9\xcf\x01\xe7\xb4\x07\xd8\x0a\xe3\x2e\xff\x1b\xb2\xd2\xca\x7e\xfb\x9f\x07\x99\x96\xa4\xa1\x26\x61\x6a\xb5\x92\x62\x8d\xf9\xca\x18\x9d\xd4\x23\xe5\x91\xca\xba\x45\x9a\x24\xfe\xe8\x42\x53\xcb\x82\x24\xf2\x1c\xb3\xe3\x49\x3a\x7e\x7f\x2d\xae\x3c\x87\x06\x46\x45\x1b\xe7\xb9\x5f\x64\xc9\xf6\x08\x94\x29\x6f\x5c\xe4\x20\xf1\x39\xb7\x1e\x31\x32\x26\xa6\x2e\x72\x74\x13\xd9\xa6\x92\x96\xb1\x5c\xb5\xb2\x76\x26\x71\x8e\x7a\x03\x0e\x18\xd7\xac\x0b\x19\x35\xc8\x9c\xc6\xcb\xe5\x6d\x0a\xef\xdf\x36\x56\xe0\xc3\xa3\x71\x08\xf0\x3a\x7d\x1e\xb7\x58\xe2\xd6\xcf\x9a\x2a\xec\xf0\xee\x36\x55\xd4\x78\xd8\xdc\xc7\x66\xf5\x5c\xaf\x3f\x0e\x53\xb2\x3a\x7c\xd3\x9a\xde\x3e\x78\x50\xc9\x2f\x71\xda\x6f\x9f\x1e\x5d\x78\x3c\x5d\xd7\x5a\xdf\xb2\xf3\x66\x74\x58\xf2\xbe\x3e\x5c\x5a\xe8\xae\xd7\x5a\xe4\x62\x4c\xfa\xa3\xde\x1f\xf8\x4a\x5d\x76\x74\x2d\xe7\xbe\x03\x1b\x67\x58\xce\x5a\xe7\x47\x5d\x3a\x7d\x7e\x65\x2b\x99\xdb\x53\x50\x0c\x86\x99\xc0\xa5\xc3\x56\x9d\xca\x07\xae\x8c\xc8\xfa\xa5\xfd\x43\x9f\x93\xce\x27\xcc\xeb\x25\x11\x16\x00\x0f\x57\x6f\x0a\xca\x97\x55\x75\xdd\x6b\x04\x6b\x3a\x94\x67\x1e\x0a\xbb\x56\xd4\xbe\x99\xc6\x31\xac\x0e\x64\x22\xcd\x4e\xb9\x69\x1a\x95\x02\xe2\xbc\xb9\x13\x20\x2d\x41\xbe\x27\x3e\xe3\x65\x8b\x95\x78\x57\x46\x66\x69\xdf\x68\x9c\xe3\x7c\xa4\x0a\xba\x51\x22\x66\xcc\xb3\x24\xa2\x64\xd0\x59\x87\x04\xb5\x52\xec\x96\x62\xe6\x0d\xdd\xf7\x9c\xbb\x50\x8d\xaf\x49\x45\x11\xed\x40\x2c\x6c\xb7\x78\x16\x78\xff\xe6\x70\x39\xe4\x7c\x53\x16\xe7\x7c\xc8\x72\xff\xfe\xc0\x6f\xa8\xb3\x8a\x9a\x43\x3f\x25\x5b\x45\x34\x60\xf4\xe3\xe6\x77\x8f\x63\x7a\xb3\x85\x69\x78\x46\x23\x07\x94\x7f\x2e\x52\xca\x0f\x65\x0d\x5c\xc9\xa3\xcc\x5b\xee\x22\xe0\x09\x76\xee\x63\xb1\x28\x44\x45\xb8\x20\x3b\xda\x69\x4c\x8d\x2c\xa8\xd8\x6b\xa3\x2f\xde\xed\x91\xee\x14\x71\xde\x2a\x87\xc3\x1e\x72\x89\x4e\x34\x39\x29\xd8\x8d\xfd\x26\x16\xaa\x25\x2f\x4f\xdc\x66\x1d\x3a\xa3\xab\x3c\x41\x3b\x5d\xef\x20\xa8\x97\xeb\xd6\x92\x9a\x11\x30\xc8\x53\xfe\x7d\x55\x62\x22\xe6\x23\xf1\xb7\xfa\x53\x93\x79\x01\x3d\x58\x48\xd1\xf0\x80\x84\x93\xfe\x60\x69\xae\x2b\xa8\x30\x64\x8a\xf3\xa9\x2e\x07\x3d\x30\xb9\x5e\xfe\x2d\x95\x81\xf8\xfd\xb9\x24\x7a\x26\xa3\x94\x24\xec\xbd\xb9\xa6\xfb\xfe\x6a\x63\xfb\x3d\x67\x66\x38\x0a\xd7\x3e\xfa\xeb\x1d\x33\xe7\xe4\x3a\x3d\xc8\x9b\x8e\x4e\xaf\xed\x32\x9a\xcd\xf7\xad\xde\x61\xa8\x43\x07\x12\x02\x12\x61\xc3\x9e\xdd\xdd\x61\xce\xe3\xf8\x47\x51\xc1\x4a\x62\xb0\x2d\xc1\xf7\x68\xde\x0c\xc2\x84\x53\xcb\x0c\x0e\x8f\x83\xe1\x0a\x88\x57\x36\x76\x43\xbb\x90\xfb\x50\xd0\x56\x4d\xf7\x63\x1d\x75\xa5\x16\xaf\xdd\xc3\x49\x85\xe7\xe3\xba\x96\xef\xe1\x3f\x5b\xc9\xf4\x01\x2e\x87\xde\x93\xd3\x2e\x5c\xac\xb2\x6c\x2a\xe4\x1d\xae\xa2\xeb\xc1\x39\xc8\x4b\xce\x04\x77\x88\xbf\xa2\xd6\x93\xbb\x47\x1e\x6b\x41\xab\xcb\xc2\x50\x0d\x2e\x1a\x22\x7f\x89\x05\xe4\x62\x63\xd4\xed\x3b\xef\x4f\xc2\x0a\xe6\xdd\xa0\xf6\x08\xb4\x6d\x16\xcb\x08\xa4\xf5\xd2\x74\xc1\x70\x26\xe5\x2c\xc7\x58\x6d\x2b\x2c\xcb\x4c\x0b\xee\x96\xcd\x6c\x2d\xa1\xd5\xd4\xeb\x14\xb9\xe0\x8e\x29\xfb\xc5\xb7\xc2\x73\x9b\xf2\x89\x3a\x42\xb3\xa6\x42\x1a\x44\xa8\xf3\xb5\x13\x63\xaa\xf9\xcd\x92\x25\x1c\xdc\xe9\x6b\x02\x58\x5d\x39\xed\x30\x55\xb8\x5a\x6b\xbd\x31\x60\x3b\x2a\xf6\x74\x74\xc5\xab\x5c\x2d\x6c\x75\xd7\x60\x76\x16\xcf\x6a\xfb\x1a\xc1\x90\xa6\xd2\xcf\x50\x23\xea\x07\xa4\x25\xd1\x40\xd0\x9f\x47\x11\xdc\xf0\x19\x38\x7f\x69\xd0\x80\xd5\x98\xdf\xe8\xfb\x63\xe2\x1b\xb9\x37\x37\x07\xf3\x4b\x27\x7f\x10\x92\x8a\xce\x5d\x36\x82\xd1\x14\x6d\x3c\xde\xbe\x89\xbd\xed\x3c\xfe\x60\x9b\x8d\xeb\xf9\xce\x88\x9e\x27\x78\x7f\xbe\x7e\x3b\xd0\xbb\xec\xf0\xcd\x20\xfb\x71\x2e\x16\x83\xcf\x64\x31\x9f\x3a\x97\x52\x85\x49\xe2\xb2\xf1\xf9\x1e\x84\x68\xc1\x56\x7e\x36\xf0\x20\xfa\xc9\xe2\xfd\x3b\x6a\xfe\xea\x8d\xe0\x4d\xc7\x19\xb2\x49\x91\x29\xab\x78\xa7\xaa\x87\xfe\x3a\x8c\x78\x83\x6d\xdc\x48\xac\x3a\x8d\xe9\xfb\x6d\x29\x45\x3a\x96\xcd\xc6\x8b\xe0\x94\x59\xcf\x1c\x89\xa7\xf2\xa9\x2a\x40\x5b\xce\x1d\x2a\x02\x82\x3a\x71\x33\x57\xd5\xd8\x56\x71\x22\x00\x3e\xdf\xa0\xf4\x66\xd5\x02\x00\x37\xef\x2d\x4a\x32\x7c\x22\xa7\x02\xc7\xc0\x16\x57\x88\x4c\x83\x9c\x55\x74\x28\xac\x5d\xff\x2a\xdd\x4a\x8a\x70\xf5\x5b\xa9\x2a\xc6\xe9\xc2\x4e\x27\x88\x4a\x65\x5c\x15\x23\x01\xe5\x65\x5f\x65\x53\xe8\x18\x40\xb5\xc8\x42\x86\x99\x8f\x67\x2a\x0e\x3c\xe2\xeb\x3e\x78\xba\xd2\x79\xcf\x7a\x06\x92\x08\xf4\xbc\x37\xba\xa2\x13\xc9\x69\x58\x19\xe8\xbd\x46\x3b\x49\xe5\x9c\x2f\xf1\xb3\x4f\x75\x59\x5e\x0c\x1d\xee\x97\xee\xad\x3c\x1f\xaf\x37\xc7\x28\xe4\xd4\xeb\x9f\x58\x3f\xf9\xcd\x95\x83\x6b\x38\x99\x56\xef\x87\x2b\xa8\x2a\x3a\x30\x75\xb7\x52\x26\x92\x7f\x18\x57\xb3\xeb\x6c\xf2\x1b\xef\x1b\xa3\x1f\x19\xc4\x61\x60\xd3\xa1\x9a\x9f\xea\x94\x8c\x96\x75\x48\x46\xa9\x79\xf6\x0b\xd9\x2d\x99\x9d\x3b\x9d\x54\x0d\x83\x8c\xae\x8a\x38\x67\xbf\x84\xab\xf3\x4b\x17\x72\xea\xda\xe0\x5f\x5b\x1b\xd3\x1e\x59\x4c\x59\x93\x94\xa5\xc1\x17\xed\xff\xaa\xdb\x01\xd9\x3b\xfa\xfb\x88\xac\xfc\xd5\xf3\xf8\x53\x92\xe6\x49\x38\xd4\x99\x98\x6b\x63\x1d\x7d\x37\x92\xf0\xdb\x48\xcd\x85\xbc\x99\x8a\xb3\x28\x70\xf2\x1c\xc9\x72\xf4\x62\x98\x77\x54\xfa\x41\xa9\x65\x1d\x9e\x68\xf7\xdb\x5e\x1c\xbe\xad\xd6\x4c\xba\x0a\xd6\x42\xc4\xfe\x17\xf9\xa0\xab\x84\x42\x84\x8c\x7f\x7f\x9d\x11\xf4\x02\x46\x2b\x05\x7f\x37\x3a\x85\x25\x2f\x3d\x3f\x39\x5c\x17\x9a\xe8\x62\xed\x3c\xd0\x11\xf8\xef\x40\x6c\xab\x96\xa9\xec\x93\x46\x70\x83\x22\xb1\x2c\x17\x8b\x79\x52\x58\x1b\xc2\xc6\xa9\xe0\x03\xd1\x3a\x71\xc4\xa1\xa0\x17\xea\x34\x23\xe7\x64\xa3\xc2\x8e\xad\xe1\x12\xbf\x62\xd1\x6e\xd4\x3b\xe3\x3d\xb2\x5b\xbf\x7f\x9e\xd5\x75\xfc\xfa\x4d\xb4\x59\x89\x7a\x37\xdf\x26\x3c\x0a\x83\x4e\xb3\xbd\xf6\x38\xb5\x73\xd2\x22\xb0\x23\xf1\xf1\xb6\xed\x0f\x66\xb2\x1b\xfe\xaa\x9e\x6f\xfc\x57\xd4\xd3\x99\xa3\x2e\x5b\xee\x12\xa8\x52\xb5\x3b\x6f\x82\x4d\xdb\x20\x92\x49\x71\xf1\xa0\x80\x63\x3d\xf6\x49\x23\xff\x4b\x05\x85\xdb\xa7\xe7\xbf\xb6\xa1\x7d\xa9\xfe\xa9\xda\x95\x58\xd9\x40\xf1\x00\xe6\x39\x65\x66\xc3\x2a\xd3\x6c\xf1\xbd\x97\x99\x83\x17\x39\x41\xda\xa3\x90\x4d\x84\x55\x09\x55\x06\xc3\xa0\x06\xe6\x34\xe6\x8d\xe5\xee\x42\x7c\xe7\xee\x0c\x0c\xbb\x6c\x4e\x8f\x03\x1d\xa5\x62\x1b\x4d\x4f\x5d\x9b\xa9\x36\xb0\x81\xa6\x63\x89\xf7\x12\x9b\x2d\x4e\x9b\xe1\xe1\x28\xa6\x33\x48\x84\xca\x0a\x1c\xeb\xd5\x45\xd4\x30\x92\x2f\xa2\x4f\xc8\x73\x49\xd2\x14\x94\xa3\xd1\x70\x99\xdb\x62\x9d\x5b\x69\x99\x8e\x6a\xe1\x05\xdb\x33\xac\x74\xd7\xa4\x85\x74\xd7\x3a\x08\xa3\x5f\x5d\x1a\x05\x09\x0f\x34\xe9\x5f\xa9\xab\x72\xee\x0e\xb0\x5b\xe5\x7a\x4d\x22\x39\xe2\x2d\x43\xd3\x6b\xed\x49\x6b\xb5\xf7\x41\x55\xfd\x06\x0b\xe7\x24\xa8\x6a\x10\x94\x4b\xb6\x47\xbc\x61\x6d\x51\xdb\xb2\x2c\xa4\x85\x26\x85\xcc\x2d\x6e\xc5\x8c\x23\xb7\x70\x5d\x99\xd8\x71\x5a\xcc\x4a\x85\xd9\xcb\x63\x1c\x72\x3e\xd6\x53\x77\x53\x29\xba\x6e\x31\xfc\x25\xc3\xca\x9a\x2c\xb9\x46\xe0\xc2\x33\x08\xa7\xd7\xa8\x6a\x74\xdd\xb6\xab\x95\x65\x13\x87\xa4\x52\xa5\x9b\xde\xf6\x1e\xa5\x66\xd7\x48\xd5\x6e\xc9\xb5\xb2\x2f\xeb\xce\x7e\x89\x09\x4b\x83\x27\x2b\xcc\xe4\xcf\x56\xe5\x78\x7e\x0c\x93\x63\x0a\x1c\x21\x56\x4c\xd7\xdb\x85\x9d\x5e\x4c\xa4\x65\x5e\x4a\x2a\xbd\x55\xe2\x22\x8f\xa8\x4d\x68\x23\x0d\x0f\x95\x2e\x4a\xbd\xcc\x9a\x64\x13\x15\x66\x46\x25\xc2\x0c\x39\x27\x7e\x3c\x99\x96\x0e\x4e\x50\x25\xe9\x6e\x4f\x9f\x19\xa3\xbc\x0d\x27\x81\x81\x5e\xf0\xb8\x3e\xdb\x1e\x13\xc9\x8f\xe7\x4e\xdb\x7e\xb4\x60\xf8\x48\xff\x46\x30\xb7\x5f\x57\xdb\x78\x66\x38\x7a\x0c\x3e\xf3\x79\xf6\x71\xdb\x28\xe7\xab\xda\xcd\x8c\x0d\x0a\x8b\xf3\xad\x5c\xa0\x3c\x26\x3b\x3d\xd4\x56\xa2\xa6\x1f\x62\xce\x7d\xa7\x64\x56\x88\x10\x92\x25\x67\x60\x45\x2a\x4d\xf3\x88\x77\x70\xe0\x0b\xb3\xd2\x21\x64\x84\x93\x88\x6e\xda\xc7\xa8\xb1\x9f\x16\x8a\x66\xbc\x89\x4f\x7a\x24\x67\x94\x32\x2a\x73\x82\xac\xb6\x0a\x62\x50\x7d\x4d\x6e\x63\x27\xb4\x06\xc7\x07\x85\x2b\x23\x21\x9a\x3c\xa0\xc7\x46\x12\xb4\xba\x9b\x7f\x99\xfa\x44\xa6\xbe\x6a\x0a\x4f\x1a\x4f\xee\x14\xb9\x13\x8b\x4e\x46\x9a\xc9\x65\x18\x99\x16\x8d\xf3\xd4\xfc\x58\xd1\xe6\xd8\x0b\xf9\x10\x9d\x5a\x77\x98\x1b\x02\x33\x73\xed\x25\x74\xb5\x36\x78\x48\xf6\x3f\x0e\x2d\x22\x47\x98\x3c\x59\x62\x93\x2f\x75\xdb\x77\x80\x17\x1c\xfc\xaa\xa4\x6d\x98\x2e\xe5\x3a\x90\x79\x74\x85\xac\xfb\x47\x68\xba\x3a\x15\x0f\x2b\xe5\x91\xaa\x6b\xcf\x82\xe4\x83\xf0\xaf\x33\xf0\x3a\x0a\x1b\x65\xd8\x1b\x24\xbe\x06\x53\xf2\x33\x72\x78\x4f\xc6\x53\xfa\xe3\x85\x6e\xd1\xf9\x4f\xaa\x7e\xde\xaf\x8e\x19\x04\x03\x8c\x2c\xea\x27\xbb\x65\xe4\xe6\xe2\xa7\x8c\xd1\x39\xcf\x75\x07\xfe\xd4\xc7\x96\x9e\xdb\xae\x42\xc4\x3c\xb9\x3e\x05\xca\xd3\xb1\xf3\x48\x66\x2c\x57\x25\x4b\x6e\xfa\xbe\xe6\x7a\xf7\x20\x19\xa7\x3e\xf7\x46\xa1\x41\x48\x28\x2a\x5b\xac\xb4\x1b\x0c\x9c\x86\xb8\xba\xc3\x27\x53\x9d\x55\xfd\x74\x0f\x30\x31\x78\xdc\xb4\x9e\xf5\xb9\xe3\xf8\x4b\x9c\x87\xae\x2c\x4e\x95\x94\xd4\x94\x95\x55\x3a\x6c\x56\x5b\x84\x8e\x6b\xf5\x3d\xfc\x76\xec\x97\x3e\xb4\x63\xa8\xa8\x5e\x04\xa4\x7d\x97\xc9\x52\x62\xa5\x8d\xc5\xb8\xd5\x1b\x9e\x64\x55\x5e\x8b\x33\xfb\x8c\xef\x7f\x3b\x41\x2e\x93\xaa\x65\x98\x54\x91\xd8\x5b\xb4\x83\xbf\xa7\x58\xea\x1a\x7b\x0c\x2d\xa7\xbb\x0b\x59\xcd\xf4\x14\x37\x4a\x67\x79\x06\x26\xa3\x5f\xdf\x9b\x6d\x76\x9e\x3f\x9a\x2f\xe9\xb8\x19\xce\xe2\x23\xe8\xba\xac\x5f\x6e\x14\x50\xba\xbe\xaa\x8f\x73\x7a\xce\xdf\xa2\x66\x78\x5a\x1c\x16\x17\x2d\x88\x6b\x08\x78\xbd\xdf\xec\x13\xd3\xd4\x12\xa6\xf6\x15\x1d\x10\x5b\x08\xce\x4a\x7f\x16\xf3\xda\x7b\xae\x4e\x2c\xfd\x43\xfb\x09\x5f\xf4\xf6\x17\x6a\x1f\x2a\xe3\x54\xb3\x5d\x56\x6f\x77\x0e\x93\x04\x41\xde\x8e\x4f\x2a\xf4\x54\x6a\x76\x63\x95\xed\x98\x14\xeb\x9f\x2d\x8a\x0b\x39\xe7\x41\x97\xed\x45\xe4\x08\x3e\xf5\x45\xa3\x63\x00\xc1\x95\x89\x0f\x3b\xbb\x61\x58\xb5\x07\x13\xe2\x74\x66\x88\x70\x63\x91\x80\x4b\xa9\x05\x91\xcc\x5e\x00\x52\x01\x4b\x7e\x10\x25\x98\x79\x79\x7b\x12\x64\xc3\x90\xe9\x33\x43\xc5\xd2\xf9\x11\x16\x6f\x4e\xfe\x1a\x3f\x49\x39\x78\x61\x11\x29\x0f\x8a\x04\x5a\x8d\x93\x66\xad\x07\x79\xa7\xc9\xba\x9a\x3a\x4e\x29\x2c\x55\xd1\x91\x99\x3f\xef\xda\x9f\xf2\xb1\xe0\x87\x38\x72\x0c\xda\xcd\xb2\x18\xef\x3b\xb6\x35\x0b\xca\x43\x66\xae\xba\xec\x29\x7a\x0d\x22\xb4\xe1\x68\x9a\xb5\x4e\x8f\x1f\x97\xd2\x0b\x7e\x5e\xc8\x57\xbe\x38\xf6\x98\x71\x23\x51\x57\xfa\x39\x7d\x98\xf0\xd3\x1f\xce\x20\x1d\xeb\x7b\xde\xbc\x4e\x6c\xf7\x11\x9a\x7d\xda\x9b\x08\x93\x22\xdc\x38\xca\xa9\xfd\x8c\x19\xe2\x1e\x98\x7e\x88\xea\xbf\x2d\x40\x78\x53\x49\x5d\x55\xe3\xad\xa2\x4b\x39\x24\xbb\x16\xce\x1b\xe8\xa5\xff\x05\x86\xae\x12\x8f\xb1\xa6\x84\x4e\x77\x89\xce\x47\xf1\xd8\x63\xff\xaa\x6c\xf4\xae\xf2\x67\xa7\x38\x60\xf7\xe8\xb1\x81\x98\x87\xe1\x7a\x78\x6c\x7e\x0c\x13\xc6\x40\xfd\xb5\x03\xf5\x56\x93\xa9\x1c\x07\x7d\xb1\x11\x23\xd1\x88\x50\x30\x1d\x97\xab\x89\xba\xdc\x0e\xaa\x15\x24\x38\x57\x8d\x3c\xc8\xbf\x72\xc6\x54\x8a\xb9\x84\x63\xec\x23\xd7\x40\x96\x6f\x59\xd3\xa0\xc6\x6e\x59\x07\xfb\x89\xd7\xa4\x25\x7e\x0e\x97\xe3\x02\x63\xd1\xa5\x65\x9e\x6b\xee\xfa\x37\x1c\x7a\x41\x40\x53\x40\x05\x7c\xa4\x9f\xd9\xb9\x12\x4e\xd5\xcd\x84\xfd\x12\x1b\x84\x04\x72\xcf\xa9\x29\x30\xff\x29\x34\xb3\x38\x2f\xdf\x03\x8f\x8a\x38\xee\x5b\x56\x4a\x63\x43\x7f\x68\xc8\x37\xbf\xed\x04\x2f\x93\x8c\x38\xe1\x55\xb9\xf3\x49\xfa\x8c\xba\xb9\x04\xfe\xea\xb0\x2b\xde\x69\x48\x47\x91\x6d\xf9\x9d\x03\x8c\x99\x27\xdd\x4e\x63\x77\xb5\x18\x8a\x05\xb3\x15\xa4\xda\x79\x30\x73\xc2\xca\xd9\x07\x85\xb5\x55\xc4\xe5\x6e\x5a\x2e\xcd\xcd\x27\x1d\x35\x2b\x87\x17\xf3\xfa\x63\xd2\xd1\x10\xb9\x42\x47\x58\xfa\x88\x52\x21\x83\x2a\x0b\x8b\x5a\x83\xba\x9a\xf2\xfd\x67\xf4\x07\x4b\x56\xdd\x1a\x53\x66\x00\xb1\xf3\x1f\x9a\x4e\xd1\x8b\x8f\xcc\x86\xb7\xb7\xf5\x07\xd1\xbc\xb7\x72\x2a\xba\x6c\x96\xcb\x7a\xad\xa7\x30\x41\xa5\x4f\x7f\xc4\xd3\x36\x3b\x2e\xcc\x2e\xbe\x92\xa7\xf8\x89\x95\x19\x6c\x1e\xb7\x3d\xf1\x8b\xb7\x44\xb7\x4e\x47\xf1\xf2\x97\x73\xbd\x1f\x15\xe2\xc6\x5d\xc1\x47\xa0\xb3\xe0\x08\xfb\xbf\xfa\x96\xb7\x82\xa7\xdd\xdd\x88\x6a\x51\x55\x92\x08\xc3\x31\xf2\x15\xc8\x1b\x0a\xe3\xb1\xe1\xea\x00\x05\xeb\x35\x93\x56\xf8\x73\xe4\x1d\x09\x5b\x16\x66\xb3\x89\xb7\x6b\x72\xd2\x65\xbb\xd1\xeb\x8c\x09\x4f\x6c\x1d\xb3\x0b\x4b\xe9\xcd\xc6\xaa\x6a\xd1\x39\xb0\x66\xa1\xf3\xe5\x61\xfa\x06\xd2\x78\x1c\xdc\x53\x77\x5b\xb5\xc1\x6b\x2e\xa4\xab\xf3\x80\x83\x85\xab\x0a\xe6\x9d\x15\xcc\xc1\x69\xda\x56\xba\xe5\x37\x8f\xf8\x6b\x2d\x2d\x4c\xc8\x92\xc2\xc5\x4d\x98\xdd\xc3\x9e\x99\xef\x99\x68\xf8\xf3\x11\xd2\x40\xea\xe7\xb1\x8f\xe3\x1e\xc6\xab\xf6\xf3\x41\x05\xbf\x76\xac\x9d\x81\xbd\x2f\xf6\xfb\xb3\xe4\xe5\xe7\x19\xd9\x5d\x1c\xdb\x1c\x43\xcb\x72\x39\xb9\x5b\x0d\x4a\xe6\x8e\x30\xb5\x48\x8d\x68\x66\x63\x07\x28\x9a\x0c\x78\x29\xc0\x65\x6b\xf7\x88\x17\x94\xac\xbb\x81\x9a\x9a\xa8\x80\x72\x1c\xbf\x4f\xd6\x9b\xfd\x01\x1e\xbc\x5b\x8b\xa9\x8e\x1f\x75\xe8\xc2\x8d\xf6\x3c\x65\xaa\xdf\x39\xc0\x52\x02\x32\xdc\x62\xf8\x08\x9a\xc7\xb6\x47\xf5\x26\x2a\x8b\xab\x7d\xc2\x88\xc5\x64\xcb\x6c\xb2\xe3\x62\x93\x66\x2f\xbc\x5a\x11\x96\x9f\xae\xc7\xf0\x30\x95\xb7\xef\x83\x41\xaa\xfa\x44\xc9\x65\x9f\xd8\x4f\x95\x51\xdf\x85\x11\xdb\x08\x7e\x26\x71\x79\x96\x13\x65\x56\x33\xa0\x9c\xaa\x52\xc3\x80\x98\x82\x28\x19\xbc\x09\x77\xee\x02\x61\xf9\x2c\x50\x28\x8c\x1b\xa1\x40\x77\x2c\xc0\x71\x13\x64\x63\xb0\x68\x11\x96\x19\xc2\x0c\xb6\x14\x3f\x1b\x1c\x14\xc0\x13\x25\x6b\x4c\x53\x34\x80\x04\xef\x26\x03\x61\xdc\x3b\xd1\xd6\x7e\x9b\x12\x43\x8d\x20\xb0\xbf\xd9\x0d\x43\xf4\x93\x59\x26\xe0\x4e\x55\x7f\xb6\x6c\xb6\xcd\x8c\xa3\xef\xd0\xb9\x02\xa7\x64\x31\x4e\x0b\xc3\x84\x46\xd1\xb7\xc0\xab\x89\xe3\xb0\xc7\xb5\x10\x3f\x0e\xda\x2f\x40\xd9\x57\xee\x17\x16\xa0\x3d\x49\xe6\x01\x6d\x2a\x7a\xbb\x90\x96\xc6\x8e\xb4\x89\x14\xb7\x17\xd6\x6c\x70\xe7\xa2\xd5\xb5\xaa\xfe\x9e\x80\x27\x16\x9b\xcc\x71\x1b\x1b\xc5\x21\x7b\xae\xfc\x7d\xbd\xdd\xd5\x99\x6f\x76\x87\x80\xc4\x3d\x70\x3c\x89\xef\x30\x16\x89\x95\xa2\xfc\x70\xa2\xaa\xb1\xd6\x40\x8e\x2c\xfb\x29\x1e\xea\xc1\xbd\x5a\x2d\x9e\x11\x4c\x72\xc6\xff\x53\xa2\xd5\x24\xc1\x2c\x7c\xc2\xbf\xb6\x58\xbd\x76\x67\x21\xee\xe4\xf9\xdf\xa7\xdb\x9f\xc5\x3c\xcb\xa1\xd9\x92\x81\x60\x46\xc1\x86\xf6\xf4\x7c\x55\xb1\x4d\xd4\xa0\x9d\x9f\xdc\xae\xad\xab\xb8\xd8\x4b\x58\xcb\xd4\xb4\xcb\xcc\x03\xed\x71\x24\x99\x9c\x07\x4f\x84\xbd\xc1\x3f\x99\x9e\x7e\xf2\x01\xec\xf0\xa1\xff\x0f\x00\x60\x21\x9f\xde\xa5\x5e\x71\x96\xf8\x7a\x6c\x88\x57\x18\x1a\x7b\x36\x4d\x78\xf9\xe4\x2d\xa9\xb1\xf7\x0e\xd3\x4e\xf4\xa5\x3c\x13\xf6\x70\x56\x6d\x8d\xfd\xba\x85\x8e\xd1\x1f\x10\x14\xe1\x80\x80\xb2\x79\xae\x3e\x80\xf5\xfd\xe6\x90\x4a\x72\x3b\xaf\x07\x6c\x28\x66\x34\x69\xab\xa1\x53\xad\x0c\x36\xe4\x1a\x06\x70\x55\x72\x3f\x27\xee\xa4\x72\x4f\x93\x5a\x9e\x68\xed\x4c\x77\xa1\xd4\x66\xc5\x10\x01\x90\xc9\xcf\x38\x24\x4f\x56\x6e\x51\x71\x25\xcf\x1a\x68\x25\xa5\x4c\x5a\xe7\x82\xb4\x2e\x2a\x2d\x07\x69\xad\x39\x8a\x15\x77\xbd\xd9\x93\x96\xce\x63\x81\xac\xc3\x93\x18\x31\xbf\xa4\x1e\xe1\x34\x16\xee\x68\x65\x54\xb3\x86\x61\x5a\x24\x25\x77\x0c\x4b\xfa\xdf\xb1\x65\x98\xfe\x25\xc9\xe0\x8e\xf7\x0f\xeb\xc7\x3e\x6c\xd9\x3c\xfc\x96\xfe\x23\x1d\x13\x9b\xda\xca\x1c\x37\x7a\x9e\x6e\x04\x59\x8f\x12\x77\xf8\x99\x3b\x7a\xc1\x25\x40\xc9\xfb\x27\x4d\xbd\x6e\xf4\xad\x58\xf0\xcf\xc9\xec\xeb\xe4\xf6\x5e\x8a\x2a\x21\xa9\xc7\xf7\xe4\x1e\x56\x9f\x1e\xef\xf4\x65\xba\x20\xb1\xa6\x5c\xb6\xa6\x3f\xed\x32\x3e\x9b\x05\xb5\x5e\x06\x2a\x88\xa4\x65\xc4\xee\x37\x94\x83\xb1\x0e\xd9\xcb\x35\x43\x33\x7e\x06\xc2\x5a\xbc\xe4\xc2\x3f\x5b\x8b\xef\xcf\xd6\x92\x76\x26\xe4\xc4\x55\x48\x32\x82\x0e\x72\xfd\xd1\xbc\x34\x43\x77\x30\xbd\xc1\xd7\xe6\x34\x24\xe9\xd4\x3f\xa1\x9e\x83\x89\x53\x67\xb3\x38\x3d\xe3\x52\xeb\x1d\x56\x9c\x0e\x98\x0a\xf2\xd6\xda\x42\xde\x9e\xb6\x6a\x1e\x94\x4f\x5e\xf4\x03\x47\x4f\x1c\x6d\x5e\xf1\x00\x16\xa9\xc7\xda\xcd\x4f\xb1\x07\x18\x78\x4d\x22\x16\xd4\xb2\x26\xf4\x6d\x30\xfd\x08\xfe\x2a\xeb\x6e\x31\x1d\x61\xf5\x71\xd8\xdd\x62\xc1\xc9\x44\x82\x84\xd6\x0f\x2b\xda\x44\x53\x02\xbc\xf1\x02\xe4\x97\xcc\x03\x8c\x51\x8e\x7d\xc7\x3b\x84\x05\xec\x2d\x16\xa6\x00\xbf\x88\x70\xdd\xb2\x16\xdd\xc5\xd6\x84\x23\x6c\x33\x02\x0c\x51\xc9\x64\x89\x18\xb8\x0f\x2b\xcc\x54\x78\xf1\xc0\x0b\x09\xe3\xa0\x99\xf4\xb0\xde\x5f\xe0\xd7\x48\xa0\xbd\x05\xec\xa0\x32\xa3\x0a\xc6\xc6\xae\xeb\xc4\x31\x53\xac\x9f\x0b\x9b\xeb\x1d\x56\x8c\x28\x09\x66\x63\xb1\x71\x3a\x62\x1c\x21\x95\xd3\xaf\xf2\x40\x9c\x70\xc7\x5e\x8a\xf7\x35\x8b\xa7\xde\x80\xeb\xdf\x04\xf4\x13\x99\x56\xe9\x6d\xcc\x41\xc3\xb4\x16\x06\xdb\x2c\x61\x36\x84\xc5\x1a\x8a\xb7\xb9\x26\x27\x45\x78\x33\x2e\x6b\x72\x76\xc4\x1b\xb1\x31\xa7\x8d\xf7\x44\xcd\x56\x7b\x34\xfd\x40\xce\x51\xc4\xfd\xb1\xe7\x19\x5c\x03\x38\x0d\xc0\x77\x20\x26\x2b\xc8\x77\xf4\x99\xaf\xe0\xf2\x1d\xb3\xbf\x3c\xf8\xe8\x07\x8e\xa1\xc4\x21\x3a\x2b\xd4\x4c\x1e\xea\x4b\x0f\x31\x37\xda\xc1\x82\x7a\x29\x6c\x8c\x68\x34\x85\x89\xf2\x14\x6c\x2c\x70\xb0\x64\xa0\x03\xdd\xad\x14\xe6\x62\xc6\x0b\x1c\x79\xc0\x21\x3e\x6a\xa0\x8c\x2a\x9e\xc4\xb0\x01\x64\x9c\xf2\xc7\x9a\x27\x0e\xe8\x7d\x1a\xf9\xcc\x01\xea\xd5\x7f\x14\x36\x6d\x15\x16\x26\x46\x0f\x08\x9b\x74\xd1\x98\x3e\xa0\xe7\x6c\x8d\xef\x47\x13\x05\x5b\xc9\x0e\x96\xd2\x9a\xd3\x3a\x82\xd5\x8c\x20\x4e\x90\xaa\xcf\x76\x67\x20\xf3\x9a\x12\x35\xf5\x46\x8b\xb0\xc3\x5e\xd1\x90\xc7\x75\x70\x9e\x0b\xb9\xb9\x21\x8d\xbf\x4b\x6b\x6e\x1f\x46\x51\x9f\x67\xc7\x50\x14\xb8\x7a\x9a\x84\xdd\x0f\xa2\x25\x92\xdc\x44\xac\x66\x28\x6a\x5e\x44\xcd\x66\xf5\x83\xa9\xe8\x2e\xa7\xb5\x6a\x2c\x6e\xcb\x72\x6a\x6e\x36\x96\x5a\x19\x4d\x2d\x9b\x8f\x5b\x58\x4d\x6c\x9f\xb3\x5e\x64\x73\x1d\xa3\x59\x3e\xe9\xd1\x66\x37\x72\xa0\xad\x4a\xd3\x82\x56\x33\x4e\xff\xa4\x21\x99\x59\xec\xed\x76\x25\xf7\xc2\xbd\x77\x36\xad\xc9\xe2\x11\xd6\x6f\x14\x5f\x77\xf8\xff\xf7\x75\x33\x79\xde\xee\xba\x69\x39\xdb\xdd\x67\xb3\x72\xe1\x6d\x63\xf7\xc7\xd7\x7e\x05\x5b\x7b\x51\x3b\x6b\x2f\x6e\x6b\xed\x25\x49\x6b\xcf\x3f\x0b\x9c\xc7\xa5\x45\xbb\xeb\xbf\x88\x8b\x90\xb3\x5a\xff\x09\x43\x3b\xc4\xd7\x3f\x95\xad\x3f\x48\x6e\x6c\x63\xfd\x6a\x59\x50\x2b\x80\xbd\xd2\xb1\xa0\x0c\xf6\x4a\x9e\x29\x31\xd5\xcb\x00\x28\x1b\x76\x47\x90\xef\x8e\xa0\x0b\x8d\xd4\x86\x12\xfe\xae\xa4\x19\x58\xac\x97\x28\x0e\x82\xe9\x6a\x57\xd2\xf3\xa4\x32\x66\xba\x96\x49\xb0\x21\x82\x11\xb5\x40\x51\xb3\x23\x7f\x02\x7c\x1b\xdb\xa4\x5d\x3c\x94\xb5\xda\x35\x67\xc5\x8a\x69\x2d\xf7\x92\x64\xe0\xa5\xc0\x98\x2f\x5c\x88\x15\xa2\xa7\x63\x06\x24\x5e\x7e\x58\xcb\x01\xe9\x1b\x48\x94\xc8\x37\x63\x45\xcb\x73\xb0\xb2\x58\xf4\xd2\x0b\x1d\x2c\xb4\x14\xc7\x07\x9a\xf2\xf9\x58\x1b\x02\xf8\x90\xce\x86\xf8\x5c\x79\xb6\x0b\x73\x47\xd0\xa4\x67\x45\xf8\x53\x5c\xc9\x52\x32\x8a\x7c\x21\x7e\x21\xdd\x00\xf2\x91\x78\xac\xb4\xce\x8a\xc1\x29\xb3\x95\x8e\xa2\xe7\xea\xcf\x2d\xa4\xe7\xd0\x73\x17\xea\xcf\xd2\x81\x0b\xf5\xe7\xf4\xbd\x74\x2c\x1d\x4a\x87\x2e\xd4\xeb\xe9\x90\x85\x7a\x54\x8f\x2e\xa4\xe7\xeb\x0d\x9c\xf7\x1f\x30\x09\xa6\x7f\x92\x0c\x52\x4c\x3a\x61\xf5\x35\x0b\xb3\x97\xc5\x31\x54\x80\xbc\x1f\x4a\xf4\xbf\x67\xb2\x44\x20\xe2\x47\x0b\x63\x35\x04\xe1\x93\xf8\x3a\x2a\x7b\xcc\x8a\x57\xca\x2b\x41\x83\x38\x85\xcf\xfc\x29\xc3\xc6\x7e\xaf\x3f\x82\xcc\x11\xb5\xe5\x76\xc2\xd8\x86\xd4\x3c\xf1\x24\xc0\xaa\xaf\xd1\xe4\xc5\x37\x58\x1f\x53\x58\xc7\xea\x18\xf2\x28\xc5\xe2\x30\x40\x18\xc6\xe5\x11\x7d\x25\x41\xbe\xe1\xc7\x3c\x3e\xf0\xc2\x8d\xcb\x86\x8c\x40\xc4\x8d\xd8\xd4\x7b\xf4\xc6\xdb\x87\x5f\xda\x58\x52\x28\x0b\xf9\xa1\x9b\x06\xee\x7e\xeb\xe1\x8e\xd3\x7a\x3e\xf3\x41\x20\x57\x8e\x23\x31\x5c\xb5\xf2\x93\xe1\x5f\xde\xc2\xf1\x58\xd6\x61\xcb\xf7\xc3\x7f\x5c\x35\x62\x7d\x0d\x15\xef\x2a\xeb\x08\x78\x8c\x5d\x5f\x50\xc0\xd0\x3a\xf8\xb6\x10\x65\xfa\x86\xf5\x78\x03\xbf\x28\x24\x0d\x23\xe5\xad\xbb\xbc\xd5\xb4\x20\x2b\x91\x39\xbd\xd1\x3b\xdd\xa8\xca\x8d\xa6\xba\x7d\x91\x48\xdb\xcd\xde\x4c\xe0\xb6\xe8\xf8\xfe\x02\x85\xec\x69\x6d\xdf\x72\x0d\x93\xa8\xcd\xeb\xc9\x65\xeb\xe9\xd6\x56\xd7\xf9\xff\x7a\x31\x4c\x8a\xb6\x6c\x3f\x7f\x93\x49\xce\xd3\x96\x63\xea\xd8\x6c\x1f\xf3\xf5\x0c\x84\xf5\x64\xb6\xbd\x9e\xac\xb6\xd6\x93\xdd\xbc\x9e\xb4\x76\x91\x13\x97\x8c\x2d\xd6\xf4\x3f\x5c\x1a\x9e\xbe\xa6\x4b\xe3\x86\xb1\x68\xac\xc9\x09\x6b\xf2\x01\x0f\x5f\xde\x06\xd5\xdc\x41\x35\x2d\xac\x79\x6c\x68\xcf\xc4\xeb\x19\x8d\x25\xa2\x11\xe3\x83\x5d\xed\xe3\x03\xf0\x33\x1c\x2c\x87\x18\x5f\x38\xc6\xcd\xd3\x7c\x58\xd4\x27\xb7\xbb\x6c\xbe\xa7\x5b\xac\xfa\x6d\xd8\xc7\xa7\x2f\xf9\x0a\xb6\x69\x05\xde\xf3\x6d\xce\x01\x3b\xd3\x89\x95\xbe\x2d\xbb\xbe\x53\x12\x5d\xdf\xa9\x46\xd7\x77\x54\xb0\x3a\x59\x2c\xf0\xf4\xce\x6f\x96\x36\x6b\x6e\xff\x76\x18\x76\x6d\x73\x13\xb8\x24\x37\xdb\xb7\xe4\x41\xb8\xef\x78\x36\xa7\xd2\x47\x06\x27\xd9\xcd\x0d\x76\x1e\xe2\xc3\xb1\x9c\xa2\xaf\x79\xac\x4d\x5a\xbc\xa5\x49\x13\x9c\xa1\x10\xe6\xd3\x14\xc3\x66\x62\x25\xc8\xac\x37\x24\xde\xdf\x74\xfa\x28\x91\x07\x1b\xa9\xf3\x3b\x2a\xe9\x27\xbf\xd3\x7f\xa3\xce\x0d\xf0\x4f\xff\xcd\xa4\xea\x47\x7f\x7c\xe1\xc5\x1f\xf4\xd7\xe9\x7b\xf7\xce\x9e\x73\x1f\xaf\x0b\x5e\x09\xf4\x9b\x25\x7b\x48\x29\x76\xf0\xb1\x55\xb9\x08\xb7\x4e\xb1\x26\x4b\x6a\x9e\xb8\x58\x6a\x67\x13\xe6\x50\x10\x9b\x5d\x4d\xf5\x36\x73\x3e\x68\xb2\x1c\x38\x99\x13\x64\x2d\x20\x66\x3e\x6c\xc4\x69\x8c\x62\xcc\x29\x05\xc9\x2c\x79\x3d\xac\xb2\xcf\xa6\x68\x2e\x7f\xc4\xa8\xa9\x55\x3d\x11\xb5\x50\x89\x9a\x9d\x5e\x63\x64\x4d\x3c\xbe\xe2\xf3\x12\x5f\x72\x13\x5f\x6d\x0d\xa9\xad\x89\x87\xa2\x95\x95\x3f\x3c\xb3\xe3\xf0\x2d\x74\xf4\x5f\xa3\xc3\xb5\xe2\x8e\x15\x4b\x7a\xcc\x98\xa4\x3f\xbc\x66\x52\xdf\x29\x8b\xa5\xae\x9f\x1d\xdf\xfd\xe8\xdc\x8f\x23\x17\xe9\x5f\xdf\xfe\xe8\xce\xb2\xdc\xfb\xb2\xab\xc7\x0e\x1d\x4e\xf3\xd6\x0f\xfb\xe4\xfc\x2b\x66\x3c\xba\x99\x95\xc3\x03\xaf\xb2\x9e\x6c\xd3\xe7\x60\x1f\x15\x93\x6a\xb2\x85\xe7\x3e\xf8\xd0\xa9\x32\x8c\x1d\x27\xba\xb2\x5d\xcd\x5d\xd9\x55\xb9\xae\x78\x57\x76\x27\x86\x87\x12\x80\xb5\xc4\xe8\xca\x36\x62\x2e\xd8\x95\x5d\xc2\xbb\xb9\xa4\x8e\x21\x56\x39\xad\x85\x90\x89\x09\x1f\xda\x53\xa2\x68\x81\x02\xb0\x6f\xb3\xc0\xd2\xdd\xe3\xca\x2d\x2c\x2a\x46\xed\xad\x7a\x15\x56\xa2\x23\x62\x89\x8e\x37\x8b\x37\x6a\x3b\x3d\xa7\x37\x6a\xb7\x51\x96\xc3\xe3\xbd\x6d\xb5\x6a\xcb\x3f\xec\x6d\xd1\xaa\x7d\x13\x0a\x39\xed\xf4\x7e\xed\xb9\xaf\xb5\x68\xd6\x36\xf5\xc5\xd0\xf0\x25\x46\xcb\x76\x02\x57\x1f\xb3\xda\xa4\x6a\xcc\x8e\x35\xe3\xaa\xa8\x3d\x5c\x95\xb5\xc6\x55\xc0\x8e\x05\x4b\xa7\xe1\x2a\x60\xe0\xaa\xf4\x74\x5c\xc5\x71\x54\xd4\xb1\xb2\x9a\xe3\x28\x9a\x5e\x15\x64\x3b\xf0\x7f\x83\xa7\xa4\xf2\x25\xb6\x5d\xdb\xc7\x53\xa2\xa5\xfd\x01\x2e\x87\xdb\x43\x94\xd1\xd5\x2e\x8e\x48\xec\x6d\x03\x57\xb2\x0c\xb8\x2a\x03\x99\x72\x5f\x32\xae\x2a\xdb\xc3\x55\xa8\x19\x57\xb5\x0c\x57\x6c\x7e\xeb\xe9\xb8\x2a\x37\x70\x55\x6d\xe0\xaa\x73\x12\x5f\x95\x27\xf1\xd5\xd3\xc8\x57\xa5\x65\x95\x71\xa4\x15\x97\xfc\xaf\x91\xd6\x1c\x5f\x3f\x1b\x06\x5b\xc7\x95\xc4\xb4\x3f\x65\x31\x69\x32\xd7\x1a\x27\x2b\xe3\x5c\xd6\x8c\x3b\x37\xe0\xae\x86\xf4\x22\x07\x93\x71\xd7\xa5\x3d\xdc\xf5\x88\xe3\x0e\xcb\x3f\x4b\xc1\xac\xee\x54\x5a\x05\xc2\xa8\x08\xcd\xea\xde\x0c\x99\xb5\x58\x31\x1a\x52\x6b\x4f\xc7\x67\xad\xab\x21\xc0\x4d\x6b\xf0\x86\x6a\x19\x72\xa3\x52\x79\xb7\x10\x47\x6f\x43\x05\x0f\x13\xf7\xc1\x60\x7e\x00\x24\x98\x2b\xb7\xb4\x0a\xf3\x91\x5e\xf4\x47\x53\xd2\x11\xa5\x3d\xd2\x31\x2b\x84\x38\xe5\xc5\x74\x0c\xad\x5a\x95\x0b\x68\x52\x83\x15\x78\x6a\xe0\xac\x90\xdc\x56\xbc\xff\x6c\xf0\x3d\xa9\x95\x69\xee\xfc\x73\xc4\x2f\x49\x32\xcc\x4f\x76\x8c\x63\x5f\x32\xf6\xf8\x1b\x80\xfb\x22\xf0\x5b\xc2\xe4\xe9\x64\xec\x77\x68\x0f\xfb\x95\x09\xec\x03\x06\xab\xc3\x5a\x81\x0d\xf3\x92\x54\xad\x61\x98\xc7\x99\xe7\xc5\xa7\xa1\xbd\x3e\x50\x8c\x11\xae\x22\x07\x7e\xc8\x19\xba\x82\x63\x5c\xf5\xba\xd4\x30\x7e\xb9\x1a\x3e\xab\x0e\x6a\x61\x47\x93\x56\x0b\x9f\x57\x17\x31\xec\x5b\x58\xcf\x5b\x98\x4b\xca\xca\xb6\x30\x7f\x56\x0c\x1d\x4e\xc6\x2d\x86\xd1\xda\xc7\xef\xd4\xa3\x8b\x12\x18\xbd\xf1\x68\xfb\x48\x9d\x7e\xf0\xe0\xc9\x32\x43\x18\xdc\x86\xfe\x80\x81\x4f\x79\x10\x93\x99\x75\xa4\x1f\x79\xe5\xbf\x93\x9a\x20\x08\x1a\xba\xf1\x64\x46\x9f\x60\x43\xd0\x48\x66\xf4\xff\x13\x49\x0a\xfe\x40\x43\x17\xce\xd1\x5d\x5c\x5a\x4f\x78\x17\xe2\xef\x42\xad\xa4\xec\x00\x78\xd3\xb3\x0b\x97\xae\x96\xda\x20\xf7\x1f\xdb\xe4\xe5\x3e\xdd\xe0\x28\xd4\xf1\xbf\x95\xb0\xed\xd5\xc2\x9d\x85\xd0\xad\x38\x2d\x77\xf2\x67\x02\x58\x32\xb7\xce\xa7\x88\xa4\xeb\xa9\x1f\xe4\x9b\xa4\xa1\x2c\x63\xdf\x97\x3c\x49\xa2\x1d\x31\x62\x55\x12\xd6\x42\x22\x4b\xab\x23\xfa\xd1\x16\x05\x0a\xa8\xbd\x43\x0d\xdd\xb2\x3a\x02\xe6\xd5\xce\x61\xad\x9b\x89\x4f\xa9\xea\xc7\x70\x1d\x04\x5c\x07\x4f\x9f\xbb\x02\x8e\x79\x2d\xef\x42\xc9\x06\x56\xed\x1a\x52\xb3\x5d\x5a\x77\xb4\x5a\x01\xb7\xfd\xe1\xb5\x16\x67\xb0\xb8\x3a\x86\xd0\xd1\xca\x56\x34\x4f\x19\xbc\x76\x77\xd7\x67\xa5\x31\xb7\x8c\x00\x42\x79\x25\x66\x96\x12\x25\x05\x65\x0c\xe3\xdd\xb0\x14\xd7\xd9\x6e\x29\x2e\x6f\xf7\x6d\x35\x60\xa2\xe4\x34\xbc\xd3\xf8\xc4\x89\xae\xdf\x7c\xfc\x8f\xc9\x13\x26\xdf\xb8\x4f\x30\xfd\xe3\xa5\x39\x4f\x85\x7a\x3f\x75\xd5\x91\x6f\x63\xdd\x04\xba\x6d\xeb\xe4\x5b\x87\xf6\xab\xdd\xb7\x7a\xc5\x3b\x7d\xbb\x7c\x76\xff\xce\xe7\x1a\xaf\x1c\x7f\xfe\x23\x15\x5f\xcd\x5f\x2e\xec\x15\xe8\xc9\xf9\x8b\x67\xaf\xa2\xd5\xdb\x9f\x18\x31\xed\x86\xab\x87\xba\xe5\x55\x7b\x2e\x1c\x32\xf8\x62\xfd\xe4\xd7\xf3\x4c\xf7\x1d\xa8\x0b\xaf\xea\x38\x74\xfc\x65\x17\xcc\x78\x72\xc3\xa0\x2b\x46\x46\xfe\x3e\x8b\x5a\x4c\x79\x37\x6e\x79\x9c\xf5\x64\xeb\x03\xd8\x2c\x94\xb6\xf2\x3d\xf4\xff\x94\xef\x49\xfd\xbf\xe5\x7b\xd8\xe8\x94\xb6\x6a\xbc\xc1\x69\x10\x5a\xe7\x7b\xc6\x9f\xf8\xe1\xc5\x5f\xa4\xe4\x19\x2a\x26\x3d\xb6\xfb\xc7\xe3\x74\x64\x72\xb2\x87\x0d\x54\xf9\xfc\xc1\xa4\x69\x2a\xab\x3f\xa4\x35\xb1\x0d\x2d\xb3\x3c\x22\x9f\x41\x62\xfa\x02\x3c\x46\x8c\x65\xcd\x68\x3d\x85\xa4\x00\xcc\xfc\x1c\x3e\x85\x24\x47\x4c\x84\xb5\x70\x0a\x49\x36\x9b\x42\x92\x6b\x18\xf9\x18\xd9\xb2\xa1\xce\xf1\xa7\xb3\x9a\x84\xa7\x71\x1a\x49\x46\x26\x6b\x64\x32\xbb\xff\xbb\x81\x24\xcc\x56\x3c\xf3\x54\x92\xdb\xd0\x4a\x54\xcf\x30\x9a\x44\x7a\x15\xec\xc3\xd8\x33\xf1\xf9\x24\x71\x38\x3f\x61\xb3\x56\x8a\xc8\xe4\x3f\x9b\xb6\x52\xdc\xce\xb4\x95\x12\x63\xda\x0a\x83\x2f\x3f\x50\xc4\x07\xae\xd4\xbb\x94\x82\x42\xb6\x69\xfe\xcb\x99\x2b\xcc\xc8\x3b\xf3\xe0\x95\x3b\x79\x84\xb2\xfd\xf1\x2b\xf4\xf5\x78\xad\x02\x83\x51\x36\x33\x18\x3b\x90\x59\xad\x61\x2c\x01\x18\x03\x1c\xc6\x00\xc2\x58\x96\x80\x31\x9f\xc1\x58\x60\xc0\x58\xde\x82\x96\x05\xca\x33\x9c\x96\x39\x79\x9c\x98\x00\x6c\x56\xf6\x7f\x03\x6c\xc2\x3c\x3b\x33\x4d\xef\xe1\x86\xd9\xd4\x33\x50\x55\xfc\x8e\x9b\x64\xb1\xb5\x06\x61\x25\x83\xae\x6f\x02\xcc\x38\x99\xb1\x94\x2c\x69\x0d\x35\x80\xda\x90\xcd\xa1\xc6\xa9\x00\xfe\xa0\x5a\x14\xd6\xd2\xc1\x06\x28\x0e\xc5\x5d\x45\x44\x41\x56\xa8\xde\x6f\x43\x9d\x9f\xe9\x60\xe3\x01\xb0\x45\xad\xd4\xd1\x54\x9f\x53\x5a\x64\xa9\x48\x0c\xec\xcf\xc4\x7e\x52\x6b\x36\xab\x0b\xab\x77\x7a\x25\x7c\x46\x9a\x5a\xca\x7b\x4d\xad\x7c\xfc\xc1\x19\xf0\x00\x5a\x3d\x8e\x02\x36\xcb\xbe\x4d\x34\x5c\x7b\x74\xa1\x81\x01\x3a\xf5\x68\x9b\x48\xf8\xf1\xe0\xc1\xd8\x2a\x4e\xfa\xff\x60\x8c\xe0\xd4\x73\xe0\x18\x8f\x01\xbb\x48\xe2\x39\x2e\x9e\x3b\xa3\x46\x8e\xeb\xcf\x13\x67\xe7\xb2\xc4\x59\xa3\xa9\x11\xb6\xcc\x89\x5e\x38\x51\x05\x64\xe5\x3d\x20\x30\xfb\x99\x5e\x6f\x99\x37\xa3\x67\x9d\x37\xbb\xa7\x71\x1f\x2f\xd0\x85\xab\x49\x2f\x24\xe5\xcd\xde\x84\x5f\x21\xd3\x2f\x2d\xf3\x66\xf4\xbf\xca\x9b\xd5\x18\x79\xb3\x46\xe9\x7b\xa3\x58\x26\x8d\x2d\x9a\xe5\xcd\x1e\xc1\xbc\x9c\xe9\x69\x23\x6f\xd6\xd7\xc8\x9b\xb1\xd8\x8e\x95\xb7\x14\x59\x42\xac\x13\xf4\x7f\x93\x39\xbb\xec\x68\x7a\x63\xee\x51\xe9\x5f\x07\x0f\x9e\x70\x33\xc8\xfe\xc5\x62\x34\x03\x4f\xfd\x20\x55\x9b\xfe\x09\x76\x54\x25\x99\x63\x4c\x85\x2e\x02\x5e\xab\x08\x62\x6c\x84\x0d\x9d\x91\xf8\x44\x95\xaa\x24\xe3\x88\xf5\xc5\x60\x23\x6f\x1a\xd7\x1c\xa5\x60\xbf\xef\x11\x1d\x5e\x7f\xae\x19\xb9\x2a\x4b\x51\x7d\xc0\x55\x15\x60\x57\xaa\x24\xa2\x8a\x8a\x26\x9b\xb1\x8e\xc5\x1d\xb5\xd9\xfd\xa8\xb3\x15\x45\xf3\x1a\x63\xd2\xd8\x33\x4c\xea\xc0\xc4\x31\x95\x16\xc3\xef\xba\x5c\x8a\x0d\x85\x69\xee\x56\x63\x43\x58\x13\xed\x40\xea\x7d\xff\xb2\xfb\x6a\x24\xeb\x88\xfe\xfa\xa7\x43\x28\x29\xbd\xb8\x63\xf7\x0b\xee\xe8\xf5\xd1\x90\x57\xc7\x4e\xd1\x3f\xff\xe0\x23\xbd\xa9\xf1\xa1\xd5\xb7\x3e\x5e\xb8\x63\xee\xd2\x1d\xf4\xdd\xaf\x69\xf6\xa0\xee\xa6\x99\x6a\xdf\x87\x27\xad\x4f\x2b\x48\x79\xc8\xd3\xb7\xea\xe6\x49\xb3\xa6\xe8\xff\x7c\xf0\xe3\x7f\xeb\x87\x68\xfa\x5f\x96\x1d\xfa\xfa\xc9\xbb\xba\x5d\xc8\x9e\x0b\xc0\x66\xb0\x80\x6f\x84\xd1\x99\x5b\xdb\x99\xc2\x02\x46\xb8\x96\x09\x2e\x50\x51\x66\x00\xf6\x95\xdf\x78\xa2\x0b\x3d\xc2\x46\xb2\x08\x2e\xb5\x14\xac\x98\x06\x2f\xb7\x08\xbd\xc1\x86\x52\x7e\xe4\x66\x45\x87\x38\xc0\x23\x87\x0d\xf0\x68\xc8\xe5\x7e\x0f\xee\x49\x3b\x05\x4e\x91\x53\x03\xcc\x7f\x0c\x60\xa5\x61\x29\x3e\xc6\x46\xf5\xb6\x33\xbc\x45\x6c\xc3\x93\x69\x39\xd0\x65\x66\xeb\xc2\xa5\xd6\x03\x5e\x4c\x99\x2d\x53\x07\xc0\x6d\x6c\xde\x8b\xe9\x73\xe2\x24\xe8\x1b\x9e\x63\x64\x0e\xd2\x92\xf4\x4b\x3c\x9f\xd5\x3c\x55\x2d\x91\xcf\xf2\x30\x6f\x2d\x95\x65\x0f\x1b\x24\x97\xdd\xad\x18\xf9\x81\x16\xd3\x5f\x92\x82\x28\x6d\x8e\x80\xb9\x1f\xf7\xf1\xfb\xed\xcc\x81\x91\xf6\xa2\x42\xec\x96\x34\x0d\x26\xbe\xe6\x8f\x8d\x1c\xdc\x39\x6d\x4e\xa9\x39\x63\x0e\xae\x41\xb2\x67\xe7\xb0\x16\x1d\xf0\xd6\x73\xf3\xfe\x74\x62\x0d\x53\x77\x6d\x8f\xad\x39\xc0\xd5\x5c\x7b\xc3\x6b\x84\x5d\x49\xf1\x0b\xb6\x6e\x19\xab\xa9\xd3\x40\x97\x5f\x60\xac\x3b\x33\x49\xe2\xc7\x15\xb8\x1f\xb3\xd2\xbc\xba\x37\x9e\x7f\xf3\x27\x70\x9d\xa3\xec\x91\x5c\xe0\x1c\xd8\xf9\xc8\x2e\x56\x59\x74\x3a\xd2\x5b\x06\x17\xda\x44\x7c\x3d\x17\x48\x6b\xdb\x41\xbd\xf8\x99\xa1\xb5\xdc\x2d\x66\xf1\xc4\xe1\x70\x03\x1c\x01\xf0\x67\x97\x1a\x70\x14\xc7\xe1\xe8\x08\xb2\x23\x2b\xa8\x79\x61\xb7\xe4\x7a\xb3\x60\xb7\x28\xcd\x79\xb8\x02\xf6\x64\x46\x35\x80\xbb\x25\x85\xef\x91\x94\x60\x3c\x52\x50\xe0\xd2\x3a\x70\x88\x55\x3f\x7e\x81\x57\x96\xb1\x84\x9c\x1f\x85\x8c\xa4\xd8\xb3\xd8\x20\x16\x30\x4a\x25\xf6\x94\x02\x8c\xed\xa5\x44\x4e\x83\xbd\x5d\x9f\xbf\x4d\x34\xac\x6a\xb5\x6d\x3a\xb5\x87\x8f\xe3\x49\xbb\x27\xa6\x24\x23\x45\x32\x78\xf2\x0d\xe2\x64\xd3\x7d\xd8\xac\x65\x7b\x7c\xbe\x4f\x62\xb4\x4f\x0a\xcb\xc1\xa5\xb6\xc8\xc1\xb9\xed\x4d\xf5\x29\x6e\xd4\xe0\x8a\x23\x31\x7f\x11\x50\x50\x5f\x68\x49\x87\x93\xf9\x70\x32\x3f\x88\x39\x39\x9e\x88\x53\x30\xdc\x6b\xf7\x65\xb7\xb9\xd1\x12\xfe\x77\x1c\x4e\x54\xd7\x2d\x60\x5d\x73\xf4\xc1\x38\x74\x74\xfb\xd1\xd6\x00\x7e\x05\x1a\x3a\xa5\x99\x77\x3f\x66\xf5\x15\x22\x39\x97\x34\x48\x95\x52\xd4\xd0\x4d\x55\xc4\x98\x75\xc6\xda\x33\x2c\x6c\x1a\x91\xd5\xc6\xa7\xea\x4b\x47\x70\xd4\x22\xea\x23\x5b\xa8\xf9\x39\x86\x6c\x19\xa8\x8f\x40\x63\xc7\x76\x1d\x38\x70\x40\x18\xb1\x6f\x9f\x3e\xf6\x8d\x37\xc4\xf0\x1b\x6f\x30\x7e\xba\x41\x2a\x97\x9e\x33\x72\x73\x53\xe2\xb9\xb9\x24\x5b\xfe\xcf\x72\x73\x69\x98\x9b\x7b\xda\x22\xf9\x14\x7f\x3c\x39\xa7\xd9\x58\x67\x47\x72\x7a\x4e\xcb\xa9\x66\xc9\x39\xcd\x6c\x8b\x24\x98\xc6\x48\xcf\x71\x14\x36\xa7\xe7\xfc\x61\xae\x76\x7c\xcd\x03\x2d\x4b\x0b\x11\x95\x5d\x26\x57\x0d\xba\x65\xca\xa8\x31\x80\xcf\xf0\xe5\xe5\x03\x6f\xb9\x72\xdc\xe4\xc6\x0e\x65\x32\x3d\x3f\xa7\x5f\xf1\x9a\x3b\x9f\x4a\xef\x12\x58\xb3\xbe\x30\x5f\xe6\xa8\x4d\xf3\x6e\x7c\x6f\xd0\x77\x6b\x10\xbd\x8a\x6b\xc3\x9b\xe7\xfe\xbc\x71\xf4\xa6\x6a\xe1\x01\x97\xfb\xcb\x9d\xfa\xf5\x0e\x3b\x20\x7a\xd8\x9a\x20\xcb\x5b\xb0\x99\x39\xc0\x3f\x1e\x92\x8e\x33\x15\xdb\x99\x9a\x93\x71\xe6\xa9\x39\x99\xf1\x8e\x23\xaf\x2f\x82\xe6\x6d\xbd\x92\xe6\x4f\xe7\x3d\xfc\x7f\x3e\x42\x87\x89\xe9\x56\x73\x74\xae\x63\xa9\xbb\xd3\x86\xe9\x48\xff\x49\xe4\xee\xf8\xba\x5f\xff\xbf\xaf\x1b\x53\x67\xf5\x8a\xd7\xc7\xd7\xcb\x1e\x21\xe5\x70\x6b\x69\x2c\x9d\x71\xc6\x75\xb3\x1c\x5f\xeb\xf9\x3f\x63\x79\x74\xf9\xb4\x95\x8b\x3f\x27\xe5\x8a\xf8\xda\x7f\x81\xb5\x67\x93\x69\xed\xae\x3d\xe7\xcc\x6b\xcf\x6d\x85\xf3\x06\xc0\x79\x66\x76\x02\xe9\xaa\x43\xd1\xd2\x33\xfe\x14\x88\x84\xb8\x6e\x05\x88\x51\x6b\xdd\x06\x09\x72\x9a\x73\x83\x1c\x8e\xa7\x01\x0e\x3f\x68\xc4\x05\xad\x21\xf1\xa1\x11\x99\x11\xd6\xbc\x58\xbe\x1f\x6a\x06\x2c\x3b\x01\x98\x17\x43\x30\x7e\x47\x2b\x08\xd5\x2c\x3c\x9d\xee\x60\x45\xff\x59\x8e\x64\xa0\x51\x31\xa5\xa3\x4f\xa1\xc8\x67\x01\x1a\x4f\x1e\xb6\x82\x6c\x3c\xa6\x0f\x4f\x07\x2b\x60\xe4\x0f\xd9\x9c\x20\xe0\x2b\x1f\xf8\x47\x3d\x4f\x9f\x14\x94\x95\x98\x14\x84\x69\x57\x19\x0b\x6c\x39\x96\xcf\x7a\x66\x10\x33\xf7\xdb\x1d\x1c\x64\x38\x01\xa7\x8d\x0f\x92\x1e\x4d\xe2\x9f\x7b\xf4\x71\x52\xd8\x98\xed\x3a\x22\x69\x26\x5d\xd2\x38\x3a\x95\x26\x4f\xa4\xd3\x04\x77\x28\xd4\x7a\x1e\x1d\x7b\x16\x33\x9f\xae\x6b\x4c\xa2\xd3\xe4\xec\xf8\xf8\xa9\xd6\xf3\x75\x5b\xcd\xa2\xbb\xa7\xb1\xf6\xee\x09\x6d\x8c\xa2\x33\x3f\x1b\xdb\xd9\x7f\x60\xfb\xb3\xe8\x44\x03\xbf\x4f\xb3\x6c\x72\x0e\x76\xc5\xfb\x91\x4b\xb2\xc2\x5a\x1a\x70\x49\x66\xe8\x34\x84\xe7\xe2\x38\xb1\x78\xe6\xd8\x84\x38\x47\x27\x53\x36\x19\x9e\x67\x26\xf0\x04\x10\x23\x0f\xc3\x0c\x69\x60\xd7\xda\x14\x8a\xb6\x7e\x26\x50\x41\x62\xd9\xf9\xb3\x27\x4c\xbc\xfa\xb2\x3d\xda\xe8\x3a\xce\x4a\x68\x83\x34\x7f\xe7\xf5\x22\x38\x2b\xe5\x07\xf3\x05\xec\xb9\x7f\xc5\x64\x19\xef\x37\x63\x93\x82\x13\x8f\xff\xc3\xa7\xca\xb3\xa7\x0b\xf1\xda\x0f\xf0\xb4\xed\x29\x3e\x89\x67\x87\xa9\x5a\x92\x78\x0e\xa0\xf1\xf8\xbf\x54\xa6\xcf\xa2\xa9\xb9\x6c\xd0\xb0\xd5\x5a\xa1\xba\x42\x70\xe0\xb4\x56\x30\x5f\x08\xeb\xdc\x35\x9f\xc4\xa6\xe0\xa8\xf8\x10\x43\x56\x3e\x97\x1b\x01\x35\xa3\x18\xdd\xa9\xc6\xe3\x1a\x9b\x4b\x4c\x03\xc6\x53\x1f\x92\x87\xf1\x4d\xa1\xb5\xc7\x06\xac\xbb\x40\xbc\x3d\x51\x74\x3a\xed\xf2\x25\xfd\x8e\xe9\x87\x1a\x5f\x79\xbc\xc7\x8d\x5d\x7b\xdc\xd8\xfd\xf1\xfd\x42\x6f\x5a\x4d\xad\xf4\x7c\x87\xd5\x28\x45\xb5\xd9\xe9\xf9\xd4\x7a\xe4\x6b\xab\x55\x5a\x64\xb1\x7f\xf5\xbe\x61\x9f\xc9\x7f\x48\x43\x49\x01\xa9\x26\x11\xb2\x9e\x44\xf3\xd1\xa3\xc9\x0c\x63\x24\x45\xf5\x84\x98\x56\x05\x09\x80\x0f\x40\x54\xeb\x42\x0d\xa1\xd4\x7c\x84\x3d\xd4\xfc\x24\xed\x42\x3b\xab\x00\x42\x2f\xc5\xe5\xc6\xac\x03\x86\x0f\xc3\x46\xd6\x19\x1f\xa1\x5d\x56\x88\x33\x9b\xf2\x59\x7f\x82\x66\xce\x81\xd7\xb0\xbb\x3e\xd5\xe6\xc9\xe4\xc2\xdb\x10\xdb\x25\xf9\x00\xbf\x1f\xd1\xa2\xa5\xc1\x77\xb4\xca\x50\x62\x2c\x21\xd7\xbc\xed\xc7\x5d\x5b\x19\xe0\xc5\xf1\xf8\x03\x6a\xe0\x25\x07\x7b\xf7\x79\x79\x46\xab\x08\xc4\xd2\x37\xfa\xf4\x3e\xb0\x28\xd9\x32\x17\xfd\xf1\x88\x0c\x53\xc5\x33\x27\x8c\xbf\x3a\x39\x20\x31\x75\xdc\xb8\xa9\xc9\x96\xfa\xe4\xe6\x98\x1b\xaf\x5d\x70\x30\x5f\xdf\x45\x2e\x6e\x59\xbd\x80\x71\x04\x67\x58\xb3\xd9\xf0\x41\x9e\xac\x54\x1b\xbd\x7f\x2e\x1d\xcd\xfc\xa9\x54\x38\x84\x1d\x1f\xd8\xe2\x82\x1d\xe1\x3e\xf3\x58\x7b\xd1\x60\xf6\xe6\xfa\x86\x5f\x59\xa1\x71\x52\x75\x43\x9d\x51\x6b\x4c\xc9\x2e\xe9\x6b\x51\x31\xfd\x00\xeb\xaa\x60\xcf\x9b\x36\x85\xf1\x71\xcf\xac\xf1\x98\x05\x37\x1a\x4c\xac\xe5\x16\xe3\x1b\x7c\x44\x9b\x81\x6c\x43\xb5\xec\xe2\xba\x44\xfa\x3a\x51\x6e\x0d\xd7\x5c\x2e\x7d\x21\xf6\x30\xfd\x06\xba\xe3\x02\xc2\x66\x1d\x83\xd5\xee\x92\x9d\xb0\xad\x45\x53\x7c\xf4\x68\x83\x87\xdb\xe7\x1e\xa6\x1d\x1a\x6c\xdc\x2c\x67\x23\xfa\x3c\x58\x3e\xca\x64\x97\xcb\xc9\x1c\x7e\x4d\x94\x8d\xf6\xa5\xb6\xac\xf0\xe5\xad\x3d\xd4\x13\x2d\x1d\xd2\xe4\x19\x11\xa4\xc5\x04\x88\xff\xcb\x67\x8f\x0b\x2b\xa4\x6f\xc5\x42\xf8\xcc\x7f\xda\xdc\x89\xe6\x21\x06\x8f\x4b\x3d\x85\x15\x5b\x71\x36\xff\x1a\x61\x85\xa9\xf1\x4f\xbf\xbf\xc6\xd4\xc5\xf8\xfe\x30\xf1\x24\xbd\x90\x3d\x6f\x3d\xf1\x0c\x6e\x4b\xf3\x33\xb8\x4d\xc6\x33\xb8\x4d\x94\x73\x01\xfe\xb5\x27\x2c\xfa\x86\xdd\x3f\xbe\xbb\x78\xf2\x59\x7a\xa5\x7e\x77\xd4\x78\x6e\xbb\x18\x3b\xc3\x75\xda\x7d\x66\x7b\xf7\xc6\xfb\xe1\x0f\x47\xbe\xf6\xb2\xfe\x88\x71\x9d\x53\x94\x5e\x48\x8e\x9d\xf5\x33\xc1\xfd\x9e\xf8\x75\x4e\x51\xf3\x2f\x9f\xe9\xdf\x02\xab\x03\x4c\xc2\x16\xb6\x16\x8c\x46\x21\xb7\xc9\x61\x63\x41\x60\xe2\x33\x63\x9f\xc3\xa6\x9a\x38\xdf\xdb\x8d\xa7\x14\x19\x60\x62\x2b\xb5\x68\x3c\xb5\x36\x01\x72\x38\x01\xf8\xb2\x24\xe0\x0d\x14\xe0\x3d\x63\xc2\x03\x7f\x7a\x4f\xde\x8c\xc3\xee\x69\x33\xee\x69\x80\x82\xf7\x94\xe3\x0f\x6c\x8a\xa3\x27\x9c\x00\xee\xe7\x24\x44\x19\xe8\x82\x7b\x9e\x52\x84\x5b\xe9\xff\xb3\x7b\x72\x54\x36\xdf\xf3\x3d\xf8\xf9\x89\x0e\x78\xe5\x59\x5d\xa3\x43\xf6\xc2\x6f\x56\x0b\x24\xf8\x85\x52\xf1\x0b\xf0\x15\xc1\x97\xb2\x07\x1b\x24\x46\x1f\xe3\x85\x55\x47\xc1\x9e\xb3\xb0\x21\x02\xc6\x0b\xd6\x49\x9d\xd6\xd7\xbd\x72\xd6\x98\xb1\xb3\x67\x8d\x1d\x3b\x4b\xf8\xa4\xfb\xa8\x59\xb3\x46\x75\xbf\x74\xe6\xd5\x4c\x7e\xed\x00\xf9\xd5\xc8\x9e\xc7\x8e\xfe\xda\x00\xa3\x87\x42\xb2\x84\x59\xf5\xbd\x66\xb2\x86\x42\x49\x4f\x67\x77\x24\xdb\xb7\xad\xc3\x89\xcd\x4f\x44\x33\x04\x15\x7f\x6e\xfb\xef\x8d\x9f\x35\x1e\x66\xff\x10\x9e\x19\x64\x33\xc0\x83\x7d\xe2\x01\x42\x55\x73\x5c\x14\xd9\xf8\x73\x30\xf0\x3a\x26\xc2\x07\xef\xf3\x47\x52\x8b\xb4\x70\x86\x31\x77\x46\xc8\x89\x8f\x9b\x61\x75\x9e\x9b\x05\x4f\xcb\xeb\xa8\x42\xc8\xb8\x54\xf3\x75\x28\x5e\xc7\x68\x47\x1f\x75\x7a\xfb\x39\xdf\x03\x17\x80\x4d\xfc\x3e\x7b\xd6\xf8\x1f\x24\x5a\x4a\xf8\xa3\x1d\x59\xa7\x83\x6a\x0f\x63\xac\x08\x74\x78\x03\xa1\xa5\x36\x27\xb3\x8d\x71\x3c\x5c\x16\xdc\x4a\x62\x27\xfc\x61\xd6\x5d\xe2\x0b\xd5\xa7\x94\xda\x70\x5e\x5c\x45\x50\x15\xc0\xdc\xc4\x47\x41\x60\x1a\xd2\x9b\x03\x18\xcc\x10\xd0\x1c\xc8\xc8\xb2\x62\x0f\x7a\x54\xc8\xc0\x77\x02\x76\x0d\x48\x21\xb4\x91\x90\x47\x3a\x26\x3d\xf8\xda\x89\x0f\xbe\x76\x1a\x0f\xbe\xfe\xf5\x8b\x97\x2f\xe7\xcf\x90\x49\x61\x0f\xbe\x76\xe2\x83\x61\xf6\xfe\x7b\xd8\xfe\x6f\xf0\xc1\xd7\xaa\xdd\x55\xef\xb0\x3b\x3d\x60\x67\xb8\xea\x53\x5d\x29\x9e\x8a\x28\xbc\x4d\x7a\x5a\x32\x9c\x63\x4f\x4b\x76\xa4\xe2\x80\x50\xbb\x23\xd5\x95\xf4\xb4\xe4\x7c\x96\xfe\xe4\x63\xe7\x0b\x71\xf4\x7c\x8b\x27\x45\x1b\x23\xcb\xcc\x72\xf3\x68\x57\x52\x7b\xc1\xfa\xf5\xeb\x69\xd6\xb7\xdd\xae\xef\xeb\xe9\x3c\xbb\xcb\xfa\x5d\xf4\x47\xdd\x0b\x3f\x59\x82\xb4\x6b\x43\x64\x56\x8d\xa7\xcb\x82\x1e\xdf\xea\x5f\xd1\x2f\xb6\xae\xd8\x9a\xfa\x3f\xb4\xd0\x95\x7a\x9f\xcb\xf3\xf6\x6e\x05\xde\x9a\x56\xbd\xa5\x28\xdb\x52\x5d\x34\xf0\x3e\xb7\x89\x27\x8b\x9b\xa4\x71\xec\xf9\x44\x7e\x9c\x86\xca\x9a\x76\xac\xce\x70\x18\x67\x30\x78\x19\x43\xc4\xe7\xac\xe0\xf3\xcb\x2d\xa9\x9e\x50\x28\xc4\x66\xc2\xc8\xc0\x33\x4c\xb1\xb4\xfd\xe4\x22\x14\x33\xc0\x01\x0d\x7e\xae\x8a\xfc\xac\x7f\xa7\x21\xb5\x79\x6e\x8c\x0b\xdd\x11\x9b\xd3\x08\x85\x05\xd8\x84\x7d\xaa\x84\xc1\xc6\xc4\xd9\xc7\xa5\x62\xa1\x68\x56\x26\xd3\xc5\x77\x8e\xa1\x3d\xae\xdb\x21\x3f\x70\xf5\x15\xf2\xdd\xe1\x7b\x65\xd3\x98\x8b\x2e\xd2\x23\xf4\x75\x3d\x22\x64\xe8\x37\xd2\xdb\x62\xdf\xd2\x91\x82\xfe\x28\x9d\x2c\xe8\x7c\x3e\x0b\x06\x77\xba\x48\x5d\x60\x2f\xd5\xf2\x7d\xd4\x40\x6d\xa8\x64\x93\x8f\x8d\xe1\x14\x38\xf7\x03\xde\x19\x2f\x86\xa6\xe8\xa4\x04\x14\xbc\xc0\x89\x83\x1c\x3f\xd9\xb0\x41\xdf\x67\xcf\x1b\xc8\x22\xdf\xf2\x27\x0e\xa8\xe9\x3c\xd6\xac\x29\x19\xe1\xc4\x63\x07\x6c\x41\x4c\x2c\x38\xc2\xac\xfb\xd2\xcc\x3b\x56\xfe\xfc\xf9\x03\xc6\x68\x90\x7a\x97\x35\x2b\xa5\x82\x9b\xb0\x41\x8c\xd5\xa3\xc3\x16\xe7\x44\x9b\x15\x39\xd1\x6a\xe3\x9c\xf8\xe3\x90\x57\xb3\x39\x27\xda\x5c\xaa\x63\xbf\x6a\x75\xe1\x23\x8b\xfe\xf5\xf2\x2b\x63\x18\x27\x9a\x5d\xf5\x16\xb3\xd5\x83\xad\x8d\xc0\x67\xf8\xdc\x6e\x78\x9b\xc4\x89\x70\x8e\x71\xa2\xc5\x8e\x9c\x68\xb6\xd8\x1d\x89\x51\xb5\xe9\x3e\x3e\x73\xbf\xfd\x07\x20\x00\x79\x94\xec\x9d\xef\xbf\xd0\x6f\xc9\xa8\x82\xda\xf9\xbd\xae\x9f\xfc\xc1\x07\x8d\xc2\x79\x07\xc4\xc7\xd6\x5f\xff\xf4\xc1\xbc\xdc\xfb\x7d\xb9\x53\x66\x5c\xcf\x9e\x83\x70\x72\x14\xcf\x94\x08\xf8\xbc\x06\xa9\xd4\xc0\xdf\xb5\x2d\xf1\x97\xf4\xd0\x06\x30\x87\x32\xc2\xf5\x5e\xab\x0c\x58\x70\x1a\x0f\xb6\x3b\x3b\xec\xa5\xf3\xe4\x06\xf7\x70\x7d\xc6\x34\x85\xc4\x23\x1d\xce\x0c\x4b\xeb\x07\x3a\x08\xb7\xb4\xf5\x4c\x87\x93\xa3\xd8\x48\x7b\xe0\x28\x80\x45\xde\xcc\x60\x09\x92\x30\x0d\x71\x68\xb4\xca\x6a\x63\xae\x7d\xbd\x92\x51\xd6\xa9\xc8\xcf\x80\x8a\x7a\xd2\x2b\x60\xa7\xe0\x43\xe7\x80\x2d\x8a\xc3\xe8\xd8\xab\x79\xbc\x1a\xe8\xec\x00\xc3\x49\x6f\x99\x21\xad\x92\xcd\xfb\x8b\x56\x56\xe1\x67\x95\x15\xf0\xb5\xaa\x4a\x3c\xac\xc2\xd9\x3d\x95\xac\x48\xa0\xde\x15\x08\x03\xde\xaa\xed\xbc\x50\xc8\xce\x0a\x85\xe2\xdc\x53\x10\x40\xee\x09\x14\xb4\xe4\x9e\x14\x0c\xea\x16\xed\x37\x61\xed\x4c\x5e\x12\xfb\xe4\xb9\xea\xf3\xf3\x02\xc0\x3e\x45\xae\xfa\xc2\xa2\x02\x60\x1f\x78\x9b\xc4\x3e\x70\x0e\xd9\x27\x9a\x5f\x58\xc4\x66\x1d\xe7\xf1\x03\xce\x40\x55\x71\xf4\x6b\xd5\x95\xcc\xa1\x02\x32\x14\x9c\xd5\x93\x35\x02\xff\x05\x91\xa8\xde\x26\x07\xb6\xa6\x5a\xbb\x2c\x69\xd0\xf1\xfb\x38\x1d\xc9\xee\xd6\x74\x8c\x02\x1d\xc3\xe1\x16\x64\x04\x1a\x16\x70\x1a\xe6\x86\x34\xab\xa9\x49\x0b\x74\x0a\xfd\xff\x40\x4c\x7c\x64\x91\x41\xbf\x56\xd8\x64\x53\x5b\xc9\xff\x1b\x0c\x0a\x99\x67\xc5\xf7\xed\x6c\x84\xff\x0f\xcd\x46\xfa\xda\x00\x00\x00\x78\xda\x63\x60\x64\x60\x60\x00\xe2\x1d\x66\xdf\xfe\xc7\xf3\xdb\x7c\x65\x90\xe7\x60\x00\x81\xf3\xf5\x73\xce\xc2\xe8\xff\xcb\xfe\x09\xb2\x27\xb2\xf7\x00\xb9\x1c\x0c\x4c\x20\x51\x00\x85\x4d\x0d\xd3\x00\x00\x00\x78\xda\x63\x60\x64\x60\xe0\x28\xff\xbb\x16\x48\x32\xfc\x5f\xf6\x7f\x0d\x7b\x22\x03\x50\x04\x05\xbc\x02\x00\x95\x51\x06\xd6\x00\x78\xda\x6d\x93\x4b\x48\x54\x51\x18\xc7\xff\x73\xce\x77\xee\x0d\xa2\xd2\xb0\x16\x66\x11\x56\xf4\x00\xcd\x36\x39\x24\x36\xa2\x66\xb6\xd0\xc4\x36\xb3\x32\x74\x06\x47\xd4\x1e\x13\x92\x42\x41\x6a\x42\x3e\xa6\xb4\x17\x24\x14\x31\x4a\x0f\xb5\x50\x62\x2c\x6d\x21\x44\x2f\xa2\x68\x13\xb4\x28\x68\x51\x9b\x20\x89\x24\x5c\x99\x4d\xff\x7b\x9d\x62\x0c\x17\x3f\xfe\xdf\x39\xdf\xf9\xce\x39\xf7\xfb\xdf\xa3\xa6\x51\xbc\x0c\x80\x67\x7e\x01\xb5\x0e\x23\xea\x3a\x2a\xe4\x17\x4a\xa4\x0d\x27\xcc\x07\xd4\x31\x2e\xf0\x84\x50\xa1\xee\xa0\x43\x8d\xc2\xd2\x4d\xc8\x90\x6e\x94\x7b\xae\x20\x47\xed\xc2\x26\xb5\x19\x51\x5d\x89\x14\x69\x47\x98\x35\x8f\x49\x35\x09\x92\x5c\x72\x83\x74\x90\x32\x52\x4b\x0e\x29\x83\xa8\x5a\x81\x80\xa4\x60\x3f\xc7\xd7\x24\x07\x9d\xfa\x2d\xf2\xed\xed\x3c\x2f\x1b\x69\x66\x3d\x62\x26\x15\x27\xcd\x3e\xc4\xe4\x3e\x19\xe2\xb8\x09\x2d\x66\x1c\x31\x55\x84\x29\xa9\x47\xa1\xd9\xc2\xf9\x4a\xc4\x6c\x9b\xb9\x71\x37\x1f\x36\x1b\x13\x5a\xc6\xdc\x3c\xcf\x1a\x43\xa6\xa9\xc7\x65\xb3\x0a\x6b\xed\x54\xec\xa6\x16\xca\x67\xa4\xc9\x2b\x54\xab\x6d\xe8\xd5\xe5\xd8\x4a\x5d\xae\xfd\xc8\xd7\x83\x10\xd5\x86\x4a\xa9\x45\xbd\x44\xd0\x2b\x3e\x7e\x43\x04\x35\x92\x87\x80\x7a\x0a\x2f\xe3\xa0\x33\xaf\x04\x37\xd5\xea\xf8\x94\xa4\xa3\xcf\x89\xad\xdf\x5c\x1b\x71\xa9\x4e\x68\x8d\x9a\xa2\xee\xc4\x11\xf5\x0c\x99\x1c\xf7\x88\x85\x6c\x6b\x25\xb2\x1c\x25\xe9\xa4\x4a\x4d\xc0\xe7\x99\xc3\x28\x75\x8d\x39\x86\x56\xb7\xff\x73\xe8\x93\x1a\x34\xc8\x30\x4a\xcc\x18\xfb\xfe\x11\x1b\x3c\x3f\x71\x51\xbe\xa1\x4a\xcf\x63\xd8\x2a\x86\x5f\x5f\x45\x8b\x7e\xc1\x7b\x85\x71\xc6\xe9\xbd\x3b\xf7\x10\xa7\xd4\x1c\x5a\xe5\x00\x02\x3a\x88\x66\xdd\x88\xe3\xea\x02\xce\xf2\xec\x7e\xfd\x1d\x3e\x95\x81\x28\xf7\x6f\x56\x59\x38\xac\x6f\xb9\xf5\x47\xad\x3c\x4c\x58\xf7\xc8\x2c\x5a\xf5\x6c\xa2\xef\x4b\x60\xb7\xc7\xa7\x1d\x2f\x5c\x1f\x92\x50\x45\xf1\x4f\x8e\x17\xd4\x19\xf2\xda\x04\xb0\xe3\x9f\x0f\xff\x21\xa5\xf0\xbb\xb1\xe3\x45\x12\xae\x17\x93\x18\x94\xe7\xe8\x72\xfb\xbe\x04\xd6\x13\xec\x71\xbd\xa0\x0f\xc9\x28\x1d\x9f\x54\x1a\xfd\xd4\x37\xe4\xb6\x3c\x40\x69\x92\x0f\x8b\xb9\xc4\xff\x6c\x21\xee\x59\x84\xe3\xc5\x00\xfa\x1d\xb5\xef\xa2\xce\xde\xcb\x35\xbc\x93\x7e\x87\x11\x72\x8e\x7d\x82\x1d\x01\xfe\xaa\xea\xa0\x47\x5f\x48\xe1\x02\x98\xa1\xb6\x53\x1b\x98\x73\xde\x41\x02\xd3\x89\x21\xeb\x34\xce\x7b\x06\x50\xe1\x12\xe5\xdb\xf9\x4a\x7e\x90\xf7\xe4\x11\xba\x4c\x90\x9e\xb0\x56\x85\xd0\x48\xfc\xce\xbe\x52\x80\x83\x46\x10\x12\x2f\x63\xe7\x8d\xbd\x84\xd7\xce\x25\xdd\xf0\xfe\x01\x18\x6a\xd4\xaa\x00\x00\x00\x78\xda\x63\x60\x60\xd0\x81\xc2\x08\x86\x09\x8c\x25\x4c\x0c\x4c\x73\x98\x2d\x98\xe3\x98\x7b\x98\x77\x31\xbf\x61\xd1\x63\x09\x62\x29\x60\x99\xc0\xb2\x82\xe5\x0b\xab\x1c\x6b\x0b\x1b\x17\x5b\x18\xdb\x1b\xf6\x24\xf6\x3d\x1c\x2e\x1c\xbb\x38\x1e\x71\xf2\x70\xaa\x70\xba\x71\xc6\x70\x1e\xe1\x9a\xc2\x75\x8c\x5b\x87\x7b\x12\xf7\x05\x1e\x1e\x1e\x27\x9e\x2d\x3c\x6f\x78\xb9\x78\xfd\x78\x7b\x78\x37\xf1\x71\xf0\xb9\xf0\x4d\xe3\xbb\xc5\x6f\xc7\xbf\x4c\x40\x4d\x20\x4c\x60\x92\xc0\x2e\x41\x3f\xc1\x06\xc1\x0d\x82\xf7\x84\xb8\x84\x14\x84\x82\x84\x4a\x84\xfa\x84\xd6\x09\x9b\x08\xcf\x12\xfe\x27\x92\x21\x72\x4e\x54\x41\x74\x9e\xe8\x33\x31\x01\x31\x1f\xb1\x0e\xb1\x45\xe2\x7c\xe2\x61\xe2\x8b\x24\x58\x24\xb2\x24\x96\x48\x2a\x49\x56\x48\x1e\x91\xfc\x20\x15\x26\xd5\x26\x75\x42\xea\x9b\x74\x80\x74\x8e\xf4\x11\x19\x09\x20\xb4\x93\x59\x23\xab\x24\xbb\x4a\x8e\x4f\xce\x44\xee\x8d\xbc\x84\xfc\x01\x05\x1b\x85\x18\x85\x16\x85\x45\x8a\x51\x8a\x65\x8a\x87\x94\xf8\x94\xd2\x94\x5e\x28\xf3\x29\x27\x29\x4f\x53\xde\xa2\xfc\x41\x45\x4c\x25\x46\xa5\x4e\xe5\x97\x6a\x9f\x5a\x94\xda\x21\xb5\x7f\xea\x56\xea\x55\xea\x1f\x34\x7c\x34\x0e\x68\x6a\x68\xee\xd0\x62\xd2\xf2\xd0\x9a\xa6\xf5\x4e\x5b\x4a\xdb\x4d\xbb\x4c\x7b\x83\x8e\x80\x4e\x97\xce\x33\x5d\x17\xdd\x25\x7a\x06\x7a\x0b\xf4\x0e\xe9\x7b\xe8\x4f\xd0\xbf\x61\xa0\x64\x50\x65\xb0\xcd\x90\xc9\xb0\xc2\x88\xcf\x68\x89\xb1\x93\x09\x83\xc9\x0a\xd3\x0c\x33\x05\xb3\x55\xe6\x72\xe6\x13\x2c\xb8\x2c\x7a\x2c\xb6\x59\x3c\xb2\x14\xb2\xf4\xb1\xbc\x60\xe5\x67\xb5\xc2\x9a\xc5\x3a\xc3\xfa\x93\x4d\x82\xcd\x04\x5b\x21\xdb\x3c\xdb\x33\x76\x06\x76\xb3\xec\xde\xd8\x7b\xd9\xef\x70\xb0\x70\xb8\xe1\xa8\xe2\xe8\xe7\x38\x0d\x07\x5c\xe2\xb8\xc9\xf1\x80\xe3\x0d\xc7\x0f\x4e\x22\x4e\x16\x4e\x51\x4e\x53\x9c\xce\x39\x73\x38\x5b\x38\x17\x00\xe1\x14\xe7\x5d\xce\xbb\x5c\xca\x5c\xee\xb9\xb2\xb9\x2e\x73\xe3\x71\xfb\xe0\x3e\x01\x00\x72\x51\x8e\xd4\x00\x01\x00\x00\x00\xea\x00\x46\x00\x05\x00\x00\x00\x00\x00\x02\x00\x01\x00\x02\x00\x16\x00\x00\x01\x00\x01\x57\x00\x00\x00\x00\x78\xda\x7d\x52\xcb\x4e\xc2\x50\x10\x3d\x05\xd4\x10\x91\x18\x63\x5c\xb1\xe8\x8a\x15\x94\x82\xe8\xa2\x1a\xe3\x23\x62\x34\xc4\x18\x34\xca\xc2\x4d\x41\x04\xa2\x80\x29\x55\xe3\x3f\xf8\x21\x7e\x89\xd1\xad\xf1\x43\xfc\x04\x4f\xa7\x23\xd2\x2e\xc8\xcd\x4c\xcf\x3c\xef\xb9\x33\x05\xb0\x8c\x77\x24\x61\xa4\xd2\x00\x76\x28\x21\x36\x90\xa1\x15\xe2\x04\xb2\x38\x51\x9c\x44\x15\x4d\xc5\x29\xe4\xf0\xaa\x78\x0e\x05\xbc\x29\x9e\xa7\xff\x5b\xf1\x02\x76\xf1\xa3\x38\x8d\x8c\x61\x2b\x5e\xc4\xaa\xb1\xad\x38\x83\xbc\x71\xa6\x78\x09\xd7\xc6\x93\xe2\x2c\x2e\x8c\x2f\xc5\x2b\xc8\x25\xf2\x8a\x3f\xb0\x96\xd8\x57\xfc\x09\x3b\xd1\x44\x0d\x23\x0c\xe1\xc3\xc4\x0d\x5c\x7e\x5d\xa2\x36\x7d\x0f\x78\x81\x87\x3e\xba\xe8\x49\xf4\x88\xbe\x11\xad\x7b\x74\x68\x55\x60\xa3\x4c\xdd\xa0\xaf\x45\xf1\x29\x0d\x46\xba\x78\x64\x86\xcb\xca\xe9\x7c\x27\x92\x67\xc6\x32\x1d\xed\xb6\x3e\x33\xeb\x92\x96\x87\x31\x19\x05\x7c\x4d\xe6\x5b\x14\x5b\x2a\xab\x94\xad\x09\xab\x68\x9f\x62\xac\x4f\xf4\x8e\x3e\x3b\x9a\xf2\x66\x9f\x31\x97\x33\xe8\x60\x20\x79\x77\xf4\x8d\x70\x1b\x7b\xb9\x15\xb1\xa2\x91\x60\x6a\x03\x1c\x70\x5e\x9e\xf4\xf5\xa9\x5d\xe1\x1a\xde\x19\xf0\xf7\xe9\x0f\xf8\xd7\x19\x6b\xd3\x33\xa4\xdd\xe1\xad\x26\xf9\x0d\xe5\x76\x4f\xb8\xf4\x64\xca\x7b\xdc\x82\xcb\xbc\xd0\x8a\xd6\x14\xe8\x89\xcf\xa4\x42\x16\xb6\xec\xcb\x67\xa5\x83\x12\xcf\xb3\x1c\x8b\x7d\xfe\x7b\x59\xcc\xf7\xc8\xbb\x44\xe6\xd3\x3d\xc7\xf4\xd4\x71\xcc\x37\x1c\xe2\x14\xe7\xd4\x45\xed\x39\x6b\x33\x57\xb4\x5a\x9c\xd4\xdf\x7f\x54\x96\x8a\x9a\x4c\x21\x7c\x83\x27\xdc\x36\xa8\x83\xfd\x38\xd4\x15\xd1\x9b\x93\x9d\x55\x7f\x01\x3d\xf4\x7c\x3e\x00\x00\x00\x78\xda\x6d\xd0\x47\x4c\x93\x71\x18\xc7\xf1\xef\x03\xa5\x85\xb2\xf7\x06\xf7\x1e\xef\xfb\xb6\x65\xb8\x5b\xe0\x75\xef\xbd\x45\x81\xb6\x88\x80\xc5\xaa\xb8\x8d\xe0\xd6\x68\x4c\xbc\x69\x5c\x17\x35\xee\x19\x8d\x7a\x50\xe3\x5e\x71\x44\x3d\x78\x76\xc7\x83\x7a\xd5\x42\xff\xde\x7c\x2e\x9f\x3c\x4f\xf2\x3c\x79\xf2\x23\x82\xf6\xfa\x53\x4b\x15\xff\xab\xcf\x20\x11\x12\x49\x24\x16\xa2\xb0\x62\x23\x9a\x18\xec\xc4\x12\x47\x3c\x09\x24\x92\x44\x32\x29\xa4\x92\x46\x3a\x19\x64\x92\x45\x36\x39\xe4\x92\x47\x3e\x05\x14\xd2\x81\x8e\x74\xa2\x33\x5d\xe8\x4a\x37\xba\xd3\x83\x9e\xf4\xa2\x37\x7d\xe8\x4b\x3f\xfa\xa3\xa1\x63\xe0\xc0\x89\x8b\x22\x8a\x29\xa1\x94\x01\x0c\x64\x10\x83\x19\xc2\x50\x86\xe1\xc6\x43\x19\xe5\x54\x60\x32\x9c\x11\x8c\x64\x14\xa3\x19\xc3\x58\xc6\x31\x9e\x09\x4c\x64\x12\x93\x99\xc2\x54\xa6\x31\x9d\x19\xcc\x64\x16\xb3\x99\xc3\x5c\xe6\x31\x9f\x05\x54\x8a\x85\xa3\xb4\xd0\xca\x0d\xf6\xf3\x91\xcd\xec\x66\x07\x07\x38\xce\x31\x89\x62\x3b\xef\xd9\xc4\x3e\xb1\x8a\x8d\x5d\x12\xcd\x56\x6e\xf3\x41\x62\x38\xc8\x09\x7e\xf1\x93\xdf\x1c\xe1\x14\x0f\xb8\xc7\x69\x16\xb2\x88\x3d\xa1\xa4\x1e\x51\xcd\x7d\x1e\xf2\x8c\xc7\x3c\xe1\x29\x9f\xa8\xe1\x25\xcf\x79\xc1\x19\xbc\xfc\x60\x2f\x6f\x78\xc5\x6b\x7c\x7c\xe1\x1b\xdb\xa8\xc5\xcf\x62\x96\x50\x47\x3d\x87\x68\x60\x29\x8d\x04\x68\x22\xc8\x32\x96\xb3\x22\x94\xf2\x4a\x56\xd1\xcc\x6a\xd6\xb2\x86\xab\x1c\x66\x3d\xeb\xd8\xc0\x46\xbe\xf2\x9d\x6b\x9c\xe5\x1c\xd7\x79\xcb\x3b\xb1\x4b\xac\xc4\x49\xbc\x24\x48\xa2\x24\x49\xb2\xa4\x48\xaa\xa4\x49\xba\x64\x48\x26\xe7\xb9\xc0\x65\xae\x70\x87\x8b\x5c\xe2\x2e\x5b\x38\x29\x59\xdc\xe4\x96\x64\x4b\x0e\x3b\x25\x57\xf2\x24\x5f\x0a\xa4\xd0\xea\xad\x6b\x6e\xf4\xe9\xb6\x60\xbd\x5f\xd3\xb4\xf2\xb0\x6e\x4d\xa9\x7a\x8f\xa1\x74\x28\x5d\xca\xd2\x36\x8d\xd0\xa2\x52\x57\x1a\x4a\x87\xd2\xa9\x74\x29\x8b\x94\xc5\xca\x12\xe5\xbf\x7b\xee\xb0\xba\xba\xab\xeb\xf6\x1a\xbf\x37\x18\xa8\xae\xaa\x6c\xf2\x85\x47\x86\x19\xd6\x65\x5a\x2a\x82\x81\x86\xf6\xc6\x65\x96\xb5\x69\x7a\xc2\x7f\x84\x34\x94\x0e\xa5\xf3\x2f\x0f\x26\x9e\xe4\x00\x00\x78\xda\x3d\xcd\x2b\x0e\xc2\x40\x14\x85\xe1\x0e\xd3\x27\x7d\x97\x2a\x12\xd2\x69\x10\x88\x61\x03\x24\x48\x5a\x53\x43\x50\x9d\x84\x45\x20\x08\x1a\x83\x03\xd6\x72\x8b\x62\x77\x70\x02\xd3\x71\xe7\x3b\xe6\x7f\xb3\xcf\x8d\xd8\xc3\xea\xc8\xdf\xf7\x03\x63\x4f\x35\xb4\xae\xec\x6b\xca\x54\x47\xe5\x01\xe3\xaa\x16\xe4\xca\x63\x6f\x11\x17\x0d\x71\xb9\x23\x5b\x34\x2f\x7e\x9a\xc8\x1f\x1c\xc0\x1e\xe1\x02\xce\x59\xc3\x03\xdc\xad\x86\x0f\x78\x6b\x8d\x00\xf0\x85\xc6\x14\x08\xaa\x3f\x18\x85\xba\x11\xe1\x0d\x37\x13\x39\xf0\xf6\x02\xc6\x60\x34\x37\x4c\xc0\xf8\x6e\x98\x82\xc9\xd2\x30\x03\xd3\xda\x30\x07\x33\x61\x58\x80\x79\x65\x38\x03\x8b\xd5\x48\x45\xa5\xfc\x02\xfc\xb9\x4d\x56\x00\x00\x00\x01\x53\x59\xec\x4e\x00\x00\x01\x00\x00\xff\xff\x7d\x3f\x4c\xf6\xc0\x61\x00\x00") func fontsRobotoRegularWebfontWoffBytes() ([]byte, error) { return bindataRead( _fontsRobotoRegularWebfontWoff, "fonts/roboto-regular-webfont.woff", ) } func fontsRobotoRegularWebfontWoff() (*asset, error) { bytes, err := fontsRobotoRegularWebfontWoffBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "fonts/roboto-regular-webfont.woff", size: 25024, mode: os.FileMode(509), modTime: time.Unix(1492020681, 0)} a := &asset{bytes: bytes, info: info} return a, nil } var _fontsRobotoslabBoldWebfontEot = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x74\x90\x53\x70\x1d\x0e\xd4\xed\x4f\x92\x13\xeb\xc4\x27\xb6\x6d\x5b\x27\x6a\x6c\x9b\x8d\x1a\x27\x6d\x6c\xdb\xb6\x6d\x1b\x8d\xed\xc6\x8d\x1b\x36\x6a\x92\x3b\xf3\x9f\xef\xe1\x9b\x7b\xe7\xae\xa7\xdf\x9e\x35\x7b\xed\x59\x9b\xc4\x0c\x00\x18\x30\x01\x00\xa0\x01\xd0\x00\x20\xe0\x7f\x0b\x0a\xd0\x03\x0d\x00\x00\x01\x8a\x2a\x9f\xd0\x80\x3d\x7d\x32\x80\x0a\xd9\xff\x38\xf9\x50\x00\x32\x00\x00\x4a\xb9\x93\x16\x7a\x1b\xf0\xff\x08\x17\xa0\x06\x70\x02\x98\x01\x9c\x00\x6e\x00\x27\x00\x19\x40\x1d\xe0\x00\x30\x05\x98\x01\x00\x00\x04\x80\x04\xc0\x09\xe0\x00\xb0\x00\x00\x00\x15\x00\x2d\x80\x25\xc0\x15\xf0\x0d\x60\x0b\x70\x02\x38\x02\xc8\x00\xec\x00\x16\x00\x3b\x80\x0d\xc0\x06\xe0\x00\xf0\x00\x38\x01\x82\x00\x32\x00\x07\x80\x0d\xc0\xfe\x3f\xec\x06\x70\x03\x58\x01\x4c\x01\xee\xff\xe5\xda\x00\x6c\x01\x8e\x00\x37\x00\x19\x80\x0e\xe0\x01\x60\x03\xb0\x00\xf8\x01\x5c\x00\x96\xff\x36\x98\x01\xec\x00\x73\x00\x2f\x80\x0b\x40\x0f\x20\x03\x30\x03\x1c\x00\x64\x00\xbe\xff\xc8\xf5\xbf\x3b\x1c\xff\xb1\xec\xff\xe4\xb3\xfd\x37\x79\xfd\xe7\x70\xfd\xc7\x9e\x00\x32\x00\x05\x80\xe2\x3f\xd6\x06\x00\x00\x64\xff\x9f\x46\x64\xff\xab\x0f\x00\x20\xa1\x2e\xab\xf2\x7f\xff\x02\x06\x10\xb2\x0d\xe0\x7f\x05\x08\x00\x00\x5c\x8e\x98\x33\x67\x51\x13\x5e\x7a\xda\x93\x36\xfa\x2e\xf2\xfe\x5e\x14\xe6\x5d\xae\x4c\xd6\x4c\xd2\x4f\x34\x4f\xb0\x92\x41\xdb\x04\x23\x7d\x51\x7f\x1f\xfe\xa5\x20\xd4\x8b\xe5\x7d\xae\x57\x0c\xe0\xeb\x82\xfb\x51\x21\x6b\x2a\x36\x0e\x2a\x35\x38\x6d\x19\xd2\xe3\x8a\x32\x4a\x5d\xa6\x46\x59\x04\xd8\xc4\xd6\x85\xf9\x3c\x22\xc6\xff\xce\x59\xfa\xa4\x2b\x46\xe6\x4f\x35\xce\x38\x32\x83\x60\x4b\xa6\xcf\x6d\x8d\x3e\x18\xfa\xcc\x66\xd6\x6f\x35\x5d\x8e\x32\x17\x2b\x78\x3b\xeb\x7d\xd2\xbc\x02\x0f\xa3\x6e\x51\x8b\xf5\x28\x87\xb4\xf8\xaf\x5c\x0f\x03\xeb\x26\x68\x4e\xa3\x62\x1a\xbe\x20\x6b\xea\x80\xf5\x0c\xf8\x87\x60\x60\xd8\x94\xbf\x45\xb6\x2b\xb9\x6a\x11\x93\x9e\xb8\x8a\x7f\x9b\xeb\xb3\xad\xe1\x5a\x10\xea\x45\x64\xca\xfd\x51\x6d\x51\xda\xdf\x34\x41\x2b\x2f\x12\x08\xa5\x3f\x89\x3e\x84\x05\xca\x9c\x3a\x5e\x5f\x7b\xd4\x8d\xda\x5d\xf8\x27\x3c\x62\x23\x61\x6a\x37\xc3\xc5\x23\x17\x76\xa3\xc8\xc0\x20\x16\x67\xb6\x21\xd7\x4c\xe3\x1a\xd3\xcd\x89\x8c\x0c\x85\x8f\x7f\xeb\xb7\x1d\x41\x47\x6b\x9c\x98\x44\xa8\x2c\xa5\x7c\x7a\x35\x5a\xcc\xb9\xf6\xd5\xd7\x45\x9e\x18\x51\x7f\xf6\xc7\x78\x39\x87\xb7\xf0\xc7\x2f\x58\x67\xd3\x73\xe2\xd4\x74\x2c\x01\x8f\x4a\x1d\x8f\xc8\xe4\xd2\x1f\x2c\x88\xe4\x54\xc9\x7f\x16\xc3\x31\xc1\xc6\x37\xc5\xf5\x08\x15\x96\x3d\xf2\x24\xb3\x78\xce\x43\x12\x09\xa4\x97\x20\xdd\xaa\xb9\x2f\xb3\x7b\x5a\x8e\xf0\xab\x75\xc0\xcc\xce\x7d\xb4\xa8\xc3\x16\xd2\x9c\x89\xea\xd5\xa8\x71\x12\xfa\x78\xaa\x9d\x63\xf4\x75\x36\x1e\xab\x57\xd7\x49\x39\x09\xbf\x10\x19\x76\xc4\xb2\xda\x15\x8d\x0c\xbc\xc5\x1f\x70\x02\x16\xe5\xab\x32\x89\x50\x74\x4f\xe6\x9a\xf0\xa7\x5c\x09\xbe\x68\x5c\xf5\x2d\x31\x93\xe9\x44\x0a\xfa\x31\xaf\x70\xaf\xe4\x89\x4b\xd8\x77\xe6\x5d\xf0\xbe\x52\xf8\xa2\xae\x01\x04\x76\xf2\x08\xf4\xe4\xbe\x12\x73\x6d\x5f\x33\x1c\x5d\xe2\x5c\x86\x5c\x4c\x8e\x51\x46\x21\x2a\x72\xc7\x3e\x9c\xc7\xb3\x09\xbe\x8d\x81\x50\x2e\x51\xa8\x19\x08\x19\xd7\x60\xf0\x34\x50\x0b\x44\x1f\x98\xde\xb0\xda\xec\x6f\xe9\x3a\x18\x37\x66\x0f\x95\x41\xc1\x42\x11\x50\x93\x17\x09\xb6\x60\xa1\x8d\x92\xf6\xd2\xf3\xb1\xed\x1c\x19\x8a\x40\xdb\x91\x74\x67\xe4\xaa\x11\xe8\xe7\xc0\xaf\xcf\xf5\x39\xbe\x58\xb5\xb1\xf0\x57\x1b\xe8\xd4\x42\x41\xbb\x41\x2a\xf5\xd6\x34\x25\x18\xb1\x41\x4b\xc1\x50\x3c\x3a\x2d\x2a\x69\xe2\x4f\x13\xa9\x39\x69\x3f\xce\xc5\x75\x97\x5b\x17\xed\x2a\x88\x31\x46\xa8\x33\x0b\x58\x43\x54\x4b\xe7\xb8\x6f\xd8\x31\xd3\x8c\x2c\x23\x1c\x22\x12\xda\x45\x4c\xc2\x86\x1d\xa0\xd4\xe5\x9f\x56\x4e\x78\x9a\x63\xfb\x17\x1c\x86\xeb\x34\x36\x97\x75\x88\x45\x30\xc1\x48\x75\x18\x61\xf0\x82\x25\xc0\xd9\x41\x9a\xae\x2f\x15\xf1\x37\xc1\x0f\x25\x81\xcc\x12\x05\x85\x13\x46\x40\x14\x0f\xcf\x6d\xbb\x6c\x2b\xfc\x9b\xcf\x22\xa8\x7a\x10\x33\xc0\x82\x9c\x1c\xd3\x6c\xab\x72\xf7\x36\x83\x18\x19\x24\x80\xd4\x70\x8a\xeb\x17\x71\xcc\x37\x91\xcd\x5f\x4b\xd9\x91\xc8\x45\xe1\x0b\x99\xc0\xa4\x5f\xb1\x8a\xde\x0d\xf9\xf6\xc3\x23\x8d\xc1\xa0\xbd\x54\x09\x0d\x0f\xba\x48\xb0\x52\x93\x1a\x89\xa1\xc1\xde\x74\x7b\xdf\x01\xb6\xf8\x56\xe4\xe1\xef\xe1\xf7\x7f\x72\x26\x82\x40\x8f\x2e\x8a\x9e\xa3\xe8\x8e\xed\x10\x3e\x19\x0b\xb0\xa5\x95\xb8\xc9\x66\xe5\x59\xc6\x60\x54\x66\x4c\x87\x62\x66\x0e\xa9\x2b\x8d\x0d\xe9\xb4\xe2\xb4\x7d\xe1\x9f\xe0\xf8\x02\x62\xd0\x19\xdc\x11\xa3\x18\x2a\x29\x97\x0b\x33\x69\x0c\xe6\xdf\x8c\x96\x99\xb2\x5a\x5e\x7f\xdc\xbc\x96\xf7\x3f\x8b\x11\x24\xac\xaa\xcb\xa8\xcc\xb6\xf5\x8a\x8f\x9c\xf7\x8c\x32\x55\x30\xb3\xe9\x6e\xb5\x03\xc3\x67\xfb\x60\xf0\x67\xd7\xd5\x24\x85\x2c\xd7\xc3\x1c\x4f\x5a\xfc\xfd\xa2\x99\x9d\x2e\x8e\xed\xb0\x4f\x0d\xa5\x30\x17\xba\x45\x01\xba\xc1\x2c\x16\xb1\x1c\x18\x31\x90\xfd\x8d\x11\xc8\x03\x35\x98\x48\x39\xca\xad\x68\x57\x44\x66\x37\x22\xe4\x4e\x3d\xc1\xce\x8a\x6a\x89\x66\x08\x78\x31\xa6\x82\x9d\xee\xc0\x34\x8e\xea\x86\x93\x80\x28\xb0\xb8\xc8\xe7\x20\x9c\xdd\x93\x2b\x52\x41\x8a\xa7\x47\xd9\x1e\x93\x38\xc5\x68\x04\x8f\x62\x81\x08\xb6\x28\x1f\x0f\xe4\x34\x7c\xef\x04\x74\x3e\x4c\x3e\x48\x64\xae\x4c\x94\x65\x18\xb7\x08\xec\xcd\x81\x68\x45\x49\x4c\x7b\xe6\x19\x29\x51\x1d\xec\x1b\x5f\x53\x22\x8f\x24\x75\x90\xc4\x3a\x02\xa5\x33\x15\x58\x8d\xed\x59\x2b\x7a\x55\xe9\xfa\x8a\x1e\x30\xcf\xb1\xe6\x51\x39\xd8\xdd\xc5\x6c\x17\xa2\xa3\x3e\x70\xc0\x6d\xf5\xe6\x18\xd1\x76\x57\x3d\x81\x7a\xda\xcc\x0f\x48\xae\x9d\x8e\x05\x58\xa9\xdd\x43\xaf\x2e\x7d\x0b\xa2\x8e\xbc\x9b\xac\x3b\x56\x5b\x0a\x4f\xba\x6d\x97\x2f\x35\x1b\x1e\x39\x5c\xd9\x2c\xda\x61\xdf\x2c\x67\xf6\x73\x36\xec\x9c\x67\x6d\x5a\x95\x3a\x67\x70\xab\xdb\xd9\x8b\x56\xaf\xa6\x6d\x3a\xb8\x4f\x38\xb7\x69\x72\xc6\x7c\x43\x97\x42\xe6\x5c\xdc\xf6\x39\x77\xb8\xf6\xd9\x0d\x95\xc0\x8a\xda\xda\x32\x58\x38\x5b\xc5\x50\x51\x99\xc5\x50\x51\x59\xe6\x03\xa6\x65\x1d\x7b\x20\x5b\x1b\xcf\x04\x1b\xd0\x1f\xb2\x79\x88\x67\x02\x1d\x13\xe3\xef\x76\xcc\x76\xc9\x42\x23\xb1\xc2\x1e\x6d\x10\xdd\x1c\x0e\x15\x12\xd7\xcd\xa2\x58\xb1\x21\x2a\x15\x92\x68\x61\x49\x5f\x84\x8d\x6d\x42\xee\x89\x26\xc6\x9e\x35\x43\x91\x3d\xca\xb1\x86\xa2\x49\x4e\x55\xb6\x60\x4e\x55\xd6\xce\xac\xa6\xd2\xda\xb7\x71\x45\x58\xf0\x6e\x10\xd8\xff\x59\xf4\x2e\x78\xd7\x4f\x84\x3a\x00\xca\xfd\x5c\x27\xe7\x90\x18\x8b\x48\x20\xb7\x29\xdc\x1d\xd0\x10\xe6\xc8\x41\x0c\x30\xae\x2d\x1e\xb9\x38\x11\xfc\xa5\x56\x49\xc3\xee\xea\x97\x73\xf6\xe1\x73\x76\xe9\x05\x07\x9c\x07\xf0\x4b\xd7\x6f\x71\x04\xd5\x2f\xa5\x8b\x6b\x5f\x1f\xcf\xaa\xbf\x65\x7e\x4b\x79\xde\xf8\x96\xf2\x9c\x53\x39\xe5\xe7\xc9\x60\x96\x4f\x34\x95\x51\x7e\x37\x95\x52\x7e\x73\x2c\xaf\x7a\x58\xac\x96\xe2\x15\xb1\x5c\x4a\x02\x9a\x6e\x55\x5d\x22\xbc\x81\x3d\x74\x83\x4d\xae\xee\x46\xcb\xcd\x15\x6c\xd6\x9a\x7c\x49\x3e\x51\xbe\xcc\xcb\x2c\xf5\xdc\x97\xfe\x93\x9a\x90\xa9\x92\xab\xb1\x59\xed\xf9\xfb\xe2\x4e\x52\xe2\x5e\xfa\xd4\x66\x7d\xa1\xb3\x7a\xfb\x1f\x75\x29\x9d\x9b\x93\xdf\x3c\x62\xe5\xa1\x2c\x90\x4b\x48\x81\x4b\x91\x4b\x89\x4b\x85\xeb\x8b\x3d\xaa\x3b\xcb\xa8\x40\x03\x45\x73\x1a\x14\x77\x5a\x01\x59\xb6\x2b\xc2\xec\xdf\x80\x3e\x73\x5e\xed\xe0\x50\x47\xec\x94\xcc\xab\x81\x34\x36\xce\xe7\x5f\xcf\xf0\xb7\xd0\x46\x40\x09\x10\x24\x62\xf1\xd6\x19\xf3\x76\x00\x58\x76\x60\xf2\x26\x38\x88\x08\xf7\x51\x6c\x17\x46\xb7\xb1\x8b\x44\x33\x03\xb7\x07\xf9\x9b\x11\xd5\x38\xa9\x83\x79\x13\x82\x62\xf3\x1d\x74\x88\xd5\x4a\xbd\x97\x1b\x6b\xf0\x42\xb7\x1a\x76\x4a\xf6\xa3\x64\x02\xed\xe0\x63\xf4\xd4\xbe\x73\x00\x52\x03\x24\x33\x85\xf5\xe6\xce\x22\xb5\x51\x9a\x4f\x4f\x71\xd2\x83\xc9\x9b\xcb\x92\x1f\xe5\xad\x84\xeb\x4e\xda\xdc\x1a\x0a\xf3\x0f\x58\xd7\xf1\x72\xfb\x42\x0c\xbd\x19\x60\xe7\x33\xe6\x26\x88\x1a\x81\xb4\xfc\x56\x40\x54\x34\x11\x79\x49\xd0\x85\xca\x8d\x30\x49\xe1\x59\x68\xb7\x20\x3b\x2d\xbe\x19\x87\xab\xcc\xd4\xe5\x9c\x60\x2d\x23\xc7\xaf\x4e\x61\x53\x2e\x8d\x33\x79\x56\x05\x1c\x66\x5a\x00\x93\x0b\x07\xd0\x16\xde\xc2\x9d\x60\xf9\x37\xfc\xc0\x0d\x11\x2d\xf3\xca\x9a\x0c\x08\xb5\x79\x09\x3e\x1c\x14\xa8\x48\x8a\x63\x6a\xcf\x67\x31\x8f\x1d\x95\x71\xc7\x77\xe2\xa0\x3a\x8f\xc5\x0e\x41\x9e\xb8\x6f\x0d\x0c\x2d\xae\x50\xb3\xd5\x02\xb3\x0b\x9a\xee\x8b\x85\x88\xa1\x43\xaa\x04\x86\x9c\xf5\x2b\x98\xd8\x09\x16\x4b\x03\xf9\x62\x6f\x0e\x2a\xbb\x74\x2a\xb2\x8c\xdd\xe7\x23\xd4\xb2\xb1\x05\x47\x05\xf6\x9d\xbf\x45\xa2\xd9\x06\xee\x6c\x40\x13\xd7\x85\x6a\x96\x0d\x66\x06\x2f\xa1\x6f\x22\x90\x1b\xec\x71\xd2\x72\x4c\x1e\xa7\xd1\x61\x07\xf1\x00\xde\x43\x63\x62\x0f\x97\x69\xc8\x70\x5c\x64\x76\xd1\xb5\xde\xd1\x19\xc2\x3d\x8c\xfc\x55\xf4\x91\xd5\x1e\xa1\x67\xa0\x11\x53\xe8\x0c\xc2\xb0\xf9\xf5\x5e\x47\x4c\x35\x98\x00\x34\x83\x84\xc3\xd1\x0a\xec\x57\xdb\x2a\xc1\x75\xdb\x55\x6f\x40\xfa\x1c\x0e\x6a\x7d\x74\x1b\x44\x05\x43\x94\x67\x41\xec\xb0\xa0\xaa\x96\x43\xf9\xd2\xd7\x12\x55\x9e\x09\xa6\xc6\xa5\x50\x7b\x82\xca\x37\xa4\xc0\x42\x42\xfc\x73\x9d\x8c\xaa\x49\xd1\x23\x45\xd9\xc4\x93\x94\x4b\x40\xec\xc0\x81\x9c\x5a\x19\x06\xf9\xb4\x32\xd1\x0c\xfd\x10\x57\xa6\xad\x96\x29\x7d\x6c\x17\x99\x66\x72\x80\x58\x04\xc6\x58\x0c\x4f\xa7\x9d\x6d\x88\x64\x98\x69\x57\x54\x98\x27\x19\xfd\x0e\x48\x21\x3b\x9f\x29\xbe\x4c\x44\x90\x28\x07\xa3\xc8\x82\x57\x92\x0d\x4a\x95\x0d\xa1\x98\x5b\xe2\xab\x06\x86\x6a\x33\xca\xd0\xb5\x58\x15\x47\x94\xe6\x34\x9d\x93\xfb\xfd\x3c\xd8\xcd\x39\x0d\xb1\x83\xe6\x5a\x37\x51\x72\x1f\x3b\x11\x67\x5d\xb1\x78\x3c\x5c\x7e\x28\x30\x7b\xcc\x52\x54\x8e\xfa\xeb\x0d\xf4\xe3\xe6\x67\x6a\x40\x6e\x54\xe6\x8c\x9e\xc0\xe3\x02\x9d\x9d\xf4\x53\xeb\x31\xb2\xf6\x96\x14\x46\x7f\xa5\x97\x23\xe3\xf9\x0f\x68\x42\x65\xf5\x05\x4d\x4b\xe1\x38\x54\xf5\x24\x2f\x05\x18\xd9\x7d\x8f\xbc\xb3\xcc\x18\x71\x27\xa7\x0a\x97\x8d\x21\x6f\x39\x95\x6f\x9d\x41\x19\xc6\x35\x73\x11\x1c\xaf\xb3\x8e\xa0\xbe\x13\x22\x40\x32\x50\xbf\x6e\xb9\x9e\xe0\x72\x0f\xc3\x20\xb2\x6e\x24\x47\xcb\x7c\x0c\x2b\x5e\x46\x3e\xb1\xe3\x67\xe6\x19\xf8\x93\xc5\x3a\x21\xaf\xf3\x9b\x10\x70\x56\x5a\xf1\x06\x59\xb2\x63\x32\x5d\x8f\x2e\x68\x2a\xe3\x5c\x88\xe5\xa8\x7e\xdf\x62\x5a\xd3\x02\x8e\x69\x54\xc8\xc9\xc5\x8a\x0b\xcb\xcf\x64\xda\x86\xc2\xeb\xba\x6e\x97\xcd\x8a\xaa\xbc\x31\x5a\x8a\x58\xcc\x20\x33\x95\xce\x43\x63\xa2\x4d\xe0\xd2\x6c\xbd\x8e\xf7\xa6\xfb\x57\xa7\xca\x8e\xe3\x94\x0c\x94\x4e\x1a\x6b\xa8\xb3\xce\xfb\x14\xa4\x1c\xb7\x03\x42\x72\x46\x15\x10\xa8\x7f\x76\x06\xad\x9c\xd8\x96\x98\x92\x72\xf2\x30\x05\x5b\x5e\xa6\xb9\xfa\xa3\xee\xe9\x70\x5f\xb6\xe1\x06\x59\xf7\x98\x95\x1e\xaa\xf0\x28\xe8\xfb\x6c\x1e\xf6\x57\xb4\x2a\x25\xc7\x7b\x3c\xea\xcc\xca\x54\xb5\x58\x94\xea\xc1\x61\x06\xb5\x42\x81\x62\x98\x90\x98\x76\x05\x84\x6b\xb7\xb6\x44\xcf\x1c\xdb\xca\xe7\xe3\xa0\xe4\xdb\x0a\x7d\x4d\x8b\x7c\x1d\x39\x51\x1b\xa5\xc1\x0e\x34\x3a\x6c\xa1\x2d\xe8\xd0\x56\x48\x81\x2a\x2f\x36\x42\x19\x45\x78\xc9\xb4\x66\x5f\x47\x35\xcb\x2d\x69\xf1\x05\x45\xb4\xd1\x93\xe9\x6b\xc3\x44\xb4\x59\x25\xdc\x93\x76\xe2\x5b\x56\x3e\x69\x0b\x38\xc4\x16\x6b\x02\x2e\xc2\x44\xc8\x26\x65\x3e\x96\x9e\xbe\xb1\x14\x56\x5d\xe2\x87\xf5\x5c\x1f\x03\x39\xf0\x94\x66\x24\x19\xb7\x06\x89\x54\x47\xca\x89\x64\x9a\x4e\xf6\x2a\x0a\x6a\x64\xac\x60\xd2\x90\x86\x32\xb3\x2e\xa1\xc2\x9d\xaf\x4e\x67\x61\xc6\xb4\x95\x68\x90\x83\x32\x75\x15\xd5\x0a\x81\xd4\xdf\x01\x16\xcc\x15\xe4\x16\x2c\xc5\xbc\xb7\x98\xd5\x60\xc3\xad\xc3\x85\x2b\xd9\x14\xbd\xb7\xc8\x53\x4c\x20\xf4\x4a\xa0\x54\x2f\xe9\xd2\x24\x53\xaf\xa7\x4b\xbc\xc3\x6c\x24\xa1\x98\xd0\x4a\x4b\xab\xa6\x94\x88\x19\x5a\x0c\x3e\x13\xb2\x56\x33\xe1\x2f\xaa\x6a\xc4\x25\xc5\x28\xa0\x2c\x43\x42\x78\x25\x8b\x53\x73\x92\x9a\xe8\xa2\x37\x69\x68\x91\x86\xfb\x32\x6d\x79\xd7\x0c\x6a\xc4\x02\xf9\x17\xa9\x20\x57\x94\xd0\x2a\x56\x5c\x90\x63\x29\xd9\xd3\xe1\x54\x48\x0c\xcd\x33\x95\xf8\x82\x34\xc6\x68\xdc\x37\x88\x1d\x6a\x68\xd3\x8c\x17\x04\x18\xc1\x8c\x2c\xa2\x6c\xd3\xb4\xe9\x19\x16\x25\x07\xf7\x35\x92\xed\xa1\x9d\xd2\xa9\xdc\x0e\x63\xf6\x53\x43\x12\xc7\xb3\x2c\xcc\xce\xdb\x62\xf5\x74\xdf\x02\x91\xbf\x23\x9a\xdc\xb9\x10\xdc\xf3\x09\xe6\x5a\xb5\x7d\x48\x80\x49\x98\x1b\x00\xf3\x2d\xeb\xfb\xf3\x78\xeb\xe0\x18\x35\x13\x2c\xed\x26\x41\x53\x28\xfe\x73\x1a\x4e\xd8\xd0\x68\xf1\x19\x27\xbc\x1d\x96\xd8\xc4\x18\xc4\x03\xa5\x69\x13\x57\xca\x17\x70\xc7\x73\xee\x1e\x1d\xdd\x62\xda\x2c\x37\xaa\x45\x69\xe4\x40\x84\x78\xa9\x04\x82\x81\x9b\x27\x7e\xee\xcb\x20\x4d\x15\xe3\x29\xf2\xa8\x00\xf6\xad\x4e\xec\xcb\x94\xce\xba\x22\xbc\xd7\x47\x28\x22\x5c\x93\x1e\xd9\x3c\xa8\x00\xee\x31\x45\xc6\x45\x2d\x3f\x72\x04\xdb\x32\x52\x71\x4a\x7a\x5d\xcf\x42\x1b\x25\x64\x1e\xd9\x39\xe3\xfc\xc0\x1a\x0e\x6a\xc6\x3e\xa1\x53\x62\x12\x6b\x42\xc4\x29\x8e\xc5\x99\xf3\x37\x3c\xd1\x8e\xcc\xd1\x34\x44\xad\xa5\x41\x7a\xfa\xdb\x22\x3a\xd9\xa6\xa8\x04\x81\x9a\x8a\x37\xe1\x23\x63\x96\x6d\x51\x58\xb9\xc2\xa4\x93\xe6\x79\x7f\x2f\xfb\x93\x1d\x1f\x65\x09\xe6\xe7\x5d\x48\x23\x35\x4f\xab\x0a\x06\xae\x49\x24\x25\x56\xf0\xc7\xef\xcc\xad\x6e\x65\xe1\x8f\xaa\xe4\x23\xb2\x66\x2b\x43\xc3\x8c\xf3\x71\x9a\x3a\x0a\x6c\x09\x77\xa3\x8e\xda\x21\xe7\x46\x3c\x82\xe2\x71\x27\x5e\x22\x92\xf7\xba\x31\xf4\xa2\xf3\x5e\x7b\x1f\xc3\x13\x98\xb6\x17\xde\xc4\xa1\xbd\x76\x9b\x53\xa3\x72\xd3\xe8\x50\x9c\x63\xb3\x3d\xb0\x54\x93\xa9\x65\x40\x15\x09\x93\xf4\x11\xd1\x70\x30\x2d\x1d\xdc\xde\xc2\xbb\xd5\xa4\x61\x32\xd7\xcb\xc2\xac\x91\x89\x20\x14\x99\x8b\xd4\x02\xab\x0f\xf1\x41\x4b\x64\xa6\x18\x2f\x57\x27\xb6\x11\x94\xe2\xb6\xfc\x69\x4c\x8f\xb6\xd8\x01\x7b\xf2\xf7\x4d\x11\xc4\xba\x46\x26\x40\x0a\x38\xb0\x79\x6b\x44\xb4\xe5\xf6\xaf\xf9\x6f\x7a\x22\x68\x34\x59\x89\x0f\x98\xdf\x72\xbd\x66\x70\x4c\xf2\xbb\xab\x7b\x3f\x99\xc9\x7f\x73\xe0\x2a\x5b\x25\xdd\x39\x78\xfc\xda\x5e\x48\x26\xf7\x8a\x93\x4c\xfe\x48\x22\x3c\x83\xfc\xf8\xd5\x90\x4e\xab\xf6\xbd\x92\x91\x3b\x4a\x96\xbb\xb1\x0f\xb6\xff\xf8\x1c\x73\x71\xd9\xfe\xa3\xcc\x03\x9d\xa6\x43\x54\x37\x6a\x6f\x98\xa7\x38\x9a\x35\x11\x0e\x33\x32\x91\x70\x0f\x6b\x20\x18\x73\x9b\x36\x64\x8b\xae\x85\x8b\x7e\x6f\x3e\xef\x85\xc6\x28\x09\xc2\x61\x72\xd5\xf6\x38\xb1\x78\x72\xba\x6a\xdd\x4a\x9a\x55\xec\x0c\x0a\xac\x82\x83\xb3\x99\x51\xe7\x26\xcf\x9e\xfc\x18\xfd\x57\xb5\xbe\x57\x21\x34\x18\x28\x65\x19\xe0\x22\x0f\x28\x1c\xd4\xac\x85\xb8\x31\x06\x72\xd8\x48\x8b\xdb\xeb\x60\xcf\xed\x3a\x58\x35\xf3\x73\xd1\x79\x9d\xe5\x99\xb2\x0d\xbd\x5a\x61\xab\xe4\xf4\x4f\x25\x54\x14\xc1\xc8\xdc\x54\x22\x18\x72\x2d\x60\x75\x20\x5d\xdf\x98\x30\x4a\xfa\x8b\x5d\x4c\x5d\x31\x6a\xac\x60\x1e\xcc\xa0\xbb\xf4\x0e\x19\xd1\x78\x89\x31\x05\xae\x87\x78\xaf\x65\x56\xfd\x74\x1d\xd1\x39\x92\x47\xa9\x0a\x54\x62\x6b\x73\x9d\xef\xb0\xb5\x84\x55\xe1\xe1\x71\x66\x78\xcd\xa6\x13\x47\x14\x60\x72\xe5\x50\xf5\x11\x33\x15\x70\x24\xab\x5b\xf8\xad\x96\x3d\xf2\xe3\x47\x2b\x88\x69\x81\x34\x5c\xbd\xcc\x9d\xe5\x0e\x35\x85\x9a\x4b\xdd\x26\x49\x7d\x60\x23\x56\x0a\xc1\x67\x14\xe0\xb8\x20\xad\xb3\xed\x64\x00\x6d\x1e\x48\x15\x30\x5a\x79\xb1\x98\xe7\x8f\x73\xa3\xe6\x71\x23\x36\x9d\x16\x81\x52\x44\x1f\x88\x98\x0d\x7a\xae\x2f\x4e\x9c\x9d\x06\xc3\xc7\x5a\x6c\x72\xf7\x5f\x7e\x13\xe8\x84\x3e\x22\x2c\x77\x3f\x0b\x6a\xe7\x05\x07\x3a\x93\xc3\x4d\x62\x58\xe7\x5b\xf1\x0c\xe3\xa4\x69\x08\xd4\x49\x9b\x95\xd7\x2d\x1c\xa3\xcc\xf8\x10\xd8\x0d\x2d\x29\xee\xf7\xca\x11\xa5\x23\xa9\x47\x96\x3b\x7f\x4e\x44\xe6\x2a\x67\x6c\xc3\x54\x92\x82\x45\xa2\x13\x22\x6e\xa5\xce\x9a\x0f\xf7\x52\xe1\x93\x64\x5b\x60\x0f\x0b\x82\xbf\x9c\x88\xe8\xcf\xfe\x44\x2c\x70\x8e\x61\x76\xa1\xf0\x28\xcb\xc6\x18\x54\xe9\xf2\xc6\xe8\x93\x0b\xb5\x9b\xaa\x1e\x54\x9f\x0a\x1f\x71\xd1\x10\x4e\x26\x49\x9d\x24\x46\xb9\x34\x0f\xa0\xa6\x66\xc5\x93\xc8\xc7\x20\x77\xa4\x8b\x08\x3d\xc3\x21\x26\x1a\xbd\x95\x0d\x28\x51\x54\x41\xb9\x52\x17\xd3\xa2\x90\x40\xc0\x16\x19\xcd\x34\x90\xb4\x69\x41\xa9\xeb\x45\x3e\x54\x23\xd7\x62\xa3\xba\x94\xc3\x5a\xa6\x22\x3c\x42\xbf\x97\xb2\x99\x6a\x64\x85\x09\x92\xa4\x93\x38\x87\x4d\x62\xc4\x09\x45\x3f\xa2\x9c\x24\x3a\x70\xa3\xec\x70\xd1\xc2\x87\xe6\x57\xb7\xd2\x24\xa1\x46\x38\x14\xb4\x0c\xee\x49\x59\x08\x54\xac\x5f\x70\x0c\x90\xc0\xd5\x61\x47\x8d\xd4\x0b\x4d\xd1\x4a\x14\x5b\xdd\x1c\x41\x61\x03\x11\x51\x80\x7e\xba\xf6\x01\x42\x50\xca\x76\xed\x4f\xce\x11\x1e\x78\x4b\x15\x13\xc3\xd7\x7b\x3e\x43\x15\x6d\x5e\xe9\x84\x47\xc4\x83\x46\xfe\x14\x22\x06\xc6\x0f\x87\xc5\x6a\x67\x3c\x76\x45\x7c\xe2\x34\x02\xbe\x2a\xca\xa2\x5a\xaa\xce\xbd\x50\xa2\xf5\x64\x21\xd2\x47\xa9\x46\x26\xb6\x90\x2a\xab\x70\x1f\x24\x6e\xe8\x57\x51\xd6\x4f\x02\xe9\xa2\x75\x42\x4c\xb4\xe2\x3a\x5e\x42\xd6\x29\x4c\x95\x7c\xb6\x95\x8a\x09\xb0\x8e\x1c\xee\x90\xc6\xe1\x08\xe4\x9a\x53\x20\x20\x9e\x64\x04\x79\x4a\x06\xb6\xb3\x0a\xb3\x2e\xa2\x40\x02\x40\xf4\x0a\xc6\x10\x5c\x50\x69\xf3\x0e\xb2\x2d\x1c\x5d\xdb\x66\xf8\x3c\x1e\xa1\x7a\xe8\xf5\x40\x2e\x44\xee\x77\xf8\x9c\xa1\xdb\x6b\x65\x10\x6d\xbe\x69\x71\x19\x97\xb2\xb7\x7d\x65\x24\xe5\xd0\x74\x75\x4e\x2a\x97\xdc\xdc\xa6\x54\xa5\x30\x39\xbd\x88\x70\xa8\xcc\xf7\xac\x33\x84\xf4\x31\xb5\xe1\xa2\x02\xfc\xdf\x0f\xb5\x37\x57\x02\x02\x34\xbd\xfd\x24\x7f\xf3\x6b\x1c\xd7\xe7\xab\xda\xe8\xeb\x09\xac\x43\x2c\xea\x12\xde\x25\xa4\xf8\x6e\xc6\x2a\x05\x22\xea\x08\x10\x6d\x6c\x12\xdb\xe1\x10\xe2\xd7\x46\x15\x9a\xb8\x81\x29\x7f\x5e\xe9\xc5\x62\xe3\x88\x18\xd2\xde\x09\xe2\x57\x3f\x5f\x76\x10\xca\xa7\x29\x16\x0a\xa6\xf1\x2a\xee\xd0\xf0\x64\x39\x3e\x95\xd2\xa1\xa6\xe7\x0c\x3e\x72\x3f\x4c\xea\xe2\x9f\x15\x96\x89\x22\xa3\x8e\xac\x30\x0c\x5b\x24\xac\x17\x3e\x89\xe1\xdf\x27\x89\xce\x47\x8c\x60\xcc\x8d\xb5\x40\xa7\x88\x3a\xd7\x24\x56\xe7\x0a\x0d\xa6\x32\x52\x30\x9d\x0e\x98\xc8\x73\x4d\x25\xec\xf8\x64\xb5\xff\xf0\xa3\x66\xaa\x21\x0d\x8f\x85\xab\x61\x0b\x68\x19\x9b\xea\x47\xb6\xf7\x83\x25\x6a\xf8\xe3\x6e\x6f\x9f\x3f\x92\xc5\xb8\xdf\xfe\xbc\x0d\x0c\xfd\xfb\x55\xae\x62\x8b\x40\xf6\xc0\xe2\xa9\x1d\x56\xd8\xe7\x44\xa7\x6b\x21\x0e\xd5\xb2\xe7\xbc\x67\x56\x08\x58\x30\xb2\x12\xc9\x4d\x6a\xc6\x94\x38\x5c\x89\x1c\x97\xbe\x13\x86\xfa\xc7\x79\xfb\x73\x85\x4d\x66\xaf\x75\x12\xd8\xa1\xf4\x4e\x17\xf7\x50\xa1\x91\x2d\x88\xdb\x80\xce\x09\x8a\x48\x44\xea\x83\xc7\x1b\x92\xf3\xdb\xa7\xd0\x50\x21\x0e\x19\x1b\x10\x82\x75\x34\xc5\x36\x4e\x48\x6a\x64\x8f\xce\x1d\xc2\x04\x47\x21\x15\xfc\x16\x21\x3f\x80\xef\xe2\x5c\x9f\x0e\xbc\x97\xa7\x15\x63\xa2\x95\x87\x02\x44\xc1\x0b\x7f\xe1\xa1\xcb\x46\xfd\x46\x0f\x35\x23\xcf\x82\x42\x48\xa8\xfa\xb0\xbf\x72\x53\x8c\xa4\x09\x13\x97\x65\xa1\x81\x2e\x93\x2f\x73\x13\xce\xe9\xa0\xd2\x65\xa9\x00\x6d\x01\x6a\x25\x4e\x5e\xc6\x71\xe5\xee\xfe\x79\x2a\x95\xd4\x49\x29\x3f\x83\xa0\x69\x96\xad\x61\xa5\xb4\x28\xcb\x5a\x3c\x5d\xea\x54\x33\xcb\x98\x9d\x3c\xfe\x53\x9c\xa1\x30\xe8\xd8\x94\x1f\xe7\x92\xaa\xe7\x4d\xe5\x8b\x54\x46\x43\x35\x40\x65\xc2\x19\xc6\xb1\x1f\x15\x85\xb6\xa1\xb6\xb7\x62\x8b\x06\xb8\x2f\x2f\xd0\xaa\x4f\x1d\xac\x83\x2f\xcd\x43\x97\xc5\xa3\x81\x9a\xfc\xc0\x10\xa2\xd8\xe9\x73\x85\x87\x82\x2b\x85\x66\x4b\x7a\x94\xf0\xc7\x77\x42\xd2\x52\xcd\x77\xfc\x76\x32\xe5\xd7\x52\x30\x0a\xd3\x12\xf9\xb9\x7b\x87\x31\x5d\x48\x19\x0c\x22\x14\x3e\x4f\xf2\x43\x01\xec\x97\xed\xa9\x43\x12\x27\xd2\xd3\xc7\xb7\xb6\xf7\x02\xb5\x36\x48\x47\x75\x23\xc4\xe7\xef\xe7\xfa\x8f\x62\x04\x7b\xfc\x8b\x27\xa7\x56\x8c\x86\xe8\xc5\xdb\xb1\x1b\x34\x78\x8f\xb7\x16\xb2\xdf\xb1\x91\xa8\x66\x89\x32\x8c\xe5\x8c\xb0\xe0\x51\x96\xdd\x65\x03\xbe\xaf\xf5\x8e\x54\x06\xa7\xbb\x64\xcc\x89\xdc\xe7\x0a\x74\x4c\xbd\x44\xc0\x6a\x00\xee\xdc\x53\xd7\x8c\x1c\x34\x81\x1f\x2f\x39\x36\xc6\x40\x96\x7f\x4c\x6f\xa5\x89\x2d\x76\x0a\x07\xbb\x1c\x58\x08\xda\xa9\x09\x64\x32\x6d\x96\xc3\x15\xcb\xa4\x9b\x2a\xd4\xbe\x88\xce\x38\x27\x05\x1d\x8c\xf2\xbb\x24\x11\xf3\x54\x2a\x98\x8d\x0a\xe3\x74\xae\x89\x43\x58\x2b\x7e\x14\xa8\x45\x63\x6e\xf1\x2b\x20\x24\x9a\x7c\x2b\x32\xc8\x1c\xcd\xa3\x0c\x48\xc5\x6a\x8d\x62\xe9\x70\xbd\xb5\x15\x96\x2b\xcc\x71\xa9\x11\xef\x44\x55\x10\xa7\x5b\x0b\xd1\xd3\x9b\x68\x20\x5f\xb2\x1a\xf3\x22\xe1\xf1\xc0\xb3\x5b\x9d\x27\x7e\xb5\x04\xfb\xc5\x18\xea\x37\x4f\x76\x2c\x8c\x46\xe9\x90\x6d\xa4\x4c\xe4\x55\xc3\x77\x9d\x68\x31\x9c\x74\x91\xd9\xf4\x67\x38\x61\xfc\x3a\x3f\xcf\x9a\x09\x19\xfc\x01\x42\xab\x1c\x0c\x31\xed\x2d\x08\x6b\xd4\x88\x3d\xd3\x2c\xf4\xd6\xf7\x67\x60\xcb\xcb\xd5\x66\xca\xdc\xee\x59\x3c\xf7\x08\x34\x2a\xda\x4a\x50\x90\x9b\x1f\x6d\xd5\xdd\xa2\x99\x57\xb9\x4a\xc1\x0e\xe3\x28\xf8\x42\x24\xc6\x4b\xf2\x25\x84\x5d\xee\xfe\x7c\x98\x41\x6c\x03\x83\x2f\x97\x0d\x75\xc4\x47\x25\x78\x1b\xba\x98\x0f\x73\xe8\xde\x2c\xc6\x37\x9b\x9f\xc0\x73\x40\xb3\x95\xe7\x20\x6c\xa1\x65\x85\x79\x36\xc6\xd3\xce\x1e\xeb\xaa\x07\xf8\xc7\x53\x04\xe0\x98\x57\x10\x7e\xd3\x86\x84\x7f\x89\x14\x46\x71\x70\x93\x12\x76\xf3\x3d\x41\x66\x2e\x58\x79\x0f\xaf\x3b\x8d\x50\x5c\x72\xf8\x67\x92\x0b\x91\xd0\x7e\xe6\x30\x91\x8d\x36\x86\x6d\x9a\x2a\x84\x84\xbd\x9a\x8e\x12\x5b\x0b\xd2\x2e\xdb\x58\x7b\x6a\x4a\x23\xd6\x18\x1a\x52\xb9\xef\x9c\x37\x27\x25\xb6\x15\xc9\x5b\xc8\xfb\xbe\xd2\xe5\xc5\x8d\x90\xc7\xfd\x32\x60\xec\x2a\xc8\x04\xc1\x1e\x84\x8d\x2c\xb9\xcb\x32\x32\x85\xdc\xd8\x3e\xa4\x60\xd4\xac\x06\xb7\xd4\x51\x94\x3d\xd8\xb7\x92\xd8\xd7\xf3\x77\x2f\x25\xb8\x9b\xd3\x47\x83\x87\x55\xa6\x96\xd4\xb3\x5b\x73\x5b\x79\xb2\x0e\xf1\xbf\x1a\xcf\xf0\x6a\x27\x6b\x5b\x19\xbb\x3a\x06\x61\x47\x84\x1e\xc4\x9d\xe2\x3e\xa3\x9d\xa3\x46\xbf\xe8\x98\x2d\xa6\xa2\x13\x14\x75\x2c\x4c\xa3\xeb\xad\xb6\x38\x6e\x2b\x54\x47\xae\xfd\x92\x0c\x61\x02\xe6\xaf\xb7\x2c\xdb\x5e\xae\xab\xf0\xcd\xdc\x6f\xb8\xfc\x51\xbc\x87\xad\xf7\x79\x8f\x56\xa7\xcd\x3b\xc6\xe3\x7e\x13\x7d\xff\x74\x20\xef\x07\x1e\x50\xf9\x8e\xc0\xb8\x6d\x11\x28\x6d\x39\x77\x6b\x72\x17\xb0\xdd\x91\x58\x32\xe7\xec\x50\xe0\x96\x67\x1c\xb1\xdf\xae\xb7\x08\x89\x4a\xf0\x84\x39\x96\x02\x13\x06\xe4\xf1\xcf\x14\x2e\x8d\x8f\xa5\xd8\x68\x04\x49\xa1\x94\xc2\x78\x58\xb2\x2a\xd2\x69\x17\xef\x82\x98\x39\x28\xc7\x47\xaa\xbf\xe8\x23\xc2\xfc\xa9\x54\x3d\x4e\xfc\xde\x90\xc3\xf2\x1c\x4b\x1d\xc9\x2e\x1d\x0b\x3d\x48\xdc\xf3\x10\x19\xa7\x49\x97\x4c\x39\xb1\x2b\xac\x13\xff\x94\xdd\x45\x60\xf4\x03\x43\x09\xa7\x65\x75\xb2\xc2\xb8\x6a\xbc\x0d\x9a\xe1\x4d\x9d\xba\x11\x13\xdf\xe0\xe5\xef\xf8\xf2\xb7\xc0\xe9\xa2\xba\xde\x78\x64\x08\x41\xf4\x57\x67\xa1\x4e\x31\x5d\x59\xc2\x4f\x01\xfb\xcc\x58\x59\x50\xb6\x2f\xba\x32\x66\xc6\xc5\x2a\x4a\x19\xea\xb9\x2e\x1f\x54\xf2\xad\xa2\xe9\x4b\x44\xdf\x34\xf9\xe1\x45\x48\x71\x25\x4e\xc6\x0c\x4d\xcf\x39\x31\xff\x3b\xf6\xf4\x9c\xf7\xf9\x9d\x8d\xa3\x34\xcd\xdf\x9a\xf3\xe3\xc8\xa6\xd5\x06\x32\x70\x87\x30\x3a\x6b\xf2\x9d\xb9\x6a\x34\xa7\x69\xc9\xe1\x3d\xc9\xdd\xad\x8d\x54\xd9\xd1\xe0\x30\x1e\x2b\x0c\xbf\xe2\xbf\x6e\x87\xf6\x7c\x0f\x04\x6c\xbb\x0b\x6e\xdf\x46\xf8\x96\xe6\xba\x96\x1a\xfa\x1d\xcc\x70\x69\xc7\xc5\xb4\xba\x18\x07\xc3\x30\x7c\x7f\x1a\x38\x15\xab\x61\x26\xfb\xe8\xef\xf8\x43\x22\x09\x71\xa3\x1c\xdc\xe5\xa8\x7e\x84\x72\x97\xe0\x01\xc5\x6e\x0a\xe2\xec\x8b\x10\x26\x4b\x21\x2a\xca\xbc\x7d\x95\xea\xc9\xcc\x7d\x12\x59\x58\xe0\xaf\x92\xdc\xa6\xda\xd4\x6c\x2d\x0b\xdf\x9f\x6d\xf2\xf2\x99\xdf\xae\x1d\x18\xdf\xa8\x33\x54\xde\xf9\x85\xf2\x16\xcc\xa5\x30\xea\x80\xbe\xd9\x70\x18\x75\x50\x53\x43\x6e\xaf\x3b\xa6\x89\xce\xba\x3c\xd9\x37\x90\xd5\x08\xc2\x7b\xc4\x4a\x99\xf2\xb8\xdb\xcc\x02\x73\x63\x02\xa4\xb4\xcf\xbf\xc2\x48\x45\x5f\x46\x6b\x00\x57\x3f\xd4\xc3\x7a\x6e\xdb\xeb\xed\xf8\xee\xbe\xa1\x27\x75\xd3\x1b\x27\x1a\x8a\x72\x01\x29\x63\x03\xc5\x55\xf6\x84\x3d\xc5\x92\xb5\x75\xb9\x2e\x7d\x8b\x1a\x25\x20\xf7\x37\x4b\x28\x8e\xae\x7c\xd6\x3b\x24\x1b\x95\x98\xfa\x3c\x0e\xe4\x20\xf3\x36\xc7\xd1\x05\x50\x4c\x5e\x76\xf1\xa2\xfb\x33\x24\x7e\xbd\x40\xfe\xa1\x61\x56\x0c\x93\x42\x9e\x1d\xeb\x71\x9d\xa5\x5b\x37\xbe\xbf\xeb\x25\x2b\x29\x01\x7d\xec\xcc\x79\x5e\xa9\x22\x3c\xab\xcb\x35\xe0\xed\xec\xa0\x7f\xa1\x74\x09\x24\xf0\x35\x61\x86\xe8\x86\x0d\x18\x87\xee\xfd\x75\x99\x86\x3f\xfc\x32\x5d\x70\xad\x83\x5b\xc6\x94\x8c\xf6\x59\x4b\x24\x85\x5e\x6b\x80\x94\xb2\x03\x8e\x0d\xbb\x7e\x17\x3e\xa0\xd8\xc3\x93\x7c\xc7\x6c\x59\xa4\xbd\x64\xc4\x75\x51\xfc\xe8\x4b\x45\xf2\x23\xab\xc7\x4e\x1b\xc7\x36\xbd\xe5\xa1\xb7\x9e\x6e\x20\x1e\x57\x8b\xe4\x0a\xee\x69\xe4\xf4\x6f\x3a\xb6\x2e\x33\xee\xc8\x11\x66\x38\x71\xc8\x7e\x49\x53\x91\x9d\x41\xf2\x1e\x00\x09\x16\x07\x1e\x4b\x60\x0d\x13\xa7\xcc\x2c\xe3\xbb\x21\x14\x03\x98\xdf\x4c\x17\x9a\x19\x31\xac\x27\x79\x11\x67\x99\xdc\xf5\x82\x93\x98\x11\x99\x05\xef\x4f\x62\x21\xc1\xaf\x16\x73\x58\xee\x67\x32\x15\x71\x27\x1f\x85\xec\xe9\xc4\xe8\x0a\xa0\x79\xc8\x82\xb3\xdd\x7b\x13\x81\x55\xb1\xd3\x19\xe2\x3f\x86\x63\xb4\xcf\x9d\xe9\xec\x4c\xba\xcd\xd9\xab\xec\x40\x0e\x9d\x7f\xf9\x4a\x7e\xa4\xc2\x32\x12\x3f\xcd\x82\x88\x83\xfc\x1d\xc2\x7f\x4b\xe6\x0a\x8d\xec\x37\x58\x9e\x28\xb6\xf4\xbb\x8c\x37\x20\x12\x28\x7c\x76\x95\x57\xe5\x27\xb5\x45\x82\xa7\x51\xcf\x71\xb0\x14\x38\xff\x98\xb7\x7c\xd6\x56\x58\x8c\x87\xe9\xa3\x7c\xeb\xc2\xb6\xf5\x8f\x2b\x9d\x92\xb4\x39\xa6\xa5\x09\x28\x73\x6e\xf1\x9f\x3f\x98\x59\xe8\x91\x35\x6b\xf7\xd6\x9e\x5b\x5d\xa8\x46\x6d\x6c\x32\x7e\x9a\x44\xba\xa4\x70\x1b\xc7\xe9\xa4\xa5\xc0\x7b\x9b\xaa\x44\xd6\x7a\x80\x75\x6e\x55\x62\xee\x9d\x17\x0d\x80\x5c\x29\xa3\x04\xdc\x2c\x69\x1a\x7c\x1d\xd6\xb2\x61\x19\x59\x69\x8b\x24\x80\xae\x13\xd0\x2d\x92\x16\x49\x14\x24\x5c\x91\x23\x08\xbc\xd0\x54\x24\xcd\x5f\x08\xa0\x83\xcb\x8a\x1c\x98\xa2\x88\xfd\x9b\x7d\x16\x44\x5e\x10\x21\xf3\x5d\xd1\x40\xca\xfc\x48\xda\x28\x24\x56\xfa\x75\xb4\xc5\xcb\x20\xc9\x44\x26\x37\xbd\x5f\x68\x6d\x51\xe5\xef\xcd\x6d\xcf\x99\x00\x1b\x2f\xbd\x17\x6e\xd0\xd8\x44\x19\xaf\xba\xd5\xe1\x94\x94\xc7\x2f\x33\x62\x6b\xba\x91\xe7\x43\x8f\x9f\x65\xeb\x3f\xbf\xf7\x5e\xf3\x57\xd2\x32\x10\xa5\x96\x99\xf6\x2b\xf7\x66\x72\xbb\x93\xa2\xae\xf0\x94\x2b\x95\xb9\xa3\xb6\x2c\xe2\xa1\x21\x8b\x2a\x98\x40\xa3\x5b\x60\x9f\x29\xc0\x24\xcc\x64\xf8\x30\x7a\x60\xff\x91\x68\xe7\x86\x77\x27\x93\x09\x75\xd3\x2a\x8f\x8d\x77\xad\xd1\x74\x77\x21\xc7\x38\x2d\x9d\xcb\xac\x52\xd5\x9c\x21\x1e\xa1\x30\x4a\xff\xaa\xa6\xc8\x9f\x1c\x64\x4b\x14\xc8\xc6\x76\x2d\xe1\xfd\xad\x70\x14\xb7\xd8\xad\x52\x94\xfd\xe0\x4a\xa3\x02\x27\x2c\xab\xa5\xd4\x2a\x5f\x94\x7f\x84\xc8\x20\x9c\x03\xa9\x3e\x39\x39\x0c\x13\x15\x4b\x95\x11\xbb\x8c\x37\x74\x0b\x45\xfd\x1b\xa7\xe4\x80\xd1\x5c\xce\x4d\x75\x62\xe3\x2c\x33\x44\xaf\x9e\x32\xb5\xb2\xe3\x0e\x9a\x6f\x86\x2d\x4d\xae\x2d\x8c\x86\x04\xe1\xb8\xc3\x12\x23\xff\x3a\x68\xdf\xe4\xf8\x8f\x65\x7d\xc9\x02\x05\x2c\xcb\x3a\x8d\xab\x02\x3e\xd8\x24\x99\x50\x4e\xa2\x89\x9c\xf9\x95\x44\x47\x17\x5a\x9e\xe6\x22\x45\x8c\xe0\x2d\xf1\x2a\x4f\xd5\x94\x49\xef\xb3\x9f\x86\x05\x9d\xb1\x7e\x62\xc3\xdf\x18\xb7\x96\xe1\xef\x8f\x46\x45\x4c\x1b\x01\x85\x52\x15\x33\x43\x01\xe5\x90\xbc\xd4\xe7\x9e\x05\xff\x44\x58\x6a\x36\x44\x6b\x03\xb2\xa5\x1b\xa6\x87\xb9\x48\xd5\xf9\xf7\x7e\xcd\x43\x99\xf9\x92\xe0\xf0\xeb\x0c\x11\xf2\x28\x2b\x75\x83\x62\x65\xf6\x12\xba\x2a\xa4\x00\x2a\x8c\x56\x44\x57\xfd\x1e\xf1\xb3\x87\x16\x6d\xe4\xdd\x9f\x89\x88\x66\x43\x61\x7e\x86\x49\x4e\x67\x21\x47\x5f\xe1\x24\xf1\x8f\x5c\x62\xe1\x50\xe4\x96\x51\x18\x9b\xe5\x97\x27\xe9\x7e\xca\x35\x76\xec\xac\x25\x71\xf1\xd8\xbf\xaa\x8d\xf4\x24\xa7\xba\xba\x9f\x60\x53\xf5\x9a\x2f\xf2\xc7\x6a\x40\x89\xe6\x94\x4c\x76\xbd\xf6\x07\x57\x0c\xa0\x56\x38\x27\xb5\x84\xb7\x0e\xbd\x0f\x7a\x67\x80\x0a\x31\x0f\xe3\x0c\x5d\x9c\x4f\xd2\x22\x24\x7f\xca\x8e\xe7\x22\x65\x4d\x13\x1a\x61\x18\x3c\x42\x9b\xd9\xa7\x5a\xd1\xcd\x79\xe2\x63\x47\x4c\xf6\xeb\x2d\x20\x90\xde\x69\x0e\x8a\xa8\xd3\x16\x25\x45\x72\xa0\xd5\xb3\x13\xb5\xf0\xe8\xa2\xfd\xf3\x48\xe2\x69\xfb\xf3\x85\xc4\x83\x02\x63\x34\xb1\x87\xf9\x3d\xfd\xb0\x55\x31\x7a\x35\xa3\xb6\xce\x6a\xe7\xaf\x27\xf2\xf4\x44\x4d\x5a\xb1\xfd\x83\xa6\xe4\xd5\xf9\x8a\xb4\x46\x90\x32\xe8\x96\xe9\x34\x6e\xe4\x4a\xdc\xcd\x26\x7e\x29\xaf\xe0\x4f\xd4\x43\xca\x3b\x2c\x71\x06\xb8\x82\x98\x6f\x19\x8a\x5f\x69\x63\xbd\xc8\x3d\xa4\x81\xdc\x4a\xa8\xeb\x8b\x0d\x21\xbf\xe2\xf5\x77\x65\x24\xfc\x43\x54\xee\xe9\xf9\x86\xd4\x86\xca\x80\x1d\xbf\x68\x9c\x10\xcd\xa4\x89\x58\x2f\x65\x6b\x38\x13\x1a\xb5\x92\x82\xe3\x25\x04\x5c\x4c\x80\x22\xe9\xa8\x90\x49\xa5\xec\x36\x2d\xfb\x04\x6b\xb1\x00\xcc\x8b\x6d\xe2\x12\x92\x23\xc1\xc3\xa5\xd9\xef\xf8\xfe\xa8\x60\x77\x04\x69\x4e\x6c\x6a\xf9\x9f\x12\xe7\xc3\xb7\x06\x08\xe8\xd5\xc6\x01\x40\x00\x79\xba\x89\x8c\x0a\xbc\x77\x66\x35\x80\x46\x45\x49\x38\x7a\xf8\x5f\x3f\x3d\xd4\xcb\x02\x91\x7e\x10\xab\x92\x1e\x55\xbc\x09\xe5\x40\x03\x53\x3b\x10\xcf\x3b\xfe\x74\x55\xfb\x0f\x67\x79\xc6\xd2\x03\x06\x42\x90\xb4\xd5\x3a\x23\xfb\xb9\xa3\xd4\xce\x78\x2e\x47\x2f\xea\xc5\x0c\xe8\x67\xb3\xf2\x17\x8d\xe9\xcb\xae\xf0\xfc\x3f\x36\xdc\x43\xcb\x0a\x93\x59\x13\x30\xa8\x81\xe5\xc0\x07\x0f\x22\x4a\xf6\x2a\x1c\x67\x94\x2e\x8b\xda\xeb\x65\x38\x86\x46\x56\x78\x7d\xbd\xa7\x42\x1b\xb0\x8b\x30\xb3\xd2\xe4\x6d\xb6\x07\xd7\x49\xf3\x2b\x5d\x99\x70\xe9\xf4\x50\x0c\x35\x8c\x72\xd1\xcb\x65\x0b\x0a\x19\x74\xf3\xf4\x5f\xcd\xc0\x90\xb2\x43\x76\x22\xdc\xe4\xc8\xea\xec\xca\x6e\x04\xc3\x76\x24\xf1\x2c\x48\x4c\xca\x94\xb9\xc4\xfd\x56\xb0\xb2\xf1\xf4\x30\xf7\x02\x3a\xa6\x6f\x33\xab\x31\xa4\x1f\xc0\x7d\xcd\x3d\xf9\xc3\x48\x7b\x1a\x71\xd7\x3a\xc0\x26\x15\x9f\x2d\x97\xda\x44\x1f\x63\xb8\x3e\x4b\x5d\x1f\x4f\xc0\xd1\xb6\x41\x45\x53\xfc\x49\x7f\x7e\xc8\x44\xec\x5c\x07\x62\x4d\xca\x0b\xa0\x3c\xe9\x1b\xf8\x21\x77\x24\xe2\x23\x30\xd0\x12\x05\x9e\x54\x5e\x0f\x56\xb8\xe6\xc6\x1d\xb0\xd3\x29\x10\x4a\xb1\xd1\xfc\x0d\x5f\xf7\xfd\x5f\x05\x91\x65\xbb\x69\x96\x21\xff\xf6\xd0\x76\xb8\xce\xd7\x7d\x8e\x6e\x90\x9c\xdb\x14\x76\x29\x84\x45\x33\x4c\xe6\x89\x3d\x4a\x80\x98\x8b\x70\xb2\x4b\x57\xed\xb9\xc0\x32\x89\xd4\x2b\x01\xef\xf6\xa2\x36\xfe\x2a\xa9\xdb\xab\x4b\x43\x65\x37\x8b\xb3\x1c\x3c\xe8\x41\x68\x2f\x60\x72\x71\xca\xd9\x97\x4f\x89\x63\x66\xff\x2f\xcb\xef\xe3\xc7\x2a\x62\x78\x12\x35\xcc\xe6\x42\xe7\x93\x40\x9e\xb4\xa6\x9b\x95\xd4\x16\x42\x84\xcc\xb1\xfb\x9b\x8e\xd7\x67\x56\x75\xde\xd3\xc8\xe3\x75\x89\x6b\x00\x27\x11\x97\x23\x4b\x5b\xa2\xd2\x48\xdc\xb3\x08\x0a\x7c\xc0\x3a\x81\xdf\x88\x65\x7f\xcc\xe4\xa8\x67\x6e\x1e\xab\x48\xc4\x53\x51\x88\x9c\xb9\x72\xf9\xda\xa4\xda\x96\x27\xc6\xcf\x21\x0d\xf1\xe3\xfd\x38\xb5\x58\x72\x5a\xae\xc8\x04\xbc\x7b\x92\x88\x0e\xf3\xad\xf4\xa2\x4c\x1b\x84\x6a\xe2\x5b\xe0\x59\x0d\x9a\xe8\x7c\x5e\x0a\x8b\x3f\x70\xf3\x17\x7a\x03\x3a\x50\xee\x96\x2d\x85\x39\xf0\xac\x96\xe7\xb1\xc9\xce\xc1\xc6\x79\xe0\xc8\xa0\xf3\x62\xb9\xe0\x00\x5a\x77\x7b\x7b\x50\x99\xd3\x8e\x9e\x67\x5c\xde\xf3\x17\x49\x2c\x1b\xac\x5d\xbc\x21\xe2\x37\x03\x09\x59\x68\xb4\x03\xee\x3a\x30\xc9\xdb\x90\x35\x8f\x90\x53\x67\xbf\x13\x91\x9a\x14\xe1\x0c\xea\x01\x10\xe1\x54\x1e\x6e\x22\x52\xe4\x9a\x96\x56\x45\x7c\x27\x33\xbd\xbd\xa3\x04\x1c\xd8\xaf\x00\x95\x08\x3b\x51\x8c\x36\xef\x25\xb1\x67\x97\x8e\x4a\x2d\x2f\x6e\x86\x43\xda\xf4\xa1\xd3\xd6\xd8\xb9\xf4\x0b\x79\x2f\x91\xf6\x5a\xdb\x72\xbc\x7c\x69\x8e\x92\x28\x40\x06\x09\xac\x80\xf0\x87\x28\x37\x75\x18\x7c\x71\x39\xc8\x0c\x1f\x3b\x21\xfc\x96\x66\x46\xb5\x5f\x5f\x3e\x9d\xbd\xb7\xc2\x9f\xe0\x6e\x40\x1a\x99\xa4\xd1\x3e\x17\x73\x86\xb1\x59\x31\xdc\x81\xec\x84\x00\x63\x30\x0c\x33\x9a\x57\x7b\x87\x64\x4b\x04\xca\x73\x75\x28\x09\xbe\xc7\x49\x65\xd3\x04\x40\xd6\x98\x2a\xdf\x06\x16\x24\x85\xa5\xba\xd5\x5c\x17\xca\x3f\xb4\xe4\x42\x09\xa8\xca\x4b\xd1\x59\x71\x03\x68\x22\x9d\xf8\xb6\xd3\x28\xc1\x66\xd7\xd8\x32\x0e\x91\x32\x0e\x54\xb5\x8c\x85\xe4\x21\xa2\x92\xd2\x6e\x2a\xfa\x68\x77\xb3\x5e\x7a\x64\x81\x62\x9e\xc3\xa1\x31\x26\xb1\xca\x55\xc8\x23\xbc\x12\x20\xda\x28\x19\xee\x88\x6e\x39\x01\x16\xbb\x26\xdd\x70\x09\x6f\x91\x35\x7e\x67\x2e\x75\x0a\x36\xee\x58\x5d\x73\x2c\x64\xff\x41\x14\xbe\x77\xb6\x4c\x4d\x77\x76\x2d\xcf\x12\xa2\x49\xfc\xa2\xe1\x4c\x24\x57\xdc\x75\x09\xb8\xee\xec\xef\x10\x99\x6e\x27\x56\xf3\xcc\xf2\x08\xae\x45\x04\x82\xc3\xea\xdb\x8d\xd4\x96\x91\x32\x60\xa5\x08\x88\xac\x4c\x8f\xc4\x15\x25\x46\x04\xea\xed\x37\x1e\xd6\xad\x48\x93\xdc\xb1\xa3\x64\xad\x84\xc6\xf6\x3b\x36\x14\x76\x8a\x46\x28\xa1\x4e\xc8\x79\x89\x28\x39\x04\x03\x71\xb5\xd2\xf6\xf7\xf3\xdc\xeb\x0c\xd7\x15\xdf\x9e\xeb\x3a\x35\x76\x8c\xc6\x8e\xdc\xd3\x55\xea\xa0\x72\x29\xe0\x9c\x96\xee\x27\x17\x23\x73\x91\xd2\x05\x72\xf6\x8e\x0e\x76\x99\xad\x50\x6e\xbe\x7c\x22\x83\x83\xf3\x69\xe7\x70\x23\xee\x6b\x76\xd6\xca\x66\xae\xde\x0d\x02\xa6\xe5\x30\xb1\x2c\xad\xd2\x0f\x09\x65\xb8\xa6\x2e\x71\x5b\x59\x9f\xd4\x6a\x32\x3d\x35\xb8\x59\xa9\x8a\xb1\x16\x2f\xd0\x41\x0d\xfe\x88\x91\x2c\x8f\xce\xaf\x25\xd3\xce\xc8\xab\x0b\xeb\x85\xca\x98\x99\x8e\x96\xe5\xc3\x08\xad\x2a\x21\x1b\xee\xb4\x34\xdf\x0f\xad\x89\x15\x95\xa6\x6e\x23\xb5\xe2\x02\x94\x8d\x45\x52\x17\xa5\xc5\x42\x5d\x68\x24\x6b\x78\x04\x9f\x24\x0a\xd1\x11\x41\x83\x8e\x80\xab\xdc\x64\x1d\x1e\x79\x8b\x1e\x2a\x0b\x25\x64\x1e\x6f\xd6\x5f\x2a\x55\x8e\xb9\x6d\x24\xb2\xa6\x9e\xa1\x65\x1d\xbc\xdf\xbf\x48\x60\x1f\xa8\xd2\xfc\xa0\x27\x6f\x11\x78\x60\x19\x95\x2b\x88\x1b\xa7\xee\xd7\xe3\xbe\xdd\x69\x45\x4a\xd7\x4a\x00\xc7\x90\x6a\xe4\xb7\xae\x29\xd3\xad\xc3\xac\x26\x13\xd4\x10\x63\x6a\x25\x58\x76\x83\x03\x0e\xd5\xec\x7a\x0e\xd9\x8c\x16\x0e\x79\x71\x57\xca\x3f\x3b\xe5\xbe\xba\x1a\x98\x56\x50\x19\x5d\xf1\xd9\x75\xb5\x62\x7d\x8d\x42\xf6\xde\xc8\xc8\x86\x73\x50\xb1\x1c\xd8\x86\xd2\x1f\x67\x9c\xd1\x39\x3f\x92\x68\xc7\xd7\x1b\x71\xe2\x1a\xd0\xc1\xf0\x2b\xc2\x06\x95\x3a\x7c\xd5\xd4\xaa\x0e\x9b\xec\x71\x4c\x58\xbd\x00\x86\x0c\x11\x8b\x58\x80\xe4\x7e\x93\x2c\x22\xd4\xb4\xb9\xc5\xc4\x89\x0f\x26\x5b\x22\x27\xba\x70\xd3\xa5\x52\x76\xe2\x0a\xa9\x23\xf5\x3b\xb9\x6f\xeb\xaf\xc3\xaa\x5e\x34\xa1\xa7\x27\x96\xa3\x16\x15\x32\x07\xd0\x19\x0b\x95\x78\xd5\x32\x39\x9e\xb3\xa0\x19\xef\x12\x24\xd3\x73\x27\xe2\x01\x39\x13\xea\x4f\xdc\xf5\xed\x63\x60\x5c\x48\xa4\x10\x39\xdc\x21\x12\x21\xba\x84\x7b\x52\xd4\xbe\x7e\x3c\x67\x54\x75\xbd\x4e\x56\xcc\xec\x89\x0b\x28\x92\xff\x08\xc0\xba\xf4\x7d\x47\x54\x8d\x25\xf3\xe3\x73\xb2\x16\x4f\xee\x15\x7a\x60\x31\x0d\x8e\xb1\x81\x2c\x3c\x44\xc5\x88\x72\x89\xab\xdb\xfd\x7c\x92\xbb\x0c\x66\xce\x68\x04\x90\x09\x14\x0d\xe4\x96\x46\xc1\xfb\xde\x65\xc7\x8d\xff\x9b\x3a\x2d\x4c\xd6\xa1\x85\x30\xf6\x6f\x73\xc1\xdc\x7a\xf2\xce\x8b\xaa\x3b\xec\xa7\x50\xa9\x55\xf7\x72\xf8\x6d\x26\x2a\x59\x5c\xe3\x91\x35\x99\x5d\x43\x91\x14\x28\x0e\xd8\x0f\xfe\x1f\x52\x90\x32\x56\xae\xf5\x7a\x58\xd6\xc8\x0c\xab\xdf\xac\x1d\xbf\x18\x1e\x29\xd3\xbb\xee\x34\x43\x2b\xb2\x79\xc2\x24\x17\xd5\xec\x08\xfe\x6d\x4b\xd8\x0d\xfc\x71\xde\x02\x85\x6c\x48\xfb\xcc\xac\x15\x9a\xc0\x10\x39\x4a\x1e\xa6\xec\xd1\xa7\x05\x93\x1e\x4a\x4d\xf0\x88\x58\x6c\xb5\x7a\x19\x2b\x42\xc1\xe0\xb4\x06\xac\x4f\x88\xae\x7b\x60\x24\x9a\x3d\xec\x88\x7d\x8c\x03\x8b\xc0\x83\x0a\x80\xdc\x9a\x2f\x09\x9a\xea\x46\xb9\xd1\x03\x26\xbb\xa3\x19\x15\xe2\xc3\xfb\xf7\x27\x52\xae\xbe\xf2\x5e\x36\x70\x2a\x6c\x8c\x10\xd8\x3d\x46\x1a\xaa\x14\x0b\x14\x00\x51\x31\xc3\x17\x8d\x6b\xf2\xe7\x36\x80\x59\xc9\xe8\xb1\x4f\xf0\xf9\x3c\x43\x9a\x98\xc9\xc6\x60\x79\x3f\x1d\xe4\x26\xe4\xd1\x4b\xde\xcd\x0d\xad\xd1\x74\xfa\xbb\x29\xd2\x79\x79\xbe\xf4\xac\x40\x21\xb6\x5b\x7e\x0f\xf2\x41\x24\xb5\x19\xcb\x5b\xdd\xf6\x81\x34\xc2\x4e\xa5\xa1\x70\x9a\xe5\x3d\x37\x4f\x62\x02\x35\x8f\xad\x06\xfc\x2d\xff\x9e\x9c\xce\x77\xd4\x7c\x44\x98\x09\xa7\xd9\x67\xa4\x65\x0d\x61\x9a\xd9\xf2\xbe\x05\x45\x6b\x6a\x98\x52\xc2\x8e\x3a\xe6\x9c\x82\xb6\xac\x22\x39\x7c\xe9\x2a\xee\xfd\x7b\x09\xbf\x20\x4e\x5d\xf3\xdf\x79\x8a\x0e\x00\xc4\x28\x65\xa1\xab\x24\x1b\x59\xc6\x04\x5c\xfe\x02\x89\xf4\x6e\x93\x99\x88\x92\xbf\x89\xbb\xfc\xe2\xbe\xd1\x72\x26\x46\x87\x38\xfd\x64\x0f\x31\x6f\x92\x75\x27\xa6\x34\x03\x1a\x34\x97\x1e\x63\xff\xde\x95\x08\x7f\x21\xb8\x0f\x94\xe4\x53\xb9\xe8\x9f\xe4\x74\x92\xfe\x28\x3e\x47\xad\x5d\xc4\x7d\x55\x97\x22\x17\xe1\x15\xe1\x0f\xcd\x17\xd4\x4b\xab\xf8\x9d\x86\x2a\x51\xa9\xf5\xbb\x26\x96\x12\x88\xcf\x3e\x52\xf7\x05\x3a\x42\x74\x77\xe6\x52\x5f\x2c\xeb\x88\x3c\x02\xcb\xbb\x3b\xa0\xd4\xce\x5d\x53\xab\x57\x0a\xab\x4c\x0c\x9d\xf1\xf5\x66\x2e\x63\x26\x56\x9f\x95\x6a\xb9\xfe\x3b\xf7\x3a\x79\x6a\xa7\x83\xab\xcb\x0a\x0a\x9a\xc9\xd2\xbb\x79\x8f\x07\xcd\x3f\xb9\x58\xc8\x9d\xe9\x1e\x04\xd8\x15\x35\x6f\x9a\x66\x71\xd0\x9a\x0e\x9b\xd7\x78\xd3\xd4\xd7\x41\xf9\xae\x4d\x7b\x12\x15\x51\x3f\xfe\xc3\xf0\x83\x71\x31\x5a\xb8\xf6\x78\x95\x35\xf5\x54\x57\x05\xc9\xdd\x35\x40\xa2\xa0\xc0\x92\x4f\xf0\x8b\xf8\x4d\x39\x46\x07\x9a\xde\x14\xd2\x7b\x64\xd9\x16\x08\xad\x99\x77\x51\xbf\x42\xd9\x7a\x59\xd0\x66\x83\x90\x6a\x5d\x72\x1a\x05\x4f\x74\x38\x05\x03\xd5\x71\x21\x16\x48\x47\x38\x34\x1d\x4b\xb3\x69\x24\xd6\xf0\x42\xb3\x00\xee\x05\x22\x3d\x63\x15\x50\x0a\xd7\xc2\x9f\x3f\x69\x3f\xc6\xf1\x0f\x94\xe5\xa6\x3c\x89\x79\x2a\xbe\x4b\xfb\x47\x3b\x53\x7f\x6f\x6c\x78\xdf\x48\x33\xf7\x26\x9c\x43\x8c\xb9\xeb\x2e\x52\x82\x1a\x7d\x28\xc2\xcf\x90\x6f\xe7\x65\x47\x8e\xa1\xbf\x87\x4a\x47\x20\xdb\x82\x50\xd6\xc8\x4c\x30\x85\xab\x55\x6c\x97\x33\x9c\xdc\x28\x14\xe4\x71\xc0\x96\x72\x0f\xa9\xfd\x74\xa1\xda\xd9\xb2\x6c\xe5\x8a\x42\x0c\x88\x50\x84\xa6\xce\x12\x34\x72\xc3\x34\x1b\x24\x5f\x60\x3b\xc3\x10\xbc\xfe\x71\xa9\x38\x7d\xd7\xa4\x56\x84\xfa\xaa\xb6\x80\x95\x68\x4b\xc7\x11\xa3\xeb\xb6\x37\xa2\xf5\xe8\x80\x8b\xf8\x0d\xda\x87\x9f\x04\xe0\x8d\x27\x82\xc3\x34\x22\x50\x9b\xa0\x58\xfa\xa4\x4f\x21\x31\xb4\x78\xa0\xf0\x78\x04\x08\xca\x6d\x99\x74\x81\x49\x04\x51\xa0\x6a\xff\xd1\xc4\x0f\xad\x2a\x0b\x98\xd0\x27\x71\x5a\xab\xd7\xc7\x80\x86\x02\x61\x11\xd4\x85\x43\x3b\xf3\xf2\x09\xbc\x18\x26\x04\xc9\xcd\x0e\x8e\x6c\x59\xb2\xf3\x6c\x3e\x3b\x4f\x63\x5f\x76\x3f\x1d\x16\x61\x8f\x54\x79\x8d\x2a\x99\x4d\xb1\xef\xe1\x72\x50\xf3\x35\x92\x61\x48\x38\x83\x0f\x0e\xe8\xed\x95\xe7\xd7\x06\x13\x38\x9f\xc5\x4e\x39\x8b\x9a\x48\x09\xb9\xa3\xf1\xde\x84\x61\x69\x61\xc6\x38\x12\x7f\x51\x78\x5e\xde\xf9\xe0\xd3\xf7\xaa\x1b\x60\xf4\x7b\xc1\x27\x60\xd7\xc2\x85\x98\x5b\x9c\xba\x15\x2d\x9a\x1d\xb6\x88\x2a\xb1\x37\x37\xc1\xf8\xad\x8c\x85\x9b\x29\x56\xfb\x1f\x77\x81\x05\x67\x92\x42\x0f\x98\x13\x03\xbc\x2a\xb0\x3a\x64\x33\x41\xa1\x7a\x22\x2a\xf4\xb5\xf0\x9c\x28\x97\x6b\xa2\xf7\xa4\xea\x32\x45\x38\x43\x0a\xab\x3b\x0c\x89\xb5\x81\x6f\xa5\x8f\x9d\x11\x06\x18\xe6\x45\xfb\x5f\x51\xd3\xb1\x62\xcc\x34\x8b\x6e\x74\x44\xbb\x4e\x07\xde\x1e\xb2\x6a\x59\x29\x33\x83\xe8\x56\xa4\x42\xc1\x19\x1c\xe2\x21\x28\x92\xd0\x9a\x34\x21\x4d\xe7\x98\x77\xfd\xa5\xce\x26\x0d\x9b\x94\xa8\x87\x18\x6f\xff\x0e\x6e\x4a\xca\x92\x22\xc9\x6b\x52\x26\x55\x5f\xff\x3a\x96\x74\x85\xcf\xb5\x3c\x1d\xfe\x9b\x30\x80\xe5\xa7\x51\x4b\xd4\xe7\x44\x8f\x1c\xef\x85\x9a\x6f\x94\xaf\x47\x5e\x65\x21\x7f\xec\xc3\xe6\x26\x2f\xe9\x16\x1b\x53\xde\x99\x91\xb6\x72\x62\x67\x90\x15\x48\x03\x42\x97\x1f\x66\x8a\xd9\xe9\xc6\x5f\x82\x09\xf4\xea\xe3\x4d\x33\xcc\x0a\xff\xad\x05\xd9\x07\xb3\x83\x5e\xba\xbd\xa4\x6e\x59\xb9\xd5\x22\xe9\x4a\x71\xeb\xb9\x4c\x6d\x71\x74\x15\xa2\x72\x40\xb3\x5f\xd3\x11\x5e\x35\x22\xa3\xc9\x48\xe8\x86\x29\xd2\xd4\xc9\x1f\x97\x39\x38\xc4\x1f\x0e\xbe\x7b\xb7\x25\x3c\x34\x58\x22\x95\xe4\x95\x02\x2d\x20\xec\x92\x07\x5e\x0c\x37\x7c\x58\x2a\xe8\x02\x03\x24\xb7\x8c\xb3\x7f\xb1\xe3\x92\x03\xd8\xe9\x4c\x08\xe8\x66\x71\x04\xad\x56\x69\xfe\x32\x82\xa2\xb4\x04\xe0\xdd\x48\x1d\x36\x72\x31\xb5\xcf\x73\xd3\xbe\x4d\x1d\xb5\x17\x75\xe0\x9b\x6e\xc2\x0a\xe6\x32\x5e\x2a\x61\x35\x21\x7d\x9d\xa0\xcb\x7a\x43\xa4\x94\x5c\xd4\xff\x40\xff\xb7\xb0\x53\x40\xbf\xc0\xaf\x90\xf1\x31\xe4\xf7\x97\xf8\x1e\x03\xfd\x2d\x09\xef\x5b\x67\xec\x4c\xe0\x77\xa9\x6b\xf1\x43\x43\xa8\x23\xc6\x05\x30\x0f\x77\x82\x45\xeb\xf5\x58\x65\x46\x11\xd1\x22\x2b\xae\xa4\x55\xf1\x78\x1f\x6b\x38\x9b\xc7\x06\xeb\x98\xb6\x25\x20\x70\xc5\x44\x73\x76\xcb\x60\x26\x7f\x64\xaa\x3e\xf0\x41\x53\x36\x37\x52\x3a\x54\xf5\x9e\xec\xc7\x5a\x03\x2c\xd3\xb6\x6e\xe6\xcb\x0e\x18\xda\x41\x5a\x65\x6c\x92\x28\x6c\xe0\x71\x1e\x13\x62\xfa\x3b\x61\xb8\x44\xce\x52\xd8\xc3\x46\xe9\x51\xeb\x24\x6e\xed\xbc\x1c\xf5\x13\xd7\x22\x37\x5c\x3a\x77\xa6\xf1\x54\xb2\xe6\xaf\xce\x3a\x3b\xd5\xba\x9f\x59\xfd\x02\xd9\x83\x55\xab\xd0\x53\x3d\xab\x62\xfd\xd3\xef\x34\x84\x51\xb0\x8e\x07\xb5\xbf\x8c\x68\xba\xb7\x75\xf2\x96\x3d\x36\x7e\x84\x1f\xd4\x57\x5d\x8f\x84\x86\xb3\xd2\xa9\x67\x78\x9c\xc1\x5d\x4f\xb0\x22\x29\x86\xd6\x30\x6f\x5d\x7f\xc9\xe9\x9a\xfa\x09\x53\xd8\x96\x89\x0f\x6e\x69\x55\x55\x7e\x86\x9a\xec\x5d\x98\x14\x26\x93\x0c\x76\x53\x4c\x5b\x15\x36\x2a\x0a\xba\x4c\x1b\x47\x89\x58\x7b\x5f\xaf\x6e\x31\xb9\x0a\x00\x7b\x23\x9f\x6a\xc5\xbf\xbb\x5c\x07\x57\x12\x61\xb3\x19\x9f\x92\x6a\x99\x03\x75\xb2\x23\x3f\xea\xa4\xe3\x68\xb3\x26\x3a\x88\x33\xfc\x4f\xbd\x3a\x4a\x96\xb4\x90\xe4\x09\x6a\x3d\xfe\xd7\xb9\x3f\xb2\x48\xac\xb1\xa5\x74\x3e\x74\xa4\xf5\x6c\x5b\xea\x0b\x7e\x04\x9d\x91\x36\xde\x20\x5a\x96\x76\x99\xbb\x6d\x89\x91\x2f\x24\xe1\x10\xbd\xe5\x0d\x21\xa2\xf7\x84\x78\xac\x04\xdc\x5b\xeb\x44\xbe\x5b\xee\x2a\x88\xdd\x6c\x79\x14\xa2\xd0\xa1\x8f\x7e\x6e\x77\xe9\xb3\x0f\x3d\x76\xdc\xd6\xbe\x39\x3d\xb9\x86\x0d\x1a\xac\xa2\x1d\x0d\xdb\x29\xc2\x13\x29\xfb\x98\x44\xc1\x5a\xbe\x29\x95\x17\x16\x39\xd7\x3b\xb5\x7c\xad\x26\xde\xbf\x9c\xa4\xb4\xea\xf3\xce\xcd\x30\x4c\x39\x04\x76\x12\x17\xb1\xe6\xa8\x88\x8c\x2f\x8c\x11\xbf\x01\x59\xcb\xd7\x7f\xd5\x43\x23\x82\xe7\x49\xa0\xa1\x62\xaf\xf4\xdc\x10\x85\x43\x7f\x9e\x2c\x81\x90\x8c\xeb\x9f\x13\xd8\x45\x2a\x1f\x59\x31\x6e\xf6\xc8\x36\x42\x04\xca\xb6\x9b\x19\x4d\x40\xec\x77\x41\x32\xdf\x96\x5c\x40\xbf\x49\xb0\x32\xd1\x18\x83\x05\x4f\xfc\x49\xd0\x5b\x22\xaa\x76\x34\x44\x0b\x16\x02\xf4\xff\xd4\xbe\xbd\x65\xd1\x9b\x2a\xf8\x47\xc5\xcf\x8b\x00\xa1\x81\x11\x89\xbe\x5c\xbd\x92\x12\x34\x09\x7a\x47\x28\x85\x65\x44\x5f\x2f\x54\x4a\x89\x1f\xb8\x5a\x68\x8e\x39\x41\xf3\x70\xf1\x00\xf5\x52\x8f\xc6\x29\xad\xc2\x4e\x76\x45\x58\x2f\xd2\xd7\x35\xf9\x76\xa5\xb7\x94\xc2\x4b\x70\x97\xa2\x85\x71\x24\xfc\x6b\x03\x9c\x08\xc7\xa7\x7e\x94\x1c\x96\x0d\xf5\x88\xc3\x24\x0a\xdc\x9a\x09\xe8\xe7\xee\x84\xb4\x36\xd4\x78\xa8\x8f\x80\xec\x7a\x0a\x2d\xdb\xfd\x11\x35\x2d\xd5\x32\xb4\x13\xf5\x17\x38\x0f\xf3\x9e\x54\xd7\x83\x9c\x59\xe1\x9c\x40\x68\x2b\x13\xfc\x50\x7d\x18\x2f\xcd\x38\xaa\x3d\x47\x1c\x09\x0f\x8a\x10\x65\xaf\x20\x6b\xf8\xec\x14\xd8\x19\x68\x11\x03\x2a\xfc\x88\x8b\x91\x48\x1e\x19\x81\x19\xd5\x19\x97\xc1\xf2\x46\x6b\x5c\x26\x6c\xf5\x84\x84\xbe\x87\x90\x2a\x21\x69\x45\xe2\xfc\x9a\x82\xb3\x09\x62\xae\x30\x53\xe7\xbd\x9e\x85\x9a\xf7\x0c\x0a\xd0\x70\x81\xbe\x3c\xbe\xde\x4b\x72\x12\xea\x82\x53\xeb\x6d\xad\xea\x8b\xc6\x8b\x64\x80\x0f\x05\xc9\xe6\xdc\x58\x28\xaf\x12\xf2\x01\x05\x03\xe7\xdf\x25\x23\xc4\x3a\x84\x07\x97\x02\xfe\x82\x77\x7a\x0e\x83\x69\x16\xcd\x09\xef\x77\x4e\x18\x79\x1a\xb2\xc6\xef\x74\xd1\x58\x8a\xc9\x52\x7b\x3e\xae\x37\x09\x36\xc0\x4c\x6b\xcf\x1d\xc5\xc3\x76\x21\xa1\x9b\xc5\x15\xd1\x28\x68\x8e\xae\x72\x20\x1a\xda\x26\x59\x04\xa0\x9d\x89\x06\x91\xb5\x19\x56\x00\x38\xed\xf7\x07\x16\xe3\x16\x47\x88\x0c\x2e\x0d\x2b\xc1\xba\x53\x6f\xd2\xcf\x51\x97\x50\xad\x2e\x6c\x97\xcc\xc0\xdb\xec\xbe\x50\x70\x0a\x75\x83\x9c\x71\x3d\xda\xbd\x42\x31\x42\x35\xe4\x85\x76\x77\xd5\xa0\x19\x75\x1a\x3e\x37\xcc\x71\x27\x63\x5d\x58\x6c\x49\x5e\x92\xe9\xbe\xc8\x54\xba\x31\x0a\x8b\x8b\xcf\x5d\x08\xa1\x44\x66\xfd\x5c\x7d\x5e\x4f\x55\x5f\x91\xd8\xb2\xf8\x45\x52\x54\x1a\xfb\x6c\x25\x98\x32\xa1\x68\xc4\x8d\x5d\xfa\x1d\x22\xff\x9e\x4c\xa1\x00\x8b\x76\x17\x76\x49\xef\xbe\x41\xfe\xd0\xe8\xe0\x33\x19\xfd\xa0\x3f\xc0\x6f\xdd\xb6\x9f\x1c\x1b\x28\x8b\x76\x09\x15\x65\x89\x68\x33\x03\xe5\x45\x08\xff\xf3\x00\xfb\xcb\x6f\xda\x70\xe1\xb6\x36\xdf\x75\x74\xa4\xe0\x1c\x56\xd8\x00\x71\xcf\x1f\x66\xdf\xaa\x0f\x22\x8d\x83\x07\xbb\x61\x84\x0c\x5d\x10\x05\xb8\x10\xbb\xfa\x3c\xe6\xe8\xb4\x9f\xfd\x4c\x8d\xaa\x68\xcd\xf8\x4d\xb0\x88\x67\xe7\xd9\xb0\xe0\x20\xd1\x48\xaf\xea\xa7\x60\x9c\xec\xdc\x39\x2b\x2c\x0a\xe1\x48\xd5\x31\x92\x09\x40\xdd\x8e\x63\x08\x91\xee\x26\x91\x43\xae\x92\x39\xab\x29\x11\x6b\x92\xbf\x3c\xf9\x0b\x37\xff\x89\xe9\x3c\xef\xc3\xe4\x20\x0f\xf2\x9d\xeb\xf9\xdb\x93\xf0\x81\xa9\x78\xf7\x71\x4c\x96\xa4\x78\x8b\x74\x67\x05\x8d\xd9\xc2\x37\x25\x9e\x4e\x93\xd4\x29\xf8\xb8\xe7\xe1\x70\xf1\x48\xe9\x97\x62\xaf\xe0\xea\xbf\xa5\x37\xf4\x83\xbe\x1c\x22\x4c\x50\x68\xdd\x6d\x8c\xef\xe8\x7e\x22\xff\x6e\xae\x45\x79\x48\xfe\x5d\xde\x04\x40\xf9\x2f\x4e\x86\xd4\xb4\xec\x9d\x02\xb5\x2d\x06\x11\x8c\x11\xa9\x58\xd7\x63\x3a\x8f\xf5\x25\x94\x79\xd6\x1b\x70\x60\x03\x31\x53\x9a\x97\x08\x8a\xc6\x64\x21\x0b\x35\xf4\xea\xa1\x41\x32\xf2\x11\xe1\xb5\x13\xc1\x0b\x6a\x44\xcf\x6a\x77\x31\xfd\x08\x0c\x7d\x5d\x3d\xaa\x2b\x2a\x86\xfd\x98\x53\x04\x3e\x5b\x78\xb0\x6a\x7a\x38\xd9\x9d\x54\xa5\xb3\x03\xde\xbe\x09\x7d\x59\xbb\xf2\x3e\x6c\xe2\x67\xa7\xed\xf3\x76\x8d\x6e\xa6\xb4\x78\x57\xad\x5c\x38\x36\x13\x38\x81\xd1\xcd\x2f\xd9\xfb\xc7\xb0\x0c\x36\x84\x47\xea\x92\xaa\x7b\x30\xd2\xcc\xe4\x96\x26\x3f\x18\xd1\x4b\x65\xc2\x8f\x27\x4f\xe7\x19\xdb\x27\x29\x2b\x94\x71\xec\x1d\xd3\xb5\x6f\x51\x36\x53\x33\x4c\x18\x1d\x7b\x8f\xfa\x1e\xb5\xf7\x6b\x2f\xc3\x23\x94\x3e\xf2\x8c\xb9\xa1\xf8\x3e\x7e\xb6\xa9\x6b\x28\x82\xa8\x0f\x72\x21\x3a\x84\x7f\xc2\xb4\xf4\x7e\x1e\xb3\x67\x44\xd5\x34\xff\x95\x48\x10\x9b\x63\xc3\x72\xf8\xc9\x3d\xe5\x33\xdd\x4f\x51\x2e\xc1\x62\x92\x0b\x5f\x7c\x90\x77\x53\xbd\xcb\xe0\x64\x62\xdc\x07\xe3\x7c\x35\x23\x12\x34\xac\x2b\x76\x55\xb0\x3a\xff\xf6\x1d\xbd\x35\xf4\x30\x11\x15\xff\x16\x9c\x0b\x6d\x00\x1a\x10\x71\x6a\x35\xfe\x03\x6e\x76\x7a\x06\x38\xc1\xaf\x8e\x4a\x45\xfd\x4c\xcd\xd0\xcb\x1e\x8f\xf2\xa2\xd6\x1e\xf9\xe3\x0c\xfa\xba\xd4\xe1\x8c\xaf\x49\x49\x1a\xbc\x6a\x2d\x77\x03\xd4\x9c\xbb\xdd\x0f\xb0\x11\xd3\x29\x2b\x81\x30\x11\x13\x61\xa2\x07\xe6\x37\x43\xad\x3a\x31\x79\x8c\x3b\xe6\x5a\x5f\x5d\x62\xe5\xd4\x79\x12\x40\x54\x50\x7b\x4b\x52\xfb\xe8\x95\xcd\x2a\xaf\xf8\x91\x2f\xa5\x49\x7d\x15\xba\xcc\x26\x2a\xbb\x42\x5f\xaa\xee\xdb\xf2\x6f\x70\x8f\x2c\xae\x4d\x2b\x29\x42\x6f\x70\x73\x38\xea\xc2\xe2\x2b\x44\xf0\xde\x2e\xc5\x6e\x5f\x6b\x1d\x4f\x43\x97\xc9\xbc\x3c\xb5\x1c\xb9\x43\x09\x8a\xa8\x14\x9a\x7d\xfd\x75\x7a\x18\xec\xc8\x2f\xce\xb4\xb0\xd8\x63\xd7\xf8\x84\x90\xb5\x4d\xe2\xbc\xf3\x80\x4a\xa2\x36\x35\x9f\x03\x5a\x5c\x4a\xe4\x56\xe0\x00\x8f\xbe\x14\x87\x1c\xed\xb4\xa2\x90\x70\x14\x98\x35\x32\xd7\x8a\xfa\x0e\x48\x4a\x53\xa2\xc4\x25\x16\xf6\x12\xde\x22\xd5\xeb\x05\xbf\x84\x58\x22\xee\xf2\xab\x79\x93\x4c\x90\xa3\xe7\xf0\x1c\xb4\xe5\xcc\x98\x1c\x6c\x7c\x71\x2f\xd5\xcf\x98\x54\x61\x85\x5a\x7b\x2b\x57\xcb\x4f\x82\x95\x39\x8a\xbc\x05\x12\x74\xc2\xb4\x91\xa9\xcb\xd5\xc8\xc5\xa4\xd1\xad\xa4\x8f\x0c\xbc\x97\xab\xe6\xae\xca\xa0\xb2\xbd\x24\xde\xbc\xc0\xb2\x24\x27\x77\xd8\x83\x46\x30\x8b\x24\x4b\xba\x38\xc9\x5a\x1e\x7d\x25\x61\xbb\xed\x22\x2d\x3e\x51\xc4\xf7\xeb\xa1\xdf\xaa\x38\x92\x05\xf6\xa5\x41\x89\x76\x2e\x26\x4f\x44\xd2\x27\x3a\x7c\x7e\x6d\x2f\x27\x3b\x3f\x86\xba\x61\x48\x4f\x5d\x1e\xb1\x5a\xeb\xcb\xa0\xad\xca\x4e\x88\x96\x0d\x20\x2c\x9d\xa8\x1b\x58\xf6\x7c\x9e\x1f\x83\x6a\xee\x6f\xe5\x3d\xaf\x13\xa0\x61\x4c\x31\xd9\x8a\x82\x29\xb7\x35\x6d\xd2\x6f\x9f\xdf\x53\xbe\xf6\x62\x88\x88\xea\x12\xc0\x98\xc2\xfd\x83\xd8\xd9\x23\x21\xdd\x15\x6e\xf7\xd9\x15\xeb\x07\xbe\xbc\x18\x9b\xe2\xe9\x6c\x7e\x21\x21\x81\xfe\xc0\xbe\xa4\x88\x3a\xe6\x91\x23\xf7\x92\x57\x8d\x90\xe7\x49\x3a\x41\x72\xe1\x10\x73\x13\x4a\xce\x19\x49\xf6\xaa\x6a\x5f\xd5\x91\xa3\xa7\x16\xc8\xe0\x18\x50\x90\xf7\x90\x65\x2a\x2a\x8e\xff\x70\x37\x08\x84\x44\x87\x2e\xbf\xa7\x80\x40\x39\x9e\xe8\x79\xde\x36\x42\xa8\x43\x51\x38\x68\x80\x52\xac\x8b\xdf\xcc\x43\xe5\x66\x34\xe1\x56\x61\x17\xa4\x3b\xef\x99\x52\xe4\x69\x73\xcc\xb7\x59\xfb\xf1\x72\xb2\xce\x30\x47\x7f\xdd\x51\xf3\xd3\xaf\xd5\x8f\x98\x08\x5c\x21\x5a\x5d\x10\xda\xf7\x71\x2d\x73\x28\x76\x54\x35\x4e\x7b\x3a\xb4\x08\x94\xf8\xe9\x52\x74\xec\xc6\x56\x27\xe1\x26\x0e\xf3\xdc\x0c\x3b\x18\x77\x0a\xc9\x77\x8a\x37\x47\xc2\xd6\x79\xa3\xd5\x89\xd2\x21\x90\x3f\xf4\xc0\xf0\xd4\xe7\xd5\xab\xf4\xf9\x29\xe9\x33\xa5\x63\x8a\x7f\xc4\xaf\x56\xc5\x82\x3c\x1e\x87\xd1\x48\x31\x76\x9c\xe0\xd4\xc8\x51\x85\x21\xf6\x79\x00\xeb\x22\xca\x82\x78\x2f\xc8\x1f\x20\xe3\x85\x48\xc1\x33\xac\xc8\xc9\x99\xbe\x8f\xac\xda\x91\xca\xa8\x7e\x4b\x44\x9f\x42\x74\x65\xb4\x6f\xa8\xb5\x10\x29\xdd\xa1\x0a\xf7\xd2\x88\xb7\x21\x8d\xe6\x13\x53\x84\xda\xa1\x3d\xa8\x5d\x0a\xb9\x2a\x2a\x0a\xba\x4e\x48\x24\xda\xdd\x41\xd5\x70\x51\xdd\x17\xc6\xf4\xe6\xff\xb0\x23\xea\x66\x30\x67\x85\x0c\xf6\x0b\x67\xaa\xf5\x26\x2c\xac\x0b\x23\x61\x7d\xf5\x63\x4a\xc8\x18\x74\x57\xdd\x08\x6c\x69\xa5\x2e\x9f\xff\x5a\x70\xeb\x87\x4b\x13\x0f\xf5\xb0\xae\x06\xa3\xe0\x07\xe0\x98\x34\xfd\x99\x49\x46\x4e\x88\xb8\x08\xc5\x18\xdf\x28\x22\xfc\x15\x70\x57\xed\x24\xe1\x72\xf2\xd4\x21\x55\x94\xc3\x77\x6d\x68\x40\xee\x17\x18\xce\xcd\x3d\x89\x05\x4c\x03\xee\x3e\xcd\x7b\x99\xa1\x3f\x0d\xe0\x56\x6d\xe9\xc0\x6a\x12\x92\x7c\x7a\xc7\x00\xa9\x5f\xb6\x03\xcc\xfc\x83\x8a\xce\xcc\xee\x32\x1f\x63\x0a\xf2\xad\x27\xd4\xae\x51\x64\xa3\x24\x2b\x5c\x76\xd6\xaa\xf9\x52\xc8\x81\xe5\x9d\xff\x18\xec\xdc\x63\x05\x8c\x9a\x33\x22\x48\x4e\x33\x8b\x73\xe6\x42\xf8\x02\x87\x22\x58\xd3\xec\xf9\x60\x64\x0f\xe6\x8f\xf4\xc1\xbd\xbd\xbe\x4e\x9f\x06\x96\x67\xf3\x3c\x8b\xbd\x09\xcc\x22\xc7\xfb\x2e\x2a\x06\x73\xf1\x71\x5c\x42\xec\x99\xb1\x0e\x55\xed\x4d\x2b\x5f\x2a\x68\x55\x86\x80\x3e\x3d\x42\x42\xe1\x94\x11\x71\x1a\x6c\xbd\x9b\x35\x64\x1c\xf4\x68\x24\x21\x7d\x20\x53\x07\x15\xc1\xf3\xb6\x90\x88\xd0\xef\xd4\x51\x72\x26\xff\x3e\x93\x69\xf1\xb9\x14\xf7\xb6\x20\x65\x7d\x07\xba\xd1\xc6\x60\x01\x9c\xc6\xc0\xaf\x3b\x09\x9a\x2e\x4a\x9e\x6b\xbc\x16\x97\xaa\x2e\x3e\xc5\x3c\xe7\x50\x39\xf5\xae\xc0\x73\x66\x9a\x4c\x15\x37\x41\xf0\x96\xe7\xc4\x11\x0d\xf8\x48\x7d\xbf\x84\x32\x5e\xe6\x15\xd2\x5a\x9e\x70\x71\x4d\xb4\x34\x6e\x7d\x47\x78\x3f\xb9\x25\xea\xa7\x4c\x79\x7e\x7c\x9b\x01\xd6\xea\xde\x48\xaa\xa8\x74\xa9\xd3\x95\x0b\x48\xf6\xd6\x1b\x50\x9b\x29\x5d\xf5\xe0\x7a\xb7\xef\x78\x5f\x7a\xf6\x93\xe8\xb5\x20\xfc\xb7\xe7\x9e\x2d\xf9\x98\xff\xc9\x93\xce\xed\xd9\xcc\xbc\xee\x3b\xf2\x83\xac\xf6\x29\xe1\xaf\xd5\x76\x69\x5a\x1e\xff\x39\x4b\x8f\x44\x82\xe9\x64\xed\xf3\xae\x69\x3c\x98\xe1\x60\xbb\xc9\x2e\xc0\x60\x4b\x79\xe3\x5c\xd4\xc5\x27\xc3\x4e\xe5\xd7\x0a\xea\xc4\xa6\x67\x6d\xc3\x9a\x7d\xa7\x9d\xac\xd8\x10\xcb\x1f\x1d\xec\x3d\x1d\xd6\x2f\x8d\x0e\x51\x6b\x5e\x82\x6b\xe0\xdf\xcc\xaf\x3f\xc8\x1e\x86\x9b\xb6\xe4\xb0\x37\x90\xc4\x97\x6b\xd4\xb8\x77\x09\xf7\x86\x31\xa7\xd1\x6a\xe6\xb0\xec\xbe\xf2\x02\x9e\x63\xa3\x96\xfe\xc6\x52\x0c\x7a\x52\xbf\x00\xa9\x52\xa1\x00\x74\xdc\x71\xd9\xc9\xb4\xed\x14\x23\x26\x7b\x84\x9b\xb3\xae\x46\x67\x96\xa2\xa8\x86\xb5\xbe\x1f\xec\x75\x63\x30\x32\xc1\x4e\xca\x4e\x6a\x83\x47\x95\xd0\xc7\x92\x70\x6b\x76\x40\xe4\x62\xa5\xf9\x74\x0c\x5a\xf9\x37\x00\x61\x02\x89\x89\x05\x02\x63\xef\xa0\x2a\xa2\x6d\xfc\x15\x48\xa8\x73\x09\xe5\x63\x80\x53\x5a\xa2\x98\x2e\xbc\x75\x14\x57\xf5\xbd\x7a\x80\x2b\x83\xfa\xd7\xf7\x44\x0b\x1f\x7b\xdd\xc6\x16\x6d\x1d\x78\xc1\xfa\x8e\xde\xd0\x23\xeb\x4a\x3b\xb2\xa4\x43\x32\xd7\xdb\xa3\x46\x83\xf2\x95\x98\x5e\x78\xe1\x1d\x18\x5d\x7f\x69\x0f\xb1\x97\xfa\x53\x85\xd4\xd7\xb5\x3f\xd4\x04\x8a\xba\x7c\x40\x19\xe1\x51\xc1\x67\x6a\xc2\x10\xaa\xae\x34\xfd\x9e\xa1\xb9\x91\x29\xc4\xe3\x11\xcb\x96\x28\x57\x38\xfe\x84\x0c\x5d\x90\xe0\x6a\x53\x37\x90\xf4\x52\x46\x4e\x6f\xfb\x90\x86\x4f\x8a\x82\x23\xe6\xdc\x34\x40\x42\xf7\x07\xdf\x10\x6a\xff\x8b\xfb\x32\xbb\x1d\xe9\xa4\x46\x0f\x7c\x20\x76\x91\xa0\x98\x07\x39\x52\x97\xcd\x54\x21\xa1\x7e\x3a\xf6\xbd\xab\x49\x05\x54\x83\x67\xc6\xcc\xba\xed\xbe\x86\xef\xf7\xc9\xdd\x83\x8e\xee\xb2\x4d\x03\x46\xe5\x66\x83\x77\xb5\x24\x07\x6c\x5a\x91\x0e\x1d\x46\x5e\xfa\xab\xa9\x11\x5e\x6a\x41\x56\xd6\x08\x5d\x5b\x24\xb2\xf2\x10\x56\xda\x9d\xb6\x8c\x6e\xa7\x05\xb1\x60\xec\x8a\x26\xb1\x37\x6a\x21\xe6\x24\x23\x42\x3e\xa5\x26\xe5\x89\xc2\x09\x18\xd5\x84\xd9\x42\xf2\x99\x4d\x08\x99\x48\x3f\xda\x51\x00\xae\x33\x5f\x1c\x34\x84\x86\x64\x13\x17\xe4\x1f\x1b\x24\xe0\x59\x7f\x71\x3f\x41\x68\xc2\x76\xdf\xd3\xb8\x7a\xb2\x3a\x24\xb2\x48\xb5\xc9\x1b\x74\x3b\xb6\x97\x5d\xfd\xa4\xf6\xcc\xc7\x06\xdf\x38\x34\x28\x10\x26\x89\x6b\x10\x5b\x08\x37\x8a\x74\x43\x3d\x2e\xc9\xac\xc0\x57\xf4\x39\x09\x83\x63\xed\xd2\x10\x40\xb1\x0b\x96\xd3\x71\x14\x63\xbc\x90\xe8\x34\xc3\x99\x2d\xc0\xc2\xd2\xf4\x17\x1e\x1b\x36\x07\xd7\x45\xa2\x67\x11\xe3\x0c\x15\xc0\xac\xe9\xb0\x35\x31\xae\x1f\x9e\xec\x80\x74\x1e\xe4\x2c\xec\x03\x11\xa0\x10\x28\x74\x61\x0d\x80\xda\xeb\xdb\x65\x2f\x9d\xa4\xf1\x04\xcf\xd9\x13\x1e\x2d\xb3\x4a\xd7\x86\x25\xe5\x58\xc3\x23\x7f\x05\x97\x6d\x10\x76\xe2\x4d\xa8\x18\x7b\x02\x85\x42\x94\xf6\xac\x15\x41\xaa\xdb\x40\x48\x94\x00\x39\x74\x73\x2c\x03\x98\x5c\x76\x00\x29\x76\xb4\x35\xee\x67\xaa\x4b\xd4\x18\xd3\xe6\x28\xf6\x53\x75\xd5\x4a\x57\x41\x13\xd7\x9f\x0f\x15\x29\x90\x33\xdc\x3f\x01\xa0\x7e\x1c\xd3\xaa\x11\xf9\x01\xcf\x5c\xf6\xd8\x00\xea\xda\xd8\xc3\x0f\xd9\x5a\x19\x8c\xf3\x9e\xbf\x7e\x98\xb7\x75\x64\xb4\xae\x24\xd7\x6d\x2e\x7b\xe8\x77\x7f\xcd\x5c\x97\x1a\x03\x23\xcd\xc4\x3d\x03\xb3\x01\xef\xdb\x35\xe1\x1f\xe1\x10\x24\x06\xa6\xba\x95\x5b\xdf\x6f\x31\x7a\x80\x51\xa8\x20\xa2\xcf\xa7\x3a\x9b\x7a\xda\x15\x9c\x23\xeb\xaf\xbe\x72\x04\x4a\xd2\xa6\x5a\x88\xbf\x1d\xa1\xdd\x60\x5a\xf6\xd5\xc3\x0d\x64\xe4\xc9\x55\x80\x07\x08\x06\xfa\x04\x54\x7b\x79\x79\xea\x50\xf6\xa9\xa3\x93\x50\x7b\x5e\x6f\x44\xf1\x79\x20\xe0\x13\x6a\xcb\x46\x1d\xaa\x57\x08\x7f\x97\x55\x71\x3f\xec\x87\xe9\x38\x9c\xb9\x24\x56\x04\x20\x4d\x65\x51\xd2\x31\x46\x9a\xa0\x1e\x44\x16\xd2\x7e\xba\xd1\x6c\xce\x70\x6d\x0a\x11\xeb\x2e\xe2\x95\x54\x79\xbd\xae\x9a\x1d\x17\xdd\x53\x75\x67\xf1\xf6\x4a\x22\x65\x80\xf7\x45\xbc\x21\xc6\x59\xa3\x8e\xed\x06\x68\xfd\x1a\x32\x85\x95\x35\x51\x46\x04\x63\x52\x3c\x06\x94\xf6\x9a\x3c\x52\x8f\xff\x6d\x3d\x37\x73\x19\xcc\x6d\x92\x6f\x0a\x24\x26\x97\x0b\xf9\xab\x35\x95\x57\x17\x86\x32\xd3\xe8\xa3\x57\x71\xa9\x55\xdc\xde\x02\x12\x73\x41\xc4\x44\xa9\x85\x73\xb3\x0e\xe9\x28\xab\xca\xb3\x6a\x8e\x88\xbb\xcc\x94\xc2\x16\x12\x4f\xe0\x11\xa7\x0b\x36\x89\x95\x02\xc7\xfb\xc5\xb1\x1d\x3a\xc3\xbd\xc8\xc0\x4c\xf2\x2b\x0d\x26\xc1\xfa\xc2\xe0\xa5\x13\xb0\x6e\xf3\x25\x5d\x15\x85\x1d\x39\x4a\xbc\xaa\x97\x40\xf5\x9b\xba\x4a\x46\x1f\x27\x7d\x5b\x2f\x9e\x66\xcd\x71\xed\x19\xa8\xca\x49\xdd\xdf\xa5\x5c\x49\xe5\xc0\x5b\x81\xd9\x63\xf3\xe3\x5c\x20\xb9\x63\x52\x30\x59\x97\x88\xb8\x25\x67\x32\x55\x30\x54\xa1\xc3\xf7\x0d\x67\x44\xce\x41\xa3\x4a\x48\x5a\x9f\x9b\x15\x99\x00\x92\xd1\x1a\xc8\x0c\x21\xc1\x4a\x38\xa0\xf6\x81\xf7\x7e\xe7\x50\xd9\xa1\x78\x44\x6d\x35\x14\x46\xdc\x4d\x43\xe4\x9b\x60\x61\xc9\xbc\x41\x83\x3d\x72\x99\x7f\xb2\x51\x17\x89\xf4\x54\x55\x3f\x11\x82\xc4\x47\xfa\x59\x0c\x28\xd0\xca\x2e\xfd\xa4\x1c\xd8\x8b\x99\xfb\x78\x89\x8e\x17\x57\x02\x23\x3d\x45\xdb\xad\x53\x3c\xb6\xd2\xa1\xd8\xed\x7d\x3c\x74\xdb\x85\x7b\x98\x2a\x8f\x2b\x0e\x55\x5e\x4e\xb5\x6e\xf8\xbc\x4c\x29\x1a\x5c\x5e\x7e\xfc\x51\x2e\x5b\x5a\xd0\x02\x62\x91\x34\x12\x04\x76\x64\xb7\x3f\x6b\x3c\xe1\x26\x9e\xc2\xef\x0f\xf8\x67\x3c\x03\x97\xc4\x7c\x5e\xb3\x70\x7d\x83\x2d\x27\x2b\xb3\xe7\x50\xcf\xf1\x4b\x6b\x38\xb7\xd7\xba\x7b\xbf\x13\x20\xbe\x72\x13\xef\xc8\x51\xd0\xd9\x08\xe4\x4a\x59\xfa\xe7\x8a\x1d\x75\x84\xc2\xfb\x4a\x9b\x8b\xaa\xfe\xfa\x7c\xd5\xe4\xbc\x29\x49\xb8\x16\x84\x86\xa5\xed\x8e\x28\x60\x4d\x1a\x55\xa2\x3e\xed\xc2\x85\x02\x10\x5f\xe9\x7e\x78\x8a\x56\xbe\x11\x49\x5c\x68\x85\x8c\x7d\x9b\xab\x0f\x86\x69\xd2\x89\x18\x13\x67\xd1\xe2\x46\x42\x99\x68\x18\x9a\x60\x86\xd5\xbd\x3a\x27\xd5\x79\x3b\x9c\x8a\x5a\x2e\x61\x47\xb5\xce\x8a\x29\xd2\x1d\xe5\xc3\x80\xa4\x9d\xf2\x4f\x8c\xd3\x8d\x9d\x8f\x80\x67\x14\x48\x42\xd2\x37\x31\xd9\x0a\x21\xfb\xa0\x11\x93\x6f\x94\x32\x5f\x44\xf6\x83\xa9\x1c\x5f\x5c\x23\xf2\xc7\x1f\xd1\xc9\x02\x88\xeb\xe9\xa4\x68\xae\xb9\x23\xf0\x89\xe8\xf7\xc7\x6e\xc5\x58\xd9\x91\xce\xc2\x22\xb7\x6f\x17\x22\x24\xe0\xc8\x4a\x0c\x3a\x12\xe4\x02\xe3\x70\x30\xba\xeb\xb0\x70\x10\x0b\xae\x87\x12\x68\xb0\x40\x11\x2e\xaa\x37\x09\x19\x01\x26\x70\xeb\x70\x88\x5f\x89\x59\x87\x70\x6a\x62\xe7\x40\xed\x79\xc7\x88\x85\xb0\xa5\x91\x2c\x2b\xb0\x91\x74\xe1\x02\xa9\xec\x3f\x6d\xfa\xe9\xe5\x7b\xf9\x9a\x92\x96\xe7\x77\x88\xcf\x60\x17\xa2\x64\x93\xbe\x0f\xc2\xc7\x43\x9d\x63\x3a\xff\x01\x22\x48\xdb\xd3\x26\xab\xb7\x81\x55\xd4\xb3\x84\xd2\xdb\xf0\x27\x41\x4b\x1d\x8f\x07\x06\xc3\xeb\xd2\xee\x39\x16\x3c\x07\x24\x1b\xbf\xad\x64\x50\xe9\xe8\xec\x9e\x84\xc5\xcb\x39\x7d\x9b\x8f\x96\xbf\x72\x9e\xe0\x10\xba\x59\xba\xa4\xa7\x57\xa6\x98\xf9\xd3\xed\xea\x30\xd1\xd1\x19\x2e\x5e\x96\x06\x24\x5a\xa7\xde\x4e\x3c\xa8\x62\xa8\x84\x22\x80\xe2\x10\x49\xbb\x33\x18\xc7\x7e\x28\x26\x26\xb2\x8d\x7c\xc3\x48\x90\x51\x45\x6c\x6d\xaf\x29\x27\xe4\x68\x83\x4d\xf4\xbc\x54\xa0\x4b\x8b\x8b\xf3\xe8\x9b\x06\xcb\xc8\xb3\x2e\x05\x59\x32\x93\x20\x2a\x27\xf3\x56\xd3\xbe\x3e\x7c\xff\x6a\xaa\x6f\xff\x50\x6d\x32\xd3\x64\xc0\x45\x9a\xb9\x1f\x78\xc7\x7b\x31\x35\x8d\xca\x49\x01\xe4\x9d\x2f\x70\x9f\x6c\x81\xee\xc1\x0d\xc1\x8e\x09\xe8\x7d\x0c\xbf\x46\x72\x87\x42\x81\xb4\x5e\xb9\x30\x44\xa1\x8d\xac\x37\x40\x0a\x31\x10\x4c\x49\x26\xc2\xa5\x67\x5b\xaa\x66\x53\x92\x2d\x24\x1f\x0d\xe9\xe4\xf0\x7b\x78\x93\x6c\x00\x03\x83\xc5\x30\x64\xee\xfb\x7e\xcb\x53\x6a\x03\x19\x46\xfc\x2c\xaa\xb5\x67\x28\x08\xe0\x07\xf2\xa6\x09\xfb\x6f\x63\x09\xad\xf4\x5f\x80\x8b\x0a\xe2\x08\xdf\x4d\x9e\x06\xa8\x1b\x94\xfb\xa0\x57\xb8\xa3\x85\xc2\xfa\x83\xcf\x11\x03\x48\x2d\xc8\xa2\xc9\xab\x91\x54\x53\x02\xb6\xb1\x1a\x83\xc9\x24\x99\x76\xe2\xff\x41\xbd\xb3\x6d\xfa\x21\xbf\x7a\xb9\x04\xc0\xae\xe3\xf9\xe3\xa0\xa3\x3f\x6c\x2f\x29\xbf\x97\x40\xc9\xb6\x4d\xbf\xd7\xdc\xff\x9a\x36\x42\x11\xe6\x66\xbe\x79\x94\xb9\x52\xf6\xfc\x53\x17\xcc\x25\x8c\x33\xbd\x7c\xb1\x70\x88\x2e\xd7\x41\x2f\xaf\x33\xde\xbf\x4a\x0f\xd7\xf0\x8c\x04\x26\xde\xdb\xa4\xb8\x98\x18\xcc\x11\xbc\x94\xfa\x4e\xde\x1a\xf7\x68\x36\xe4\x61\xbf\xf2\x2e\x21\xb8\xcb\x85\xca\x4f\xd7\xce\xbe\x1f\x5e\xa1\x89\xac\x05\xc0\xcd\x73\x41\x7d\x97\x0a\x68\x44\x66\x77\xfe\x1c\xb3\x64\x9b\xf9\xea\xaf\x47\x23\xbd\xe3\xa3\x42\xe5\xf9\x5b\x47\xb7\x5a\x91\x7c\xde\x13\x69\x1c\xc2\x35\xcc\xe9\x80\xbd\x18\xf3\x78\xb8\x1a\x64\x13\x94\x60\x0a\xa3\x88\x05\x9d\x37\x80\x25\x66\x40\xf1\x36\x09\x65\x86\x64\xa6\xdb\xa5\xa6\xb5\x9c\x72\x27\x87\x34\x8e\x88\xf2\x29\x53\xf2\xe5\xdf\x12\x60\x51\x22\x2e\x2c\xc7\x65\x02\xf2\x3c\xbb\x37\x01\x9c\x8b\xd9\x76\x9e\x4a\x99\x6c\x57\xdc\x3b\xa1\xe5\x1a\x8f\xb4\xba\xe6\x58\x4a\x3b\xa1\x73\xf9\x31\xde\xa0\xf3\xef\x3b\x3b\xbb\x37\x24\x9c\x20\x55\x3c\x9d\xde\x67\xbb\x8c\x89\x36\xd4\x10\x18\xb1\xe0\xa1\x3b\x94\x3b\xac\x6d\xdd\xfb\x0a\x43\x57\x67\xd8\x57\xfa\x8f\x85\x37\xc8\x0a\xbd\x88\x96\x0c\x63\x73\x47\xec\x0d\xdf\xa7\x5d\x4c\xf3\x15\xc3\x30\x52\xdb\x20\x6c\xf3\xef\x93\x20\x28\x05\x31\x08\xd9\xaa\x40\xd2\x67\x6b\xdc\x50\x8b\x7c\x55\xdf\x78\x43\x57\xcf\x5a\xa5\x9f\xbc\x2b\x7e\x45\x36\x5b\x22\x00\x7d\x5b\x99\x25\xa1\x4d\x98\xcd\x9f\x93\x70\x27\xfb\x3a\x5b\x5c\xbd\x94\xf0\xa6\x1a\x98\xdf\x58\x0e\x85\x23\xca\x27\x05\x17\x04\x75\x51\x02\x8d\xba\xde\x7a\x8f\xff\x25\xf0\x8f\x64\xce\xd3\xdf\x35\xa7\xaa\xed\xdb\x4d\x62\x16\x42\xf8\x72\x8a\xce\x0c\x1e\x78\x96\xa4\x60\x38\x76\xd7\xa3\x2f\x9a\xc8\xfb\xfb\x03\xb3\x6f\x88\xda\x1b\x73\x7f\x9d\x3f\xce\x0f\x69\xfd\xd1\xb9\xab\xdb\x72\x96\x89\x64\x65\xcd\xbb\xf8\x78\x22\x24\xf1\x9f\x04\xea\x93\x23\x88\x82\x4b\x26\xe7\x7e\x23\xc7\x49\x97\x85\x7e\x1b\x8b\xd7\x93\x10\x0b\x0b\xb5\x8f\xd2\x8b\xf4\x74\x54\xf0\xd9\xe6\x89\xd1\x23\x75\x44\x96\x8e\x42\xf8\xeb\xa8\xcb\x50\x42\x9b\x21\xd7\x8c\x2e\x9e\x47\xc4\x71\x6f\xb6\x5c\x12\xa7\x66\xb0\x7b\x70\x36\xd3\xa7\x11\x9d\x17\x93\x21\xee\x7e\xbe\x22\x97\xc1\x4f\x8c\x36\x2d\x8a\x6c\x8a\xb9\x6d\x11\x6c\x52\x79\x0d\x1f\x7c\x4f\x9c\xe6\x86\xed\x90\x44\xff\x73\x78\x18\x0a\xff\x7b\xf6\x20\x4b\x84\x4d\x23\xdc\xc7\xb7\xcd\x2c\x57\x16\x9c\x03\xbe\x70\x40\x5f\x06\xe1\x88\xc6\xf6\xbd\xb6\x60\xda\xb3\x51\x6d\x23\x4e\x5d\x27\x23\x16\x05\x72\x9b\xa5\xf7\x75\x12\xbc\x5d\x77\x08\xad\x0a\xb2\x78\xb0\x93\xca\x63\x34\x46\xb5\x58\xa0\x60\x2a\xdf\x9d\x54\xc1\xaa\x80\xc2\xe3\x17\xaa\x67\x61\x38\x1d\xe7\xa3\x0f\x36\x1a\x3e\x80\x9f\x70\x6f\xef\x02\xfe\xe9\xc4\x18\xc2\x4b\x49\x90\x2e\x87\xb4\x07\x0e\xb4\x5b\xaf\xd3\x3e\x86\xdd\x37\xa2\x5b\xb3\x15\xa4\xec\x6c\x98\x82\x42\x41\xb9\xc0\x11\x73\x4d\xb6\xdd\xe0\xa5\xd7\x50\xea\xf3\xec\x1a\x78\x75\x9c\x28\x12\xa1\xdc\x85\xe0\xcb\xbd\xb4\x72\xf5\x7c\x74\x65\x2b\x04\xaa\xdc\x07\x90\xd0\x1a\xab\x22\xb8\xad\xf3\x00\x1c\x64\x5d\x4f\x2e\xd6\x64\xdb\x20\x1d\x5b\x5c\xdc\x56\xf6\x71\x22\xad\x04\x88\x91\xc6\x06\x6f\xb3\xb5\x29\x0e\x87\x14\x37\x58\x26\xd9\x07\x3a\x85\x1c\x65\x84\x7c\x70\x68\xd0\xab\x3f\x98\x25\x46\xba\x64\x45\x07\x2d\x8f\x03\x5b\xa0\x84\xda\xb8\xa8\x8f\x5d\xac\x60\x2f\x8f\x5f\x96\xc4\xa8\x32\x50\x32\xe8\xf9\xaf\x1c\x8c\x5d\x1c\x15\x0c\x74\x32\xc9\x70\x4b\x05\xfd\xc8\xc2\x90\x70\x6c\xb6\x4f\xe7\xc9\x45\xe7\x0b\x25\xe1\x7d\x69\x64\xcd\xd7\x8c\x46\xaf\xfb\xbb\x89\xbd\x6c\xfe\xfe\xe2\xfd\x4b\x53\x5b\x10\x59\x4d\xaf\x2f\xeb\xb7\xfa\x13\x4c\x10\x56\xc5\xb0\xa0\x8d\xdf\x1b\xfb\x85\xb3\x35\x60\xd5\xab\xe9\xa4\xd6\x20\x0f\x56\x30\x40\x4f\x1d\x01\xf7\x63\x22\x59\x18\xef\x08\x1d\x35\x1b\x3d\xce\xdd\xba\x2b\x4a\x23\x04\x11\x35\xf8\xa7\xc3\x47\x77\x29\xd1\x03\x2a\x92\x44\x62\xc5\x7c\xb3\x4d\xc5\x93\x5a\xab\x6c\xa9\x3d\x47\x86\x0d\xf5\x5d\xf3\xb6\xf6\xb4\x96\x10\xf4\x17\xb6\x21\xda\x41\xae\x0e\x5a\x0d\x28\x93\x91\xf8\xb3\x0b\x78\xdd\x8e\x10\xf8\x60\x51\x35\xef\xd1\x47\xb9\x25\xec\x31\x95\x2d\x26\x70\xf0\x58\xf8\xcb\xab\x7b\x7d\xe0\xa9\xf5\x26\xb2\xa4\x2b\xf0\x9c\xbb\xbd\x01\xba\xbc\xce\xf4\x91\xdb\x83\x34\x02\x11\xdc\xbc\x9a\x2c\xe8\x57\xe4\xef\x66\xea\x04\x2b\xc3\xbf\x5a\xde\x93\x5c\x3d\x5a\xb3\x56\xa0\x34\x4b\x2c\x11\x86\xa2\x41\x38\x96\x90\x4f\x0d\xcc\x7d\x17\x8a\x7d\xbe\xf2\x72\x1f\xd4\x0e\x53\x7b\xd7\x44\x1c\x19\xf4\xc4\x39\xc8\x03\xf3\xfd\xcb\xd6\xfc\x5b\x75\x48\xf5\x4c\xa1\xad\x58\x99\x11\xa6\x29\xa6\x4e\xc8\xe8\x56\xac\x99\x52\xa4\x99\x31\xc9\x01\xff\x0d\x91\xb4\xa6\xa2\x58\x14\xc7\x3a\x85\xad\xa9\xfb\x28\x8b\x77\x9f\xea\xcb\x17\x9c\x68\xed\x19\xc5\x94\x36\x74\x9d\x34\x1f\x65\x8d\x70\xf1\x14\x6e\xd3\x23\xf4\x14\x55\x5d\xaa\x43\x0b\xb2\x29\xe5\x4f\x21\x5a\x2e\x25\x01\xaf\xa5\xb4\x1c\x0b\x51\xf2\x50\xe8\x0a\x37\x19\x24\x41\x50\x2a\xd4\x87\xf8\x35\xb3\xe5\xaf\x67\xc9\x3d\xcf\xf9\x0b\xe4\xa4\x20\x4a\x3f\x0b\xda\xaf\xb7\x36\x53\x9c\x30\xc5\x9d\xd1\x22\x8f\x13\xe5\xfc\xce\x1e\xe6\xef\xb6\x01\xe6\x57\x36\x9a\x45\x0d\x1a\x04\xbe\x03\xfc\x19\x4e\x4d\xb1\x6d\x86\xc2\xae\x04\x22\xd1\xb9\xd1\x56\x1e\xcc\xea\xaf\x74\x6f\xd2\x0c\xa7\xac\xf9\x71\xf2\x53\x93\x52\x99\x4c\xab\x8c\xb5\x51\xf1\x6c\xc6\xd9\x29\x8d\xae\x2f\xab\xc5\x96\x85\x3e\x77\x55\x04\xa5\xe2\x19\xbd\x97\xaf\x1b\xc9\x81\xc7\xcc\x3f\xdf\x4c\x0c\xba\xe3\xbf\x1b\xc9\xa4\x37\x0d\x5d\xa0\x33\x26\x6f\xd6\xf2\x5a\x89\x47\xb3\x4d\x2f\xd6\xa1\x6a\x34\xb5\x32\x5a\xa1\x1b\x01\x6f\x53\xa3\xcc\xf8\x60\x12\xbe\xe0\x3e\x53\xac\xa2\x10\xce\x6f\x8e\x1a\xb7\xc0\xa8\x62\x6c\x73\x29\x6a\x09\x86\xca\x16\xf4\xf5\x23\x2a\x15\x21\xbc\x47\x59\x89\x49\x85\x18\xb1\x8c\x74\x8c\x57\x64\x9d\x42\x8a\x70\xc4\xc3\x25\xa6\xfa\xb7\x4f\x24\xc4\x29\xc9\x79\xe4\x74\x70\x73\x81\xfc\x09\xf7\xa9\xea\x78\x67\x09\x12\x67\x95\x51\x0e\x13\x02\xa5\xe7\x94\x6d\x8e\x25\xbc\x8b\xd2\x66\xb4\x44\x9f\x9e\xea\x7f\xc6\x24\x0a\x17\x2f\x1b\x9b\xb2\x53\xc3\x1a\xde\x4c\xbc\xe1\xb9\xd4\xd9\xf1\xc6\x03\x00\x00\x28\x18\x28\x13\x00\x23\x41\x2d\xe7\x75\x36\x6e\x0c\x79\xe8\xce\xcc\xaa\x33\xdf\x74\x50\xa1\xa2\x0d\x42\xcd\x3b\x06\x31\xbe\x14\x46\x55\x84\x0b\x19\x21\xf0\x12\x1a\x17\x35\x91\x9f\x3c\x00\xf4\xe3\x97\x92\xbc\x2b\xf0\x4a\x75\x49\xd5\x10\xb6\x6d\x93\x6c\xc7\x7d\x1e\x58\xb5\x5f\x5a\xbb\x11\x4a\xda\xcb\x68\xad\xa2\x6f\xe6\xce\xa6\x39\x60\x8e\xa1\x52\xd6\xe9\xa6\x46\xcd\xcd\xf4\xf3\x8b\x6b\x71\x12\x36\x93\xe2\xb6\x57\xb9\x98\x59\xac\x6a\xd4\xe9\x54\x51\x6b\x27\x96\x93\x98\x09\x67\x6b\x3b\xb8\x54\x57\xcf\x76\xb4\x73\x44\x32\x4c\xfa\x12\xb4\xc1\x1a\xe3\x52\xb9\xb7\x21\x2a\xee\x56\x6c\xc7\x1a\x0c\xe8\xf9\x6d\x1e\xd6\x89\xc8\xb8\x8d\xb7\x98\xab\x7d\xb1\x58\xa4\xf0\x5b\xec\x7b\x9d\x83\x76\x8b\x4e\x5d\x09\x7a\x99\xf5\x58\x62\x77\xa0\x7e\x6c\x7e\xbc\xe7\x66\x4b\xcc\x1b\xf7\x5f\x8f\x66\x83\x2b\xac\x63\x0b\x8d\x46\x80\x4e\x68\x8f\x1d\xb3\xa3\x58\x89\xfd\xb2\x1a\xfb\x79\x26\xc3\x40\x6d\xa0\xdc\xbe\x54\x80\x19\x0a\x5d\x80\x18\xcc\xce\x9a\xfb\x3d\xec\x6c\x91\xd6\x5c\x87\xea\xdb\xf3\x3f\x4c\x74\x7a\x17\x64\xd7\x1d\x62\xb7\xee\x5e\xf6\x36\x3c\xdf\xd9\xc4\x71\xa2\x5a\xff\x0f\x39\x8f\xfa\xd3\x3a\x0c\xcc\xc0\xab\xc1\x0c\xf2\x61\xf0\x0b\xcc\xa3\x68\x5f\x98\x15\xf5\x84\x13\x21\x7c\x13\x96\x88\x02\x52\x00\x2e\x85\x35\xa4\x84\xcc\xae\xfc\x15\xc9\x5d\x25\x1c\x6e\xc6\x9c\xe1\x1d\xa9\xed\x5d\x71\x29\x02\xce\x22\x17\x5c\x12\x76\xa8\x83\xb2\x1d\x43\xa3\xc0\x55\xa9\x42\x55\xd9\x18\xb0\xdf\xcc\x37\x32\xbf\xbc\xab\xa2\x34\x76\x0c\x24\x6e\x09\x9a\x28\x69\x2b\x8c\x7c\x68\xf0\x1e\xd7\xc4\x0f\xc1\xf0\xa5\x1e\xd8\x02\x6b\x44\xbd\xa3\xbe\x60\x29\x44\xe0\xf9\xf1\xf4\x61\x52\x4d\x59\xed\xef\x68\x98\x16\x8a\xa0\xd0\xbb\x14\x52\x19\x75\x44\x4d\xd1\x49\x5e\x70\xc9\x2c\x66\xed\x6d\x90\xe5\x80\xa0\x9b\x6d\x70\x52\xe2\xeb\xf7\x54\x08\x8e\x79\xf0\x97\xac\xee\x24\x67\x31\xf1\x39\x33\x42\x52\xb3\x00\x95\xca\x65\x75\xeb\xa7\x21\xe6\xd3\xe3\x19\x0a\xcb\x64\xc9\x48\xd1\xdc\x88\xd2\xd1\xc7\x0a\x2c\x52\x9f\x86\x03\xf3\xdb\x02\xae\x02\xf1\xf2\x7c\xbc\x03\x03\x18\x1a\xa1\xb5\x57\x76\x1b\x7a\x55\xee\x92\x05\x55\x8d\x09\xbb\xf7\x40\x7a\xf4\x27\x17\xe1\x23\xc8\x0c\x05\xf0\xab\xd5\x35\xd1\xb7\x92\xb1\xf6\x4d\x9e\x92\x17\x8e\x33\xbe\xaa\x0b\x2a\x33\x5b\x6a\xd9\x26\xf8\xde\x68\x9c\x2b\xea\x10\xdb\x01\x69\xd4\x5b\xfa\xe1\x8e\x2c\x7f\x85\x54\xd5\xbd\xdb\x35\xb6\x76\x8c\x21\x9a\x8e\x09\x9f\xd2\x86\x1e\x93\x19\x08\xdb\x8e\x1b\x37\xd3\x2c\x43\xb1\x6a\xa3\x41\xdf\xb0\x01\x3d\x14\xfb\x4e\x66\x67\x7d\x18\x00\xa7\x9b\xf5\x70\xc2\x42\xe1\x9e\x77\xb0\xce\x1d\xaa\x55\xa6\x5b\x57\xd3\x93\x09\x6f\x5a\xd2\x9b\x09\x27\x94\x7b\x02\xf1\x07\xae\x96\x27\x09\x56\x23\x27\xa2\x6c\x18\x7b\x70\x28\x19\xa3\x39\x9a\xbf\x2c\x81\x2c\xa0\x49\x82\xb3\xd6\xce\xf4\xab\xb0\xca\xe6\x0e\x31\x35\xac\x88\xca\x4b\x3f\x04\xf3\x5c\x9d\x7c\x66\xbc\x5b\x35\xe0\x22\x40\x7b\x45\xf0\xc6\x3d\xa0\xef\xf7\x33\x47\x78\x64\xd4\xe7\xc1\xe6\xb5\xb2\x2b\x6e\xdc\x91\x74\x9b\x33\xd6\x4e\x41\x2d\x10\x76\x86\xf3\xc0\xc2\xc8\x92\x1a\x69\x42\x70\x22\x10\x6c\x26\x15\x5d\xc7\x8f\x53\x78\x60\x14\x45\xd0\x62\x46\x62\x02\xbf\x5d\x00\xfc\xe1\x37\x68\x22\x15\x90\xf6\x15\x5b\xba\x9d\x5d\xa7\x65\x81\xd0\x7f\x41\x4c\x3e\x7b\x00\xde\x03\x81\x12\x61\x61\xed\x6d\x20\x41\xae\x76\xd0\xdc\xd2\x78\x62\x80\x56\x94\x30\x96\xe2\x04\x65\x4c\x66\xc7\x09\x1a\x63\x37\x2d\x7d\xd9\x2f\x0a\x86\xe1\x5c\x87\x03\x43\xec\x0b\x79\x08\xd0\xab\x2b\x68\xbb\xd4\x9e\x88\x8c\xac\xf6\x0a\x5a\xeb\x5c\x20\xb2\x27\xeb\x85\x9f\x59\x88\x4b\xc4\xe0\xbb\x85\x8d\xd7\x4c\x82\x0c\x49\x72\x77\xb0\x8d\xea\x78\x97\x47\x3b\x4d\x3f\x45\x76\x39\xf1\x6b\x9b\x9e\xa3\xeb\x9e\xe2\x1b\xe4\x56\xf2\xe1\xcf\xf8\xf5\xee\x3f\xb0\x75\xdb\x5b\x29\x58\x92\xda\xa6\x55\x13\x40\x02\x0e\xaf\xb1\xad\x32\x40\x88\x4a\x84\x92\x24\x51\x12\xc7\xa8\x8e\x19\x3c\x78\xe6\x62\x28\x36\x91\xf9\x66\xcf\xdb\x54\x40\x87\x40\x22\x81\x2c\x2e\x6e\xa6\x54\x70\x76\x92\x5e\x4a\xec\xa9\xb2\xbe\x6e\xd5\x80\x24\x88\x37\x55\xb0\xd8\x17\x7b\x41\xfa\xbe\xf8\x6f\x8c\x0f\x4f\x41\x3b\x4b\x2a\x34\xf8\x4f\x79\x41\xe1\x3f\x13\x84\x13\xc1\x80\x42\xd3\xa6\xd0\x9c\xf7\x6e\x19\xd9\xb6\xbc\xf0\xb8\x20\x54\xfa\xde\xa6\x11\xbe\xc3\xd9\xe7\x76\x88\xea\x81\xf1\x78\x67\xe9\x7a\x84\x2a\x5c\x99\x33\x32\x55\x07\xb6\x9a\xc5\x48\x50\x2f\x9b\x41\xab\xfd\xfd\x75\x6b\x46\xb1\x1d\xd1\x34\x63\xfe\xfd\xac\x88\x90\x84\x6a\x70\x37\xe7\xd5\x4f\x39\xdd\x67\xe1\xe1\x16\x25\x0b\x3e\x3f\x10\xa0\x58\x4e\x4d\x6e\x44\x7a\x68\x6b\x7e\x7e\xd3\xbf\x98\xba\x90\x02\x48\xe7\xf6\xc9\x20\x27\x1f\x6d\x64\x02\xf1\x26\xd6\xda\xd6\x07\xb5\x0d\xd2\xb3\xeb\x8d\x16\xc2\x2c\x75\x1d\xb1\x09\x23\x27\x06\xb8\x2c\x12\x72\xae\x73\x45\x8b\xb3\x5b\x68\x12\x53\xc0\xe0\x27\xaf\xe8\xdf\x34\xe5\x53\x65\x5d\xa4\x04\xd7\x58\xe0\xab\x3e\xfa\x1a\x5a\x5a\x1b\x68\xb8\x8b\xc8\x87\x1e\xa9\x0e\x46\x5a\x83\x80\x97\x0c\xb2\x4f\x66\xf2\x8e\x0e\x98\xb9\x42\xb8\x11\x8b\xd0\xc5\xcd\xf9\x36\xe6\x0e\x0c\xcb\xc5\xc5\x8c\xff\xba\xe8\x0f\xa5\xb1\x63\x8f\x94\x64\x55\xdb\x22\xd1\x26\xa1\x0b\x68\x86\x7e\x96\x16\xca\xc0\x1b\xdc\x3b\xaa\x4e\x35\xdd\x18\xa0\x0a\x02\x9b\x0c\x61\x59\x58\xa5\xec\x5d\x8e\x84\x67\xfc\xbe\xc6\x43\x34\x90\xa5\x2c\xd7\x9c\xb6\xe1\x42\xf3\x92\x87\x8b\x79\x2e\x87\x56\x73\x8b\x18\x6d\xa2\x69\x1c\xbc\x16\xa0\xcb\xf2\xd0\x09\x57\x0c\xf5\xbe\x7b\x4f\xc9\x7f\x52\x4e\xb4\x44\xc4\x56\x2e\xd1\x22\x2c\xec\x84\x0a\xba\xfc\xbc\x55\xc6\xea\x30\xce\x37\xfd\x94\xaa\x61\xea\xc8\xbc\x86\x9f\xa4\xe0\x06\xae\xae\x66\x33\x63\xe7\x95\xc6\xa2\x7f\xb5\x51\xc9\x1e\x56\x2b\xfb\x3f\x00\x9e\x21\x61\xde\xcc\x01\x9a\x41\x85\xc9\x6d\x75\xea\x23\x0e\x98\xcc\x2c\x58\x88\xd1\x94\xad\x8c\x1c\x48\x6e\x41\xbb\x23\x3a\x80\x69\xd4\xdb\xd0\x0b\xf3\x6d\x63\x4d\xe4\xf0\x26\x64\x15\x43\xcb\x82\x93\x22\xb6\x67\x9a\x10\x67\x75\xbc\x27\x7c\x75\xde\xcc\x50\x80\x48\xfa\xa6\x4d\x08\xfa\x08\x9a\x36\xec\xc4\x82\x15\x5b\x0d\x20\xb2\x38\xb1\x6a\x89\x77\xb1\x13\x07\xd4\x94\x3c\x16\xa2\x17\x61\x95\xe0\xdb\x79\x6e\xfb\xbd\x79\x3d\x14\x51\x15\xcb\xef\x19\x20\x91\x9d\x72\x82\xb3\x11\xbc\x55\x38\xee\x40\x36\x5c\x41\x59\x19\x4f\xe7\xb1\x4a\x05\x2a\x8f\x20\x13\x60\x40\x59\xb5\x48\x1d\xe8\x71\x46\x22\xac\x91\x33\x88\xb4\x39\x27\xf1\x7e\xc5\x99\x68\xef\xc4\xe6\xcb\xae\x5f\x04\xd6\x47\x9d\x8f\xd2\xee\x76\x87\xc2\xc9\xdf\xb0\x32\x56\xc0\x18\x37\xd9\x94\x34\xed\x36\xb5\x90\x06\x69\x0d\x51\xe1\x9d\xcc\x96\xde\x77\x90\x41\x5c\x61\x8e\x48\x80\xd9\x07\x4c\x9a\x78\x7b\x96\x0e\x86\x6a\x3f\xba\x9f\xf0\x41\x78\x8f\x65\x6d\x02\x9d\x24\x66\x00\x56\x65\x1f\x28\xbe\x50\x02\x2f\xc7\x6c\xa0\x54\xc5\x8a\xc3\x07\xb6\x5a\x93\x64\x0a\xed\x16\x95\x2e\xa3\x2e\x10\xfa\x9d\x2f\x05\xc6\x30\x97\x3c\x18\x22\xa0\xde\xd8\x80\x73\xd8\xcc\xf0\xc0\xf8\x3f\x7b\x59\x62\x61\x2c\x08\xd4\xb0\x83\xda\xff\x5d\x5c\x43\x22\x49\xac\x5e\xf6\xca\xa0\x31\x12\x0b\x27\xd8\x52\x86\xb2\x16\x7e\xda\x38\x6c\x5a\xa7\xc9\x18\xc7\x47\x13\x7a\xbd\x05\x1c\xdc\x27\x37\x7c\xd3\x04\x63\xa4\x9d\xfb\x36\x7c\x65\x67\x2b\x8b\xa7\x36\xeb\x54\x3e\x04\x59\x4c\xbe\xdc\xb6\xbe\xe1\x09\xdd\xcd\xb0\xc3\x32\xe8\xc0\xf1\x90\xdc\x70\xf7\x61\xda\x04\xd8\x23\xe4\x84\x86\x82\xa2\x7e\x4d\x38\x3a\xae\xdb\xa9\x42\x65\xa8\x81\x80\x7b\xf2\x81\x4b\x6e\xd6\x83\xcd\x94\x84\x3a\xa7\x59\xcf\x06\x10\x0c\x9c\x3c\xb2\xea\xdb\x17\x19\x33\x7e\x56\xfa\xcf\x16\x16\xd8\xb9\x83\x80\xd5\x02\x03\x31\xba\x42\xc0\x5f\xc1\x43\x54\x47\x19\x14\x55\xd7\xb6\xea\x46\x01\xed\x48\x30\x23\xef\x87\xd0\xee\xf2\x55\x6c\xb3\xeb\xab\xc2\xee\x49\x9a\x6d\x49\x5e\xf2\x42\x24\xf4\x58\xd3\xda\x7e\x6c\x40\x85\x3b\xe0\xe6\xe7\xdb\x44\x95\x4b\x4f\x4c\x32\x81\x00\x04\xf2\x4f\x03\x0c\x61\x8c\x77\x0f\x1a\x05\xbb\x26\x1c\xed\xc5\xb4\x88\xf6\x0b\xf5\xb8\x40\x68\xc9\x81\x6e\xbc\x1f\x07\x08\x46\xca\x71\x04\x57\x6b\x9b\xd3\x22\xf5\x84\x0b\xc5\x6e\x4f\x9e\x53\xf7\x8c\x1b\xf0\xe0\xc3\x40\x3e\x6e\x20\x94\xc4\x42\xdf\xbc\x9f\x2e\x75\xff\x41\xae\x5a\xe3\x57\x66\xc4\xb1\x4b\xc8\x21\x8e\xd4\x97\xa2\x10\xe1\x32\xb8\x68\xd6\x37\x4a\x87\x04\xc6\xc0\x11\xa6\xcc\x87\x21\x75\xd6\xb5\xbe\x10\xee\xc9\x49\x1e\x8c\xd7\xa4\xbe\x05\xf8\x30\xad\x55\x03\x1c\x7f\x0e\xd0\x23\x67\x84\x18\x86\x3b\xf7\x14\x2c\x40\x61\x11\xe4\xde\x46\x9d\x35\x32\xdc\x5d\x47\x63\x06\x90\xa1\x40\x79\x71\x3a\x1f\x06\x40\x16\x44\xd1\xe6\x81\xe8\xb4\xac\x4e\x1d\x2a\x1d\x98\xef\xca\xaf\xa0\x29\x23\x5f\x9d\xb6\xce\xf9\x98\x0f\x24\x54\x85\xb0\x07\x96\x1e\xc7\x6f\xc0\xe0\xa5\x02\x8d\x14\xd4\x85\xe1\x00\xa0\x8a\x49\x45\xe0\x7a\x72\x93\xea\xe1\x42\x3f\x2a\x23\xcb\x70\x30\x78\x59\x8b\xe9\x5d\xd7\x4e\x9d\x36\x6c\x0c\xcb\x35\xc4\x35\xf0\x2f\x00\x54\xf2\xe5\x19\x4a\x9d\xf7\x0e\x49\x6c\x86\x99\xd0\xad\x0f\xaa\xa1\x7a\x0d\x68\x78\x0a\x1a\xb5\x89\xc5\x42\x1e\x0b\x02\x48\x7d\x13\x07\x68\x2d\x8e\x1a\x85\x69\xa9\xcb\x4c\xa0\x47\xac\x0d\x31\xd8\x29\x6d\x56\x98\xd8\x70\xd4\xf4\xf5\x9b\x92\x4b\x13\x26\xad\x51\x53\x85\x00\x56\x4b\x73\x5f\x67\xfd\xa7\xab\x6b\x57\x4a\x04\x86\x61\xec\x30\x5b\xe0\x37\x17\xd9\x00\x5f\x54\xc3\xa0\x22\x05\xfc\x74\xfc\x86\xc8\x32\x03\x11\xf3\x3d\x2f\x3f\xd0\x0f\xe6\x26\xa3\xf8\x45\x58\x98\xab\x74\x03\x80\x30\xe4\x1c\xd6\x1c\x7a\xf5\x1b\xac\x20\x4a\x20\x93\xd8\x2a\x4d\xac\x20\xe5\x3f\xef\x44\xd7\xa0\xe8\x82\x7a\x84\x0b\xc9\xdd\x07\xd5\xc4\xc0\xa8\x7c\xb1\xaa\xb6\x23\x16\x63\x64\xef\xb1\xa8\x24\x7e\xb5\x04\xbb\x13\xa0\x2a\x19\x81\x91\x04\xda\x0d\x02\x2b\x5b\x0b\x00\x93\x0a\x31\x15\x44\xb0\x91\x7a\x72\x7f\x3d\x0d\x6d\x05\x8c\xc9\xea\xf1\x2d\xa9\x8e\xb1\x65\x03\x67\x6e\xe6\x6b\x10\x71\x30\xed\x66\x1c\x9e\x2d\xe2\xca\x68\xed\xba\x8b\x0c\x52\x7f\x8b\xdb\x01\xf7\x5a\xcc\x99\x51\x3b\xa6\xdf\x4a\xa9\x70\x18\xfd\x78\xe2\x08\xc6\x3c\x3e\xe8\x52\xe8\x65\x12\x8f\x35\x94\x03\x0a\xa4\x23\xab\x90\xb8\xcc\xc6\x8b\x3a\x10\x75\x88\x13\xaf\x64\x1e\x4c\x70\x84\x03\xc2\xfb\x80\x18\x38\x3d\x21\xa4\x41\x21\xf6\x8e\xa3\x12\x80\xd6\x6b\x7c\x83\xf8\x26\x0c\x47\xc4\x7d\x24\x42\x46\x99\x04\x0e\x92\xca\xfa\x31\x0a\x57\x1c\xda\x0a\x93\x73\x68\x64\x61\x10\x9b\x31\x8f\x16\x5c\xfc\xdc\x46\x02\xe4\x95\x5d\x39\x87\x01\x35\xb5\x59\x10\xb1\x11\x65\x6b\xa2\x08\x70\x61\xbd\x7d\x25\x5c\xfb\x7d\x08\xbe\x82\xe9\x31\xa5\xa9\x39\xc1\xd7\xd2\x2a\x8f\xe3\x5f\x38\xbe\x27\x7e\x09\x22\x2c\x44\xca\x13\x38\x53\x6d\x4c\x45\x37\x62\x1b\x97\x50\xa6\x05\x2d\x7b\xd9\xe1\xdb\x80\x7f\xee\x1b\x3d\x89\x28\xa3\x2e\x6d\x90\x31\x82\x1e\x4d\x8e\xc4\xa9\x6f\x5a\x30\x9b\x3e\x09\x10\x1c\x69\xbd\x32\xcb\x8a\x9b\x02\x58\x1b\xf3\x49\x12\xea\x81\x14\x00\x49\x92\xa8\xb0\x47\xef\x20\x99\xed\x9b\x81\x28\xff\x24\x80\xcc\x7e\xc8\x21\x45\xe3\x09\x02\x06\xdf\x40\xdb\xbb\xc9\x86\x2f\x03\x6f\x02\x67\xa0\xc0\xc8\x76\x3a\x9e\x1a\x41\x70\xcb\xf6\x21\x5d\x7c\xe7\xe4\x96\x32\x28\x41\x02\x66\xf1\x74\x75\xcb\x22\x98\x1d\x8d\x08\x1c\x7e\x27\xa0\xc4\xe2\xbb\xbf\xd2\xed\x36\xfe\xbf\x45\x5e\x59\x6e\xbf\x05\x48\xa3\x70\x3c\x5a\xfb\x09\xc0\xc9\xd8\xa7\xd9\xa4\x68\x55\x26\x40\x5a\xa7\xbc\x98\x68\xf1\xc0\x13\x88\xa9\x01\xb7\xaa\x5a\x21\x09\xae\x2c\x1a\x70\x86\x44\x0c\x0e\x92\x48\x54\x20\x05\x5d\x90\x32\x09\x16\x59\x9b\x99\x24\xbd\x5f\xf2\x34\x49\x73\xaf\xda\xeb\xd4\x6a\x15\x14\xe4\xe8\xb0\xd5\xbc\xa5\xc6\xc1\x55\x94\xd9\x0a\x0d\x3a\x3c\x3a\xe4\xa3\x87\xae\x5a\xaa\x6f\x5d\xc0\x00\x37\xb5\x68\xb5\xe5\x9a\x44\x5e\x5e\x37\x1b\x1e\x00\x1f\x7b\xc9\x08\xe3\x8c\x9a\x02\x54\xcd\xe8\x67\x8b\x05\xb8\x30\x8a\x07\x05\xdd\x67\x08\xec\xd1\x89\xd1\x78\x4c\x09\xd2\xff\xd2\xad\x0c\x0d\x64\x7d\xf2\x43\x0d\x2b\xf1\x93\x39\xef\x86\x79\x43\x4d\x90\x60\xed\x19\x33\x0c\x8d\x81\x5a\x66\x08\xd9\x72\x80\xac\x4a\xea\x5e\xcc\x5d\x44\x48\x08\xe5\xfb\x4b\x07\x3d\x11\x8a\xc1\x29\x45\xd6\x6f\x6f\x93\x06\x0d\x73\x06\xce\x11\x85\xc1\xc9\x92\xbc\x9f\xa5\xac\xe5\xa8\x1d\x80\xd6\xaa\x1e\x20\xae\x52\x7c\x0f\xd6\xe2\x0a\xea\xef\x21\x88\x4f\x35\xd9\xa5\x40\xed\xa9\x47\xae\xb7\x8d\x79\xef\xc6\xfd\x1c\x2d\x19\x04\x50\x9f\x8d\x69\x76\xf0\x85\x72\x18\xf7\xde\xbb\x0e\xde\xff\x0e\x7c\x88\x90\x50\x42\x72\xc9\x2e\x04\x84\x5f\xfc\x4d\x5e\x26\x84\x08\xff\xc5\x1a\xe7\xbd\x0b\x6a\x14\x04\xba\x40\x7b\xb1\x46\xba\x21\xc1\xc5\xa8\xee\x45\x34\x1d\xb9\x50\x48\xc3\x23\x7c\x36\x08\xa9\x62\x4e\x9b\xaf\xa3\x2e\x6c\xc5\xc5\xff\x9e\xd8\xf9\xb6\x28\x24\xc0\xfc\x14\x4c\x37\x8c\xbc\xe6\xbc\xf7\x08\x3e\xfa\x39\x0e\xde\x4f\x91\x50\x3c\x24\xca\x21\x45\x72\xe8\xab\xf7\xbd\x0a\x44\xeb\xac\x40\x53\x1c\xad\xc7\x5d\x97\xa1\x68\x0f\x29\x58\xe0\xce\x1c\xc8\xc9\x39\x20\x08\xf1\x1c\xc6\x4c\xe3\x53\x80\xb3\x98\x49\x18\xb3\xab\x50\x99\x50\xdf\x73\x72\x79\xef\x81\xd1\x64\x3d\xfa\xea\x34\xfe\xc6\x82\x9a\x3e\xa8\x8a\x10\x52\x20\xbc\x23\x80\xed\x55\x59\xb2\xee\x34\x2a\x6d\xe1\x03\x48\x44\xc4\xcd\xed\xe5\x3a\x28\x5e\x06\x8b\xf7\x14\x27\x4e\x8b\xf8\x71\x4f\x4b\xa1\xf4\xc8\x39\x99\xc2\x69\xdf\x74\x65\xde\x50\x4a\xb1\x8b\x4c\x5d\x4b\x5c\xc7\x05\x6c\x2c\xa1\x60\x7a\x78\x48\x49\xd0\xb0\xcc\x17\x89\x84\x60\x38\xd1\xb8\x26\x2f\xae\x5b\x9a\x85\x61\x78\x25\x56\x46\xd1\x85\x82\xd2\xd3\x91\xec\xd2\x76\xc4\xe1\xf2\xa0\x49\x5d\xb9\x95\x12\x50\x32\x68\xce\x51\xd9\xc5\x3c\x2d\x9a\x0f\xd5\x34\x37\x50\x12\xd4\xf2\x20\xb1\x4f\xfa\xf9\x42\xfd\xcd\x1d\xd6\x02\x7d\x05\x3e\x4c\xd6\x63\xfd\x50\xe3\x3f\x67\x01\x31\x35\x92\x12\x91\xb1\xff\x50\xd9\xec\xcc\xd7\xb8\x63\x5f\x0d\x06\x28\xb8\x5c\x52\x94\x45\x23\xa0\xa5\xf4\xf8\x07\x59\xe7\x71\x93\x32\x4e\x72\x18\xbd\x99\xcb\x78\x1b\x0a\x49\x22\xe8\x71\xa0\x6b\xc4\x9c\xd7\x95\xd7\xc8\x51\x27\xb3\x94\xf1\xc8\x64\x82\x01\x45\xe2\x0a\x08\x54\x5b\xc8\x15\xa0\x8d\xfd\xe3\x62\x16\x9e\x1f\xbf\x00\x21\xc3\x28\x6c\xfa\x9a\x3b\xe7\xb1\x06\x8b\x96\x88\x50\x2d\x1f\x04\xd5\xb7\xdd\x2c\x6c\xf5\x37\x2c\x5e\xa3\x94\xbb\xb3\x3c\x12\x09\xa7\xa9\x98\x41\x8e\xd4\x62\x91\xf8\x04\xe8\xed\xd0\x9a\x88\x5b\x49\x08\x19\x31\x67\x58\x04\x4d\x0a\x31\xf0\x0f\x50\x0e\x3c\x46\xba\xf8\x61\x85\xdd\x3e\x14\x82\x11\xb9\xc1\xd1\x81\x06\x36\xec\x83\xde\xc2\xf8\xcd\x54\x24\x8a\x3a\x0b\xd6\xdb\x30\xae\x1a\x3a\x2d\xb5\x85\x19\x4b\xde\x76\x21\x92\x99\x19\xaa\x17\x65\x55\x7e\xdc\x62\xcc\x81\xbc\x55\x34\x34\x1e\x64\x54\x04\x1c\x47\x15\x64\x3a\x42\xde\x5e\xec\x89\xca\xb1\xca\x92\x00\xe6\xb9\xf3\x86\x41\xbd\x28\x2e\xb9\xa8\x10\x49\xd6\x5a\x26\xcf\x85\xf0\xa4\xe1\x89\x4d\x73\xa4\x94\x9c\x58\x30\xb6\x51\x5a\x69\x62\x7f\x46\xc3\x96\x58\x73\x0b\x8d\x15\x35\x62\xa5\xe8\x2f\xea\x22\x61\x8e\x7c\xc4\xc2\x5f\xa3\x27\x60\x9c\xcf\x59\xf2\xe3\xf1\xc2\xc9\xcd\x1e\x9c\xd3\xe4\x97\x87\x24\xcc\xf5\x58\xa8\x1f\xaa\xe9\x01\xb6\x8f\x4f\x8a\x0e\xf1\x2c\x11\x18\x1e\x79\x2d\xc9\x6c\xba\xb4\xbc\x4c\xed\xf7\x19\x6c\x38\x0e\x08\x8a\x97\xd2\x32\x46\xac\x6f\xa6\xcc\x83\x10\xd4\x5c\x8d\x47\xab\x4c\xa5\x50\xcc\xa4\x70\xb1\x8d\x66\xaa\xf8\x5e\xbe\x04\x86\x4c\x5c\x0b\xd1\x64\x62\xe2\xd0\xf1\x5c\x0c\x04\x93\x68\x92\xc9\xd0\xce\x4a\x41\x59\x99\x8b\x1e\x02\xd1\xc7\xe7\x21\xe0\xe6\xa0\xb7\x4b\xc9\x28\x99\x9c\x72\xda\xa8\x0e\x53\xde\x90\x4f\x20\x76\x56\x68\x6c\x56\x5f\x18\x75\x49\x3b\x00\xaf\x06\x95\x09\x30\x96\x99\x9a\xc6\x9f\x55\x0f\x23\xce\xbd\xea\x1a\x64\x48\x56\xb5\x48\x03\x42\xbd\xd6\x7b\x04\x67\x56\xd8\x4c\x78\x55\xb8\x31\xe8\xf2\x91\x2d\x5d\x78\x38\x32\x57\xc0\x91\x05\x52\xea\x44\x28\x19\x11\xb5\x1f\x26\x17\xc4\xe8\xcd\x2a\x5c\xcb\x2a\xcf\xa2\xfc\xaa\xa8\x2d\x40\x7e\x21\x4a\x0d\xd0\x39\xa4\x19\xfc\xa7\x13\xb0\xcf\x3f\x18\x04\xac\x06\x05\x4a\xee\xe1\xbf\x3a\x9d\x26\x03\x8e\x07\x53\xa4\xfb\xac\x71\x42\x23\x47\xe2\xb4\xc8\xe8\xd4\x43\x4f\xc7\xa7\x6c\x18\xf7\xc3\xea\xc2\x7e\x83\xc3\x67\xc4\x02\x29\xa1\x4f\x1f\x65\x78\x97\x49\x7b\x38\x97\x76\xd9\x7d\x4a\xa6\x04\x5a\xde\x73\x7f\xcc\x9b\x2e\x53\x98\x02\xb2\x77\xb9\x2b\xec\x4f\x7d\x62\x3c\x34\xdf\x40\x6a\xdc\x44\xe0\x70\x4d\x63\x3f\xc3\x99\x90\xb5\x4b\xe8\x08\xe6\x41\xe9\x67\xe7\x8e\xfa\xc7\x8a\xfa\xf1\x1f\x1f\xe2\x21\xd2\xdc\x2a\x61\xd4\xad\x58\x7d\x9e\xc0\x87\x6e\xee\x44\x42\xcf\x30\xa9\x1c\x70\x36\x26\x07\x72\x99\xcf\x46\xdc\x22\x77\x01\x0d\x5c\xb2\x99\x1f\x4d\x07\x6e\x5c\x71\xe6\x87\xc2\x4e\x7c\x45\x15\xdc\x7b\xf0\x14\x63\xfe\x09\x11\x05\xb7\x77\x04\x09\x29\x84\xf5\x92\x0e\x6a\xe4\x8a\x41\x88\xe1\x27\x18\xf3\x48\x41\xfe\x72\x44\x16\x33\xbd\x24\xf8\xd2\x7e\x54\x92\x71\x05\x88\xc1\xbe\xba\x3b\x74\x8e\x0d\xea\xd9\x91\xfc\x92\x22\x40\xe6\xae\x9b\x6a\x79\xcb\xf3\xe6\x8a\x17\x02\x57\xfb\x49\xbe\xd9\x9f\xf5\x03\x17\x43\x37\xfb\x52\xa1\xb2\x71\x9b\xb1\x1e\xc9\x98\xfc\xd0\xb9\x5e\xad\xcb\x3a\xea\xef\xfe\xd6\x0a\xb0\x30\x90\x90\xab\x06\xca\x80\x85\x0e\xb7\xda\x01\xd3\x4e\x9d\xd4\x02\x91\x41\x84\x5f\x94\xe5\xc9\x1d\xf9\x61\xdf\x84\x92\xa3\xc4\x77\xf2\x25\xed\x92\xde\xb7\xc8\xda\x1c\x2b\x23\x5d\xf6\x6e\x85\x7f\x9a\xb4\x24\x53\x85\xac\x0f\x0c\xfb\xea\x03\xfa\x91\x84\x38\x91\xbc\x5d\xdb\x39\xe5\x44\xfa\xe9\x8a\x6e\xb7\x1e\x5d\xc1\xe3\xef\x84\xca\x59\x64\x36\xf3\x42\x1d\x8f\x26\x57\x7a\x41\x71\x8b\x66\x7a\x16\x8c\x12\x36\x2a\xc2\x07\x89\x5e\x6c\x27\x03\x20\x19\xf4\x94\x8f\x0b\x1f\xc2\x94\x46\x97\x87\xad\xfc\x47\x7c\x15\x07\xe6\x58\x9b\x98\x41\x3b\x46\x36\xd7\xe9\xb4\x01\xfe\xc2\xc1\xdd\xa0\x48\x76\xc4\xf8\xb6\x26\x2d\x2a\xb0\x7e\x5e\x6b\xd6\x18\x11\x21\xdb\x18\x44\x25\x83\xc6\x07\x07\x7b\x78\x93\x40\x00\xe0\xed\x28\x01\x0f\x44\x6a\x54\x8c\xd0\xa9\x4b\xe9\x90\x81\x25\x78\xef\x0b\xdc\x2c\xc0\xc8\x56\x30\xf4\xe1\x58\x9f\xa4\xe8\x12\x09\xcf\xf0\x55\x46\x4f\x10\x37\x7c\xb0\x24\x24\xa2\x12\x00\x31\x3c\x25\x1f\x99\x20\x8a\xf7\xb4\x4d\x7c\xf0\x9b\x77\x0f\xa2\x0e\x5d\x83\x09\x98\x9c\x08\x3d\xa6\x6a\x16\x30\x4e\xb6\x0c\x9a\x6a\xf7\x77\xb7\xc2\x67\x07\x1f\xb6\x57\x01\x2d\x8a\xbe\x3e\x5b\xa3\x4c\x3b\x35\x96\x40\xc1\xd3\xc8\x2f\xd0\x6c\x1b\x3f\xf9\xa7\x9d\x0f\xc0\x72\x0e\x20\x48\x68\xe2\x07\xcb\x08\x10\x82\xbf\x06\xb3\x81\x85\xe2\x07\x00\xc2\x2f\x90\x38\x60\x1b\x37\x4a\x52\x5a\x62\x50\x0f\xf2\x15\x1a\x96\x89\xe5\x38\x23\xec\x9c\x0d\xeb\x00\x4d\x06\x9f\xd5\x9b\x7d\x83\x67\xa1\xdf\x63\x03\xa0\x48\x02\x9f\xe7\x48\xda\xc4\x4a\xe5\x62\xe0\x04\x82\x04\x77\x66\x33\x73\x70\x02\x23\x00\x57\x16\x28\xbf\x1b\x52\x18\x2d\xf0\x00\x8f\x05\x5c\x64\x16\x39\xb2\x8e\xb1\x41\x01\x11\x80\x3b\xfc\x80\x07\x00\x5b\x03\xe0\x62\xe6\xa3\xa1\x80\x0e\xcc\xd0\xbe\x22\x5b\x1c\x31\x95\xc1\xfc\x13\xf5\xc7\x73\x30\x0a\xda\x0e\xe0\x0f\xb1\x2a\xb6\xbf\x00\x1f\x00\x70\x6a\x18\x34\x90\xb1\x34\x70\x71\x08\x10\x0a\x48\x0b\x2d\x73\xc2\xbb\x6d\x81\xc2\x83\x78\xf1\x87\x7a\x0d\x45\x83\x12\x36\x75\x2b\x58\x17\x76\x8c\xb5\xaa\x75\x88\xff\x57\xba\x12\x06\x75\x3f\x24\xb1\x9d\xe4\x24\x49\xfa\xe4\xc2\x6c\xe9\x54\xac\x8b\xff\xa3\x20\x0e\x1b\xc6\x18\x07\xa9\x2b\x37\xea\x1d\x85\xfb\xe8\x1e\xb2\x48\x09\x1b\xe0\x8d\x08\xa2\xec\x58\x84\x49\xe8\x03\x8b\xdb\x0c\xf8\x53\xe0\x0b\xc5\xa1\x8b\x8e\xb0\x00\xee\x2a\x75\xf5\x01\xde\x50\x0d\xb5\x3c\x4a\x1c\xd9\xaf\xd0\x08\x4a\xb2\xf2\x1a\x93\x30\x67\x53\x7e\x53\xfd\xc3\x4b\x4a\x9c\xc4\xf2\x68\x38\xb1\xd0\x3c\xe9\xa6\x8e\x4f\x5f\x84\xe3\x5f\xd8\x4a\x9b\x36\x75\x91\xbd\x00\x17\x9f\x5f\xb6\x12\xe0\x03\x50\x46\x52\x60\x81\x20\xc2\x27\xa8\x85\x2f\x37\x31\x28\x39\x2c\xf6\x75\xca\x56\x4e\x6c\x41\x55\xbb\x76\x59\xbe\x5e\x0d\xbc\x66\x69\x7f\x53\xc6\x3d\xa2\x58\x09\x9e\xe1\x89\xc0\x1a\xde\x40\x78\xf4\x44\x07\x21\xbf\x0c\xe0\x7b\xe3\xcb\x5e\x7b\x11\x2f\xa8\x0b\xef\x0c\x08\xd4\x07\xdf\x77\x3c\x45\x2f\x6b\x4b\xdf\x09\xdd\x71\x4d\xe0\x14\x07\x8a\x83\xf8\xf5\xd6\xe7\x1b\x7b\xa8\xc4\x0c\x84\x5e\x20\x9e\x13\x22\x74\x1a\x58\x3c\x50\x5f\xa5\xe0\x94\x2d\x2c\xaa\x92\x68\x3d\x9c\x69\xde\x84\x4d\x38\x57\x16\x42\x78\xa3\x88\x78\xa0\xde\xc7\x69\xff\x49\x3a\x68\x6f\x9e\xb0\x0c\x03\x03\x8c\xd6\xeb\x63\x07\x02\x13\xdb\xf3\x81\x80\x9a\x15\xcb\x25\x76\x80\x3a\xf0\x0e\xcd\xad\x3b\x9d\xdc\x6b\x14\x5a\xbc\x28\xd0\x0d\xf5\xab\x65\x80\xfd\x81\x83\x3b\x04\x8d\x1e\xa0\xf6\x19\x8d\x20\x4a\x27\x9c\xbf\xf1\xe7\xde\x09\x21\xaa\x59\x49\x35\x7b\x7d\xa0\x2b\x40\x0c\x38\x22\x66\xb6\x13\x85\x89\x17\x83\x27\xab\x3a\xb2\xe7\xbe\x71\xf3\xe3\xb0\xba\x54\x94\xd0\x03\x7d\xaf\x0e\x82\x09\x95\xeb\xca\x3f\x64\xe0\x00\x2a\xbb\xf0\x8e\xa6\xee\x42\xb9\x80\xa9\x76\xd6\x8f\x62\x4b\xb6\x6b\xf1\xda\xe0\x07\x1e\x46\xd6\xe8\xb3\xfd\x35\x9e\x93\xb0\x91\x58\x1f\x01\x49\x75\x7a\xb5\x85\x18\xf9\xe4\xc1\x0c\x4f\xa2\x08\xb2\xd6\xe0\x39\x25\x7e\xe4\x81\x17\xff\xb5\x25\x0c\xff\x8c\x88\x83\x00\xee\x54\xed\xdc\xf6\x3e\x8a\x29\x17\x62\xcc\x3e\x33\xeb\x97\xe3\x90\x4a\x65\x17\x65\x33\xbe\x8b\x9b\x83\xe5\xc2\x41\x49\x72\x01\xa3\xe5\x57\x85\x02\x56\x5b\xc0\x44\xa2\xb9\x81\xfe\x49\x98\x7d\x88\x8e\xb0\x3c\xf0\x50\x2e\xac\xb7\xd6\x7d\x87\x58\x61\xcf\x5e\x71\xcf\x86\xa9\x06\xa3\x28\x07\x43\xb0\x18\x12\x17\x55\x71\x19\x80\x75\x3c\x6b\xdd\x18\xe8\x34\xcd\xe2\xe5\x1b\x1b\x8a\x52\x45\x39\xad\xc3\x08\xf7\x11\x90\x84\x94\xb2\x6f\x01\xce\xf3\x12\x43\xb8\x93\x9a\x62\x3e\xcd\xb6\x1a\xed\xa5\xc4\x82\x90\x86\xd2\x1b\x2c\x1f\xb5\x5f\x86\x24\x04\x00\x38\x5a\xea\xd2\xd9\x1d\x29\xce\x95\x02\x01\x66\x57\x8b\xf9\x92\x1a\xa1\x1c\xd4\x18\xcf\x7a\x56\x0d\xa5\x2c\x23\xc5\x60\xcd\xc8\xde\x70\x70\x9b\x1f\x0b\xb1\xe3\xc0\x54\x59\xc4\x80\x90\x02\xe0\x18\xe1\x55\x55\x96\x41\xbf\xc7\x30\xc2\xaa\x5f\x6d\x2a\xcf\xdb\x23\x59\x6a\x02\xe5\x21\xc1\x19\x43\x13\xa0\x99\x43\x1f\x07\xa3\x2d\x00\x79\x2d\x37\xcc\x00\x41\x36\xa3\x00\x5e\x77\x6b\x6d\x41\xb0\xac\xdc\x88\xd5\x69\x71\x42\xe6\x85\xd5\xc5\xb6\x96\x41\x83\x1e\x80\x60\x06\x62\x19\xb0\x1b\x0a\x8d\xc2\x08\xdf\x60\xd7\xbc\x6e\x88\x57\x4c\x2d\x31\xdf\x5e\x50\xec\x39\x28\xd9\xce\x27\x4f\xb1\x58\xe5\x64\x6d\x90\x95\xd5\x40\xfe\x64\x0f\x18\x25\x10\x10\x57\x74\x88\x6a\xae\x7d\xba\xb0\x00\x8e\xb7\x90\xca\x6f\x87\x36\xc2\xc7\xad\x1a\x0b\x50\x0b\x4d\x3a\x56\x47\x72\x96\x0b\xe5\xd5\x58\x97\xbe\xcc\xae\x14\xbd\x1e\x74\x68\xb7\x80\xf5\x18\xd7\x7f\x04\x41\xf0\xd6\x05\x2b\xec\xd0\x4f\x9f\x2a\xbd\x97\xdf\x2b\x97\x7e\x3e\x15\x7b\x22\x9a\xf3\x38\x20\x31\x7a\x37\x87\x4c\x7e\x36\x4b\xd6\x7c\x6b\x91\x66\xe7\x50\x20\xf4\x9f\x76\x4a\x5e\x59\x39\xd5\x87\x65\xce\x13\x12\xb2\x9c\x1b\x45\x39\x61\x9a\xa4\x30\x64\x45\x13\xfa\x59\x57\xfa\x60\x98\x88\xba\xc4\x5d\x00\xc7\x7d\x5b\x02\x81\xa4\xeb\xcf\x0c\x4b\x4c\xb0\x76\xc3\xf8\xb8\x08\x31\xfc\x11\xba\x0b\x7b\x3d\x03\x9c\x18\xa3\xf8\xf7\xb8\xd7\xee\xa8\xf7\x55\x35\x13\x59\x63\x97\x74\x7a\xb1\xe9\xd7\x5d\xf3\x3d\xe8\x15\x42\x5b\xa0\x2a\x60\xec\xde\x8c\xe2\xc1\x5f\xdd\xf6\x32\xb2\x18\x34\x5d\xed\x10\x7f\x70\x6b\x00\x39\xfe\xf3\x5d\xc0\xae\xcf\x49\xe7\x5c\x83\x73\x4f\x69\x71\xe0\x7c\xc9\xde\x6a\x0f\xbe\x98\xd2\xa6\xbd\xfe\x54\xbd\xfe\x32\xce\x30\xe1\x5f\x0d\x79\xb8\xee\x10\x31\x82\x5f\xee\x20\x11\x3f\xec\x53\xb6\xc2\x75\xcb\x29\x2d\xf4\x4b\x92\x82\x00\x3e\x3f\xd6\xcb\x78\x88\xf1\xe1\xb3\x04\x44\x84\x03\x7e\xf5\x17\xe6\x63\xcf\x94\xe0\x61\xb1\xf8\xfa\x5c\x6d\xfd\xc1\x38\x41\x97\x42\x41\xf6\x05\x40\x35\x00\xa6\x64\x47\x56\x04\xd8\x9f\xd0\xa1\xc5\x81\x4b\xf1\x31\x06\xce\x47\x42\xe4\x5e\x89\x5b\x2d\x50\x29\xfb\x97\xf6\xdf\x09\x1a\x63\x15\xd0\x46\xcf\x14\x44\x90\x70\x87\xa6\xcd\x98\x42\x96\x27\x8f\x25\x12\xc4\xa5\x59\xc4\xbb\x7d\xd6\xd3\x0e\xa0\x9c\xdc\x01\x3c\x7a\x93\xe7\xee\x65\x0b\xcc\x21\x6e\x53\x3f\x0b\xde\xab\x7c\xb8\x2a\x11\x9f\xf2\xc2\x7f\x07\x93\xe9\xa5\x78\x08\x8a\x50\x9d\x83\x54\x6a\x06\xfc\x1a\xc6\x96\xd8\x02\xd8\xa8\x48\xe4\x5b\x50\xd1\xe4\xef\x7c\xc4\x10\x5f\xba\xe3\xdb\xb9\x69\x70\x4c\xd1\x1b\x50\xcd\x8d\x00\x6e\x05\xe6\xc7\xf0\x6e\xaf\x60\xea\xaa\xdc\x24\x0d\x01\x54\x44\xa7\x88\x30\xe3\x8a\x7e\x0c\xd1\x12\xa5\xd1\x34\xaf\xca\xf1\xba\x65\x58\x0d\x4f\x44\xa4\xf8\x3c\xfe\x97\xc3\x68\x34\x90\xa6\xb5\xf2\x55\x90\xbe\x48\x3f\xb0\xb2\x49\x70\x18\xe8\xac\x74\x4a\x59\xaf\x61\x84\x0c\x29\x5a\xe1\x00\xb8\xcb\x0f\x8d\x1c\x7c\x80\xc4\x41\x3e\xb9\xed\x60\x0a\x74\xd2\x9e\xdb\x97\x43\xe8\x2b\xb8\x83\x97\x11\x09\x5d\x2a\xc4\xa7\x78\xd5\xfa\xec\x94\xfb\x7e\x42\x2d\xb0\x38\x94\x4d\x95\x6e\x82\x30\x8d\x0c\x85\x1e\x0b\x53\x22\x61\x88\xd9\xcf\xc1\xf4\x9b\x88\x0b\x19\x5e\xe4\xd5\x65\x28\x68\x0f\x5c\xef\x86\xbb\xd0\x86\xba\xdb\x16\x1f\x8e\x26\x99\x74\x69\xa6\xe2\x83\xf4\x79\xa9\x36\xe1\x0a\x3f\x36\x08\xf8\xa7\x70\x88\x62\x1d\xc6\xce\xeb\xf1\x97\xd2\xa8\x72\x1f\x36\x2c\xb4\x7e\x10\x66\x90\x3e\xce\xd9\x45\x29\xaf\x21\x72\x1c\xf9\x28\x35\x27\x52\xd2\xb0\x2d\x23\x63\x5e\x30\x89\x15\x1f\x80\xd9\xf7\x0e\x1f\x20\x21\x0a\x6e\x37\x8a\x80\x91\x4e\x5b\x33\x90\xa9\xe2\x97\xfa\xb1\xcb\x6c\x5e\x0d\xde\x14\xb1\x06\xee\xc9\x7c\x41\x1e\xa9\xfa\x62\x42\x47\x71\x06\xba\x04\x90\x0c\x26\xfe\x7f\x41\x26\xf6\x0d\x93\x48\x64\xe1\x42\xd1\xe3\x70\x13\x53\x0e\xfd\x32\x09\x9e\xec\x4b\xde\xe5\xe7\x71\x93\xc3\x82\xc2\xc7\x4b\x19\x38\xbc\xfc\xb9\x3d\xbd\x23\x94\x02\x51\x47\xbd\x87\x5d\x08\x87\x5f\xfc\x43\xad\x08\x90\xe7\x46\x2c\x39\x46\x23\x11\x70\x86\x73\x2d\x3c\xdd\x6b\x1f\x59\x4d\x38\xa3\xe2\x08\x3c\xa0\x40\x00\x0c\x6e\xf1\x3a\xce\x14\xfd\x0b\x75\x39\x83\xb4\x68\x40\x1a\xf8\xf2\x1d\x3a\x4b\x23\x10\xa5\x4f\xfe\x45\x3a\x58\xf1\x8f\x77\x52\x4d\x81\xc4\x76\x8d\xae\x4c\xf2\x54\xe0\xd8\xa4\xad\x87\xdf\x6c\x2e\x49\x4e\x8e\x05\x73\x13\x56\x1f\x31\x64\xdf\xce\xb0\xc9\xd4\x71\x03\x9e\x55\x84\x8f\xdc\x52\x0e\x06\xb5\x3c\x51\xfe\x44\x53\x6c\xe7\xb7\x91\x54\x10\x94\x08\xb8\xa7\x03\xb2\xee\xb0\x4d\xdd\x92\xd0\x6f\x4b\x53\x19\x4c\x4d\x0b\x5a\x59\x1f\x0b\xb0\xca\x9e\xcc\x3f\x2d\xdc\x33\x02\x25\xb3\x49\x5e\xcf\x86\xf1\x07\xdf\xb0\xaa\xe8\xd0\x81\xe7\xfb\x65\x24\xbc\x7a\x8c\x88\x6c\x0d\x80\x66\xbc\x07\xce\x3a\x8a\x33\x2a\x91\x71\x2f\x8c\x77\x8e\x22\x01\x85\x24\xe1\x9a\x76\x6f\x88\x29\x3f\x34\xf5\x37\x59\xfa\xc5\x29\x92\xa9\x34\x0b\x7e\x60\xd4\xa5\xaa\xd1\x0a\x90\xf7\x20\xa2\x66\x7c\x19\xc7\xde\xce\x22\x11\x68\x7f\xa0\x74\xb6\x44\x02\x2f\x7d\x27\x5f\xf3\x14\x92\x78\xf8\x79\x3c\xff\xd8\xb7\x36\xf5\x97\xe9\x1c\x52\x71\xf9\xdd\x99\x6d\xac\xad\x32\x78\x2b\x52\x67\x82\x93\xdd\x02\x52\x55\x64\xf2\x93\xc8\x8c\x24\x16\xab\xe3\x71\x5c\xdb\x27\x3a\x5c\x66\x95\xba\x4a\x58\x3c\x0e\x1f\x41\xe1\xf6\x9c\x81\x22\x4c\x83\xde\xe5\xf9\x60\x09\x5a\x71\xed\xc0\xea\x51\x08\xa3\xf3\xa6\xcc\x14\x09\x10\xab\x19\xa0\x99\xd5\x5a\x30\xb0\x81\x83\xf8\x03\x5c\x52\x99\x50\xcb\x0b\x70\x00\xab\x98\x82\xb4\x04\x42\x00\xe0\x68\xb4\xfb\x47\x31\x81\x02\xc8\x5e\x66\x8c\xc4\x42\x41\xaa\xf9\x04\xc6\xd5\xa2\xef\x3b\xc8\x83\x35\xd6\x0d\x00\x10\x04\x5f\x64\x89\x25\x24\x57\x1d\x3c\xf4\x83\xc1\x7d\x18\xf0\x48\x02\x26\x52\xc7\x23\xd0\x90\x6d\x0d\x93\x21\x20\xd9\x98\x00\x39\xe5\xc8\x13\x95\xbb\x0b\x9a\x9a\x42\xd6\x28\x68\x1d\x55\xb9\x8c\xf2\x43\x75\xf1\xb6\x7a\xe9\xc2\x1c\xb3\x2c\x86\xdd\xe0\x41\x22\x5e\x79\x39\x75\x27\x0e\x48\xc2\x67\xf4\xc9\x0f\xe1\x35\x12\xc3\x04\xe8\x97\xdb\x4a\x9a\x10\xa0\x99\x95\xc1\xaa\xb6\x4e\x12\x44\x6b\x32\xa4\x61\xad\xae\x19\x2e\x2d\xce\x0b\xa1\xac\x92\x50\x81\x29\xde\x58\x8e\xfc\x88\x74\xf2\x92\x9a\xa1\xc0\x3a\x73\x46\x01\xa1\x51\x60\xe7\xe4\x8f\x11\xab\x39\x49\xc8\x36\x56\x1c\x79\xb1\xed\xe7\xea\x44\x06\x04\x78\x29\xbb\x2b\x0f\x81\xe0\x2f\x27\x38\x49\x18\x93\x86\x1c\x32\xc1\x60\xa0\x53\x23\x8d\x37\xe8\x4a\x29\x27\x22\x34\x12\x60\x30\x6c\xce\x3b\x43\x3f\xb1\xe8\xc9\x83\x87\x15\xaf\xa2\x9d\x69\x44\x41\x8b\x94\x24\x2c\x47\x87\x9e\x55\xd3\x04\xd4\x22\x11\x1f\xa6\xc4\x86\xce\x25\xa2\xa9\x7a\x3a\xf4\xab\x22\xa5\x2e\x6b\x89\x11\x4f\x07\x76\x52\x9e\xd8\x31\x82\x9e\xaf\x63\x4a\x3e\x22\x8c\xb1\x09\x38\x26\xbb\x32\x24\x50\x0e\x76\x86\x74\x31\xa0\xb1\x21\x01\x06\x86\xa6\x03\xed\x70\x58\xf5\x87\x07\x65\x43\xfe\xe6\xb7\xfc\xf4\x2c\xd1\x36\x11\x0c\x0f\x52\x4c\x04\xf1\x5f\xc9\xf2\xdd\xac\x59\x20\x1a\xdc\x48\x01\xce\x70\xa1\xa4\xe0\xc9\xa4\x34\xff\x37\x20\x95\xb0\x65\x24\xd8\xfb\x26\x76\x1c\x62\x00\xec\xed\x48\xe1\x53\x40\x7d\xc8\xdc\x40\x29\x95\x04\xa1\xb0\x0c\x3a\xc3\x08\x62\xe7\xc8\xb6\x9c\x5f\xdd\x0c\xac\x92\x53\x6e\x4b\x93\xba\xc8\xa1\x62\xe7\x62\x37\x20\x11\x40\x30\x1c\x92\x0a\xd0\xdc\x36\x27\x7f\xe2\xb3\xa0\x24\xe3\x39\x4f\xe4\x0e\x41\x39\x4c\xc0\x92\x16\x49\x44\xb4\xe5\x92\x02\x63\xc0\xb8\xf9\x56\xa9\x1a\x01\x38\x9e\x50\x57\xa3\x7f\xe0\x8f\xdc\x30\x67\xfd\x00\x75\x3c\x9c\x1f\x44\x62\xd9\xc5\xe0\x62\xc3\x93\xc8\x6e\x5f\x83\xbf\x56\xb3\x44\x60\x87\xb2\x18\x06\x1e\xe2\xc2\x2e\xd0\x7a\x1d\xf2\xec\xf7\x47\x07\x52\x85\xb0\x9a\x02\x0b\x12\x8e\x49\x59\x2b\x51\x3f\xc0\x16\x88\x27\xea\x86\x7b\x08\x7f\xe7\x60\x80\x46\xa7\x0b\x91\x7e\xca\x49\xfd\x5b\xa3\x41\x9f\xac\x00\x7e\xc2\xf7\x4c\x4b\xbc\x48\x99\x2a\x45\x8c\xe6\x97\x5e\x11\x12\xe8\x8a\x1f\x41\x7d\xf2\x86\x31\xd5\x0c\x5e\x88\x74\x6e\x58\x28\x2a\xda\x11\x94\x81\x8e\x4b\x8f\x71\x77\x66\x29\x96\x0e\x5e\x39\x2d\x52\xe4\xe7\xf2\xf5\x1b\x52\xca\xf3\xf2\x28\xed\x0e\xb1\xd0\x0e\x34\x37\xad\xfd\x29\x05\x84\x74\x9d\x95\xa8\xdb\x5b\x43\x6c\x2c\xb8\xf1\x32\x4d\xaa\x28\x59\x72\x61\xb1\x1c\x10\xb8\xca\x63\xd8\x17\xcf\xcd\xa8\x3e\x6a\x26\x08\xb3\x66\x78\xe2\x2d\xfd\x57\x79\x92\x9d\x64\x6b\xc1\xdc\x0c\x8f\x64\xad\xe5\x19\x32\x12\x16\x1e\x30\x4d\x26\x09\x04\x28\x62\x93\x9c\x45\xaf\x35\x69\xc4\xc7\xac\x4b\xd1\x2c\xed\x8c\x33\xe4\x39\xd2\x45\x42\x5c\xc3\x86\x72\x51\x77\xa9\x57\xa1\xbe\xf0\x29\xe8\x45\xaa\xf4\x02\x63\xd0\x04\x57\x58\xa2\x13\x0f\x6e\x29\x68\x58\x5d\x35\x04\x0c\x9d\xa1\xf8\x0a\xd5\xc4\x43\x02\x48\xf4\xe1\xd1\x08\xf4\x9e\x1e\xe1\x57\x03\xb0\x23\xda\xbf\x20\x25\xa9\xa0\x5d\x6c\x1b\x00\xcf\x32\xde\xdc\x63\x3e\xd3\xb8\x20\xb9\xff\x00\x13\x79\x7b\x39\x2c\x10\xa8\xed\x70\x4e\xca\x57\x82\x24\x54\xa8\xfb\xc0\x23\x79\x76\xab\xc3\xb9\x9c\xad\x3e\x66\x6e\x31\x1b\x63\xf1\x74\x40\xb1\xa6\xb4\xfa\xd7\xda\x9c\x81\x3c\x93\xf9\x36\xdd\x29\xb4\x61\x06\x90\xf9\x4c\x1e\x6b\x89\xf4\x08\xc7\xe7\x06\xa0\x37\x1d\xfc\xf9\x02\x9a\xac\x1c\xda\xd6\x76\x03\x42\x18\xd8\xe7\x65\xd1\x4b\x7a\xcb\x97\x33\xd7\x11\xc6\x9b\xf6\xc4\x52\x21\x53\x64\xc9\xa2\xcd\x4e\x5d\x08\x4f\xe7\xce\x8a\x46\x57\x4b\xa2\x73\x21\xc8\x31\x5c\x18\xc4\xcd\x4e\x3c\x73\x3c\x72\xff\xa6\xc1\x2f\xc4\x52\xb5\x24\xd0\x02\x6b\x44\x77\x7b\xd5\xc4\xbf\x0b\x5b\xdb\x9d\xbb\x1a\xc2\x52\x1f\xb6\x7c\x02\xd5\xdc\x4f\xcd\x71\xae\x83\x26\x5f\xa7\xbe\x2b\x31\x93\xde\xf2\xd6\x1e\xd4\x87\x0b\x36\x1a\x82\x0b\xbb\x78\xed\xa7\x3f\xfa\x1d\x8a\xfb\x29\x2b\xaa\xe5\xca\x2c\xdd\x91\xc5\xc0\xe0\x58\x76\x76\xb2\x55\x76\xb0\xa0\x38\x5b\x72\xd5\x52\xe3\xa1\x9b\x8a\xe7\x0e\xf1\xe9\xae\x97\xe4\xaf\x79\xf9\x7a\x17\x46\x00\x64\x04\x88\x80\xdd\x38\x17\x91\x92\x77\xaf\xf7\xa1\x00\xb9\x74\x37\xd1\x1b\x3c\xa7\xbf\xc7\x91\x3f\x6c\x81\x15\xfc\xd1\x3c\x07\x89\x30\xf3\x1e\x74\x0f\x63\x38\x85\x2a\x66\xa0\xe8\x0a\x02\x8a\x86\x1c\x27\x9d\xae\xd3\x00\x9d\x9a\x61\xd3\x39\x12\x76\x60\xf9\xea\xd9\x05\x38\x1a\x60\x23\x86\x19\x24\x78\x10\xd2\x11\xaf\xb7\x6a\xc2\x9b\xd6\x29\x4e\x65\x95\xc1\x57\x43\x85\x86\xc5\x56\x2f\x16\x87\xc4\x5c\x18\xa3\x9c\x4a\x9e\x0c\x57\xdb\xe2\xb4\x2b\x8d\x7d\xee\x0d\x84\x98\xb2\xb3\x7b\x7c\x33\x18\xcb\x5c\x79\x9e\x52\x42\x46\xcc\x82\x64\x14\xd6\xed\x61\x40\x60\x1c\xef\x23\x22\xf7\x13\x86\x88\x0a\x43\x03\xc1\x69\x79\x8e\xb8\xf6\x81\x88\x91\xc5\x89\xe2\x42\x6c\x93\xed\x5b\x42\xcd\x5e\xa4\x94\x6d\x99\x84\xf7\xd4\x82\x8b\x7a\x34\x97\x05\x95\x32\x82\x49\x4b\x6a\x8f\xf2\x62\x02\xd7\x3e\xb1\x38\xe1\xc2\x30\x25\xc2\xd3\x16\x69\x9c\x34\x89\xe3\x51\x86\x47\xc3\xb0\x85\xb8\x5a\xe8\x84\xe9\xa2\x44\xf9\x8b\x12\x07\xc4\x02\x71\x2d\x0a\x4d\x7a\x06\xb2\x19\x26\xf4\x4f\xc3\xa3\xee\xf6\x40\xd8\x95\xed\xa4\x93\x55\x90\x06\x88\xbd\x7c\x24\x48\xa4\xa4\x0e\x25\x7b\x60\xc8\x66\xe8\x12\x78\x59\x85\xb6\x60\x56\xd4\x0b\xdc\x95\x6c\x5c\x0a\x3b\x49\x25\x98\xe1\xdc\x42\x87\x2d\x6b\x54\xa2\xc7\x9c\xa2\xf7\x82\x53\x02\xba\xf2\xc4\xae\xe1\xa0\xdb\x41\x75\xfb\xd8\x43\x2d\x02\x6b\x97\x3d\xe1\x44\x00\x0c\x09\x55\x95\x10\xe3\x4b\x9c\x03\xfc\x54\x8c\x3d\x4b\x38\x22\x70\x87\x10\x9f\xc0\x42\x34\x18\xda\x70\xa4\xa9\xc2\x27\x5b\xfd\xb4\xac\x87\x08\x61\x31\xb7\x24\x54\xc2\x32\x09\x24\x29\xfd\xf9\xe8\xf9\xd5\x50\x27\xd7\x4a\x58\x93\x61\xb7\x26\x2c\xc0\x48\x6d\x63\x77\xf0\xe3\x26\xb5\x80\x8b\x6e\x62\x7d\x1f\xc4\x04\x80\xa0\x71\xfa\x22\x83\xc5\xab\x2a\xae\x51\x31\x91\x6a\x3f\x6e\x1c\x1d\xa4\x34\xc1\x75\x6c\x5d\xce\xae\x16\x26\xcb\x6f\x9f\xc8\xc0\x27\xf8\x3f\x9d\x11\x7c\x6f\x75\xe6\xb9\x29\xa4\x92\xea\x13\xde\x4a\x57\x23\x9a\x7e\x80\xf5\x09\x80\x75\x09\xc0\x97\x03\xc4\x6c\x46\xca\x90\xba\x58\x48\x9e\x36\x15\x37\xec\x85\x85\xcc\x05\xfb\xde\x0c\x52\xf3\x3e\x90\xf8\xa6\xab\xc5\x69\xd1\x88\x48\x37\x9d\x57\x7e\x4a\x32\x10\x6e\x19\x5c\x19\x24\x56\x85\xce\x9a\x1c\xd5\xb7\xe9\x0b\x8c\x52\xf2\x54\x85\xb2\x39\x28\x0e\x92\xa4\xc4\xce\x84\x8a\x97\xd6\x5f\xc8\x6f\xaa\x60\xc0\x25\x53\x2a\xd9\x01\x20\xb4\xf9\x73\xac\x28\x60\xe8\x8c\x94\x58\xbd\x8c\xd4\x8e\xe3\xb0\xf8\x4c\xab\x26\xc4\x72\x93\x1d\xe9\x3e\x31\x91\x63\x0d\x90\x8f\xb5\xf3\xd8\x33\x6b\x81\x10\xad\xd1\x69\xe5\x8b\x37\x23\xde\xe4\x2e\x78\x83\x1f\xa2\x72\xc1\xf7\x07\x0c\x01\xd4\xc0\xc5\x0a\x4d\xa5\x85\x40\x68\x95\xa1\x2b\x71\x82\x17\x84\xb4\x2a\x3e\xf7\x55\x02\x86\x3c\xa8\x96\x9e\x27\xdc\x8a\xf2\x8f\x19\xf1\x44\x30\xed\xc3\x66\xa3\xf7\xf6\x24\xb4\x3c\xcd\x55\x58\x42\xb4\xa9\x9e\xd9\x52\xf9\xb8\xb3\x1c\xc3\x62\xf6\xd5\xcf\xf5\x3f\x08\x10\xae\xd1\xbb\xa6\xd4\x80\x5b\x8e\x1b\x08\x50\x7d\xf5\x3e\xe9\xd8\x35\x12\x25\x9c\xa8\x2c\x87\x93\xaa\xc2\xf7\xbe\x5b\x0e\xba\xa2\x96\x02\x98\x44\xed\xb7\x18\x48\x1d\x2d\xb7\x4b\xc3\xdb\x13\x74\xad\x85\x09\x39\xfa\xb7\xea\x1f\x07\xc4\x89\xa0\xca\x4b\x8e\x81\x45\x40\x71\x78\xbe\x5c\x0e\x9e\x78\xc9\xd9\xfd\xd1\x58\x3c\x48\x1a\xa1\x78\xdc\xd9\x1c\xb1\x12\xca\x02\x0a\x5e\x5e\xd7\x86\xf8\x0f\x53\xe7\x6c\x79\x09\x49\x64\x40\x7e\x71\x78\x60\x38\xe8\x59\x10\x62\x56\x38\x19\xc5\x93\xce\x2d\x89\x48\xe2\x1b\x83\x68\x7c\x84\x0a\x5d\x69\x28\x88\x66\x67\x78\x5b\x80\xe1\x7a\x42\xf5\xf6\x14\x74\x44\x03\x35\x8a\x9c\xc6\x10\x24\x3e\xe9\x73\x5d\xe0\xa6\x8c\xe6\x2f\x14\xb3\x04\xf3\xa4\x88\x06\x54\xcd\x99\x6d\x6d\xb2\x51\x95\x27\x70\xb9\x16\x7c\xbc\x1c\x29\x1a\x86\x72\xaf\x6f\x51\xd9\x88\x2c\xff\x62\x82\x01\xf7\x25\xac\xd6\xf6\x89\x09\xa5\x4f\xcf\x45\x68\x10\xd7\xb9\x72\x40\x21\x92\xe5\xf6\x21\x17\x9d\xc1\x1c\xe7\x86\xb6\x8a\x01\x62\xe0\x97\x50\xf5\x31\xe7\x00\x83\x4a\xe0\xfe\x11\x93\x97\xa2\xfc\x76\x44\xaf\xfa\x9c\xb8\x24\xb2\x9a\xc4\x48\x68\x14\xe8\x01\x3d\x3c\x9a\x05\x3b\xad\x67\x28\x00\xa4\xb1\xd0\xa4\x81\xec\xae\x72\xb5\xa1\xd8\x6f\x6a\x3a\x87\xec\x37\xd3\x3c\x09\x11\x08\x94\x96\x52\xb4\x94\xa7\x23\x4b\x11\x70\x9c\x03\x00\x23\x69\xf4\x38\x43\x2b\x80\xa4\x75\xb4\xa5\x01\x1d\xb4\xcf\xd5\xe6\xeb\x92\x11\xbd\x5a\x41\xf5\x7b\xc5\x9e\x5b\xd9\xe2\x0a\x50\x55\x89\xe1\x90\xa0\x83\x5b\x01\x55\x62\x11\x3a\x33\x6f\xd8\x3d\x00\x0c\xb0\x4f\xa7\x25\xe3\x48\x32\x3c\x9e\x57\x94\xca\xef\xc9\xa1\x21\xf4\x54\xd5\x7f\x0f\xba\x75\x55\x93\x1d\xae\x19\x7b\x6b\x3b\x10\x38\x14\xeb\x06\x84\x59\x70\xc0\xf8\x59\xa4\xba\xd9\x37\xed\xf9\xb2\xc4\xc3\x04\x40\x99\x80\x9b\x6d\x5d\x69\xbf\x33\x53\x5d\xae\x5e\x0e\xcc\x33\x87\x52\x78\x55\xa0\x31\xd6\xcc\xd7\xde\x02\x6a\xb0\xac\xc3\x81\x8e\xe6\x2d\x4c\x4a\x57\xc6\x83\x90\x61\xed\xf3\x51\x17\xeb\xa8\x93\x5f\xdd\x16\xbf\x26\xe9\xf0\x74\x14\x62\x7e\xc1\xb3\xc4\xc3\x89\xc1\x24\x11\xf8\x4e\x62\x65\x39\xac\x80\x66\x01\x8f\x8e\x98\x2b\x17\xa7\xdf\x95\x18\x29\xd5\x08\x4c\xff\x3c\x5b\x78\xfc\xf1\x6b\x8d\x35\x56\x4b\xb4\xcd\x28\xf4\xf3\xe1\xa3\xeb\xca\xe3\xdf\x21\xeb\xc7\x27\x82\xfe\xc4\x68\xf9\x81\xeb\xc3\x84\xfe\x23\x7a\x14\x34\x06\x70\x3b\xa6\x96\x16\xe0\x96\xf6\x13\x5c\xad\x60\x2a\xfe\x8b\xa7\xbd\x24\x6a\x5c\x87\xf3\xc0\xb8\xee\xb2\x20\xc8\x5d\xba\x75\x44\x1f\x19\x57\xb1\x11\x07\x00\xbc\xbb\x51\xad\xc5\x44\x0b\x5c\x95\x8f\x34\x13\xda\xe9\x42\x3e\x22\xb7\xed\xe9\xe6\xc2\x27\xe6\x98\x03\xfc\x0d\x80\xef\xbb\xd5\x78\x95\x2f\x06\x6b\x7d\x6c\x33\x87\x6a\x79\xaf\xad\x86\x70\x45\x27\xbd\x40\x06\x55\x89\xc4\x49\xc7\x3a\x17\x87\x7e\x46\xf9\xdb\xd0\x8d\xad\xd6\xa0\x55\x06\xc0\x3a\x14\x00\x11\x90\x63\x91\x81\x82\x23\x6f\xee\x2f\xa2\x76\x5e\x1b\x62\xc6\xc1\xaf\x2e\x25\xd1\x24\x4d\xe1\x72\xa1\x5b\xec\x7b\x5b\xf0\xbc\x3f\xd2\xb6\x16\xbe\x8d\x6d\x3d\x82\xfe\xed\x17\x90\x23\x96\xef\x15\xa0\xde\x75\xd5\xd2\xfd\xb7\x80\x56\x1b\x14\x25\xfd\xb0\x07\x44\xf7\x6e\x29\xed\xe5\x01\x2e\xe5\x6c\x38\x9c\xf7\x12\x61\xb4\xf1\xae\x5c\xa8\x0b\x6d\xd8\x47\x9d\x65\x62\xc2\x22\x21\x51\x63\x83\x2c\x23\xfe\xe4\x95\xf0\x8a\x94\x0c\xc9\x08\x97\x1b\x0a\x68\xd6\x74\xe9\x36\xdd\xfc\xcb\xf6\xd5\x82\x20\x2a\x47\x97\x42\x27\x6e\x0f\x77\xac\x75\x84\x63\x98\xae\x52\x84\x7a\xdc\xa6\xd5\xcc\x77\x69\xc9\x57\xe1\x12\x3b\x99\x12\x64\x54\x7d\x8e\x08\x0f\x71\x71\x50\xf3\x1c\x31\x01\x64\x73\x86\xa4\x35\x56\xf5\x65\x63\x1f\x1e\xc8\xcb\x92\x49\xe2\x8c\x25\x9e\x27\x43\xc9\x2a\x8f\x27\x90\xa6\x25\xea\xe2\x93\xc6\x5f\x84\x68\x80\xd5\xd0\x80\xdd\x9e\x4d\x12\x4d\x79\x61\x18\x91\x27\x9e\xc7\x85\x14\x6d\xc5\x8d\x3c\x32\xe1\x1f\x11\x39\x21\xb4\x8f\x9b\xd8\xb9\x68\x46\x70\xaf\x59\x75\xa0\x93\x81\x68\x46\x56\x50\xc5\x22\xc4\x23\x0a\xa7\x0c\x17\x9c\x30\x34\xc1\x04\xfc\x24\xfa\xe0\x45\xb0\xd0\x7a\xc2\x31\xe2\xc4\xcd\x44\xb2\xfd\xd6\xa5\xf8\xa7\x91\xc6\x4f\x2f\x92\x10\x05\xf7\xa9\xdd\x4b\xf2\x55\x43\x64\xe5\x2f\xcd\xd0\xa4\x19\x54\x7d\x2a\xe9\x7e\x80\xda\xdf\x77\x1c\x16\x91\x87\x43\x56\xd1\x98\x2b\x43\x8f\xb5\x04\xe1\xe2\x9d\xab\x1b\xda\x1f\xea\x7e\x0f\xb6\x96\x10\x44\x19\xe2\x87\x81\x6e\x31\x42\xf9\x6d\x29\x76\x34\x5d\xd6\x01\xa0\xec\xd8\xe6\xe3\xc3\x21\x4d\x6f\xc6\x84\x41\xd7\xa6\x21\x8e\x50\x88\x3d\x39\xeb\xd7\x4f\x28\x64\x77\x12\x29\x08\x09\x79\x18\x0f\x63\xf2\x78\x42\x48\xbe\xd8\x0a\x87\xe5\xe0\x93\x96\x0e\x71\x68\x5b\x43\x89\x08\xe8\x4c\x66\xce\xb2\x4f\xc9\x1c\x66\xf5\x90\x23\x9e\x0d\x4d\xa0\xcc\xcc\xdd\x44\x88\xaa\xb2\x2b\x52\x54\x40\xb2\xe5\x99\x99\xe8\xf9\x09\x7a\x98\x86\x43\xcd\x96\x48\x07\xb9\x65\x44\x56\xcb\x09\x00\x49\xe4\xfd\x4e\x29\x11\x35\x44\x2d\x83\x0f\xcf\xc5\x48\x12\x85\x01\xb8\x20\xc3\x70\x2f\x01\xe3\xd0\xf4\xd8\x49\x91\x6f\x1f\x01\x32\xa3\x53\xed\x90\x7a\xfd\xd4\x38\x50\x18\xfb\x43\x84\x42\x3a\xc5\xdc\x4d\xaf\xee\x05\x58\xcb\x12\xc7\x1f\x99\x80\x8b\xee\x10\x4f\x25\x47\x40\x54\x7f\x17\xd6\x6b\xc4\x87\x81\x49\xcd\x21\x1e\xa0\x3f\x51\x52\x0d\x54\x54\xa4\xb1\x1a\xfe\x54\x10\x11\xd4\xeb\x18\xa9\xb0\xbe\x2d\xf4\xb8\x35\x17\x81\x40\xc7\x0a\x6d\x04\xa2\x17\x02\x15\x9c\x4b\x5a\x8a\x3d\x0b\x89\x6e\x4c\xb3\x22\x11\x9d\x10\x66\xb9\x91\x3f\x5f\x12\xe0\x28\x92\x58\xa5\xff\xdd\x06\xd0\xa2\x52\xac\xd5\x22\xa0\x2c\x2d\xb2\x17\xd3\x38\x33\x8d\xf5\xbc\x9a\xc5\x99\x36\x90\x7b\xa4\x8f\xd3\x57\x3e\x92\x42\xdb\x17\xe0\xfb\x72\x7a\xb6\x2c\x4a\x51\x8d\x90\xe2\x05\x06\x1c\x77\x01\xe1\x2c\x09\x3d\xb8\x30\x49\xfc\x5e\x7d\x83\x03\x24\xb3\x8c\x5a\x76\x30\x04\xe1\x36\x3e\x0c\xc1\xc6\x07\x00\x16\xd2\x0b\x8f\x9d\x12\x78\xa2\x6c\x6e\x00\xe0\x52\x1f\xdb\xe8\x23\x86\xb7\x7c\x42\x8a\x43\x84\xc7\x3f\xcd\x25\x3d\x76\x43\x54\x1d\x36\x9b\xa9\x4d\x9d\x78\x46\xb0\xc6\x39\x6c\x01\x3a\x8a\xf2\x63\x30\xa3\x0c\xb6\xdc\x1c\x97\xce\x89\x5f\xd7\xd1\xb5\xdd\xb2\x1a\x91\x43\xa7\x5e\x89\x18\x37\x95\x06\xda\x68\xab\xfc\x4d\x9b\x0e\x97\x98\xc0\x45\x35\x91\xab\xaf\x38\x1f\x08\x83\x61\xa3\x96\x62\x10\xe7\x8c\xc8\x89\x00\xcc\x94\x8a\x66\x79\x5c\x3a\xf2\x01\xe1\x84\xbf\x49\x2b\xa4\x80\x63\x63\xe4\x15\x79\x95\x07\x83\xa2\x92\x65\xe0\x24\x0c\x58\x84\xe7\x0e\x9c\xeb\xe9\x4b\x5b\xd7\xf6\x1d\x58\x04\xea\xb6\xb6\x36\x72\x31\xb4\x70\x1b\xc3\x8f\xb5\x7b\xe4\xe3\xc5\x00\xf2\x17\xc4\x98\x3d\x3d\x43\x70\xc5\xc6\xeb\x4f\x11\x99\xde\xd7\xa9\xec\xd6\xb7\xb4\x92\x9a\xc3\x71\x4b\x1e\x98\xe5\xb0\xb3\x68\xcc\xdf\x94\x4e\x61\x33\x35\x39\x09\xfd\x73\xc8\x93\xc0\xac\xf3\x13\x81\x04\xcc\xc4\x79\x38\x38\xbc\x86\xe6\x68\x3c\x6f\xda\x01\x7f\xb8\xd4\x48\x98\x3b\x12\x4a\x40\x5a\x61\x02\x3e\x64\x98\x80\x09\x79\xfd\x06\xa7\xd1\x89\x89\x5c\xff\x26\x4e\x4d\x62\x60\x22\xba\xb9\x5f\xbc\x49\x34\xdc\xa9\xe4\x44\xea\x2a\x85\xc1\xc1\xba\x46\x0a\xd2\xf7\xc6\xbd\x5a\x2a\xdc\x63\xdc\x64\xc6\xa2\x31\x31\x91\x2b\x1f\x15\x41\x23\x66\x64\x08\x32\x16\x6f\x13\x93\x60\xb8\xf4\x35\xaf\x87\x33\x0c\xda\x98\xab\xc8\xf7\x14\x57\x4e\xb6\x2e\xa1\x0c\xb3\xbf\x1d\x8a\x25\xeb\xda\x17\x47\xcb\x88\x40\xf8\xbf\x10\x85\x4f\x40\x2c\xc7\x2e\xa0\x16\x1b\x42\x70\x00\x8c\xd4\xd6\xb4\x2f\x45\x67\x66\x2e\xa9\x51\x28\x3b\x7a\xc1\xf9\x05\x81\x66\x39\xb3\xb7\x1d\xd9\xb8\x17\x2c\xc7\x39\xc7\xcc\xae\xe0\x5a\x1f\x22\x2f\x9e\x38\x48\xb2\x01\x14\x34\x20\x44\x59\xde\x3a\xe8\x2c\x07\x6d\xf2\x7d\x48\xbf\x40\xfa\xe1\xaa\x50\x1b\x2e\x1d\x69\x13\xa9\xa2\x5d\xc4\x7d\x06\x2e\x71\x69\x2a\x09\xe8\x77\x2f\xbf\x22\x55\xc2\x0e\x9c\x9d\x1c\x78\x41\xe2\x89\xba\xd2\x39\xc4\x49\x31\x24\xcb\x1e\x14\xce\xc9\x53\x72\x4b\xad\x8a\xae\xeb\x5d\x75\x91\x89\x62\x87\x45\xfb\x7b\x21\x33\x62\x54\xc9\xe9\x70\x3b\xfe\x13\x01\x15\xcd\x9b\x6e\xda\xfa\x88\x67\xf8\xa5\xeb\x27\x44\xa0\x58\x12\xe9\xe5\x4b\x0b\xc6\x60\x95\xdd\x98\x8f\xb7\xb1\x90\xbd\xbb\xa5\x6b\x02\x34\xe6\x55\xc0\xc4\xca\x7e\x1c\x5f\x8e\x25\x56\xd9\xd4\x0b\x6c\x14\xa7\x26\x0f\x61\xf7\xc4\x7c\x80\x4b\xa4\x90\xe4\x2c\x6e\x9a\x04\xf1\xed\x2e\xa7\x41\x46\xda\x97\x33\xc0\xa5\xf5\x7c\x67\xc0\x07\x51\xec\xfb\xea\x2c\xf8\x31\xc6\x22\x88\x82\xa9\x08\x31\xd8\x9b\xa4\xf6\x77\xd5\x3d\x3b\x36\xfa\x06\x84\x1e\xdf\x4a\xd0\x64\x96\x5d\x0d\xcc\x2f\x0b\x49\xdf\x32\x2c\x36\x0e\x41\x68\x10\x95\x21\x6a\xd6\xe5\x76\x2b\xa3\xcd\x17\x61\x24\x12\x85\x42\x99\x4b\x0b\x3f\x66\xcd\x55\xad\x55\xd8\x6d\x32\x04\x19\x42\x97\x61\xa2\xa8\xce\x08\x4d\x88\xf7\x8c\xa6\xc6\xb6\x1a\x36\x62\x23\xd4\x93\x0f\x95\x9c\x4e\xe4\x8e\x0f\xd8\x82\x32\x25\xf9\x43\x20\x80\x48\x64\x10\x09\xc3\x10\xa0\x13\xd4\x47\x37\xe8\xdc\x37\x5f\x0d\xdd\xad\x86\xbc\xef\xd1\x9e\xb7\xa2\x1d\xc9\x2d\x10\xc1\xde\x9b\x7a\xd1\xa6\x3f\x21\xaf\xa9\x57\xaa\x74\xa2\xd1\xae\x88\x8b\x99\x1c\xbd\x58\x90\x18\xc1\xd6\x8c\xf4\x1a\xd8\x76\x66\xae\x03\xcf\x93\x95\xa1\xd5\xca\x26\x20\x01\x00\x00\xff\xff\xb5\x8e\x0e\x07\x1e\x62\x00\x00") func fontsRobotoslabBoldWebfontEotBytes() ([]byte, error) { return bindataRead( _fontsRobotoslabBoldWebfontEot, "fonts/robotoslab-bold-webfont.eot", ) } func fontsRobotoslabBoldWebfontEot() (*asset, error) { bytes, err := fontsRobotoslabBoldWebfontEotBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "fonts/robotoslab-bold-webfont.eot", size: 25118, mode: os.FileMode(509), modTime: time.Unix(1492020681, 0)} a := &asset{bytes: bytes, info: info} return a, nil } var _fontsRobotoslabBoldWebfontSvg = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\xbd\xe9\x7e\x24\xc7\x91\x27\xf8\x79\xfa\x29\x7c\x4a\xbb\xbd\x17\x1c\x74\x33\xbf\x47\xa2\x7a\xd9\x12\x47\x3b\x92\xd0\xa4\xba\x29\x52\xd4\xec\xec\x6c\x1d\x28\x06\x57\xa1\x2a\x46\x55\x30\x44\x61\x8f\x67\xdf\x9f\xfd\xcd\x23\x91\x80\x67\x24\x12\x28\xf0\x18\x4a\x5f\xaa\x02\x19\x1e\x7e\x9a\xdb\x7d\xfc\xec\x9f\xbe\xf9\xf3\x68\x96\xcb\x37\x6f\xbf\x7c\xfd\xea\xfd\x27\x74\xee\x9e\x98\xb7\xf3\xd3\x57\x2f\x9e\x8e\xaf\x5f\x5d\xbe\xff\xe4\xd5\xeb\x27\xff\xf4\xf3\x7f\xf8\xd9\xbf\xff\xe5\x47\xbf\xf8\xe4\xf3\x8f\x3f\x34\x6f\x97\x2f\xcc\xc7\xbf\xff\xe7\xdf\xfe\xa7\x5f\x98\x27\xf6\xbd\xf7\x3e\xf3\xbf\x78\xef\xbd\x5f\x7e\xf2\x4b\xf3\x6f\x9f\xfe\xca\xd0\x39\xbd\xf7\xde\x87\xff\xf2\xc4\x3c\x19\xe6\xf9\xab\xff\xf0\xde\x7b\x7f\xf9\xcb\x5f\xce\xff\xe2\xcf\x5f\xbf\xf9\xe2\xbd\x5f\xbd\x79\xfa\xd5\xf0\xe5\xf3\xb7\xef\xfd\xdb\xa7\xbf\x7a\x4f\x1a\xfe\xf2\x93\x5f\xbe\xf7\x76\xf9\x82\xe8\xfc\xc5\xfc\xe2\x89\xf9\xf9\x3f\xfc\x4c\xba\xfe\xe6\xcf\xe3\xab\xb7\xef\x1f\xf8\x9e\x9d\x73\xd2\xfe\xc9\xcf\xff\xe1\x67\x7f\xbe\x9c\x9f\xbe\x78\x3a\x3f\xfd\xf9\xcf\xde\xdb\x3d\xfe\xc3\xcf\x5e\x5c\xbe\x7c\xfb\xf3\x7f\xf8\xd9\xcb\xd7\xaf\x66\xf3\xe5\x8b\xf7\x9f\xbc\x79\xfd\xec\xf5\xfc\xfa\xbf\xbe\x1d\x9f\x3e\x7b\xf6\x7a\x7c\xf1\xc4\x0c\xaf\xdf\x7c\x79\x65\x9f\xbe\x58\xec\x37\xef\x3f\xa1\x90\x09\xa3\x4a\x7b\xfb\xf2\xe9\xf3\x4b\xf3\xf5\xab\x2f\xe7\xb7\xf6\xab\xcb\x37\xf6\xf2\xcf\xef\x3f\x61\x17\xca\x13\xf3\xf4\xed\xf3\xcb\x57\xf3\xfb\x4f\x28\xf9\xf2\xc4\xbc\xb8\x6c\x7f\xda\x40\xee\x89\x79\x4f\xe6\xf2\xe5\xdb\xb7\x5f\xbe\xfa\xc2\x7e\x31\xfe\xf5\xab\xe1\xe6\x10\xd1\xb1\xb6\xd1\x77\x5f\xbf\xfa\xf2\xf9\xeb\x17\x97\xef\x3f\xf9\xc7\x9f\x7c\xf3\xf2\x99\xa3\x9f\xde\x9e\x91\xf7\xf9\x89\x79\xf1\xfe\x93\x0b\x1f\x4c\xc9\x79\x61\x17\x07\x4a\xb4\xe4\x30\x39\xc3\x2e\x18\xe2\x70\x1e\x8d\xa7\x70\x1e\x67\x1f\xdd\x79\x34\x44\xee\x3c\x4e\xb9\x18\x67\x28\x06\x63\x29\x9e\xc7\x99\x72\x32\x36\x84\xf3\x38\xda\xc0\xc6\xb2\x77\x93\xcd\xde\x30\x1b\x4b\x9e\xa5\x87\x30\x5b\xf2\x49\xbe\xe7\xc9\x92\x23\xe3\xe4\x53\x3a\x8f\xc6\x86\x34\x5b\x74\x6d\xc9\xc7\xc5\xe6\x30\xa4\x98\x16\x5b\x72\x1e\x29\x46\x63\xbd\x5b\x2c\xe5\x38\xd8\x58\xca\x42\x39\x8e\x14\xc8\x78\xb7\xa4\xcc\x83\xf5\x29\x2c\x36\x65\xc6\x8f\xfb\x4d\xab\x36\x8d\x69\xd7\x94\x12\x5d\x1d\xd9\x1d\xee\x76\x27\x30\xb5\xdd\xa9\xc6\xf5\xdd\xf9\xa4\xfb\xe5\xd3\x12\xb2\xec\x17\x65\x43\x9e\x8c\xf7\xd8\xad\x54\x0d\x51\x3e\x8f\x53\x49\xb2\x57\xd9\xad\x7b\x55\xa3\xee\xd5\x40\x99\x17\x4b\x9e\xd2\xed\xc9\xe7\xb0\xbf\x4e\x22\xaa\x93\x8d\xb2\x75\xc6\x92\xab\x86\xea\x6c\x89\xb2\xc9\x93\x25\xf2\xd8\x49\xe9\x3d\xca\x3e\x66\x63\x29\xc5\xc5\x86\x3c\x70\x70\x8b\x95\x19\x5a\x3c\x1d\xdc\xa4\x1b\x1b\x72\x63\xf5\x0a\x8c\x27\xbe\xdc\xdf\xca\x17\xb7\xf7\xf1\x16\x50\xde\xec\x88\xe3\x56\x3f\xf5\x76\x3f\xee\x60\x4b\xf3\xc4\x9c\x7c\x07\x5c\xd7\xe7\x91\xc6\x4f\xdd\xa9\x8d\xff\x7d\xd7\xae\xdd\x2a\x22\x01\x1c\x8e\x69\xe0\xca\x8b\x95\x07\xcb\x95\xaf\xf0\x22\x3a\x5e\x6a\x0c\xfa\x4a\x1e\xf0\x6a\x6b\x36\xdc\x81\x67\x2e\xdc\x46\x09\xce\x90\xf3\x75\x89\x4c\x03\xbb\xb4\x58\xce\x3c\xda\x9c\x8d\xe5\x50\x07\x4b\x5c\xaf\x2e\x42\xca\xfb\x8d\x62\xdf\xa8\x1c\x1e\xfb\x27\xb7\x6f\x05\xd5\xb2\xbb\x15\x81\xdc\x42\xa9\x0e\x1c\xd3\x18\xc9\x70\x75\x83\x65\x4f\x0b\x65\x1a\x38\xd1\x98\x83\x09\x94\x06\x2a\x7e\x14\x7c\x60\xf1\x47\xe5\x31\xfb\xf6\x7b\x18\x6d\x0e\xfa\x3b\x33\xe0\x92\x06\xcb\xd1\x8d\x36\x92\xb1\xd2\x1f\x73\x5a\xac\x8c\x61\x39\xc6\xd1\x66\x96\xd6\x6e\xb0\xd2\x67\x66\xa3\xcf\x95\x6f\xbc\x09\xbb\x37\xcc\xf9\xea\x22\xe4\x6a\x62\xae\x18\x79\x9d\x25\x6d\xed\xf5\x7f\xd7\xad\x77\x3d\xcd\x98\x4d\x08\x75\x64\x13\x07\x2e\x82\x20\x2d\xf9\x60\x92\x5c\xca\xca\xb3\xa0\x06\x1b\xcb\x54\x05\xb5\x91\xaf\xe7\xd1\x84\x72\x1e\x67\xf9\xc7\x90\x17\xa4\xe9\x4c\x21\x41\x77\xf8\x81\x67\x4b\x51\x5a\xd5\x38\x59\x66\xc6\x3b\xcf\xd5\x50\x71\xe7\x71\xb6\xe4\xb2\xe1\xa2\x9f\x51\x2a\x86\x5c\x3e\x8f\x86\xb3\xa0\x10\x2e\x15\x98\x34\x9d\xc7\x85\x29\x0e\x14\xeb\x62\x99\xca\x44\x39\x1a\xcb\x49\x9b\x19\x4b\x32\xd6\x5c\x65\x06\xd6\x93\x17\xf4\xec\x8d\x15\x84\x80\xf9\x13\x15\x63\x83\x8c\x28\x93\xf1\x6c\x52\x98\x2c\xb0\x95\x80\x03\x50\xb3\x8c\x33\xdb\xc0\x8a\x9d\x09\xb3\xb1\xb9\x18\xc1\x5f\xd2\x4a\xfa\xa7\xe4\xe5\x8f\x1a\xcf\xe3\xc4\x4c\xc6\x96\x6c\x3c\x17\x63\xa9\xa4\x59\x96\x61\x39\x67\x6c\x97\x80\x80\xae\x43\x7e\x92\x55\x72\x55\xc4\xcf\xfe\x3c\x2e\x96\x6a\x19\x64\x57\x16\xaa\x82\xdb\x4a\x36\x54\x05\x5f\x55\x03\x2a\x22\x58\xaf\x18\xef\xfd\x79\x3c\x7c\x76\xff\x7d\x8f\xc1\xab\x9e\x9d\xac\xd2\xd5\xba\x60\x22\xc4\xd5\x14\x99\x33\x53\x9c\x19\xf4\xa9\xa4\x89\xa2\x9c\x1c\xfb\x60\x6c\x91\x4d\x2e\xde\x58\x16\x8c\xbd\xd8\x36\x7d\xae\xc6\xea\xaf\x61\xb6\xec\x59\x1a\x4e\x96\xa2\x93\x1d\x93\x0f\x4b\x9c\x6d\x09\x86\x29\x5c\x5d\x70\xf0\x18\x52\xbe\x8c\xc5\x48\xeb\x2a\x4b\xae\x6c\xac\x40\xc7\x14\x85\x84\x56\x67\xe4\x8f\xd9\xb3\x91\xb7\x3a\xbf\x58\x04\x12\x04\x34\x04\x80\x6c\x15\x2a\x19\x00\x14\xba\x5b\xfa\xec\x41\x3c\xa5\x89\x4c\xf0\xea\xc2\xbb\x62\x00\xfa\x44\x86\xc8\x17\x33\x92\xd0\xe2\x2c\x97\x86\xc8\x08\xa9\x28\x57\x17\x39\x44\x01\xab\x75\x23\x8a\xd1\xf9\xce\xec\xbd\x6e\x82\xc3\x26\xe0\x44\xdb\x36\xe0\xb8\x84\x03\xd8\x6d\x84\x77\xeb\x46\xc4\x83\x1b\x21\x1b\x2a\xdf\xda\x12\xb0\xcb\xe1\x3c\x5e\x5d\x54\x5f\x65\x64\xec\x47\x36\x68\xd4\x76\x64\xb7\xa8\x29\x45\xd9\x13\x6f\x7c\x06\x94\x1b\x72\x6e\xb7\x29\x59\x36\x05\xbb\x24\x5b\x82\x0d\x99\x6c\xc2\x90\x95\xd6\x1e\xcc\x6e\x5f\x72\xdb\x97\x4d\x84\x9a\x3a\x7a\xcf\xb9\x61\xb6\x10\x8d\xaf\xdc\x6e\x48\x8a\x86\x9d\x07\xe1\x2e\x86\x72\xc1\xb0\xc5\x54\x10\x63\x19\x8b\x52\x99\x2d\x76\x8c\x22\x6e\x6b\x96\x93\x2f\x86\x73\xd2\xbb\x2a\x88\xf7\x3c\x4e\x14\xab\xec\x6d\x2c\xeb\xb9\xcd\xb5\x62\x6f\x7d\xd1\x7b\x55\xf5\x3a\x5a\xca\x42\xe0\x05\x10\x29\xf0\x68\xab\x37\x36\xa5\x91\x85\xc7\xf2\xcc\x93\x4f\x26\x39\x13\x93\x60\x95\x99\x9d\xa1\x50\x06\xb9\xfc\x38\x19\x01\x9d\x60\x2c\x47\x61\xb8\x9c\x3c\xb9\x34\xb2\x2b\x82\xe6\xc3\x68\x19\xd7\xdf\x73\x00\xea\x2f\xd5\x4c\xb6\x44\x23\xcc\x85\x05\xee\x28\x7a\xcd\x64\x48\x16\xde\x45\xb0\x8a\xec\xb0\x0f\xd9\x10\xb8\x40\x5c\x03\x96\xe9\x5f\x5d\x78\x9f\x4d\x70\x80\x89\x52\x4d\xdc\x61\x1c\x0a\x41\x0e\x59\x80\x5c\xd8\x13\x72\x32\x57\xf9\xdd\x31\xce\x6d\xb4\xde\x39\xe3\x43\x19\xad\x5c\x70\xf2\x13\xd0\x7d\x28\xc6\x26\x6c\x49\xf5\x18\x49\x77\x8a\x64\xa8\xe0\x83\xb0\x9e\x00\x9f\xe0\x0d\xe3\x90\x8b\x6c\x62\x52\x54\x24\x90\x32\x96\x64\x62\x9a\x84\x49\x4b\x06\x28\x30\x87\x99\xa4\xc7\xe2\x05\x84\x64\x21\x82\x7d\x4b\x35\x33\xf0\x95\xf1\x75\xb2\x00\x3a\xe9\x40\x7a\xc6\xcd\x42\x7f\x65\x0b\xcb\xfc\x0f\xb7\xe0\x26\x84\x86\x64\xc8\xcb\x51\xbb\xb2\xc4\xc8\x03\x55\xc1\xc9\xa9\x8e\x56\x78\x33\x2e\x5e\x09\xf1\xc1\x1e\xff\xc7\x5b\x3d\xa6\x12\xb5\x47\xd9\xd5\xec\x16\x16\x58\xf4\x95\x0d\x45\x36\x29\xc9\xd5\xf2\x21\x18\x1f\x85\x8b\x4c\x63\xf4\xd8\xf8\x49\x30\xb4\x42\x11\xb3\x2c\x95\xd2\x2c\xe7\x62\xa3\xb0\xd3\x9c\x64\xeb\xbc\xaf\xa6\xfd\x24\xb0\xa9\xcd\x8a\x9c\x88\x76\xe2\x07\x2b\xfd\xd4\x46\x8e\x74\x10\xa1\x54\x32\x6e\x3a\x3c\xfb\xff\xe9\x36\x63\x42\x8d\x31\x49\x60\x36\xf3\x24\x10\x53\x8b\x61\xaa\xc6\x53\x9e\xab\x33\x31\x96\x05\x13\xf2\x3e\xc9\x09\x1b\x9d\x0f\xa0\xcd\xcb\x81\x8d\x31\x18\x0a\x3c\xa4\x89\xaa\x20\x64\x67\x7c\x14\xc4\x19\xeb\x4c\x82\x1e\x53\xa2\xc5\x62\x5b\xac\x17\x4c\xb4\xfe\xa8\xc7\x87\x96\xe5\x3c\x0e\x76\x63\xca\xff\xf3\xad\x29\x57\x0a\x3b\x39\x88\x5c\x8c\x63\xcc\x86\x72\x1e\xb9\x66\x10\xa7\xd1\xca\xc4\x42\x1e\xa8\x94\xd1\x62\xd7\xa2\x1f\xb9\x92\x21\x76\xa3\x50\x7e\x2a\x4e\xa0\x3a\xc9\x4d\x18\x59\x60\x89\x53\x1c\x45\xc4\x11\xcc\xeb\x46\x5c\x2f\xae\x78\x90\xcb\x55\x68\xc4\xae\x52\xbb\x9e\x9c\x37\xf8\x91\xff\xe5\x36\x96\x72\x2b\xff\x15\xaa\x89\x49\xd8\x4b\x1e\x7c\xe2\xc5\xd7\x30\x70\xce\x8b\x95\x07\x0f\x8e\x20\x8a\x80\x24\x4f\x81\x84\xbd\xcc\x79\xc1\x83\x4f\x1b\x63\x9d\x75\x8c\xac\x6f\xac\x8f\xc0\x54\x49\x93\xaf\x26\x3b\xc1\x3e\x24\x0c\xc0\xcc\x64\x28\x29\x13\x52\x06\x4e\x3c\x5a\x61\xda\x9c\xf2\x46\x8e\x15\x07\x08\x99\x48\xb3\xa5\xa0\x94\xbe\x6c\xa0\x64\x7b\x6b\xec\x42\x71\xbd\x55\x64\x22\xc9\x25\x88\x43\x14\x69\x4f\x1e\x6c\x4c\xe1\x70\x3f\xe7\xb7\xd7\xc0\x2b\x9b\xcc\xd7\xcc\x38\xed\x98\xf1\x0d\x91\xf0\xbd\xdb\x30\x1d\xda\xa6\x5b\x16\x68\xe3\x38\x46\x01\x95\x58\x68\x60\x4a\x72\x7b\x20\x0a\x17\xe1\x5e\x69\x03\xe8\x5c\xc7\x59\x66\xa7\x9d\xd6\x6c\x62\xca\x8b\x67\x12\x31\xb2\x14\x65\x77\x4c\x10\xc2\x30\x7b\x70\x89\x24\x12\xf2\xc4\x2c\xdc\x99\xfe\x62\xf1\xd3\x4c\x4a\xab\xd1\x76\xb1\xda\x85\x15\xa2\xd3\x24\x6f\x7d\x33\xeb\x85\x90\x2b\x5e\x81\xd6\x59\xd1\x7a\x22\x83\x5f\x84\xde\x78\x1d\xf0\xea\xc2\x97\x62\xa2\xaf\xca\xb2\x25\xa3\x52\x3a\xc7\x34\x37\x81\xbd\xb8\xa9\x42\xfe\x0f\xd5\x14\x37\x0b\x4b\x1d\xd3\xe2\x73\x6d\xc4\xcf\x46\x36\x1c\x15\x85\x47\x67\xc0\xc4\xda\x5a\x55\xe4\x17\x5a\xe1\x66\x65\xef\x63\x30\x8b\xf5\x79\x03\x2b\xd2\xed\x4b\xea\x1a\x44\x24\x36\x44\x95\x16\x4a\x79\x8c\xc1\x99\x5a\x16\x39\x12\x1a\x39\xa4\x3d\xf1\x36\x17\x0f\x31\x5a\x7e\xf5\x6e\xa9\x45\x0e\x3c\x6c\x0c\xc6\xdd\xe1\xf8\x06\x37\x51\x08\x98\xcb\x93\x8d\x86\x6a\x16\xe6\x51\xe8\x86\xec\xfa\xec\x13\x83\x97\x4f\x38\x9a\x88\xa3\x11\x38\xa0\x3c\x83\x59\xf4\xc4\x4a\x95\x85\x0f\xc3\x61\x70\x10\xd6\x51\xaf\x02\x8b\xd4\xc2\xb1\x82\x3a\x8c\xa0\xcc\x3e\x97\x91\x58\x6e\xd7\xc0\xcc\x8b\xf5\xa9\x0c\xb6\xd6\xb0\x50\xa5\x31\x64\x32\xd1\xc5\x49\x6e\x96\x88\xff\x14\x30\x23\x91\x31\xbc\x9e\xe2\xe4\xc0\x96\x84\x1d\xc0\xac\xd7\x2e\x82\x6b\xd9\xa9\x5d\x00\x31\x09\x60\x11\x95\xb5\x17\xba\x0f\xb1\xe0\xf0\xee\xf8\x6e\x77\x56\x1c\x2f\xac\x5c\x75\x23\x9b\x34\x30\x88\xac\x30\xc0\x49\x59\x11\x81\x4e\xc1\xc5\x42\xa6\x26\x1d\x5c\x45\x9e\x98\x66\x40\x23\x45\x65\xb2\x62\xc3\x14\xa4\x73\x22\x30\x01\x32\xcb\xc1\x52\x0a\x0b\x53\x1d\x28\x85\x49\xf8\x19\xd5\x3a\x49\x8f\xb3\x1c\x4c\x54\x91\xa4\x14\x63\xe5\xcf\x40\xb2\x62\xf9\x76\xb2\x85\xcd\xca\x11\x85\x32\x5b\x20\x69\x16\x10\x10\x61\x94\x4d\x9a\x6c\x32\x94\x09\x2a\x1b\x2e\x3c\x7b\x11\xa3\x89\xd6\x3b\x96\x14\x5d\xb9\x32\x93\xf2\xaa\xc2\x5f\x83\x4b\x93\xbd\x73\xc0\xf8\x3a\x59\x88\x46\x60\xf0\x44\xf8\x91\xb3\x28\xca\x92\x78\x9e\x55\x34\x62\xe5\x91\x40\x16\x28\x44\x15\xc7\xc0\x4c\x79\x05\x0b\xb0\x56\x93\x65\xe7\x95\xd9\xc2\xe6\xb8\x7c\x7d\x80\xde\x6d\x0a\x3d\xa1\x3b\x9b\xb8\x12\xb3\x64\x42\xa5\x31\xb9\x68\x6a\x8a\x03\xd7\xb0\xd8\x4a\x61\x80\x82\x88\x6a\x18\x54\x55\x44\xc1\xdf\x52\xb4\x25\xc7\xfb\xea\x2e\xb0\x05\xb1\x06\x91\x31\xaa\x89\x81\x07\xef\xe3\x12\x39\x8e\x36\x19\x81\x61\x91\xe0\x37\x48\x4a\xec\xc9\xd7\xca\x1d\xac\x90\x13\x47\x2e\x72\x76\xd8\xdc\xac\x6c\xa4\x9c\x6b\x63\x23\x15\x78\x18\x27\x4f\x26\xfb\x19\x12\x2b\x70\x0d\x27\xc5\x35\x0e\xc2\x74\x34\x39\x4d\x22\x97\x40\x56\xcb\xba\xcb\xb3\xd5\x23\x28\xc2\xfc\x46\x61\xe0\xc7\x12\x4c\x21\x1a\x8a\x2f\x8b\xf5\x9e\x07\xa5\xdd\x9c\x8c\x48\x9f\x5e\x2e\x25\xb4\x64\x3e\x4d\xd0\xbf\x09\xeb\x02\x14\x29\xc3\x31\xb0\x30\x39\xe3\x8d\x67\x08\xae\x79\x06\xfc\xfa\x84\xab\x2e\xaf\x54\x2c\x96\x63\xac\xb3\xf5\x8d\x3d\xf5\xc2\x6a\x0b\x00\xe0\x7c\x21\x1a\x2a\xd6\x2d\xc6\x8b\x14\x71\x78\xf7\x52\x77\xb6\xa1\x9d\xad\xf0\x4c\xa9\x0a\x39\x13\x2e\x4a\x24\x64\xac\x33\x00\x28\x03\x43\x53\x9b\xe5\x72\x94\xb6\x73\x4a\x31\x40\x30\x40\x3d\x04\x0c\x9b\x96\x45\xf8\xef\xd4\xb4\xb5\x94\x8c\x57\xcc\xcd\x82\x65\x80\x36\xbc\xca\x75\x4e\xd9\xf1\x38\xdb\xac\x72\x4b\x71\xa3\x20\xfb\x49\x18\x11\x6a\xaa\xe2\xe2\x66\xdc\x62\xc3\x75\xa2\x0a\x94\x28\x4c\x51\xc3\x06\x22\x87\x7a\xb9\xd8\xd8\x2b\xc6\xfd\x14\xb9\x2e\x79\x21\x50\x10\x78\xfc\x64\x59\x07\xf4\x59\x30\x44\xd2\x4b\x20\xd4\x50\xae\x80\xb9\xf0\x85\x4d\xd4\xdd\x16\x62\x93\x14\xaf\xa6\x34\x83\x15\x11\xd9\x61\xaa\xce\x34\x16\xc5\x40\xa0\x11\x18\x32\x54\x15\x43\xe2\x96\x46\xf9\x1b\x5c\x49\x36\x39\x4e\xb6\xd0\x0e\x59\xb0\x70\xcd\xc5\xd8\x4c\x8b\xad\x1b\xcc\x4a\xde\x54\x12\x41\xd1\x50\xf2\xe2\x53\x1d\xc8\x71\x05\xbb\x32\x41\x3b\x60\x39\x07\x01\x49\x6c\x5e\x24\xc2\x1e\xe3\x39\x0b\xe7\x84\xd5\x17\x68\x01\x47\x12\xee\xb7\x4c\x3e\x18\x2f\x3c\x56\x48\x26\x16\xa8\x09\x5c\x36\xa1\x02\x31\x46\x12\xae\x54\xb8\xcb\x20\xbc\x1d\x6f\x60\xee\xd2\x63\xee\xb8\x77\xff\xca\x2a\xe4\xca\xd6\xe1\x84\x67\xd0\x02\xd5\x60\x4d\xe0\xe2\x82\xf0\xc0\xb1\x0a\xa2\x84\x82\x99\xaa\xe0\x79\xe1\xcb\x89\xb3\xf1\x22\x78\xcd\xde\x0b\xc2\x4a\x78\x92\xe3\xc6\x23\xb1\x48\xa3\x4e\x75\x58\xd0\x5c\x5b\x61\x24\xa9\x7a\xe8\xbe\xa0\x51\x9a\x04\xe2\x54\x09\x05\x01\xc4\xcd\x29\x03\xd6\x14\x61\xf2\x0a\x21\xe4\x1a\x13\xd3\x44\x33\xd5\x99\x81\x11\x07\xb5\x73\x4a\x39\x7c\x86\xb9\xc2\x81\x8d\x89\xd5\x84\x26\x17\x3b\x08\xcc\x96\x40\x66\x66\x61\x5c\x54\x3e\x55\x6d\x5d\xc8\xa0\x91\x73\x84\x6a\x2e\x0a\xb2\x16\x29\x4a\x69\x52\xcc\x02\x26\x02\xd2\xb1\x2a\xc0\x58\x79\x68\xdd\x5d\x5d\xf8\x2a\xb7\x19\x1f\x41\x2f\x01\x26\x2b\x34\x7c\x61\x01\xec\x59\x78\x1f\xbd\x1f\x60\x8b\x40\x02\xd0\xa8\xd1\x2e\xd5\x09\x06\xd2\x8b\x17\x5b\xbb\x49\xe4\x1e\xe0\x13\xe0\x90\x08\xd9\xbc\x69\xde\x02\x6f\xe1\x8c\xda\xe3\x8c\x66\xc6\x48\xde\x54\xcc\x93\x05\xa8\xe4\x46\x1a\x9f\xdd\xb5\x65\x07\x2c\x04\xb3\x07\xf9\xe3\xc6\x28\x08\xbe\x10\xaa\x46\x60\x2f\x29\x29\x7b\x09\x91\x0b\x33\x09\xc1\xcd\xd6\xd7\xac\xf8\x25\x4f\x36\xab\x02\xb1\xed\xa5\xde\x5e\x19\x0a\x08\xc7\x8b\xe8\x4e\x13\xce\x18\x6a\x51\x95\xc8\x67\xa8\xaa\x80\x6e\x84\xb3\x71\x82\xe0\x0d\x20\x3e\xb3\x61\xc1\x27\x22\x03\x43\x39\x92\x3c\x18\x2c\xd5\x37\x4a\xdf\x49\x95\x65\x82\x5d\x03\x00\x82\x9d\xa1\x86\xc3\x04\x9b\x01\x1b\x09\x34\xc4\xb6\x7a\xf0\x63\x41\x51\x18\xb9\x99\x02\x08\x44\x2e\x53\x86\xb2\x82\x55\xcf\x7a\x1e\xe7\x22\x4b\xc8\xfe\x3c\x2e\x04\x34\x4b\x09\x56\x16\xc3\xc1\xab\x48\x5c\x84\xcd\x00\x23\xdd\x3a\x29\xc0\x56\x31\x2a\xd1\xdf\xd4\x20\xfc\x87\xdb\x1a\x84\x18\x77\x58\xfd\x90\x88\x82\xdf\xf1\x6f\xe1\x78\xaa\x08\x73\x5b\xbd\x15\x62\x13\xe6\x84\xf5\xbf\x92\x7f\x1f\x51\xa4\xbb\xa8\xee\x3e\x73\xfb\xc7\x9f\x7c\xe3\x9f\x77\xfa\x37\xb7\x63\x2a\x8b\x09\x3e\x2d\xcc\x79\x2c\x89\x8c\x4f\xab\x4d\x23\xe6\x04\x6e\x6a\xb1\x69\x6c\xcf\x1e\xaf\x0e\x0f\xf3\x7e\x77\x15\xd8\xaf\xc2\xa0\x37\xde\xf3\xc2\x5c\x87\x52\xa5\x7b\xae\x83\x2d\x35\x5d\xe1\x55\x4e\xfe\xc0\xab\xcd\xa5\x5c\xf6\x4b\xf1\xed\xce\x09\xcf\x2a\x42\x7a\x76\x63\x2c\x82\x62\xeb\x22\xe2\x22\x1e\xd3\xc2\xa9\x8e\x25\x0b\x51\xc4\x12\x79\x83\xdc\xfc\xd3\x6d\x49\x68\xd5\x0f\x41\x5d\x51\x68\xb2\xde\x50\x65\xb5\x08\x18\xae\x61\xf6\x40\x84\xe4\x78\x62\x0e\x90\x4b\x94\x01\x50\x35\x5c\x63\x8e\x5c\xd3\x3b\x0a\x1a\xb7\x39\xa8\x2e\x12\x7a\xb7\xa4\xe7\x4a\x93\x4d\xc2\xd2\x66\x68\x60\x6c\x55\xfd\x1f\x10\xb7\x83\xbc\x50\x69\x12\xf2\xe4\x8c\xa0\x2e\xc3\x2e\xce\x94\xa0\x12\x8d\x65\x12\x69\xa5\x18\x8c\x68\x88\x85\x29\x51\xa9\x64\x15\x52\x8a\xe2\xc0\x59\x79\x03\x13\x79\xb2\x39\x28\xba\x8b\x8a\x58\x76\xd2\x89\x1c\x80\xc8\x26\x17\xc2\x73\xc9\x05\x71\x46\xb9\x59\x8e\x4e\x66\xb1\x41\xfb\xfe\xd7\xdb\xa7\x52\x5c\xda\xd1\xbe\x90\xcb\x44\xc5\x04\xce\x86\x63\x34\xa9\xc8\xce\x24\x61\xf1\x04\x73\x4d\xbe\x08\x1a\x8a\x50\x84\xca\xcc\x67\xaa\xce\xd8\x94\x80\x69\x44\x64\xa3\x02\x2b\x89\xb0\x29\x49\x08\x13\xc8\x41\x99\x6c\x56\x7c\xe0\xa3\x91\x05\x14\xe1\x8b\xfc\x64\x85\x93\x2d\x6a\xbe\x6d\xf6\x8e\x79\x95\xc3\x02\x4d\x96\x02\xf8\x0f\x26\x20\x4d\x02\x79\x01\x21\x8b\x13\x47\xc3\x50\x86\x05\x13\x5c\x9e\xa1\x1d\x88\x1e\x64\x53\xd0\x64\x02\xc3\x02\xf6\x1d\x1a\x28\x63\xc3\xd0\xf8\xba\x98\xfd\x64\x05\x51\xca\xd7\xd8\x45\xa1\x7d\xd0\xa3\x47\x20\xda\x88\x1e\xc0\x1b\xb9\x3a\x67\xc5\x7b\x69\x12\xa4\x09\x5e\x0c\xba\xd2\x08\x56\xdc\x86\x8c\x73\xad\x50\x0a\x7b\xc5\xb4\x41\xe5\x1c\x26\x59\x0c\xd4\xa9\x36\x66\x59\x8d\xec\x8a\x70\x58\x2a\xea\xc4\xe4\xe6\xa0\x7a\x5d\x76\x71\x2a\x18\x16\xda\x59\x76\x32\x73\x19\xc4\x8d\xc2\x7a\x51\xc8\x93\x15\xda\x00\x6a\x90\x81\x5d\xa0\xed\x14\x4e\x40\xc1\x13\xc3\x57\x90\x98\x24\x64\xde\xb0\x70\xd9\x98\x97\x49\x85\xaf\x2e\x32\x93\x09\x94\x84\x75\x51\xc8\x56\x2d\x32\x55\xe9\x60\xc6\xbf\xe8\x73\x8a\xd8\x40\x68\xf0\x61\xc6\x2a\xf2\x54\x13\xae\x04\x1b\xe9\x3a\xcd\xf8\x77\x94\xad\xaf\x49\x98\x38\x93\x57\x5a\x4d\xb2\x25\x42\xd5\x26\x2b\x5c\xad\x8c\x95\xaa\xb1\x15\x04\x00\x98\xa9\x6e\x72\xf5\x1f\x34\x56\x91\x56\xaf\x02\x17\x0c\xc5\x31\x88\x58\xc0\x49\x10\x68\x1d\x43\x50\x41\x22\xe1\xad\xa5\xd8\x44\xb3\x50\x53\xfb\x86\x0c\x95\xd1\xa6\x60\xd8\xb9\xc1\x06\x41\x8f\x09\xfa\x7e\x87\x97\x96\xca\xf5\x27\x57\x17\x31\x55\x93\x5c\x19\xbc\x0f\xa3\x08\xd5\x26\x92\xdf\x54\x8f\xfe\x73\xe7\x27\xb2\x8a\x94\xb2\x69\x4d\x34\x8c\x10\x0d\x5d\x80\x96\x53\xff\xc8\x69\xa0\x18\x87\x50\x79\xe2\x28\xf7\x27\x60\x22\xce\xa9\x28\xc7\x6a\x0d\xc3\xec\x14\xf6\x57\x19\x5a\x29\x26\x09\x6b\x3c\x41\x89\xcd\x45\xf8\x73\xbd\x2a\x6e\x4e\xb1\xc1\x99\x32\x85\x75\x35\x74\x10\x76\xdb\x57\x6a\x66\xc5\xc1\x66\x92\xb5\x3a\x11\x66\xc2\xc0\xa9\xae\xf7\x24\x67\x03\x7d\xc8\xaa\xef\x12\x6a\xee\x32\xa4\x47\x08\x4e\xb3\xee\x49\x6a\x58\x6d\xb1\x81\x9d\x76\x54\x42\x1a\x44\xaa\xdb\x31\x26\xce\x84\x32\x27\x2f\x68\x0f\xbd\x90\x51\x11\x93\x00\x88\x45\x0d\xbf\x83\x9c\xc3\x62\x7d\xd9\x00\x81\x5f\x74\x3b\xcc\xab\x95\x99\x4d\x76\x7e\x09\xb2\x55\x9e\x32\xae\x78\x64\x9a\x43\x21\x23\x74\x58\xc0\x4c\x84\x2a\x01\x63\x82\x0e\x5f\x36\x49\xf0\xd2\x62\xb9\xc8\xc0\x94\x47\xeb\xc1\xa0\x4f\x36\x78\x13\x7c\x63\x99\x4d\x2a\x73\xe3\xda\x44\x24\xa1\xaa\x62\x5d\x6d\xc6\x5d\x79\xa9\xb7\xcc\x27\xb7\xd8\xa8\x8a\x44\x91\x02\x85\xec\xfb\x44\xc0\x3d\x22\xc9\x36\x8f\x16\x70\x02\x2c\x52\x1d\xae\x49\x19\x75\xd0\x81\x29\x63\x2a\xe0\x8d\x94\x69\x60\xe5\x60\x31\xcd\xd9\x7a\x87\xf3\x84\x86\x65\xb2\x5c\xbd\x22\x13\x67\xd8\x09\x26\x29\x59\x16\x7c\x78\xdf\x7e\xd9\x59\x78\x89\xee\x01\x99\xd1\xb9\x89\x13\x20\x33\xb8\x86\x62\x66\xa8\x2c\x83\x87\xc1\x90\x83\x2e\x3b\x95\x66\xae\xc6\xef\xc2\x75\xeb\x0d\x87\x4d\x21\xc6\x6b\x18\x13\x61\x88\x00\xeb\x1c\x92\x88\x40\x73\xa9\x86\x73\x5e\x38\x40\x4a\x12\xa4\x80\x5f\x04\x89\x69\x8b\x41\x24\xa0\x45\xae\xc5\x06\xb9\xff\xb0\x03\x0e\x57\xee\xb1\xc8\x5a\x85\x53\xaf\x15\x52\xe1\x68\xc9\x1b\xca\x61\xb0\x41\x58\x0c\x9f\xd2\x10\x64\x74\x28\xd1\xf1\x14\x28\x0d\x21\xbb\xb1\xb5\x53\xbd\x23\x0c\xf1\x14\x37\xf8\xaa\xff\xd8\x59\x4e\x53\x3c\x75\x82\xf0\x55\x38\x30\xbb\x1c\x17\x1b\x1c\x0d\x91\xdc\xaa\xe2\x97\xa7\x20\xe8\x2c\xa6\x1b\xca\x29\x7f\x78\x56\xbf\xea\xb1\x56\xe3\xf6\x42\x36\xa9\xba\x05\xbc\x87\x07\x49\x60\x88\x58\x3c\x87\xac\x82\x6f\x9c\x28\x0b\x16\xf7\xa4\x12\x39\x58\x61\xdf\x9c\x28\x14\x32\xaa\x87\x6e\x1f\xda\x21\xaa\x71\xb2\xc1\x19\x68\xfd\x01\xcd\x31\x34\x75\x37\xba\x83\xe8\x5c\x95\xa6\xc3\x84\x04\xc5\xa4\x93\x65\xa4\xba\xd8\xc8\xd7\x77\x2b\x08\xad\x84\xc3\x98\x73\x4d\x67\x3f\x15\xd5\xae\x2b\xc3\x34\x17\x18\x2a\xe3\xc2\x21\x8f\x22\x55\x18\x52\xc7\xb3\xe8\x68\xb1\x31\xd6\xc9\x0a\x07\x09\x2b\xa3\xcb\xab\xf6\x69\x86\xf1\x0e\x6c\x84\x5c\xb1\xb8\x5e\x31\x55\x18\x5b\x2a\x51\x28\xc0\x16\x85\xfa\xdf\x6e\x6f\x65\x72\xa7\x5e\xb3\x24\x1c\x39\xe5\x24\x3f\xb6\x63\x0b\xec\x86\x58\xc3\x12\xd8\xe9\xaf\x3b\x60\x85\xb0\x20\xff\xdf\xfe\x04\xdd\x76\xe7\xbe\xaf\x94\x0c\x42\xf5\xa4\xd7\xfb\x80\xc8\x7f\xea\x4c\x95\xab\x81\x2b\xde\xf4\xf0\x5b\x97\x95\x8e\x2c\xeb\xf0\x1c\x0f\x0f\xfc\xeb\xde\x8b\xaa\xc9\x3a\xc2\x28\x52\x6e\x0a\x74\x15\xb3\x28\xaa\x12\x34\x65\x48\xc6\x45\x45\xff\xa9\xa8\x67\x11\x38\x1d\x68\xb5\xd2\xaa\xe4\x5b\x0a\x94\x41\xd7\xb3\x0d\x21\x1f\xda\xd5\xd2\x28\x28\xd4\x46\x5e\x85\x00\xaf\x7a\xe8\x90\x77\x7e\x38\x37\xad\x43\x24\x0c\x1d\x5c\x31\xb2\x32\xbc\x9e\x68\xd9\x32\x71\xfd\xa6\x43\xcf\xe9\x54\xc6\x21\xd6\xb8\x4e\x37\x14\x9d\xae\x2f\x75\x20\xce\x50\x0f\x07\x97\x47\x5b\x92\x21\xd6\xd6\x39\xef\x16\x27\x82\xac\x90\x3c\x79\x08\xb9\x8c\x41\xc5\xd4\x38\x42\x37\xc0\x71\xe7\x55\x99\x31\x81\x2a\x32\xfe\x68\xd1\x29\xd3\x60\x29\x09\x12\x74\x7e\xdc\x8d\xab\xcd\xeb\xc6\xdd\xf8\x6d\x87\xfc\x9c\xbb\x07\x76\xe6\xca\x87\x01\x9e\xd3\x10\x88\xa0\xfa\x2b\x7e\x60\xc6\xac\xf2\x20\x22\xc3\xc6\x4c\x2e\x6e\xcf\xa4\xae\xee\x4e\x27\xcd\xc4\x17\x1a\x7d\x56\xde\xc9\x0f\x69\xf4\x59\xa4\xc9\xec\x87\xe8\xcb\xbd\xee\x23\x7a\x65\xae\x23\x17\x93\x82\x1f\x6d\x32\x34\x5a\x5f\xc1\xeb\x65\xa1\x24\x35\x8d\xd6\x17\x00\x51\x90\xd7\x96\xa4\xad\x4d\x1e\xfa\xd1\x7a\xea\x2d\xfa\x97\xdb\x0b\x8e\xab\x0f\xe4\xa9\x5b\x3f\x46\xe1\x49\x6a\x71\x63\x32\xb4\xe4\x7c\xd2\xb5\xa1\x26\x66\x92\x08\xee\xc5\xc8\xd7\x58\xc3\x62\x73\x0e\xa7\xce\xfd\xa3\xee\x6a\xac\x26\xe5\x94\x4d\xa6\xdc\x9c\x3c\xa8\x18\x2a\x64\x22\x17\xa1\x4d\x86\xc9\x4d\x0c\x71\x27\xe4\x6b\x8d\x95\xfa\x64\x45\x2e\x3b\x1f\x08\xa8\xd2\x0b\x4c\xaf\x55\x24\x93\x0a\x3e\xf9\x1a\xf3\x37\x32\x07\x0e\x95\x20\x6d\x57\x55\x90\x66\x52\xd3\x94\x77\x46\xbd\xa8\x54\x23\xc8\xb9\xa9\x19\x85\x94\x11\x44\x36\xce\xc5\xe0\xef\x19\x0e\x5a\xee\x5c\x28\x12\x94\x89\x09\x32\xa6\x4f\x79\xb6\xda\x88\xe4\x61\xed\x60\xf5\x5a\xf3\x49\xa6\xbb\x21\xaa\x7f\xdc\xf3\xc3\x27\x73\x14\xc2\xd7\xf9\x32\x31\xdc\xcf\x7c\x6d\x9e\x89\x45\x0d\x48\x8a\xe3\x52\xb3\x38\x40\x74\xd8\xfd\x28\xa2\x43\x6b\x9d\x07\xe1\xce\x16\xeb\xd9\x1f\x38\x50\x70\x7b\x39\xfa\x81\x43\x9a\x08\x7a\x67\x95\x9b\x53\x82\xd2\x00\xa6\xcb\x55\xaa\x10\xce\x16\xbf\xe4\xe6\xc4\x84\x86\xf0\x46\xc1\x10\x21\x6f\x78\xda\xfe\xae\x87\x90\xfa\x68\x10\xa2\xea\x0b\xf5\x04\x0d\x59\x24\xe6\xd5\xaa\x3f\x7a\x48\xca\xd5\x0b\x73\x01\x2d\x46\x1d\xad\x0f\xd5\xb0\x87\xac\x6d\x6c\x31\x36\xab\x10\xed\xe7\xf6\x14\xbf\x7d\xd0\x32\x8f\x05\x5b\xff\xda\xed\xeb\xbd\xd8\xe9\x50\xeb\xc4\x41\x08\xa2\x87\x57\x85\xaa\xd0\x60\x22\xa4\x66\xc9\x22\xd9\x41\x18\x34\xaa\xf0\x79\x70\x73\xf5\x34\xa9\x0f\x80\x1c\x57\xbc\xf6\x96\x05\xd5\xb6\x2c\xa2\xee\x62\x11\x67\x61\x43\x81\x9f\xab\xac\x4a\x04\x4b\x78\x30\x8e\x3e\x19\xab\x14\x71\xb0\x14\xa1\x23\xf2\x6a\x86\x23\x93\xf3\x6c\xa3\x7c\x54\x17\xd8\xdc\xc1\x59\x2a\x3b\x90\xd4\x5e\x06\xa3\x48\x82\xa1\x88\x05\xc9\xfa\x72\x13\x51\x99\x3d\xc0\x2e\x14\x06\x76\xbc\x03\x6c\x6f\x22\x43\x50\x8e\x6e\x56\x21\x6d\xb5\xc2\xe1\xec\xd5\xb1\x0a\x4a\xd8\x40\x1b\x12\xcc\xbf\x75\x34\x32\xf0\xce\xd5\x85\x5c\xa6\x49\x65\x72\x8a\xce\xb0\x5a\xb6\xe4\x2f\x82\x5e\x2a\x95\xd5\x6a\x18\x69\x86\x77\x29\xf9\x24\x0c\x38\x84\x5b\x01\xce\x62\xd8\xb9\x09\xff\xc3\xdd\x82\x4c\x68\x16\x60\x2a\xc2\xad\xa8\xd5\x44\x77\x5d\xdd\x20\x54\x83\xb0\xba\x61\xdb\x1c\x8c\xde\x05\x62\xc8\xd0\x3e\xed\x7c\x08\x27\x96\xa3\x4d\xd9\xf8\xf6\x4d\xce\x73\x33\xc0\x70\x51\xfd\x45\x01\x47\x2f\x6c\x47\x85\xfa\x01\x74\x4e\x06\xce\x6a\xbe\x87\x0c\x11\xd5\x35\x56\xbd\x1c\x16\xef\x82\x19\x98\xe5\xb2\xa9\x3b\x80\x30\xe7\x3e\x19\x6a\xd6\x40\xd8\x97\x75\x4a\xac\xae\x04\x30\x61\x42\x4e\x09\xb5\xa1\x18\x2f\xdb\x56\x82\x36\x37\xe4\xa1\x17\x2b\xd0\x5a\x4d\x70\x24\xc9\x72\x15\x2a\x1b\xca\x45\x1d\x7a\xb8\x6c\x48\x70\x9f\x74\xf8\x36\xaf\x06\x4c\x80\x53\x59\x7c\x29\x03\x71\x2d\x02\x3b\x65\x15\xd6\xa0\x2d\x19\x44\x3c\x56\x8e\xa5\xc3\x95\xe1\x26\x13\x0d\x7f\x8b\x94\xf1\xa5\xd5\x4f\x79\x83\x3e\xfe\xbe\xa3\xed\x21\xef\xe2\x0c\x88\xcb\x9d\x1c\x54\x4e\x70\x0e\xa5\x10\x4c\x6e\x36\x0a\xf8\xca\xab\x44\x07\x5b\x38\x79\x08\xea\x14\x4d\xa6\x39\x17\xc3\x94\x96\x9c\xdc\x5d\xf2\x4b\xeb\x99\x61\xda\x4b\x0d\x95\x95\xd9\x06\x56\x25\x96\xf7\x93\xe5\x04\x69\x2f\xc0\x31\x95\xbc\x9f\x2d\xe1\xea\xf8\x5c\x64\x88\xc3\x6b\xfe\xb4\x67\x97\xcb\xb5\x62\x7f\x5d\x73\xf4\xbc\xce\x88\x00\x3d\x23\x0b\xab\x5b\xb2\x1f\x49\xfe\x77\x43\x1a\x29\x9b\x5c\x46\x81\x81\x92\x05\x85\x91\x33\xdc\x7d\x0d\x03\xbf\x08\xb0\x82\x97\x88\x53\x18\xac\x77\x6e\xb4\xc1\xc3\x97\x62\x03\x7d\x7e\xd6\x71\x99\xb9\xdd\x65\xae\xfb\x93\xdc\x1d\x88\xf7\x02\xc4\x23\xa5\x6c\x6c\xae\x65\x54\x76\x2f\x7b\x53\x6b\x19\x98\xe2\xc8\x02\xa7\x15\x6f\x68\xa4\x94\x8c\xb4\x52\x78\xf5\xad\xb3\x9d\x2c\x00\xc6\x26\x8e\xa0\x36\x32\x67\x41\x3d\x99\x46\x81\x2a\x53\x13\x0d\x36\xe9\xb3\xc5\x1f\xfa\x0a\x5e\x5a\x69\x83\x69\xfe\x43\xb7\xe7\x7e\xdd\x73\xbf\x52\x03\xf6\x86\xc3\xe8\x45\x46\xf6\x71\x84\x23\x42\x64\xd2\x1d\xe4\xa8\x53\x8c\x75\x77\x28\xd0\x47\x8e\x50\xc4\xf9\x98\x47\x21\x5a\xf2\x3f\xcc\x94\xd4\x56\x94\x68\xff\x14\xb8\xf5\x6a\xa5\x5b\x5f\x85\x6f\xf3\x61\x04\xbd\xd8\x93\x57\x1a\x7f\x4d\x49\x05\x16\x2f\x74\xb0\xc8\x83\x52\xbc\x11\x66\x50\xe2\xb5\xfd\x96\x57\xe7\xe7\xdd\x5d\xdf\x45\xf0\xa4\xbd\x03\x8c\x74\x63\x41\xba\x0e\xe1\x56\x86\x84\x47\x11\xad\x10\x80\x41\xf9\xf6\x07\x0c\xbd\xf3\x08\xc5\xbc\xcd\x41\x70\x86\xcb\xc7\xc5\x77\xcf\x2c\x88\xbc\x9a\xec\x37\x10\xc2\x1f\x3b\x1a\xc2\xcd\x7a\x93\x83\x1c\x54\xe4\x31\x13\xd4\xb8\x75\xb0\x21\x09\xfb\xe2\x8d\xd2\x4b\x66\x39\x0e\x13\x1c\x0d\xe4\x84\xe7\xa2\x90\x46\x9b\x49\x35\xa1\x69\x88\x2e\x8f\x1c\x8c\xb4\x65\x99\x87\x1c\x09\xf4\x09\xe4\xb6\xdc\x53\xff\xf3\x6d\xb7\xd2\x35\x56\x00\xe6\x71\x8f\x58\x40\xce\x43\xf0\x7e\xb1\x4c\x42\xb3\x83\x6c\x4f\xac\x71\xc0\x13\x7e\x0b\x5b\x6b\xfd\xdf\x6f\x3b\xbf\xae\xfa\x76\x38\x03\xc6\x34\x70\x29\x63\x72\x65\xe7\x63\x5a\x36\x78\xc8\xff\x72\x7b\x9a\x69\xf5\x4d\x27\xa8\xd2\x07\x0a\x7e\xc1\xac\x84\x9f\x58\x64\x56\xc1\x87\xc5\x62\xf2\x56\x1e\x37\xdd\x57\xff\x8f\xdb\x73\x2c\x61\x17\x2d\x91\x45\xf8\xab\xd5\x64\xce\x03\x13\xe3\xd9\x66\x70\xd5\x5e\xee\x4d\x8a\x26\x90\x1f\x6d\x31\x3e\xe0\xca\x66\x61\x43\xe5\x05\x82\xb6\x3c\xda\x1d\x1e\xf6\xbf\xf6\x0e\x64\xab\x0b\x14\x1b\x37\x54\x12\x00\x2b\x69\xb0\xf2\x44\x65\x63\xf2\xff\xe7\x6d\x0f\xfb\xd5\x2b\x38\x05\x43\x21\x33\xf4\x2f\x9e\xdc\x48\x15\x16\x35\x01\x22\xbf\xd1\xd7\xd3\xde\xaa\x1c\x77\x80\xe9\x1d\x78\x9b\xc8\x06\xc8\xc2\xc7\xd9\xc7\x62\x8a\x1f\x28\xd4\x85\x5c\x9a\x9c\xc9\xc5\xd8\x10\x0d\x31\xad\x5e\xb7\x93\xd5\xd0\x19\xe5\x2f\xc1\xaf\xb4\x00\x8c\x16\x20\x41\x00\x6a\x37\x92\xe1\xe0\xa6\xe2\x4c\x84\x96\x40\x48\x3f\xcd\x0c\x7b\xa9\xcf\x13\xc3\xc5\xd2\xab\xf7\x19\x02\x4c\x9a\x29\x15\x71\x64\x8b\x0d\x41\x19\xf2\x68\x34\xe2\x26\xcf\x6a\x80\xe4\x11\x03\xaf\x88\xc4\xfb\x2c\x4c\x94\xe1\x2c\x34\xd4\xc4\xe6\x67\x61\xe0\x30\x63\x23\x37\xf7\xc7\x36\x4c\x36\xf3\x6a\xaa\xc3\x77\x08\x72\xb1\x1c\x35\xaa\x0a\xc1\x3a\x08\xb5\xf2\x11\x3e\x39\x29\x9a\xe6\x15\x2b\x24\x37\xaa\xd3\xc4\x2e\x44\x6d\x4a\xb0\x2c\xb0\x70\x85\xe7\x71\x2e\xc1\x40\xbd\x45\x09\xf0\x5a\x27\xab\xb6\x02\x70\xdf\x1a\xab\x11\x60\x62\x08\x5b\x8a\xcc\x67\xdd\x59\x15\x5a\x1d\xb9\xd9\x90\x2f\xa1\x09\xfe\x69\xb1\xb1\xfa\x29\x64\x93\xa2\x21\xf0\x0c\xb0\x5b\x41\xa1\xeb\xe3\x24\xa2\x91\x08\x5f\xb0\xc5\xc1\x8d\x4e\x6e\x63\xd0\xb0\xa8\xe6\x74\x0d\xab\xa5\xfc\xec\x4b\x9e\x85\x0d\x84\xb7\xe7\x64\x55\x50\x92\x4b\xe0\xeb\x1a\xc5\x06\x8f\xcf\x51\xf6\x57\x60\x60\x90\x0d\x5b\xc8\xc7\x70\x75\x11\x58\xa0\xa8\x4c\xb2\xfd\xd1\x19\x95\x75\x72\x9a\x89\x54\x72\x48\x93\x06\xfd\x52\x2c\x46\x24\xbe\x39\x44\x03\x10\x58\x58\x41\x6f\xf5\x27\xe2\xe6\x01\x0c\x57\x5b\x58\x79\x10\xb8\xd4\x34\x8c\x16\x3b\x8c\xe8\xcb\x02\xdf\x9e\x10\x37\x50\xdf\xf3\xee\x06\xe6\x6b\xb9\x34\x72\x5c\xbc\xb0\x47\x2c\x6c\x1a\x3c\x65\x7d\xf5\xb3\x2f\x1a\x0f\x15\x60\xce\x93\xb7\x60\x4d\xd5\xd6\x42\xe4\xc6\x00\x76\x5a\x6e\x59\x1e\x21\x00\xa5\x3a\xe1\x48\xaa\xb1\x31\x18\x8f\x5b\x90\xbd\x21\x18\xdc\x89\xd5\x33\x00\x8c\xc3\xea\x3d\x2e\x8c\x8d\x6f\x3c\x5f\x84\x97\x1a\xe2\xd6\x66\x78\xe4\x96\xb2\x8b\x52\x67\xf5\x3d\x9a\x83\xb0\x05\x74\x1e\x07\x4e\x61\xf4\xc6\x0a\x5d\xd0\xcf\xd5\x37\x58\xae\x5c\x0a\x93\xba\x43\x40\xa4\xf3\x94\x20\x5e\x4c\x38\x5b\xb8\x24\x7a\x43\xd1\x0b\xc8\x7b\x92\x85\x1e\xde\xb1\x2e\xf2\x9f\xe9\xda\xe9\x35\x12\xe9\x49\x71\x14\xfe\x9f\x04\x33\xce\x02\x2c\x14\x73\xd3\xf1\xc2\xa7\x09\x40\x06\x78\x43\x10\x9c\x2f\xe5\x80\xf2\x1c\x01\xe4\x31\x8e\x14\xdc\x1e\xad\xf5\x10\xe6\x05\xbe\x59\x23\xab\xb2\x1a\x52\x9b\xab\xf1\x0a\x13\xd6\xd7\x6b\x9f\x54\x52\x17\xb0\x24\xe0\x09\x98\x2f\x49\xc5\xf8\x48\xa4\x7b\xcc\x46\x95\xc4\xcc\xd8\x65\xb5\xd9\x0a\xec\x4c\x09\x7e\xd9\x44\x86\xd3\x9c\xb3\xc9\x71\x09\xb1\x9a\xc9\x7a\x67\x04\x5d\x40\x43\xb0\x46\xb5\x8a\xe8\xc2\xcd\x1d\x3d\x9b\x75\xf7\x45\x90\x0a\xc2\xfd\x08\xf3\xb0\x65\xfc\xbb\xec\x49\x01\xed\x6d\xab\x5b\x82\x9b\x04\x43\x92\x30\xe0\xc6\xd7\x3c\x91\x97\x6d\x8d\x08\x1e\x82\xca\x73\x62\x82\xf9\x34\xa8\xad\x65\x86\x33\xa8\x8f\x19\xa4\x7a\xb0\x49\xf8\x04\x41\x70\x13\xd0\x4a\x06\xfa\x01\x53\x31\x93\x7a\x6a\xa7\x3a\x55\xd8\x81\x45\x40\x86\xd4\x16\x9c\x11\x99\x60\xcc\x15\xf6\x6c\x75\x60\x40\x34\x55\x56\x9f\xb0\x2a\x82\xa0\x2a\xdb\x93\x7a\x82\x02\x92\x82\x0a\xd8\xf2\xbd\x2f\x24\xa8\xb1\x9a\x14\x19\x2e\xb5\x83\x5f\x03\xa4\xaa\x57\x4c\x67\xe0\x44\x37\x6b\x10\x2e\x70\xb2\xd9\x79\xad\x42\x95\xca\xb3\x3a\x57\xa6\x0d\x98\x7c\x79\xdb\xf4\x91\x56\xd5\x69\xbd\x91\xfa\x81\x18\x66\xed\xc2\x50\x65\x81\x72\xcc\xc2\x7c\x0b\x8a\x9e\x20\x3f\x69\x6c\x31\x62\x43\xc3\xea\x55\x3c\x0a\x55\xb1\x4c\x59\xae\x8a\x09\x0d\x03\xe5\xe6\xc1\xe3\x61\xa2\x72\xbb\xe0\x5f\x0f\xc7\x68\x85\x46\x81\x60\x76\x22\x17\xac\xc9\x0a\xe4\xe9\x40\xb2\x82\x9b\x49\x11\x8e\x67\x74\xf8\x62\x33\xd4\xa6\x50\x77\x01\xcf\xe3\x7a\x05\x9b\xf7\xa7\x3a\x85\x0a\x91\x83\x4e\x0a\x61\xd2\xd0\x4d\x8c\xf0\x9b\x4c\x03\xc7\x20\xb8\x23\xaa\x58\x88\x3b\xda\x62\x04\xd4\x85\xd3\xa7\xe6\xe5\x03\x8a\xd9\x02\x11\x72\x30\xac\xd1\x95\xb9\x41\x4c\x0c\xb0\x3c\x66\x5c\x5d\xb8\x51\xc1\xa7\x44\x4d\x3e\x48\x1d\xa1\x57\x44\xa6\x92\xe2\x1c\xbd\xa1\x42\x4b\xa6\x49\x23\x25\x35\xa6\xd7\x58\xb8\xd3\xca\xe5\x91\xdb\x4e\x1a\x67\xb3\xbb\xce\x30\x05\xea\x22\x7d\x51\x12\x9c\xfd\x8d\x3b\x5d\xae\x6f\x74\x5a\xef\x33\x46\x85\xe7\x16\x87\xf3\x38\x83\x06\x81\x12\x87\xec\x26\xcb\xc5\x84\xa6\xaf\x32\x39\xad\xdd\x73\xde\xbf\xd2\xab\xab\x78\xf3\xb3\x3c\x76\xad\x87\xde\xdc\xbd\xda\xc6\x6e\x90\xe8\xbc\xd8\x44\x69\x8a\x64\x32\x3c\xca\x0c\x28\xe2\x4c\x29\xc0\xfd\x6c\x92\x7d\x75\x86\xd3\x0a\x58\xe7\x71\xae\xcd\x11\x1f\x16\xdc\xe0\xf3\x2d\x3c\x19\x63\x4b\x28\xc2\x6a\x52\xf4\xbb\xa8\x02\xe8\x88\xa1\xef\x9a\x5b\x1c\x15\x4c\x70\x36\x35\x30\x56\x52\xcc\xb3\xe2\x36\x9b\x78\xb1\xb1\x24\x74\x74\xa0\xfb\x35\x8f\xc7\x56\xf0\xd1\x97\xb7\xb9\xd3\xe4\x76\xaa\x8f\xea\x52\x5b\x7f\x69\x39\x51\x6e\x2e\x61\x95\x12\xd7\x6b\x41\x57\x17\x54\xa3\x90\x62\x42\xe0\x8c\x66\x9e\xa0\x7a\x24\xbd\xc4\xff\x75\x5b\x68\xa8\x8d\xbe\x5b\x11\xe5\x83\xf0\x9d\x02\xbb\x7e\x12\x39\x29\xc1\xc3\xb9\xce\x08\xa6\x9d\xc0\xed\x69\x80\x3a\x21\x8c\x1d\xce\x7e\xb2\xdd\x95\xd2\x2d\xdb\x4a\x59\xe4\x54\xae\xb5\xd1\x70\x9d\x61\x0d\xf5\xe5\x82\x1f\x60\x7d\x54\x5f\x38\x40\x57\x98\x35\x20\x98\xbc\xac\x2a\xc8\xaa\x44\x68\xc9\xeb\xaa\xf2\x91\x55\xfd\xa9\xd7\x41\xd6\x0d\xb0\xaa\x2e\x0c\x29\x8e\x94\x8a\x01\x3f\x82\xfd\xeb\xb4\x27\x50\xf8\x09\x43\x0e\x2e\xac\x40\xa5\x61\x61\xb2\x83\x5a\xc6\xaf\x27\xe2\x54\x8b\x90\x44\x36\x15\x11\x27\x19\x4e\x65\xb0\xc4\xf0\x2f\x29\x0f\x05\x92\xf1\x36\x90\xac\xde\x0d\x37\x97\x53\x76\x1c\xc1\xd1\x94\x32\x5b\xa3\xfc\xb9\xd3\xf6\xac\x51\x77\xbc\x07\x8b\x9c\x47\xe5\x6e\xfd\x14\x59\x04\x1a\x68\x56\x0d\x58\x8c\x59\xcd\x00\x81\x81\xbf\xc0\x19\x40\xe2\x11\x0e\x96\xd5\x7f\x28\x3a\x53\x32\xbc\xbf\xc9\xa7\x99\x8a\xe0\x93\x89\x10\xcb\xcf\xcd\xe5\x13\xfe\xfe\xea\x9a\x04\xf3\x8d\xf0\xa7\xee\xf6\xa2\x62\xbd\x71\x7d\xe1\xb2\x04\x3e\x2e\xc8\xa0\x22\x5e\x51\x35\xa1\x4c\x36\xf1\x1e\xf5\x81\x6f\x77\x8b\xc7\xcb\xcd\x32\x44\xd5\x90\xfa\x91\xcf\xa4\x2d\x16\x1b\x5d\x32\x23\x90\xff\xf5\x88\x9c\x9b\x4e\xa6\xec\x8f\xe8\x74\xc4\xa4\xdc\x3d\x3b\xa3\x41\x96\x2a\x0a\x01\xaa\x05\x59\x28\x47\x0b\x74\x81\x6c\x17\xb1\x84\xe3\xb0\x20\x97\xf9\xe0\x21\xbd\xea\x31\xa6\xdb\xc1\xc2\x8d\x43\x82\x9f\x7e\x9c\x62\x30\xc5\x83\x2b\x22\x16\x26\x3c\x9b\x90\x26\x02\xdb\xc6\x60\x7e\x9d\xd7\xc4\x14\xb0\x3a\x67\xda\xc4\x93\x50\x93\x0a\x11\x10\xe0\xae\x82\x27\x0d\x35\xd7\x17\x91\x64\x23\x96\xad\x32\x06\x92\x0f\xe0\x72\xe7\x6c\x2c\x7c\xca\x6d\x2c\xee\xf6\x8e\xc6\xa6\x73\x13\x36\xe8\xc8\x92\x5f\xf7\x51\x0d\x65\x17\xd5\x10\xbd\x6b\x14\x3d\xc8\x5d\xd0\xc0\x7e\x04\xa3\x00\x8b\x60\x86\x13\x07\xd8\x07\x5b\x66\x94\x18\x66\x6d\x68\x7d\xcd\xd7\x12\x1c\x48\xf9\xfa\xb3\x06\xe8\xa9\x8e\x57\xe3\x31\x58\x71\x93\xcf\x1a\xdc\xa0\x06\xbe\x36\x5e\xd6\x98\x93\x28\xb3\x51\xe2\x5a\xc0\xfd\x82\xf7\x9b\x05\xb7\xd8\x02\xff\x46\x95\xde\x60\x5d\xa8\x6e\x06\xbc\xb3\xcf\x4d\x7a\x83\xd3\x8e\x37\xea\x87\x9d\xb2\x81\x41\x29\x21\x48\x7e\xb6\xda\x1d\x04\xce\x2b\x73\x70\x9b\xbe\xea\x91\x9e\xdb\x79\x9b\x5e\x43\x46\x18\xd5\x23\x38\x4d\xa1\x98\xac\x21\x98\x08\x75\x14\x7c\x5d\x56\x45\x02\xae\x6b\xcc\x1a\xb6\x15\xc8\x5f\x6f\x93\x53\xab\x8b\xf5\x25\x89\xa0\xeb\x5a\xfe\x81\x12\x5b\x5a\xaf\x26\xbf\xc9\x52\x2b\x6b\xe0\x88\xdf\xbf\xbc\x69\x25\x5c\x69\x87\x91\x9c\xc8\x1b\xa1\x14\xc3\x35\x43\xf6\x0d\xc9\xe8\xde\x67\x37\x43\x5a\x96\x81\x27\x72\xea\x7b\x18\x91\xd4\x61\x06\x7b\xc1\xbc\x93\x7d\x85\x79\x16\x11\x00\x9e\x8e\xc9\x54\xc8\xbc\x1a\x90\xa2\x76\x00\xce\xeb\x25\xcc\x59\x40\x7d\x43\xe9\x3d\x6d\x06\x55\xde\x29\xc1\x69\x66\xb4\xa4\xe2\x2e\x34\xb4\x44\x23\xcb\xed\x73\x03\x47\xa1\x12\x1a\xe1\x75\x73\x33\xc2\xfe\x66\x78\x72\x8d\xc7\xbb\x9e\x78\x6d\xe1\xbc\xca\xd1\x38\x0d\x78\x39\x55\x74\xf3\x3b\xd1\x2d\xee\x89\x6e\x7c\x2d\xba\x89\x84\x2e\x8c\x5e\x34\x82\xc4\x96\x50\x44\xe6\xad\x60\x0e\x95\xcd\x0b\xc2\x46\xc2\xd8\xc4\xe9\xb6\xe8\x76\xbe\x13\xde\xaa\x6a\x43\x0e\xef\xe9\x9b\xdb\x0a\xc4\x55\x02\xc9\xee\x00\xd2\x2a\x93\x47\x72\x9a\x5a\x10\x78\x46\xbe\x9a\x90\x27\x04\x27\x05\x15\x5e\xcf\x5b\x4c\x81\x45\xfe\x0a\x18\xd6\x52\x33\x19\xf8\xc9\xa6\xd0\x38\x35\x63\x39\xce\x70\x8d\xce\xb4\xd8\xc8\xa9\xe3\xa0\xf8\x24\x0c\xf4\xb6\x93\x3e\x57\x90\xa8\xd9\xe4\x84\x7c\x3a\xb0\xe8\xb1\x61\xcd\x00\x47\x55\xa5\x26\x42\x44\x31\xd2\xbc\x08\x33\x3a\x93\x32\x8d\x25\x8f\x50\x39\xd4\xd5\x41\x46\x84\x0b\x78\xd7\xc3\xac\x09\x44\x15\x44\x42\x74\x38\xdf\x34\x09\x22\x85\xbc\x27\x98\x1a\x48\x37\xb4\x98\x23\x58\x91\x2b\x5c\x7d\x0b\x22\x67\x73\x8b\xd4\xc1\x55\x16\xe2\xc4\x15\x42\x0c\xf2\xed\x40\xaf\xb7\x9a\xae\x43\xda\x45\x5c\x70\xcb\x14\x00\x5a\x6e\x6b\xd3\xbc\xe0\x4e\xb3\x46\xbd\xa7\xe6\x3b\x08\xed\x98\xc0\xc5\x68\xbd\xe1\xe0\x07\x76\x61\x0c\xaa\x99\x9b\x84\xa4\x31\x9b\xbc\x12\xd4\x0a\x1d\xc6\x79\x9c\x0a\xc2\xe0\x14\x5d\xf2\x0c\x48\x2e\xb2\x6d\x01\x8e\x5b\x72\x9d\x5b\x44\xa7\x3a\x4f\x7a\x44\xc6\x23\x4c\x44\xe3\xc8\xe0\xe4\x7f\x24\xac\x6a\xee\x44\xdc\x55\x43\xbd\x97\xdd\x30\xd6\x85\x11\x0c\x4d\x8b\x95\x07\xaa\x6b\x96\x3c\x3c\x45\xf5\x7b\x4e\xde\xc0\xf5\xc0\xcd\xf0\xab\xcc\x13\x42\x52\x15\x57\x23\xf4\x5c\xe6\x2e\x02\x21\xa4\x5e\xd2\xd0\x34\x52\x7d\x68\x23\xf5\x20\x80\x10\x00\x35\xb3\x54\xb3\x06\xcb\x2a\x8b\x06\x1d\x78\x24\x8a\xb1\x14\x37\x78\xb1\xaf\x37\x13\x14\x79\xbf\xbb\x31\xb4\xf2\xf8\x29\x36\x5f\x84\x62\x34\xc2\x57\xf9\x11\x9c\xb9\x60\x45\xb9\xec\x38\x00\x52\x9c\x29\xf2\xbb\x4c\x28\x85\xf3\xb8\xc4\xe2\x95\xc5\x5d\xb5\x4b\x5c\xb4\x57\x48\x1c\x7e\x9f\xeb\xf2\x25\x43\x2b\x4d\x3e\xab\x36\x38\xa7\x5d\xbe\x30\xa2\x2c\x67\x18\x76\x71\x2d\x2a\xf6\x33\xf2\x97\x55\x3d\x43\xe3\x45\xaa\x5e\x42\xd8\x50\x37\x2e\x1d\xea\x4d\xab\x21\x78\x8f\x84\xd5\x9d\xf1\x09\x31\xa2\x75\x14\x24\x67\x83\xb0\x54\x15\x4e\xe7\x43\x82\xb4\xee\x14\xd5\x06\xac\xcf\x85\xd5\x2a\x7a\xfd\x3d\xa0\x13\xf8\x03\x9e\xda\x30\x22\xd6\x11\x1e\x55\x65\x2b\x7c\xed\x2f\x9d\x7b\xec\xea\xde\xb0\x2f\xb0\x55\xb7\x33\xa8\x01\xf5\x8e\x98\x6a\xa8\x51\xa6\xe6\xd8\xa4\xea\x07\xb9\xf8\x2c\x80\x92\xf0\xb3\x88\x44\xa1\xe2\x93\xb4\x1a\x43\xf7\xfa\x51\xf7\xa5\xd1\xc2\x32\x57\x2a\x0f\x2d\xa9\x93\x23\x93\x82\x1a\x56\x70\xdf\xf1\x07\x07\x28\x01\xb3\x29\x5b\x12\xd2\x37\xbd\x53\x2a\xed\xd8\x48\x77\x1d\x66\x92\x46\xae\xc1\xf8\x28\xdd\x97\x60\x7c\xe0\x11\xc2\x5b\x33\x04\x86\x92\x91\xa1\x6f\xb4\x15\x66\x84\x91\x34\x0e\xa5\x8c\x94\x48\xee\x6b\x6b\xcd\x48\x15\x18\xca\x6a\x38\x05\x46\xca\x23\xfc\x7a\xac\x74\xca\xd5\x1b\x2b\xc3\xe8\x99\xa6\x5d\xfc\x4a\x5c\x28\x95\xb1\x56\xd8\x41\x21\xa5\x91\x74\x9a\x11\xbc\x5e\x47\xf8\x63\xc8\x79\x8a\x98\x15\xb6\x5c\x1e\xfe\xba\xa9\x94\xe5\xb4\x3b\xb4\xe8\x77\x9b\xcd\x6a\x6b\x87\x32\x26\x78\x1e\x09\x41\xa2\x6a\xcd\x96\xa1\x23\xad\x16\x61\x77\xfb\x53\x44\xbd\x08\x4c\x61\x89\x2e\xfa\x09\x31\x74\xcd\x5e\xab\x0c\x68\x4d\xb3\x6d\x7e\x27\xb9\x4e\x16\x9a\x35\x15\x76\x53\xd3\x2a\x50\x1e\x7d\x30\x4c\x7e\x12\x66\x8d\x0d\x0b\xbf\x3d\x03\xbb\xb6\x50\x55\x62\x98\x50\xe6\xe4\x8c\xe0\xc9\xd1\x7b\x53\x78\x44\x7e\x81\x4d\xd8\xbd\xea\xb5\xf9\xab\x6a\xac\xe0\xd0\x79\x8c\x14\x4d\x2a\x02\x42\x48\x61\x44\x2d\x31\x14\x73\x40\x58\x7b\x49\xc8\xc8\x98\x47\x1b\xe5\xce\xa4\x4a\x83\x97\x6b\xb6\xe6\x2d\xf1\x2d\x6f\x49\xa9\x1b\x78\xed\xff\xee\x24\xd9\xb0\xbb\x3d\x91\xca\xc2\x8e\xd6\x34\x8a\x61\x75\xad\x0f\x2d\xbf\xda\x79\x5c\xd8\xc1\xe7\x29\x13\x82\xfb\x0d\x52\x08\xce\xc8\x27\x68\x80\x7a\xc6\x16\x9a\x8d\x5c\x86\xe0\x0b\x76\xaa\x6f\x0d\x22\x57\xad\xa5\x66\x88\xd3\xce\x14\x59\xc3\xbf\xa3\x34\x69\x26\xb6\xa3\x9a\x2a\xd4\x72\xa6\xfd\x92\xd5\xe0\xa2\x19\x53\xae\x3f\x47\x7a\xa8\x5d\xb7\xf3\xfe\x80\xa3\xdd\xc5\x06\x52\x55\xcf\xee\x75\xb2\xd1\xcc\xb6\xad\x81\xda\xb2\x6a\x5d\xf5\xbd\xc8\xbb\xa5\x1b\xb0\x41\xef\xfe\x9f\xdb\x11\xbe\xbc\xb3\x49\x8b\xa0\x90\x71\x9a\x69\xa0\x0c\x97\x02\x4e\x83\xdc\xa7\xc3\x5d\xfd\xbf\xdd\x91\xd0\xb5\xdd\x98\x1d\x4f\x72\xef\x49\x68\x87\x26\x00\x9e\x7d\x0b\x06\x5c\x4f\xc3\x05\x13\x92\xa1\x12\xa0\x10\x27\x8e\x93\x60\x56\x0d\x86\xc7\xdf\x60\x57\x92\xfa\xc2\xad\x1f\x69\xa0\xe0\x2e\x26\x61\xed\x5c\x0e\x50\xce\x0f\xa9\xbf\x62\x34\x2c\x02\x24\x8e\x56\x93\x32\x56\x77\xe3\xe4\x48\x43\x9c\xd4\x2a\xe7\x5b\xca\x10\x79\x4f\x93\xad\x2d\xaf\x03\x3a\x9a\xad\x36\x0c\xd7\x1f\x0b\x0a\xd1\x3e\xe1\x57\x88\x71\x36\xb6\xe8\xff\xeb\x5d\x54\xd7\x60\x62\xe7\x4c\x08\x48\xa5\x90\x18\x46\x4f\xc3\xa0\xbd\xd0\xab\x6a\x22\x97\xa9\x34\x9b\x9d\x6a\x34\xc0\x85\x2b\x9b\x25\x32\xa1\x70\x0f\x41\xb8\x21\xc1\xdd\x88\x45\x14\x48\x3a\x8f\x13\x38\x87\x22\x82\xe4\xec\xb3\x6c\x23\x28\x87\x30\x24\xb0\x28\x92\x1a\xba\x70\xd8\x50\xa3\x35\x8f\x24\x07\xfd\xc3\x2a\x8e\xe5\x55\x1c\x8b\x2d\xe0\x11\xf6\x66\x84\xa4\x16\x93\x82\xc0\xa0\x61\x07\x62\xee\xf0\x9b\x8d\x34\x5b\xe4\x71\xe0\xed\x8c\xb4\x4f\xbb\x74\xd2\x91\x57\xaf\x05\xaf\x16\x8e\xa5\x46\x3f\x70\xf5\x8b\x95\x07\xcb\xd5\x5f\xe1\x9d\x46\x8a\x67\x7d\x25\x0f\x78\xb5\x39\x50\x9f\x99\x79\x97\x44\xa6\xb8\x3d\x0b\xa4\xf3\x86\x34\xaf\x20\xf2\x2e\xe6\x15\xd8\xb8\x0e\x88\xc6\x63\xaa\x93\x86\x31\x38\x83\x14\x87\x4d\xdb\x9e\xd4\x5a\xfe\x3d\xdb\x24\x23\x6c\x92\x93\x57\x17\x36\x4d\xe3\xa7\xa9\xb9\x90\x23\x0a\x1c\xd6\x62\xd9\x13\x62\x0b\xcd\x02\xf7\x5c\x2a\xc5\xc8\x41\x71\x01\x46\x01\xf3\x0f\x90\x32\x48\xb3\xb2\xbd\xa7\xbe\xdb\x53\xca\xd7\x79\x6e\x63\x29\xc8\xb7\x46\x31\x8e\x56\xc8\x2d\x1c\xbd\xc9\xa9\x86\xcf\x78\xef\x66\xcf\xaa\xeb\x75\x13\x23\x90\xd8\x6b\x1e\x32\xd8\x02\x76\xf2\x7a\x55\x23\xb7\xb1\xc8\xbb\x84\xfc\x54\x09\x92\xfd\x9a\xeb\x82\x52\x53\x1a\x35\xfb\x90\xa0\x9b\x58\x67\xab\xe1\x76\xc2\x09\xc0\xc0\x32\x78\xa4\x30\x64\x61\x3f\x43\x1a\x91\xa2\xb5\x65\xa2\x15\x71\xc9\xc2\x92\x56\x92\x86\x8a\x87\x5c\x7b\x62\x54\x6b\x5e\x10\xaf\xe7\x26\xec\xb9\x81\xcb\x42\xd5\x38\xaf\x35\x8e\xc6\x8c\x36\x20\x0b\xd0\xa6\x15\x4d\xb6\x2e\xf4\x89\xc2\xd7\x5c\x61\x85\x05\xa9\x8d\x42\x2b\xc0\x1e\x87\x6a\x72\x6a\x22\x34\xb5\x48\x66\x08\x4f\x72\x5c\x2d\x7a\x14\xa1\xae\x5e\x2f\x3d\x66\x31\x02\x00\x28\x64\x70\xae\x14\x82\x26\x72\xa5\x10\xa7\x1c\x84\x7e\x00\xcb\xc4\x99\x4a\x34\xde\x4d\x55\x03\xc1\x9b\x56\x00\xe6\x10\xc8\x84\x23\xf2\x83\x85\xb2\xfb\xba\x45\xd6\x50\xa4\x09\x36\xe1\x62\x60\xb2\x54\x4c\x85\xbc\x2c\x2d\xbf\x2f\x64\x18\xe5\x52\x34\x8d\x6b\x4b\x52\x95\xbc\xf4\xea\xc1\x84\x0a\xef\xd3\xfa\x35\x23\x32\x6a\x90\x0f\x93\xaa\xfa\xa8\xf5\x6a\x6c\x15\x1a\xb6\x6a\x71\xaf\x13\x90\x55\x6f\x5a\x3e\xdf\x94\x4d\x45\x5e\x62\xf8\xbe\x91\xe7\xab\x0b\x2f\xac\xb1\xe6\x7f\xa1\x12\x56\x0f\x59\x0f\xb8\xda\xa5\x0b\xce\xd7\xf6\x9e\x96\x0b\x39\xcf\xda\x52\xbd\x4b\x34\x9b\x4c\xfb\xc1\xcd\x76\xd7\xea\x5a\x26\xd9\x75\x35\xdb\xdd\x18\x1b\x7e\x9a\x72\xea\xb1\x3f\xf5\x35\x26\x4e\x4e\xa9\xf7\x83\x44\x08\xa9\x1f\x15\xd1\x50\x11\xee\xbe\x7a\x13\x10\xb4\x5d\xae\xed\x0b\x3b\xb7\xc9\x04\xb1\x59\xd8\x61\x78\x3e\xa7\x81\x43\x10\x3e\x4b\xf3\xb5\x22\x0a\x65\xd0\x07\x38\x6e\xca\x53\xf1\xb7\x75\x19\x25\xef\xfb\xb3\x17\x3f\x58\xef\xeb\x22\x5f\xe0\x7f\x5c\x20\xfc\x20\x18\x27\xeb\x60\x71\xcb\xe3\x4b\x96\xdd\x65\xc9\x8d\x6b\xc8\x1c\x69\x4a\x23\xb7\xe4\x2a\x9d\xd1\x62\xe5\xc1\x72\xa2\x2b\xbc\x4b\xb5\x2c\x39\x96\xf6\x2a\x16\x7d\xb5\x39\x50\xee\xd3\xf1\x86\x36\x12\xfc\x30\x93\xa6\xca\x09\xd0\xb2\xcd\x9a\x9d\x2a\x4c\x36\x55\xa4\x75\x55\x25\xbb\xda\x1f\x94\xc1\x83\x37\x35\xf8\x44\x56\x6c\xd3\xf2\xf1\xfa\x5c\x56\xed\xc5\xc4\x01\xb9\x31\x40\x6d\x89\x66\xb0\x4d\x5e\xd8\xfa\x15\x63\x71\xcb\xcf\xa3\x5e\xf0\x41\x3d\xa1\xe0\xa6\xad\xce\x50\x44\x8d\x06\xa8\x43\x15\xf4\xc1\x31\xed\x58\x3f\xa0\xa8\x66\xad\x6f\x81\x03\xac\xe9\x89\xa1\xb4\xe1\x00\x7a\x6f\x7c\x0a\x2d\x35\x91\x2a\x0c\x19\xba\xe1\x96\x4f\x48\x73\x21\x20\xf5\x10\xeb\x3c\xa7\x04\x0a\x6d\x5a\xb4\xb6\xba\xb0\x37\xee\x33\xe5\xa6\xd6\x01\x2b\xd3\xf2\x0c\xe6\x3c\x5b\xaf\x3e\xd1\xe4\xdc\x84\x8c\xcd\x48\x9c\x9a\x4d\xad\x2b\x63\xe0\x29\x9f\xc7\x91\x4d\x1a\x59\xb0\xd8\xd4\x94\x67\xed\xea\x47\x9e\x11\xab\x2f\xc8\x7b\x67\x95\x4e\xab\xd9\x6f\x3f\x05\x93\x6e\x95\xe6\xae\x53\xad\x51\x55\x65\x65\x88\x26\xc1\xe9\x9d\x35\x74\x5c\x6b\x18\x60\xad\x57\x17\x3e\x67\x13\x13\x63\xd1\x85\x34\xfc\x91\x59\xbd\xff\xab\x9f\x34\xce\xb6\xf9\xec\xb3\x9b\x5b\x36\x09\x9a\x7c\x35\x2c\xe8\x42\xb3\x33\xc1\xf9\x1a\x94\x41\xf8\x3a\xa4\x89\x84\x94\x45\xa6\x66\xc4\xeb\x92\xfa\xfe\x33\xcd\x36\x45\xc3\x8c\x18\x02\xb8\x7f\xea\xa9\x61\x9b\x31\xc8\x56\xe0\xbe\x80\x6a\x39\x92\xee\x45\x30\x37\x47\x5e\xd8\x05\xb9\x61\xc2\x69\x42\x90\xca\x57\x17\x69\xfb\xdd\xe6\x50\x5d\xc1\x02\x8a\xe9\xda\x0b\x36\xb3\x66\x09\x88\x86\x5d\x36\xd1\xd3\x8c\xb0\x74\x4a\x93\x06\xe7\xc4\x96\x35\x83\xd2\xcc\x6a\xfb\x8a\x88\x21\x50\xc7\x26\x64\x85\x8e\xde\xcf\x36\x82\xa7\x84\xf3\x86\xa6\xd6\xd0\x6e\xf2\x6c\xb5\x5f\x58\x5f\x53\x1b\xce\x72\x0a\x8d\x5c\xda\x80\x9c\x41\x81\x5a\xbe\x18\xb7\xbb\x53\x81\x94\xcc\x69\x7c\x3d\xec\x81\x2d\xdd\x15\x23\x81\x53\xfb\x49\x33\x5a\x69\xdb\xac\x89\x49\x03\x26\x10\x20\x2a\x67\x85\x4e\x39\x4c\xb4\xbd\x32\x17\x81\xc9\xa4\x54\x17\xa2\x35\xdb\x28\x42\xb8\xb8\xb8\x99\x35\xcd\x9b\xcb\xbb\x80\xfc\xa8\xd2\xf5\xce\x53\x85\xb9\x5c\xf3\x23\x04\x8e\xbd\xaa\xdc\x47\x4d\xb5\xe9\x9b\xe1\x52\x84\x97\x16\x4c\x60\x53\x95\x1d\x82\xc8\x07\x5f\x95\x5d\x8c\xae\xc6\xdc\xad\x89\x0a\x81\x6f\x34\xf3\x1c\x2e\x23\x6e\x86\xfa\x11\xf8\x7c\x1e\x07\x21\xc5\x70\x2d\x0a\x6a\x22\xb1\x25\x34\xbd\xea\xac\xa1\x05\x9a\x5a\x5c\xcd\xa0\x76\x5d\x4c\x9a\x6d\x5b\xe0\x96\xc9\x47\xc0\xe4\xe9\x6d\x30\x29\xab\xce\xac\x06\x53\xd5\xa3\x87\xc8\x68\xae\x97\x4c\x33\x43\xf9\x9a\xdc\x40\x3e\x2f\xd0\x78\x26\x81\x80\xba\xb2\x44\xc0\x4f\x46\xd3\x6a\x35\xf3\x09\x40\x24\xa9\x58\x80\xb0\xc9\x24\x0b\x1b\x2d\x69\x26\xcd\x0a\x6e\x82\x92\x47\x42\x8a\x14\x27\x82\x9f\xd3\x2e\xfa\x62\xce\xed\xee\xc2\x18\x84\xb0\xa7\x48\x46\x3d\xbf\x58\x2e\x3d\xa4\x53\x91\xd9\x8d\xfa\x44\xa2\xc4\xc0\x6c\x4b\xb3\xa5\xc2\x13\x21\xaf\xe2\x8e\x16\x0f\x68\xa9\x6f\xd5\x18\x82\x5a\x1b\xca\x32\x24\x32\xb8\xdf\x24\xb7\x8e\x53\x35\x95\xc3\x9a\x37\xbc\xb6\x8c\x32\xa5\xa8\x9e\x56\x25\x2c\x72\x42\x2f\xe7\x4c\x26\xc5\x85\x9c\x47\x75\x97\x5d\x3e\x22\x52\x83\x20\x0b\xa8\x62\xf4\x0d\xe7\x6b\x39\x89\x67\xb7\x4f\xa2\xee\x92\x10\x08\x36\xba\xba\x08\x26\xba\xb4\x50\x45\x54\xb3\xaf\x6e\xa0\x22\x74\x18\xce\x3f\xce\x8d\x78\x40\x7a\x04\xa4\xd5\xf2\xb5\xde\xa7\xfd\xe6\xb4\x0e\x24\xdb\x5a\x83\x00\x84\x86\x25\x1f\x50\xb3\xa3\x78\xf8\xc9\xa8\x88\xb1\x70\x72\x83\x4d\xfe\x08\x26\xec\x6a\xbd\x9c\x90\xb5\x79\x7d\xb5\xdd\x6b\x9f\x4e\xeb\x6f\x1d\xe9\x95\x6a\x3c\xa5\xa5\x44\x37\x70\xa1\x5d\xa9\x0a\xe1\x4c\xca\x0c\xf5\x67\x0d\xad\xd0\x84\x05\x23\xed\x20\x5e\x89\x50\x20\xb2\xc7\x14\x55\x4e\x52\x2c\x08\x0d\x17\xb7\xe4\x3a\x10\x2a\x91\xdd\xce\x06\x32\x6a\x18\xd5\xac\x7f\xba\x73\x28\xcb\x81\x10\x44\xe4\xbd\x52\x16\xc4\x68\xa2\x75\x86\x02\x6e\x89\xa1\x11\x5c\xad\x81\xe0\x76\x6e\x9e\x3e\xc8\x77\xc8\xb2\x9a\x11\xc4\x28\x34\xd0\x99\x5c\xf2\x20\xd7\x0b\x7c\x38\xac\x75\x6e\x0e\xd5\x14\xf8\xc6\xa3\x3a\x86\xc8\x45\xa8\x17\x25\xf7\x55\xee\xa2\x08\xef\xe1\x08\x97\xfa\xb2\x07\xef\x35\xc6\x53\xc4\x7b\xe2\xca\xe0\x79\xb3\xa7\xc6\x52\xe7\xad\x78\x83\x7f\xfc\xc9\x37\xcf\xba\xca\x3f\x39\xac\x60\xed\xa4\xb7\xa6\xbd\x62\x83\x84\x1a\x7e\xd6\x7c\xf9\x13\x91\x6b\xa9\x0b\x6d\xa1\x19\xc2\x55\x6d\xea\xc1\xb0\x0b\xa1\xad\x2a\xf8\x40\x1e\x59\x51\x7e\x2b\xe2\x04\x41\x29\xd7\x96\x5f\x95\x2a\x5f\x5d\x70\xf4\xeb\x78\x36\x7a\xa3\xfa\x62\x94\x3d\x50\x44\x08\xf5\x6f\xc9\x06\x71\x06\xa6\xd4\x19\xbf\xc0\x6b\x40\x51\x78\xbe\x56\xeb\xa8\x8b\xfe\xea\x79\x79\x24\x35\xdf\xb3\xbe\x50\x98\x5b\xdd\x08\x52\x32\x99\xe2\xc2\x9e\x07\xef\xfd\xe2\x93\x1f\x38\x22\xb1\x8c\x1f\x3c\x0b\x4f\xe3\x59\xa4\x93\xbc\x58\x5f\xe0\xd7\x9e\x16\xaf\x72\x88\xd7\xba\x47\xb4\x30\x97\xa1\x20\xea\x84\xcb\x60\x8b\xdf\xb0\xc1\xcb\x4c\x3a\xd5\x4f\xb9\x56\xba\x89\xd4\xc5\x1e\x69\x9c\x5d\x52\x5d\x30\x15\x6a\xc1\x9c\x39\x4e\x84\x4b\xc9\xdc\x52\x7e\x35\x0a\x44\x2d\x4b\x35\xef\x72\x50\x29\xa1\xa1\xc6\x20\x27\x78\xb3\xc2\xd4\x52\x91\x95\x3b\x0d\x1e\x21\x44\x31\x0e\x36\xb1\x5f\x28\x46\x84\x4c\x73\xe4\x29\xa1\xa8\x04\xbe\x54\x46\x20\xc3\x56\x8e\x3b\x0f\xf3\xa5\x8c\x90\xae\x65\x68\x46\x3a\x96\x08\xbd\x9c\x48\xa8\x1e\xa2\xa9\xd0\x33\xc1\xb8\x47\x4e\xa4\x53\xd7\x14\xef\x77\x5a\xfb\x82\x89\xa6\x81\x5b\x79\x0c\x36\x2a\x64\x60\xe0\x16\xe7\xed\xd7\x8c\x67\x55\x18\xa3\x59\xe4\xb3\xb2\x96\xc4\x88\x08\x28\x86\x2e\x42\xee\x29\xf1\x42\xde\x0f\x44\x3c\xc1\x6f\x0a\x3d\xc0\x0f\x14\x0c\x42\x56\xc1\x06\x8c\x73\x31\x9a\x3c\xab\x04\xc3\xea\xfb\xa3\xbe\x7b\x55\x9d\x23\x19\xb8\x16\xc4\xe4\x3a\xe5\xb6\x23\x23\x02\x06\x52\x98\xb0\x30\xef\xf0\xdd\x6c\x18\xed\x3a\x1a\x56\xe1\x75\x0d\xab\x47\x85\x92\x96\x8f\xc7\x69\x9d\x17\xf5\xed\xc4\x6c\x60\x08\x0a\x2a\x81\x68\xa8\xe7\xac\x0e\xd7\x1a\x51\xac\x4e\x14\xea\x7e\x03\x45\xf2\xac\x39\xfd\x44\x44\x98\xa0\xc1\x80\x75\xb6\x6a\x5a\x15\x5b\x8a\xa6\xa7\xdb\x3e\x8d\x4e\x03\x94\xd6\xb4\xcc\xb2\x32\x26\x1e\xa9\x56\xc3\x29\x0d\xde\x55\xc0\x50\x13\xeb\x41\x51\xf9\x18\xc0\xf7\x6a\x06\xbf\xc6\xc1\xc6\x78\x6d\xf4\x5d\xd3\x6c\xa6\xc6\x8e\x86\xda\x4a\x32\x21\x51\xde\x9a\xb2\x5c\x93\xcf\x6a\x48\x4d\xd2\x9c\xa6\xb9\xc0\x13\x7f\x89\x48\xed\x79\x23\xf5\xc5\xea\x5e\xba\x6f\xec\x0d\xc4\xa3\x4d\x02\x2b\x48\x61\x18\xd6\x70\x04\x75\xe8\x9a\xd7\xd4\xb4\xe0\xa4\xda\xe1\x57\x39\x08\x40\x7c\x01\x07\x29\x0c\x45\xd1\xac\x6a\x74\xac\xc2\xd9\xb3\xbe\x20\x0f\xed\x92\xa2\x05\x53\x4b\x81\x8e\xf7\x3a\x03\x7f\xde\xcb\xc0\xef\xce\xe3\xe0\x61\xe7\xe0\x48\x5d\x36\xf3\x9b\x91\x87\x14\x05\xe9\x88\x18\xac\xe1\xda\xda\x05\x37\xe7\x3d\xed\x1b\x75\x10\x2a\x0b\x8a\x89\x6e\x61\x87\xc8\x63\x68\x6a\xb6\xe7\xdf\x69\x30\xe2\xca\xfa\x21\x25\x7d\x2a\x60\xa8\xd4\x73\x15\x70\x70\x6c\x33\x3a\x19\x33\xae\x2e\x7e\xd0\x6c\x79\x44\x92\x53\xe0\x01\x11\xf1\x50\x9b\xe6\x09\x7a\x04\x5a\x33\xdb\xcd\xb0\x76\x70\x13\xe5\xf3\x5a\x26\x09\x8e\x91\xac\x25\x24\x52\x18\x6d\x36\x94\xa8\x19\x1a\x08\xb9\xab\x66\xef\x70\x15\x26\x61\x69\x50\x75\x69\x95\xd7\x1d\x0a\xef\x6c\xcf\xba\xaf\xaf\xe7\xd3\x8a\xae\xe5\x66\xd4\xb8\x50\xac\xa3\xf7\xd9\xb0\x5f\x6c\x21\x1e\x2c\x93\x5b\x92\x77\x83\xa5\xad\xf4\xa7\xd2\x73\x27\xe1\xec\x4a\xb6\xa0\x22\xa2\xe3\xb8\x10\xf2\x4d\x50\x28\x22\xd4\x31\xc4\x2f\x8e\x0c\xfd\xe2\xdc\xdc\x4a\xf1\x5c\x9b\x2f\x19\xa2\x9e\xf4\x23\xf5\x9f\x17\x59\x50\xbf\xb3\x2c\x02\x5a\xf3\x80\x59\x23\xda\x7c\x0b\xa3\x5a\x25\xb2\x80\xc2\x44\x5c\x02\x86\x07\x51\x89\x26\xac\x89\x33\xb5\x02\x44\xbc\x4e\xc1\xce\x5a\x49\x63\x0e\x41\xa5\xcd\x36\x5f\x39\xce\x26\x25\x02\xfe\x72\xcb\x85\x5a\xc2\x5e\x1e\xfb\x28\xb2\x47\x0b\x36\xd7\x49\x6f\x0b\x83\xcf\x7a\x11\x24\xfb\xeb\x60\xc7\x48\xa3\xa0\x3a\x5f\xeb\x08\x9c\x17\x9c\x8a\x14\xf0\xc0\xf6\xf0\x35\xa8\x9a\x1d\x49\xfe\x6a\x62\x88\x7e\x78\x75\x11\xb2\x7b\x58\x0f\x9b\x93\xed\x05\x93\xb0\x53\x30\x52\x36\xee\x0a\xff\x11\xd7\x70\x07\xe4\x5c\x88\x24\x84\xda\x82\xad\xfe\xd9\xe1\xf2\x67\x2e\x18\x4e\x71\x0c\xec\x4d\xf4\x61\x91\xfb\x43\x8b\x8d\x2e\x0e\xe4\x10\xb0\x8b\x8c\x4b\xf2\xe4\xab\x8c\x40\x0b\x1e\x02\x21\xff\x72\x35\x5c\x85\xce\x96\x85\x63\x6e\xd5\x0f\xc8\x0b\xd6\xdd\x5e\x61\x27\x23\x51\x88\xf9\xfa\x52\xc8\x0a\xf5\x6e\xdc\xbd\x42\x5f\xee\x5e\x61\xe1\x60\x62\x4c\x3f\x4c\xb6\xc8\x3c\x36\x5f\xd4\x8b\x8a\xc9\xaf\xc1\xb8\x5e\xf6\x36\x57\x53\x6a\xf8\x51\xb3\x47\xe6\x00\x7f\xf4\x5d\xb0\x47\x17\x21\xa6\x13\xe0\xb1\xd2\xc3\x6f\x1c\x09\x08\xdf\xff\xca\x75\xe2\x60\x5d\xe5\xb7\x80\x38\x25\x35\xc0\xe6\x60\xd8\xfb\x19\x65\x26\x8b\x17\xa0\x0d\x11\x11\xb5\x8a\xe5\x49\x03\x4f\xf8\x1c\xce\x82\x93\xe5\x35\xee\x58\xd5\x0b\x6e\x2f\xd1\x8e\x2a\xef\x27\x94\x20\x45\x10\x1e\xb5\xb4\x52\xea\xf5\xa0\x2a\xf4\x96\x76\xd6\xd6\xd5\x81\x95\x02\xaf\xc5\x38\xe2\xea\xd1\xc3\xc1\x04\x3f\x47\x64\xff\x18\x5a\x59\xa0\x34\xc1\xc3\x8d\x76\xd4\x80\x95\x0a\xf9\xf5\xbc\x49\x73\xf6\x25\x2d\x87\xe0\xe5\x2c\x40\x49\x8c\x77\xe5\xea\x22\x38\x6f\x8a\x27\xb3\x70\xa4\x35\x6b\x36\x1d\xc9\x9a\xfd\x8f\x3f\xf9\xe6\xb9\x08\xc0\xdf\x79\x8a\xe2\x80\x24\xf7\x3e\x27\x43\x85\xcb\x46\x44\xfe\xfd\x12\x19\xcb\x5a\xe8\xfb\x5b\x4b\x8c\xc8\x9d\xe4\xee\x14\x07\xee\xbf\x2a\xfe\x1e\x4f\x28\x69\xe5\xb3\x85\xd5\x56\xc4\xc1\x0d\x94\xea\xc8\x05\xc5\x84\xfd\x62\xd9\xb7\x34\xc4\x48\xc9\x14\x10\x08\x86\xf2\x26\x72\x88\xc4\x0f\x58\xae\xff\x1e\x97\x1b\x92\xa0\xe3\xa0\xc6\x02\x35\x75\x25\xd5\xfa\xc3\x5b\xaf\xee\x72\x89\xb7\x72\xe6\xfa\x2e\xaf\xcf\x93\x17\x04\xaa\xc9\x80\x78\x86\x5d\x3d\x57\x15\x51\x82\x22\x84\xd4\x32\x3a\xd9\x35\x15\xb5\x7a\x06\xa5\x8c\x20\xdf\xac\xd9\xac\xe0\x39\xa4\x16\x46\xb5\xeb\x05\xcd\x85\xae\xa9\xd0\x35\xff\x02\xab\x2d\x61\xd5\x90\x3f\x60\x9f\xc3\xf7\xb8\xcf\x3e\x18\x4a\x8e\x0e\x99\xce\xb6\xd6\x71\x51\xb6\x3f\xda\x5c\x63\xfc\x1e\x11\x02\x55\x43\x19\xc7\x5e\xbc\xd1\x52\x09\xc8\x09\xa1\xb0\x83\x6c\xbd\x2d\xf9\xaf\xa6\xd9\x43\x7e\xc1\x56\x1b\xbf\xd1\x8f\x12\xd6\xf3\xd6\x9c\xdd\xad\x65\xd8\x39\xbb\x45\x36\x31\xcc\x36\xa1\xc6\xcb\x8d\xbd\x33\x37\x37\x2f\xc9\xe6\xe9\x6c\x60\x1b\x29\xca\x2f\x34\x97\xf7\xf3\x38\x21\xda\x29\x65\xd5\x1c\x70\x5a\x79\x1b\xe4\x72\x4f\x26\xf3\x6c\xe5\x65\x99\xac\x66\x47\xd0\x42\xa7\x1a\xce\xa9\x7c\xc6\xf6\x21\x74\xc2\x3e\xbb\x55\xcf\x91\x76\x59\xf9\x7c\x32\xec\xc6\x94\x8b\x9c\x0b\x09\xbf\x90\x17\xeb\x51\x0b\x9c\xb5\xfa\x11\x05\x42\x3d\xcb\x91\x90\x5b\x39\x0d\x01\x65\x57\x91\xcc\xa6\xba\x91\xb2\xb1\x41\xd6\x5e\x48\x5d\x82\x68\xaf\xae\x1e\xb9\xb8\x46\x7e\x24\xc3\x05\x69\x4b\x85\x32\x06\xef\x46\x70\xa1\x94\xe2\x58\x80\xb7\x76\xc1\x6a\x74\x75\x91\xbd\x33\xb1\xf0\xe0\x5d\x42\xca\xa1\x18\xc3\x68\xa3\xd9\x66\x52\x9f\xf7\xae\x0d\xfb\xd9\xde\x05\x2c\xfe\x9e\xf3\x5d\x73\xbe\x5f\x44\x2d\x0b\x55\x7e\x88\xda\x8d\xe7\xbd\xdd\xff\x7b\x4c\xcc\x8e\x21\xaf\x2e\xd4\xcd\x71\x93\x5d\xda\x5c\x4b\xef\x58\xf0\xfd\xaf\x25\xa4\x74\x1a\xbb\xb4\xb9\xaa\x4e\x4b\xf4\x03\x58\x15\xa3\x8c\xdd\xbb\xb0\x4b\x9b\xcb\xed\x34\x3d\x3f\x84\xe5\x86\xb8\x49\xc6\xf3\xf6\xbb\xcd\x35\x76\x0a\xa2\x5d\xce\x76\x8b\x54\xd9\x9c\xb7\x24\x05\xa7\x2c\xf8\xb7\x9b\xd8\x5d\xa6\xd8\x69\x78\xbe\x8d\xb4\xf2\xe8\xeb\xea\x82\xc0\x7c\xc7\xfa\xf0\x3b\xd2\xa9\x4c\xae\x37\x94\xe5\xfe\x15\xf7\x0e\x8c\xfd\x77\xb6\xe7\x9d\x88\x7f\xbd\x8a\x28\xfc\xba\x73\x87\x00\xf0\xb1\xa7\x77\x11\x42\xd8\x1a\x6c\x6b\xea\x2f\x3a\xeb\x32\x85\xb5\x42\x5f\x48\x26\xa5\xb8\xc8\xdd\xa4\x1a\x17\x70\x22\xfb\xb9\x49\x63\x7c\x94\xf2\x25\xfb\x88\x21\x08\xc0\x50\x15\x61\xc1\xbf\x6b\x49\x93\x40\x34\x30\xb8\xa5\x88\x44\x3e\x61\xb1\x21\x6c\x33\x46\x2f\x7a\x3b\xf3\x0f\x33\xa1\xfb\x4a\x9f\x10\x0c\xf7\x2d\x49\x82\xe6\x2e\x51\xf0\x9d\x24\xc1\xcd\x23\xe8\x63\x2b\xf6\xf3\xd2\xbb\xab\xbf\xb5\xec\xf4\xe6\xc2\x67\x3e\x46\x56\x36\x77\xb2\x8f\xa8\xf8\x5b\xdf\xc9\x18\xe9\xdd\x68\xd5\x8b\x03\xa1\x16\x7f\xe3\x7b\xea\x93\x7b\x47\x1a\xbd\xb9\xd9\x07\x22\x1c\x7e\x28\x9b\x1d\x60\x11\xf1\xdf\x95\x0a\xce\x3c\x1e\xe2\xfd\x21\x15\xd9\x90\x43\xee\x9d\x2c\x7e\x30\x87\xec\xdd\x26\xdf\xf6\xed\x6d\xa2\x39\xb6\x8b\x17\x65\x7b\x4e\x9b\x3b\xdc\x6b\x7b\xdc\x9a\xd5\x3d\x91\xf1\x99\x46\xef\xaa\xf1\x88\x0f\x6f\x0f\x94\x85\xb1\x08\xa3\x47\x35\x30\x72\x78\x00\xe9\x41\x79\x9e\x14\xb4\xa9\x95\xb6\xbb\x07\xbb\xff\x52\x9b\xdb\xb5\x83\xed\xd9\xf5\x3a\x8c\xb0\x3a\x96\x64\x3e\x7e\xf2\x2d\x82\x15\x69\x2e\x77\xd5\xf9\xfd\x79\x1c\x45\x6c\x27\x3f\x50\x10\x19\x12\x25\x44\x0a\x4d\x9a\x6d\x1e\x5a\x52\x64\x35\x87\x26\x33\xb7\x14\x89\x77\x42\x4a\x73\xbf\xcf\x65\xcd\x99\x18\xb5\xd8\x0a\x72\xb3\x69\x25\x01\x04\xc6\xf9\x6a\xd8\xd7\x09\x69\x77\xc9\x69\xd0\x20\xcc\xb1\x65\xb6\xb8\xae\x9e\xa3\x5a\x2c\x1a\xf8\x48\x23\xb8\xd9\xc2\x17\x76\x8e\xdc\x6a\x37\x6b\x5c\x7f\xc8\xde\x14\x62\x94\x3d\x61\x0f\x87\x0e\x9f\x66\x8b\x1c\x34\x13\x7c\xcb\xa1\x1a\xdd\x84\x97\x48\xe0\x94\x27\x28\x96\x22\x5c\x4f\x64\x8f\xd6\x24\x1c\x54\xee\x80\x50\xd8\x61\x39\x18\x76\x69\xb6\xf0\xb5\x48\x50\x4b\x6e\x9f\xe7\x81\x00\x91\xbd\xba\x09\xee\xea\xc7\x51\x3d\xe1\x22\xb0\x7f\x88\x9a\xeb\x45\xaf\x10\xfa\x51\x6e\x4f\x72\xfc\x6e\x9a\xb3\x17\xbd\x2a\xe9\x47\xb9\x51\x81\xe8\x34\x65\x9c\xb9\x3f\xff\xd4\xbb\x32\xfd\x28\xb7\xd0\x17\xda\x54\xf0\x95\x5b\xef\xcc\x29\x04\xb3\x77\x90\xda\x2f\x50\x01\x83\xf3\x0f\xa3\x4c\xc5\x45\xf4\xf9\x1d\xaf\x59\xef\xaf\xe4\xf7\x6a\x92\x1f\x57\x4b\x85\x50\x0e\x81\x4b\x0a\x03\x33\x4d\x1c\x11\xcb\x5a\x11\x04\x1f\x66\xb8\xe2\x78\x8d\x7b\x42\x4e\xa0\xf6\x03\x0a\x16\x69\x9b\xc1\x32\xd3\x62\x4b\xaf\xf1\x00\x25\x8b\x26\x92\x76\x4d\xc8\xba\xd6\x0a\x99\xa1\x4c\x7a\xab\xf1\x8e\x78\x4f\x3c\x27\xb7\xab\x74\x16\x5b\xbf\x9b\x09\x9e\x64\x1f\xfa\x80\x0d\xcf\x74\x7d\x57\x6e\x04\x31\xd7\xd4\x78\x37\xe2\x6a\x7c\xa8\x33\xb2\x79\xb3\x9f\x08\xf9\xaf\xb9\x6a\xa8\xb9\xe6\x4b\x6f\xd9\x30\x5a\x24\x3b\x69\xb4\x0f\xe2\xce\x10\x9b\xeb\x9b\x2b\x1b\x5c\xa6\x92\xd6\x82\xde\x25\x6d\x69\xb9\x8a\xcb\xfa\xb1\x96\x63\xc0\x4f\x7e\xb6\x1e\xb1\xa8\x61\x97\x85\x2d\xea\x26\xac\xe9\x8f\x03\x21\x9f\x33\xfb\xc9\x6b\xfe\x33\x75\xa7\x42\x4a\x35\x4d\xa5\x6c\x29\xed\xdc\xb1\xa9\x1a\x5f\xe6\xe0\x0d\x39\x6f\x5a\xf8\x0c\x8a\x61\xe9\x3c\xf1\xd8\x72\x93\x56\x87\x98\xff\xea\xe6\x88\x9c\x31\x6b\xb0\x0d\xa4\x20\x0a\xd7\x59\xd5\x55\x1a\xc9\x1a\xae\x27\xdc\x4b\x52\xdd\xdf\xca\xed\x2c\xd2\x2e\x0f\x47\x0f\xe6\xb2\x57\x4e\xee\x57\xb7\x70\x57\x7f\x03\x35\x2e\xcc\x81\x22\x17\xf7\xa9\x71\xc1\x54\x0d\x45\x17\xb6\xec\x12\xdf\x75\x0d\x0c\x39\xd6\x5e\xd3\xfa\xf7\x63\xbd\xe7\xb1\x7e\x8b\xc7\x76\xe1\x45\xc2\x60\x9f\x1e\x4c\x58\x2e\x7b\x3d\xee\xdf\x0f\xf8\xbe\xf7\x16\xb1\x25\x31\xbf\x83\xf9\xeb\xfb\xb8\xda\x07\x32\xf9\xfc\xfd\xe4\xef\x77\xf2\x42\xe9\xc9\xc3\x3d\xfc\xbb\x77\xf1\x7b\x27\xf5\xa2\xf9\x5e\x40\xae\x57\xcb\xff\x1d\xe4\xee\x0b\x72\x59\x90\x0d\x92\xd2\xf6\xda\xce\x6f\x91\xd2\xa4\xed\x71\x37\x8f\xbb\x37\x0c\xfc\xfd\xb8\xef\xcd\x3c\xb0\xa1\x00\x6f\xb5\xef\xcc\xf1\xf3\xdd\xc0\xc8\x1c\x87\xa3\x20\x70\xa4\x0b\xfa\xae\x7d\x47\x2f\x7b\x1b\x46\x5e\x6b\x11\x66\x6f\xbc\x86\x01\xc6\x2a\x70\x6e\x38\xc4\xd9\x67\x67\x4a\x1a\xa8\xd0\x12\xab\x00\x62\x45\xb2\x03\xc4\xae\xce\x90\xf0\x34\x07\xdd\x5a\x4e\x29\xcb\x91\xb6\x7c\x95\x56\xd3\x93\x71\xf1\x70\xf7\x5d\xa3\x74\x90\xca\x07\x81\x3f\xbe\xcc\xde\x6b\xe2\x94\x09\xf1\x5c\xf0\xde\xd4\x22\x13\xc8\x49\x8c\x14\x0f\x89\x4c\x04\x04\x9c\x6b\x88\x49\xcb\xa6\x84\x9d\x62\x62\xcd\x9f\x77\xa3\x24\x55\x59\x84\x22\x0c\x36\x45\xd7\x4a\x52\x05\x8d\xd3\x49\xc9\x68\x25\xe6\x19\x03\x41\xdf\x3d\x55\x0c\x8c\x82\x42\xad\x22\xd5\x98\x55\xee\x43\xf1\x0b\x3d\x39\x38\x6e\x60\xcd\x2c\x83\xa1\x2a\x3a\x12\xaf\xed\x12\x7c\x07\xd7\xb2\xb2\x9d\xb7\xea\x3a\x13\x40\x1e\xee\x24\xaa\x2f\xd2\xba\x3a\x96\x35\xb5\x14\xd2\x5b\x58\xc2\xe8\x96\x11\x72\xd4\xf2\xd4\x3b\x0d\x91\xcc\xd7\x9c\xb3\xe6\x30\xa8\x46\x73\xa8\x20\x12\x93\x54\xef\xe4\x5b\x8a\x0a\x81\x46\x32\x9a\xc5\xce\x39\xa4\x9e\x5a\xb4\xfe\x75\x16\xac\x56\x1a\x90\xeb\xc0\x33\xd2\x7c\xaa\xef\xe7\xd5\x05\xb9\x18\x4c\x0a\x60\x9a\xe3\xe0\x13\x2f\xbc\xcb\xee\x83\x08\xb8\xd0\xc2\x7b\x63\xab\x9e\xb5\xab\xca\x17\xb8\x39\xd5\x5a\xb0\x72\xb2\x9d\xdb\x90\x77\xc0\xb6\xb3\x57\x0b\x4f\xad\x67\xff\x2d\x57\xc4\x03\x8c\xc1\xcf\x16\xd5\xf0\x90\x72\x75\xad\x82\xd7\xb2\x78\x6d\xd4\xc1\xbb\x08\x30\xfc\xfc\x30\x3d\x77\x2f\x0f\x64\xec\xda\x2b\x1d\xd7\xce\x4d\x0b\xc8\xb9\x56\x40\x8e\xb5\xa8\xc7\xec\x91\xbd\x8d\x62\xfc\x01\x97\x8e\xa3\x22\x33\x74\x71\x5b\xe3\xd0\x95\x96\x33\x47\x6b\xcb\xdd\xaf\xb4\x9c\xec\x70\x6f\x87\xfa\x51\xed\x30\x62\x9e\xe4\x66\xde\x19\xc9\xb5\xbf\xd7\xe6\x94\x3a\x7e\xf7\xdf\xeb\xde\xa8\xf5\xa3\xda\x6b\x02\x92\xc3\xc6\x9d\x28\x87\x9b\x03\x82\xf8\xfd\x8a\x29\xde\xff\x10\x7a\x83\xd9\x8f\xeb\x10\xc0\xe1\xe4\x72\x58\x3e\x79\x2c\x74\xd2\x72\x22\x1e\x1c\x66\x73\xe7\x3b\x3b\x5b\x2a\x6b\x76\x30\x08\x23\xb2\x92\xb4\x85\x0a\xf7\x6b\xcd\x9c\x5c\x51\x6f\x73\x2a\x9d\xe9\xea\x7a\x2a\x70\x35\x7e\xd0\x68\x8a\xce\xd9\x97\x87\x6b\x03\x3b\x33\xd3\x6e\x5e\x16\xa5\x13\xeb\xbb\xba\x78\x3f\xee\x36\x76\xd6\xa0\xeb\xe9\x7a\x64\xed\xad\x9b\xce\xdc\x0f\xdb\xe1\x90\x36\xbb\xdd\x9a\xe4\xcb\xde\x32\xc2\xb4\x46\xac\x39\x13\x90\x2f\x00\x56\x2a\xd4\xe9\x67\x24\xa7\x69\x89\x25\xa7\x1c\x21\xda\x79\xc4\xfd\x23\xed\x7d\xa2\x31\x98\x30\x59\x76\x26\x23\xa6\xdf\xa8\x3f\x89\x26\x90\x46\xce\x52\xb9\x2e\xa3\xcd\xc5\x10\xd2\x08\x23\x4b\xe1\xa4\xf9\xf2\x55\x42\x32\x5a\x04\x08\x17\x1b\x99\x2d\x2b\x1b\xa6\x32\x15\xd8\x8c\x0d\x89\x30\x1d\x93\x26\x38\x2f\x61\x64\x27\x5d\x25\x15\x0c\x90\xba\x51\x9e\x6a\x41\xde\x32\x24\x63\xa5\xbc\xba\xb7\xcc\xc2\xf6\xfb\x80\xa2\x6d\x39\xa9\x4f\x79\x6e\x71\xee\x72\xcb\xb5\xae\xa8\x6f\x71\x64\x49\xb3\xd8\xf9\xa2\x69\x65\x57\xdf\x16\xcd\x2b\x1b\x8a\xba\xc1\x51\xdb\x23\x24\xf9\x4e\x2d\xe9\x44\x99\x51\x48\xc1\xd8\x9c\x27\xe4\xfb\x30\x6b\x75\x21\xe1\xec\xd0\x0a\xf3\x59\x72\x99\xac\x0f\x46\x4e\x16\x02\x6c\x4a\x73\x93\x05\x50\x8f\x8a\x15\xbf\x20\x0b\xba\xcd\x75\x56\xb1\xc8\xb2\xdb\x4e\xd5\xf8\xb2\xb7\x89\xec\x97\xd1\x73\x57\x3f\x8a\x62\x7a\x17\xec\xd3\x5d\xba\x4d\xf3\x03\x55\x6e\x6e\x9e\xdc\x01\x63\xc7\x5e\x35\x40\xa1\xbd\x3f\xa4\x9a\x80\xcd\x1e\xb8\x49\x92\xde\xa9\x66\xa0\xb9\x57\xd1\xc0\xcd\x1d\x3d\x60\x44\xf8\x01\xef\xe8\x77\x52\x65\xd1\x60\xc7\x56\xd3\xdc\xc3\x89\xf1\xcb\x03\xda\xf2\x1f\xf0\xde\x36\x2b\xd8\xbb\x70\x08\x77\x1f\x8f\x79\xac\x2a\x98\x9b\x9b\x7e\x40\x67\xfd\x03\xde\xf4\x66\x80\xe2\xff\x06\x23\x8b\xbe\xc3\x92\xa7\x9b\x87\x7d\x20\x73\xe0\x0f\xf9\xb0\xd5\x04\x73\x90\xa7\x7d\xc4\xcd\x34\x77\xec\xe6\x6a\x0a\xba\x17\x13\xdc\x2b\x40\x69\x4d\x44\x1a\x93\x11\x56\x9b\x39\x0f\xe4\x34\x18\x00\x99\x9d\xb8\x5c\x5d\x04\x16\x80\x0e\x0b\x7b\xdf\x12\x20\x7a\xaf\x09\x10\xf1\xaa\xca\x77\xdd\xab\xcd\x49\xf4\xda\x3c\x5a\x0b\x23\xe6\x74\xda\x41\x23\xa9\x15\xca\x2d\xb5\xa2\x52\xa8\x7e\x90\xb2\x21\x9f\x07\x4a\xac\xd5\xe9\xd8\xd1\x84\x5c\x1e\x99\x5b\xc9\xd9\x96\xbf\x57\x55\xcf\x28\xba\x74\x32\x5c\x44\xb5\xa6\x38\x32\x65\xb6\x95\x0c\xfb\xd1\x66\xcd\x05\x3f\x58\x19\x92\x5c\x31\xcc\x04\xe7\xf7\xac\x7e\xe9\x86\x90\xeb\xd7\x06\x21\x3d\xa4\xba\xf4\xb2\x02\x48\x8c\x46\x93\x38\x3b\x32\xb3\x16\x1c\xcb\x79\x94\x1f\x46\x8e\xde\x44\x12\xc6\x38\x99\x60\xac\xf7\x26\xcf\xc2\x3e\xfb\xeb\x92\x15\x07\x41\x22\x08\x8d\x63\x9a\x84\xab\xac\x26\x34\x63\xd3\x79\x9c\xd5\xd6\x14\xee\x02\xbf\xc4\x5a\x5c\x49\xeb\x75\x72\x85\x13\xdc\xb1\x84\x33\x2f\x7b\xbd\xe1\x7e\x91\x4b\xa4\x85\xf9\x51\x94\xba\xbc\xe0\xc8\xc7\xb8\xc0\xcd\x0d\xea\x95\x7d\x3f\xd2\x0d\x0a\x9e\x4e\x63\xb4\x36\x33\x5f\xbe\xec\x75\x72\x3f\xd2\xbd\x62\xad\xa9\x77\x37\x93\x76\x7f\x37\xf6\x97\xbd\x1b\xfb\x8f\x75\x13\x51\xcf\xec\x30\x1d\xce\xb7\xde\x9d\xe2\xc8\xfe\xb2\x77\x64\xdf\x2f\x31\xea\xae\x7e\xb4\x85\x46\x2f\x02\x05\x24\x63\xef\xee\xae\x39\x59\x4a\xea\x3d\xe3\x39\x34\x25\xa0\x0f\x86\x7c\x09\xd7\x79\xaa\x63\xa5\x29\x64\x93\x02\x66\xa6\x1e\x1f\x50\x35\xb5\x82\xd7\xdf\x75\xed\x7a\x94\xb5\x40\xb2\xa6\x1f\x42\xed\x7a\xd9\xcd\xde\xbf\xfe\x6f\x05\x14\xa9\x22\x8b\x5b\x38\x70\xab\xcd\x45\xda\x7e\xb9\xb5\x95\x14\x7b\x6d\x53\xad\xbb\xac\xd6\xde\xc4\x9c\x16\xef\x10\x5f\xaa\x35\x67\x20\x37\xd1\x8c\xd4\x1b\x86\x52\x6a\x98\x4f\x00\x2f\x01\x4e\x2d\xc5\xa1\xfa\xf4\x28\xa9\x77\xaa\x2f\x93\xad\xca\x76\x09\xd8\x28\xc3\x79\x6d\x7e\xb1\xd0\x22\xb2\x0a\x78\x01\x25\xe8\x09\xba\xd3\xa4\xb2\x1e\x34\x1c\x41\x16\xa1\x21\x0f\x6c\x50\x96\x28\xe7\x56\x7b\x6b\x75\xcc\x40\xb9\x12\x84\x4c\x6a\x30\x83\xfc\xb3\x90\x23\x9a\x6c\xac\x06\x39\x4f\x53\xfb\x79\x6e\xf9\x4f\x31\xb2\x80\x12\xa2\x76\xc9\xd8\x56\x5a\x08\x9e\x05\x11\x37\xcb\x6d\x33\x3e\x14\x7b\x9d\x54\xc9\xcd\xed\xac\xf2\x69\x6c\x3e\xa1\x34\x25\x6b\xe2\x5b\x0d\xc5\x68\x1e\x54\xf2\xd3\x84\xb0\x50\xa3\x6a\x64\x72\x75\x26\x78\xb0\xf8\x72\xa7\x5d\x2e\x6f\xdb\xe5\xfc\x61\xbb\x9c\xaf\x6a\x97\x2b\x6e\xb5\xcb\xa5\x9d\x5d\x6e\xb5\xca\x15\xb5\xc9\xa9\x1e\xdc\x32\xc2\x4a\xe0\xe9\xa5\xfe\x62\xe4\x14\x21\x20\xcd\xec\x9a\x78\x16\xc5\x0d\x5d\x0b\x35\x39\x45\x75\x56\xc2\x77\x24\xad\x5f\x10\xaa\x00\x46\x6e\x3e\x39\xe0\x56\x1e\xd7\x08\x4b\xf9\x40\x4a\xb6\x1f\x68\xec\x98\xa7\xb4\x1d\x36\xb7\xfd\x6e\x6b\xe9\xdc\x67\x50\x2c\xb5\x59\x2f\xaa\x6b\x75\xe6\x1e\x3b\x45\x04\xf7\x31\x8e\x35\xba\x15\x15\x16\xe1\x98\xbe\x1d\x15\xd6\xf7\x62\x66\x60\xe7\x3a\x9b\x5f\xcd\xee\x48\xf3\xde\xa2\x54\x03\x1d\x69\xdf\x51\x96\xe3\xdd\xf7\x08\xf1\x78\xf7\x07\xca\x94\xe4\x23\xcd\x3b\x95\x69\x28\xf1\x48\xf3\x0e\xfe\x50\x0f\x7b\xb3\x79\xa7\x39\x3a\xde\xbc\xbb\xd8\x1c\xf8\x48\xf3\x4e\x8d\xe0\x4b\x39\xd2\xfc\x80\x07\xcd\x91\x9d\xa1\x0e\x0c\x4e\x28\x73\x76\xa4\xbb\x0e\x4c\xde\xad\xbb\xbe\x46\xd2\x3b\x75\xd7\x43\x99\xcf\x8d\x75\xa4\x58\x0c\xd0\x14\x97\x81\x5c\x89\xad\x82\x93\x3c\x5e\x5d\x50\x8a\xf2\xf2\x58\xd7\xbd\x25\x24\xd6\x75\xaa\xbc\xd7\xb5\xdf\x15\x87\x92\x47\xe9\x3a\xdd\xd5\x75\x07\x2f\xa1\xac\xd8\x30\x19\x72\xae\x2e\x5a\x8b\xab\x56\xa3\x04\x4d\xc8\xbd\x77\x5a\x1c\x61\x04\x55\xcb\x05\x35\x42\xe1\x8a\xdc\xb8\x04\xad\x81\xd0\x8a\xf9\x27\xa4\x58\xa3\x2a\xc8\xf3\x48\x31\x32\x76\xd4\x41\x63\xc8\xcd\x35\x28\x56\x43\x2e\xe6\x49\xd8\x81\x6a\x12\x9c\x02\x10\xdb\xad\xf5\x6a\x17\xaa\x34\x70\xc0\x30\xb4\xa6\xab\xd0\x00\x56\xad\xa9\xa3\x65\x92\x8b\x3b\x8a\xb6\xa8\x03\xef\x48\x6e\xe7\x9a\x64\x39\x44\x19\x3f\x3b\x1d\x3f\xac\xe3\x27\xd4\x4a\x97\xf1\x85\x20\x18\xcb\x5a\x5b\xa8\xd6\x35\x84\xb6\x9e\x3e\x83\x8e\x4e\xec\xea\x55\x21\x25\xc8\xb7\x71\x1e\xbb\x9e\xaf\x2e\x82\x2f\xdf\xf9\x99\xf7\xa5\x10\xd7\x92\x69\xd9\x9b\x9a\xcb\x95\xfc\xff\x58\x67\x7f\x11\xe8\xf1\x3a\x3b\xb2\xa8\x4e\x28\x2f\x6b\xe2\xe2\x47\x05\xa4\x8b\x00\xff\x86\x6f\x1f\x2e\xb9\xc3\x95\xd9\xad\x70\xc9\xce\x64\x4a\x4b\x55\x77\x0c\x07\xd5\x94\xa1\x14\x9a\xaf\x5d\x0a\x6b\x7d\x3f\xd5\x30\x69\x20\x7c\x4b\x71\x8c\xe8\xea\xaa\x5c\xb5\x08\xc2\xeb\xef\x7e\x5e\xfd\xee\x84\x9d\xd5\x47\x79\x6a\x7d\x6f\x73\xb6\xec\xf8\x40\xa6\xa6\xb4\x56\x19\x16\xc9\x79\xe1\xb5\x08\x98\x3c\x58\x86\xf0\xeb\xd5\xf5\x50\x26\x7a\xf0\xbd\xcb\xf1\xe0\x9b\x23\xf3\xe8\x54\x09\x47\x49\xab\xef\x4b\x40\xe5\x76\x0f\x42\x30\x31\xd0\xbb\x96\x32\x65\xe7\x7b\xf4\x96\x57\xaf\x3b\x7a\xdc\xf2\x44\xec\x62\xb7\xfc\xa3\x5c\xd1\xa1\x42\xab\x69\x35\x90\x15\x13\x4a\x5c\x28\xfa\x81\x42\x5a\x28\xca\xe0\x78\x68\x3f\xf8\x49\x8b\x7a\x2a\x63\xeb\x51\x47\xd4\xa3\xd6\x14\x02\x47\x26\x54\x06\x6e\x2a\xd5\xb2\x8b\x71\xf2\xa3\x85\xda\x86\x2b\x6c\x4c\x70\xd6\x87\x40\xa8\xd5\x47\x54\x77\x54\xb5\xce\xa4\x3a\x13\x95\xb8\xf3\x92\x6a\xf9\x45\x20\xd9\x0e\x81\x11\x74\xe2\x07\xdb\x9e\xdc\xed\x9f\xd4\x7f\xcb\xb3\x69\x1f\x3a\x94\x4f\x41\x6f\xb4\x2a\x0a\x04\xc6\x21\x69\xbb\xd4\x26\x61\x46\x9d\x60\x9e\x6c\x84\x13\x99\x2a\x8a\x2d\xa3\x4c\x89\x88\xbf\x5a\x1e\x1c\x27\x92\x5a\x21\xac\x48\xc6\x27\xbf\x14\xec\xd1\xf6\x01\x51\x7f\xa5\x89\x7d\xdd\x59\x03\xc9\x47\x5a\xc8\xc5\xc1\x57\x59\x89\x8b\x83\x88\x97\x8b\x0d\x28\x4e\x1a\xc2\xa2\x0f\x9c\xae\x2e\x62\x88\xa6\x52\x5c\x62\xa0\x81\x62\x1d\x21\x24\xfa\xc4\x43\x1a\x51\xa5\x34\xf1\x40\x31\x2c\x56\xde\x0b\xba\x59\xb8\xa0\x38\x1e\x8d\xd2\x2f\xb2\x44\x0c\x5a\x1a\x99\x9c\xe1\x5a\xd6\x9c\xa2\x5c\x33\xda\x6f\x2f\x22\x1e\x50\xba\xbb\x95\x7f\x91\xab\x2c\x7f\x09\xc7\x85\x4c\xb4\xc5\x81\xe5\xda\x4e\xf2\xf5\xf2\x59\x2f\x2a\xb0\xab\x75\xc7\x82\xb8\x2b\xf9\xb7\x20\x0a\x30\x0e\x94\x68\xd1\xb2\xd6\x54\x18\xa5\x90\x11\x37\x37\x73\x8d\xd0\xad\x4e\xd0\xd3\xa9\x4d\x3c\xee\x6a\x69\x13\x0a\x42\x71\x5c\x6b\xe8\x06\x13\x8c\x45\x59\xe9\x3c\x5b\x90\x5b\x3f\x59\xd5\xc0\x93\x96\xe1\xf5\x75\xad\x3d\x4a\xa4\x95\xb4\x07\x26\xe1\x21\x1d\x92\xc5\xc6\xc5\xa6\xcc\xb7\xea\x0f\xc6\x1c\x6e\x3a\x6f\xf2\x60\x29\xd1\xd5\x45\xae\xe9\xc6\x02\x32\x14\x70\x2e\x68\x54\x97\xf1\x48\x8c\xe1\x71\x91\x34\x57\x7d\x0b\x7d\x81\x9c\x8b\x54\x21\x39\x69\xfc\xd2\x88\x0a\xfb\xec\xdd\x64\xb3\x37\xc8\x5a\xa6\x9e\xda\x61\xd6\x4a\x6e\x86\x78\x02\x5a\xdf\x65\xfd\xb0\x21\xcd\x36\x36\xeb\x68\x5c\x6c\x0e\x43\x8a\xa9\xd9\x2b\x6e\xd4\x1e\x8c\xa5\x74\xf3\xf7\xc2\x89\x1f\x58\x6a\xa9\xfb\xda\x83\xdd\x52\x8f\x9c\x72\xc7\x4f\x33\xe5\xfc\x63\x3a\xe5\xc2\x74\xf2\x02\xcc\x0f\x72\x05\x14\x63\xda\xb7\x5e\x08\x12\xf2\x31\x1e\xff\x9c\x28\xac\xd8\x62\xf8\xd3\xe5\x9b\x57\xe6\x6b\x52\x44\x21\xb8\xee\x6b\x7e\xff\xc9\x5f\x9e\x98\x3f\xbd\xff\xc4\x12\x1d\x6a\x94\x4f\x69\x54\x5a\xa3\x9d\x16\x4d\x9a\x32\xdf\xd1\x14\xb9\x9a\xee\x6e\xf9\xf9\x29\x8d\x3e\xd3\x46\xbe\x1c\x6b\xf4\x69\xeb\xc9\x1d\x6a\xf4\xf2\x7a\x62\x78\xfe\xd3\xfb\x4f\x7c\xdf\xdd\x07\xfb\xbb\x41\xd9\x6f\xbc\x9f\xf5\x3d\xe5\x8d\xf7\xff\xf8\x93\x6f\x7c\x1b\x84\x62\xb7\xa5\xbf\xd8\x35\xca\x6d\x8b\xfa\x8e\x5a\x9b\xff\xa2\xaf\xbb\xbd\xb9\xee\x82\xab\x76\xc1\xe9\x76\x9b\x5f\xee\xda\x40\xfd\x87\x05\xdf\x6e\xf3\xe1\xfe\x7a\xfb\x23\xf8\x8f\xd7\xc3\x28\x8f\x29\x9d\xb8\x70\xac\x19\xc4\x80\x13\x9a\x3d\x3d\xa1\x99\xaa\xf5\x65\x66\xdd\x1e\xee\x37\x62\x6d\x14\xba\x73\xbf\x6e\xf4\xb2\x9d\x06\x1f\x19\xed\xe5\x8b\x13\xda\x3c\xff\xe9\x9d\x5b\x05\xcf\x82\xbb\xda\x3c\x3d\xa1\x4d\x3d\xa1\x4d\xba\x7b\x83\xe0\xde\x78\x57\x9b\x70\x42\x9b\x13\x0e\xe3\x25\xdf\xdd\xe6\xf2\xd9\x09\x6d\x9e\x9e\xd0\xa6\x9e\xd0\xa6\x9c\xd0\x26\x9f\xd0\xa6\xed\xa1\x3f\x02\x1b\x97\xe1\x84\x36\xfe\x84\x36\x7c\x42\x1b\x3a\xa1\x8d\xbb\xbb\xcd\x8b\x72\xf7\xdd\x79\x91\x4e\x68\x13\x4f\x68\x13\x4e\x68\xe3\x4f\x68\x73\xc2\x7d\x7f\x9e\x4f\x68\xb3\x9e\xa9\x3b\xd6\x28\x9c\xd2\xc8\x9f\xd2\x88\x4f\x69\x44\xa7\x34\x72\x77\x35\xfa\xeb\x71\x44\xb6\x1c\x7f\xfd\xf5\x71\xb4\xf3\x66\x83\xde\xb4\xd7\xd3\xf1\xcb\xf4\xfa\xf8\xeb\x2f\x8e\xbf\xbe\x3c\xfe\xfa\xc5\xf1\xd7\xcf\x8f\xbf\x7e\x7a\xfc\xba\x7c\xb2\xc5\x5e\xb4\xf7\xbf\x3b\x0e\x71\x1f\x1d\x7f\xfd\x6b\x9d\x9b\xeb\x58\x92\xf6\xfe\x57\xc7\x3f\xff\xc5\xf1\xd7\x1f\xdc\x0d\x55\x7c\x12\xe1\x7e\xbe\xd9\xe8\x37\xfb\xac\x44\xea\x38\x8d\xdf\xee\xbf\x8e\x1d\x6c\xfd\x4b\x77\x2d\x89\xbb\xad\xf8\x97\xee\x5a\x1e\x6f\xe4\x4f\x69\xc4\xa7\x34\xa2\x53\x1a\xb9\xbb\x1a\x7d\xb0\xf5\xfe\xa3\x13\x58\xb5\x8f\xbb\x36\x5c\x3b\xb6\xf1\xe3\x7d\xfe\xd4\x52\x77\x48\xbf\xeb\x19\x79\x1f\xb7\x1b\xad\x2c\xfc\x66\x9b\xcf\x8f\xbf\x56\xb6\x9d\xba\xf5\xfe\x6e\x9f\x61\xef\xb7\xe3\x77\xfb\x17\xae\xdf\x89\x7f\xed\x17\x41\x3d\x64\xff\x6b\xb7\x8a\xed\x46\x9f\xdf\xf1\x5e\x27\x5a\xb7\x5e\xeb\x44\x63\xf7\xfa\x93\x6b\xbe\xa8\xcd\xb3\x76\x3b\x75\xdd\xe6\xb2\x1d\x6b\xe9\x4e\xed\x93\xee\xe8\xa9\xd4\xed\x46\xcf\x1a\x83\x45\xa1\xc3\xd1\xd7\x8d\x9e\xee\x1a\x75\xdb\xff\xc9\xfe\x55\x0d\x1d\x8c\x7d\xb2\x4f\x06\x52\xb7\xa0\x4f\x3b\xe9\xc6\x52\x37\xd9\x4f\xf7\xfb\xf0\xdd\xc6\x7d\xba\x2f\xfd\xd8\x5e\x3a\xfa\xb4\x13\x7f\x0e\xa0\xe5\xcf\x0e\x4c\xa4\xdb\xda\xcf\x6e\xd0\xb4\x8e\x32\x7c\x76\x73\x22\x1d\xda\xfa\xac\x9f\x48\x7f\x19\x3e\xdf\x97\xa2\x56\xe6\xe5\x48\xab\x15\x58\x52\x37\xdb\xcf\x3b\x60\xe9\x11\xed\xe7\x1d\xb0\xd4\x0e\x0c\x3e\xef\x60\xa5\x97\x52\x3f\xef\x40\xa5\x74\xcb\xff\xfc\x94\xb3\xfe\x7c\x1f\x27\xf5\x5c\xc5\xe7\xfb\x27\xd0\x13\xb0\xf6\xfa\xe5\xf1\x19\xac\x07\xd4\xc1\xf2\xde\xde\x37\x91\x22\x6c\x4d\xf0\x38\x34\xed\x35\xda\x09\xc2\xb7\xdb\xfc\xf1\x86\x34\xdd\x41\xed\x7f\xbe\xc6\x48\xcf\x7f\xba\x81\x19\xf7\xda\x3c\x3b\xa1\xcd\xd3\x13\xda\xd4\x3b\xda\xfc\xfe\xf8\xeb\x5f\x6f\xbc\x7e\xba\x7f\xac\xa5\xdb\x8b\xf6\xfa\x99\x6e\x55\x77\x6e\x2f\xf6\xbf\xee\x01\xfd\xe5\x01\x1d\xc0\x91\x46\x3b\x91\xf2\x58\x9b\xa7\x27\xb4\xa9\x27\xb4\x29\x27\xb4\xc9\x77\xb7\x39\x72\x63\x5e\xde\xe0\xa4\xb7\xfa\xf8\xe2\xf8\xeb\xcb\xe3\xaf\x5f\x1c\x7f\xfd\xfc\xf8\xeb\xcd\xfb\xf6\xb2\xbf\x4b\x3d\x5d\xfc\xd3\x81\xd3\x3d\xd2\x68\x77\xba\xc7\xda\x3c\x3d\xa1\x4d\x3d\xa1\x4d\x39\xa1\x4d\xbe\xa3\xcd\x74\xfc\xf5\x17\xc7\x5f\x5f\x1e\x7f\xfd\xe2\xf8\xeb\xe7\x1b\xaf\xc7\x6b\xf2\x92\xb6\xa6\xbf\xd7\x26\x9e\xd0\x26\x9c\xd0\x66\xf3\x78\xf7\xda\xf0\x1d\x6d\x5e\x6f\xbc\x7e\xb3\x8f\x6e\x0f\x70\x09\x6f\x6e\x30\xc3\x3d\x2c\xbf\xd9\x27\x2d\x07\x50\xfe\xdc\x6d\x59\x8f\xf2\xe7\x6e\xcb\x8e\xb6\x09\x27\xb4\xf1\x27\xb4\xe1\x3b\xda\xbc\xde\x78\xbd\xdc\x58\x32\x75\xcc\xc3\x5f\xf6\x59\x95\x95\xd7\xec\x77\x6e\xbf\xd9\xaa\xf0\xbd\xab\xd9\xd3\x53\x9a\x9d\xd4\xd7\xf3\xcd\x46\x7f\xbd\x63\x79\x82\x76\x9f\xfd\xb4\x23\xc3\x07\x2d\x06\x37\x1a\x6e\x62\xa0\xdb\x0d\x37\xd1\xd0\xed\x86\x9b\xb8\x68\xbf\xe1\xef\x4f\x68\xf3\xeb\xed\x36\x90\x48\xbf\x3e\x66\xcf\xd8\x6f\xb4\x69\xd4\xd8\x6f\x74\xdc\xb2\xb1\x8a\xca\x77\x8e\x49\xa7\x8c\x49\x27\x8f\xc9\xa7\x8c\xc9\xa7\x8c\xc9\x27\x8f\xe9\x4f\x19\xd3\x9f\x32\xa6\x3f\x79\xcc\x70\xca\x98\xe1\x94\x31\xc3\xc9\x63\xc6\x53\xc6\x8c\xa7\x8c\x19\x4f\x1e\x33\xff\xb4\x63\x93\x0e\x77\xb9\x36\xdc\xb2\x93\xdd\xea\x6c\xdb\x58\xb6\x96\x6c\xff\xfa\x88\x35\x6c\x2d\x85\x7e\x57\x9b\xa7\x27\xb4\x79\x76\x77\x9b\x17\x7b\x77\x6e\x5b\x2d\xb4\x2a\xc4\x4f\x6a\xe8\x4f\x6d\x18\x4e\x6d\x18\x4f\x6d\x98\x4e\x6d\xf8\xe2\xa7\x27\x89\xcb\xb7\x9a\x6e\xcb\xcc\xb7\x1a\x6e\x0b\xce\xb7\x1a\x6e\x4b\xcf\xb7\x1a\x6e\x8b\xd0\xb7\x1a\x6e\xcb\xd1\xb7\x1a\x1e\x11\x0d\xf6\x5b\x6e\x49\xd4\xfb\x6d\xb6\xc4\xea\xfd\x36\x5b\xb2\xf5\x7e\x9b\x4d\x86\xff\xf6\x91\x6d\x4a\xd9\xb7\x1b\x6e\x8b\xda\xb7\x5b\x6e\x32\x5f\xab\x91\xeb\x98\x1c\xba\xdf\x66\x4b\x18\x5d\x0d\x6a\x77\xf5\x43\x27\xf4\xc3\x27\xf4\xc3\x27\xf4\xe3\x4f\xe8\xc7\x9f\xd0\x4f\x38\xa1\x9f\x70\x42\x3f\xf1\x84\x7e\xe2\xdd\xfd\xbc\xbc\x09\x74\x87\x79\xb4\x97\x2f\x4f\x68\xa4\xba\xdf\xd3\x30\xc5\x8d\xb6\x47\x51\xc5\x8d\x96\x47\x71\xc5\x8d\x96\x47\x91\xc5\x8d\x96\x47\xb1\xc5\x8d\x96\x47\xd1\xc5\x8d\x96\xc7\xf1\xc5\x75\xd3\x23\x08\xe3\xba\xd1\x11\x8c\x71\xdd\xe8\x08\xca\xb8\x6e\x74\x0c\x67\xdc\x3c\xbd\x63\x48\xe3\x66\xcb\xa3\x58\xe3\x66\xd3\x63\x68\xa3\x05\x81\x7c\x7d\x97\xe7\x93\x86\x67\x9c\xd0\xec\xf9\x69\xcd\x5e\x1c\x6b\xf6\x05\xbd\xff\xe4\x9f\x9f\x98\x7f\xf7\x85\x5a\x1c\xfe\x5d\xa7\x80\xd9\x6f\xf0\xf9\xd9\xe7\x4f\x9f\x7f\x3d\x5f\x9e\x7d\xfe\xe2\xcb\xcb\x37\x97\x6f\xbf\x7c\xab\x5f\xc4\xb8\xf5\xc5\x27\xad\xcb\x7c\xbb\xc1\x2f\xcf\x3e\x3a\xfb\x70\x1e\xce\x3e\xfa\xe2\xcd\xd3\xe5\xf2\xec\x23\xed\xf7\xa3\xe7\x5f\xbe\x79\xfe\xf5\x9f\x5f\x8e\x97\xdf\x9c\x7d\x34\x7f\x39\xbe\xb8\x3c\xfb\x68\x6f\xa8\xfd\x49\xf2\xa3\xf5\xb8\xb5\xaa\xe0\x1f\x6d\x88\xc7\xdf\x86\x0f\xce\x3e\xd0\x4f\x3e\xd0\x4f\x3e\xd8\xfb\xe4\x03\xfd\xe4\x83\xf5\x93\xb3\x0f\xde\x7c\xf9\xea\x0b\x9d\x42\x72\x8f\x36\x85\x3f\xb6\x45\x3d\xde\x36\xfd\x41\x7b\xf4\x8f\x37\xc7\xe7\xaf\xff\xfc\xe7\xa7\x67\x5f\x5d\xbe\xf9\xf2\xf5\x8b\xb3\xe9\xeb\xd7\xf3\xe5\xdb\x2f\x5f\x7d\x31\x3e\x7b\xfa\xf6\x52\xff\x7c\xf1\x4c\xff\xb8\x1c\xc7\x2f\xbf\xda\x1d\x3d\xf5\xe0\xf5\x8b\xb3\x5f\x3c\xbf\x7c\xf1\xe5\x38\x3e\xbd\x75\xa6\xf5\x76\xcb\x0f\xcf\x3e\xd4\x69\x7e\xa8\xd3\xfc\x70\x6f\x9a\x1f\xde\x9a\xdf\xeb\xb3\xd7\xda\xf6\xb5\xb6\x7d\xbd\xd7\xf6\xb5\x2e\xe9\xf5\x4d\xa8\xa4\x77\x1a\x6f\x39\xfb\xeb\xd9\x5f\xb5\xd9\x5f\x6f\xf6\x7b\x53\x3c\xb9\x6f\xbf\x6d\x33\x6e\xa1\xc8\xfb\xf6\xf2\xf5\xd9\xd7\xda\xf6\x6b\x6d\xfb\xf5\x5e\xdb\xaf\x6f\x6d\x43\x77\x95\xee\x33\xd0\xf3\xb3\x17\x67\x97\x67\x5f\x9c\x4d\x67\xcf\xdb\xa1\x9e\x5d\xea\xc7\x97\xfa\xf1\xe5\xde\xc7\x97\xbb\x7b\xf4\xfa\x72\xeb\x0c\x3e\x79\xf0\x79\xe6\xcd\xbe\xb6\xcf\xaa\x74\xd0\xb9\x7e\xf3\x8b\xb3\x5f\x9d\x7d\x74\xf6\xbb\x1d\xac\xde\xe3\xc6\x9c\x7d\xf4\x76\x7c\xfa\x76\x38\xfb\xe8\xc3\x06\x10\x65\x6b\x90\x86\x82\x2d\x75\x20\xf3\xc9\x1d\x28\xf5\xc8\x27\x9f\xdc\xd9\xe2\x1e\xd0\x91\x3a\x82\xb4\x76\xf2\xd9\x3a\xcc\x66\x8b\x87\x62\x56\x2a\x1d\xec\x7f\xf2\x6e\x58\x88\xe3\xe6\x11\xbc\x23\x00\x97\x4d\xa0\xbb\xda\x22\x13\x6b\x83\x6f\x1a\xd8\x76\xf7\x6f\x6d\xf0\xe7\xb3\x57\x67\x5f\x9d\xbd\xc2\x4e\xdd\x35\xda\x7a\x07\x36\xcf\x7c\xf8\xeb\x57\xc3\xe5\xab\xb3\xaf\x5f\x7d\xe9\xdc\x07\xbf\x3c\xbb\x7c\xf5\x42\x40\xf4\xf2\xcf\xf2\xdf\x4a\x53\x37\x2f\xc3\xbf\xb5\x83\xd9\xec\xfd\xe9\xd9\x53\xdd\xb4\xa7\xba\x69\x4f\xf7\x36\xed\xa9\x1e\xf5\xd3\xdd\xde\x3d\xbd\x3e\xea\xd2\x91\xbc\xb5\xc7\x5f\xaf\x08\xa2\x1b\xf3\x37\x0f\xc6\x10\x3d\xd7\xf0\x9b\x3b\x31\x44\xe8\xce\xef\x37\x8f\x8f\x21\x76\x31\xe9\xfd\x28\xf7\xb8\xab\x3d\xff\xf0\x9b\xc7\x01\xf2\x9e\xa2\xfd\xe6\x74\xa8\xf2\x1d\x13\xfc\xdb\x3b\x37\x9d\xfa\xa5\xfc\xf6\x5b\xc0\xcb\x1d\xe6\xfa\xed\x2d\xd6\x38\x6d\xce\xfd\xf7\x67\xbf\xd7\x71\x7f\xaf\xe3\xfe\x7e\x6f\xdc\xdf\xdf\xa2\x4b\x9b\x9d\x6c\x21\x77\xee\x49\xd9\xfa\xc9\x8a\xe4\xf6\x90\x5f\xc3\x7c\xe3\xe5\xcb\x59\x9f\xde\x7c\xf9\xc5\x30\xef\xd0\xe1\xf5\xef\x2f\x9e\x8d\x78\xb5\xf2\x86\x1d\x4e\xfc\xed\x2d\x86\xcc\x6d\x6e\xd0\x7d\xf8\x8b\xcd\xe5\x37\x0a\x52\xbb\xb3\xfe\xf8\xe1\x3c\xdd\x66\x5f\xdb\xc0\x76\x80\x82\x7d\xfc\x8e\x14\x8c\x7d\x77\x63\x3e\xbe\xc9\xeb\x6f\x37\x68\xac\x7b\xec\x84\xcb\x8f\xdf\x8d\x06\x06\xd7\x1d\xc4\xc7\x8f\xc4\xc4\x6d\x6e\xfa\x43\xc9\x42\x2f\x59\x7f\x7c\x8b\x2c\x94\x6e\x31\xbf\x3e\x3b\xf5\x4e\xbe\x13\x6f\xe2\x3a\x7a\xf0\xe9\x83\xa1\x35\x74\x40\xf0\xe9\xdd\xa8\xb1\xdb\x9a\x4f\xbf\x05\x7a\xd4\x9d\xe8\xa7\x0f\x20\x47\x1d\x7e\xf9\xf4\x5d\xaf\x55\x2f\x14\x7d\xfa\x8e\x8c\x61\x7f\xf7\x3f\x7d\x9c\x4b\x11\x3a\x00\xfd\xf4\x64\x9a\x49\xb1\x63\x07\x3e\x7d\xc7\x1b\xb5\x0d\x6a\xbf\x5e\x77\xa2\x3b\xf3\x3f\x3c\x9c\xd1\xea\x80\xf4\x0f\x77\x02\xb6\xdf\xfc\xe6\x11\x01\xbb\x57\x88\xfc\xe1\xb6\x28\xd6\x9d\xdb\x1f\x1e\x00\xfa\x9b\x6b\x79\x74\x4e\xec\x0f\xa7\x43\x55\xcf\x4a\x1f\x64\x40\x1e\x76\xe4\xbd\xa0\xb8\xd9\xf9\x11\xd5\x49\x77\x3c\x9b\x9d\x3c\x26\x1f\xd8\x71\x5b\x9b\xa3\xee\xa0\xa4\xc3\x6d\x9b\x9f\x6c\x4b\xf0\xa7\xf7\xb1\x13\xe9\x3b\xbc\xb0\xf9\xc9\x3d\xa0\xd5\x9f\xbe\xfe\xcf\xee\x3f\x91\x07\x23\xfb\x78\x3a\xb8\xfe\x61\x9d\x56\x87\xc3\x36\x3f\x79\x28\xc1\xe8\xd1\xd4\xf6\x10\xef\x76\xd7\xef\x71\xa3\xae\xb6\xb0\xdb\xe6\x17\xdf\x6c\x89\x8c\x9b\x5f\x1c\xd0\x46\x9c\x3e\xdc\x6a\xde\x38\x1d\xe4\x4f\x90\x2c\xa9\xd3\x57\x6c\xf6\xb6\xa9\xc0\xd8\xfc\xe2\xa1\x84\x36\x9d\xbe\xa3\x2b\xe5\x2d\xdd\xac\x3e\x7b\x30\x1a\xee\xc1\xf3\xb3\xdb\x38\xa4\x23\x70\x9f\x3d\x40\xa8\xeb\x50\xc6\x67\xef\xca\x58\xe7\xcd\x99\x3f\xd4\xf4\xd0\x9b\x9d\x3e\x7b\x9c\x9b\xb9\xbd\xc9\x27\x50\xe1\x5e\x80\xf8\xec\x1d\x41\xce\x6f\xae\x73\x95\x96\x42\x77\x5c\x7f\x7c\x44\xde\xee\x8f\x77\xd3\xf5\x8e\x5c\xfc\xf1\x5b\x20\xe3\xdd\x35\xfa\xe3\x63\x00\xf6\x1f\x1f\x89\x73\xeb\xb6\xed\x41\xc7\x7d\x87\x70\xd8\x91\x8c\x07\x0f\xf2\x78\x8a\xa6\x5e\xc1\xfd\xe0\x49\xdd\x87\xa9\xe9\x88\xc3\xf3\xdd\xc1\x3d\xfe\x12\xbb\xc3\x7d\x76\xf6\xd5\xd9\x3c\xbc\x7e\xf3\xea\x01\x02\xfd\xed\x6f\x1f\x6f\x9e\xbd\xfd\xe0\xf6\x58\x57\x5b\x80\x74\xbb\xe1\x37\xa7\x36\x1c\xce\xfe\x74\x36\x6e\xb1\xf7\x97\xa7\xdc\xa1\xbb\xb7\xb0\x43\x80\xf7\xe9\xf7\x11\xc1\xa0\x23\xad\xc3\x99\xb0\x4d\x3b\xa6\xe9\x81\x4a\xcd\x6e\xdb\x0e\x74\xfb\x78\xab\xa0\xd4\x21\xd2\x03\xe3\xbd\xab\xce\xb0\x5b\xd3\x3d\xf7\xe5\xbe\x88\xf0\x01\xdd\x3f\xe2\x96\xf6\x90\xff\x80\xf9\x5c\x6d\x31\xb1\x0f\xe8\xeb\x9b\x2d\xaa\xf4\x80\xbe\x8e\xde\xf0\x8d\x33\x7a\xe0\x4d\xe8\x8e\xf5\x48\xf7\x8f\x77\x7c\xf6\x3e\xc3\x3e\x94\x5b\x4d\x1d\x99\x3c\x36\xc8\x63\x6b\xec\x8f\x8c\xf5\x60\x25\x7e\xb7\x6b\x6f\x1e\xce\x74\x76\x70\xf5\xe6\x04\xbb\x4e\x27\x6d\xbe\x79\x7c\xd0\xe8\x2e\xe3\x9b\x77\x84\x83\xdc\x9d\xcd\x9b\x6f\xcb\xd7\xe6\xcd\x3b\x9e\xf0\xf6\xa9\xec\xa1\x84\xd8\x35\x3a\x95\x8b\x3b\x7e\xbc\xbd\x7a\xe8\x9b\x87\x1b\x62\xba\x39\x7e\xf3\x48\x5c\x7f\xd7\xf1\xd5\xc3\x91\x5f\xb7\xe0\xab\x47\x02\x8c\xae\xe3\x47\xba\x1f\x0f\x5d\x67\x47\x94\x1e\x71\x3e\x8f\x77\xf5\x6b\x87\xb0\x1f\x71\x9a\x0f\x56\xa3\xf4\x10\xf7\x88\xb3\x7a\x47\x40\x8b\x1d\x06\x7a\xc4\xb9\xf5\xfa\xc9\x6f\x75\x2b\x1a\xb0\xd6\x4e\xcc\x7c\xc4\x31\x1e\x8a\x97\x7b\x94\xfb\x10\x62\xf4\xb8\xb7\x85\xd7\x5c\xda\xef\xbd\x7c\xfd\x6a\x96\xff\x5f\x5c\xbe\x7c\xfb\xf3\x9f\xbd\xf7\x76\xf9\xe2\xe7\xe6\xff\x0f\x00\x00\xff\xff\x83\x14\xd5\x4b\x29\x3a\x01\x00") func fontsRobotoslabBoldWebfontSvgBytes() ([]byte, error) { return bindataRead( _fontsRobotoslabBoldWebfontSvg, "fonts/robotoslab-bold-webfont.svg", ) } func fontsRobotoslabBoldWebfontSvg() (*asset, error) { bytes, err := fontsRobotoslabBoldWebfontSvgBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "fonts/robotoslab-bold-webfont.svg", size: 80425, mode: os.FileMode(509), modTime: time.Unix(1492020681, 0)} a := &asset{bytes: bytes, info: info} return a, nil } var _fontsRobotoslabBoldWebfontTtf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xa4\x7d\x09\x78\x13\xd5\xf6\xf8\xb9\xb3\x65\x6f\x33\x59\xdb\xa6\x4d\x93\xa6\x1b\x4c\x4b\x68\xd2\x85\xb0\x96\x5d\xf6\x4d\xa0\x65\x93\x45\x10\x45\x10\x14\x11\x71\x43\x41\x44\x44\x45\x1f\x88\x4a\x11\xf1\x09\x82\x88\xdc\x49\x03\xee\x82\x0a\x8a\x3b\x2e\xaf\xe0\x06\x88\xa2\x84\xa2\xe2\xfa\xde\x13\x3a\xf3\xff\xee\x9d\x49\x69\x4b\x7d\xef\xfd\xbe\x3f\xfd\x4e\x32\xc9\x4c\x66\xee\xd9\x97\x7b\xee\x05\x10\x00\x38\x11\x00\x07\x9d\x07\x0c\xb8\x74\xd8\xd4\x9d\x23\xdf\x03\x40\xdd\x01\x20\x7b\x60\xbf\xfe\x03\x98\x7f\xa1\x23\x00\xa8\x06\x00\x4a\x06\x8e\x1c\x31\xe6\xe8\x76\x7f\x67\x00\xb4\x1c\xc0\xf3\xe9\xc0\x31\x63\xfb\xc4\xfb\xef\x7e\x08\x20\x83\x9c\xaf\x19\x31\x26\x1c\x79\xf1\x9a\x82\xd5\x00\x19\x18\x00\xa6\xce\x98\x3b\x6d\xfe\x90\xa1\x4f\x1e\x02\xc8\xb4\x03\xa0\x5f\x66\x2c\x5a\x18\x48\xdf\xeb\x18\x02\xe0\xe3\x00\xa0\xf3\xac\xf9\x57\xcc\x1d\x93\x08\x3f\x05\xe0\x2b\x07\x60\x66\x5e\x31\xed\xba\xf9\x00\x60\x07\xc8\xa9\x03\x00\xe3\x15\x57\xdf\x38\xeb\x91\x2f\x97\x56\x01\xe4\x3c\x09\xf0\x14\x9e\x3d\x73\xda\xe5\xc2\xa4\xe5\xd3\x00\x0e\x5c\x0a\x00\x95\xb3\x67\xcf\x9c\x66\xbf\x4f\x78\x1a\xe0\xc0\x6a\x00\xc8\x9f\x3d\x77\xe1\xe2\x5f\xc7\x55\xf4\x06\x38\x80\x01\x58\x7c\xf5\x35\x33\xa6\x45\x3f\x32\x4f\x00\x78\x7b\x2a\x00\xfa\x7c\xee\xb4\xc5\xf3\x19\x13\x8a\x03\xbc\x4b\xf0\x0b\xcc\x9b\x36\x77\xe6\x0c\xf1\xbe\x49\x00\xef\x4e\x02\xe0\x1c\xf3\xaf\xb9\x6e\x61\xad\x78\xab\x0a\xf0\xe1\x7c\x00\xe6\xdf\xf3\xaf\x9d\x39\xff\xca\x1f\xbe\x9c\x02\xf0\xf1\xd5\x00\xf0\xc2\x0d\x33\xa7\xcf\x3a\x33\x62\x4c\x2d\xc0\x27\xc5\x00\x20\x00\x50\xea\xc1\x7b\x3d\x9e\xf8\x90\xbc\xef\x3f\x2b\x76\x22\xef\x1f\xde\x56\xf7\x01\x3d\x93\x46\x46\x45\xbe\x01\x06\x58\x40\xf0\x3d\x20\x38\x05\x49\x60\xe0\x34\x34\x02\x02\x8e\x9e\xd1\xee\x62\x06\x3f\x94\x00\xea\x37\x60\xe8\xa5\x60\xa4\x67\x40\x55\xe9\x19\x34\x67\xe6\xb5\xf3\xc0\xa8\x5f\x47\x7e\x45\x7e\xc3\x41\x1a\x3b\xd2\xb4\xc8\x72\x09\x20\xe6\x03\x7a\x7d\x17\x58\x02\x4b\x60\x29\xac\x80\xb5\xf0\x04\x6c\x83\x67\xd1\xe3\x68\x2b\x7a\x06\x9e\x40\xef\xa0\x4f\xd1\x8f\x8c\x95\xf1\x33\x9d\x99\xab\x98\xf9\xcc\x12\x66\x29\xf3\x22\x73\x90\x39\x08\x2b\x5a\xfc\xad\x85\x6d\xfa\xdf\x13\x17\xfe\x98\xce\xcc\xfc\x16\x7f\x07\x99\x83\x4c\x67\xfa\x1c\xf2\x87\x60\x12\x58\x00\x81\x4b\x79\x16\x58\xc8\x57\xaf\x84\x5a\xf5\x1e\x98\xa4\x8e\x01\x16\xd2\xd4\xef\xa0\x8f\xfa\x1b\x4c\x57\x7f\x02\x04\xab\xd4\x63\xe4\x6a\xf5\x34\x74\x07\x51\x39\x04\x4e\xe5\x10\x14\x2a\x9f\x42\xb1\x7a\x04\x4a\xd4\x23\x10\x56\x3b\x43\xb9\x7a\x04\x2a\xd5\x23\x10\x03\x17\x0c\x50\x8f\xc2\x25\x6a\x23\x0c\x52\x1b\x61\xb0\xda\x08\x43\xd5\x46\xb8\x54\x6d\x84\x71\x6a\x23\x8c\x57\xbf\x83\x09\xea\x69\x98\xa8\x9e\x82\x29\xea\x29\x58\xae\x7c\x0a\x77\x2a\x9f\xc2\x0a\xe5\x53\xb8\x4b\xf9\x14\x56\x2a\x9f\xc2\xdd\xca\xa7\x70\x8f\x7a\x04\x1e\x52\x8f\xc0\x7a\xf5\x08\x3c\xac\x1e\x81\x47\xd4\x23\xf0\xa8\x7a\x04\xea\xd4\x23\xf0\xa4\x7a\x14\xb6\xa8\x47\x61\xab\x7a\x14\x9e\x52\x8f\xc2\x36\xf5\x28\x6c\x57\x8f\xc2\x0e\xb5\x11\x9e\x51\x1b\x61\xa7\xda\x08\xcf\xaa\x8d\xb0\x4b\x6d\x84\x3d\x6a\x23\x3c\xa7\x36\xc2\xf3\x6a\x23\xbc\xa0\x36\xc2\x8b\x6a\x23\xbc\xa2\x9e\x86\x57\xd5\xd3\xb0\x57\x3d\x0d\xfb\xd4\xd3\xf0\x9a\x7a\x0a\xde\x50\x4f\xc1\x7e\xf5\x08\x1c\x50\x1b\xe1\x0b\xe5\x10\x1c\x55\x0e\xc1\x71\xe5\x10\xc5\xfb\x35\xfa\xfa\x1e\x18\xa0\x50\x5d\x0a\xcb\xd5\xa5\x70\xa7\xba\x14\x56\xa8\x4b\xe1\x2e\x75\x29\xac\x54\x97\xc2\xdd\xea\x52\x60\xa0\x16\xd2\x60\x95\x72\x18\x04\x88\xa9\xc7\xa0\x9b\xfa\x2d\x74\x57\x7f\x84\x9e\xea\x57\xb0\x59\xfd\x0a\xde\x54\xbf\x02\x03\x8c\x57\xf7\xc2\x24\xf5\x23\xb8\x46\xbd\x1a\x6e\x53\xe7\xc1\x2a\xb5\x2f\x3c\xad\x3e\x03\x2f\xab\x9b\x89\x54\x80\x0b\xfa\x80\x08\xe3\xd5\x13\x30\x1d\x9c\xf4\x9b\x10\xf4\x01\x2b\x8c\x57\x1b\x61\x3a\xa4\x41\x1a\x58\xd4\x13\xf4\xba\x74\xf5\x43\xe8\x03\x0e\x18\xa2\x3e\x0b\xe3\xd5\x23\x50\xab\x9e\xa6\xbf\xb9\x46\x7d\x16\x6e\x53\xdf\x87\x55\xea\xe3\xf0\xb4\xfa\x1a\xbc\xac\xee\x83\x63\xea\x27\x14\x87\x93\xc0\xc0\x40\xf5\x38\xd4\xaa\x18\x10\xd4\xaa\xfb\xe8\x1d\x23\xf4\x3e\x97\xa8\xa7\x60\x90\x7a\x0a\x06\xab\xa7\x60\xa8\x7a\x0a\xc6\xa9\xa7\xe8\xfd\x76\xa8\xa7\xe0\x19\xf5\x14\xec\x54\x4f\xc1\xb3\xea\x29\xd8\xa5\x9e\x82\x03\xea\x29\x60\x61\x08\xb8\xa0\x16\x32\x60\x12\x88\x80\x60\x08\xd8\x00\x41\x17\x30\x80\x15\x5c\x50\x08\xc5\xd0\x01\x3a\x82\x04\x9d\xa1\x0c\xa2\x50\x0e\x15\x50\x09\x31\xe8\x06\xdd\xa1\x27\xf4\x82\x01\x30\x08\x86\xc0\x78\x98\x08\x53\x60\x39\xdc\x09\x2b\xe0\x2e\x58\x09\x77\xc3\x3d\xb0\x1a\xee\x85\xfb\xe0\x7e\x58\x0b\x0f\xc1\x7a\x78\x18\x1e\x81\x47\x61\x33\x3c\x09\x5b\x60\x2b\x3c\x05\xdb\x60\x3b\xbc\x06\x6f\xc0\x9b\xf0\x19\x7c\x0e\x5f\xc2\x57\x80\x04\x0f\xd5\x20\x01\x3c\x50\xc2\x1d\xe5\xaf\xe6\xbf\xe3\xcf\x03\x0f\xdd\xc0\x05\xdd\xa1\x10\x7a\x82\x07\x36\x83\x07\xde\x04\x0f\x2a\xa1\xf2\xdb\x16\x9c\xed\x00\x91\xef\xb6\x40\xe4\xbd\x2d\x94\xb4\x03\x44\x1f\xda\x02\xd1\x8f\xb6\x50\xd9\x0e\x10\xfd\x69\x0b\x44\x9f\xda\x02\xd1\xaf\xb6\x30\xa8\x1d\x18\xdc\x0e\x0c\x6d\x07\x2e\x6d\x07\xc6\xb5\x03\x44\x7f\xdb\x02\xd1\xe7\xb6\x40\xf4\xbb\x2d\x4c\x69\x07\x88\xfe\xb7\x85\x3b\xdb\x81\x15\xed\xc0\x5d\xed\xc0\xca\x76\xe0\xee\x76\x80\xd8\x97\xb6\xf0\x50\x3b\xb0\xbe\x1d\x78\xb8\x1d\x78\xa4\x1d\x78\xb4\x1d\xa8\x6b\x07\x88\x3d\x6b\x0b\x5b\xda\x81\xad\xed\xc0\x53\xed\xc0\xb6\x76\x60\x7b\x3b\x40\xec\x65\x5b\x78\xa6\x1d\xd8\xd9\x0e\x3c\xdb\x0e\xec\x6a\x07\xf6\xb4\x03\xcf\xb5\x03\xcf\xb7\x03\x2f\xb4\x03\x2f\xb6\x03\xc4\x9e\xb7\x85\x57\xdb\x81\xbd\xed\xc0\xbe\x76\x80\xf8\x83\xb6\xf0\x46\x3b\x40\xfc\x45\x5b\x20\xfe\xa3\x2d\x10\x7f\xd2\x16\x8e\xb6\x03\xc7\xdb\x81\x10\xf5\x39\x6d\x61\x79\x3b\x70\x67\x3b\xb0\xa2\x1d\xb8\xab\x1d\x58\xd9\x0e\xdc\xdd\x0e\xf8\xa9\x67\x6b\x0b\xc4\xd3\xb5\x05\xe2\xf9\xda\x02\xf1\x84\x6d\x61\x73\x3b\xf0\x66\x3b\xc0\x43\x4c\xfd\x00\xba\xa9\x5b\xa1\xa7\x5a\x07\x9b\xd5\x3a\x78\x53\xad\x03\x01\xc2\xea\x8f\xd0\x55\xfd\x11\x36\xaa\x3f\xc2\x63\xea\x8f\xb0\x49\xfd\x11\x1e\x57\x7f\x04\x04\x02\xd8\x40\x82\x28\x54\x42\x15\x54\x03\x42\xaf\xa7\xbc\x04\xea\x8c\xa6\xa0\xc5\xe8\x41\xb4\x0d\x06\x50\xef\xd7\x16\x88\x37\x6c\x0b\xc4\x3b\xb6\x85\x41\xed\xc0\xe0\x76\x60\x68\x3b\x30\xae\x1d\x20\xde\xb6\x2d\x10\xef\xdb\x16\x9e\x69\x07\x76\xb6\x03\xcf\xb6\x03\xbb\xda\x81\x03\xed\x80\x05\x2e\x51\xcf\xc0\x20\xf5\x0c\x0c\x56\xcf\xc0\x50\xf5\x0c\x8c\x53\xcf\xc0\x0e\xf5\x0c\x3c\xa3\x9e\x81\x9d\xea\x19\x78\x56\x3d\x03\xbb\xd4\x33\x70\x40\x3d\x03\x02\x5c\xaa\x9e\x81\x3d\xea\x19\x78\x4e\x3d\x03\xcf\xab\x67\xe0\x05\xf5\x0c\xbc\xa8\x9f\x39\x01\x7b\xd4\x13\xf0\x9c\x7a\x02\x9e\x57\x4f\xc0\x0b\xea\x09\x78\x51\x3d\x01\x3c\x88\xea\x72\x70\xaa\xcb\xe1\x0b\x75\x39\x1c\x55\x97\xc3\x71\x75\x39\xe5\xe8\x19\xe8\xaa\x9e\x81\x8d\xea\x19\x78\x4c\x3d\x03\x9b\xd4\x33\xf0\xb8\x7a\x86\x72\x74\x08\x8c\x84\x51\x50\x0b\x93\x60\x2a\x30\xe6\x83\x84\xa3\x46\xa3\x69\x1e\xe4\x81\x1f\x00\x44\xf5\x98\xfa\x9b\xda\x47\xdd\xaf\x76\x51\xf7\xab\xa0\x9c\x52\xaf\x52\x1f\x50\xfe\xa9\x5e\xad\xfe\x06\xff\xf3\x3f\xf5\x14\x80\xfa\x36\x80\x7a\xb2\xf9\x9b\x5f\xff\xcb\x4f\xc4\x0b\xd7\xb6\xb8\xcf\xb7\xe4\xcc\x7f\x7d\xda\xd7\xcd\x47\xa7\x01\xd4\x7f\xb4\x7c\x2e\x80\xba\x5f\x4d\xaa\x27\xd4\x15\xff\xf3\xd8\xbf\xf9\x5f\xaf\xa4\x57\xff\xa0\x7e\xd7\xe2\xa3\x4b\xfd\xe9\xe2\x2b\xda\xfd\xdd\xbb\xea\xcd\xaa\xac\x3e\xab\x7e\x4b\xb2\x3d\x0d\xd4\xbd\x00\x90\xae\xde\x0a\xa0\x0e\x25\xd7\x28\x8a\xfa\x94\xba\x5f\xad\x57\x9f\x52\x13\xca\x59\xf5\xac\xba\x53\xed\x4e\x7f\xfb\xa0\x6a\x55\x67\xa9\xd3\xd4\x57\xc0\x00\xa0\x01\xf9\x15\xf0\x6a\x3a\x80\x1a\xa5\xbf\xad\x54\xc7\xaa\x2b\xd4\xab\x00\xd4\x39\x8a\x5f\xfd\x48\xbd\xac\xc5\xb3\xcf\xb4\x3b\xa2\x23\x2d\x8e\x3f\xf8\x0b\x6c\xff\xae\x9e\x54\x8f\xa8\xeb\x5a\x7c\x93\xbc\xe8\x9a\x66\x7a\xa8\x9e\x8b\xce\xdd\xa9\x7e\xaf\xfc\x4b\xdd\xa3\x24\x95\xf7\xd4\xa8\xfa\x0b\xb9\x63\xfb\x4f\x6a\xf5\xab\x6b\xa8\xfc\xa4\xb7\x73\xe6\x29\x00\xd5\xa5\x7e\xa9\xbe\xaf\x5c\xdd\x5a\xc2\xd4\xdf\xd5\x4b\xfe\x87\x3b\xd7\xfd\xd7\x2b\x3e\x56\x7f\x6f\x79\x67\x2a\x91\xda\x11\xcd\x6b\xd5\x0e\xea\xa7\xcd\xdf\xcc\xa0\xd7\x4b\xf4\x83\xa8\x7e\xa4\x36\xaa\x5f\xd3\x3c\x23\x75\xbe\x51\x3b\xd3\xe2\x6e\x17\x68\xd5\xbd\xcd\x73\xf7\xaa\x67\xd4\x6f\xc0\x01\x40\x41\x54\x3f\x4b\xfd\x52\x25\x2f\x36\x35\x53\xdd\xab\x9e\x50\x93\x2a\x56\xdf\x54\x4b\xd4\xb3\xea\x6b\xca\x89\xe6\xdf\x7e\xdd\xea\x56\x69\x17\x24\x50\x1d\x4b\x5f\x17\xb4\xd0\x98\x3a\x00\xf5\x98\x3a\xe7\xc2\x18\xd5\x93\x2d\x25\xfa\x62\xe9\xd5\xb1\x68\xfb\xed\x3b\x6a\x52\x7d\xa5\x59\x1e\x52\xe3\x26\x67\x5e\x02\x50\xbe\x22\x47\xca\x5c\xb5\x3f\xfd\xe6\x51\xf5\x63\xa5\x09\x40\xdd\xd5\xea\x0e\x3f\x37\x1f\xd5\x03\xa8\xc7\xdb\x7b\xca\x7f\xff\xa7\xbe\xf0\x7f\xfe\xc5\xef\xcd\x47\x4f\x35\x1f\xfd\xd2\x7a\x64\x17\xc6\x06\xad\xf4\xe7\x82\x64\xa8\x7b\xfe\x8f\x4f\xfd\xa3\xc5\xf1\x84\xff\x76\xc5\x45\xe7\x2e\xd0\x6a\x65\xf3\xd1\xd9\x56\x57\x9c\x6d\xcd\xa7\xd4\x98\x5b\x61\xc2\x37\x9f\x3d\xdc\x7c\x54\xdb\x46\x8f\x7e\x6e\x75\x0f\x47\xf3\x07\xa1\x9d\x51\x8d\x69\x2d\x2d\xe4\x99\x17\x2c\x89\x7a\xf0\xaf\xf1\xf9\xcf\xff\x5a\x5a\xa6\xbf\xb8\xa2\x5d\x8b\x06\x17\x51\xe5\xff\x76\x45\x2b\x9b\xb9\xa9\xd5\x19\x9d\xea\xea\x01\xed\xe9\xea\x93\xf0\x1f\xac\xa6\xf2\x7f\xf2\x28\xcd\xcf\x98\x00\xa0\xee\x54\x03\xe4\xc9\xea\xf7\x70\x91\xe6\x11\xff\x7a\xd1\x6f\xbe\x01\x50\x77\x37\x7f\xba\xf1\x2f\xef\xdd\x56\x87\x19\xe8\x06\x06\x30\x80\x1f\xac\x60\x05\x3f\x88\x20\x42\x2e\x38\xc1\x09\xb9\x50\x04\x45\x80\xa0\x18\x8a\x81\x83\x0e\xd0\x01\x58\xe8\x08\x1d\x81\x87\x52\xe8\x04\x0c\x84\x21\x0c\x56\xe8\x0c\x9d\xc1\x04\x65\x50\x06\x66\x88\x40\x14\x18\x28\x87\x72\x60\xa1\x02\x2a\xc0\x02\x31\x88\x81\x00\x5d\xa1\x2b\x58\xa1\x1b\x74\x03\x1b\x74\x87\xee\x60\x87\x1e\xd0\x03\xd2\xa0\x27\xf4\x84\x74\xe8\x05\xbd\x40\x84\x01\x30\x00\x9c\x30\x10\x06\x82\x1b\x2e\x81\x4b\xc0\x05\x83\x61\x30\x78\x60\x18\x0c\x03\x2f\x8c\x86\x31\xe0\x85\x4b\xe1\x52\xc8\x80\xb1\x30\x16\xdc\x30\x1e\xc6\x43\x16\x4c\x80\x09\xe0\x83\x89\x30\x11\x32\x61\x32\x4c\x86\x6c\x98\x02\x53\x20\x13\x2e\x83\xcb\x20\x07\xee\x81\x7b\x80\x83\xd5\x70\x3f\xf0\xb0\x06\xfe\x06\x0c\xac\x85\xb5\xc0\xc2\x3a\x58\x07\x0c\x3c\x04\x8f\x02\x0b\x1b\xe1\x71\xb0\xc2\x66\xd8\x0c\xe9\xf0\x24\x6c\x27\x31\x23\xec\x00\x17\x3c\x03\xbb\xc0\x03\xbb\x61\x37\x78\x61\x0f\xbc\x08\x19\xf0\x0a\xec\x03\x1f\xbc\x06\xaf\x41\x26\xbc\x0e\xaf\x83\x1b\xde\x80\x37\x20\x13\xde\x84\x37\x21\x9d\xd6\x53\xfc\xf0\x05\x7c\x01\xb9\xb4\xae\xe2\x87\xa3\x70\x14\x72\xe1\x38\x1c\x87\x5c\x60\x20\x46\xa9\x6c\xa2\x54\x36\x51\x2a\x3b\xc1\x01\x0e\xc8\xa4\xb4\x76\x42\x21\x14\x82\x9d\xd2\x9a\x87\x12\x28\x01\x9e\xd2\x37\x9b\x52\x93\x87\x4a\xa8\x04\x1e\xba\x40\x17\xc8\xa2\x34\x35\x53\x9a\x1a\x28\x4d\x05\x4a\x53\x1b\xa5\xa9\x83\xd2\xd4\xd8\x82\xa6\x3e\xb8\x04\x06\x83\x0b\x86\xc2\x50\x70\x51\x6a\xe6\xd0\x28\x30\xa7\x05\x4d\x59\x4a\x53\x2f\x8c\x83\x71\xe0\x82\x1a\xa8\x81\x0c\x4a\x59\x0b\xa5\x2c\x47\x29\xeb\xa1\x94\xe5\x28\x65\xdd\xb0\x00\x16\x40\x26\x2c\x87\xbb\xc1\x4e\xa9\xcc\x53\x6a\xf2\x50\x07\x75\xc0\x53\x9a\x1a\x28\x4d\x8d\x94\xa6\x3e\xd8\x01\xbb\xc0\xd5\x82\x9a\x2c\xa5\xa6\x85\x52\x93\xa3\x74\xe4\x60\x3f\xec\x07\x1e\x0e\xc0\x01\x70\x51\x9a\x1a\xe1\x30\x1c\x81\x4c\x4a\x59\x13\xa5\xac\x93\x52\xd6\x44\x29\xeb\xa4\x94\x75\x02\x03\x19\x94\xb2\x40\x29\x8b\x28\x65\x19\x4a\x51\x16\x0a\xa1\x23\x70\x50\x0a\x15\x60\x82\x18\xf4\x02\x07\x0c\x80\x4b\x20\x93\x4a\x56\xb6\x4e\x8b\xd1\x30\x16\xfc\x54\x9a\xf2\x60\x02\x4c\x84\x10\x4c\x86\xcb\xa0\x80\xe2\x56\x0c\xf7\xc0\xa3\xd0\x09\x36\xc2\x66\xe8\x49\x31\xe9\x4b\x31\x19\x04\xbb\xe1\x45\x18\x0e\xaf\xc0\x1b\x70\x29\x1d\xeb\x44\xf8\x0c\x8e\xc2\x24\x3a\xa6\xe9\xff\xad\xa6\x7d\xf5\x95\x57\x4c\x6b\x55\xd3\xe6\xe8\xbb\x11\x10\x64\xd1\x77\x06\x04\xb0\xd2\x5a\xf9\x28\x38\x05\x0c\x0c\x07\x44\x2b\x84\x2c\x37\x84\x79\x19\x78\xe0\xf8\x47\xf9\x28\x00\xca\xd5\xde\xd9\x8f\x60\x16\xd3\x4a\xa9\x8f\x03\xa3\x8e\x84\xc0\x44\x00\x08\x90\xcf\xf3\x6f\xbc\xf6\x3a\x08\x00\x73\x8e\x13\x66\x29\xb3\x00\x8c\xd3\x99\xfb\x02\x80\x36\x8d\x40\x00\x5c\x57\x1e\xd3\xeb\xc8\x2d\x58\x1d\xb2\xb5\xea\x3e\x9c\xa1\xb5\x7b\xf2\x99\x83\x43\x00\xd0\x19\x02\xc0\xd1\x98\x95\x01\x13\xd8\xe0\x56\x50\xd1\x18\xb4\x98\x79\x93\xf9\x32\x60\x0e\xb8\x02\x59\x01\x7f\x20\x2f\x50\x18\x08\x07\xba\x06\x2e\x0b\x3c\x13\xcc\x2b\x38\x7f\x8e\x53\x55\xdd\xd2\x90\x5f\x04\xe0\x71\x34\x5a\xff\x05\x04\xec\x81\x8c\x40\xb6\xfe\x8b\x58\xf3\x2f\x10\xa5\x14\x52\xcf\xa9\xbf\xab\x27\xd5\xfd\xea\xb5\xea\x70\x05\x35\x9d\x39\xfe\xf6\xf1\xfd\xc7\x5f\x3b\xbe\xef\xf8\x2b\xc7\x5f\x3c\x1e\x3f\xbe\xfd\xf8\x9d\xc7\x63\xc7\xf6\x7f\xde\xc8\x7f\xaf\x8f\xf6\xff\xf4\x0f\x09\x84\xe8\xac\x76\x9c\x9a\x8d\x68\x75\x01\x00\x2f\x18\x8c\x26\xb3\xc5\x6a\x4b\x4b\xb7\x8b\x0e\xa7\xcb\xed\xf1\x66\x64\x66\xf9\xb2\x73\xfc\xb9\x81\x60\x5e\x28\xbf\xa0\xb0\xa8\xb8\x43\x47\xa9\xa4\xb4\x53\xb8\x73\x59\x24\x5a\x5e\x51\x59\xd5\x25\xd6\xb5\x5b\xf7\x1e\x3d\x7b\x55\xf7\xee\xd3\xb7\x5f\xff\x01\x03\x2f\x19\x34\x78\xc8\xd0\x61\xc3\x47\x8c\x1c\x35\x7a\xcc\xa5\x63\xc7\x8d\xaf\xa9\x9d\x30\x71\xd2\xe4\x29\x97\x4d\x9d\x36\x7d\x06\xac\xbc\xfb\x9e\x7b\xd7\x3d\xfa\xf8\x96\x27\xb7\x6e\x7b\x6a\xfb\x8e\x9d\xcf\x3c\xbb\x4b\xc6\xf1\xfa\xdd\xcf\xed\x79\xfe\xc5\x17\x5e\x7d\x65\xef\x3e\x58\x38\xeb\x8a\x39\xc7\x96\xfc\xfd\xda\xb9\xdf\x2d\xbe\x1a\x56\xd5\xc1\xf5\x00\x57\x6a\xb6\x7d\xde\xad\xf0\xf4\xcb\xcb\x66\xce\x27\xc7\xd7\xdc\x76\xfc\xf2\xe5\x77\x3d\xb2\xff\xc0\xe1\x23\x5f\x7e\xf5\xd9\xe7\x2f\xc1\x1b\x6f\xc2\xc9\x13\xdf\x9c\x4a\xc2\x4d\x5f\x1c\x85\x15\xf7\xdd\x79\xff\xea\x07\x1e\xfc\xdb\x9a\xf5\x0f\xc3\x43\x8f\x6d\xda\x08\x6f\x1d\xbc\x0e\x00\x6e\xd6\xd1\xa4\xfc\xff\x1a\x30\xca\x47\x5e\x38\x8e\x8c\xf0\x19\xf2\xa3\x7c\x26\x0c\xbb\xe1\x1b\x38\x09\x2f\xc1\x51\x94\x07\xa7\xe0\x27\x78\x15\xfa\xf1\x22\x86\x12\x0c\xce\x21\x78\xe8\xc8\x1a\x3c\x78\x51\x2d\x86\x50\xaf\x0c\x2c\x48\x35\x3d\x6a\xe9\x77\xb7\xd4\x06\x3e\xc5\xc8\xd9\x29\xa3\x14\xa3\x92\xc0\xe7\xd8\x2a\x95\x62\xa6\x64\xc8\xe8\x9a\xfe\xa1\xda\x60\x29\x66\x4b\xae\xcc\x08\xe0\xea\x91\x35\x41\x5c\x5d\x5b\x8a\xb9\x12\xf2\xd3\x60\x28\xb8\xa4\xe6\x2b\xdf\xfb\xb5\xbe\x21\xa3\x6b\x6a\x9a\x7c\x3f\xd4\xfa\x42\x41\xcc\x4b\x35\x78\xc0\xa2\x5a\x7a\xa2\xb6\x36\xa3\x14\xf3\x25\xb6\x49\x13\x4a\xb1\x50\x22\xe7\xa1\x95\x23\x6b\x70\x60\xe5\xa4\x49\x3e\x0c\xb5\xa5\xd8\x50\x22\xe7\xd3\xaf\xaa\x9b\xbf\x32\x96\x38\xc4\x40\x2c\x5c\x8a\x4d\x25\x81\x5b\xc8\x43\xf6\xfb\xde\xaf\x0d\x60\xb6\x60\x50\x28\x80\xb9\xc2\xc1\x18\x46\xd6\xac\x9a\xb9\x6a\x5a\x80\x1c\x74\xf1\x05\x83\xb5\xbe\x55\xf4\xd3\x68\xed\x13\x79\xa0\x59\x1b\x9d\xdd\x67\x0f\xd6\x96\x62\x4b\x49\xe0\x63\x8a\x8e\xb5\x24\x10\xc6\x06\x69\x52\x4d\x20\x30\x30\x34\x60\xda\x55\x81\x9a\xc0\xe5\xd3\xb5\x5b\x90\xeb\x6c\xe4\xc9\x81\x58\x38\xb0\x2a\x30\x70\xd5\x80\x69\xa1\x55\x81\x55\x21\xfa\xb8\x10\xb9\x39\xae\xee\xe2\x0b\xd6\xfa\x42\xe4\x0b\x5c\x3d\x93\x7c\xa8\x2d\xc5\x69\xf4\x49\x3d\x1a\x32\x82\x41\x5f\xa0\x61\xd5\x90\xd1\x35\x81\x55\xa1\x41\x01\x0c\x63\xf5\xb1\x05\xe9\x65\xe9\x25\xa1\x40\x83\xfe\xf0\x50\xa0\x66\xc8\x18\x5f\x10\xa3\xda\x9a\x55\x98\x2b\x1c\x14\x5a\x15\x0a\xac\x1a\xb4\x2a\x34\x8d\xfc\x40\xfb\x09\x79\x2b\xc5\x76\xc2\x06\x87\x54\x8a\x45\x82\x00\x39\x70\xb4\x41\x60\x15\x79\x0b\x4d\xbb\x6a\x6a\x4b\x4c\xc8\x4f\x9d\x25\x81\x55\x81\x55\x77\x11\xb2\x0d\xbe\x3c\xb4\xca\x80\x03\x23\x6b\xba\xfb\xf6\xd5\x96\x62\x57\x49\x3d\x54\xa3\xea\x3e\x7d\xd0\x90\xe7\xed\x30\x03\xe8\x2b\xb9\x78\x6c\x0d\x79\x1d\x5d\x13\x9a\x1e\xc0\x10\xea\xe3\x9b\x1e\xc0\x28\xd4\xa7\x36\x80\xab\x47\xd7\xc4\x21\x00\x7d\x67\xf4\x89\xa3\x00\xea\x3b\xa3\x0f\x0e\xcc\xc0\x99\x33\xb3\x53\xcf\x72\x97\x60\xd4\x77\x46\x08\x43\xdf\x19\xa1\x52\x4d\xfb\x88\x15\x48\x07\x06\xfa\x01\x30\x97\xf3\x63\x81\x05\x03\x74\x92\x11\x84\xbb\xc7\x0d\x9c\xe7\x87\x88\x2c\xf0\x5f\x76\x8f\xb3\x8c\xe7\x87\x08\xc8\x2c\xf9\x9a\x27\x5f\xc7\x0d\x82\xf7\x7c\xf7\x38\x22\xdf\x47\xc5\xa0\x58\x10\x14\x83\xfd\x98\x80\x92\x8f\x1e\x56\x66\xf3\x63\xff\xdc\xd1\x8f\x7b\x9f\x6a\xfb\x0d\x00\x68\x03\x8f\xe9\x7d\x2b\x21\x0e\x00\x52\x02\xb1\x50\xcc\x49\x71\x9e\x01\x09\x61\x63\x18\x43\x03\xe6\x22\x32\xcb\x27\xb1\x10\x91\x0d\x7c\x52\x36\x21\x09\x64\x1e\x89\x0e\xcc\xc5\x3a\x97\x91\xfb\x23\x31\x28\xde\x80\xf2\x95\x2f\x51\x3e\x02\x15\xd0\x1f\xec\x8b\xe7\x07\x90\xfb\xaf\xe6\xd2\x99\xc7\x85\x0c\xe0\xc0\x04\xdd\x01\x43\x18\xf3\x51\xf2\x00\x23\x27\x61\x21\x82\xb0\x99\xdc\x5e\x66\x4d\xc9\x04\x67\x02\x0b\x27\x61\xd6\x2e\xf3\x48\x92\x8d\xa6\x64\xc2\x44\xbf\x91\x2d\x48\x82\xce\x65\x4e\x31\x2a\x1a\xa2\xe4\x65\xf5\x07\xc3\xde\x7c\x7f\x18\x97\xce\x98\x94\xb3\xff\xa6\x2f\xc0\x40\x11\x00\xb7\x8c\xc7\xe0\x83\x5c\x34\x0b\xe2\x59\x00\x52\xdc\xed\xc9\x8c\x46\xa3\x71\x03\x03\x52\xdc\x68\xb1\x46\xa3\xd1\x04\xa0\x2c\x83\x4d\xaa\x67\xc4\xec\x9c\x7c\x6f\x54\x06\x2e\x59\xef\xf2\x66\xf8\xf2\xbd\x91\x04\xcf\xd1\x53\xac\xdd\x9f\x4b\x4e\xf1\x5c\xb2\x5e\x30\x99\x6d\xf9\xde\x08\xc2\x81\x30\xce\x6a\x48\x64\x6a\x23\xcc\xb4\xcb\x1e\x24\x25\xdc\xf4\x53\xdc\xed\x31\x4b\xf5\xd5\x6e\xa7\x49\xaa\x37\xba\x3d\x46\x29\x61\xd0\xae\x32\x84\x13\x46\xed\x0a\x83\x91\x5c\x61\xe0\x4c\x12\x76\xdb\x09\x36\x09\xab\x86\x58\x10\x49\xb8\x32\xeb\xc5\x5e\xc6\xdf\x4e\x83\x5b\x32\xbf\xd8\xcb\xf4\xdb\x59\x72\x80\xb3\xec\xf5\x4c\x96\xc1\x29\xd5\xb3\xf4\x55\x20\xaf\x38\xd3\x5e\x6f\xca\x34\x3a\x25\xec\xb1\xd7\x9b\x3d\x16\x27\xb9\x5b\xbd\xcd\x6d\x75\x4a\xf5\x76\xfa\x2a\xd2\x57\x17\x79\x25\xd7\x78\xe9\x35\x99\xf6\xfa\x0c\xfa\xab\x2c\x7b\xbd\x2f\x75\x9f\xec\xd4\x7d\x72\xc8\x35\xf5\xfe\xd4\x95\xb9\xe4\x7b\xb6\xda\xce\xb0\x04\x73\xbb\x48\x48\x43\xcc\x7c\xa7\x36\xff\x70\x75\x16\xe1\x48\x45\xd0\x19\xaa\x08\x3a\xa3\x6c\x94\x80\x3b\x44\x21\xe4\x24\x50\x15\x75\x86\x8a\x10\x44\xbf\x47\xfc\xe0\xe7\x06\xed\x1b\xf4\xfc\xe0\x2f\xff\x8c\x9e\x50\x2f\x79\xee\x92\x7d\x97\x3c\x7f\xc9\x3f\xf6\x45\xf7\xa1\x47\xb7\xa3\xbc\x1d\xe8\x71\x65\x2a\x81\x1d\xca\xd1\xed\xca\x2c\xf4\x28\x81\xed\x28\x4f\x93\xfd\x98\xda\x91\x13\x85\x87\xa1\x14\xee\x07\xdc\x31\x9c\xe0\x59\x30\x73\x12\xce\x0e\x27\x1c\xf4\x08\xe1\x4e\x61\x9c\xd6\x20\xe7\xf2\x49\x0c\x81\x06\x51\x66\xcc\x49\x9c\x6b\x97\x45\x24\x25\x5c\x1a\x17\x3a\x06\x1a\xc4\x44\x07\xed\xd8\x65\x97\x8d\x48\xc2\x99\x11\xb9\x80\x4f\x62\x6f\x44\x0e\x23\x49\xce\x4d\x13\x1d\xd8\x1a\x93\x3b\x74\x14\x1d\xf5\x16\x3e\x3b\x2f\xdf\x1b\x03\x99\xef\x28\x3a\xe4\x62\x29\x16\xc3\xd9\xe2\x6e\x40\x69\xde\x8c\x82\x7c\x6f\x0c\x3b\x1c\xb2\xe8\x8a\xc5\x3a\x97\x39\xab\x82\x2e\x4f\x34\x52\x59\x51\x5e\x58\xd4\x09\x55\x94\x57\x56\x55\x44\xdd\x7e\x94\x8e\x82\xe5\x85\xa1\x3c\xc1\xed\xf2\x78\xfd\xc8\xed\x12\x0c\xee\x50\x45\x27\x14\x63\x50\xf6\xcd\x53\x26\x4e\x9b\xbc\xe0\x68\xc3\xe1\x3d\x9b\x76\xbd\xcd\xb0\xca\xb7\xd3\xc7\x8c\x1b\x5b\x7b\xc3\x57\x0d\x87\x9f\xdb\xf4\xd2\x6f\xe8\x35\x7e\xc5\xc2\x69\xa3\x47\xcd\x2a\x19\xf5\xd6\xee\x6d\x87\x9d\x87\x3f\xcf\xfa\xf9\x35\x7e\xd1\xd2\x19\xa3\x87\x4f\x0b\x8f\x7f\x33\xbe\xf3\x23\xe7\x9b\x07\x9c\xdf\x00\x0f\x65\xea\x19\x7e\x06\x7f\x00\x6c\x44\xd2\xa1\x14\xba\xc1\x83\x10\x97\x00\x24\xb9\x8c\x4b\xc6\x39\x06\x24\x39\x83\x4b\x26\xba\xe4\x4b\x9c\x4d\x92\xbb\x70\xc9\x84\x68\xa1\x87\x22\x97\x44\xb8\x3b\xd1\xb6\x44\x9a\x09\xc6\x70\x12\x4e\xb3\xcb\x2e\x24\x11\x29\x1d\xcc\x49\xd8\x68\x97\x03\x48\x4a\x74\xd2\xce\x75\xb2\xcb\xe5\x48\x4a\x14\xd3\x4f\x72\x0f\x24\xc9\xae\x34\x42\x20\x2e\x3b\x37\xdf\x1b\x93\xcb\x3b\x89\x8e\xfa\x9c\x7c\xc9\x4f\xa9\xd5\xa5\x4c\x74\xe0\xec\x98\x9c\x21\x8a\x0e\xec\x27\xe4\xa9\x28\xaf\x8c\x46\x3c\x39\xc8\x25\x84\xf2\x0a\xab\x28\xa9\x7a\x20\x8d\x34\x4e\xe4\x45\x05\xff\xe1\x7c\xd9\x53\xeb\xd6\x6f\xdd\xba\xee\xa1\x6d\xaf\x57\x77\xef\x5a\xdd\xbb\x5b\xb7\x5e\xbd\x99\xb7\xee\x6b\x8a\xa1\xa2\x6d\xeb\x1e\x7a\x6a\xeb\xba\x87\xb6\xbf\xde\xbf\x4b\xef\x2e\xd5\xdd\xba\xf7\xe2\x86\x0c\xbb\xfd\x99\x1d\x77\x0c\xbb\xfd\xe9\xa7\x6f\xef\x3a\x62\x44\xd7\x61\x5d\x47\x8d\xea\x7a\x3e\xc0\x5d\x3b\xe4\xdc\x7d\x3b\x86\x2d\x7d\x66\xc7\xed\xc3\xee\x78\x7a\xc7\xed\xb1\x51\x43\x7a\x0d\x8b\x8d\x1a\x15\x23\x51\x5d\xa9\xda\xc8\x5b\xf9\x03\x10\x84\x12\x88\xc1\x6a\x88\xfb\x88\xa5\xc8\x25\x04\x2c\x60\x93\x71\x13\x21\x60\x15\x9b\x44\xb8\x2b\x35\x4c\x79\x7c\x12\xe7\xd9\x71\x29\x91\x2e\xc1\x98\xc4\x42\x58\x2e\x35\x92\xaf\x08\x79\x64\xab\x21\x89\xad\x94\x8a\xb2\xdb\x94\x94\xbb\x21\x49\x2e\x15\x44\x07\x66\x63\xb8\x5c\x4c\x98\x72\x0b\x3a\xd8\x89\xd8\x58\x1d\x71\x31\xbb\x38\x16\x8b\x61\x97\x88\x7d\x31\x90\x0b\x7c\x94\x60\xb8\x4a\xdc\x0d\x82\x35\xa3\x43\xe7\x7c\x2f\xa1\x5a\x79\x65\x15\x15\xa6\x68\xc4\xe3\x76\x09\xe9\x08\xf5\x44\x15\x51\x97\x60\xf0\x1a\x82\x45\x69\x28\x94\x97\x5f\x40\x29\x55\x85\x0c\x69\xc8\xe9\xf2\x78\xab\x7a\xa2\x0a\x4a\xb4\xd2\x3b\xee\xec\xd7\xf7\xc8\xee\x4d\x6f\x4d\x1f\x3b\x19\xb9\xf2\x8b\x3f\xef\x37\xe0\x10\xa3\xbc\x3c\x6c\x6c\xe2\x8a\xcf\x15\x05\xe5\xcf\xab\xad\xb8\xaa\x4c\xf9\xd4\x19\x2d\x98\x26\x49\xe3\xba\x14\x0d\xea\xd6\x7b\x00\x5a\xb9\x68\xc7\xe4\x49\x0f\x8f\xd8\xf9\xe1\x81\xd5\xd3\x9f\xe8\xd1\x47\x79\xb5\xfb\xea\xe1\xab\x4e\x4d\xf8\x8d\xaf\xad\xaa\x3a\xf9\x56\xed\x75\x3e\x1f\x9a\x64\xeb\x3c\x91\xb9\x4b\x9a\x58\xd5\x25\x7f\x68\x69\x64\xf8\x78\x40\x70\x0f\x7b\x16\x8d\xa6\xf6\xbc\x98\x58\x73\xdd\x94\x23\xcc\xa7\xec\x78\x0b\x5b\x2e\x0b\xcd\x96\x9b\xbd\xe7\xad\x01\xec\x59\xa6\x58\xf9\x55\x39\x49\x75\xbb\x56\xe9\xc9\x2c\x17\x86\xd2\x0c\x10\x61\x07\xfd\xb5\xd9\x98\x94\x9d\xda\x4f\x2a\xec\x50\x15\xf5\x0a\x8c\xe8\xb6\x3b\xbc\x86\x50\x21\xd4\xa2\xce\xfb\x84\x8a\x65\xf1\xf8\xb2\x0a\x61\x9f\x72\x88\xe9\xea\x41\x2b\x99\xd0\xa8\x07\xa7\x2b\x43\x95\x67\xb3\x94\x9d\xca\xb0\x99\xf7\x8f\x62\xf2\xe8\xbd\x7b\x28\x3d\x99\x1b\x5a\xde\x9b\x6d\x90\x6d\x17\xee\x5d\xe9\x10\x2b\xec\x4c\x51\x55\xd4\x03\xa2\xdb\x0e\x86\x50\x8f\xdb\x13\x7b\x6e\xab\x14\x5e\x47\xdd\x95\xfd\xaf\x0b\xca\xfb\xd3\xd1\x1e\x34\x26\x0b\x8d\x44\x2f\xcc\xb8\x6f\x64\xd3\xc7\xca\x1d\x1e\xe5\xf6\xa6\x4f\x46\xd2\x7b\xe7\x31\x7d\xd9\xeb\x79\x0c\x69\x20\x42\x9c\xa5\x1e\x32\x3d\x2c\xdb\xb5\x3b\x57\xf1\x6c\x94\x2d\xf0\xf2\x4e\x83\x05\x15\x39\xf3\x62\xa8\x83\xe3\x65\x17\x0a\x75\x51\x3e\x38\xb8\x7e\xd7\xce\x87\x0f\x71\xb9\xf2\x4d\x68\xa2\xb2\x69\x71\xa2\x56\xf9\xe7\x3c\x94\xa7\x7c\x7f\x15\xb2\x6b\xb6\xae\x0c\x1e\xe4\xbc\xdc\x1e\xb0\xc0\x58\xea\x25\x0d\xd4\x4b\x96\x71\x12\xe6\x23\x71\x40\xc4\x83\x80\xd9\x24\xc5\x11\x90\x43\xc4\x9a\x24\x84\xad\x61\x6c\x6e\xc0\x4c\x44\x36\x09\x49\xcc\x45\xe2\x26\x33\x39\x67\x32\x98\xa4\xb8\xd9\x44\x0e\xcd\x60\x92\x64\x9b\x4e\xd1\xa0\x18\x14\x83\x6e\xf2\x5a\x86\xae\x42\x6e\x74\x85\xf2\x88\xd2\xc8\x74\x3e\x8f\x56\x29\x8b\xce\x2b\xd3\xd1\x63\x74\x1c\x5d\x95\xb5\xe8\x01\xf8\x15\x4c\x50\x00\xd8\x14\x4e\x70\x2c\x18\x08\x7f\xcd\x94\x8a\x82\x31\x49\x1c\x98\x2c\xb0\xa2\x03\x9b\x62\xe4\xbe\x3d\x51\x0f\x14\x34\xb8\x04\x43\xd7\xa2\x8e\x48\x40\xd7\x8d\x51\x4e\x0c\x58\x37\xe9\xf3\xf7\x66\x7d\x3b\x88\xdc\x6f\x19\x52\x98\xe7\x98\x63\xc0\x42\x2e\xc1\x4b\x46\x6c\x92\x00\xc2\x5c\x58\x06\x24\xc9\xac\x35\x49\xfc\xbd\x36\x42\xf7\x32\xa6\x1c\x29\x5f\x7f\x0d\x08\x6e\x07\x40\x4f\x22\xa2\xb1\xe1\xd6\x51\x49\x8b\x63\x72\x13\x2a\x75\x7c\x92\x82\x76\x1f\x12\x8e\xdc\x8e\x42\x24\x0c\x01\xa4\x26\xd5\x65\xcc\x61\x1a\xdf\x88\x10\x47\x94\x5f\x5c\x58\xbf\xd2\x80\xa2\xc8\xcb\x78\x8e\x34\x9d\xbe\x45\x28\xfd\xf7\x27\x34\x1e\x9a\xa6\x36\x72\x5d\x75\xfb\xda\x15\xe2\x16\x62\x18\x44\x36\x65\x59\xc9\xc0\xb3\xe9\x33\xd3\xf8\xa4\x6e\x40\x65\x23\x9f\x94\x73\x74\x0b\x29\x5b\xb8\x18\x25\x8b\x68\x87\x68\x04\x32\x91\x1d\x42\x79\x80\x34\x67\x21\x6a\x16\x6e\x1a\x32\x7d\x73\x02\x59\x94\x7f\x9e\xf8\x56\xf9\x03\x85\xae\xb8\x7c\xfa\xac\xd9\xd3\x67\xcc\x62\xaa\x50\x6f\x14\x40\xa5\xca\x27\xca\x71\x65\xaf\x72\x4c\xf9\x07\x92\x10\x8f\x1f\x7f\x1c\xa3\x9b\x76\x6e\x7e\xfc\x59\x4d\x4e\x7a\x02\xb0\x23\x79\x0c\x26\x18\x06\x71\x81\x8c\xce\xc0\x51\xe6\x33\x64\x80\x88\xb1\x07\xf6\x85\x49\x58\x43\x39\x66\xa4\xb4\x89\xb3\x34\x00\x61\x79\x93\x14\x37\xb2\xe4\xd0\x48\xe4\x82\x84\x55\x32\x18\xa8\xb9\x22\xd4\x2f\x10\xbd\xee\x60\x45\x95\xd8\x93\xc9\xfe\xe3\xfc\xcf\x7f\x70\x4f\x3d\x35\xfd\x5c\x8e\x7f\xd7\x2e\x3f\xfb\x39\x20\x88\x00\x70\x12\x7f\x00\xb2\xe1\x7e\x88\xdb\xc9\x73\x2d\x6c\x92\x1e\x24\x6c\x2c\x58\x39\x89\x2a\x03\xa1\x50\x3c\x83\x3e\x23\x23\x9b\x88\x68\x4e\x18\x67\x37\xc8\x3e\x73\x12\xfb\xec\xb2\x9b\x48\x0e\x9f\x8c\xbb\x05\x1a\x32\xd9\x4d\x12\x16\xec\x38\x8d\xd8\x56\x9b\x21\x89\x6d\x61\x39\xcd\x90\x94\xfd\xc4\x9a\xfa\x44\x47\x9c\xb5\x98\x89\xcd\xb4\x89\xd8\x1a\x03\xd9\x62\x17\x1d\x58\xa4\x1f\xcd\x31\x9c\xe1\x88\x0b\xe0\x8e\x51\x5f\x5c\x08\xd1\x08\x47\x9c\x2d\xf2\x06\xab\xa2\x62\xb0\x02\xa5\xec\xa2\x3b\x18\xe1\x91\xed\xdb\xaf\x11\xf3\xc0\x36\xa5\x89\x41\x4b\xac\x47\xcf\xfb\xd1\xe1\x59\xe3\x66\x4c\x9c\x79\xa5\xf2\x2d\xfb\xd3\x01\x24\x9e\x7e\x63\xf9\xf1\x84\x72\x92\x5f\xa3\xac\xd9\x8b\xfe\x7d\xfd\xe6\xfe\x93\xae\xbf\xfb\xda\x54\xfc\xd1\xc8\x15\xf3\x07\xa0\x23\x2c\x81\x78\x31\xc1\x99\x67\x93\x71\xbe\x98\x8c\x9e\x47\x26\x29\x9e\x4d\x50\x76\xb1\xc9\xb8\x2b\x9b\x7c\xe7\xca\x30\x49\x09\x9b\xb5\x38\xdb\x26\xc9\x36\x22\x2a\x12\x65\x01\x89\x36\x44\x82\x64\x2e\x9f\x8c\x8b\xb9\xe4\x4a\xd1\x6a\x92\xe4\x12\x12\x7e\x18\x45\x07\xce\x8b\x81\x6c\xe5\x45\x87\x0c\x05\x1a\xbe\x79\x31\xec\x72\xc8\x99\xb9\x6d\x42\x0d\x09\x55\x68\x07\x14\xb5\xa2\xc2\x7c\x1d\x6f\x12\x6a\x70\xa1\xbc\xfc\x18\x83\x7c\x8b\x27\xcd\xbc\xfe\xba\xf9\x4f\x3e\x39\xfb\xf2\xcb\x2f\x1b\x3d\x5f\x39\xc9\x08\xc8\xf1\xee\x09\x64\x5b\x7c\xe5\x8d\xb7\x29\x5f\x7d\xf3\xae\xf2\x15\x5a\x21\x5c\x3a\x77\xfe\xd4\xeb\xe6\x7c\x31\x77\x5a\xcd\x55\x53\x87\x0b\x3b\x8e\x1e\x39\x78\xd9\x8e\xce\x52\x7c\xd1\xc1\x93\x87\x89\x0e\xe4\x03\x70\x43\xa9\x8d\x73\xc2\x74\x88\x9b\x29\xb7\xb9\x24\x36\x46\xa8\x06\x25\xd2\xd2\xcd\xc8\x26\x61\x36\x2a\xa7\x71\x49\xcc\x47\x10\x76\x85\xb1\xb5\x01\xdb\x69\x76\x80\x99\x48\xdc\x60\xa5\x21\xaf\xc9\x24\x11\xd1\xb4\x1a\xc8\x27\xab\xd9\x24\x11\x11\x00\x39\x9d\xc4\x5c\x10\xc3\x48\xc4\x0e\x82\x21\x0a\x8a\x51\x77\xc8\x4d\xc5\xaf\x22\x58\x10\x14\x8b\x0c\xf9\xcc\x64\x54\xb8\x65\xcb\x86\xa6\xad\x75\x4d\xcf\x22\x16\x8d\x10\x32\x50\x23\x7b\xe0\xfc\xbc\xd7\xef\x27\x22\x79\xff\xeb\x8c\x8d\xe9\x48\x78\xd4\x57\x6d\xe4\xd2\x79\x0c\x41\x98\x04\x9a\x1b\x27\x3c\xb2\x13\xc6\xb8\xf5\x83\x84\x93\x05\x1b\x27\x25\x32\x2d\xb9\x76\x9b\x24\x67\x12\xce\xe4\x51\xce\x64\xf3\x49\x39\x84\x24\x39\xdb\x28\x6a\x91\x1d\xc8\x16\x5e\x74\x24\x80\x49\x4b\xcf\x26\x71\x8e\x33\x57\x74\x60\x0f\xe5\x42\x41\x8a\x0b\xa1\x3c\xc1\x50\xe0\x0c\x8a\xa1\xa2\x20\xdb\x13\x55\x55\x3a\xdc\x2e\x26\x94\x97\xdf\x97\x41\x19\xf3\x6a\x67\x4d\x9f\x7d\xc5\x98\x5a\xa7\xa2\x5c\xca\x0e\x48\x64\x29\x8b\x3b\x74\xb8\xb6\xff\xc7\xdf\x35\xfd\x78\x50\x39\x81\x56\xf0\x69\xd3\xe6\x3e\xb8\xf0\xd6\x87\x7b\x56\x88\xac\xa4\x24\xa6\x2b\xd8\x5f\x84\x58\xe5\xfc\xa9\x8f\x95\xd3\x5f\x00\x03\x13\xd5\x46\x6e\x38\x7f\x00\xb2\xa0\x08\xae\x81\x78\x06\xc1\xc6\x9f\xb2\x3d\x16\x36\x99\x70\xe4\x67\x90\x50\xce\x41\x30\x28\xa6\x66\xc8\x47\xcc\x50\x84\x28\x57\x90\xa8\x0d\x9f\x94\x3b\x20\x49\x0e\xfa\x68\xac\xe6\xc8\x20\xd1\x87\x5b\x94\x8d\x06\x82\x5a\xbe\x5f\x74\x60\x77\x0c\x3b\x44\x39\x2d\x3d\x16\xc3\x16\x07\x36\xc6\x30\x27\x62\x43\x4c\x33\x58\xc1\x88\xc7\x6b\xe8\x84\x08\x82\xde\x9e\x28\x1a\x71\xb8\x5d\x2d\xac\x97\x86\xf9\x44\x34\x10\xa1\xd1\xf7\x0c\x88\xf6\xba\xaa\xff\x1d\x1b\x11\x5b\xb6\x7e\xf2\x1b\x47\x95\x1f\x3f\xfb\x4e\x39\x8a\x42\xb7\xcc\x9e\x30\x77\xde\xa4\x51\xd7\xe6\x32\x31\x04\xa8\x02\x8d\xcf\xf5\xff\xc3\xe3\x7d\xf5\x05\x3e\xda\x55\x69\x3c\xfc\xa5\x72\x02\xc5\x50\xda\xce\x17\xb7\x5c\x7f\xe3\x43\xe5\xa5\x29\xbf\x07\x5c\x25\x95\xb5\x31\x10\x37\x92\x58\x8c\x88\x18\x51\x1f\x4d\xd6\x80\x1a\x17\xe2\x64\xa9\xd5\x35\x50\xab\x6b\x44\x12\x91\xb4\x54\x66\xc5\x9a\x24\xe2\x81\x65\x23\x91\x2b\x5b\x0c\x64\x1b\xa4\xac\x9a\x18\x74\x9b\x11\x6b\x08\x56\x65\xa1\xaa\xa0\xa1\x8c\xe3\x4f\xef\x28\x48\x53\xbe\x4c\xcb\x3b\xfe\x46\x93\x6a\xe1\x7a\xa1\x05\x5f\x2b\x3f\x2a\x85\x8a\xbc\x76\x2d\xea\xcd\x64\x7e\xbd\x86\x78\x1c\x22\x53\x21\xfe\x00\x78\x21\x04\x61\x58\x05\x71\x37\xe1\x84\x2f\x15\x1e\x96\xb2\xc9\x44\x51\xd0\x6d\xb2\x49\x72\x11\xe1\x44\x67\x3a\xb4\x0c\x92\x1e\x13\x2d\xcf\xe7\x93\x38\xc3\x4e\xcd\x98\x83\x4f\x62\x87\x1d\x5b\xc9\xd7\x1d\xf9\x24\xee\x18\x96\xad\x7c\x52\x2e\x43\x92\x9c\xaf\xc7\x89\x1d\xc5\x7a\x93\x2f\xe8\xd6\xc2\x44\x9c\x1e\x03\xca\x3c\xd9\x01\xb1\x18\x2e\x12\xe5\x74\x36\x16\xc3\xa5\x0e\xd9\x2a\xc4\x5a\x47\x88\xad\x14\xbf\xa5\x6c\x3a\x5b\x1c\xf7\xbd\x73\xe1\xac\x6b\x95\x43\x87\x10\x2c\x9c\xb9\x70\x85\xf2\xe3\x57\x47\x95\x1f\x50\xfe\xfc\xc9\x13\x17\x5c\x37\x71\xe2\xfc\xbc\x09\xa3\x46\x4c\x9c\x3c\x62\x64\x2d\xba\x6f\xd1\xee\xb2\xf0\xb6\xb9\xaf\xff\xe3\x1f\xaf\xcf\xdd\x16\x2e\xdb\x73\xfd\x3b\x9f\x7d\x76\xf4\xf2\xeb\x16\xce\x98\xbe\x68\x11\x93\x33\x71\xce\x9c\x89\x35\x73\xae\xd4\xaa\x97\xbd\xd4\x46\x2e\x47\x97\xd1\xb9\xba\x6d\x20\xfe\x91\x5a\xff\x02\x36\x99\xc8\xf0\x9b\x59\x9b\xee\x2a\x2f\xc8\xa8\x8f\xba\x4a\x1c\xd4\xea\x07\x44\x46\x7d\x20\x3a\x64\x5b\x1a\x0d\x8a\xeb\xcd\x22\x9b\x41\x53\x09\xd1\x4c\x59\x88\x33\x44\x9c\x16\xc3\x7e\x2a\xaf\x05\x22\x06\x8a\xfc\x05\x8f\x5a\x58\x54\xe5\x47\x34\x69\x20\x71\x31\xa3\xc7\xc5\x1a\xd2\xbd\x90\xfb\xd3\x63\xc8\xa3\xbc\xfb\xeb\xd0\xcd\xfd\x82\x7d\x6f\x1d\x71\xfd\x9a\xb2\x95\xc3\xdf\x3b\x85\xf2\x67\x4c\x19\x34\x37\x30\x7f\x6a\xcd\x35\xec\x2b\x5f\x21\x49\x79\x5f\x39\xad\xec\x57\x4e\x2a\x6f\xe6\xfa\x3f\xc9\xf4\xd6\xd7\x7b\x7a\xf5\x46\x96\xc6\xe5\x75\x55\x9d\xea\x1e\xdf\xba\x13\x58\x98\x08\x80\x6e\xe5\x62\xc0\x02\x07\x46\x12\x0d\xb4\x8c\x43\x38\x22\xab\x02\x02\x89\xa4\xa5\x34\x18\x31\xd1\x4a\x09\xaf\x55\x4a\x0c\xf4\x4d\x36\x37\x87\x24\xc1\x4c\x14\x14\x27\xa2\x90\xf2\x95\x16\x9b\xb0\x31\xa4\xcd\x65\xb3\x90\xad\xac\x45\xb7\x70\x31\x5a\x2f\x4f\x83\x72\x88\x5b\xc9\x6d\x2d\xfa\x6d\xd3\xc3\x98\x6b\x90\x0d\xc6\x24\xb6\x45\xb0\xc1\x2e\x5b\xf8\x24\xb6\xd0\x90\x53\x36\x70\xa2\x03\x9b\x63\xf4\x09\xcd\x71\x18\x2b\x06\xc5\x6c\x3d\x16\x1b\x8d\x42\x17\xc2\x31\x6e\x8b\x16\x13\x41\x57\xe8\xcf\xae\xe7\x78\x30\x00\x38\x2b\x90\xc8\xbb\x79\xb1\x2b\x3b\xb9\x69\x1f\x53\x8d\x12\xdf\xa0\x79\xca\xd9\x0f\x85\x77\x95\xb3\x1a\xbf\x6f\x42\x43\xd9\x73\xec\x71\x5a\x1f\xca\x4a\x45\x70\x34\x84\x22\x0c\x36\x86\x69\x2d\x48\x0b\xde\x50\x45\xd0\x7d\x13\xbb\xf4\xfc\x52\x76\x29\x1a\x7a\xf2\x24\xda\x75\xf2\xa4\xa6\xe3\xb3\xa1\x3b\xfb\x21\x7b\x9e\x3c\xaf\x4a\x2c\xa8\x28\x10\x91\x7b\x36\x33\xa8\xe9\x39\xf6\x8a\xee\x28\xed\x23\xe1\x03\x64\x53\x1e\xfc\x06\x18\xc8\x03\x60\x3f\xa2\xb2\xe5\x87\xd9\x5a\x66\x96\xc8\x66\xa1\x6b\x2a\xb8\xf0\xb0\xc9\xb8\x87\x06\x17\x9e\x2c\x12\x5c\xe4\x86\xb1\xaf\x01\xdb\x22\xb2\x9f\x4f\x62\x6b\x04\xfb\xed\x24\xc4\x27\x21\x06\x49\x65\x65\x3f\x0d\x22\x44\x0f\x09\x22\x9c\x34\x6a\x10\x68\xd0\x2a\x7b\xb2\x45\x47\x1c\x04\xab\x1e\x3e\xa4\xdc\x68\x1a\x72\x07\x7b\xa2\xe6\xa4\xca\x10\x24\x08\xe5\xb1\x88\x3d\x74\x1c\xd4\x75\xf3\x7b\x14\x2a\x5f\xa1\x51\x37\x0e\x1c\x3b\x6d\xc2\xe0\x2b\x90\xf2\x2d\x0a\xa2\x42\x2e\xb6\xef\xbd\x6f\xde\xb8\xed\xc8\xa0\xf0\x65\x63\x56\xdf\x31\xb9\xeb\x8a\x31\x93\x66\xd7\x8c\x3d\xf7\xfe\x9f\x7f\x12\xda\xf5\x55\xba\x09\x6f\xf0\xab\x20\x0a\x7d\xe1\x19\x88\x9b\x08\x3e\x7e\x0e\x3a\x70\x52\x3c\x9d\xe8\x4d\x15\x97\xc4\x65\x61\xb9\x23\x97\xc4\xbd\xc3\xb2\x9b\x4b\xe2\xfc\x70\x82\xe5\xa0\x9a\xb0\xbd\x1f\xd5\x9d\x22\x53\x12\x17\xd9\xe5\xae\x44\x61\x4c\x49\xdd\xce\x27\x04\x2d\xbd\xea\x8f\x24\xb9\x88\xa8\x11\x2a\x8e\xc5\x70\x57\xb1\xda\xc4\xa6\xbb\xf3\xc5\x8e\x65\x15\xbd\x89\x3d\xf1\x39\xe2\xd6\xd2\x9e\x04\xfb\xa0\x98\x30\x65\x64\xf9\x3b\x91\x6f\x05\x87\x6c\xc8\x23\xee\xc0\xd4\x51\x74\xe0\xd2\x98\x5c\xe5\xd7\x2a\x20\xee\xde\xa2\x43\xce\xcc\xa2\x34\x71\x40\x30\x00\xac\xc0\x10\x4d\x23\x1a\x56\x58\x55\xe9\x88\x12\xef\x10\x65\x05\xaa\x6a\xda\x05\x0c\x04\x23\x95\x55\xde\x34\x14\x0a\x00\xd2\x4e\x94\x57\x56\x38\xa9\x0b\xe9\xeb\x40\x9f\xa3\x3b\xd1\x32\x54\x67\x37\xfd\xf8\xc3\xf0\x6b\x33\x4a\x96\xd5\xdc\xbb\xde\x99\xf9\xe3\xf6\x85\xab\xc7\xb2\x7c\xd4\xd0\x31\xff\xba\x7b\x8c\x76\xe5\x43\xe5\x35\xe5\x90\xb2\x3e\xdd\x81\x06\xa2\xc8\xd8\xdd\xbd\x0b\xfb\x7e\x38\x43\x59\xa8\x8c\x61\x36\x99\x63\xd5\x5d\x26\xe6\xa3\x12\x6f\x38\xe3\x9a\x85\xe8\x28\xda\xc1\x20\xc5\xa7\x4c\xfa\x5c\xd9\x5f\x33\x62\xf4\xe8\x1f\xf7\x2b\x28\x52\x5e\xc9\x35\xbd\x31\x65\xe0\xe7\x4f\xa1\xe9\xe8\x1e\x65\x9c\xf2\xa8\xb2\x51\x99\x55\xec\xff\x5b\xc7\x30\xfa\x05\x5d\x77\xdb\xb2\x8a\x01\x8c\x91\x41\x67\x0d\xc6\xd7\x08\x3f\x3a\x00\xf0\xeb\x79\x0c\xe9\xe0\x84\xde\x9a\x36\x63\x43\x54\x46\x5c\x32\x2e\x98\xd2\x22\x91\x08\x15\xb3\x84\xd5\x0e\xc4\x82\x59\x89\x80\xbb\xc2\x5a\xc8\x62\x45\xa2\x43\x66\xf8\x58\x4c\x66\x49\x1c\x4a\xc2\x96\x68\x45\x15\x0a\x22\x1a\xb4\x14\x05\x0d\x5e\xb7\x33\xc8\x86\x3a\xcc\x46\x2f\x21\x09\x3d\x3f\x5b\xb1\xcf\xac\x56\x8a\xab\x67\x06\xd0\xf0\x27\x85\x5d\xe9\xdc\x2f\xe7\xd2\xd2\x77\xed\x72\x1c\x3c\xe8\xd8\xc5\x4c\x65\x90\xa6\xf7\x5d\x00\x78\x37\x8f\xc1\x09\xd9\x50\x00\x2b\x21\xee\x04\x3d\x9e\xa4\x07\x64\x5c\x06\xdd\xac\x6a\x07\x1c\x97\x4c\xe4\x64\x3b\x0d\x36\x29\x91\xc3\x42\x84\x88\x49\x61\x18\x33\x0d\xb2\x8b\x4f\xe2\x9c\x08\x76\xd9\xe5\x0c\x24\xc9\x76\x3e\x89\xed\x76\x6c\x26\x6e\x27\xc8\x27\x71\x30\x2c\x9b\xf9\xa4\x5c\x84\x24\xd9\x9c\xa1\xbb\x48\x17\x12\x1d\x98\x89\xe1\x6c\x11\xdb\x63\x38\x87\x1a\xdd\x02\xa2\x24\x14\x31\xb1\xa8\x22\x1a\x0c\xb4\xf0\x31\x05\x41\xcd\xa7\x04\x2b\x52\xa1\x68\x97\x0d\x1b\x36\xa0\x33\x08\xa1\xc0\x9c\x59\xcb\x96\x29\x67\x9a\x94\x5f\x91\x6d\xe1\x92\xd9\xf3\x95\xaf\x3e\xbe\xfe\xd6\xdb\x6e\x3d\xb8\xcb\xcf\xb9\xfd\xf8\xe0\x5b\x33\x37\x15\x67\x3f\x7f\xe3\x47\x87\x8f\xcf\x9c\x31\x67\xc1\x3b\x53\x27\xcd\x9c\x4a\x6c\x42\xb9\xda\xc8\x7d\xcd\x1f\x80\x5c\xa8\x81\x78\x4e\x0a\x6f\x4e\xf7\xfd\xb4\xe2\x0a\x0d\xb2\x48\x42\x67\x8a\x14\x36\x45\xe4\x4c\x13\xb5\xab\x24\xd2\xc9\x10\x45\x87\xcc\xe5\x10\x39\x76\xe5\x88\x0e\x9c\x45\xe2\xe6\xb8\x31\x23\x93\x88\x3b\xe7\xd0\x42\x9a\x0a\x12\xd2\x70\x5e\x31\x54\x44\x24\x92\xc9\x41\x2e\x47\x34\x52\xd9\x0b\x45\x45\x81\x0b\x05\xa0\x1c\x2d\x44\x45\xdb\x91\xbd\xf6\x33\xbf\xb4\xac\xf6\xd5\xf7\xdf\x7b\x71\xdc\xfd\x45\xfe\xcf\x6a\x94\x9f\xb6\x2b\x5f\x28\xab\x98\xbd\x65\xa8\x07\x7a\xf8\xa6\x99\xca\xf1\xd7\xa5\x88\x72\xe6\x68\xf4\xa8\x72\x3a\x22\xbd\xae\x1c\x9f\x75\x23\x7a\x88\xc8\x13\xe1\x5f\x09\x8d\x5d\x32\x60\x34\xc4\xd3\x08\x16\xe9\x6c\x52\x3b\x68\xe6\x5e\x46\x0b\xee\x21\x9c\x49\xf9\x95\xce\x27\x71\xba\x66\xad\x2c\x7c\x52\xce\xa2\x51\xb1\xc6\x11\x99\xcb\xd0\x83\x97\x66\x3e\xd0\x32\x45\xb0\x48\x2f\x92\xe9\xa4\xff\x0d\x59\xd0\x04\x65\xab\xf2\xfb\xa1\xd7\x36\xc6\xe3\x1b\x5f\xd3\xc8\xad\xec\x50\x7e\xff\x59\xf9\x4d\xd9\x79\xfc\xd3\x1d\xbf\x6e\xff\x54\xb3\xbf\x5d\x00\xb8\xe7\x79\x0c\x2e\xa8\xd3\xa4\x5e\xb6\xb3\x49\xed\x80\x8c\x92\x7a\x35\x07\x4b\x6b\xd5\x82\x1e\x6a\xd2\x83\x84\xa9\xc5\x97\x44\xf6\xac\xe9\x20\xa4\x34\xc3\x4d\x11\x21\xa2\x66\x89\xc4\x19\x3b\xb1\xca\x0c\x67\x92\x30\x44\xb0\xdd\x4e\xbc\x02\x76\x44\x64\xa3\x21\x89\x9d\x11\xd9\x83\x24\xd9\xa4\xe7\x6f\x46\x91\x7a\x7d\x90\xed\x3a\xbe\x82\xa5\x0d\xbe\x24\xb2\xd6\x2a\x15\x55\x51\x91\xe0\xca\x7e\x73\xdc\xa6\x74\x42\x3f\x28\x4e\xd4\x60\x3b\xaa\x23\xba\xe0\x59\xe5\xc1\xaf\x95\xa9\xcf\x2a\xd7\x36\xe3\xb8\x97\xc7\x20\xc2\x9d\xd0\x8c\x1a\xb6\x47\xe8\x2c\x86\x6c\x26\x79\x1b\xc1\xc8\xa8\x61\xc4\xa7\x30\x4a\xb3\x00\x6f\x93\xe4\x34\x82\x91\xa3\x99\x35\xe6\x48\x3c\x9d\x21\x18\xa5\x8b\x26\xf2\x6a\x33\x49\x71\x26\x9d\xa2\x08\x34\xa5\x21\xcc\xa3\x41\xa8\x41\xab\x2a\xc9\x69\x3a\x32\xbc\xb9\x15\x32\x17\x70\xf1\xba\xbb\x6c\xd8\xc0\xdd\x75\xdc\xa6\x14\x20\x45\x61\xea\x2e\x60\x71\xcd\xd7\xca\x7c\xff\x2e\x82\x43\x58\x6d\xe4\x7e\xa2\xb5\xc9\xf9\x7a\x2e\xd3\x52\x27\x12\x99\x59\xb9\x5c\x8b\xfc\xe5\x82\x7a\x78\x49\x0a\xc3\x27\xe3\x5e\x9a\x85\x7a\x33\x4d\x12\xcd\x6a\xbc\xa2\xe8\x88\xdb\xb8\xdc\x18\x2d\x63\xcb\x66\x9a\x04\xb8\x72\xb5\x5a\xad\x2d\x4b\x6c\x15\xfe\xb7\xaf\x2b\x55\x15\x04\x07\xaa\x2d\x61\x34\x17\x15\xee\x40\xbe\x29\x47\x3a\x14\x2f\x1b\xbb\xf7\xd3\x43\xfb\x6b\xe6\xe6\x1e\x42\xbf\x0f\x54\xce\x1e\x52\x3e\x53\xee\x63\xe2\x11\x34\x10\x3d\x3a\x77\xb2\xf2\xc5\x1b\x79\x1d\x94\xef\xbe\x2d\x3f\xaa\xfc\xd3\xef\xfa\xa7\xfd\xfd\xa6\x8f\x06\x2c\x40\xf7\x68\x3c\x12\x8c\x3c\x86\x1c\xd8\xac\x5b\x5f\xb7\x66\x7d\x5d\xde\x6c\x62\x7d\x09\x57\xb0\x2d\x4a\x18\x13\x37\x58\xc5\x48\x24\x92\xc8\x32\x51\xfe\x64\x11\x9c\xfd\x94\x3f\x24\x9a\x34\x46\xe2\x3e\xca\x1f\x9f\xc1\x24\xe1\xec\x48\x9c\xf1\xb5\x94\x3f\x9f\x66\x31\xcc\x11\xd9\xc9\x27\xe3\xce\x0c\x72\xce\x29\x9a\x24\xec\x8a\xc4\x33\x9c\xb4\x38\x61\x35\x49\xd8\x13\x91\x73\x09\xef\xb2\xa8\x6d\x77\xc6\x62\x32\x67\x12\x1d\x32\xeb\x88\x5d\xe0\x9f\xdb\x20\x06\xa9\x50\x46\xdd\x06\xbd\x3e\xa2\xf3\x92\x99\x58\xc7\x8c\xae\xab\x43\xa1\xba\xba\xba\xa6\x2d\x75\x4d\xcf\xea\x2c\xc5\x7e\x65\x12\x7a\x92\xbc\x9f\x6b\x24\xa9\x2a\x5a\xa3\xb1\x17\x10\x54\x01\x30\x0f\xf2\x18\x2c\x30\xb0\x85\x8c\x9a\x23\xcd\xe2\x88\x0d\x11\x5a\xd5\x63\x1a\x64\x13\x4f\xb2\x8d\x54\x3d\x8f\x5c\xc4\x98\x5a\xe0\xa8\x57\xf5\x2e\x8c\xd2\xeb\xae\xaa\xab\x63\x26\xd6\x35\x8f\x82\x3c\x1d\x10\x84\xd4\x46\xee\x5e\x1e\x43\x06\xcc\xd2\xfd\x0b\xad\x61\x38\x9b\x6b\x18\x16\xaa\x1f\x1c\x49\x23\xa9\x75\xf2\x36\xd0\x69\x14\x46\x13\x70\x3b\x9f\x8c\xdb\x69\x96\x65\x4f\x33\x49\x71\x23\xd5\x73\x23\xc9\xe4\xb3\x48\xc2\xc5\x88\x0e\xec\x8c\x81\x6c\xe6\x45\x87\x9c\xee\x6d\x55\xaf\x20\x03\x23\x54\x23\x19\x4a\x51\x61\x45\x79\x88\x41\xd9\xf3\x26\x8f\x5a\x50\x87\xf6\xd6\xd5\x29\x3f\x7c\xfc\xed\x9d\x4b\xd1\x66\xe1\xba\x2b\x6f\x99\xcb\x96\x92\x01\x9f\xff\xe4\x93\x7f\x5e\x33\xe7\x3d\x63\xb3\xcd\xe2\x1f\xe1\x31\x64\xc3\xad\xba\xac\xb8\x34\x59\x71\x7a\x7c\x17\xcb\x4a\x3a\x91\x15\x53\x26\x91\x15\x62\xb4\xca\x38\xad\xf4\xc4\x34\xc8\x59\x9a\xb8\x64\x51\x52\x66\x11\x52\xfa\x22\x71\x26\xab\x25\x29\xfd\x44\x08\x32\xa9\x10\x38\x62\x31\x6c\x12\x89\x99\xe2\x1c\x32\x6b\x6f\x2d\x08\x51\x44\xdf\x4d\x9a\xcf\x47\x21\x5d\x0e\xc6\xac\xbd\x0d\x65\x8c\x63\x7a\x3f\xa6\x3c\x8a\x1e\x7c\xb0\x69\xef\x04\xe5\xd4\xdf\xd7\x36\xcb\xc2\x4d\x68\xbd\x15\x63\x9f\x92\xd7\xf4\x5a\xe6\xae\x5d\x56\xb4\x45\x99\x4b\xf9\x42\xec\xd5\x6d\x34\x16\xb9\x4e\x97\x05\xcb\x45\x36\xd9\xd6\xda\x58\x61\x53\x04\x61\x3b\xc5\xca\xc2\x27\xe3\x16\x8a\x92\xc5\x44\x6c\x93\xa5\xa5\x6d\xb2\xd8\x89\x74\xd0\x5a\x9a\x48\x50\xb3\xa4\x1c\x8b\x8d\x48\xb7\x39\xd6\xc2\xd4\x12\xfe\xa4\xac\x2c\xca\xaf\xab\x43\x1b\xd2\x8e\x35\x0b\x90\xf2\x9c\x72\x65\x8a\x17\x86\x5a\x1e\x83\x1f\xb6\xa5\xfc\x87\x37\xaa\x71\x23\xdd\x91\xd3\xcc\x0d\x33\xe5\x06\xb6\x46\x68\x64\xce\x68\xe5\x95\x2c\x63\x32\x45\x7c\x3f\x19\x69\x56\xcb\x91\x66\x6b\x2e\x30\x8d\x68\x69\x5a\xb3\x96\xa6\xd9\x65\xb7\x31\x89\xdd\xe1\x78\x9a\x9b\x7c\x99\x66\x31\x49\x38\x3d\x42\x63\xfa\x6c\x62\xb6\x32\x49\x3c\x5f\x6f\x30\x7b\xb5\xfa\x86\x03\x7b\x62\x20\x73\x48\x74\xd4\x1b\x4d\x9e\x4c\x3a\x97\x92\x42\x10\x45\x51\x30\xa5\xb9\x15\xce\x22\x14\x42\x06\xa7\x9b\xf2\x6d\x03\xba\x05\x5d\x27\xa0\x45\x4c\x16\xd1\xdf\x0d\xd9\x82\xb2\x64\xbf\x72\xb3\x90\xad\x2b\xd0\xb9\x0f\xb9\xb2\x94\x0a\x9f\x64\x96\xa1\x73\xef\x70\x11\xd4\x74\xfb\x49\xaa\xca\x2d\x6c\x99\x17\xee\xd2\xe5\x53\xa4\x14\xc1\x1e\x9d\x1a\x56\x4a\x0d\xd9\x92\x1e\x89\x20\x9c\x41\xe9\xe1\xe6\x93\x71\x37\xa5\x85\xdb\x4b\x68\xe1\x6e\x49\x0b\x37\x75\x9a\xc4\xa4\xc7\x45\xaa\xe9\x62\xba\x49\x8a\x9b\x44\x6a\x02\x2c\x26\x49\xce\x44\x92\xec\x26\x0a\x67\xa0\x32\xea\xd0\x71\x8e\x1b\xed\xce\x58\x4b\x9e\xa2\xaa\x94\xe6\x05\x91\x41\xd4\x71\xcd\x67\x86\x0a\x9a\xe2\x7d\xd5\x94\x10\x74\x1c\xcf\x97\x20\x96\xa7\xac\xf6\xb3\x9f\xa2\xf3\x7f\x6a\xb8\x31\xd0\x57\x6d\xe4\xe7\xfc\x7f\xd4\xc0\x39\x8b\x56\x03\x27\x3e\x45\x0f\x5e\x02\x40\x1d\x8a\xa3\x07\x2a\x67\x42\x79\x8c\xbb\x2f\xba\x0a\x15\xa1\x62\x74\x8d\xf2\xa0\x72\x44\xf9\x4c\x59\x87\xf2\x9f\x7b\xee\x85\x17\x5f\x7e\xfe\xf9\xdd\xcc\xfb\x1e\xd4\x13\x3d\xa9\x4c\x52\x5e\xf7\x28\xfb\x94\x29\xe8\x09\x54\xfd\x9d\xf2\x3d\xca\xfc\x2e\xe3\x04\xca\x52\x4e\x7d\x0b\xa9\xd8\xcb\x48\xfd\x7d\x16\xdc\xd8\xda\xe3\xd3\x60\x2b\xab\x65\xcc\x9c\xe6\x00\x43\xca\xcb\xfb\x9a\xbd\xbc\xa3\xa5\x97\xbf\xd8\xbf\x93\xa0\x85\x84\xcd\xd9\x2d\xfd\x7b\x16\xd0\x8c\x9b\xb8\xcd\x96\x21\x4b\x04\xdc\x2e\x4e\x42\xa2\xd7\xcd\xb6\x8c\x8f\x99\xac\x3f\x51\x50\x39\xf6\xe7\x1f\x75\x75\x7f\x2c\xb9\xe5\x96\x25\x7f\xe8\x5e\x5f\x3d\xf4\x91\xa2\xbc\xe2\xdf\xc5\xfc\x7c\xe7\x15\x57\xde\xad\xd3\xdc\xc1\x6f\xe4\x0f\x80\x13\x82\x30\x14\xe2\x22\xc1\xc7\x9b\xa2\xb9\xff\x82\xcb\x27\x91\xbe\xcb\xae\x59\x5f\xbd\x7a\x99\xe5\x12\x1d\xf1\x34\x4e\x24\x7e\xde\x28\xca\x16\x1b\xf1\xf3\xc4\xf9\x63\x4b\xac\x05\x17\x5c\x8c\x81\x37\x14\x68\xb9\x5a\xfb\xbc\xb8\xfb\x26\x54\xf9\x81\xf2\xf7\xa2\x11\x45\x7f\xcd\x91\x57\x95\x37\x67\xbc\xb6\xa9\xd1\x68\x6e\x8f\x2d\x3a\x5f\x6a\x78\x0c\x79\x20\xc1\x06\x5d\x33\x3c\x54\x33\x64\x77\x30\xa2\x33\x47\x6a\xc9\x9c\xdc\x10\x65\x4e\x2e\xc1\xb1\x84\x32\x27\xc0\x27\x71\x28\x12\x0f\x50\xe6\x04\xf2\x08\x73\x02\x2d\x99\x13\xa0\xf8\xe3\xa2\x08\x0d\x80\xcc\x91\xb8\x48\xad\x8a\xe8\x31\x49\x72\x29\xd1\xa1\x2c\x3d\xc9\xc9\x25\xfa\xc1\xd8\xb3\x62\xb1\x98\x2c\xfd\x05\xe7\xf4\x24\x27\x07\xb9\x3c\xb9\xc8\x1d\xca\x2b\x24\x31\x76\x51\xa8\x2d\x2b\xd1\xaf\xff\x42\x59\x8b\xae\xbd\x7d\x41\x61\x49\xfe\xfa\xfb\x17\x2e\xb8\xe2\xa7\xba\xba\x77\x96\x2c\xb9\x71\xd1\x87\x1a\x4f\xbf\x39\x38\xef\x89\x48\xa1\xbc\x6c\x70\xe7\x0a\x9e\xc7\x8f\x2e\x19\x73\xd5\x8d\xac\xb2\xd4\xbf\x8b\xed\x34\x7b\xfa\xf4\xeb\x35\x9b\x31\x4d\x6d\xe4\x36\xf1\xfb\xa1\x03\x89\xef\x68\x75\x37\x98\xaa\x9c\xd1\x90\xba\x23\x2d\x20\xf9\x22\x44\x3a\xe5\x1c\x03\x4d\x11\xf2\xf5\xb2\xae\x84\x24\x39\x3d\x47\x74\xc8\x7e\x92\xeb\xe7\x8b\x09\xab\x23\x23\x58\xa4\xd9\xbf\xb8\xc9\x29\xc4\x08\xd3\x83\x24\x75\xf0\xc5\xb0\x55\xac\x07\x83\x3b\x9b\x9c\x65\x1d\x58\xa0\xc5\xb3\xfc\xaa\x0b\xe1\x5d\x73\x83\x02\x17\xca\xcb\x2f\x12\xa3\x5e\x5a\x4c\xab\x28\x2f\x2c\x2a\x41\xd3\x50\xc9\x37\xdb\x90\x6b\xca\x17\x85\x85\x0f\x8e\x5e\xbc\xec\xee\x6d\x3f\xff\x5b\x39\xf2\xcb\x4e\x25\x39\xf9\x44\x6e\xc9\xfa\xc9\x8b\x6f\xb9\x61\x9d\xd2\xa4\xfc\xc1\x85\xe5\xaf\xd9\x59\x63\x95\x86\x83\x19\xf9\x33\x47\x0e\xbe\xac\xa2\xef\x97\xf5\x2f\x1d\x99\x37\x0d\x75\xfe\x30\x3f\x3c\x7d\xf4\xa5\xb3\x4a\x87\x7c\x00\xb4\x6f\x1a\xf8\xae\xd4\xcf\xcd\xbf\x78\x26\x81\x68\x24\xe6\x23\xcd\x95\x5e\xda\xff\xa3\x39\x39\x68\x90\xd3\x35\x0a\x58\x53\xc5\xde\xe6\x39\x85\x16\x13\x0a\xd8\x60\x97\x39\x24\xc9\x6c\xca\xd9\x81\x45\x74\xc8\x06\x6b\x4c\x2b\xfe\xd2\xf0\x5b\x0f\xdb\x0c\xc5\xbc\xe3\xb8\x55\xf9\xad\xae\xe9\xc9\x3a\xe5\x77\x2b\x57\x82\x96\x2b\x37\xff\xfd\x9c\x42\x2c\x3c\xc7\xfc\x1d\x10\x14\xa9\x8d\xfc\x0f\xb4\x87\x68\x31\xc4\xbd\xa0\xe7\x0d\x64\x70\xd8\x4e\x7b\x85\xe2\x7c\xba\x23\x42\xec\x79\x76\x18\x67\x35\x68\xa3\xa2\xa2\x67\xe0\x4d\x52\x3c\x8b\x8e\x2a\x0b\xb4\x51\x11\x17\xec\xe2\x93\x71\x97\x8d\x4e\x0d\x39\x4c\x52\xdc\xe6\x22\x87\xb6\x74\x93\x44\x6d\xa5\xcd\x20\x3a\xb0\x37\x06\x32\x98\x45\x87\xec\xf4\xd1\x31\xeb\x4e\xf9\x42\x08\x45\x3e\x10\x05\xae\x10\x8b\xa8\x8b\xde\x70\xd7\xdd\x75\x24\xf8\x54\x5e\x51\xfe\x54\xce\x29\x7b\x79\xc0\xd8\xdf\x64\x5c\x73\xff\x7d\x0f\x30\xff\xf2\xd3\xe3\xdf\x95\x3f\x90\xf9\x77\xe6\x5f\x74\xbe\x1a\x80\xdf\x40\xed\x64\x89\x36\x6f\xa7\xe1\x63\xd1\xf0\x61\xcd\x36\x8a\x8f\x23\xac\xa5\x31\x40\x92\x34\x2a\x2f\xe4\xc1\xc8\x1b\xad\xd2\x62\x1e\x14\x44\x79\x8c\xeb\x1a\xc4\x38\x04\x11\xb1\xf3\x18\xd7\x12\x65\x8c\xf2\xa9\x32\x9a\x3c\xdc\x75\x7e\xfd\xc8\xe1\xec\x1c\x17\xc6\xf6\x73\x76\xee\x2c\x20\xc8\x01\x30\x3c\x44\x7d\xe3\x52\x88\x7b\x08\x1d\x1d\xee\x68\x94\x3e\x38\x6e\x30\xda\xa2\x51\xfd\xe1\x34\x6c\x23\xce\x91\xf8\x36\x5c\x99\xf5\x62\x8f\x97\x7e\xca\xa1\x0d\x50\x86\x4e\x69\x58\xd8\x27\xbb\xd2\xfe\xcd\x63\xf7\xbe\x17\x5f\x1f\xf6\x13\xd0\xef\x1d\x9d\xd2\xb0\x73\x9f\x6c\x4a\xff\x37\x8f\x8d\xfb\x58\xa8\x17\x4c\x4e\x57\xa7\x4e\x9d\x3a\xa1\xe7\x04\x83\xd1\xe4\x70\xba\xdc\x17\xf5\x28\xb9\x0d\x4e\x2f\x8a\xa2\x2a\x67\x0a\x93\x10\x0a\xa2\x1c\x26\xe3\xce\xa7\x04\x24\x1e\x46\x4e\x61\xeb\x9d\x8c\x77\xb1\xf2\x99\xf2\xb3\xf2\xbb\xa0\xfc\xae\xfc\xac\x1c\x26\x68\x79\xcf\x9f\x40\xec\x77\xe7\xb3\x10\xeb\xf7\x62\x9c\x7e\x2e\x9d\x7d\xed\x7c\x2f\xee\x67\x42\xd3\x20\x00\x7f\x33\x95\x93\x71\x6d\x63\xd3\x2c\x12\x0d\x09\x7a\x6c\xca\x73\xc9\xb8\x51\x47\x32\x3b\x8c\xf9\x06\x12\x6d\x1a\xad\x49\x9c\x15\xa1\x02\x60\xe4\x45\x47\x3d\xc3\x9a\x32\xb5\x9e\x23\x12\x81\x9a\x33\x74\x57\x6e\xd2\x08\xef\x6b\x15\x73\x5a\xc8\xdb\x4d\xe8\x76\xe5\xee\x25\x4c\xf8\x86\xaf\x4f\x5c\xcf\x94\x2d\x51\xee\x46\x77\xdf\xde\xf4\xc6\xc2\xd3\x8d\xd7\xef\xca\x60\xbc\x8c\x29\x13\x63\x9b\xb2\x01\xcd\xb4\x61\x9c\xd9\xf4\xcf\xa6\xd3\x34\xec\x9c\xaf\xac\xb1\xd2\x1c\x33\x1f\x80\x1f\xc1\x63\x70\xc3\x65\xba\x97\x71\x70\x49\x9c\xae\xe9\x20\x36\xe9\x9c\x31\x5a\xe8\xa0\x3d\x61\xec\xa4\x6e\x3e\x9e\x46\x13\x86\x34\xbb\x49\x6a\x11\xa9\xd1\xc4\x33\xcd\x29\x3a\x76\xb3\xbc\x60\x34\x31\x14\x0d\x70\x88\x0e\xcc\xa7\x44\xc8\x19\xd5\xc9\xae\x6b\x21\xca\x67\x8a\x6e\x38\x21\x9c\x58\xc4\x14\xdd\xac\x2c\x24\x89\x93\x72\x13\xa1\xb6\xa8\xe4\xa1\xa3\x22\xc6\xae\x26\x97\xf2\x3e\x4d\x9b\xfa\x30\x5f\x91\xf1\x0e\x06\xe0\x36\xf1\x18\x6c\xcd\x71\xb2\x89\x4d\xc6\x4d\x90\x0a\x8b\xb4\xe2\x04\x4b\xec\xa8\x90\x9a\xe5\x46\x38\x2d\x45\x6d\xce\x90\xc4\x1c\x6d\xba\x93\xad\x86\xa4\x9c\x8e\x24\x99\xe3\xa9\x8c\x63\x8b\x28\x33\xa6\x18\xed\xce\x31\x1a\x6c\xd4\x7e\x9a\x88\x8f\x40\x31\xad\xbd\xc1\x48\x19\x81\x82\x86\x90\x33\xe8\x46\xc1\xaa\x28\x3b\x98\x79\x53\x29\xf3\x1e\xf3\x70\x9e\xa6\x2a\x74\x2e\xe3\xa8\xe7\x61\xae\x0a\xa3\x07\x1e\x3c\xf7\x3a\x56\xe6\x03\x82\x7b\x14\xcc\x74\x17\x36\x80\x01\xaa\x40\x73\xdc\x0c\x9b\xc4\x86\xe6\x5a\x39\x86\x86\x84\xc1\x0a\x69\x9c\x84\x99\x88\xcc\xf3\xc9\xd4\x27\x36\x92\x2a\xa3\x8b\x41\x77\x48\x8c\xba\xef\x41\xf2\xbd\xf7\x2a\xd8\xd0\x78\xe4\xdf\x07\x8e\x50\xdf\x61\x55\x97\xb1\xab\x53\x7d\x0c\xd0\xba\x8f\xc1\x19\x44\x41\x2b\x0a\x30\x53\x95\xe3\x3c\xa6\x7d\x0c\x08\x2c\x0a\x46\xaf\xd0\xb1\x54\x6b\x7d\x2a\x32\xa7\x8d\x05\xf4\xb1\x18\x1a\x30\x1b\x49\x08\xda\x00\x04\xbb\x8c\xf8\x24\x46\x61\x2c\xd8\x53\x83\x32\xa4\x6a\xfb\xde\xa8\x18\xaa\x08\x8a\x41\xcb\xfd\xf7\xa3\xb8\x32\x7c\xb1\xd0\xed\xc8\xbf\xdc\xe4\x19\xa5\xcc\x67\xec\x78\xda\x8b\xd0\xdc\x5b\x61\x0e\xa7\xda\x35\x51\x14\x85\xd8\xa2\x90\x81\x2d\x45\xd2\xa7\x48\xfa\x7e\x8b\x51\x30\x3c\xc1\x7c\xc6\x1c\x6e\xea\x80\x36\xe6\xe5\x29\x33\x34\x9f\x38\x49\x1d\xc0\x9e\xa6\xd5\xd0\x2c\x9d\xbf\xac\x9e\xfe\xb4\x40\x30\x1a\x74\x07\x27\xb1\xf7\x9d\xbf\xf6\x45\xfa\x9b\x6a\xee\x65\xa6\x3b\xff\x26\x70\x90\x0b\xb4\xef\x21\xc1\xb1\x90\xdb\xa2\x0b\xc9\x9a\x4c\xb5\x1e\x55\x05\x9d\xa1\x6a\x06\x55\xee\x3f\xc3\xef\x13\x94\x3f\xb4\x18\x65\xb0\xda\xc8\xf5\xe6\x86\x43\x08\x3a\xc1\x3d\x10\x0f\x92\xa7\x16\xb1\x49\xda\x34\x2a\x67\x72\xc9\xb8\x88\x40\x92\x8d\x6c\x32\x6e\xa4\xe1\xb7\xd1\x6a\x92\x12\x25\x6c\x50\xb4\x49\x72\x09\x97\x44\x38\x4c\x1f\x93\xaf\xcd\x3a\xe4\xdb\x65\x9b\x29\x89\x6d\x61\x72\xd4\x11\x91\x08\x85\x7a\xec\xce\x48\x92\x3b\xe6\x8b\x8e\xb8\x45\x0c\x92\xd0\xcc\x2d\xca\x3e\x3f\x91\xb2\xcc\x2c\xda\x26\x87\x4b\x44\xd9\x0d\xb1\x98\x6c\x24\xd2\xe6\xd2\xa6\xf7\xba\xe9\x93\x0f\xe9\x28\x54\xd5\x13\x45\x23\x1e\xb7\x48\xe3\x92\x60\x27\xa4\x15\xe2\x53\x53\x5d\xa1\x3c\x61\xf0\x6f\x67\xd6\x4d\xa8\x89\x0c\xcf\x70\x7e\x89\x46\x7e\xb8\xe4\xed\x73\x88\xad\x55\x76\x59\x1d\x7c\xf9\xba\xa9\x9b\x5e\x42\xa1\x81\xbd\xfa\x5c\xed\x5f\x37\x79\x2a\x2a\x7d\x78\xeb\x55\xc3\xc7\x79\xed\x0b\xcf\x56\x0e\x3e\xb0\x47\xe9\x9d\x59\xe2\xb2\xee\xf2\xc5\x72\xba\x0f\xde\xf9\x78\x55\xcf\x98\xb4\x65\x3c\xa5\x8b\x7a\x5a\x6d\xe4\xc6\x0a\x19\x34\x06\xbd\x0a\xe2\x0e\xe2\x2d\x6c\xa9\x40\x54\x40\x5a\x20\x4a\xa7\x80\x38\x2d\x1e\x75\x68\xf1\x28\x13\x89\x3b\xa8\x6b\x73\x10\xdf\xa7\x47\xa7\x66\x3d\x3a\x75\x11\x7b\x60\x8f\xe1\x2c\x51\x16\x68\x64\x2a\xd0\x34\xd4\x1e\x8b\x61\x10\xb1\x33\xd6\xb9\x8c\xad\x08\x8a\x74\xba\x59\xa4\x33\xe9\x85\x45\x86\x90\x88\xf4\xe9\x3d\x6d\x26\xc6\x83\x5e\x0d\x2f\x1b\xfb\xc1\x91\x23\xef\x5d\xb6\xba\xb3\xfb\x3c\x0a\xf9\x2e\xeb\xbf\x60\xc2\xe4\xf9\xfd\xa6\xf8\xf8\xd9\xb8\x69\x57\xef\x01\xca\xdb\x4a\x93\xfb\x17\xe5\xe8\x88\x21\x77\xf2\x83\xcf\x9d\x8e\x94\x6f\x7a\xd0\xfd\xd8\x0b\xb1\x0a\xd0\x7b\x04\xd8\x5f\xb8\xe1\x10\x84\x41\x2d\xea\x6a\xae\xdc\x54\xcf\x46\x9c\x43\xfa\x94\xb3\x8d\xa3\x1e\xda\x44\x6c\x48\x73\x89\x8d\xa0\x01\xb2\xcd\xa5\xc5\x56\xcd\x05\xb3\x72\x88\x46\x3c\x5e\xa7\x1e\x51\xe5\xe8\xb3\xe4\x41\xaf\xcb\xed\x32\x08\x86\x3c\xe8\x8b\x6c\xff\x5e\x76\xa8\x3f\xf7\x43\x67\x4f\x75\x87\x9b\x67\x4d\x59\x34\x7c\x0a\x32\xb2\x37\xdd\xf6\xca\x2f\xca\x9f\x8c\xcd\xff\x13\x2a\x1f\x3e\x50\x39\xb6\xdd\x99\x99\xb8\xcf\xff\x80\x3c\x71\xa8\xc0\xf3\x75\x57\xcf\x43\x28\x92\xca\xc1\xb8\xc7\x84\x0c\xf0\x40\x3e\x2c\x81\xb8\x0b\xf4\x9c\x86\x4e\x1c\xa5\x71\x49\x6d\xcc\x41\x36\x89\x4d\x61\xd9\x4c\xf8\x51\x40\xc7\xeb\xe5\x93\xd8\x6b\x27\xee\x05\x1b\x22\xb2\x8d\x4f\xc6\x73\x68\x00\x92\x63\x32\x49\x72\x21\x92\xe4\x1c\x2f\xc9\xd0\x5c\xb4\xd1\x44\xb6\x8b\x84\x23\x69\xe9\x5a\x69\x36\x28\x62\x9b\x5e\x3d\x27\x19\xa6\x51\xcb\x1e\xe8\xc4\x8f\x56\x98\xf5\xba\xb5\x46\xc4\xd4\x84\xab\xa8\x05\x93\x7d\x8f\xbe\x3d\xea\x8e\xb2\xba\x3a\x94\xbf\x5a\xb9\xc1\x13\xbd\xa7\xf6\xe0\x57\x28\xff\xb2\xab\xab\xa7\xf8\xfd\x93\x7b\xcd\x99\x8e\x54\x37\x02\xd4\x75\x60\x6f\xb4\xdc\x8f\xff\xdc\xed\xdf\xb5\x7c\xc8\x70\x94\x7f\xf6\xbe\xbf\x97\x97\xa1\x77\xcb\x63\xaf\x3e\xa2\xe3\xcb\xfe\x8b\x1b\x0e\x99\x90\x07\x63\xf4\xe8\xcb\xce\x26\xe3\x3c\x41\x33\xc0\x26\x13\x3e\xab\x97\xb7\x49\xb2\x8f\xa0\x1a\xa2\x5d\x45\x66\x73\x32\x9e\x4d\x5b\xde\xb2\xc1\x24\xd1\x48\xd9\x9c\x4d\x22\x29\xda\xc8\x61\xf7\x52\xad\xc2\x56\x4d\xc8\x9c\x15\x95\x55\x95\xd1\x48\x34\xe2\xc8\x41\x41\x03\x95\x2e\x3a\x71\x95\x07\xc8\x1b\xd4\x67\xcb\xd1\xf2\xe5\x5f\x22\xe6\x8b\x5f\x9a\x96\x30\xc6\xdb\xe6\x4e\x5b\x3a\x74\x44\xdf\x7f\x2c\x3b\xad\x9c\x42\x9d\x58\x34\x6b\x7c\xcd\xa8\x29\x48\x29\xfe\xb9\x6e\x83\xf2\xaf\xaf\x37\x09\x73\x56\x15\x75\x4c\x54\x5c\x82\x4a\xd0\xf5\x7c\xd6\xe4\x6b\x6e\x26\x72\xd6\x0d\x80\xb5\x0a\xa5\xe0\x83\x39\x7a\x7c\x9f\xa9\x15\x04\x10\xd2\xea\x03\xc0\x26\xb1\x33\x82\x6d\x61\x59\xd0\xb3\xe8\x2c\xda\xbf\xe7\xe6\x69\xe2\xea\xce\x6a\x6e\x25\xd7\x2a\x04\x59\xee\x54\x44\x59\x5f\x9d\x95\xa1\x85\x8d\x20\xdb\x90\x96\xc9\x08\x22\x36\x69\x21\xa3\xd6\x33\xaa\xf7\x6e\xe4\xa0\xa8\x3b\xa4\xbb\xdb\x6e\x9b\x3f\x7e\xb5\x60\x58\xa7\xcc\x8c\x52\xff\xc0\x41\x87\x0f\xdf\xdb\xf4\xfa\xbd\xec\xdc\xf7\x17\xef\x39\x60\x31\x7f\xc6\x09\xc3\x07\x2d\x7e\xbf\x69\x2a\xf1\xb6\xcc\xe3\x84\x07\xa3\x94\x21\x5c\x1e\x37\x1c\x72\x40\x22\xd1\xba\x2f\x95\xa1\x18\x11\xe8\x3a\x52\xcc\xd2\x36\x2d\x97\x9e\xab\x41\x03\x9d\x7a\xf5\xd3\x12\x34\xce\x8f\x50\xa5\x27\x19\x98\x1f\x44\x07\x15\x2e\xec\x15\xeb\x39\x97\xcd\x47\x52\x11\x33\x11\x2c\x90\x7d\x2e\x2a\x6d\x72\xb1\x4d\x74\xe0\x0c\x92\xb2\xa6\x2a\xd0\x54\xd2\xaa\xa2\xb4\x62\xd8\xfe\x0c\xbf\x2e\x70\xa3\x8e\xbd\x3d\x71\x55\x99\x5b\x51\x7e\x6d\x1c\xfd\xfc\xf0\xca\x01\xab\x87\xcf\xb9\xaa\xf3\x1d\x97\xbe\x75\x0c\xe5\x4f\xbd\xba\xef\xe4\xec\xec\xc9\xbd\xe7\xcc\xd0\xc5\x6e\xd4\x90\x95\xe7\xbe\x6b\x50\x4b\x8b\xde\xf7\x87\xee\x58\x38\xb0\x47\x35\x2a\xf8\xe9\xbe\xbf\x97\x85\x51\x43\x59\x25\x11\x3d\x40\x10\x00\xe0\xfe\x29\x64\x40\x0e\xac\xd5\x56\x0e\x60\x6b\x94\x08\x5a\xdc\x92\x96\x41\xe3\x39\x82\xba\xb3\x85\xe9\xf3\x53\xf9\xf3\x6a\xa6\xef\x42\xd5\x3d\x9e\xed\x4d\x49\x63\x7d\x75\x76\x96\x49\x22\x9a\x98\xae\xd9\xc2\xb8\x99\xd6\x17\xcc\x56\x93\x14\x4f\xa7\x42\x9b\x6e\x33\x49\x72\x2e\x49\xeb\xbc\x34\x20\x01\xd9\xe9\x23\x11\x60\x76\x8c\xb2\x96\x8d\x61\x70\xe0\x1c\x2d\x90\x12\x75\x5f\xa0\x71\x55\x33\x8a\xfa\x87\x00\xda\x1b\x5d\x3b\xe1\xe9\xd7\x56\x37\x7d\x7c\x6b\x6d\x4d\x8f\x89\xb9\xb7\x36\x7d\x7c\x2f\xb1\x8a\x0f\x0f\x19\xf3\x75\xa3\x32\x84\x06\x53\xcf\xdd\x7a\x65\x49\x71\xd3\x1e\x9a\xea\xdc\x42\xed\x4b\x11\x00\x73\x9d\x90\x41\x57\xa3\xd5\xb6\xee\x24\x24\xd2\x4a\xc2\x40\xea\xcc\x09\xa7\xd3\xc2\xd8\xd8\x80\xcd\x5a\x63\x83\x35\xd2\x7e\x3f\x61\x7d\xb5\x51\x30\x49\x04\xdd\x56\x5d\x85\x7a\xfa\x95\x89\x2a\x82\xee\x22\xb4\x6f\x75\xd3\x1b\xf7\xa2\x7c\x76\x15\x3e\xff\x37\x2a\x77\x9b\xd0\x47\x5f\x7c\x41\x7c\xcf\x31\x65\x08\x3a\x23\x64\x80\x08\x6e\xe8\x03\x71\x33\x19\x83\x89\x44\xa6\x61\x1a\xb8\x70\x76\xaa\x3c\x24\x4f\x21\x23\xf2\xd0\xf8\xc5\x11\x91\xad\x7c\x12\xbb\x5a\xf6\x9b\x11\x49\x84\xce\x65\xac\x26\x3d\x34\x83\x12\x69\x97\x39\x09\x47\x83\x69\x9e\x4e\xbe\x6e\xbd\xeb\xd0\xbe\x77\xea\x3b\xf4\xdd\x8b\xf2\x95\x49\xc7\x04\x61\xcc\x38\x76\xad\x1f\x9f\x7b\xec\xd5\x0f\x8d\xc2\x99\xcf\x3e\x83\x66\x99\x78\x51\xc8\x80\x2c\xb8\x5a\xb3\x46\x38\x2d\x2a\x67\x70\xc9\xb8\xcd\xee\x26\x32\x61\x20\x03\x14\x68\x51\xb6\x59\x2c\x7c\x61\x9c\xd9\xec\x11\x5d\x99\xd4\xbd\x78\x4c\x52\x3c\x93\x3a\xc7\x4c\x4a\xa4\x4c\xaf\x49\xd2\x4a\x4a\x42\x86\xe8\x88\xb3\x8e\xcc\x58\x2c\xa6\x11\x2c\x4b\x27\x58\xb4\x8a\x86\xcc\xac\x16\xf3\xb3\x7a\x63\x1c\x61\x74\xef\x6d\x97\x31\xae\xa5\x6f\x20\xf1\x1a\xc5\xda\x7d\xeb\x2d\x3a\xa7\xcf\x2f\xfe\xc1\x86\x71\x8e\xf2\x9b\x32\xd3\xbb\x6b\x97\x19\x59\xff\xd5\xcc\x67\x8a\x07\x33\x97\xf2\x79\x70\x2b\x2e\x37\x0f\xfa\xbf\xb4\x89\xea\x6c\x6d\xdb\x2c\x1a\x6c\x96\xbe\x7d\xc4\xa8\xf0\xb3\xa9\x61\xa7\x4f\xd5\xf2\xbf\xd1\xdc\x70\x88\xc2\x21\x88\x77\xa6\x39\x46\x5e\x34\x2a\x97\x71\xc9\x84\xe8\x0a\xe6\x77\xca\xf7\x6a\x3a\x45\xd4\xac\x03\x9b\xc4\x99\x17\x64\x0e\xe1\xf2\x30\x8e\x34\xc8\xa5\x7c\x32\x5e\x1a\x21\x83\x28\x0d\x9b\xa4\x78\xa4\x94\x1c\x46\x3a\x9b\x24\x5c\x6a\x97\x0b\x90\x24\x07\xf8\x64\x3c\x50\xd0\x5c\x20\x2a\xa0\x05\xa2\x82\x90\x49\xc2\x01\xad\xd1\x94\xce\x5c\x50\xfb\x69\x27\xb9\xb7\xdb\x9e\xb2\xad\x72\x05\x92\xe4\xd2\x08\x09\x42\x98\x18\x9d\xf4\x16\x62\x38\xe0\xc0\x26\x1a\xa2\x59\x33\x89\xf3\xe8\x50\x46\xec\x57\x44\x8b\x51\xa2\x31\x8c\x1c\x32\x6b\xd2\xf2\xf3\x20\x6d\x8d\xf3\x78\xdb\xd1\x48\x57\xfb\x1a\x9a\x83\x76\x58\xcb\x37\x5e\x31\x7b\x6d\x61\xe4\xf1\xab\x1f\x7f\xe1\xde\xa6\x8f\x6e\x1d\x39\xa2\xe7\x44\x1f\xb3\xa8\xe9\xe7\x45\x23\x47\x76\xab\xcd\x21\x8c\x64\x57\xe1\xfb\x87\x8f\x9d\x34\x79\xfc\xf4\xaf\x4e\x28\x3d\xa9\xd6\xbe\x71\xd3\xd4\xaa\x32\xa7\x2f\x4d\x11\xb4\x8f\x8b\x67\x94\x76\x68\x7a\x5e\xd3\x9b\x94\x8c\xfe\x41\xed\xf5\xba\xff\x68\xb7\x5a\x50\xb7\xd9\x72\xb5\x63\xb6\xfe\x67\x83\xe5\xcd\x4e\x11\x2f\x5d\x6c\x63\xb8\x40\xc4\x39\x84\x5c\x29\x31\x69\x8f\x4c\xcd\xa2\xb3\xc3\x56\xf9\xd8\xf4\x27\x9f\x5f\xdd\xf4\xf1\x2d\x35\xb5\x5d\x27\xe5\x2e\x6a\xfa\x7c\x35\xbb\x0a\x6f\x18\x33\xe9\x83\x2f\x95\x0e\x14\xe7\x86\xb9\x13\xc3\x52\xd3\xcb\x29\x9c\xb5\xfe\xb3\xee\xdc\xf0\x8b\x6b\xd3\xe8\xff\xd6\x9f\x4d\xc3\x37\xc8\x41\xb4\xc3\xb1\xa0\xd5\x0a\x94\x5e\x28\xfd\xa7\xb3\x28\x5d\xf9\xf9\xc7\x9f\x95\x9f\x51\xfe\xec\x85\x0b\xae\xbc\xea\xda\x6b\x67\x33\x0e\xf7\x2f\xa8\x42\x79\xef\x57\xf7\x6f\xca\xfb\x28\xfa\xdb\xda\xfa\xc4\xdf\xdc\x6b\xf6\xec\x59\x43\xed\x69\x07\x65\x2a\xb7\x8e\x1b\x0e\x5e\x28\x80\x15\xa0\x85\xcd\xbe\x54\xd8\x9c\xd7\x82\x07\xb4\xa5\x84\x4b\x62\x47\x84\x36\x6f\x78\xb4\x59\xdc\x8c\x48\x5c\xa4\x0b\xc9\x44\xa7\x49\x8a\x7b\x68\xda\xe1\x71\x99\x24\x2c\x6a\x9d\x84\xa9\xfe\x0d\xd1\x93\x22\xbd\x5f\x94\x6d\x02\x91\x55\x9b\x5b\x74\xc8\xa2\x27\x16\xc3\x3e\x11\xdb\x63\xb2\x00\x62\x6b\xf2\x37\xc7\xd5\xa9\x1c\xbc\x55\x6c\xdd\x01\x6d\x4b\xeb\xbc\xa2\xf6\xed\xa3\x47\xdf\x1a\xbb\x3c\x7c\x2f\xb1\xcf\x21\xdf\xe4\x7e\x57\xcd\x98\x75\x65\x9f\xc9\x3e\x76\x15\xbe\x75\xc0\x50\xe5\x4d\x15\xdc\x67\x95\x2f\x7b\xf5\x50\xde\xf2\x63\xec\xe7\x7a\x36\xbd\xd2\xa9\xf3\xd6\xfb\xdc\x8f\xbc\x5a\x19\xd1\xe7\x0c\x94\xa9\x5c\x1d\x37\x1c\xdc\x10\x82\xa5\xfa\x4c\x63\x66\xab\xd8\x21\xa0\xc5\x0e\x69\x5c\x12\x5b\x22\x08\xe7\x53\x36\x79\xf8\x24\xf6\x50\x99\xc3\xd9\x91\xff\x20\x76\x44\xe5\xd3\x09\xee\x9c\x33\x16\xc3\x66\x91\x46\x12\x4e\xc2\x50\x73\x7a\x2c\x26\x07\x6c\x5a\x92\x71\x71\x2c\xa1\xa1\xdc\x7e\xd0\x5a\xb3\xb2\xcc\xdb\x44\xcc\x57\xe7\xdb\x47\xeb\x21\xeb\xa4\x9c\x9c\x89\x17\x42\xd6\xe1\x97\xdc\xf1\xe7\x6f\x04\x61\x54\xd9\xbd\x07\xca\x3f\x7b\xff\x96\x70\x27\xf4\x75\xe7\xf2\xbd\x8f\x52\xdb\x3a\x00\x80\x1d\x40\x71\x9e\xad\x65\x4b\xb2\x53\x9b\x81\x10\xf4\xfe\x3d\x3f\x27\xb5\xd0\x3d\x4f\x18\xbb\xe8\xcc\x43\x3c\xdd\xd5\x3c\xed\xe0\x4a\x4f\x95\x07\x69\x35\x25\xdd\xa5\xf3\x17\x64\x8b\x53\x0b\x60\x41\xc4\xee\x8b\x55\xca\xcb\x16\x5d\x50\xa5\x01\x68\x87\xad\x70\xf1\x08\x6f\x54\xcc\x5d\x5c\x7d\xa9\x67\x75\xd3\x7e\xa2\x47\x8f\x5d\x3a\xc5\xc0\x2b\x7f\xb0\x91\x4e\x4d\xbf\xe8\x0a\x44\x6b\xd0\xec\xe7\xdc\x50\xe8\x00\x77\x69\x31\x6a\x22\xc8\x41\x39\x27\xc5\x83\x74\x9a\x3c\x98\x63\x92\xe2\x2c\x19\xbe\x55\xfb\xda\x4a\x3d\x81\xd5\x48\x32\xa2\x8e\x5a\x59\x56\xb8\x50\x98\x36\xeb\x85\x69\x10\x1d\xf5\xbe\x6c\x7f\x31\x09\xf3\xf2\xc5\xdd\x6c\x8b\xe2\x74\xbd\x60\x72\x1a\x68\x65\xe8\x42\x75\x5a\x06\x77\xac\x45\x69\xba\xb2\x65\x22\xd5\xbc\x76\x2e\x94\x57\x18\x46\x2d\x4a\xd3\x9d\xd0\xb4\xe3\x1f\xde\xfa\x75\x35\xbb\x3f\xd7\x3f\xb1\x6a\xd8\x84\x71\xb7\xbf\xfd\xfa\xb9\xf7\x6f\xf9\x68\x14\xfb\x5e\x71\xd6\x84\xb2\xda\xc9\x53\x6e\xdd\xfb\x06\xa3\xae\x3c\xd0\xaf\x42\xf9\xf5\xae\x8c\x40\xff\xf2\xb2\xde\x99\xc5\x1b\x56\x3e\xf8\xc2\xa0\x7e\xbf\xde\xeb\x71\x57\x57\x75\x1e\xe0\x2b\x7a\x04\x10\x94\xa8\x8d\xcc\x07\x7c\x5f\xf0\xc2\x54\x5d\x52\xad\xba\x82\x62\x5e\x0b\xd2\x0d\x91\xd4\x42\x1b\x8e\x20\x9e\x41\xf4\x94\x2e\xb4\xe1\xb5\x85\x36\x9e\xe6\x85\x36\x1e\x3a\x57\xe7\x01\x6d\x82\x0e\x64\xab\x53\x93\x44\x10\x71\xba\x16\x9c\x8b\xb4\xbb\x5d\xab\xe8\x6a\x29\x47\x61\x85\x58\xb2\x09\x85\x5e\x7d\xb5\xbc\xc4\x5f\x9a\x9d\x59\x36\xb5\xcb\xfa\xbf\xb3\x73\xdf\x47\x26\xe5\x9f\xef\x37\x7d\xd6\xab\x92\x17\x3e\x49\x4f\xdf\x9a\x60\x8a\x01\x41\x50\x6d\xe4\xde\xe1\xba\x82\x0f\x6e\xd4\xb3\x22\x03\x9b\xd4\x84\x4d\xe4\xf4\x41\xdb\x68\xd5\x8e\x4e\xbc\x6a\x85\x69\x8e\x4f\xc6\xb3\xb8\xe6\x6a\x34\x67\x97\xcd\xba\x47\x34\xdb\x53\xda\x45\x4d\xa2\x99\xa3\x25\x68\x6c\x17\xf5\xac\x49\x74\x68\x42\x67\xa0\x6d\x61\x40\xf8\xa5\x15\xa5\xf5\xf1\xb7\xce\x03\x0b\x2b\xc4\xe0\x0d\x28\x7f\xc4\xf0\xfe\x33\x03\x4b\x97\xa2\xfc\x65\xca\x2d\xce\xf2\x47\xa6\xef\x78\x9d\x5d\x85\x9b\x16\x2c\xba\xa2\xb4\x23\x33\xd0\x4f\x43\xbd\xbb\x87\x8e\xfe\xe2\x7b\xb4\x57\x8b\xad\x72\x01\xb8\x05\x5c\xd7\x96\x35\x69\xf4\xbf\xd6\xa4\x9d\xde\xe8\x85\x4a\x6e\x2e\x6a\x9c\x75\xbf\x53\x70\xdf\x3b\x1b\x35\x4e\x51\x5e\x53\x92\xca\x3e\x76\x15\xc6\x4e\x25\x7b\xd6\x2c\xf4\x8d\x0b\xe3\xf4\xf3\x77\xb2\x37\xd1\x67\x16\x01\x08\xfd\xb9\xae\xe0\x85\x4a\xad\x26\x8d\xc5\xa8\xa6\x9b\x06\x5b\xbb\xf5\x68\x90\xc1\x23\x3a\xea\x79\xc1\xe4\xd4\x56\xe7\xe9\xe5\xcc\x68\xaa\xa4\xc9\x86\xe8\x5f\x11\x3a\x7d\xdd\x2c\xe1\x9d\xfd\xef\x09\x33\x17\xa2\xd3\x73\x4f\xfc\xf6\xb6\xf0\xf6\xaf\xdf\x90\x61\x78\x14\x91\xd9\xdd\x34\x08\x9d\xf5\x62\x9c\x76\x7e\x39\xb3\xbc\xe9\x66\xf6\xe6\x94\xdf\x5e\x45\x79\xda\xbb\xfd\xfa\x31\x6a\xaf\x7e\xac\x25\x7f\x3c\x12\x1d\xbb\x4d\x66\x8b\x37\xa3\x79\xa2\x5b\x2f\x15\x7b\xab\x5a\x96\x8a\x8b\x0c\x5e\x77\x60\x26\x2a\x54\xbe\x9d\x89\xbe\x9f\xf1\xe4\xe6\x99\x28\x39\x5d\x39\x8d\x0a\x66\x29\xe2\x8c\x6d\x3b\xc6\xef\xb2\xa3\xcb\xd1\x38\x11\x6f\xb7\x1e\x3a\x64\xdd\x8e\x45\xe5\x69\xa5\xce\xbe\x6b\x9b\xf5\xf3\x2f\x2c\xdb\x28\xbd\xb2\x94\x21\xdc\x26\xae\x2b\xe4\x10\x7a\x51\xf6\x98\x75\x2a\x99\xac\x91\x48\x04\x8b\x61\xcd\xdb\xfa\xc3\x5a\x13\x0d\x5d\xfb\x49\xad\x95\x6c\xb0\xc5\x9a\xe9\x95\x8b\x74\x66\x51\x71\xd1\x73\xba\x5e\x08\x65\x31\x8e\x1b\xd7\xa6\x0b\x3b\x96\x30\x8e\x99\xca\xb5\xe1\x8d\x8f\x15\xf4\x2e\xc9\x4b\xf3\x5b\x06\x0d\x77\x07\x95\xed\x84\x7a\x2e\x65\xe4\x70\x84\x54\xc2\xc4\x73\xdf\x5c\xff\x98\xd5\xf2\x0f\x86\x1b\x58\x31\x9a\xb2\x13\x10\xd4\x00\xb0\x5f\x70\x5d\xc1\x06\x8b\x5b\xd4\x85\x69\xdb\x84\x45\x5b\x8f\x44\x3d\x2f\xab\xbb\xe0\x04\xaf\xaf\x23\xa0\x95\x61\x99\x33\x24\xe3\x1c\x4f\x54\x81\x33\x6a\x0a\xa2\x57\x88\xe3\x16\x9a\x49\x58\x40\x4b\x65\x64\x0b\x27\x3a\x68\x99\xf8\x2f\x8b\xc3\xa2\x56\x1c\x16\x6b\x18\x56\xf9\xa7\xe5\x38\x3b\xbd\xe9\xdf\xa8\x93\xf5\xd8\x33\xcc\x33\xf7\xa3\x05\x4f\x35\x0d\x5b\xa3\xac\xa1\xf2\xa7\x3c\xcc\xdc\x28\xf4\x00\x3f\x44\x53\xeb\x26\x69\xff\xa6\xd6\xc3\xcc\x45\x64\x97\x91\x68\x30\x6d\x72\x70\xf9\xa8\x0d\x01\x19\x01\x3d\x20\xc4\xa4\x0e\x9b\xda\x8f\x1c\xd4\x3c\x61\x49\x32\x7e\x3a\x5d\x39\x71\xfc\x96\x37\xba\x8c\xeb\x3f\x61\xc2\x84\x09\xfd\xc7\x75\x79\x63\xcb\x78\x46\x78\x7b\xee\xcc\x77\x77\xfc\x54\xb5\x31\x77\xd3\xa2\x77\x67\x6f\x2e\x0d\x6f\x9e\xf5\xee\xa2\x4d\xb9\x8f\x55\x9d\xdd\xf1\xee\x8c\x79\x1a\x0d\x97\x2b\xbf\xa0\x28\xad\x29\xe7\x5d\x58\x1b\x87\xa1\x21\xc1\xd2\xfe\x62\xfd\x2d\x55\x64\x16\xa3\xe2\xf2\x5d\xca\x2f\xc2\xab\xff\xee\x43\xeb\xcb\x0f\x33\x93\x52\xf8\x78\xc3\x09\xcf\x05\x7c\x58\x9a\x2b\xfa\x8c\x24\xc6\xa1\xf8\xf8\x58\x51\x4b\xfd\x3d\x5e\x51\x6b\xcd\xf4\xf6\x44\x14\x1d\x7d\xf8\x55\x1a\x3a\x51\x37\xad\xa3\x09\x06\xcb\xa5\x03\x26\x4d\x99\x32\x69\xc0\xa5\x5d\x5e\xdf\x3a\x6e\xe2\xc4\x71\x5b\x5f\x7f\x87\xa2\xf1\x78\x69\xe9\xe6\x2b\x09\x1a\x1b\xab\x7e\xda\xf1\xee\xcc\xb9\x6f\xcf\x9b\xf1\xee\x8e\xb3\x55\x04\x97\xcb\xd1\x12\xee\x55\x36\x06\x99\x30\x0c\xb0\x27\x4c\x18\x5f\x6f\x62\x3d\x46\x5a\x45\x42\x38\x8b\xba\xae\x4c\x53\x12\x67\x6a\x33\x8a\x36\x53\x52\xf6\x11\x9e\x67\xea\xd5\x48\x90\x3d\x76\xd1\x21\x43\x66\x2c\x26\xb3\x26\xd1\x21\x5b\x6d\xb1\x0b\xde\x49\xf3\x42\x5e\xea\x95\x74\x3f\x75\xf9\xce\xbb\xc7\xac\x1f\x52\x36\x54\x8a\x0e\x7e\x47\xbe\x6b\xec\x9a\xe1\x91\xa1\x25\xe5\x97\xa0\x7d\x4f\x1c\xee\xdb\xa7\xb4\x68\xf6\x20\xdf\xe6\x2f\x7a\x0d\x28\x29\x9e\x35\x90\xc6\x47\x77\x28\xab\xd0\x53\x5c\x57\xda\x47\xdf\x01\x68\x59\x2b\xc1\xe9\x1d\xfe\x6d\xb7\x58\x60\xf5\x2d\x16\xb4\x29\x4c\x24\x06\xc5\x3b\x50\x81\xf2\x05\x2a\x50\x56\xb1\x2f\x9c\x1f\xc8\xed\x42\x48\x51\x01\xc1\x48\xd5\xc2\x01\x5f\x08\xf9\x70\x25\xe0\x60\x38\xe1\xd5\xd6\xc7\xdb\x53\x2b\xe5\x53\x35\x41\xbd\x67\x20\xa8\xd5\xa6\x03\x26\xf2\x90\x78\x20\x48\x93\x27\xb3\x5e\x16\x0c\x04\x49\xc6\xe3\xa5\xad\x03\xe4\x30\x37\x2f\x46\xdc\x42\xdc\x92\x95\x1d\x8b\xc5\x30\xef\x90\x39\xb3\xa6\xd6\xe5\x0e\x6d\xb1\x7b\x3b\xa5\x4f\x0f\x5d\xf0\x5e\xc8\x8c\x3c\xf8\xd2\xc1\x39\xcf\x74\x6f\x55\xfa\x34\xb1\xec\x3b\x8f\x1d\x7c\xf9\x2d\xc6\xe6\x7f\x17\x85\x8a\x4f\x7e\x61\x1e\xd2\xa3\x55\xf9\x73\xcd\x27\xde\xef\x1b\xf3\x51\x48\x5f\x7b\x07\xc0\x4d\xe6\x0f\x40\x3e\x24\x20\xee\x27\xfa\x9d\xab\x65\x8a\xe4\x38\xe1\xd3\x55\x5c\x9f\x43\x8e\xa7\x09\xa9\x46\xa1\x04\x20\xbf\x60\x93\xb0\x43\x73\xe4\xae\x08\x25\x02\xd3\x20\x3b\xf8\x64\x9c\x71\xa4\xda\x08\xea\xab\x19\xbf\x49\xc2\x8c\x1d\x87\x02\x0d\x22\x09\x43\xe3\x9e\x50\x73\xd0\xed\xb0\x53\xd9\xc8\x36\x24\x71\xb6\xde\x47\x6d\x31\xd3\x55\x17\x66\x73\x92\x92\xcb\x13\xd2\xfa\x90\x2c\xa2\x2c\xa4\xc5\x68\x6d\x2b\x2b\xa6\xb7\x89\xe8\x45\xb9\x22\x2a\x39\xcd\x5b\x02\x78\x83\xee\xa0\xd7\x25\x18\xb4\x25\x8a\xd1\x9e\xa8\xa2\x28\xb6\xc1\xf8\xf3\x3b\x87\x7f\xe0\x18\xe5\x9b\x49\x03\x06\x8e\x34\xa3\xcb\x95\xad\x5c\xf7\x2e\xe8\x98\xf5\xd8\x79\x9f\x39\x1c\xe6\x98\xa1\x5f\x37\x7c\x7c\xf6\xd8\x73\xc2\xd4\x89\x8b\xe6\x34\x7c\x3d\x76\xf8\x9a\xd8\x1a\x65\xcd\x71\xeb\x96\xda\xe9\x44\xa6\x46\xab\x27\xf9\x7e\xdc\xcf\x74\x95\xd2\x6d\x7a\x65\xdb\x17\x8a\x46\xe5\x22\x2e\x89\x4b\xc3\xb2\x8d\xd3\x56\x27\x71\x0d\x89\x7c\x6d\x0b\x04\x6d\x86\x22\xe1\xd1\x14\x9b\xae\x43\xe2\x44\x47\x3d\x32\x98\x42\x24\x5a\xeb\x28\xd6\x9b\xed\x74\x0b\x04\xec\x71\xd4\x8b\xce\x4c\x1f\x0d\xdc\x8a\x72\x45\x47\x7d\x16\x68\x27\x4a\xc5\x7a\x64\x70\x12\xe7\x83\x6d\x8e\x7a\xa3\xd9\xee\xa0\x7e\xa8\x17\xd2\xf6\x41\x28\xaa\xd2\xe3\xd3\x2a\xaf\x41\xdb\x02\xc1\x6b\xd0\x62\x85\x22\x43\xcb\xa5\x49\xa3\xef\x2a\x8b\x76\xa9\x58\x73\xef\x7d\x83\xf1\xb4\xa9\xf1\x21\x0f\xdc\xb7\x36\xda\x25\x1a\xbe\xe7\xbe\xe5\xc3\x5e\xb8\x7c\xe6\xf3\x43\x6e\x1f\xf1\xd3\x8e\xa7\x7f\xfa\xe9\xe9\x1d\x3f\x2d\xba\x7b\x68\xfd\xf4\x99\x2f\x8c\xf8\xdb\x9a\x07\xaa\xba\xf7\xe8\xb2\xf6\x81\xf5\xc3\x9f\xbb\x7c\x9a\x3c\xe4\xde\x07\x56\xf4\xe8\xd3\xbb\xc7\x72\x66\xc9\xf3\xaa\xf2\xc2\x73\x8a\xa2\xc9\x4d\x07\x00\xbe\x96\xc7\x10\x82\x47\xda\xd4\x60\x2f\x9a\xdf\x4c\x64\xe7\x64\x20\x1b\x2d\xcc\x66\x73\x49\xec\x8c\x24\x02\x41\xfa\x85\x2d\x2a\x07\xe8\xa4\x28\xcd\x52\xb2\x1a\xb0\xbf\x6d\x89\x36\x9d\x08\x49\xa4\x75\x95\x36\x40\x5b\x51\xf5\x42\x2d\xc9\x57\xdc\x59\x6d\x66\x46\x83\xed\xce\x8c\x46\xdd\x41\xfa\xa7\x2f\x7f\xd4\xfe\x50\x07\x26\xa3\xdf\x6b\xc2\x6b\xfd\x98\x8c\xad\xca\x99\xdf\x94\x97\x51\x3f\xe5\xe5\xd5\x4d\xbb\x37\x28\x3b\xd1\x18\x65\x27\xb2\x28\x67\x78\xc0\xd8\xa6\x4c\x41\x4f\xd8\x30\xf6\x34\x9d\xdf\x72\xcb\x93\x63\x48\x94\x3f\xe6\xc9\x5b\xb6\x30\xda\x4e\x4e\x2b\x94\x5f\xd0\x3d\xfa\xde\x2e\x79\x70\xd1\x7e\x2e\x46\xcd\xd8\x18\xdb\x1a\x9b\x15\x88\x57\xce\x21\x5e\xf9\x85\xf5\x9d\x3f\xc9\x1e\x64\xfe\x68\x32\x6b\x39\xde\x58\x25\xca\xad\xe5\x0f\x40\x14\xfa\xc3\x3a\xd0\x16\xc3\x91\xdc\x5b\xef\x57\x4b\x33\x49\x38\x14\x96\x25\x62\x6f\x07\xd0\xa7\x14\x46\xe4\x72\x3e\x89\x8b\x23\xda\xca\x38\x62\x87\xca\xed\x72\x27\x24\xe1\xb4\x08\xed\xf2\xb1\x46\x70\xc0\x8e\xb3\xc8\xc9\x1e\xe6\x24\xee\x11\x96\xb3\xcc\x49\x79\x20\xf1\x81\x02\xb1\xcb\x91\x58\x0c\x77\x12\xab\xcd\xa2\xc9\x1b\x92\xca\x62\x5d\xab\xfb\x12\xb9\x0b\x38\xe4\x0c\xda\xfa\x2f\x4a\xa2\x63\x8f\x60\x0d\x14\x16\x77\xed\xdb\x6a\x0b\x85\xfc\x68\x84\xbb\x78\x33\x8e\x54\xc7\x4b\x2f\x54\xd0\x62\xf7\x8e\x02\x7a\xde\x4b\x97\xfd\x14\xd1\x69\xb6\xb1\x97\x8e\xec\xdf\x1f\xf9\x7e\xf8\x0d\x39\x78\x46\xf9\xee\xc6\xab\xaf\x5d\x70\x0d\xfe\xe7\xe9\x4b\x47\xf4\xeb\xaf\x7c\xff\xc3\x29\xe5\x1d\x9e\x41\x59\x0f\x5c\x3d\xe7\x86\x1b\xb7\xff\x7e\x1a\xe5\xcf\x93\xf3\xfa\x87\x8a\xa4\x9b\xb7\x17\xf7\xcb\x2d\x2c\x60\x32\x6a\x56\x95\x46\xee\x9d\xfe\xcc\x47\x47\x0f\x0a\x35\xd7\x8d\xef\x3b\x64\x58\xe7\xea\x97\x9e\x99\xb8\x52\x8a\xde\x3b\x4d\x3e\xf8\xd6\xe7\x02\xba\x6a\xd2\x98\xbe\x7d\x47\x45\xaa\x5f\x7a\x73\xd4\xe8\x72\xb3\xcb\xe2\x19\xdc\x79\xe0\x84\x72\xb3\xc7\xe2\x19\x4c\xe9\xbc\x86\xfb\x96\xbd\xff\xc2\x9e\x3c\x54\x72\xf5\xc4\x84\xd3\x1b\x67\xa0\x79\x46\x99\xf2\x91\xd5\xba\x60\x0c\x17\x78\x59\x11\x74\x47\x2b\x82\xee\x35\xc8\x92\x44\x16\xee\xdb\xf7\xde\x7b\xef\x3d\x3a\xcb\x3a\x58\x6d\xe4\x1b\xf8\xfd\x60\x01\x2f\x54\xc0\x2e\x7d\x55\x52\x3a\x07\x69\xfa\x2a\xab\x84\x9b\x1e\x27\xa2\x92\x89\xb5\x49\x89\xa8\x76\x46\x8a\x12\x16\x4b\x61\x93\x94\xc8\xce\xa7\x27\xb2\xb5\x13\xf9\xb4\x8c\x94\x1f\x20\x69\x52\x25\x0d\x1e\xb4\xcd\x6d\xb0\x95\x36\x61\x27\x8a\xb5\x4f\xc5\x1a\xdb\x83\x91\x44\x67\xed\x8b\xdc\x08\xee\x6c\x97\x1d\x17\x16\x33\x55\x21\x49\xee\x54\x2c\x3a\xf6\x98\xd2\xdd\x6c\x7e\x76\x94\xaa\x4c\xbe\x24\x3a\x76\x0b\x56\x47\x2e\xe8\x5b\x64\x68\xbd\x6c\xf4\xd5\x49\x57\xd8\x8b\x74\x81\xbd\xbe\xe1\x48\x3a\x0a\x51\x96\xa7\x3c\x52\xd4\xeb\x21\x0e\x7b\x30\x7a\x0c\x15\xa3\x22\xb4\x49\x99\xaa\x7c\xae\x1c\x51\xa6\x2f\x41\xe3\x7f\xff\x0d\x8d\x57\xb6\xff\xf6\x87\xf2\xf4\xd7\xaf\x3c\xbe\x51\xe6\x98\xb5\x13\x26\x4c\xb9\xfc\xf2\x29\x13\x6a\xd7\x32\x1c\xde\xf8\xf8\x2b\xcc\x67\xa8\x1b\xc2\xca\x48\xe5\x80\xb2\x5f\x19\x8e\xe2\xa8\xbb\xf2\x2f\x65\x3d\xba\x12\x19\x91\x81\xee\x9d\xf0\xca\x0d\x3b\x1b\x36\xad\x13\xa6\x8c\x5d\xb5\x60\xf1\x75\x77\x8f\x99\x2a\xac\xdf\xf8\xa9\xa6\x27\x53\x98\x04\x73\x8e\x3f\x00\x01\x90\xe0\x76\xd0\xd6\x20\x1b\xe9\xba\x2f\xec\x0f\x27\xf2\x29\xe1\x70\x07\xba\xd4\x2b\x8d\x78\x69\x3a\x93\x92\x08\x6a\x84\x09\xda\x69\xa1\x87\xf3\x45\x22\xfa\x26\x36\x74\x46\x25\x08\x24\x24\x49\xa3\xab\x42\xe3\x16\xbb\x9f\xee\x26\xe2\xc0\x19\xfa\xba\x5e\xd9\xeb\x8b\xc5\x70\x07\x51\x76\xa5\x66\x94\xe3\x16\xab\xd6\x17\xda\x62\x56\xd9\x1d\x46\x85\x95\xfa\xa4\xb2\x37\x94\x9a\x52\xae\xba\x30\xa5\x3c\x65\xfb\x13\x77\x77\x8b\xf5\xb9\x64\x0b\x12\x9e\x5e\xbd\x62\xa3\x35\x4d\x36\x9a\xd9\xe0\x35\xc3\x6f\xb8\x63\x57\xd7\x6e\xd1\xab\xc5\x95\x83\xc7\xb0\x0f\x5f\xb3\x38\xda\xb3\x77\x79\xd8\x26\x4c\xbf\xe3\xbe\x15\xca\x9b\xd1\x9a\x8e\xee\x70\x56\xb8\xc7\x92\x79\x52\x69\xf7\xd0\x15\xd5\xda\xda\x26\x0e\x16\xb2\xd3\xd9\xbf\xd1\xfd\x99\xd3\x00\xaa\xc4\x0a\x14\x65\x9d\x21\xa7\xf6\xc6\xa1\x8c\x97\xce\x9e\x7d\xe9\x3a\xed\x6d\x21\x5a\xe1\x44\x2b\x94\xf9\xca\x82\xe6\x03\x6a\xcb\xaf\x45\x8b\xd8\xdd\x6c\x01\xf0\xd0\x19\xf4\x7a\x75\x6a\x2b\x0c\x9a\x96\x0b\x74\x65\x24\x6b\x4a\xc6\x39\x5a\xa5\xe0\x48\xd4\x6e\x68\xde\xee\x22\x24\x5e\xcb\xf6\x3d\xc8\x2c\xd9\xa1\x8c\x42\x1c\xe1\xcb\x85\xbd\x28\x38\x28\x6a\xbd\x1b\x05\x7f\x61\x37\x0a\x81\xa4\x33\x34\xf2\xe6\x74\x5b\x1d\x5c\xc6\x94\x37\xbd\x47\x37\xa6\xa0\xff\xef\x4e\x4b\x1d\x8a\x40\x37\xd8\xfb\xd7\x5a\x54\x16\xa5\xca\x52\xa6\x9d\x29\xa3\x5a\x54\x96\x61\x92\x70\x71\x24\x91\xd5\x8d\x9e\xcb\xd2\xa5\xa0\x7b\x3b\xda\x13\xd1\x3e\x45\x23\x38\x62\x97\x4b\x90\x84\xab\x22\x29\x57\x9e\x13\x49\xe9\x56\x7e\x2b\x3d\xea\x81\x24\xb9\x24\x22\x3a\xea\xa9\x1e\xd1\x7a\x0c\x0e\xc4\x40\x2e\x4b\x17\x1d\x38\x14\xc3\x51\x31\x21\x58\x1d\x10\x20\xa7\xba\xe9\x13\x4c\x7f\xa1\x55\x48\x0c\xd2\x9d\x68\x52\xd9\x86\x3b\xa4\xc5\xeb\x12\xca\x44\xa9\xde\xc8\xff\xac\x5b\xa8\x00\x65\xae\x7f\xb6\x6b\x97\xae\x15\x06\xf3\x06\x13\xd7\x77\xe8\x63\x2b\x07\x4e\x1f\x3e\xed\x8e\xff\xa6\x5c\x4d\x93\xd8\xd1\x2b\x6f\xed\x3a\x3e\xd7\x3f\x77\x70\x97\x0e\xbd\xdd\x76\xf7\xa8\x8e\x95\x03\xfb\x29\xbb\xd0\xe1\xee\x5d\x2e\xe9\x0a\x08\x1e\xe4\xad\xec\x5c\x5e\x06\x16\xfc\xa0\x9b\x44\x2e\xd9\x7c\xd0\xb2\x39\xa6\x22\xe8\x7e\x90\xf9\x82\xb7\x6e\xd9\x42\x64\xe0\x2a\xf6\x49\x66\x05\x7f\x80\xf2\x6e\x38\xb4\xe4\x15\x36\x85\x75\x0e\xd2\x82\x4f\x2b\x5e\xb4\xa0\x6f\x26\x92\x64\x87\x55\x74\xc8\x26\x96\xb8\x20\x77\xba\xe8\x90\x05\xb8\x90\x2a\xb8\x5b\xec\x69\xa4\x69\xdd\x55\x8f\xcf\x9f\xf7\xd8\xc6\x6b\x16\x6c\xfa\xdb\xa0\xf2\xf2\x01\x03\xa3\xe5\x83\xb8\xfa\xf9\x4f\x3c\x31\xff\xda\x8d\x8f\x2d\xa8\x18\x38\xa0\xb2\x72\xf0\x60\xcd\x6e\xf4\x01\xc4\x36\xf0\x7e\xb0\x40\x3a\x4c\x84\xb8\x15\xb4\xae\x04\x6d\x3b\x18\xba\xee\xf6\xaf\xf7\x82\xb1\x37\xef\x05\x63\xfc\x0f\x7b\xc1\x88\x17\xed\x05\x83\x2a\x82\xee\x3e\x68\x18\x02\x34\x50\x79\x41\x05\xe5\x14\xdb\x87\x79\xf7\x14\x9a\xa3\xac\x3b\xa5\xdc\x8e\x6e\x6b\xaa\xfc\xf6\x5b\xaa\x8b\x33\x99\x0d\xcc\x67\xfc\x5b\x90\x45\xf2\xab\xb4\x70\xc2\x42\x97\xa9\x62\x4f\x6a\xc1\x6a\xab\x85\xb9\x3e\xda\x37\x26\x98\x92\x71\x27\x0d\xcc\x9d\x69\xa9\x49\x2f\x4b\x9a\xe8\xc0\xe9\x31\xec\x11\x53\x44\x2b\x6c\xde\xee\x88\x44\xc8\x15\x05\xcd\x7b\x77\x84\x66\x0a\xf2\xda\x35\x1b\xe7\xdc\x3c\x97\x41\x13\x9a\x1e\x40\x95\xdd\x43\xe1\xb2\xaa\x2e\x6f\x73\x6f\x5d\xf5\xd0\x1d\x8b\x46\xdf\x72\xc5\x64\x61\xc3\x86\xf3\x91\xbe\x1d\x8a\x2a\xba\x87\xb5\x9a\x00\x73\x3f\xd3\xc8\xbf\x09\x1d\x89\xd5\xcd\x26\x9c\x75\x69\x63\xbb\xb0\x3d\x07\x2e\x0e\x27\x78\xed\xcb\x0b\xfb\x78\x60\x6b\x38\x61\xd3\x39\xaf\x6f\xd9\x61\x4a\x12\x0f\x55\x60\x97\x45\x53\x12\x8b\xe1\xb8\x48\xa7\x9a\x44\x9b\xbe\x6d\x47\xc1\xff\xb0\x6d\x47\xb4\xdd\x6d\x3b\x42\x45\x29\x84\x0d\xa9\x2a\x67\x0d\x73\xb0\x57\xf7\x2e\xfd\x06\xf4\x99\x3f\xbf\x67\xb7\x2e\x5d\xa2\x5d\x0e\x32\x02\x5e\xb1\x5e\x1e\xd8\x63\xe0\x90\xfa\x47\x1e\x78\x99\xbd\x45\xe8\x18\xee\x5c\x12\xa9\xbc\xb3\xac\x53\x61\xb4\x24\x57\x98\x79\xd3\x0d\xf3\xaa\x26\x66\x66\x5c\xd6\x6f\xfe\xcd\xb7\x00\x82\xd1\xdc\xcb\xcc\x48\xda\x0f\xd5\x01\x9a\x7b\x69\x2f\xee\x87\x92\x59\xe2\x43\x18\x6d\x02\xc4\x87\x82\x5e\x34\xfa\x2d\x54\xc1\x28\x67\xb8\x97\x91\x59\x50\xce\x6b\x6b\x94\x94\xa9\x7c\x01\xd7\x15\xb2\x61\xb5\xde\xbb\x69\x20\x11\x1e\x6d\xc7\xb8\xa8\xde\x88\x7d\x61\xba\xce\xc6\xa7\xad\xb3\x61\x23\x71\x1f\x8d\x8f\x7d\x60\x92\x70\x96\x56\x75\xa4\xf5\x6e\xad\x90\x6f\x27\xc2\xd8\x5c\xde\xd7\xe6\x35\xb2\xe8\x06\x1b\x38\x5d\x94\x1d\x4e\xda\xb6\xe1\x13\x1d\xb2\x33\x33\x46\x4b\x90\xe9\xb4\x04\x99\x7d\x51\x09\xb2\x45\x05\xb2\x48\x0c\x8a\x55\x75\x28\x54\x3b\x61\xe8\xe5\xd9\x75\x68\xef\xbd\xca\xe5\x42\xc9\x82\x7e\xd1\x71\x21\xe5\x2b\x76\x15\x6e\x5a\xbb\x6e\x4e\x55\x05\x13\xd1\xaa\x90\xfd\x4a\x4a\xdd\x1e\x65\x30\x6f\xd5\xf4\xad\x12\x80\x2b\xa7\xeb\x37\x1d\x70\x85\xb6\xfb\x04\x9d\x73\x16\x22\xd4\x67\x63\x36\x4a\x97\x73\xd2\xcd\x44\x1c\xc4\xa8\x38\xa9\x59\xe0\xac\x60\xe0\xb4\xaa\x2a\x9f\xc4\xe6\x70\xdc\x4c\x4b\xad\x66\xbd\x92\x94\x6e\x91\x12\x0e\xcd\x72\x08\x11\xd9\x45\x97\x76\x9a\x44\x87\xcc\xeb\x46\x02\xa2\xa9\xc9\x53\x62\x62\x2b\xa2\xee\x4a\xe2\x81\x6e\xd8\xd0\xb4\xa5\x6e\x4c\x52\x69\x62\x67\x6c\x60\xbf\xfc\x10\xf1\xda\xde\x3b\xa8\x1b\x62\xd1\xe1\x0f\x30\xe5\xcd\x03\x4c\x17\xb4\x9b\xed\x0e\xec\x85\xbd\xb7\x8a\xb9\xff\xbc\x19\x12\x89\xe9\x1f\x40\xf9\x4c\x17\xc4\x11\x06\x23\x18\xa3\x54\xa0\x23\x20\x40\x3a\x74\x07\xbd\x75\x88\xde\x4a\x17\x7f\x7b\x18\xdb\xb4\x6d\x9e\x44\x24\xe9\xad\x5a\x74\x36\x02\xcc\x5a\xd7\x24\xd2\xda\xe7\xbd\x55\x51\x5d\x7e\x8b\xa8\x68\x8f\xc9\xfd\xc2\x52\x3d\xee\xb9\x6d\x86\x68\xf7\xea\x95\xf7\xc5\x2c\xa3\x47\xce\x59\xba\xb9\x43\xc7\x0e\x41\xf2\xcc\x59\xcc\x23\xe8\x39\xfe\x00\xf0\xd0\x51\xeb\xd7\x6b\x9e\x7c\xfe\x8f\x1e\xbc\x40\x0c\x89\xb3\xd0\xa8\x8f\xf9\xf4\x4d\xde\xf3\x9f\x32\x8b\x28\xcf\xe6\x32\xf5\x6c\x9e\xbe\x36\xa5\x9f\xd6\x65\x99\xc8\xd0\x62\x2b\x4b\x38\x21\xea\x68\x64\xa7\xf6\xb9\xb3\xb4\xda\xe7\x8e\xd8\xef\x76\x66\x02\xff\x72\x2f\xba\xb9\x2f\x3f\xf6\xd8\x2b\x2f\x6f\xdc\xf4\xca\xae\x9a\xb1\xa3\x6b\x6a\xc7\x5c\x3a\x9e\x43\xd7\xaf\x7d\xe9\xa5\xb5\xd7\xaf\x7b\xe1\x85\x75\x63\xaf\xb8\x62\xec\xf5\x63\x66\xcf\x1e\x43\xe2\x9d\x6a\x58\xcf\x6e\x67\xf7\x80\xa0\xc7\x3b\x4e\x36\x8a\xdc\x28\x14\xd4\xde\xab\x7f\xfa\xe9\x25\x94\xa1\x9c\x7a\x09\x3d\xa4\x1f\xad\x47\xf7\xa3\x35\xca\x12\xa7\xb2\xa4\xf9\x80\xee\x48\x7f\x3d\x00\xbf\x89\xdf\x4f\x77\x98\x37\x83\x07\x7c\xb0\x59\xeb\xfe\xa2\xb5\x4d\xcd\x5f\x79\xbc\x2e\xd6\x26\xe1\xf4\x68\xc2\xa3\x59\x61\x31\x12\xf7\xd2\x29\x09\x2f\x31\x50\x0c\x4b\x37\x81\xa2\x04\xce\xd6\xca\x9d\xa6\x64\x9c\xe7\x9a\xcd\x1d\xa7\xcd\x8b\x5a\x33\x22\x11\xd9\x69\x4a\x92\x64\x2c\x27\xd5\x18\x6b\x8e\x61\x97\xb8\xdb\x68\xb2\x78\xbc\x5a\xf2\xef\x71\x69\xdf\x7a\x45\xd9\x62\x88\xc5\x30\x72\x24\x38\x93\x35\x8b\x76\xf4\x30\x5a\x93\x58\x54\xa4\xbc\x62\x91\x17\x15\xa0\x8a\x28\xdd\xcc\x27\x54\x11\xac\x8a\x8a\x45\x86\xeb\xd1\xa8\x8f\x39\x6d\x03\xbf\x3e\xe8\xa9\x4f\x66\xce\xfc\x44\x99\xf5\xce\x21\xc1\xc6\xa7\x69\x4c\x3d\x17\xa7\xdb\xf5\xad\x65\x3c\x8c\x62\xd8\x78\xcf\x3d\x1b\x11\x62\x5c\xc0\xc1\x2c\x00\xfe\x99\x66\x3a\x14\xc0\x56\x88\x67\x92\x18\x4b\xc3\xb8\x05\x31\x82\x69\x99\x24\x8a\x0a\x6a\x94\xe0\x22\xf1\x20\xed\x4f\x0e\x16\xb4\xa1\x44\xe1\x5f\x50\x82\x58\x21\xd1\x94\x8c\xfb\xe9\x9c\xab\x3f\xd3\x24\x69\xf1\x37\x31\xec\x06\x33\x9d\x68\xdd\x63\x34\x59\xd3\xdc\x9e\x02\x6d\x16\xcb\x23\x3a\xea\x0d\xa2\x25\x2b\xdf\x1b\x93\x51\x26\x09\x04\xc8\x55\xad\x49\xe1\x44\x5e\x13\xfa\x6b\xcf\x46\xa4\xda\xa4\x11\xe5\xe5\xf6\x9d\x5c\x1b\xf2\xa0\xe7\xda\xf7\x79\x3c\x0c\x02\x10\x26\xf0\x6f\x11\x7a\x40\x18\xba\x41\x35\x1c\x81\x78\x2c\x25\x2f\xb8\x5b\x18\x57\x46\x13\xdd\x35\xe2\x94\x47\x48\xd6\x21\x68\x14\x14\x3a\x10\x7c\x05\xc6\x24\x61\x5b\x38\x91\xa6\x85\x40\xee\xf0\xff\xa3\xed\x4b\xe0\xdb\xaa\xae\xbc\xcf\x7d\x8b\xf4\x64\xc9\xb2\xde\xb3\xb5\x78\xd1\xee\x25\xb6\x6c\xcb\x96\xbc\xc9\x76\x12\x2f\x89\xb3\x27\x40\x02\x24\x90\x06\x02\x59\x69\xf6\x04\x08\xcb\x40\x52\xa0\x6c\x0d\x93\xa6\x40\xcb\x32\xb4\x65\x18\x4a\x69\x0b\xef\x49\x0a\x74\x28\x94\xf6\x9b\x32\x13\x82\x4b\x29\xc3\xa4\xd0\x12\xa0\x50\x4a\x55\x28\xa5\x29\xf0\x51\x42\xe4\xef\x77\xcf\x7d\x4f\x96\x6d\xd9\x31\x9d\x7e\xc9\x4f\x79\x4f\x92\xfd\x72\xcf\xff\xdc\xe5\x9c\x7b\xcf\xf9\x9f\xb4\x97\x7d\xed\xf4\xe2\x46\x47\x39\x5d\xce\xfb\xa3\xaa\xe5\x98\x56\x6b\xc9\xa8\x81\x98\x5a\xeb\xd0\x14\x4b\x46\x55\xa2\x49\xa5\x16\x63\x3e\xa9\xdb\x5f\xeb\xd0\x12\x24\xa2\xb5\xce\x8c\xc5\xb4\x2e\x4b\x46\x8d\xc7\xb4\x01\x12\xd1\x6a\xe9\xbc\x17\x8e\x26\x12\x6a\x42\x3e\xdc\xd4\xdc\xd2\xd3\xdb\x87\x18\xf6\xf6\xc8\x8a\xd6\xd2\xc8\x3c\x96\xd9\x7d\x89\x84\x6a\x52\x52\x91\xd6\x58\x1c\x77\x95\x64\x8d\xd4\x26\x12\xaa\x1d\xcd\x55\xa7\x9c\xac\x08\x34\xb3\x04\xb7\xcf\xb1\xa6\x5a\x0a\xf5\xc5\x05\xa6\xd3\xac\xb4\xe4\x5a\xa6\x94\x9a\xfc\x9e\xca\x5f\x33\xd5\xf2\x7b\x2a\x55\xa8\xff\x72\xd0\x94\xbd\x8c\x7f\x55\xe8\x46\x2e\x93\x0d\x90\xac\x22\x6c\xd7\xb2\x55\x88\xa8\x9e\x28\x46\x36\x3a\xf0\xc0\xd5\x51\xaa\x33\x99\xc0\x31\xad\x58\xcc\xa8\xc5\xb8\xf5\x48\x57\x0e\x1f\x63\x91\x09\x90\x88\xc1\x67\xa4\x56\xca\xaa\x90\x50\x7d\x4a\xd2\xea\xf0\x60\xc0\x7a\xa5\x03\x99\x4c\x18\x11\x5a\x67\x5b\x47\xe7\x2c\xd2\x1e\xb4\x13\xb3\x9d\x38\xd9\x62\x19\x74\xbb\x84\x70\xa8\x96\x5a\x79\x4d\xb7\xef\xec\xad\x23\x61\xee\xcc\xcb\xe7\x9f\xbd\xf6\xfc\x05\x1b\x78\x52\xc9\x71\xd9\x53\xcf\xbf\x99\x25\x1b\x48\x6d\xe5\x3f\xbd\xbc\xa8\xe9\x82\xb3\x0f\x5c\xb7\xba\xfb\xc6\xb3\xce\xdb\x74\xce\xd9\xa6\xa7\x9f\x7b\x93\x7f\xe7\xe4\x49\xb4\x2a\x40\xfc\xba\xb9\x01\x4a\xc0\x01\x4e\x28\x87\xa1\x82\xdc\x19\x8e\xdc\x90\xb4\xb9\x46\x09\x34\x2a\xa2\x54\x9e\x31\x04\x1a\x2e\x8c\xfb\x9b\x48\xa0\x11\x24\x9d\xc1\xd2\x30\x5f\x88\x46\x23\xeb\x20\xcb\x30\x8a\x7b\xd9\x44\x3e\x0d\x73\xb5\x29\xfb\xf1\x67\x7d\x48\xaa\x61\xb4\x35\x94\x6b\xeb\x82\x69\xb7\x55\x95\xa3\x9f\xb3\xb9\xa5\x41\x37\x99\xa4\xb9\x1c\xc7\x4c\xab\x57\x27\xb6\xd7\xe4\x41\x6b\xeb\xb3\xf9\x1c\xc9\xb5\xb7\x13\xdb\x5b\x0e\xde\xd3\x63\x5b\x31\x8a\xad\x71\xf6\x96\xd7\xd8\x0a\x99\xd9\x4b\x13\x1b\xdb\x5e\x13\x17\x9d\xe1\x3a\xf3\x64\xf8\x0e\x92\x8a\xef\x12\xff\x2b\xf7\xdc\x6d\x2e\xd0\xe4\xa6\x8a\x0f\xfe\xea\x3e\x74\xe8\xb3\x78\x5e\x9b\x57\x61\x9b\xab\x61\x06\x3c\x7c\xba\x36\xd7\xe4\x30\xf6\x45\x35\xb7\x90\x49\x05\xdd\x3e\x29\xa2\x95\xd1\x79\xb9\x3e\xaa\xca\xf9\xfb\xd3\x15\x24\xa2\x4a\xb1\x74\x25\xe3\x4e\xd6\xed\x49\xb3\x25\xa2\x35\x90\x88\x56\x2d\xeb\x07\x33\x6a\x85\xfc\xb8\xc0\xdb\x4b\xca\x7c\x35\xb5\x8c\xeb\x46\xb3\x16\xd1\x11\x91\x87\x45\x8d\xac\xa8\x75\x74\xfe\x56\xab\x13\xaa\x5b\x51\xe5\x82\xb8\xe0\xea\x3f\x7a\xb8\x83\x14\xb5\x93\x40\xd4\x7a\xf9\x79\x5d\x4f\xb7\x85\xe3\xf7\x5c\x7e\xfe\x90\xd6\x56\xdd\x3a\xa7\x00\x52\x2b\xd7\xdc\x7a\x6e\x5f\xb4\xe9\xc2\x1b\xcf\xed\x6f\xfa\x2c\x46\x3b\xa5\xa8\xe3\x55\x8c\x78\x95\x81\x07\xaa\xe0\xa6\xd3\x21\xe6\xcc\xeb\x95\x6a\x79\x5c\x53\xf8\x8c\x5a\x11\x43\x63\x5b\x3e\x86\x67\x85\x65\x0e\x74\x45\xab\x24\xc6\x98\x58\x26\xcb\xca\x61\xde\x66\x2f\x29\x46\x2e\xb1\x72\x59\x73\x7b\x12\x09\xb5\x4a\x49\x0b\x92\xb5\xc8\x85\xd3\x6e\x1e\x36\x80\xe7\xfe\x05\xfb\x49\xd0\x49\xbb\x08\x75\x9b\x0b\x61\x50\x43\xac\xc8\x69\xb3\x9e\x58\xc7\x49\xde\x3f\x3c\xfc\x99\x9f\x23\xe4\x8d\xe1\xe1\x9c\xcc\x77\xa0\xcc\x55\x10\x80\x46\xf8\xe6\xe9\x64\xf6\xe6\x64\xae\xc8\xed\x92\x35\x44\xa9\x0f\x87\x36\x5d\x13\x76\x94\x31\xbb\x64\x69\x37\xb3\xe9\x9a\x49\x44\x0b\xca\xb2\x92\xe2\x4b\xec\x5e\x2a\x7e\x9d\x9c\xaa\xf0\x07\xca\xe8\xad\x5b\x49\x09\x16\xc9\x37\x1e\x00\xaf\xac\xa8\xfe\x04\x26\x68\x68\x6e\x39\x31\x79\xd7\x60\xeb\x09\xed\x12\x7c\x9e\x4f\x5f\x08\x9a\xd7\xae\x3a\x6f\xe5\x15\x57\xac\x3c\xff\xca\x18\x05\xe8\xe2\xae\x86\xfa\xb6\xb6\xfa\x86\xae\x71\x30\xfd\x72\xf9\xce\x9d\xcb\x57\x6c\xd9\x72\xf2\x2d\x8e\x70\x3b\x22\x9d\x9d\x91\xc6\xae\x84\xe1\xff\x83\xf9\x41\x51\xc5\x79\xe0\x19\x16\x51\xa4\x42\x1c\x13\x13\x14\x3d\xbf\x59\x2b\xf5\xc4\x62\xf8\x2e\x5d\x92\x47\xbb\x29\xe9\x79\xa4\x69\x13\x7e\x98\x76\x55\x28\x14\x4b\x17\x9f\x49\x5b\x6c\x78\x6b\xe1\x73\xd1\x7f\x52\x51\x46\x95\x58\x9c\x9f\xc3\x9c\x49\x96\x60\x48\x48\x89\x62\x89\xa8\x0e\x87\x2a\x22\xd3\xb1\x19\x99\x8e\x45\x73\x06\xe3\xfd\xa4\x2a\x59\x49\x96\x39\x2b\x13\x18\x99\x9c\xb4\xd0\x01\x98\x50\x4b\x14\xd5\x9e\x50\x45\x59\x2b\xb2\x62\x18\x1a\xe6\xda\x96\xb9\x13\x14\x5d\x45\x66\x3b\x4b\x88\xa9\x1c\xae\x0b\x96\x06\x9d\xc1\x52\x76\xf4\x95\x63\x4b\xaa\x1b\xb8\x89\x7b\x90\xff\xdb\xeb\xd6\xec\x9d\x0e\xf2\xd7\xac\x4b\x26\xff\x64\x7b\xed\xe4\xef\x0e\x99\xb2\x67\x2d\x5f\xb1\x93\xc4\xdc\xe2\xa3\x65\xc2\x9f\xb2\xff\x7c\x20\x7b\xe8\xad\xec\xa6\x03\xd9\x83\x8f\x56\x7d\xfd\xdf\xec\x8f\x72\x43\x5c\x03\xc1\x3d\xc6\xb6\x6c\x1c\x39\x84\x00\x02\xd0\x02\x5f\x65\xe7\x84\xe9\x10\xdb\x6b\x43\x0b\x51\x34\x92\x4c\x1b\xa2\x5a\x84\xce\x36\xad\x51\x95\x1c\xd3\x79\xf9\xb0\xdb\xd4\x49\x48\xb0\x55\xce\xf8\x42\x2a\x2c\x19\x55\x8a\x69\x31\x12\xd1\x9a\x15\x59\x49\x05\x43\x0d\x11\xd6\x9f\x0e\x8b\x4e\x9f\xbd\x1a\x4f\xc9\xca\x15\xcd\xea\xa1\x22\xfb\x22\xf4\x47\xaa\xeb\x9a\xa9\x29\x68\x0f\xc9\x4a\xd2\x12\x40\x90\xc4\x9c\x31\x38\x35\x03\x11\x19\xe7\x45\x9d\x86\x91\x88\x9c\xcc\xf3\xb2\xa6\xa6\x27\x3a\xf5\xd1\x18\x27\x8c\x67\x1c\x40\xe6\x06\x28\x03\x27\x54\xc0\x23\xa7\xe3\x01\x72\x22\xbb\xdd\xb4\xc9\x80\x2a\x3f\x07\x19\x50\x15\xed\x77\x9c\xac\x68\x2e\x37\xb2\x6d\xa4\x64\x4f\x39\x35\xa6\x55\x49\xf9\x5c\xcc\x40\x41\x4c\xee\x9a\xc8\x0f\x74\x72\xdf\x3b\x68\x2a\x4c\xe0\x09\x42\x43\x01\x72\x58\x84\x74\x2c\x1e\xfd\x87\x62\xa1\xba\xa2\x7f\x1f\x1c\xaa\x8b\x81\xe1\x9e\x0c\x0c\xcb\x94\x60\xa0\x31\x52\x08\x0c\x72\x37\xb3\x44\x26\xc0\xa1\xdb\x21\x39\x3c\x3a\x11\x0f\x1f\xa4\xff\xc1\x7d\xc3\xff\x39\xc0\x08\xe8\x60\x24\x5d\x6e\x3c\xe1\xb0\xc8\x69\xd9\x53\x5e\xe5\x65\x88\xa4\x8a\xed\x15\xcc\x29\x9d\x6e\x0f\x31\x8c\x9e\x42\xc0\xfc\xc6\x30\x78\x26\x22\xa3\x9b\x3b\xd4\x9e\x64\xd8\x14\x23\x36\x74\x5e\x7e\xee\x1f\xdd\x5b\xd4\x8a\xb8\xe6\xe6\x33\x6a\x65\xcc\x60\x38\x72\x88\x19\xcd\x4a\xa7\xf9\x09\x60\xb9\x24\xfc\x8d\xf1\xb0\xa5\xbc\x92\x45\x8a\x68\x15\x12\x5d\x39\x35\xaf\xc4\x66\x6d\x0b\xc7\xb2\xba\xbc\x13\x08\xb7\xa6\xee\x49\xc6\xd1\x61\x21\xcc\x9e\xc2\xe3\xc4\x89\x80\xf5\x1b\xe7\x8b\x23\x27\x00\xb8\x43\xe6\x7a\x10\x40\x04\x19\x56\xe6\xe5\x1c\x38\x62\x49\x91\x62\x93\x23\x1c\x2a\xc6\x20\x3f\x55\xd2\x63\x62\x25\x23\xd8\x97\xfe\xa4\x54\x62\x10\x0d\x51\x57\xa8\x94\x44\xb4\x12\x89\xae\x2f\x02\x9f\xc0\x5d\x1b\x9e\x8e\x7d\x92\x4f\x7f\x64\xc7\x41\x9f\xcd\xea\x34\x48\xe6\xb0\x29\xfb\xf1\xdf\x7e\x3b\x86\x0d\x89\x8e\xfd\x4e\x00\xee\x7e\x73\x10\xac\x60\x03\x19\x56\x8d\xe5\x61\xb2\xe5\xd6\x0c\x46\xc6\xa4\x16\x47\x0d\x5a\xb0\xd3\xf1\x31\x95\xea\x88\x6b\x76\x19\x1b\x98\xdf\xb4\x20\x6e\xb6\xea\x0d\x3b\xf5\x6f\x5b\xf3\x07\x24\x6b\x9a\xc9\xad\x8f\xc5\x91\xdf\x03\x70\x47\xcc\x1d\x20\x81\x05\x9c\xb4\x7d\x39\xce\x84\xb2\x18\x9e\x32\x25\x4b\x38\x96\x01\xa8\xca\x2c\x43\xdb\x76\x8c\xd1\x5c\xd9\xf2\x69\xae\x6c\x98\xaf\x6d\xb3\x63\x53\x31\xb2\xb8\xd4\x26\x2b\x29\xce\xc4\x63\x2c\x6e\x4b\x2b\x9f\xf3\x07\xf2\x5b\x5a\x61\x8c\x89\x27\xf4\xd6\x9a\x1a\xd9\x50\xf8\xdb\x4b\x63\x90\x14\x46\x8e\x00\x70\xff\x65\xb6\xe1\x59\x1a\xb5\x6a\xb7\x01\x6a\x17\x53\x62\x4a\x62\x8c\x1d\xb5\x88\xd3\x37\x54\x6d\x31\x15\xa2\x48\x90\xc3\xb3\xc0\x77\x67\xfe\xc9\xb5\xd9\xca\x28\x80\xec\xc8\x9f\x60\xb7\x21\xdb\x4f\xd2\x6c\x37\x52\x7a\x54\x31\x96\x92\xed\x66\xea\x30\x48\x19\xcd\xc5\xf2\x7b\xa8\x99\x9a\xdf\x72\xfa\x41\x17\xb1\xfe\xb7\xde\xee\x63\xc4\x6a\xea\x1b\x1e\xfe\xdb\x4f\xc6\xa0\xdc\x47\x3b\x29\x07\xcd\x00\xe2\x42\xe4\x44\xf0\xc3\x95\x7a\xac\xbe\xc2\x67\xd8\x4d\x89\xc0\x46\x2d\x8b\xde\x37\x86\x2c\x81\x62\x53\x71\x44\xf5\xc5\xd3\x84\xed\xa5\x54\xb1\xaa\x30\x0e\x3c\x73\xa1\xf6\x44\x65\x2c\xa9\xe0\x78\x55\x7c\x96\x48\xd2\x81\x91\x46\x0e\x60\xc1\x44\x06\x95\x4c\x90\x7a\x6b\x4a\x49\x2e\xa8\x2f\x4e\x9b\xcf\x18\x72\xea\x49\x7b\xa7\x4c\x72\x14\x7f\x72\xdc\x19\x6e\xfe\x8f\x7b\xb8\x7f\x36\x58\xfe\x4e\xed\xbc\x87\x54\x33\xa6\xbf\x63\xc7\xb8\xbb\xee\x21\x8f\xe4\x91\xfd\x3d\xea\x23\xc3\xd9\x79\xc8\xf8\x97\x5d\x7f\x8f\xc1\x2d\x69\x92\xcc\xab\xc0\x0d\x1e\x68\x84\x77\x26\x70\x14\x79\x8c\xae\x9e\x4f\x54\xa4\xd6\x46\x35\xbf\x90\x49\xd5\xfb\x6b\xa5\x88\x56\x45\x0d\xa6\xa6\xe9\x30\x17\xa9\x8d\x81\x63\x72\xae\x3c\x4e\x34\xdd\xc8\xee\x4e\x47\x69\x94\x0a\xcb\x16\x29\x92\x0e\xb1\x9f\x0e\x45\xd3\xe1\x51\x73\xbe\xb1\x5c\x56\xb4\x52\x73\x22\xa1\x86\x64\xad\xaa\x36\x91\x50\xc3\x8a\x26\x29\x89\xb1\xac\x47\x5a\xad\x28\x2b\x6a\x63\x42\xf5\xcb\x6a\xf9\x14\x1c\x48\x05\xdd\xbc\x42\xc4\x48\xa7\xfe\x8d\xac\x1a\xe7\xe5\x4d\xc6\x95\x34\xc6\xd5\xc3\xbd\x07\xe4\x4d\x32\xd7\x03\x80\x1d\xaa\x20\x08\x8b\xf4\x33\x3c\x45\x5f\x2b\xd8\xd4\x62\xf0\xf7\x91\x1c\x0d\xa4\x93\xce\x1d\x7a\xba\xb4\xb3\x44\x56\xd2\xa2\xcd\x1b\x08\xe2\x42\x57\xae\x18\x0e\xbd\x3c\x05\x9b\x12\x5a\x42\x53\x50\x2a\x15\xe3\xdc\x78\x5a\x62\x25\x61\x16\x35\x90\x0c\x39\x82\x39\x39\x96\x4e\x26\x87\xea\x8d\xfe\xa3\x45\xc1\xa9\x72\x0a\x51\x7e\xc2\x26\xcf\xd3\xca\xc2\xc7\x8c\x33\x2d\x43\x9e\x0e\x5d\x9e\x1a\x58\x31\xb9\x5e\x6a\x0b\x09\x53\xa7\x0b\x73\x98\x0a\x13\xc6\x4a\x40\x16\x59\x0b\x22\x8b\xee\x34\x15\x64\xcc\xb6\x53\x48\x46\x8c\xb9\xf7\xf4\xb2\xcd\x1b\xb5\x4f\x98\x6c\x2b\x51\xb6\x10\xb4\xc0\x5e\x5d\xb6\xda\x31\xb2\x35\xf1\x19\xb5\x0a\xf3\x8e\x52\x7e\x67\x95\xa4\x1f\x67\x31\x67\x28\x2c\x66\x52\x25\x61\x32\x3a\x10\xc3\x2c\xf6\x60\xb4\xda\x55\xbd\x8e\x03\x75\x8b\x3c\x21\x59\x39\x6c\x53\xc4\xaa\xda\x26\xd4\xaa\xb3\x0a\x0f\x74\x27\xca\x5f\x60\xc0\xf1\xa7\xa1\x00\x2b\x1d\x37\xf2\x6e\x99\x9c\x12\x4c\x38\x9a\xbf\xcf\xf2\xad\xf1\x44\x54\xa2\x8e\x8b\x0d\x71\x51\x20\x00\xd5\xb0\x4b\x47\xc6\x35\x06\x19\x2f\x9f\x51\x4b\xa2\x6a\x30\x4e\x2d\x3a\x35\xc4\xc2\x45\x09\x2e\xa9\xa9\x92\x52\x42\xa1\x92\x32\x6a\x29\xdb\x6c\xb1\x88\x99\x54\xb5\xa5\x5c\x8a\x68\x41\x09\x69\x75\xab\x25\x16\x0e\x1a\x24\xb2\x92\x12\x6d\x2e\x2f\x62\xe2\x75\xc9\x8a\x1a\x28\x80\x09\x5d\xb4\xc6\x60\x40\x3f\x99\x88\x83\x99\x58\xdf\xcf\xf5\x8a\x5f\x11\x6b\x01\xf1\x53\xc3\xc3\x9f\x1d\x18\xdb\x29\xce\x1f\x1e\x06\x02\x33\xe1\x17\xfc\x5f\x85\x03\x60\x05\x28\xb5\x90\x4e\x0b\x71\x5b\x88\xd9\x42\x66\x92\xf6\xec\x73\xdf\x23\x2d\xa4\xe5\x7b\xd9\xe7\x48\xfb\xf7\xb2\x2f\x64\x5f\x20\xbb\x49\x0f\xe9\x79\x20\x7b\x94\x74\x3c\x90\x7d\x26\xfb\xcc\x03\xa4\x23\x7b\x94\xae\x1d\xf3\x47\xbe\x2d\xee\x10\xdf\x87\x72\xa8\x81\x56\xd8\xa8\xf3\xc4\xd4\x1b\x6c\x64\x21\x3a\x50\x62\xb8\x82\x57\x88\x19\xb5\x02\x23\x53\xe8\x0a\xae\xc5\x49\x84\x31\xa4\x39\x13\x6a\xa3\x7c\x58\x12\xca\x64\x3f\x6e\xcf\xd9\x15\xad\x08\x83\xe8\xeb\x65\x59\xd1\xca\xdc\x6c\x5a\xf7\xb5\x22\x59\x2f\x1e\xb3\x18\x14\xa4\x2e\x77\x67\xdc\xec\x52\xbc\xc4\x01\x41\xa4\x82\xe8\xac\xe5\x6a\xca\x5c\x7e\x42\xd0\x83\x76\x96\xfa\x08\xc3\xaf\x36\x4a\xe6\x53\xe4\x96\x7f\x63\xce\xc0\xc1\x4b\xae\xfc\x32\x45\x6f\xcd\x43\xf3\x2e\x38\x78\xeb\x96\x4b\x49\x75\x28\x6c\x22\xaf\xd4\xad\x6e\xfb\xe1\xe1\x7b\xea\x37\xf7\xff\xfb\x13\x2d\xcd\x26\x1d\xc5\x9a\xf0\xce\xc3\xeb\xb3\xcf\x3e\x81\x48\x36\x35\xfe\xeb\x9f\xd7\x91\x19\xda\xba\xef\xf6\x10\xbe\xd1\x4d\x71\xcc\xb6\x84\xab\x29\xaa\x3b\x9e\x9c\x45\x80\x67\x9c\x50\xe6\x06\xac\xfe\x19\x84\x5b\xf4\x98\x52\x83\xab\x91\x9d\x66\xca\xfa\x8e\x96\xa3\x14\x53\x35\x42\x78\x20\x2e\x89\x99\xa4\x84\xb4\xa4\x92\xc9\x12\x49\x56\xa2\x79\x5b\x49\x2c\x58\x69\xcb\xce\x58\xbd\x92\x4e\xbb\x91\x95\x6a\x70\x1d\x3a\x74\xf2\x56\xa9\x52\x56\x34\xaf\x2f\x91\x50\xed\x72\xca\xe3\xd7\xe7\x50\x62\xa5\xf0\x55\x25\x58\xdf\x9a\x9c\x2a\x0a\x17\x84\xc2\x7c\x51\x6f\x33\x36\x94\xc9\x59\xa3\xb8\x01\x46\x94\x62\xc8\x1e\xd2\x65\x3f\x70\x7a\xd9\x8d\xf5\xe0\x7f\x2f\xbe\x5d\x92\x95\x94\xc7\xeb\x0b\xea\x15\x2c\xfc\x81\xc4\xe7\x10\x1f\x9d\xe1\xc2\xe2\x93\x6f\xb0\x05\x64\x0a\x00\x48\x87\xb1\x74\xe4\x30\xe8\x44\x0c\x6a\xe0\x6b\xd3\xd1\x7f\xed\xff\x16\x80\xba\x71\xfa\x4f\x7b\xfc\xfa\xb2\xe3\x54\xf4\x65\x67\xda\x1d\xc1\x58\x78\x0a\xa3\xf1\x8a\xb1\xe6\x4c\x05\xc7\x22\x63\xb5\xa1\xeb\x0d\xc3\xa3\x18\xf1\xa0\xb3\xea\x37\xa7\xd5\x2b\xe8\xfc\xea\x1b\x9d\x5f\x75\x78\x46\x31\x49\x79\xa5\x4a\x29\xa2\x05\xa4\x8c\x2a\xc6\x4e\x0b\x50\xaa\xda\x69\x2f\x30\x07\x07\x64\x45\xf3\x58\x3f\x1f\x3a\xcc\xd5\x2d\x0c\xce\x8f\xd0\xd9\x9d\x0a\x99\x0b\x74\xb7\x17\x78\xc6\xab\x85\x63\xc5\xc5\xf8\x3f\xf2\xf3\x41\x47\x81\x29\x62\xc0\x08\x2c\x89\xca\x1d\xc5\x13\xfa\x29\xb3\x42\xbd\x7a\x56\xe8\xe3\x82\xc9\x6c\x29\xe2\x3d\x6c\x03\x84\x94\xca\x8a\x66\x72\xe9\x12\x16\x20\xda\xb2\xe0\x18\x28\xc0\xb6\x45\xae\x1c\x1d\x00\x05\x59\xb7\x48\x23\xeb\xfe\x1c\x0c\x02\x08\x9f\x22\x57\x98\x6f\x0c\xab\x76\x59\x1e\x63\xb1\x14\x4b\x2b\x2e\xe4\x68\x56\xf8\x4c\xba\xc8\x87\xb7\x45\xa3\xfb\x3e\xa5\x62\x46\xb3\xb8\x62\xb1\x64\x29\xba\x0f\xa5\x12\xf3\x4f\xb9\xd2\xfc\xad\x8d\x52\x46\x19\x64\x67\x85\x1b\x40\x53\xf4\x9d\x0a\x1f\x5d\x48\xed\x09\x4d\x18\xc7\xaa\x1d\x77\x9a\x9d\x58\xb4\x41\x88\x10\x67\x1e\x51\xe3\xe0\xbd\xf7\x92\x9f\xdc\x7b\xef\xf1\x2c\xa9\xca\xfe\x2e\x7b\xfc\xde\x7b\x8f\x5f\x75\xd5\x55\x57\x1d\x37\x7c\xc0\xbe\x4f\x8e\x3c\xfb\xc9\x0a\xdf\xa3\x1c\x77\xed\x05\x17\x7c\x89\xe5\x0b\xd0\xfe\x6c\x32\xd5\x40\x3d\xdc\xac\xeb\xac\x3c\x6f\x67\x47\xad\xd1\xa9\x5a\x1a\x50\x98\x7a\x31\x93\xe4\xea\x73\xbe\x4f\xbd\x43\x0b\x51\xab\xa0\x28\xa3\x5a\xf4\x2a\x2f\x7e\x31\xa3\xfa\xb1\xca\x4b\xaa\xca\x12\x92\x30\xfc\x09\x53\x64\xfd\xf5\xb2\x92\x32\xb9\x9c\x38\x8c\x6d\xb2\xa6\x20\xcf\x00\x61\x8b\xa5\x56\x53\x4e\x9d\x73\x4b\x89\x2b\x47\x5e\xdb\x56\xcd\xce\x1e\x9c\x65\xc0\x4e\x20\xf4\xdc\xb9\xf6\x36\x68\x6f\x33\x0e\xbe\xe5\xba\x7b\x08\xf7\xfa\xe1\x3f\x5d\x42\x22\xbf\x7f\x65\xc9\x1d\x35\x1d\xd5\x5f\xec\x5d\x7c\x4e\xf6\xa5\x6d\xcb\x86\x16\xaf\x79\xd4\xc7\xef\x7b\xf3\xe3\xa7\xd5\x2d\xff\x31\xa7\x2b\xfb\xf6\x57\x9e\x7a\xd2\x57\xf1\xba\x2b\xb8\xb8\x7f\x1e\x29\xbe\xed\xbc\x23\x8b\xe6\x9d\x7b\xe3\xa5\x27\x1f\x37\xe2\x59\x85\x7e\xf1\xf7\x00\x50\x0d\xf5\xd0\x06\xdf\x82\x64\x08\x98\xd5\xc8\x48\x60\x2a\xf4\x3d\xae\xa4\x42\x0c\x02\x36\xf4\x6f\x2d\xc5\x96\x48\x3a\x26\x84\x94\xe2\x88\x16\xa3\x16\x65\x3b\xda\x4e\x0d\x22\xd6\x2a\x69\x70\x68\x76\x4b\x46\xb5\x47\xe9\x5d\x0b\xa1\x7e\xbc\xe6\x12\x33\x5a\x07\x89\x68\x0d\x76\x59\xd1\x6a\xa8\x5b\xd7\x22\xa7\x6d\x4a\xa8\xae\x9e\x25\x9d\x24\xab\xfc\x33\xf0\x64\xbb\x82\xce\x7f\xd5\xfe\x44\x42\x8d\xc9\x49\x17\x69\xa3\xce\x9e\x45\x40\xb4\x68\x97\x9f\x06\x53\x16\xae\x81\xfc\x74\xe9\xb2\xbe\x8a\xcb\xe2\x35\xd3\xe1\xcc\x12\xe7\x9b\xb2\x1f\x7f\xb6\xda\x60\xce\x32\xf0\x7b\x0d\xf1\x8b\x42\x1b\xdc\xad\xe3\x37\x63\x5a\xf8\x35\x31\xfc\x9a\x46\xf1\xab\x61\xf8\xd5\xe4\xf0\xab\x71\xd0\x3e\x94\x8f\x5f\xa4\x06\xcd\xf0\x50\x4b\x6b\x1b\x02\x27\xa7\xaa\xfc\x31\x16\x33\x3f\x8a\x5c\x13\x45\x2e\xfa\xf9\x91\xcb\xe3\x18\x43\x77\x6c\xba\x44\x63\x41\x36\xb3\x4c\x83\x6f\x8c\xbf\x80\xcd\x31\x06\x76\x7f\x45\xec\x9a\xa0\x0b\xee\xd7\xb1\x6b\x9d\x16\x76\x1d\x0c\xbb\x0e\x8a\x5d\x02\xb1\x6b\x66\xd8\x35\xe7\xb0\x63\x95\x4c\x0d\xec\xba\x49\x44\x6b\xce\xf5\xbd\x36\x99\x62\x58\x37\xa3\x51\xcf\x78\xaa\xf2\xd7\x47\xc6\x61\xd8\x41\x31\xec\xfa\x3b\x7a\x5f\x6e\x7f\x6d\xba\x3d\xf0\x06\x63\x2d\xee\x98\x4e\x27\x14\xce\xd4\x8f\xe4\x97\x8d\xeb\x87\x26\x27\x62\xd9\x05\x83\xf0\x1b\x1d\xcb\xde\x69\x61\xd9\xcf\xb0\xec\x17\x32\x6a\x0c\x4f\xcb\x52\xed\x91\x98\x14\xd1\x66\x50\x70\xe7\x20\xb8\x09\x06\x6e\x22\x07\x6e\xc2\x91\xae\x61\x6e\x62\x0d\x7d\xa3\xcd\xce\x21\x9d\x8a\xba\x66\x4b\x58\x4e\x96\x7e\xdb\x1c\x4d\x47\x47\x6b\xd6\xcc\xae\x91\x95\xb4\x12\x8a\xb4\x77\x55\xbb\x13\x5a\x33\x91\x15\xad\x2a\x36\x76\xd0\xf7\x53\xd8\x07\xf3\x60\x57\x15\x59\x2d\x49\x68\x91\x98\xac\xa8\x35\xd3\x56\x42\xa1\xc3\xfd\xe9\xea\x63\xf7\x38\x6f\xd4\x39\x2d\xb5\x5c\x9d\xef\x97\x2e\x35\x74\x23\xea\xfd\xfc\x59\xd4\xcd\x0c\x88\x43\x27\x3c\xa7\x6b\xa7\x71\x5a\xda\x69\x65\xda\x69\xc5\x35\x49\x6d\x8b\x53\x07\x5f\x6d\x8f\x11\xb5\x2b\xaa\xd6\x1c\xd3\x66\x48\x19\x75\x86\x43\xad\xa7\x6b\x10\x63\x72\xa4\x8b\x15\x55\x56\x7d\x4e\x59\x33\x1c\x5a\x34\xa7\x1f\xb5\x8d\xfe\x68\xa7\x94\xc1\xc0\xad\x19\x35\xb2\xa2\xd9\x42\x38\x24\x92\x16\xa5\x31\x91\x48\xa8\x9d\x8a\x56\xe5\x1f\xab\x95\x56\xaa\x95\xf8\x04\xad\x4c\x7b\x48\x50\xf7\x37\x87\x3e\xf5\x7d\xa7\xd6\xc0\x46\x62\x5d\x96\x03\xbd\x8b\x58\xa7\x04\x7e\xfd\xf0\xf0\x67\x3d\xfa\xec\x72\x13\xb5\xca\x74\xcc\x4d\x67\x22\xe6\x2d\xd0\x03\xf3\xe0\x35\x1d\xf3\xb6\x69\x61\x9e\x60\x98\x27\x84\x0c\xed\xc0\xb3\x59\x44\xc2\xdc\x68\x7a\x86\x1e\x91\x30\x1f\x07\x45\x2b\xc3\xb9\xd5\xc0\x39\x55\xd3\x4a\xa4\x48\xba\x97\xf5\xfc\x56\x87\xd6\x39\x0a\xfa\x40\xe0\x98\x9c\x8e\xb0\x91\xb0\x80\x44\xb4\x5e\xbb\x81\xfb\x80\x9c\xb6\x28\xcd\x6d\xc8\xa0\x11\x99\x88\x7c\x82\x22\xdf\x33\x71\x3c\xcc\x9d\x2d\x2b\xa9\x9a\xc8\x3c\x96\x1e\x35\x2d\x35\x8c\x09\x6b\x18\x55\x47\x7e\x72\xe6\x69\x26\xfc\x80\x11\xe8\xc0\x1b\xda\xd9\x61\x04\x3b\x4c\xa9\xa2\x8f\x8c\xd0\x87\x11\xa6\x27\xc1\x63\x84\x3f\xf0\xb0\x60\xe4\x5d\xd3\x43\xc2\x52\x68\x86\x04\x0c\xc0\x0f\x20\x59\x0b\x10\x51\x1b\xe3\x9a\x9f\xcf\xe0\xbd\x16\xe3\x33\x49\x07\x61\x74\xe2\x12\x9f\x51\xfb\x62\xe9\x9e\xca\x5a\x47\x71\x44\xed\x88\x6b\x3d\x42\x06\x99\xa3\x07\x71\x5b\x22\x2a\x66\xd4\xa8\x83\x2e\x94\xaa\x10\xd3\xaa\xc4\x8c\xda\x8d\xc5\x06\x7a\x49\x44\x2b\x2f\xca\x68\x73\x48\x44\x8b\xe6\x12\xaa\x3a\xe4\xa4\xd5\x81\x5d\xbe\x4a\xd1\x4a\xeb\x13\x09\xb5\x57\x4e\x55\xba\xd8\xce\x45\xb9\xa2\x85\xc2\x54\x17\x3d\xb5\xb2\x92\x84\x50\x7d\x1e\xcb\xba\xea\x50\x18\xb7\x60\x5e\x86\x55\x0d\x96\xe5\x64\xf4\x50\xe3\xa9\x06\x6b\x27\x2c\xaf\x39\xee\xc1\x05\xd9\xbf\x1e\x3e\x6b\xe1\x99\xab\xb3\x6f\x73\x26\x18\x79\x69\xc3\x43\x3d\x33\xff\xf5\xe2\x97\x4e\x9c\xba\x8c\x13\xae\xbe\x7a\xf5\xd5\x4b\x97\xcc\x3a\x76\xcd\xfe\x67\x07\x7b\x9f\xbb\xf5\x27\xbf\x24\xd5\xcb\xcf\xea\xbe\xa6\x26\x75\xd1\x56\x4e\xe3\xc8\x25\x67\x2f\xbf\x60\x0d\x99\xf9\xcd\xef\xf7\x2c\x3b\x7f\x51\x97\x62\x3a\xf8\x64\x67\x5b\x5b\x67\xf6\x93\x37\xef\x33\xed\xb8\x61\x46\xfd\x0f\x5b\x16\x9c\xb9\x78\xce\xaa\xc3\x77\xf5\xcc\x9d\xd9\xa0\xae\x24\xb2\x58\xb5\x66\xfb\x55\xcc\x67\x19\xcc\xc6\x91\x17\x13\xc0\x0f\x51\xf8\x32\xab\xc3\x94\x0e\xe6\xc7\x4f\x10\x23\xc1\x1a\xc9\x12\xec\x45\xd4\xea\xc5\x8a\x65\x98\x58\x3c\x1a\x4a\xd1\x44\x22\x5a\xad\xc4\x4a\x1b\x36\x29\xb2\x92\x0a\x04\xeb\x1b\x28\x7e\xb5\xf2\xe3\x45\xa2\xdd\xe9\xf5\x84\x59\x65\x75\x6f\x03\xfd\x32\x8c\xbb\x87\x9a\x3d\x28\x2b\x29\xbf\xd3\x83\x27\xde\xa3\x41\x13\x93\x31\x6b\xba\x4c\xe1\xd0\x84\x98\x89\xc2\x34\x9b\x42\xf6\xa9\x13\xd9\x4f\x49\x7e\x58\x7a\x41\xce\xcd\x07\x8e\x93\x58\x76\xd5\x98\x58\x09\x81\x71\x51\x8a\xef\x00\x80\x1b\xbd\xfe\x95\x7a\x05\x48\x7b\x6e\xe7\x90\xc2\x12\xe6\x33\x69\x5f\x91\x93\xfa\x3b\x3e\x3d\xc0\xd8\x8f\xc1\x35\x49\x3f\xfa\xb5\x7e\x62\xb8\xf2\x7e\x59\xd1\x64\x3c\xba\xb0\x3b\xb1\x78\x98\x5a\x24\xb3\x68\x34\x2a\xab\x7b\x22\x25\x25\x33\x5d\x47\x79\x29\x2d\xaf\x4f\x24\xa5\xbc\x0c\x0d\xd6\x95\x79\xcc\x94\xa4\x8b\x8c\xa5\xa6\x14\x8e\x9a\xb2\x1f\x9f\x7a\x54\xe7\xa7\x34\xe4\x7a\x3d\x27\xd7\xf9\xff\x7b\xb9\x52\xb2\xa2\x1f\xc9\x4f\x53\x34\x16\x34\x39\xb5\x68\xa4\x9e\x19\x92\x6f\x4f\x25\x1c\xff\x63\x34\x21\x4f\x3d\xae\x8b\x97\x93\xef\x43\x94\x2f\x00\xf5\x93\xc8\x57\xc7\x67\xd2\x21\x26\x5f\x48\x60\xae\x5d\x98\xc9\x17\x46\xf9\xc2\x54\x3e\xea\xb2\x49\x61\x94\xaf\xca\xfb\x79\xe4\x1b\xb5\xfb\xa6\x96\xf1\x12\xc3\xda\x73\x4c\x29\xe4\x7f\x33\x2b\xef\xd4\xfd\x4c\x4a\x51\x97\xf1\x28\xca\x58\x89\xb6\xc4\xed\x05\xa5\x0c\xf1\x99\xb4\x97\x49\xe9\x15\x32\xaa\x27\xaa\xd6\xc4\xf1\xc8\xa6\x36\x86\x31\x97\x9e\x63\xc8\xd0\x51\xc9\xd8\xf4\xa8\xf9\xe0\xa3\x06\x01\x85\xc1\x87\x30\xf8\x88\x1e\x73\x59\xe9\x91\x95\xc3\x45\x36\x6b\x35\x0b\xc3\xa8\x91\x93\x76\x67\x88\xae\x44\xd2\x8c\x5c\xbf\x2e\xb2\x33\x4e\xcf\x90\x57\x56\xd4\xea\x29\xe1\x09\x3a\x73\xc8\xb0\xdd\xef\x42\xe8\x2c\x21\xd6\x06\x03\x17\x89\x58\x0b\x63\xf3\xce\xf0\xf0\xa9\xdb\x10\x17\xae\x78\x78\x18\xb3\xa5\x81\x3b\x24\xfe\x01\xf7\xff\x4b\xe0\x42\x23\x83\x8e\x9d\xed\x23\x34\x06\x6b\x23\x26\xba\xd8\x8f\xe5\xf8\x9c\xec\xc6\x91\x64\xd2\x8e\x07\x95\x76\x93\x45\x3f\x8a\xc6\x3c\x18\x0b\x5d\xa6\x79\x31\xc7\x5e\x6c\x29\x61\x1b\x2f\x38\x4c\x73\x5c\x88\x66\x1c\x91\xbf\x64\x24\x97\xe2\x9b\xa6\xec\xc7\xd9\xef\xe7\x78\x2e\xe9\x7c\x3b\x04\xc0\x3d\x2e\xbe\x81\x75\x3e\x4b\xe0\x0b\x90\x34\xd3\xf6\x49\x02\xcb\xeb\xc3\x3d\x22\xc2\xf6\x1d\xb0\x7d\x16\x46\xe4\x24\x60\x8b\x04\x93\x25\x92\xb4\x60\xe6\x82\x85\x58\xf4\x30\x04\x6c\x1c\x16\xad\xb2\x95\xe0\x76\x82\x24\x2b\x9a\x60\x31\x76\x85\xf4\x76\xf1\x74\xc8\x0d\xb1\x66\xe9\x23\x2b\x9f\x80\xf3\x12\x7d\xb7\x93\x1f\x39\x09\xc0\x1d\x17\x3f\xc2\xd8\x83\x52\x58\xa3\xd7\xf9\x96\xb1\x36\x14\x8b\x3d\xb0\x12\x16\xbb\x81\x15\x9f\x15\x8c\x58\x4f\x16\xa3\xc1\x54\x5c\x62\x89\x24\x15\xa4\x1a\x56\x8a\x68\xfb\x14\x07\x2b\xf7\xac\x15\x2b\x79\x81\x07\x5a\x91\x8c\xb5\x39\xf2\x03\x10\x46\xd9\x24\x45\x63\x50\xfc\x42\x6f\xae\xf0\x2e\xeb\xff\x27\x9d\x79\x2d\xa6\x63\x7d\xe4\x38\x00\xf7\xaa\xf8\x1c\xc6\x1f\xd8\x41\x81\x2b\x74\x2e\x40\x1b\x52\x72\x8e\x56\x67\xd5\x44\x4c\x70\x52\x4b\x58\xf0\x81\x23\x86\x59\x5c\xc5\xfa\xfe\x6c\xb1\x11\x65\x92\x2c\xc6\x4e\x5f\x2c\xd2\xa6\x17\x5b\x2d\x91\x14\x2f\x15\x4b\x11\x0d\x24\x64\x7d\xe5\xa5\x4c\xaa\x04\x3f\x50\xa4\x0c\xcb\xe9\x12\x6d\x3a\x0d\x10\x86\x22\x8c\xca\x40\x7b\x78\x98\x58\xff\xa0\x4b\xf0\x67\x62\x15\x46\x86\x87\x4f\x92\x7c\xc8\xbf\xc6\xe2\x10\x7a\x47\xde\x15\xae\x16\xff\x04\x01\x68\x82\x15\x3a\xcb\x49\x35\x9f\x51\x23\x48\x5f\x43\xd4\x66\x34\x66\xb0\x82\x23\x4b\x0a\xaf\x14\x33\xd4\x84\xd7\xea\x82\xb2\x92\xe6\x6d\xe6\x32\x1f\xc6\x3e\xcb\x9a\x13\x89\x5b\x22\xd5\xac\xae\x36\x2f\x6b\x26\xb3\x91\x6c\x16\x73\xb9\x3b\x9b\x49\x9d\xb9\x8e\xfe\xdb\xe9\x23\xee\x4e\xb7\x7e\xbe\x92\x47\x7c\x88\x0b\x6d\x2f\xb1\xbd\xb3\xe8\xa6\x98\x50\xb6\xb4\xfd\x9d\xa5\x3f\x0e\x2f\xa8\x59\x7d\xf6\xbd\x73\x5e\x58\xa2\x6d\xdb\x9b\x7d\xe6\xdd\xf7\xb3\x2f\x91\xf0\xcd\xbb\x2e\xbd\x39\xb4\x7f\xe5\x15\x37\x90\x97\xde\x24\x72\x63\x9d\xb0\xe8\x4b\xed\xfb\x76\x6e\x2e\xf5\x17\xff\xda\x39\xd4\xba\x67\xe7\x45\x97\x66\x9f\x79\x6a\x71\xf6\xa3\xec\x0f\x48\xf9\x0b\xdb\xef\xfe\xd5\x77\x96\xce\x68\xbb\x8f\xd9\x1a\xc8\x55\x89\xbe\xa9\x0f\x62\xf0\x3f\x8c\x5d\x58\x2d\x46\xea\x8d\xa4\xad\xa4\x3c\x16\xcb\x1f\xa2\x65\x7c\x26\x37\x16\xd4\xc6\xa8\x56\x23\x64\x52\xd1\x9a\x46\x49\x9f\xb2\xe3\x51\xd5\x8b\x15\x97\x93\x1e\x4c\x53\xf1\x54\x58\x22\x49\x2f\xe6\x53\x78\x2b\x2d\x91\x94\xdf\xe3\x95\x72\xc9\xd3\x1e\x87\xe6\x20\x11\x75\x46\x8c\x55\xcd\xc2\x18\x0d\x6b\xb1\x25\x92\x74\x60\xd5\x2c\x87\x1d\x03\x5f\xd3\xf5\xcc\x2a\x6f\x23\x11\xcd\xe3\x95\x95\x94\xc0\x87\xa2\xd5\x48\x8d\x96\x32\x97\xd5\x34\x62\xe7\x2d\xab\x92\x15\xcd\xea\x65\xc9\x89\x42\x42\x6b\xe4\x64\x45\x8d\x21\x87\xa8\x5f\x1f\x73\x53\x10\x5e\x16\xf2\x46\x0b\x93\x60\x8e\x0f\x34\x9f\x8a\x14\x93\x3c\x34\x36\x0c\x01\x04\xc6\x91\x89\xf3\xa0\x1d\xb9\xdc\x17\xea\x33\xa1\x7b\xcc\x0a\xe1\x1b\x8d\x43\xc8\x2b\x2a\x64\x1c\xde\x97\x51\xaf\xbc\xc4\x81\x91\xf6\x29\x9b\x2c\x2a\x2c\x6c\x48\xb7\xce\x0c\xe2\xcc\xbc\x3d\xb6\x82\xec\x99\xf7\xe2\x94\x78\xd3\x24\x14\x9a\xc2\xcf\xa8\x7d\xd2\x96\x47\xa4\x69\xb4\xfd\x8d\x5c\xec\xc1\xf2\x09\x67\xf5\x64\x7a\x31\x14\x36\x51\x3f\x3d\xb2\x18\xa7\x47\xf9\x47\xf5\x93\xb3\x7f\xe2\x8e\xd7\x24\x14\xa0\x11\x3d\xf8\x60\x32\x26\x50\xee\x51\x7d\x2e\x35\xe4\xf8\x08\xe5\x70\x43\x4d\x4e\x8e\xca\xf1\xab\xb4\x11\x73\xe0\x19\x2d\x1b\x6e\xc4\x1c\x78\x72\x3a\xf0\xc9\x69\x9b\xac\x38\x45\x94\x47\x67\x38\x9f\xa8\x8c\xb1\x5b\x4e\x05\x15\x72\xd0\x98\x61\xfb\x26\xd1\x09\xff\x73\xdd\xe2\xa8\xcb\xe7\x37\xd5\xe5\x31\xb9\x73\x71\x06\xfb\x26\xc4\x19\x90\x49\xe2\x0c\x54\x4f\x34\x2f\xd4\x40\x0d\x3b\xd2\x25\x6c\x60\x96\x44\xd5\x30\x06\x17\xa8\x1e\x64\x56\xd4\x23\x0e\x30\xcc\xa0\x3e\x2c\x2b\x8f\xd9\x14\xb1\xca\x3f\x36\xce\x40\x53\xfc\x48\xbc\x34\x51\xf8\x49\xb7\x7a\x0a\xe2\x70\xcd\xb8\x11\x66\x9d\x0c\x8e\x4f\xf2\x46\xd7\xa9\xda\x7c\x4c\x44\x5d\xc7\xcf\xe5\xc5\x18\xec\x9e\x10\x63\x40\xa6\x8e\x31\x50\x4b\x1d\xaa\x42\x0d\xaf\x12\x09\xb9\xae\xc7\x06\x1b\xa8\x41\x2c\x28\x6f\x1c\x70\xd1\x85\xd4\x26\x16\x08\x32\x18\xdb\x0b\x8c\x5d\x16\x43\x70\x6a\x66\x8d\x11\x7e\x17\xb1\xae\x32\xe4\x25\x03\xc4\x3a\x5e\xe6\xdf\x0e\x0f\x9f\x2a\x1d\xed\xd4\x2f\x1b\x67\x5c\x5d\xf0\x80\xd0\x2b\x3c\x86\x96\x96\x15\x9a\x41\x2f\x03\x6e\x14\x05\x97\xa2\x2c\xcb\xc0\x16\x55\x85\x63\xaa\x84\xa5\xde\xd5\x22\xa3\x54\xa5\x51\x21\x9c\xbe\xba\x04\xe1\xd4\x56\x52\x9d\x7d\x95\x54\x73\x33\xdf\x7a\x2b\xbb\x31\x93\xe1\xeb\x33\x19\xfa\x7f\x2c\x1e\xd9\x2d\x2c\x10\x9e\xd6\x63\x0f\xd6\xe7\xc7\x1e\x90\xcf\x13\x7b\x60\x96\xcb\x04\x23\xf6\x40\x95\x26\x44\x1e\xb4\x8c\x8d\x3c\xd0\xd7\xc9\x38\x63\xba\x00\x56\x84\xa2\x13\xb9\x81\xfc\x84\xd5\xb3\x66\x91\x07\x1d\xac\x3a\xd8\x62\x52\xf2\xe7\xa6\x15\xf5\x83\xf7\x5f\xb4\x7e\x6b\xf6\x2f\xef\xb7\x5f\x18\x59\x78\xff\x96\x35\x17\x91\xea\x62\xbb\x78\xca\x11\x92\x77\x6d\xba\x4e\x69\xaa\xd8\xb9\xb9\xac\xd4\xc4\xc0\x2d\xb6\xde\xfc\xec\xfc\xbf\xdc\x49\x01\x76\x94\x7c\xfd\xf8\xfc\xcc\x57\x3b\x57\xfb\x09\x27\x08\xa6\xc7\x0e\x66\x1f\xb3\x58\xd2\x5f\x73\xce\xfa\x62\x35\xf0\x8c\xef\x13\xe7\x6e\x3a\xfb\xdd\xa0\x9f\xae\x4a\x46\x4d\x68\xc5\xd8\xaf\xa2\xab\xa3\x6a\x67\xe1\x7c\xc5\xb9\xa0\x03\x51\xcc\x24\x2b\xc5\xdc\x49\xb3\xc8\x78\x0d\x65\xba\xee\xc9\xc6\xba\x87\x53\xa4\x98\x3b\x5e\xb6\xe6\xc2\x0b\x54\x0a\x90\x93\xce\x94\x4a\x29\xc3\x51\xca\xf9\x3a\x93\x13\x80\xe2\x12\x50\x98\x05\x74\x1d\xce\xfe\x93\x71\x81\x72\x97\x19\x71\x06\x4c\xe6\x37\x74\x99\x6f\xfd\xff\x29\xb3\xea\xa5\x12\x27\x3d\x3e\x2c\xc9\x22\x2b\xa9\x32\xa7\x3f\x80\xe3\x69\x8c\xcc\x2a\xc9\xad\x14\x93\x4b\x8e\xae\x6c\x61\xc9\x89\x3b\x67\x67\x17\x94\xdd\x30\xba\x0d\xd9\x3f\xd2\xe3\x0b\x6e\x9e\xb6\xec\xb5\xd3\x97\xbd\x6e\x9c\xbe\x47\xc3\x09\x50\xfe\x60\x68\xa2\xfc\xa7\xd3\xb9\xb1\xd2\x14\x96\x7e\xa5\xb1\xc8\x4c\x2a\xfe\xb5\x7a\x48\x81\xa0\xcb\xff\x5c\x2e\x9e\xe0\xc1\x69\x22\x50\x30\xa8\x60\x02\x1c\x6a\x80\x4e\xa0\x5e\x29\xa3\x7a\xa3\x2c\xba\xa0\x10\x42\xaa\xd5\x31\x6e\xa6\x0d\xc8\x8a\x26\x79\xb0\xd0\xde\xb8\x21\x41\xa6\x05\x0f\x0b\x2b\x28\x8c\x4e\x37\x86\x15\x4c\x0a\xcd\xd7\x46\x63\x0a\x90\x83\x55\xfc\x25\xda\xcc\x61\xe8\x02\x06\x81\x55\x0f\x21\x40\x9a\x5c\x55\x89\x32\x63\xa8\x3a\x4a\x1d\x79\xdd\xc8\xc1\x76\x26\x25\xbb\x2f\x91\x17\x20\x30\x09\x15\x2b\x0b\x14\x98\x9a\x8f\x95\xf8\x73\xdd\x79\x72\x5e\x56\xb2\xc4\x88\x1b\x08\x65\x2f\x14\x6e\x33\x79\xd0\xee\xb9\xa5\x00\x17\xfa\x28\x05\x7a\x8e\x08\x22\xc7\x84\xae\x71\x9e\x58\x21\x2e\x74\xe4\x6c\x2c\xc4\x88\xee\xa3\xf3\x3a\xab\x2c\x34\x81\x09\x3d\xc4\xd2\xa6\x41\x56\xdd\x79\x75\x34\xa6\xe6\x43\x0f\x91\xa7\xa3\x5f\x3a\x7b\x12\x3a\x74\x71\x93\x7a\x4a\xeb\x9b\x3b\x9e\x0f\xdd\x54\x75\xf2\xf5\x31\x7c\xe8\x82\xae\xbb\x27\x51\x77\x21\xa8\x85\x2b\x21\x19\xe0\x20\xa2\x56\xe3\x8e\xb6\x1a\x8e\x4d\xa5\xcc\x3a\xdc\x72\x0b\x49\x19\x35\xe4\xc0\xa9\xab\x56\xca\x68\x33\x48\x44\x0b\xf9\x65\x25\xa5\xb8\xca\xd1\x10\x0c\xcb\x8f\x09\x66\xa9\xc8\xca\xe3\xbe\x4c\xad\xa2\x5a\x12\x7f\x87\xfe\x89\xd1\x5b\xa7\xee\x02\x03\x46\xaf\x9d\xa2\x03\x5c\x86\x5d\x97\x83\x8d\x23\xef\x9a\x0f\x8a\xcf\x40\x25\xd4\xc3\x77\x74\x16\x19\x99\xcf\x20\x81\x03\xee\xe7\xd3\x4f\xd2\xa5\x2c\x2b\xc6\xac\x97\xbf\xc4\x9b\x74\x11\xfb\x10\xe3\x0c\x6b\xf9\x4c\xba\xd8\x51\x2e\x14\x23\x0b\x92\x41\x3f\x5e\x25\x66\xd4\x2a\x16\x78\x21\x33\x06\x41\x19\x89\x66\xd4\xd2\x98\x66\x31\x67\xd4\xb2\x18\x6e\xde\x85\xa8\xab\x56\x2e\xd0\x49\x5e\x56\x5d\x48\xd0\xa9\xa0\x2f\x60\xc7\x9d\x12\xd9\x85\x04\x3e\x9a\xb9\x08\x59\xb1\x5a\x5a\x4b\x65\x16\x7d\x38\x2e\x19\x46\x2f\x97\x9a\x4f\x1c\xbf\x91\x2c\x23\xf6\xb9\xb7\x2d\xe3\x1f\xca\xcf\x8d\xf9\xec\x9c\xd5\xfb\x07\xb3\x27\xb2\x8f\x92\xf0\x43\xb7\x77\xef\xee\xea\xd9\x9d\xb8\xfd\x41\xae\x8f\xb4\x10\x0b\x59\x6c\xb3\xe4\x25\xcb\x14\x59\xc9\x62\x62\x79\xec\xc7\x16\x0b\xff\x57\xc9\xfa\xd4\x61\x36\xd6\x57\x8f\xbc\x6b\xfa\x48\x58\x8a\xb6\x75\x02\x7b\x0b\xf5\x8f\x2b\xd8\x39\x5f\x69\x0c\xad\x1f\xb5\x28\x8e\x16\x76\x67\x2c\x1d\x2b\x09\x08\x46\xd0\x45\x37\xe2\xc2\x6c\x6b\x34\x83\x8a\x8b\x32\x5a\x0f\x89\x68\xf1\xb0\xac\xf4\x59\x84\xa2\x92\xd2\x8a\x80\xa3\xbe\x55\x27\x57\x70\xe1\x5e\x41\x2d\x9d\xe2\xdc\x5e\x56\xc3\xc1\x95\xd0\x84\x26\x9d\x9a\xd7\x30\x86\x26\x3f\xc0\x18\xe7\x30\xd5\x18\xdb\x79\xab\x49\xc9\x9f\x77\xff\x68\xb0\x4f\xdb\xf2\x9b\x13\xa7\xae\xe0\xa4\x6b\xb7\xad\xdd\xb7\xe8\x8c\x81\x63\xd7\x5d\xfa\xd4\xe0\xc0\x8f\xf6\x8c\x2d\xa6\xf0\x3e\x47\x36\x9e\xbb\xf2\xcc\x35\xcc\x3c\x5a\x32\x34\x6f\x71\xfe\xee\xde\xe2\xf9\xf3\x17\xe7\x3b\x56\xeb\x73\x7b\xd8\x2c\xce\xaa\x18\xe3\xac\x2a\xc0\x07\x0f\x4f\x37\xd2\x4a\xad\x8c\x6b\x1e\xea\x9e\xb0\xf2\xd4\x53\xc5\x5c\xa5\x2a\x4a\xca\xa4\x88\xe6\x96\x32\xaa\x3b\x8a\x69\x55\x7c\x2c\xe9\xc6\x4c\x74\x37\xb1\x44\x52\x95\xf8\xb5\x4f\xca\x30\xb6\x66\x37\xd2\x7a\x6a\x95\x15\xb2\x92\x32\x99\x2d\x45\xd5\xee\x84\xe6\x2b\x91\x99\xd9\x79\xda\x40\xad\xdc\xf8\x2b\x10\xab\xf5\x2f\xb9\x08\xb4\xc2\x91\x5a\x67\x1b\x6b\x05\x81\xf3\x84\xdf\xf1\xbd\xe2\xfb\x20\x41\x10\x54\x88\xaa\x62\x3c\xcd\xe9\x24\x50\x96\x28\x1d\x1f\xa0\x71\x90\x53\xb1\xbe\x7c\x9f\x67\x2c\xd4\xc2\xef\x46\x63\xfc\x08\x6c\x11\x9e\xe7\x57\x89\x7f\x83\x52\x58\x06\x58\xac\x4a\xc8\xa4\x1c\xa6\x62\x09\x6b\xf3\xe1\xd6\x1f\x1c\x4b\x97\x32\x27\xae\x14\x73\x3c\xd2\x45\xcc\x75\x43\x2f\x9c\x4a\xcc\xe3\x84\xec\x28\xc6\x0d\x29\x8d\x37\x21\x87\x8c\x41\x91\x36\xd6\x4b\xdb\x32\xce\x15\x13\x3e\x19\xbb\xa1\x41\xf2\x78\xfb\xd0\xbb\xb9\x8e\x6b\x33\xb8\xf8\xfe\xde\xef\x38\xb8\x8f\x5b\x25\xfc\x86\x9f\x89\xfb\x87\xfe\x09\x5c\x80\x05\x38\x00\xef\x13\x66\x9e\x3c\xca\xad\xfa\x9d\x5e\xe7\x78\x1f\xb7\x4a\x7c\xec\xf3\xfc\xfe\x3e\xb1\xe3\xd3\x0f\x8c\xdf\x27\x70\x21\xff\x17\xf2\x1d\x53\x17\x58\xa0\x06\xb9\x9c\x04\x1e\xcc\x02\x16\x50\xa4\x83\xd9\x22\x65\xd0\x4e\xb1\xb0\x47\xe8\x34\x45\x8c\xfd\xfb\xc2\xcd\x4b\x0f\xce\xa8\xe7\xff\xf2\xd3\x8b\x5f\x9d\xb7\x74\xe8\x8e\x2f\xfc\x14\x9f\xd7\xc3\xbf\x48\xf6\x63\x9d\x9f\x1a\x50\x2d\xf8\x3c\x49\x7f\x1e\xcf\x08\x9d\xe8\xf3\x90\xbb\xdc\x82\xcf\x9b\x45\x66\x92\xb8\xb3\xcc\x64\xee\xa9\x6b\xf8\xe8\x92\xc5\x42\x70\xee\x1d\x6b\x9e\x7e\x7a\xdd\xf1\x21\xd6\xbe\xc1\xec\x53\xe4\x16\xe2\xcf\x7f\x9e\x79\xaa\xe7\x21\xa3\x77\xdc\x5c\x66\x32\x0f\xd6\x35\x7c\x4c\x2e\x59\xfc\xd1\xd0\x1d\xab\x8f\xbf\x7a\x31\x7b\x1e\x0f\xeb\xf9\xbf\x70\xa7\x50\xde\x22\x28\x83\x85\xd8\x47\xad\x71\xfd\xb1\x48\xb5\xeb\x34\x24\x57\x2d\xcc\x48\xd3\xb3\xbd\x0c\x10\x54\xab\xac\x8a\x48\x7a\x59\x92\x00\x4d\x00\xa3\x4b\xe5\x80\x09\x07\x73\xb7\xeb\x11\xa3\x8f\xc9\x99\xe3\xb1\xca\x03\x8d\x87\x05\xfc\x8b\xdc\x5b\x26\x0f\xee\xc7\x97\xc1\x00\x50\xe1\xca\xe2\x69\x11\xa1\x33\xda\x24\x1c\xd3\xcc\x52\x46\x35\xb3\x98\x54\x59\x6f\x93\x59\x60\xac\x48\x76\x59\xb5\x52\x3b\x5a\x2d\x63\x4a\xca\xa1\xda\x99\xbb\x5b\x80\xf8\xfe\x0c\xff\xe5\x5f\x5c\x66\xc0\xbc\x2c\x1f\x6f\x8e\xe2\xcd\xfd\x06\xf1\x2e\xa5\x2d\xb1\x44\xd5\xd2\x1c\x3a\xf6\x18\x0e\x3a\x86\xbb\x6a\x62\xb5\x85\x1d\x52\x06\x87\x9b\xae\x02\xb5\x58\xa6\xed\xc1\x13\xe9\x31\xea\xe8\x1c\xaf\x98\x9f\x8e\xd3\xcf\xd2\x3c\x45\x11\xd8\x4b\xde\xe5\x56\x08\x45\x50\x4c\xfd\x7b\xab\xd1\x8f\x72\xdd\xc9\x8e\x63\x5f\xb2\x41\xb9\x10\xd1\x2f\x58\xf2\x6b\x3c\x8f\xd6\xde\xfd\x5b\xb6\xed\xdf\xbf\x75\xeb\x7e\x6e\xf8\xbc\x75\xfb\xae\x5d\x7f\xde\xfa\xab\xd9\x19\xdd\xcd\x00\xe2\x39\x84\x31\x84\x4a\x60\x83\x33\xf4\xb8\x52\xd1\x12\x8f\xeb\x4c\x66\x9a\xa9\x48\xdf\x0c\xd6\x3f\xc0\xdd\x7c\xa2\x16\x1b\xfc\x66\x2a\xef\xd0\x44\x56\xd8\x47\x95\x58\x8e\x99\x4d\xcc\x50\xfd\xe0\xa6\x58\x50\xae\x27\x72\x50\xa6\x37\x37\x93\x70\xf6\x38\x79\x85\x84\x1f\x21\x61\x02\x23\x60\xbc\x58\x1f\x6f\x84\xaf\x93\x11\xe4\xec\x0a\x02\x51\xcd\x28\x9a\x88\x32\xa9\x7c\x4c\x93\xa8\xdb\x94\x37\xfe\x90\xb8\xb4\x91\x31\x96\x72\xde\x7c\x9e\xd2\x79\xf0\x75\xae\x62\xec\x73\x54\x2e\xa6\x3f\x6a\xf4\x39\x84\x3e\x47\x27\x06\x9b\x37\x81\x06\x0c\x08\x74\x8f\xbc\xcb\xbf\x21\x3e\x03\x11\xb8\x0e\x92\x75\xc0\x6a\xe6\xb0\x2c\x4a\x99\xcf\xa4\x81\xd4\x15\x15\x47\xd4\xf2\x78\x1a\x04\x68\x17\x22\x6a\x65\x2c\x2d\x0a\xf8\x99\x3b\x9e\x16\xd9\x67\xce\x18\xf2\xc9\x36\x1c\xd3\x38\x53\x2c\xa6\x79\xc5\x8c\x56\x46\x2d\x6a\x6f\x83\xb1\x3b\xae\xba\x62\xc9\x06\xdc\x36\x6f\x60\x09\x7c\x5a\x13\x56\xbb\x08\xa0\x25\xa4\xc9\x22\xc6\xdc\xb2\xba\x82\xe1\xf6\xb8\x6e\x0e\x18\xb5\x05\x83\x3a\x5b\x75\x5e\x39\x13\x98\x49\xba\x0f\x1d\x3a\x44\x9a\x3e\xec\xdd\x3d\xc7\xd9\xbe\xb3\xeb\xb2\x1b\xc9\xf7\xb3\x2b\xe8\xeb\xc6\xbd\xdd\xdb\xe3\xce\xc4\x95\xb3\x3e\xca\xbe\x48\xde\xbe\xeb\xce\xbb\x8a\xdf\x27\x5e\x47\xc9\xdb\x8e\xd2\xfb\x6e\x29\xb9\xeb\xce\xbb\xa4\xeb\x6f\x93\xe5\xb7\x4a\x1c\xc4\xfe\x3b\x89\x8d\x83\xc5\xfc\xd7\x84\x65\xa2\x0a\x66\x70\xc3\x21\x9d\x63\x9a\x14\xc7\xe3\x69\x09\x7b\x60\x52\x2c\x29\x8d\xc5\x62\xf8\xb9\xf1\x11\xde\x83\xa0\x57\xd2\x45\xf2\x4e\xd3\xb1\xb4\xc8\x08\x64\x44\x24\xa0\x14\x79\x4b\x24\x69\x42\xcf\xd0\x04\xcc\x51\x96\x72\xf4\x21\xaa\x1b\x4f\x08\xf4\x6d\x49\xdc\x7b\x73\xb8\x65\x45\x2b\xc2\x35\x0c\x24\x59\x49\x59\x6d\x8a\x33\x57\x05\x24\x2c\x87\x65\x22\x63\x25\x10\x39\x2c\xd7\xf1\x61\xde\x2c\x2f\x26\xb7\xed\x3b\x48\xce\xfd\xe6\xe5\xa6\xbd\x77\xef\x37\x6d\x5e\xb0\xcd\x24\xce\xdb\xbc\x39\xbb\x94\x24\xb3\x8b\x39\x6f\xf6\x4e\x72\xc9\xa9\xb7\x48\x05\xc9\xbe\x4d\x1a\x48\xf6\x57\x40\xd0\x49\xe8\x12\xba\x80\x87\x76\xc8\xf5\x75\xb3\x1e\x77\xa1\xdf\xe7\xca\x31\x20\xe1\xa0\x7e\xd1\x89\xfd\x5a\xe5\xa0\x4c\x1f\x70\xf2\x08\xeb\xcb\x21\x00\x51\x31\x35\x41\x10\xbe\xcd\x4e\x92\x54\x67\x5c\xf3\x0b\x99\x64\x99\xbb\x8a\x02\x96\x5f\x82\xb2\x7c\xb4\x04\x65\x28\xaa\x06\x30\x85\xb5\x92\xf1\x9b\x57\x62\x1d\xb5\x4a\xaf\x25\x92\x0c\x60\xf2\x42\x80\xc2\x55\x89\x19\x61\x2c\xcd\x18\x4f\x59\x4a\x9d\x96\x48\xd2\x83\x31\xdc\x1e\x97\xbe\xbd\xe2\xa9\x94\x15\x2c\x49\xa5\x96\xca\x7a\xb6\x0f\xf8\x65\x3a\x1f\x9d\xbe\x62\x65\xae\x48\xbb\x7e\x0d\x7d\xfb\x6f\x6f\x2e\xfd\xc6\xba\x86\x05\x97\x2f\x59\xbf\x9e\x3b\x78\xcf\xa9\xf4\x81\xec\xed\x07\x4e\xa5\xee\xe5\xb7\xfe\x7c\xe1\xf0\x71\xbf\xf7\xf7\x2e\xcf\xea\x55\x0b\xf5\x03\xb5\x6f\xe5\x8a\x58\x62\x9d\x17\xf1\x0b\xa6\x26\x08\x51\xcf\x23\x2f\xe7\x35\xe9\x28\x0d\x52\x1c\x44\x8a\x43\x55\x1c\x8b\x0a\xfa\x62\xaa\x27\xca\x82\xd5\xc3\x51\x95\x3b\xa6\x9a\x18\x2b\x79\x65\x2c\x19\xc0\x68\xf5\x40\x88\x7a\x9d\x01\x9f\x25\x92\xe4\x02\x79\xa5\x03\x04\x56\x66\xae\xcc\xa0\xb7\x2c\x18\xb8\x5f\x4d\x97\xb0\x00\x0a\xce\x72\x56\xb5\x92\xb2\x44\x42\xf3\x88\xcc\x41\x2b\x62\x69\xf9\x2c\xda\x1b\xc7\x19\xc6\x0d\x19\x15\xab\xc6\x94\xf2\xac\xbb\xf7\xa6\x9b\x88\xe9\xfd\x73\x1e\xda\xfe\xfd\x03\xa7\xfe\xcf\x81\xce\x2d\xb3\x77\xee\xfa\xe0\x83\x03\x54\xe4\x9f\x47\x5f\x79\xd7\xef\xfd\xf4\x55\x2c\xbe\x77\x81\xcd\xbe\x63\x6b\x14\x6b\x7a\xd2\x19\xb6\x07\x40\xb2\x99\x9a\x70\x6f\x65\x16\xe1\x18\x83\x9e\x16\xeb\x8e\xc7\xb5\x0a\x21\x93\x76\xb7\xb6\x25\x7a\xab\xdd\x79\x47\xcf\x49\xc5\xd7\x1c\x8f\xe3\x49\x69\xb2\xcc\xdb\x41\x0d\xe7\x06\xba\x4c\x6b\x61\xac\x89\x44\xfd\x0b\x3b\x45\x6b\x36\x16\x2d\xe1\x59\x4c\x9b\x1c\x4b\xba\x2a\x8d\xd2\x09\xa9\x3e\x97\xc7\x12\x49\x56\xba\x72\x99\x1d\x7d\x95\xe5\x74\xce\x71\x68\x33\x49\x44\xf5\xc7\xb4\x2e\x31\xa3\x36\xc5\x92\x5d\x33\xe9\x4f\x74\x75\x5b\x22\xc9\x99\x5d\xf4\x76\xa6\xd7\x12\x51\xbb\x1c\x58\x9d\xaf\x45\xcc\x24\x5b\xda\xe9\xa7\x2d\x31\x4b\x24\xd9\xde\x42\x6f\xdb\xe3\x96\x88\xd6\x47\x22\xda\x4c\x97\xac\x24\xcd\x45\x18\x0d\xd7\xde\x25\x2b\x5a\x43\x18\xe3\xc8\xb5\xba\x5a\x3c\x04\xaf\x90\x15\xb5\x25\xa1\x35\x94\x23\xff\x93\x16\xc6\x2a\x61\xb5\x46\x32\xc8\xa4\xb5\x52\x83\xa7\xed\x95\x05\xaa\xa9\x72\x7d\x53\xf4\xd4\x42\x75\x56\xa7\xec\xbe\x20\xa0\xce\xd6\xea\x3a\xeb\x82\x01\x62\xd5\xb5\xd6\x36\xcb\xd0\x5a\xbc\x63\x66\xdf\x14\x5a\x6b\xa1\x5a\xb3\x47\xd5\xba\xb8\x66\xc6\x8d\x06\xda\xc1\xb5\xda\xee\x58\x4c\x2d\x72\x68\x09\x6a\xc0\x0f\xfe\x3d\xea\xeb\x64\xea\x8b\x31\xf5\xc5\x3a\x8b\xf4\x82\x8c\xa9\xbe\x58\x9b\x25\x92\xec\xc4\x62\x8d\x9d\x5e\xfa\x41\x67\xbb\x25\xa2\xc6\x1c\x5a\x3f\x89\x68\xbd\x62\x26\xd9\xdb\x4f\xbf\xeb\x9d\x65\x89\x24\xfb\x7b\xe9\x6d\x7f\x82\xfe\x58\xff\x6c\x4b\x04\x43\xf1\x3a\x5d\x3a\xd7\xa2\xd6\x1f\x93\x15\x2d\x9c\x53\xa3\xd6\xdb\x9f\x48\x68\x45\x54\x91\x03\x9f\x5f\x7d\xa3\xdf\x91\xf6\xa9\x54\xb8\xaa\xc0\x67\xb3\x58\x5d\xcb\xc9\x94\x58\xe8\x43\x72\x32\xbf\x06\x26\x9d\x93\xe1\x55\xae\xee\xdf\x2f\x28\xe9\xfd\x08\xfc\xb8\xba\xc1\x2f\xae\xbd\xf7\x79\xe3\x3a\x72\x24\x1b\x97\xd6\x9a\xef\x00\x02\x12\x70\x00\xba\x4d\x02\xd2\x45\xa7\x76\x01\x48\xfb\x47\x8e\x8c\x1c\x95\xd6\xb2\x95\x22\xef\xcf\x7b\xdc\x7b\x30\x87\x3e\x8d\x7c\x0c\x00\xbf\xd5\x7f\xed\x63\x00\x72\x12\x2e\xe7\xed\xf0\x15\xe1\x11\xa8\x13\x96\x43\x42\xbc\x03\x5a\x85\x2c\x34\x91\x9f\xc2\xad\xdc\x0f\x60\x15\x77\x04\x66\xf2\x87\x20\x24\x2c\x84\x56\xf2\x7f\xa1\x9b\x8f\xc2\x75\x5c\x11\xec\xe7\xde\x1b\xc9\x08\x87\x60\x2d\x7f\x33\xcc\x12\xb6\x40\x4c\x58\x09\x09\xe1\x4b\x50\x2d\xcc\x81\x41\x61\x2f\x9c\x2f\x2c\x87\x56\xe1\x7c\x18\x14\x2e\x85\xd9\xe4\xbf\xe0\x7c\xf2\x0c\x54\xf1\x1f\x42\xb7\x70\x31\x5c\x25\x98\x61\x13\xff\x0a\x84\xcc\x76\x18\x14\x9f\x86\x7a\x71\x21\x74\x89\x51\x68\x13\xaf\x83\x2e\xb1\x0a\xba\x84\xbf\x40\x97\xb8\x00\xa2\xa6\x7e\xe8\xe2\x9e\x85\x4e\xe1\x21\x08\x8b\x3f\x84\x2e\x41\x85\x2e\xf3\xcd\xd0\x65\x6a\x86\x2e\xf1\x21\x18\x14\x9b\xa0\x4b\xfc\x2e\x0c\x8a\xfb\xa0\x4b\xf8\x35\xac\x15\xd7\xc2\x0c\x93\x15\xea\xc4\x27\x21\x64\x4e\x83\x57\xbc\x0f\x82\xe2\x65\x50\x2d\x1c\x85\x85\xdc\x00\xdc\xca\x9f\x03\x36\x2e\x01\x56\x7e\x0f\x34\x09\x43\xb0\x9a\xdb\x06\x7d\xc2\x7a\x58\x28\xfc\xcb\xc8\x1f\x85\x4e\x18\x14\x9e\x84\x41\x61\x10\x06\xb9\x4f\xa1\x47\x38\x04\x67\x8a\x2e\x08\x70\xb7\x43\x1d\x77\xee\xc8\xeb\xc2\x6f\x21\xc0\x1d\x80\x80\x79\x27\x78\xc5\x32\x08\x08\x57\xc3\x6c\xe1\x65\xa8\x17\xbe\x04\x83\xfc\x1a\x18\x12\x7c\xb0\x96\xfb\x0c\x1a\x85\x2c\x04\x85\x7f\x06\xbf\xe9\x12\xa8\x13\xbe\x03\x01\xe1\x49\xa8\x10\x9a\x61\x25\x77\x1b\xd4\x91\xef\xc3\xf5\xdc\xad\x60\x15\x23\xb0\x8e\x62\xcf\xd9\xe0\x4b\xc2\x1c\x38\x43\xb8\x0b\x12\xe2\x37\xe0\x2c\xf1\x0a\xa8\xe7\x08\x7c\x59\xf8\x0d\x9c\x2d\x98\xe1\xa0\xc9\x07\x0b\xf9\x8b\x61\x0d\xff\xef\x20\x08\x0b\x61\x17\xc5\x1e\x3f\xfb\x00\x0e\x71\x19\xb8\x44\x70\xc0\x00\xdf\x09\xeb\xf9\x7e\x58\xc9\x5d\x0f\x67\x89\x83\xd0\x29\x6c\x84\x0e\xae\x1e\xbe\x4a\x3e\x84\xe5\x9c\x07\x36\xf0\x87\x60\x2b\xff\x73\xe8\x13\x6f\x80\x4b\x45\x0d\x36\x98\x2e\x86\x05\xbc\x06\x4d\x88\x7b\x81\x97\x79\x04\x06\x50\x17\x55\x4c\x17\xc6\x8b\x7b\x76\xe4\x04\xd5\x05\xf7\xec\xc8\xef\xb9\x67\x47\x8e\x88\xdf\x86\xe6\x9c\x1e\xc6\xbd\x84\x46\x98\x29\xee\x85\xf9\x54\x17\xf9\x2f\xaa\x0b\xb1\x02\x06\xc5\x7a\xa8\x43\xdc\x0b\xbc\x4c\x9f\xc0\x02\xd4\xc5\xe0\xd8\x17\xf7\x08\x98\xb9\x47\x60\x88\x7b\x64\xe4\x24\xf7\xc8\xc8\x71\xe1\xa7\xd0\x9b\xd3\xc3\xf8\xd7\x56\xe8\x12\xee\x86\xc5\xa8\x8b\xfc\x17\xd5\xc5\x6b\x10\xa2\x57\xf3\x30\x6c\x34\x2f\x87\xd5\xb4\x4d\xfc\x95\x70\x1e\xff\x18\x6c\xe1\x8f\x02\x98\xef\x00\x30\xae\xdc\x8d\x00\xe4\x6d\x00\x32\xc8\x5e\x70\x02\x80\x5c\x0f\x00\x5f\x04\xa0\xba\x30\x5e\xe2\x6a\xb8\xcf\xd4\x03\xfb\xc8\x1b\x70\x21\xf9\x15\xf4\x90\x2c\x0c\xf2\xfd\xb0\x9e\x9f\x0f\x0b\xf8\x1e\x18\xe4\x9e\x86\xbd\xe2\x61\xb8\x99\xfe\x2e\xd7\x0d\x8d\x5c\x1f\xcc\xa3\xcf\x15\xea\xa0\x5b\xf8\x15\x2c\x16\xba\x00\xc4\x04\x84\xc4\x03\x50\x27\xc5\xa1\x47\xda\x4f\xe7\x73\x68\xcc\xfb\xbb\x1a\x0e\x92\x2b\x39\x81\x7b\x80\x9f\xc3\x6f\xe2\xef\xe4\x7f\xc6\x7f\x20\xb4\x09\xab\x85\xbd\xc2\xbd\x42\x5a\x14\xc4\x3e\xf1\x09\x53\x87\xe9\x2b\xa6\x13\xe6\x2d\xe6\xc7\xa4\x39\xd2\x13\xd2\xfb\x96\x5a\x4b\xaf\x65\x8d\x65\x97\xe5\xd7\x45\xf7\x17\xfd\xd1\xba\xc9\x7a\xd4\xe6\xb3\x1d\xb4\x9d\x28\xbe\xa8\xf8\x4d\x7b\x95\x7d\xaf\xfd\x0f\x25\xb3\x4a\x8e\x38\x3a\x1c\x37\x39\x3e\x90\x57\xc8\x6f\x2a\xab\x95\x64\x69\x55\xe9\x39\xa5\xff\x59\x56\x5d\x76\x75\xd9\x8b\x4e\x70\x7a\x9c\x0b\x9d\x5b\x9c\x5f\x76\x3e\xe8\x8a\xb9\xee\x73\x7d\xe2\xde\xe1\x7e\xd1\x13\xf3\x3c\x52\x3e\xa3\x7c\x47\xf9\x0f\x2b\xaa\x2a\xce\xa9\x2c\xaa\xbc\xbe\xf2\x85\xaa\x33\xaa\x8e\x7a\xab\xbd\x0f\x7a\x3f\xf3\x6d\xf0\x7d\xcb\xf7\x7b\x7f\x97\xff\x26\xff\x1b\x81\x86\xc0\xfc\xc0\xc1\xc0\x1b\x81\x37\x82\x45\xc1\xbd\xa1\xa2\xd0\xed\xe1\x8a\xf0\x40\xf8\xe3\xea\xea\xea\x63\x35\x2b\x6b\xae\xac\xb9\xbf\xe6\x3f\x6b\x6f\xaa\x7d\xa0\xf6\x44\x5d\x5f\xdd\xa1\x19\xf6\x19\x6d\x33\x1e\xae\xe7\xea\xab\xeb\xd7\xd4\x5f\x5f\xff\x42\xfd\x87\x0d\x7b\x23\xb6\xc8\xcb\x8d\xb3\x1a\x6f\x6f\x7c\xaf\x69\xa8\xe9\xb5\xe6\x95\xcd\x27\xa2\xb7\xb4\x04\x5a\x1e\x6c\x6d\x6e\x7d\x32\xb6\x22\xf6\x40\xec\xc3\xf8\xfc\xf8\x83\x6d\x9e\xb6\x17\xdb\x3b\xda\xef\xeb\xb0\x75\x7c\xa3\xb3\xac\xb3\xa3\xf3\xc9\xae\xee\xae\x27\x13\x73\x12\x2f\x74\x77\x77\x7f\xbf\xa7\xb9\xe7\xf9\xde\x2d\x33\x95\x99\x6f\xcc\xba\x7b\xf6\x8e\xbe\x86\xbe\xc7\xfa\x43\xfd\x87\x06\x84\x81\x43\x03\x6f\x0e\xc6\x06\x6f\x1a\xfc\xe3\x9c\x0b\xe7\xba\xe6\xee\x99\xfb\xf2\x50\xdf\xd0\xd1\x79\x03\xf3\xf6\xcc\xfb\x70\xfe\xb6\xf9\xef\x2d\xd8\xb2\xe0\xd3\x85\xe7\x2c\x7c\x79\xd1\x39\x8b\x3e\x58\x7c\xfd\x12\xc7\x92\x8e\x25\xd7\x4c\xf2\xf7\x2b\x4b\xee\x5e\xf2\xd0\x92\x23\x4b\xfe\xb0\xd4\xb1\xb4\x6b\xe9\x85\x4b\x1f\x5e\xfa\xc1\xb2\xb6\x65\xeb\x96\x3d\xbc\xec\xe1\x65\xcf\x2f\x3b\xb1\xec\xc4\x19\x7b\xce\xf8\xc3\x99\x8e\x33\x6f\x3f\xab\xe2\xac\x0f\x97\xbf\xcc\xe6\x6b\x78\x0f\xe6\x83\x08\xcc\x7b\x21\xc0\x81\x8b\x7e\x4c\x36\xe8\xf3\xb5\x02\xaf\x01\x0f\x44\xb0\x00\xc0\x2c\xdc\x09\xa1\xf7\x04\x5c\x30\x4b\xbf\xe7\x40\x82\x15\xfa\x3d\x0f\xcd\xb0\x5a\xbf\x17\x20\x00\xb7\xe8\xf7\x22\x3c\x04\x0f\xeb\xf7\x26\xf0\x91\xb3\xf4\x7b\x33\x2c\x24\x3b\xf4\x7b\x0b\xd8\xc8\x13\xfa\xbd\x15\xca\xc8\x7f\xea\xf7\x36\xa8\x25\xbf\xd6\xef\x8b\x61\x35\x67\xb4\xc1\x0e\x2b\x38\xe3\xff\x72\x80\x8b\x53\xf5\x7b\x19\x24\xce\xf8\x5d\x05\x02\xdc\xf3\xfa\xfd\x11\x70\x71\xef\xeb\xf7\xcf\x42\x0b\x2f\xc0\x10\x6c\x87\x6d\xb0\x07\x02\xb0\x0e\xd6\xc2\x1e\x58\x0b\x01\xb8\x18\xb6\xc3\x0e\xb8\x02\x76\xc1\x66\xd8\x08\x9b\xf0\xdb\x79\xb0\x1d\xb6\xc3\x46\xd8\x02\xeb\x21\x00\x31\x68\x81\x56\x88\xc3\x59\xb0\x1d\x2e\x82\xed\xb0\x07\xb6\x43\x00\x96\xc3\x16\x58\x0b\x17\xc1\x00\x6c\x87\x2d\xb0\x6e\xcc\xef\x74\x4f\xf2\xb3\xdd\xa7\x79\x56\x20\xf7\xb4\x73\x60\x3d\xec\x82\xdd\xb0\x19\x5b\x1c\x80\x56\x68\x86\x56\x68\x81\x16\x88\x41\x07\xc4\xa1\x27\xaf\x5d\xf4\x7e\x0f\xec\x81\x0d\xb0\x16\x2e\xc5\x27\x6e\x82\xcd\xba\x9c\x33\xe0\x32\x68\xc1\x1c\x85\x36\x68\xc6\xdf\x68\x82\x56\xb8\x18\x3a\xa1\x0d\xea\x31\x8e\x6f\x0b\x04\xa0\x0b\xef\x76\xe1\xff\x13\xc3\xfb\x79\xfa\xf3\x5b\xf0\xdd\x5e\xfc\xa6\x0d\xef\x2f\x87\x00\x84\x20\x84\xf7\xe7\x8e\x91\xc3\x90\xa2\x29\x27\xc5\x64\x52\x6e\x86\xdd\x10\x40\xf4\xf7\xc0\x2e\x58\x0b\xeb\x60\x3d\x6c\x85\xb5\xb0\x0b\xbe\x08\x01\xd8\x0e\x1b\xc6\xe9\xa0\x79\xcc\xbb\xb1\xdf\x50\xfd\x6d\x85\x41\xd8\x84\x1a\xdc\x0d\x7b\x60\x33\xac\x45\xcc\xd8\xff\x4e\x71\xdc\x03\xbb\x11\xc7\xc5\xb0\x19\x2e\x86\xf5\xb0\x0d\x76\xc3\x7a\x58\x07\x01\xb8\x14\xb6\xe1\xff\xbe\x0b\xdb\xb2\x09\xf5\xdd\x0f\x3b\x60\x2d\x5c\xac\xbf\x1b\xfb\x3b\x8d\x10\x98\xa0\x9b\x18\x34\x43\x0b\xf6\x9c\x3d\xb0\x03\xba\x21\x0a\x51\xb8\x1c\xff\x36\xc3\xda\xbc\x67\x35\xc3\x76\xd8\x05\x1b\x21\x0a\x5b\xc6\x3c\x73\x37\x44\x61\x31\x2c\x80\x41\x98\x0b\x4b\x61\x39\xcc\x85\x26\xfd\x99\x53\xf7\xb8\xd3\xf5\xa1\x73\x61\x3d\x5c\x04\x1b\x72\x7d\xbe\x15\x9f\x39\x84\x38\x31\x29\x77\x61\xeb\xdb\x91\x8d\xb2\x15\xba\xb1\x77\xd1\x7f\x3b\x72\xbd\xab\x0d\x67\x09\xfc\x33\x72\x09\xac\x83\x42\x7f\xde\x03\x20\x1c\xe1\x89\x40\x44\xdc\x25\x13\x91\x53\x5e\xc2\x9d\x53\x2b\xd8\xa0\x18\xec\xc8\xaa\x2a\x83\x02\xa5\xc8\x4b\xe7\x42\x96\xa7\x72\xa8\x80\x4a\xa8\x02\x2f\xf8\xc0\x0f\x01\x08\x42\x08\xc2\x50\x0d\x35\x50\x0b\x75\x30\x03\xea\xa1\x01\x22\xd0\x08\x4d\xd0\x0c\x51\x6c\x4d\x0c\xe2\xd0\x06\xed\xd0\x01\x9d\xd0\x05\x09\xe8\x86\x1e\xe8\x85\x99\x30\x0b\x66\x43\x1f\xf4\xc3\x00\x0c\xc2\x1c\x98\x0b\x43\x30\x0f\xe6\xc3\x02\x58\x08\x8b\x60\x31\x2c\x81\xa5\xb0\x0c\xce\x80\x33\xe1\x2c\x58\x0e\x2b\xe0\x6c\x38\x07\xce\x85\x95\xb0\x0a\xce\x83\xf3\x61\x35\x7c\x01\xd6\xc0\x05\x70\x21\xac\x25\x26\xf8\x57\xb8\x1e\x6e\x80\xa7\xe0\x4e\xf8\x03\x7c\x19\x6e\x83\x5b\xe1\x5f\xe0\xbb\xf0\x00\x31\xc3\x2d\xf0\x6b\xb8\x0e\xbe\x46\x24\x62\x81\x03\xa4\x08\x6e\x82\xff\x80\xd7\x88\x15\xee\x83\x87\xe1\x23\xf8\x10\x3e\x86\xfb\xe1\x07\xf0\x2c\xfc\x17\x3c\x02\x17\xc1\xc5\x70\x10\xd6\xc1\x73\xb0\x1e\x8e\xc0\x51\xf8\x05\x0c\xc3\xcf\xe1\x79\xc8\xc0\x06\xf8\x6f\x78\x01\x7e\x09\x8f\xc2\x46\xf8\x00\xbe\x0a\xc7\xe0\x25\xf8\x1f\xd8\x04\xef\xc2\x9f\xe0\x66\xb8\x04\x36\xc3\x17\x61\x2b\x6c\x81\x6d\xf0\x2d\xd8\x0e\x3b\x51\x47\xbb\x71\x54\x5f\x06\x97\xc3\x1f\x61\x2f\x5c\x09\x57\xc0\x55\xf0\x4f\x70\x35\xfc\x10\xbe\x0d\xd7\xc2\x35\xb0\x0f\xf6\xc3\x7b\xf0\x3e\x3c\x01\x2a\x68\xf0\x23\x78\x19\x5e\x21\x36\x52\x4c\xec\xa4\x84\x38\x88\x4c\x14\x52\x4a\xca\x88\x93\xb8\x88\x9b\x78\x48\x39\x24\x21\x05\x8f\xc1\xe3\xf0\x33\x48\xc3\x61\x78\x06\x6e\x84\xef\x91\x0a\xf8\x31\x3c\x4d\x2a\x49\x15\x7c\x85\x78\x89\x8f\xf8\x49\x80\x04\x4d\x1b\xb7\x5c\xb1\x63\x53\xab\xf9\xd2\x6d\x9b\x5b\x5a\x5a\xe6\xe8\xd7\x98\x7e\x4d\xb0\x6b\x7f\x8b\x7e\xd5\xbf\x1f\xd0\xbf\x1f\x88\xeb\xd7\x76\xfd\x8a\x3f\x1f\x6b\x69\x69\xd1\xaf\xad\xfa\x35\xa6\x5f\xe3\xfa\xb5\x4d\xbf\xb6\xeb\xd7\x0e\xfd\xda\xa9\x5f\xbb\xf4\xab\xf1\xbc\x7e\x76\x6d\xd5\x9f\xdb\xda\x5a\xb4\x61\xf3\xc6\x4b\x77\xad\x5f\xb7\x76\xf7\x26\xf6\x51\x6c\x88\x5d\xdb\x87\x84\xb9\x97\xee\xda\x8e\x6f\xda\x87\x06\xe9\x75\x68\x80\xb5\x63\x68\x80\xb5\x63\x68\x80\xb5\x63\x68\xa0\x85\x76\xfd\x1f\x92\x91\x1b\x54\x72\x00\x16\xa9\xd2\x19\x2b\x35\x42\x6e\x5b\xa5\x0d\x99\x22\x2b\x83\xaa\x63\xd5\x22\xb5\xec\xac\x95\x41\x75\xdf\x2a\xaf\x6a\x8a\xac\x5e\x09\x2a\x1f\x98\xab\xf2\x91\x39\xaa\x10\x98\x9b\xe4\xdd\x5c\x84\xbe\x21\xaa\xa8\x7f\x5a\x14\x98\x9b\x14\x53\x5c\x44\xe3\x87\x2e\x8b\xcc\x51\x2d\x81\xb9\xc9\x22\x25\xf7\x56\x0a\xcc\x4d\x5a\x3c\xb9\xb7\xe6\xc0\xdc\xa4\xd4\x94\x7b\x6b\x0a\xcc\x4d\x9a\x5d\xb9\xb7\xd6\xc0\xdc\x27\x40\xbc\x76\x04\x72\x9f\xd8\x02\x73\x93\x56\xc9\x78\xbb\x4a\x2d\x8b\xa0\x93\xb5\x7c\xd5\x7b\x4b\x01\xfe\x5f\x00\x00\x00\xff\xff\xa9\x05\xe3\xd8\x30\xd3\x00\x00") func fontsRobotoslabBoldWebfontTtfBytes() ([]byte, error) { return bindataRead( _fontsRobotoslabBoldWebfontTtf, "fonts/robotoslab-bold-webfont.ttf", ) } func fontsRobotoslabBoldWebfontTtf() (*asset, error) { bytes, err := fontsRobotoslabBoldWebfontTtfBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "fonts/robotoslab-bold-webfont.ttf", size: 54064, mode: os.FileMode(509), modTime: time.Unix(1492020681, 0)} a := &asset{bytes: bytes, info: info} return a, nil } var _fontsRobotoslabBoldWebfontWoff = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x64\xb7\x43\x70\xe0\xdf\xdb\xc5\xf9\x8d\x6d\x3b\xdd\xb1\x6d\xdb\xb6\x6d\xdb\xb6\x8d\x8e\xd3\xb1\x6d\xdb\xb6\xed\x74\x92\x0e\x3a\x4e\xa6\x7e\xef\x7f\xaa\x66\x31\xb7\xea\x53\xe7\xdc\xcd\xb9\x8b\xfb\x2c\xce\xe3\xa1\x20\x2e\x0e\x80\x00\x00\x00\x38\x6c\x03\x68\xff\xe9\x12\xe3\xff\xee\xff\xff\x23\x2e\xae\x2a\x07\x00\x20\xe5\x00\x00\xe0\xff\x87\x61\x8d\xe2\xb4\x84\xa8\x98\x38\x00\x80\x0c\x03\x00\x40\x05\x00\x00\x2d\xe8\x0b\xc8\xba\x84\xa2\x82\x0a\x00\x80\xdc\x01\x00\x34\x01\x00\x60\x2e\xef\x56\x10\x32\x4a\xa8\xa8\x09\x03\x00\x2c\x32\x00\x00\xd2\x00\x00\x68\x36\x8a\xb5\xa4\x2b\xa8\x30\x30\x03\x00\xac\x2e\x00\x00\xca\x00\x00\x18\x76\x3a\x90\xc5\x9a\xd8\x19\x39\x02\x00\x6c\x3d\x00\x80\xa4\x00\x00\xc8\xbd\x8c\x6c\xf1\xbc\x89\xbb\x2b\x31\x00\xc0\x8b\x02\x00\xc0\xf8\x1f\x48\x7d\xa8\x32\xe6\x8e\x16\x76\x00\x00\xef\x0a\x00\x20\x0d\x00\x00\x6a\xa6\xd2\xcc\x50\x66\x61\xe4\xe2\x08\x00\x88\x94\x00\x00\x40\xff\xbf\x20\x5b\xd8\x7a\x99\x03\x00\x22\x23\x00\x68\x9a\x03\x40\x59\xfd\xaf\xed\x40\x0e\x4b\x33\x23\x53\x00\x30\xcf\x04\x00\x80\x09\x00\x00\x76\x48\xdd\x50\x23\x4b\x4b\x33\x23\x00\x30\x9f\x06\x00\x80\x08\x00\x00\x52\xe4\x78\xc8\x4a\x4b\x3b\x57\x4f\x00\x30\xbf\x06\x00\xd0\x14\x00\x00\xab\x7f\x50\x67\x13\xb2\x75\x30\x31\x02\x00\xab\x40\x00\x00\x99\x05\x00\x90\x4d\x96\x05\x58\x6d\x3b\x23\x4f\x47\x00\xb0\x51\x04\x00\x80\xf8\x3f\x40\x61\x40\x1a\xed\x8d\xec\xcc\x00\xc0\xc6\x11\x00\x40\x8e\x00\x00\x1c\xd5\x04\x25\x5e\xd7\xd1\xc1\xc5\x15\x00\xec\x54\x01\x00\xe4\x1f\x00\x80\xbe\x6a\xa1\xf8\x7f\x3b\x3a\x9b\x39\x02\x80\x83\x2c\x00\x00\x91\x00\x00\x74\x58\xfd\xd9\xd6\xf7\x30\x33\x36\x07\x00\x87\x65\x00\x00\x20\xff\xe3\x5a\x41\x45\x0b\x00\xfe\xf7\x2b\xd3\x7c\xbf\xe7\xfe\xd3\xe1\x3b\x14\xfa\xff\x74\x2e\x20\x67\xd6\x73\xd3\xc4\xd0\xd4\xd0\x70\x1f\xcc\x18\x03\x12\xd9\xd0\xd8\xd0\xdc\xd0\xd4\x13\x71\x98\x01\x5b\x1f\xd4\xab\x0e\x5b\x1f\x6c\x83\xd6\x10\x07\x12\x50\x59\x06\x5f\x00\x00\xc0\x73\x33\x37\xd3\xcf\x51\x4d\x02\x67\x34\xdf\xc5\xde\x9e\x5f\x52\x52\xf2\x86\x2c\x11\x14\xab\xac\x06\xc5\x92\xba\xa2\x10\x45\x1a\x3c\xc2\x3a\x2b\xf4\x7c\x19\x35\xf8\x07\xab\x1a\x7e\x2e\x0a\xb2\xf6\xb7\x63\xf3\x91\xe6\xd7\xb8\x45\x85\x3a\xcd\x09\x09\x1a\xad\x90\x64\xff\x69\x91\xbc\x5d\x20\x65\x18\x2b\x69\x48\x8b\x58\x05\x67\xb1\xb2\xb0\xb7\x8e\x65\x90\x89\x5c\xdf\xb2\xc0\x63\x2f\x7f\x97\xd4\xcd\xd8\x44\x29\xc8\x0d\x4b\x5f\x8a\xcb\xdc\x4d\x6f\xd7\x7b\x8e\xc7\x5c\x1e\x9e\x26\x50\x4a\x1c\x88\xaf\x69\x40\x4d\x4b\x27\xf2\xf3\xd0\x13\xe2\xa7\x22\xd9\xea\xa8\x43\x40\x00\x4b\x9d\xd1\x31\xde\x94\xed\x57\x9c\x48\xe5\xd9\x57\x31\x11\x29\xd6\x40\xa3\xc2\xd5\x5b\xcc\x5f\xca\x16\x8c\x96\xf5\x78\x3f\xce\x48\x44\x9b\xba\x15\xe3\x16\xa3\xfc\xa7\x46\xb7\x55\xef\x39\xf9\x06\x30\xf7\xda\x9e\x01\xff\x75\xff\xe5\x5d\x6b\x8f\xad\xb2\x6b\x95\x6a\xbc\x05\xf7\x56\x9c\x85\xde\xc8\xf5\xc3\x03\xca\x86\xb8\xdc\xaa\x77\xa5\xc6\x7a\xc4\x09\xde\x37\x11\x82\xbb\x7d\xf7\x57\x7a\x6a\x53\xbc\xd5\x09\x6a\x7f\x99\xb4\x29\xcd\x1f\x44\x46\x3d\x1f\x29\x6c\x84\x19\x31\x95\xad\xba\x62\x20\x8b\x22\x01\x41\x09\xa6\x11\xb3\xc6\x79\xf0\xc4\x11\xb4\xa9\xba\xb4\x87\x7b\xbe\x8d\xe0\xfe\xe8\x93\xc4\xd1\xc7\xb8\xd1\x52\x30\x54\x64\x66\xc5\x39\xd5\x46\xc7\x2d\xb1\xaa\x54\xb7\xbf\xa3\x55\x59\xe4\x11\x2a\xc8\xdc\x8a\xf3\x58\x13\xed\x62\x5b\x42\xae\x49\xbb\xc6\xed\x17\x25\xb3\xc6\xfd\x47\x05\x04\xb5\x25\x69\xb8\x24\x11\x93\x2c\x70\xfa\xe2\x9a\x53\x10\x17\xa5\x3a\xc7\x8d\x9c\x43\xf1\xc9\x76\x8e\xb1\xdf\x03\x92\xf0\x29\x28\x24\x91\xc6\x16\x64\xe4\x99\xdd\x89\xa6\xe6\x5c\xfc\x43\x4c\x23\xcb\xbd\x9e\xcf\x8f\x68\x24\x05\x5b\x6d\xc5\xd8\x2a\x7e\xb4\x14\xc7\x2f\xa7\x40\x1a\x17\x81\x56\x78\xf2\xba\x22\xfe\xd5\x14\x1e\x4b\x9f\xdc\xa2\x4c\x7c\xae\x97\xa5\x2f\xf8\xf5\x98\x02\x3e\xfb\xcd\x69\x92\x3b\x80\xb9\x11\x3a\x66\xca\xd2\xd3\x83\xd5\x97\xc4\xfe\x21\x94\xa5\xa6\x3e\xdf\x83\x21\x69\x51\x43\xbc\x3a\x54\x56\xb7\x3d\x4a\x43\xd5\xed\x1c\xa7\xa1\x5c\x61\x9a\x5e\xe1\x6d\x75\x6f\x91\x6e\x6a\x58\xe2\x5a\xef\x1a\xe8\x71\x5b\x69\xdf\x14\xb6\x47\x94\xa2\x81\xe3\xc5\x40\xf2\xcc\x78\x0f\xa3\x9b\xda\x77\xc9\xa5\x7b\x48\x79\x9b\xf2\x63\xd5\x2f\x7e\x8f\x46\xf3\xf7\x4f\x7f\xf9\x31\xaa\xdf\x60\x23\xc5\xa1\xa9\xc9\xce\xbf\x0f\xf9\xa6\xfa\xec\x8a\x73\x5d\x13\xe5\x17\x25\x78\x35\x27\x94\x54\x0d\xc9\x1f\x28\x73\x17\xd4\x8d\xa9\x13\x62\xb8\xc6\xd0\xf5\xe7\x46\x79\xa7\xc7\x40\xb7\x83\x74\xb7\xc3\x78\x69\x07\x77\xc6\x2d\xdc\x69\xcd\x10\xe9\x86\x9c\xd1\x7f\x67\xd2\xad\x16\xa0\xaa\x95\x8b\x23\xb0\xb4\x23\x3e\x59\xf6\xb3\xf3\x06\xe5\x1f\x5a\x78\x26\xe3\xf4\x80\xf1\x34\xc0\x75\x2d\x44\x9a\x5f\x8f\x81\x34\x17\xa4\xbd\xfa\x41\xf3\x9d\x8b\x09\xe8\x8f\xed\xfd\x85\xa4\xef\x8f\x9e\x5b\xa6\xa1\x24\xfc\x35\x1e\x85\xf7\x68\x7f\xaf\xff\xef\x0b\x4b\xff\xdf\xb1\x85\xc1\xc6\x35\x5d\xca\x1f\x96\x8d\x9f\x4b\x93\x0b\xaf\x57\xa3\x16\x82\x27\x6d\x78\x69\xb7\xf6\xce\xf0\xe5\x4f\xfb\xe2\x35\x48\x1c\xaf\x90\xcb\x6f\x4e\x45\xab\x29\x78\x2d\xbd\xdb\xe8\x78\x94\x4c\x8a\xd6\x05\xd3\x82\x1d\x20\x2d\xfe\x3b\xe5\x4f\xd7\xe2\x35\x0e\x1c\x6a\x90\xcb\x6f\x1e\x2a\x26\x05\xab\x82\xb9\x41\xde\x60\x08\x90\xcb\x0f\x23\x33\x88\x60\x3c\x08\xd7\xcc\xf5\x5b\x82\x45\x41\xe4\x60\x97\x5e\xa7\xa7\x81\x41\x98\x60\x35\x90\x88\xb8\x9c\xa6\x82\x7c\x0c\x3b\xcd\x38\x96\x1c\xf3\x46\x05\x4b\x82\x19\x41\x43\x90\xf1\xd8\x9c\xd6\x05\x5b\x81\xde\x79\x5d\x5e\x0b\xfd\x4e\x60\x14\xf0\xe5\x9f\xfd\x72\x75\x20\x2d\x06\xed\x4a\xef\x11\x78\x2d\xf9\xed\x38\xac\x8c\xa6\xfb\xec\x3d\x67\xed\x15\xec\x8a\xff\xdf\x33\xa0\xde\x16\x2e\x45\xee\xdc\x1c\xd6\x67\x2e\x45\xee\xc2\x1c\x33\x90\x6f\x08\x9e\x1b\x4b\x56\xe2\xf6\x46\x55\xe4\xab\xd6\x87\x2b\xe4\xfc\x0f\x58\xcc\x37\x7c\xa6\x48\xaf\x18\x5e\xe1\xd7\x64\x98\x53\xa5\xce\xcf\x13\x47\xb5\x0f\x5e\xbe\x28\xe9\x4f\x8b\xeb\xf4\x46\x27\xda\x6a\xab\x48\x35\x65\xd5\x21\xdb\x61\xcb\x37\x67\xe2\x7f\xc2\xed\x97\x6f\xce\x4b\xd7\x05\xa3\x82\x94\xc1\x4e\x20\x97\xed\xaf\xc4\xff\xf4\xda\x6f\xc2\x37\xe3\x9d\x33\xce\x5b\x15\xcc\x09\x32\x5b\x9c\x3b\x8a\x23\x5a\xec\x3b\x0e\x23\x4a\x9c\xd7\x7b\x44\xf4\x70\xc5\xde\x30\x66\x0d\xad\x22\xda\xf0\xb8\xb6\xc4\x8e\xd1\x3b\x67\xe2\xff\x90\x90\x7a\xb6\x94\x4a\x24\x13\x4a\x07\xd7\x42\x35\xfd\xcf\xec\x2e\xb8\x56\x84\x27\xe4\x50\xfc\x37\x87\x3c\x97\x77\xf1\xdc\xdd\x45\x88\xb7\xe5\x43\xff\x67\xdf\xe2\x6b\x87\x3f\x5f\x70\xf7\xb8\x56\x0f\xf0\xea\xcb\x72\x94\x3d\x58\x99\x98\xac\x58\xec\xcd\xcc\x83\xff\xd2\x4f\x4a\x34\x0a\xcb\x4f\x1a\x07\xcf\x77\x35\x0a\xf9\xa3\xbc\xb5\xd9\x1e\x66\x5f\xbb\x05\x70\x7a\x8c\x13\x4d\x94\xdc\xa5\x21\x51\x58\x25\x13\x56\xe0\x61\x9c\xd9\xa9\x31\x5b\x39\x38\x84\xcf\xd5\x26\xf7\x89\x3d\x4f\x3d\xa4\x38\x8b\x05\x2b\xfb\xec\x98\x04\xc0\x71\xdc\x25\x05\x38\xde\xc6\xfb\x7e\xf8\xae\x11\x69\x0c\xad\xdf\x28\xdc\x9b\xbc\xd6\xb8\x3a\x86\x2f\xbd\xa8\x0d\xb5\x69\xdf\xc5\x3d\x52\xd0\xd2\xa9\xb9\x09\xff\xb0\x3a\x39\xcf\x3f\xfb\xeb\x51\x68\x84\x93\xee\x4e\x35\x6f\x97\x9f\x8c\xfe\x1a\xef\xab\x12\xff\x97\x0f\x85\xa4\x5c\xfd\x4e\x1a\x57\xe6\xc1\x75\xcb\x57\x8b\xae\xa5\x31\x68\x8f\x23\x1c\xd4\x59\x9c\x30\xfa\x72\x8b\x29\xde\x92\xf8\xf2\xe3\x11\xbc\xe9\xb3\x45\x37\x19\xc4\x8b\xfb\x72\x32\xcd\xc9\x6d\xd0\x5f\xf2\xb4\xbd\x11\xd7\x8b\xe2\x91\xe8\x02\x56\x0f\xa6\xe7\xa7\xd7\x7d\x50\xb4\x27\x01\xa1\xc3\xc2\x6b\x8a\x39\xa5\x15\x99\xbf\x97\x88\x3e\x82\x5d\xf4\x0c\xe3\xab\x66\x74\x2d\x89\xf3\x52\x31\x9b\xbe\x49\x31\x92\x1e\x0e\x97\xb3\x7b\x17\xff\x6c\x46\xd3\x01\xcd\xde\xe2\xd3\x2d\xf6\xcc\x19\x8b\xb3\xdc\xee\x72\x1f\xcb\xe8\x64\x5d\x5c\x2a\x76\x0f\xb5\xe3\x93\x8f\x2e\xbe\xb9\x31\xa4\x02\x8b\x6b\xf3\xda\x98\x76\x34\xb7\x6c\x1a\xed\x2a\x34\x73\x53\x7e\x8a\xff\x84\x91\xfd\x63\x68\xf0\xd1\x5a\xc8\x57\xb1\x38\xb3\xa2\xfa\xd5\x11\x89\x12\x4d\x38\xa2\xe3\x88\x43\x6c\x6c\x92\xc7\xcb\x3d\x85\xd9\xed\x39\xed\xb6\x86\xc1\xa9\x66\x7c\xd8\x83\x91\xed\x76\xe5\xf1\xf3\xf4\x28\x1c\x37\x45\x1f\x85\xc1\xaa\x06\xee\x49\xcb\xfc\xf7\x4b\x1b\x0b\xf9\xe0\xfb\x41\xd3\xd9\x04\xb2\xfd\x25\x89\x84\x43\xfb\xc8\xd8\xc2\x06\xab\xf7\x3f\xa1\xeb\xf1\x9f\x26\x31\x7a\x02\x49\xd3\x89\xb5\x78\xd7\x4f\x06\x4a\x67\x36\x14\x55\x4c\xb5\xb4\x87\x6a\x7e\x2f\xb6\x9c\xa5\xa3\x8e\xd7\x7e\xb8\x78\x2e\xd3\xb2\xdd\x07\x8b\x2e\x07\x4d\xb0\x6b\xdc\xde\x02\xe4\xe2\xe2\x2f\x32\xdd\x46\xaa\x55\xc6\x4d\x62\x4f\x38\x5e\xc9\xe3\x54\xdb\xc7\x14\x6f\x13\xac\x42\x08\x16\x83\xc9\x07\x52\x5b\xf2\x9a\x24\xa7\xbf\x5e\x65\x65\x27\xca\xaf\x16\x39\x16\xbb\xae\xbf\x8b\xcb\xcc\xcf\x6b\xb2\xb3\xd8\x9a\x82\x15\x3e\x14\x2a\xf2\x4e\x72\xff\xd2\x28\xfc\xa9\x2b\xed\x91\xd1\x87\x0e\x78\x5f\x08\x6d\xd8\xb1\x59\x3f\x65\xf8\x04\xa7\x0e\x44\xa7\xee\xa7\x90\xe3\x3e\xbd\x9f\x99\x18\x3b\xb2\xa0\x84\x7b\x28\xe7\x9c\x2e\xe3\xd5\x14\xf4\x72\xa2\xe0\x9f\x72\x87\xab\x40\x3f\x56\x96\x6a\x8f\xc9\x1a\xf4\xe8\xe3\xd5\x37\x10\xf5\x72\xe4\x48\x9b\xde\xdb\x93\xc9\x64\x78\x56\xa4\xba\xb6\xa0\xda\xa3\x82\x2b\xb7\x7a\x01\x4d\x8b\x36\x53\xc5\x4d\x57\xb9\xf0\xcd\xa0\x35\xcd\x7f\x56\x5a\x52\x12\x7d\x55\x12\x36\x3b\xa4\x59\x86\xe7\x0d\x54\xe3\x4d\x57\x62\x69\xc8\xca\x8a\x67\x5b\xa6\xd3\x94\x99\x11\x26\x4b\x0b\x83\xaa\xd8\x28\xff\xdd\x78\x87\xcc\x06\xb5\x55\xce\xc9\x1b\x44\xc1\x75\x9a\x7f\x94\x81\xbf\xe5\x3e\x19\x52\x46\x85\xc7\x33\x3f\xfe\xc0\xb7\x3e\xd5\xc0\xa6\x62\xb5\x9e\x20\x72\x99\x9b\x74\x5f\x84\x90\x7b\xfd\x09\x61\x0d\xd9\x39\x3f\xe3\x9f\x70\x00\xfe\x7e\x59\xd8\x78\x87\xca\x46\xd0\xa3\x8a\xf9\x56\xc1\xfa\xf9\x9d\x0a\xcc\xaa\xb8\x3c\x7d\xab\x81\x62\x17\x9f\x1a\x47\x66\x4d\xed\xa6\x5b\x66\xa4\x34\x4f\x49\x6d\x9a\x11\xad\xa9\x42\x6e\xbd\x37\x37\x56\x58\x6d\xda\x30\x38\x53\xd6\xfd\xf3\x68\x75\x5f\x9a\x6a\xbb\xf3\x25\xc4\x52\x69\xb3\x54\x28\xb3\x54\x40\x6b\x2e\xfb\xbb\xb9\x54\xb1\xb9\x04\xff\xc7\xca\x38\xb5\xac\xe9\xdc\x0c\xe6\x4c\x45\xfa\xb5\x25\xdb\xe5\x51\x67\x3f\x87\x52\x81\x6f\x73\x09\x87\xb2\xec\xe3\x85\x9b\x4d\x85\x27\xbb\x3a\x37\x6e\x69\xd6\xdc\xda\xe2\xa8\xb9\x69\xe9\x2f\x74\x5a\x98\x35\xab\xe3\xf4\xa4\x59\x9d\xfb\x52\x0c\xf9\x64\x15\x9f\xdc\x7c\x1e\xb9\xb5\x82\xc5\xc2\x82\xbc\x78\x7c\xfb\xc5\x82\x3d\xb9\x0d\xc7\x51\x73\x82\x13\xa7\x94\xd7\x82\xc4\x6b\x4b\x59\x14\x67\x04\xc8\xbf\xdf\x39\x72\x8b\xb3\x6f\xcd\x4d\x52\x9b\x5a\xf9\xee\xab\x12\x16\x16\xd6\x16\x85\xb9\x2d\xcd\x4d\xad\xee\xcb\x22\x12\x58\x8c\x37\xb9\xd3\xc3\xa4\xde\xad\x39\x37\xe8\x8b\x71\xb4\xb9\x5a\x4d\x12\x3d\x9e\x81\x2c\x48\xe7\xb6\x9d\x69\x2c\xb5\xc7\x0c\xa3\x50\x5c\x43\x0a\x57\x1d\x33\x47\xd3\xb8\xbf\xae\x7c\x38\x53\xcc\xbc\xc9\x9f\x2f\x7f\xa1\xbb\x10\xee\xbc\x50\x9f\xcd\xcb\x3c\x2f\x6b\xd2\x70\x4d\x0a\xf5\x6a\x54\x31\xd5\x7c\x0b\x78\xd2\xc6\xde\xfc\x5f\x3f\xf8\x5f\x97\x30\x4e\x34\x99\x37\x32\x74\x75\x7a\x80\x31\xda\x37\x34\x04\x89\x66\xfc\xf8\x9e\x03\x92\x8d\xa6\x27\x64\x15\xc0\xa3\x99\x04\x3d\x05\xb9\x30\x19\x67\x40\x86\x95\x0d\xb3\xa2\x82\xe2\x82\x22\x0e\xc8\x12\x11\x4d\x3d\x41\x48\x3f\x03\x7f\xc7\xc2\xef\x02\xee\xf2\xd0\xfc\xff\xcb\x32\xff\x6b\xbe\x39\xd4\x3f\xd9\x3f\xc8\x1d\xb3\x92\x19\x14\xa4\x44\x28\xcc\x62\x60\x2a\x69\x62\x2c\x08\x89\x84\x9d\xf9\x05\xc5\x48\x29\x0a\xf6\x0b\x96\xd8\x5f\xc8\x4c\x89\x29\x71\xe4\x31\x3b\x8c\xee\x8f\x01\x2e\x18\x98\x04\xaa\x4a\x3e\x28\xd8\x91\x6f\x80\x38\x24\x24\x26\xcd\x2a\x82\xa1\x9b\x2c\xf0\x4b\x03\x71\xf6\x7f\x99\x86\x86\xe6\x81\x86\x38\x90\xe2\x90\xc8\x9e\x60\xc7\x4c\xc1\xaf\xb4\xf0\x58\x81\xcd\x20\x21\xa0\x89\x64\x80\x29\x13\x93\x23\xf3\x1d\xf3\x32\xd3\x87\x05\xbc\x79\xb5\x21\xf7\xa8\xab\x44\x90\x8c\x90\xa8\x90\xb4\x90\xbc\x90\x94\x90\x9c\x90\xc1\x80\xf4\x0f\x7d\xa3\xb8\xdf\xc9\x97\xf9\x7b\xb4\xdf\xdf\x21\x33\xc1\xe7\x8a\x86\x9a\xfd\xd8\xe0\x2b\x03\x05\xc4\x05\xc4\x85\xc4\x60\x2b\x46\x30\x6b\x03\xd0\xcb\x03\xe3\xfd\x2f\xdf\xcf\xdf\x75\xdf\xf9\x5f\x02\xf7\x7d\xe7\x7d\x7b\x02\xa3\x7d\x0e\x84\x39\xbe\x8e\xc7\x03\x03\x50\x50\x84\xd7\x7e\xf5\x57\x03\xa5\x50\x34\x44\xcd\xfc\xf5\xdd\x01\xc7\xab\x36\xab\x67\x8a\x6b\xc9\xe0\xd8\x1b\x81\xd8\xd7\x5a\xc4\x33\xa0\xee\x44\x59\xa0\x90\x90\xea\xec\xee\x88\xf2\xf4\xf6\x84\xfa\xfc\xfe\x20\x42\x3f\x8c\x50\x94\x98\x9c\x60\xa4\xa8\xac\x70\xb4\xb8\xbc\x20\xc4\xc8\xcc\x30\xd4\xd8\xdc\x10\xe4\xe8\xec\x08\xf4\xf8\xfc\xc0\x44\x48\x4c\xd0\x54\x58\x5c\xe0\x64\x68\x6c\xf0\x74\x78\x7c\xa0\x24\x28\x2c\xb0\x34\x38\x3c\x90\x14\x18\x1c\x88\x0c\x04\xbe\x03\xfb\x0b\xf6\x13\xe7\xeb\xef\x22\xc7\xcb\xcf\x33\xd7\xdb\x5f\x42\x87\x8b\x4d\xc3\xe3\x67\x6f\x76\x2b\x9a\x30\x69\xf5\x1a\x6d\x47\xee\xd3\xaa\xd6\x6a\xb5\xda\xfc\x8f\xc2\xe5\xb2\xdb\xec\xf7\x5a\x4d\xd6\x66\xfd\x7c\x9e\x89\x0c\x29\xa5\x64\xe6\x7a\x0d\x5a\xda\x29\x9f\xb5\xc4\x10\x45\xd6\xf0\xc3\x95\x21\xc3\xa7\xa5\xeb\xaf\xee\x2f\xb1\xd5\xff\x58\xc9\xd3\x01\x0d\x0f\x57\x44\xc5\xcd\xcd\x73\xbc\xce\x8f\x6f\x71\x3c\x1e\x0e\xbb\x9b\x33\x8e\x2f\xd8\x43\x4b\x12\x09\x06\xdd\xa6\xe5\xbd\x7e\x09\x85\x35\x75\x2d\x7d\x16\x87\xc5\x13\x68\xa5\x73\x86\x99\xec\x0e\x5f\xba\xe1\x47\x14\xd1\x41\x59\xd6\x81\xd8\x80\xcd\x69\xdc\x6f\x00\x00\xc0\xb9\x21\xea\x81\x03\xa0\x1e\x84\x14\x04\x0b\xd8\x07\x81\x06\x36\x40\x08\x41\x48\x41\x19\x80\x16\xe0\x08\x38\x01\xba\x80\x5d\x90\x9f\xc0\x39\x70\x0b\xf4\x02\xa2\x10\x28\x9e\x9b\x7a\x4a\x5d\xf2\x3a\x42\xc8\x3b\x08\x48\x60\x41\xc3\xeb\xc4\x5c\x9b\xe8\x4d\xbf\x12\x47\x7d\x0a\x21\x60\x86\x57\xe2\x8c\x4d\x79\xc2\x4e\xa0\xad\x38\x9c\x93\x62\x9c\x40\x88\x04\x83\x44\x11\x36\xeb\x70\x0a\x0a\x8b\x25\xb3\x21\x7f\x60\x49\xfa\x0a\xf3\xff\x40\x65\xb1\x89\xfc\xcd\xca\xc3\xd3\xe4\x32\xfb\x8b\x45\x66\x32\xa9\xd2\xe3\xc2\x66\x4e\xe5\x8c\x34\x71\x70\x07\x72\x86\xfd\x53\x5e\xb2\xa5\x09\x78\x2e\xbe\xba\x8a\x8b\x6d\x0e\x81\xd2\xb6\x35\x7f\x9c\x74\x7b\xff\x82\x83\xcc\x5e\x48\xe5\xb1\x06\x4e\xf8\x1c\xa8\x90\x70\xe4\x78\x82\xb4\x9b\xcb\xbe\x16\x3e\x60\xc3\xdf\x3f\x88\x1e\x78\xb0\x9b\x59\x97\x1e\x97\xb9\x61\x2e\x7e\x80\x9f\x66\x3b\xc9\x84\xdc\xe2\xcc\x74\x4e\x21\xbd\x05\xaf\x1c\x18\x33\x32\x16\x67\x96\x1e\xd2\x0b\x94\x2a\x7f\xb5\xb1\x9e\x59\x4f\xd5\xb7\x24\x2d\x74\x87\xb0\xa0\xbc\x4e\xb0\x0a\xaa\xd8\xd8\x81\x67\x7d\x2d\xff\x58\x79\x70\x42\x97\x49\x9c\x2a\x6d\x60\xcf\xcc\x6c\xfc\x22\x45\x1b\x08\x9b\x70\x55\x53\x69\x99\x7e\xd9\x1c\xd0\x6b\x6c\x3a\x37\x0c\xa1\x9e\x09\x82\x5a\x1f\x52\xf7\x82\x27\x44\x44\x22\x47\x5f\x6c\x23\x9d\xa4\x45\x40\xf9\x67\x5c\x35\x0c\x8d\x92\x82\x0f\xcb\x75\xb2\x3d\xf1\x55\x2c\xf8\x2a\x89\x3a\xda\x2d\x25\xcd\x73\x14\xde\x02\x39\x9a\xb4\xd6\x5f\xc0\xae\xd0\xf4\xcd\x9b\x2d\x67\xe7\x40\x30\xf8\xa2\x85\x3f\xe0\xd1\x87\x23\xc3\xfd\x32\x1e\xbe\x89\x8d\x62\xcc\x63\x4c\x15\x08\x23\x2a\x2c\xae\xf6\x1a\x8e\x3b\xd7\x43\x0b\x79\xac\xfc\x3e\x27\x98\x1a\x78\xf2\x37\x21\x20\x17\xba\xf9\x66\x5d\x94\x37\xa3\xc5\x0d\x91\x49\x1d\xda\xdb\x7f\x6b\xfb\x7e\x2a\xba\x4b\xbd\x63\x36\x46\xd8\xc3\xa1\xd2\xba\x7c\x91\x6a\xe6\x5d\x7f\xb6\x77\x0c\x2c\x8f\x10\x6e\x48\xc8\x64\x20\x7b\xee\xfd\x4b\x3a\xe8\x8d\x97\xb6\x96\xd5\x12\x11\x5c\xc4\x9b\xc3\xfb\xfb\x77\xcb\x65\x64\x55\x37\x16\x7f\x23\xc5\x52\x5f\x83\x36\xf0\x7f\xdb\x07\xc8\xf7\x37\x80\xe4\xb9\xd9\xec\x07\xe5\x8b\x6e\xf6\xf6\xdd\xcd\xd2\xd4\x33\xbb\x6a\x9a\x62\xdb\xb8\xa1\x9a\x5c\x6f\xca\x11\xa6\x58\x0c\xbb\x08\x21\x7a\xf1\x13\xd6\x58\x68\x20\x38\x1a\x43\x69\x8e\xde\xdb\xd3\x13\x2a\xda\x7b\xf5\x88\xd7\x9c\x3d\xa6\x27\xa3\xe9\x40\x6b\x76\x68\xf7\x89\xd5\xf9\x9f\x33\xb5\xe9\x8b\xc0\xdc\xc3\xac\x2d\x3b\x32\x72\x40\xdf\x9e\x81\x80\x94\x39\x5c\xd7\xed\xd2\xd4\x7b\xf7\x1e\x8a\xa8\x51\x33\x71\xa4\x84\x96\x39\x74\xb2\x21\xda\x9b\x8d\xac\x24\xc2\xc4\xe6\xf1\x38\x96\xd5\x8c\xb5\x97\x8f\xa4\x3a\xea\x81\xf2\x3c\xa9\xef\x66\xb0\x82\x85\xdd\xea\xf9\xec\x0f\xad\xf0\x39\x8b\xd4\x50\xe5\x5c\x45\xd4\xa2\x11\xd8\x9e\x68\xbd\x32\x86\x86\xe9\x17\xb3\x25\xcb\x57\x08\x10\x7e\x65\x4e\x39\xe4\x75\xef\x18\xe9\xfc\x2d\x72\xd3\x83\x8e\x70\xfc\x94\x50\xee\x8e\x1f\x36\x28\x61\x90\xa5\x9b\x2a\x95\xf5\x72\x69\x4b\x59\xa6\x17\xca\x35\x56\x33\xe6\x17\x8b\xf8\xd5\x42\xf3\xb4\xb2\x30\xe5\xce\x63\x81\xe6\x1f\xbe\x90\x02\x65\x0d\xd4\x9f\x76\xea\x23\xa1\x7a\xa0\xef\x4a\x9d\x01\x67\xd8\x1f\x1f\x53\x66\xf9\x9e\x45\x2d\x92\x89\x10\x11\x8c\xa2\x8a\x61\xa9\xd6\x13\xfb\x58\xeb\x27\x90\x2f\xac\xa5\xdc\x7f\x8f\xd8\x26\x16\xd2\x52\x08\x82\xe1\xf2\x52\x3f\xee\x26\x10\xb2\x08\xf2\x9c\xe6\x59\xb2\xe0\x7a\xed\x04\x5d\x14\x27\x28\x5b\xe1\xbf\x3a\x3f\x88\x52\xbe\xbe\x06\x49\x5f\x74\x23\xbe\x9e\xe6\x1e\xe1\x7a\xcb\xd4\x91\x8f\x57\x04\x25\xa2\x14\x67\x31\xe1\x36\xb0\xe7\x93\x10\x24\xa2\x59\x7e\xc9\xae\x42\xba\x9a\xfe\xa1\xe7\xd0\x3d\x03\xc7\x6c\xf2\xc2\xe5\x16\x2b\x69\xae\xa6\xce\x5a\x00\xef\xa8\x62\x41\xa7\xa3\xae\x88\x2e\x75\xc1\xfc\xa5\x9f\xfc\xf1\xd7\xd9\x77\x02\x94\x41\x8b\x40\x1e\xa9\x7b\x78\x39\x3a\x15\x77\x2b\x9d\xe6\x94\x86\xf6\x9f\x0d\xca\x6a\x22\xdc\x12\xc9\x0b\xaa\x85\xc8\xd9\x9d\xe3\xfc\xc2\xbc\x15\x92\xc4\x35\x02\x17\x5e\x40\x06\x5d\x5a\xd3\x83\xc7\xfa\xf5\x0b\x62\xf6\xb5\xa5\xe2\x90\x7f\x31\xf9\xd9\x69\x28\x99\x66\xc8\x26\x66\x57\x40\xe6\xe7\xfb\x5c\x98\x63\xc8\xc3\x97\x51\xfc\x6d\xdf\x28\x1c\xdb\xe9\x2d\xba\x49\x2b\x31\x6d\xb8\xbf\xce\x5f\x0e\x5f\xbb\xb2\xa2\x75\x44\x2c\x94\x80\x32\x96\x43\xd8\xc3\x32\x37\xef\x41\x7b\xcf\x90\x7c\x7f\x9a\x47\x9e\xd0\xbe\xbf\x7c\x4a\xde\x48\x1f\x55\x3f\xdf\x34\xee\x7e\x91\x9d\x9e\xa5\x66\xe5\xab\x84\xdf\x5e\xc4\x66\xdf\xd2\x8e\x9d\x95\x1c\xf8\x2b\x09\x4f\x7e\xc2\x36\x96\x36\xd3\xea\xef\x06\xb4\x7d\x2f\x1f\x30\xa5\x4a\xda\xfc\xcc\x0c\xcd\x8f\x4d\x1d\xc8\x77\x4c\xf6\x4f\x16\xfa\xb0\x9a\x03\x4f\x69\x91\x1d\xf7\x9d\xa4\x3d\xba\xc5\x79\x3e\x6f\xf7\x19\xeb\xfb\x94\x39\x1d\xd2\x83\xda\x71\x99\x2f\x82\xda\xf1\x99\xef\x23\x9c\xe1\x9d\xfc\x72\xa5\xa8\xda\x1e\xb6\x5f\xc6\xda\x9f\x23\xff\xdc\xe1\x79\x1a\xb9\x56\x78\x01\x9b\x0b\xc1\x85\x95\x3d\x5f\x5f\x51\x50\xaf\x5e\x83\x91\x1b\x54\x0b\xde\x64\x48\x6b\x92\x0c\x46\xe3\xd4\xc9\x9a\x84\x38\x8f\xae\xf8\x54\xa9\xf4\xc8\x56\x47\xcc\xa2\x52\xb5\x55\x61\x5d\xd8\x28\x49\x7f\x67\x83\xd0\xc4\x3f\x54\x3e\x87\x52\x38\xbb\x7c\x75\x1b\xaf\xdb\x08\x3a\x1a\xb1\xaa\xc1\xfd\x12\x62\xad\x29\x11\x9c\x9b\xec\x29\x18\xb9\x41\xac\xe9\xcd\x47\x3d\x77\xd5\x92\xa6\xa9\xfa\x4d\x50\xb0\x75\x27\x59\x65\x73\x7e\xae\x28\x93\x46\x07\xfa\x20\x1e\x53\x79\xe0\xc5\x86\x3c\x9f\xaa\x08\x55\xee\x5b\xcf\x87\x12\x6d\xba\x68\x57\x43\xc7\xd6\xf2\xa9\x65\x23\xa3\xe3\x63\x43\x8e\x6f\xc1\x9f\x6e\x59\x21\xa5\xae\x3d\x54\x28\xc9\x3a\x3b\xf8\xa3\x8a\x2e\xc7\xf6\xcf\x1c\xb7\xa8\xba\xf7\xea\x07\x97\xc4\xb4\xce\xd7\x4d\xeb\xda\xcd\x6e\xfb\xab\x96\xd2\xa2\x80\x3e\xe7\xe7\x3c\x4e\x93\xbc\x8f\xc5\x96\xcd\xb3\xad\xef\xbe\xcf\xbf\xcc\x93\xdf\x2a\xf1\x99\xec\x6e\x4e\x47\xcb\x65\x6d\xdb\x7f\xb5\xef\x5a\x38\x4c\xf6\x78\xcd\xb5\x9c\x76\x93\x96\xc8\x89\x92\xb8\xaf\x6f\x37\xba\xf4\x11\xbf\x3e\x2b\xf6\x25\x82\xc5\x2c\x77\x9f\x88\xa6\x92\xd2\xcb\xc0\x91\xac\xb9\x1d\xcd\xeb\x1d\xe3\x12\xed\x00\xbb\xb5\xac\x93\xda\x6a\xf8\xca\x5a\x8c\x09\xbd\x8e\x20\x35\x84\xc6\x32\x21\x3c\xe8\x8c\xe8\x18\x7a\x8c\x8e\x98\x0a\x91\xf9\x4d\x67\xfd\x08\x46\x82\x97\x83\x27\x9b\x1f\xfb\xe8\x96\x17\x9e\x9e\xa6\xcf\x36\x18\x77\xe5\x02\x01\x35\x7d\x06\x36\x41\x12\x6e\x8f\x92\x78\xb0\xb1\xb0\x5e\x49\x42\xce\x54\xd8\x12\x11\xab\x8b\x44\x84\xa9\x6a\x6c\xc3\x51\x3a\x60\xd9\x41\x11\x25\x04\xda\x49\xa0\x01\x47\xe3\x84\xfb\x92\xe4\x04\x54\x26\x3f\x6c\x1a\x1b\x4b\x73\x35\xd9\x52\x9d\x56\xc1\xb5\x52\xd5\x6e\x8f\x9e\x4e\xb7\xea\xf4\x3c\xb6\xec\xd6\xbe\x0e\xe2\xc7\x22\x90\x70\x58\x7d\x87\xf7\x07\x86\xc4\x23\x15\x0c\x36\x76\x06\xac\x6f\xdb\xff\x21\xb5\x0d\xc1\x79\xf0\xfb\xef\xf7\xa3\x80\x45\x20\x11\x32\xcb\xe6\x31\x5a\xad\x18\x70\xe4\x0a\x58\xad\x18\x7c\x35\x5a\xcf\xa7\x52\x85\x90\x23\x64\x71\xbb\xcd\xcf\xc2\xbe\x16\xc3\xf0\xd4\x6e\xb3\x5e\x74\xf7\xd9\x6b\xb3\x5d\x7c\xf4\xd9\x6a\xaf\x30\xb9\x0d\xd6\x4b\x11\xa8\x94\xb9\x43\xef\x9f\x64\xb9\xdb\xb5\xb5\x07\x05\xc0\x14\x2a\x9d\x23\xd3\x63\x35\x92\x9d\x53\x4d\x26\x05\xad\x28\x6b\xac\x06\xc1\xdb\x66\x04\xaa\x85\x8c\x33\xa9\x05\x97\xaa\xbe\xad\x90\x2f\xd3\x57\x11\xe0\x1b\x4a\xdb\x34\x1e\xa9\x8c\x13\xce\xd8\x5d\x29\xef\x0c\x8b\xd1\x5d\x9f\x2f\x42\x0e\xed\x91\xd3\xdc\x09\x5e\x2a\xea\xa4\xe6\x14\x75\x77\xee\x26\x58\x1f\x21\x9a\xa6\x2d\x76\x22\xce\x97\x26\xfe\x4e\x07\x86\x2a\x65\x22\x8d\xac\x79\x28\x33\x56\xf4\x54\x05\x80\x5d\x08\x5d\x30\xb6\x9f\x66\xa0\xab\x81\x37\x2f\xd8\x3c\x81\x2d\xe6\x82\x51\xbf\x5b\x45\x6b\x32\xc8\x68\xaa\x2a\xa3\x54\xfe\x4c\x9f\x9a\x09\x29\x36\xb8\x7b\xe6\x66\xae\xba\x7e\x85\x15\x49\xf4\xf4\x9a\x1d\x2d\xc1\x59\x4c\x9b\x14\x56\x76\x72\x48\x24\x78\x49\x2d\x13\xe5\xb0\x92\x78\x3c\x66\x77\xce\x56\xca\x67\xae\x78\xdb\x36\x7d\x59\x33\xaa\xf8\x89\x8a\x0c\x15\x82\xd9\x8c\x21\x10\x32\x85\xeb\x75\x1b\x2f\x75\x77\xac\xc9\x75\x5c\x8d\x94\xd1\x1b\x78\x3e\xcc\x27\xbd\x0d\x89\xd0\xe7\xfb\x5e\x58\x34\xf5\xb5\x4d\x5b\x3b\x7c\x1f\x5f\x68\x51\x64\xa4\xd6\x77\xe4\x81\xb8\x0c\xef\xb1\x4d\x5b\x11\x69\xb2\x35\x50\xf1\xbd\x32\xd6\x4f\x4c\x15\xd7\x6d\xb0\xde\x9f\xb9\x9d\xcf\x20\x68\xcc\xaa\xc6\x5c\x8c\xc1\xf9\x76\x98\xcf\xf8\xd8\x5f\x34\x96\x8d\x49\x1a\xc4\xb8\xbd\x79\xbc\x51\x98\x6e\x35\x3d\x82\x0d\xc3\x55\xa3\x41\x88\x41\xc3\xca\x22\xcc\xf7\xb9\x6f\x76\x35\x13\x7f\x53\xd4\xf8\x17\xf2\xa1\xb5\x44\x4b\xaf\x13\x45\x6e\x26\xb3\x0d\xd2\xb2\xef\x2b\xd9\x5c\x5d\xda\xba\xbb\x55\x3d\x29\x7d\x92\x39\x29\x86\xea\xd1\x92\x97\xe9\x37\x29\xe6\x97\x7f\xd3\x95\xee\x95\x28\x68\xbb\xae\xa8\x36\x24\xf3\xfb\x50\xfa\xfe\xb3\x0a\xcb\xa7\xb3\x5b\xe2\xe5\xcb\xdf\xc1\x54\xd4\xfe\x34\xb6\xf3\x21\xff\xd9\x3f\x06\xd7\x7a\x3c\xaf\xd6\xd1\x35\x67\xd7\xc4\x3f\x1b\x7e\xae\xc0\x6f\xbf\x62\xa0\x39\x7e\x63\xbe\x64\x72\x6d\xe8\xbe\x97\xa4\x41\xb8\xfd\x19\xed\xef\x2f\x6a\xb0\xf2\x39\x17\x72\xd1\x44\x33\xa2\xb4\x58\x81\x6c\xd1\x7d\x77\x81\xec\xce\x24\xfc\xa6\x9c\x95\x1f\xe0\xdc\x25\x36\x29\xb9\xa2\x24\x33\x7f\x6a\xdc\x32\x30\x89\xa8\x4e\xe4\xc9\x38\x9c\x0c\xf6\x14\xc0\xdb\x64\xff\xa0\xb7\xd6\x43\x9a\x61\x63\xd1\xc8\xf5\x36\xba\xe4\xd2\xf4\xf8\x9d\xd7\x4f\xfd\xa4\x90\x60\xe6\x7f\x73\x95\x15\x66\x73\x5c\xee\xdb\xb6\x8f\x6a\xae\x98\xda\xac\x94\x6a\x0b\xa9\xd2\x5c\xdc\x04\x3a\x04\xfd\x93\x93\x00\x41\x8b\x7c\x9f\x2c\x05\xff\x6e\xe4\x26\xf5\x72\xbb\x34\xda\x6a\xc6\xe8\x4f\x30\x74\xae\x1b\xe7\x5f\xb6\x08\x84\xdd\x53\xd7\xfd\x12\x15\x47\x56\x4b\xc2\x90\xa2\x44\x10\xca\x28\xc6\x2f\x7b\xf3\xb1\x46\x46\x1e\xed\xef\xa2\x5e\x3d\xfc\xfa\x14\xbd\xca\xba\xf5\x0a\x06\x53\x8e\x79\x6e\xc8\x0b\x9b\x8d\x95\x41\x0f\xe4\x9a\x2a\x88\x95\xa4\xc9\x89\x44\xec\x02\xdf\xdc\x61\x31\x46\x10\x78\xc3\x2c\x35\x50\x08\x77\xd7\xfd\x33\xc2\xfe\xf0\xc6\x50\x84\x66\x57\x45\x3b\x01\x73\x33\x0a\x85\x35\x01\x7c\x97\x3f\xdb\x1c\x6d\xf4\x5f\x9e\xf8\xfe\xbb\xd6\xa5\x31\xcf\x91\xb7\x41\x27\x69\x24\x7a\xb8\x29\x9d\x77\x11\x15\xce\xd2\x68\xfb\x29\xa4\x1e\x58\xa3\x3e\xbd\x83\x77\xd6\x0d\x61\x17\x44\xbe\xc0\xb7\x3d\xc6\xc7\x91\x0e\xb6\xb6\x6d\xa5\x87\xba\xb2\x63\x1c\x91\xb0\x36\x14\x15\xcc\xd7\xdd\xdc\x80\xab\x29\x86\x8c\x31\xee\xcf\x7a\x3d\xbd\x2e\xf5\x98\x3a\x25\x7f\xb0\x7b\x63\x52\x86\x17\xf3\x2f\x79\xbc\xa9\xfa\x72\x6c\xaf\x9e\xf7\x87\xa6\x1a\x39\x81\xef\x94\xfb\x42\x12\x77\xbb\x0c\x28\x9c\x2f\xb7\xc4\x44\xb7\x42\x13\x45\xd2\xa5\xa6\xc3\x41\x99\x0b\x9e\x9e\x7d\xec\x76\xb0\x95\xeb\xbb\x15\xb3\xf0\x88\x65\x5d\x67\xa8\x06\xb1\xbf\x70\xbf\x9a\x15\xe1\x0f\xe5\xd4\x61\x63\xa1\xe0\xc2\x7c\xda\x49\x32\x8f\x8a\x90\x7e\xc9\x7c\xdf\x46\x10\x5d\x09\x34\x1e\x2f\x48\xd0\xe9\x76\x9b\x1e\x24\xc5\x8c\xb8\xb3\x07\xab\xd5\x93\x7f\xe6\xbf\xbd\xbf\x91\xbc\xf9\xbc\xf5\x69\x82\x35\x95\x73\xec\x96\x37\xb2\xdc\x76\x5e\x8c\xf6\x39\xf1\x71\x01\x9a\xce\x8c\xf3\x47\xc8\xe4\x30\x5a\x34\xb5\xb3\xe4\x29\x77\x62\xba\xc4\x68\x9f\x18\x09\xa5\x8c\x35\x3f\xa2\x36\xa2\x38\xb4\xa2\x50\x91\x27\x40\xbd\x8d\x32\xee\x16\xe3\xbd\x83\xac\xd2\xc8\xd7\xc7\xf5\x7e\x3c\x57\xa5\x59\x72\x2e\x6c\xd6\xe2\x13\xa7\x7f\xb5\x3f\x64\x13\x9d\x6c\x39\x18\xb4\x17\xd1\xf6\x7a\xb9\xe8\x7a\xa3\xf5\x72\x20\xbc\xaa\x81\xdd\x95\xa0\x1b\x3b\xad\x26\xec\x5d\x81\xd6\xee\x8b\xcd\x92\xc0\xd8\x23\xc7\x9a\x3a\x52\xea\x88\xee\x29\xa9\x46\x53\x6b\xa7\x2b\xcb\xb4\x59\x91\x21\x67\xc8\x7c\x68\x63\xb3\x41\xad\xa2\xb5\x2a\x4f\x1e\x47\x84\x8e\x5f\x6a\xf4\x9c\xeb\xf0\xed\x4b\xf1\x51\xcd\xd8\x5c\x2d\x1e\x9e\xcb\x0d\x08\x99\x93\x65\xa0\xf9\x95\x4a\x04\xbd\xd0\x5a\xd2\x0b\x54\xab\x16\x46\xcc\x22\xb6\x50\x02\xc3\x11\x3c\x94\x98\x6b\x40\x99\x19\x7c\x2b\x6d\x96\x25\xd4\x45\x1b\xf3\x12\x43\x38\x9a\x15\xdc\x83\xef\x07\x08\x5a\x5d\xaf\xc8\x2d\xe6\x86\xf4\x73\x17\xcf\xd1\x75\xcb\x48\x04\x21\x97\xc5\x02\xd3\xdb\xd8\xa2\x86\x02\xd3\xc9\x03\x05\xbd\xa7\x40\x59\x80\xb1\x56\x51\x9d\x57\xe8\xa7\xef\xa5\x1c\xd4\x2c\xdf\x53\x72\xca\xf4\x87\x49\x97\x2e\x14\xeb\x33\x9a\x3a\xec\x06\x77\xf1\x06\xe8\xb1\xd6\xa5\xe3\x13\x26\xe4\x36\xad\x58\xb2\xc8\x9d\x6e\x39\x7a\x3e\x1c\x06\x57\x20\xde\x4d\xa7\x32\x74\x1b\xa1\x6a\x1a\x24\x2a\x88\x39\x1e\x2c\x2a\x8c\x97\xb4\x3a\xd5\x98\x07\xb5\x3d\xb2\x20\x49\x29\x91\x7b\x41\x25\xea\xb8\x8b\x8e\xa0\x57\xa8\xb5\xbc\x03\x99\x68\x74\xa0\xba\x6e\xaf\x4e\xe5\x02\x70\x10\x48\x1f\xd9\xbc\x99\x45\x1d\x62\x2f\xcb\x66\x0a\x8d\x94\x68\x91\x9a\xc3\xef\xb1\x50\x41\xc1\xd0\x75\x92\x4e\x26\x41\xe0\xf6\xd2\x6c\xf6\x46\xf1\x3b\x0d\x22\xef\x3b\xd1\x4b\x5e\xe0\x34\xd6\xe5\xc9\x83\xdf\x5b\x3f\x20\x42\xcf\x94\xcf\xf4\xa2\x11\x82\x82\xe8\x79\x75\x91\xc4\x9c\xb0\xcb\xb0\xd1\x6d\xa9\xab\x4e\xc0\xe5\xa5\x14\x04\x61\x03\x63\xce\xf7\x1e\x77\x53\x10\x63\xdc\xfb\xe7\x6b\x7b\x41\xbd\xe2\x38\xb7\xd4\x66\x81\xd9\x3f\x56\x2d\xc5\xd9\x2b\x17\x66\x24\xd3\x4b\x9c\x19\xb8\x39\x6d\x62\x01\xc4\x12\xd5\x67\xf6\x15\x85\x15\x10\xce\xe2\xea\x19\x39\xaa\x3a\x30\x52\xf8\xca\x8b\xd6\x03\x12\x8e\x76\x06\x55\x10\xa1\x07\xa3\x59\x32\xd7\x72\x59\x25\x30\xc9\x1f\x32\x94\x89\x5c\xe1\x52\x9f\xda\x68\x8a\x95\xcb\x9b\x95\xc3\x5e\xd5\xa7\xab\x3a\x6b\x1e\x7b\xad\x85\xef\x0e\xb2\xc6\x2a\xd5\x62\xb6\x5d\x8f\xcb\xb3\x68\x84\x7d\xb0\x6a\xf7\x95\x63\x62\x09\xeb\x48\x66\xac\xb0\xa6\xc7\x21\x2d\xe4\xa1\x1d\xa0\x48\x47\x94\x24\x02\xb0\xe4\xb6\xba\xc7\xc1\xc9\xfb\x49\x78\xce\x23\xb5\xce\x02\x92\xa5\xd8\x64\x2a\x52\xc9\x54\x10\x53\x72\xc1\xe8\xd2\x42\xb0\xa9\x1b\x41\x59\x41\xf8\xce\xc1\xe7\x4f\x69\xc6\x79\x68\xb4\x11\x69\xe2\x92\xb0\x2b\xa5\xe8\x81\xaf\xad\x97\x86\xc2\x52\xab\xe4\xc5\x60\x9a\x3e\x3a\xc4\xf8\xa8\x41\xaf\x45\xa2\xea\xae\x83\xd5\x23\x70\x19\xf8\x7c\x7e\xea\x8a\x6b\x48\x49\xa3\xc7\xc6\x6f\x17\x4f\x4f\x14\x04\x2f\x93\x7d\x5d\x7d\xbe\xe2\xdf\x89\x7a\xa6\x7f\x09\x1b\x1e\xb3\x54\x66\x3b\x6e\x02\xd5\xc5\xac\xe7\x5d\xe0\xdc\xd8\xf4\xa7\x48\xfd\xce\x2c\xea\xce\xf3\xfb\x20\x7c\xf3\xc1\x9a\x65\x21\xfd\x62\x84\xd8\x5c\x7e\x27\xd2\x09\x5b\x1f\x96\xde\x82\xb8\x4c\x41\x54\x46\x33\xa6\xc1\x11\x43\xb8\x1d\x87\x4b\xcf\x23\x94\x2c\xb4\xa3\x5a\xb2\x0b\x2a\xf0\x7d\xc8\xa5\x2a\xd6\x62\x52\x0e\x5e\x93\x54\x5b\xba\xe3\x25\xab\x63\x40\x19\x0f\x26\x8e\x50\x67\xad\x41\x45\x9f\xc2\x96\xff\x43\x54\x53\x57\xd5\x81\xf2\xd0\x8c\x72\x25\xb5\xbe\x9a\x4b\xec\x3f\x07\xa1\x4d\x81\x9c\x84\xed\xc6\x2a\xf3\x45\xc4\x9b\x5a\x6f\x9e\x1a\x35\x0d\x27\xf0\xd9\x7f\x5d\x63\xa9\xf0\xda\xe9\xa6\xd8\x5d\xe9\xf3\x3d\xda\x7b\xeb\xa2\xf5\xfa\x97\xbc\x21\xa3\x90\xc9\xf3\x54\xec\xdc\x10\x02\x53\x9d\x46\xa0\x4e\xf8\xad\x41\xfa\x76\xe7\x97\x3e\x4d\xec\xf7\x6e\xe3\x00\x86\xc4\x9d\xf9\x5c\xfb\xee\xc0\xf7\x14\x2b\xd0\xcc\xfa\xcb\x49\x21\x71\x4b\x72\xad\x14\x4e\x8b\xe7\xd4\xb8\xdc\xd8\x92\x5f\x77\x0d\xdc\x99\x1e\xdb\x74\xe2\x6a\x73\xfc\x4a\x18\x37\x21\xcb\x5c\x5d\x1d\x19\x9e\x09\xd4\xc6\x7d\x99\x06\x49\xf1\x12\x45\xb6\x0e\x12\x65\x6e\x82\x54\xe7\x37\xdf\xe8\x26\x5a\xab\xf9\xc6\xfd\x6b\xa9\x75\xdd\x57\x6b\xdb\xfd\x27\x45\xa7\x47\xc7\xb1\x91\xed\x2b\xd4\x5b\x86\x77\x5c\x6d\x8d\xde\x94\x78\xe4\x08\x51\xf5\x40\x64\x08\x77\x1a\x38\x97\x68\x18\xa9\x68\xbe\x4c\x98\x2d\x36\x99\x92\x71\x69\x84\x1c\x71\xd4\xa6\xe8\x3a\x48\x72\xb9\x98\x14\x7c\x41\x09\x86\x91\x57\xac\xba\x3e\x04\x96\x98\xbf\xb3\x09\x48\x3b\xfc\x8b\x1a\x07\xff\x0e\x52\xed\x7b\x49\xff\x6c\x57\xb3\xb9\x67\xc5\xe4\x38\xda\x3b\x55\x6e\x7c\xb2\x68\x66\x59\x54\x25\x12\x66\xc2\xe0\x12\x28\x28\x74\xb9\xfa\x82\x2f\xea\x87\x1d\xac\xa5\xbd\x8d\xc4\x2d\x7c\x43\xc6\x01\xd6\xa5\x79\xfd\xbe\xf7\x72\x58\x19\x2d\xbf\x54\xc0\x05\x19\x79\x4e\xe3\x79\x6a\xcc\x23\xc3\x9e\x97\xc6\x77\xb0\x1a\x5d\x36\x87\xc5\xeb\x84\xcb\x29\x6d\x55\x0e\x9f\xdb\x64\x8e\x97\x0a\x62\xde\x48\xad\x6e\x43\x09\x97\xdb\xd8\xe2\xd8\xf7\x53\xdd\x58\xc6\x6e\x92\x75\xef\xfb\xf2\xd9\xae\xe7\xd1\x4e\x91\x3c\xff\xc9\x78\x18\x8d\x7a\xa4\x99\x4b\x3c\x8f\xfd\xec\xf4\x51\x3c\x0a\x25\x3f\x22\xd8\x6e\x2a\x0e\x77\xe7\xf2\x1d\x02\x36\xd1\xc4\xbb\x08\x64\x2e\x4d\x34\x0f\x59\x02\x0a\xb5\x8f\x6b\x73\xa8\x70\x49\xd6\xfe\x27\xd8\xf2\x02\x6a\x62\xd2\xe9\x5f\x65\xe5\xed\x0b\xd5\xe2\x9f\xd4\x64\xe8\x14\x51\x8a\x74\xca\xaa\x0e\x11\xb8\x14\x7e\x35\xea\xfd\x5a\xc4\x7f\xf9\x50\x5a\x4a\x5b\xf9\x66\xcb\x2d\xfb\xbb\x35\x59\xef\x8d\xe5\x1f\x19\x31\xfd\x9f\xf8\x30\x17\xf2\xbf\xed\x0f\xe5\x8a\xd0\x8a\x66\x7f\x39\x5f\x66\x9d\xc6\x50\x38\x7c\xc6\xaa\x11\x70\x05\x6c\x2f\x46\x9b\xc1\x99\xe7\x51\xf2\x3d\x22\xda\xcc\x1b\xcc\x0b\xac\xe5\x2f\x0b\x2c\x7c\xeb\x13\x7e\x5b\x38\x35\x37\xb1\x30\xdb\x82\xbb\xd8\xf5\x19\x8a\xf8\x7c\x23\x70\xec\xba\x63\x9d\x0f\xe0\x2b\xce\xbb\x1c\x23\xb6\x27\x43\xf0\x98\x83\x85\x79\x45\xc6\x76\x5a\x9b\xdd\x85\x8e\x48\x8a\xe3\x2f\x53\x35\xdc\xc9\x47\xc5\x7d\x59\xce\xfa\x4a\x27\x53\x42\x72\x70\x44\x90\x0d\x80\xa8\xd8\xff\x74\x53\x0c\x0f\x7e\x53\x87\xe5\x5a\xdb\xb8\xe3\x0b\xde\x07\xe7\xb1\x44\x69\xb4\xff\xd0\xcc\xf8\xdb\x50\xf0\x7a\xcf\x3e\x03\xa9\x16\x41\x51\xb3\xf9\xb1\x5f\xd8\xa9\x8a\x55\x92\x83\xfc\x16\xa4\x33\x8b\xf8\x16\xee\x4b\x48\x3e\x90\x91\x86\xdb\xb1\xce\xfa\xd2\xeb\xcb\x4d\xbe\x37\xe9\xf2\xb3\xe0\x58\xd0\x2a\xd7\x16\xc5\x36\x18\xd9\xd6\x2c\x9a\xcc\x56\x09\x52\xea\xa1\x93\x08\x23\xa2\x69\x5b\xe2\x1a\xfc\xf3\x0a\xab\x66\xee\xca\xc0\xc5\x2b\x7f\x82\x5c\x9a\xa7\xf8\xb9\x42\x00\x9d\x85\x85\x53\xba\x50\xb1\xff\x1f\xfa\x53\xb0\xe7\xfd\xe8\xfe\x99\xec\x45\x77\xee\x99\xd4\x59\x43\x54\xbe\xef\x20\x7b\xc0\x3d\x4c\xdb\x5f\xb2\x41\xe4\x0b\x31\x2b\x0a\x7f\x83\x2e\x65\x84\x28\x48\x38\x06\x94\x31\xb7\x3d\x12\x02\xbe\x50\x2f\x83\xd6\xaf\x10\xaf\x47\x1b\xfe\xe0\xdb\xe0\x6b\x3d\xef\x5f\xae\x34\x88\xdf\xe1\xd4\x4d\xba\x15\xa4\xf0\xcc\x29\x31\xd0\xe7\x5a\xa1\xc9\x31\x92\xf0\x29\x31\xf7\xa9\xda\x8d\x08\xed\xbf\x47\x82\xc8\x6e\x9a\x71\x9f\x4d\xa2\x13\xa8\x20\xd3\x1b\xb5\x73\x92\xa1\xc9\x82\xa5\x44\x13\x1b\x21\x69\xc8\x6a\xb4\x8b\xd1\xf5\x03\x07\xa7\x24\x89\xa6\x19\x2f\xcd\x0e\xc0\x39\x5d\x59\xbc\xea\xc9\x12\x0b\xa4\xa3\xa4\x18\x7a\x18\xae\x3b\xdd\x37\xe6\x71\x91\x77\x96\x59\x46\x67\x39\x8d\xff\xbd\x14\xfd\xfa\x62\x92\xa9\xc7\xed\x38\x5a\xa8\x21\xe2\x73\xba\xb9\x3a\x52\x8e\x50\xe8\xfb\xf8\xf0\x0a\xa1\xcf\xe2\xf7\x98\x98\xc6\xe1\xd1\x7f\x39\xc1\x3a\xde\xa1\xf4\xab\x7f\x82\x99\x2a\x11\x16\xc7\x26\xfb\x50\x1b\xe7\x4e\xcc\x6b\xa7\x5d\x06\xe3\xe3\x6f\xce\x76\x8f\xcc\x9b\xa1\xaa\x21\xfa\xc0\x49\x5a\x1c\xbc\x2b\xa3\x4e\x4b\x31\x35\xe2\x8c\xf6\x63\xdd\x90\xaf\x29\x92\xa9\x79\xb2\x09\x99\x37\xc4\xd7\x0b\xcf\x9f\xd3\xf2\xf2\x72\x23\xe6\xd5\x89\x31\x1f\x2e\x68\x57\x85\xa2\x1a\x22\x48\x66\xd0\x2d\x79\xb4\xb1\x27\x08\xfa\x2a\x26\x4d\x74\xe3\x20\x08\x5c\xa6\x28\xc0\xa6\x8b\x1e\x79\x3f\x6a\x5a\x0d\x34\xaf\x1a\x76\xdc\x3f\x87\x9a\x5c\x5a\x2e\x6c\x19\xf3\x82\x22\xe5\x05\xe5\xaf\xe0\x14\xe7\x85\x81\x8e\x82\x15\x6a\x8c\xb6\xb4\xb2\x34\x62\x43\x3e\x65\xc6\x26\x60\x4e\x4e\x93\x8d\xeb\x13\x0a\x4d\x5c\x58\x25\x0c\xf3\x50\x85\x8e\xed\x9b\x5f\x5c\xc5\x2d\x46\x66\xa6\xee\xdf\x35\xc5\x6a\x5c\xb1\x0d\xd9\xfb\x7b\x82\x95\xa2\x40\x6d\xad\xcb\xf7\x10\xed\x36\x70\xc8\x70\xcb\x7b\x72\x8f\x93\x4c\x66\x72\xa5\xe1\x76\x6f\xe6\xde\xf7\xf5\xfb\x2b\xf3\x2b\xb9\x77\x16\x2b\xb0\x3f\x39\xaf\xc1\x4c\x74\xa6\x1c\x2b\x61\x59\x61\xa1\x2c\x06\x2f\x97\x60\x08\x6a\xb6\xc2\x38\x6e\x41\x75\x21\xaa\xac\xde\x63\x83\x3c\xe9\x82\xec\x6d\x9b\xe3\x89\xc2\x42\xfe\x17\xfb\x9f\x29\x0a\xb7\x74\x7b\xab\x94\xae\xfc\x4c\x81\x7f\x33\x5b\x1b\xc2\xee\xbf\xfc\xcb\xbf\x28\x3e\xbd\xfd\x9c\xf4\x3e\x9e\x3f\x95\xaf\x75\xdc\xef\x3b\xaa\x74\xc6\x22\xdd\x93\xfc\xec\x9a\x04\xc2\xef\xcb\xb1\xc0\xa7\xb8\x23\xd9\xf8\xc7\x6d\xc4\x1d\x6d\xc2\xb9\x65\x4c\x9c\x35\x56\x2f\xef\x4a\x97\xac\x94\x9b\x72\xb6\x18\x0a\xa0\x5c\x8a\x82\x23\x94\x79\xcd\x9c\x58\x0c\xe3\x2d\x2f\xce\xe7\x49\xa7\x45\x98\xec\x26\x9a\x5b\x43\x60\x15\x17\x95\xb3\xeb\xc5\x86\x06\x42\x53\xab\x0d\x06\x09\x03\xab\x3f\x77\xc9\x3a\x03\x16\x1c\x7b\xec\x5f\x7e\xc3\xb2\xbf\x62\x5e\x99\xe7\x7f\xfc\x41\xac\x73\x78\x38\xed\x67\x99\x03\x67\x8f\x81\x13\x1d\xfd\xe3\x4f\x5c\x4d\x01\x7f\x05\x23\xac\xae\x47\xa7\x4b\x6b\x1a\x12\x9c\xa4\xb0\x08\x51\x3b\x65\xde\xae\xe6\xff\x63\x4a\xaf\xa3\x71\xb1\x60\x66\x29\x91\x26\x25\x94\xb5\x52\x4a\x4e\x1a\xa3\xcd\xea\x07\x63\x60\x23\xab\x7b\x7b\xb4\x20\xc5\xc7\xdd\xf8\xad\x46\x2e\xb6\x3b\xaa\x63\xae\xa4\x95\x7c\x7d\x94\xb6\xe7\x84\x96\x69\xe8\x38\xb2\xbb\x83\xd8\xb5\x43\xc5\x17\x62\x4b\x6c\x8e\x3d\x1b\x2e\x0c\x4a\xe9\x72\xab\x39\x2a\x06\x04\x53\x29\xf7\x80\x89\xf4\xef\x15\x59\x31\xa8\x5a\x83\xbe\xbc\xcf\x08\x26\x75\xa7\xed\xc3\x95\xaa\xa7\x6f\xd7\xab\x3d\xa6\x39\x2a\x9a\x0c\xda\xa5\x3d\xaf\x93\x65\x97\x59\xbe\xb3\x5f\x33\x4e\x5c\xf8\x1a\xf9\x5e\xde\x0b\xa3\x9d\x8b\x3e\x73\x9e\xaf\x2d\xcf\x58\x04\x5e\xdb\xf7\x67\x98\xd3\x7a\xcd\x80\x9f\x30\xdc\x70\x12\x52\xff\xea\x54\xd8\x2f\xe1\xd6\xe9\x62\x1d\x76\x63\x01\x37\x5d\xa1\x4f\x0c\xd9\xdc\x28\xca\x95\xa4\xd5\x68\x82\x63\x0d\xa6\xa5\x01\xf5\x14\xf2\x8c\x42\xc2\x88\xc9\xc0\x64\xec\xd3\x19\x2d\x1f\x25\xa6\xca\x2e\xfc\x7d\x2a\x39\x9a\x52\x56\x67\x74\x66\xb6\x65\xc9\x86\xd8\x30\xc1\xa8\xad\xf0\x86\x58\xe3\x34\x21\x13\x9d\x75\xaa\xea\x7f\xf2\xa7\xf9\x4f\xe2\xdd\x46\x4f\xd5\x11\x06\xeb\xde\xdf\x85\x1a\x2b\xa3\x7b\x99\x15\x01\x6e\x65\x5f\xe9\xfe\x15\x2f\x92\x2c\xed\xcb\x57\xb3\xba\xc5\x7d\xdf\x9e\x22\xda\xdf\x73\x5d\xbf\x3c\x9e\xe6\x96\x10\x12\xae\x6e\x19\xf8\x43\x3e\x41\x9e\x60\x4e\xd6\x24\x3b\x64\x92\x18\xe5\xc6\xbd\x93\x60\x89\x14\x0f\xfe\x90\xf5\xfc\x06\xbd\x60\x6a\xc9\x3c\x3e\x01\xeb\xf4\xdd\xd6\x09\xe2\x59\x33\x4e\xc5\x70\x89\xb2\x74\x4e\x4a\xea\x3e\x3e\x11\xb4\x8b\x16\xad\x59\x20\x65\xd1\xfc\xe6\x73\x69\xd8\x78\xb3\x7b\x43\x62\xe0\x73\xf7\x63\xf7\xf9\x34\xc9\xd9\x79\x23\xff\x8c\x70\x78\xbc\x7d\xea\xda\x0d\x70\x5b\xf2\xf0\xe8\x9d\xfc\x64\xa8\x56\xe9\xc5\x5a\xc5\x41\x65\x77\xac\x59\xfb\xa8\x27\x1f\xd0\x25\x13\x6b\x09\x14\xed\xb1\xae\x4a\xb2\x5e\x14\x9b\x55\xba\x23\xbd\xcc\xdb\xa2\xd0\x94\x9b\x82\x46\xfb\x51\x6e\x4d\x4f\xc9\xff\x79\x9e\x26\x66\xeb\x04\x67\x35\xcf\x17\x0b\x6b\x4d\x8c\x10\x65\x91\x81\x2b\x6b\xd2\xa5\xeb\x82\xfd\x94\xad\x57\x58\xce\x20\x08\x1c\x3d\x6a\xeb\x75\x2d\xc4\xfc\x62\xbb\x55\x15\x64\x8b\x68\x96\x26\xea\xb9\x5d\x78\x6f\x62\x78\x24\xde\x3a\xf5\x5a\x23\x76\x7d\xdd\x7b\xb4\xe1\x9f\xc7\xfa\x90\x13\xa0\x52\x38\x22\x11\x2c\xfa\xa9\x4b\x79\x2c\x15\x12\x1d\xea\xce\xc4\x4a\xb1\x6a\x27\x99\x94\xab\x62\xca\x44\x75\xdf\x09\x0e\xa7\x78\x2c\x16\x0d\xea\xb5\xc0\xb9\xa4\x95\x1f\x89\xfe\x8a\x0e\xf5\xf5\x4f\xb0\x86\xe2\x2d\x52\x34\x48\x1a\x17\x9d\x90\xac\x90\x7d\x57\x6d\xb1\x1b\x92\x09\xd3\x82\xc1\xd8\xdb\x32\x2a\x3c\x08\xf5\xd5\x43\x50\x92\x6d\xc9\xcd\x49\x04\x09\x83\xc2\xbf\x80\x21\xc6\x41\x1c\x57\xd9\x10\xcd\x40\xc9\xc1\xf9\x97\xd2\x14\xfa\xa6\x68\x2d\xa7\x3a\x3d\xd6\x32\x03\xdf\x29\xca\x08\x2a\xe4\xe2\x01\xa5\x5a\xe1\x82\xb1\x64\x44\x43\x65\x54\x70\x9c\x29\x9f\xb3\x17\x54\x4b\x03\x1b\x05\x06\x48\xa1\xf3\x6e\xd5\xd3\x70\xaa\xfe\x45\xc0\x5e\xeb\xe2\x6e\x34\x6b\x62\x4b\xf1\xba\xb2\x7a\x53\x54\xda\x74\x40\x4f\xaf\xfd\x53\xac\x84\xbe\xdf\xc5\xc4\x2f\x99\x29\x03\x63\x81\xd8\x95\x3e\x7f\xa9\x00\x91\x3e\xe5\xe9\xd2\x81\x90\x6f\xab\x0b\xde\xcf\x1a\x0a\xea\xab\xa7\x80\x80\xed\xfb\xda\xaf\x3d\xcf\xf3\xbe\x2f\xac\x4e\x03\xc2\xa6\x1c\xbd\x51\x33\xd3\x96\x90\xd8\xc9\xd0\x6c\xf8\x5b\xbc\xd3\x5d\x0e\x74\x3a\xb1\xdb\x18\x65\x25\x3e\x1c\x74\x78\xd5\x44\x58\xde\xb4\x18\x2e\x49\x7e\xa6\x62\x2e\xf9\xfb\x01\x5b\x54\xd8\x05\xd4\x64\x85\x28\x84\x61\x25\xd8\x37\x0d\xe5\xf2\x00\xb2\x6d\x13\xce\x25\x6d\xe4\x76\x54\xda\xc1\xb5\x60\x62\x29\xb6\xd4\x59\x4c\x88\x0a\x2e\x90\xa7\x36\x5c\x29\x9b\x13\xca\x2e\xec\xd7\x7f\xc4\x2f\xee\x1b\x20\x1a\xca\x05\x45\x12\xfe\x46\x78\xa6\x2a\xe5\xa9\x38\xed\x87\x9f\x28\x22\xe9\x87\x39\x08\x87\xcd\x08\x78\x9a\xce\x43\xe1\x08\x3b\x6d\xc2\x69\xd6\x91\xaa\x71\x57\x2e\x1b\x74\x2f\x1e\x63\xee\xb4\x6a\x1b\xb8\xf4\xfa\x05\x7d\x04\x39\xa3\x6c\x82\x7d\x32\xd8\x3a\x05\x45\xb3\xae\xfa\x04\x03\x5d\x4a\x1a\x48\xe3\xae\x9a\xf5\x9b\x8c\xef\x5e\x2f\xe4\x0b\x4a\x82\x45\x0b\x2b\x57\x5a\x66\xac\xdb\xbd\x46\x60\xd5\x54\x7d\xb0\x1f\xee\x2f\xb3\xa4\xe7\xcb\x18\x77\xb9\x62\x83\xc6\x24\xbd\x8a\x48\x24\x99\xb7\x46\xed\xe3\xfc\xa6\xb4\x24\x13\x3c\x62\x6d\x0b\xec\xd1\xe3\x18\xf8\xd7\x3c\x57\x65\xd4\x53\xb7\x23\xff\x50\x36\x3a\x08\x68\x5e\xb1\x31\x75\x7f\x52\x2a\x21\x37\x4f\x46\xed\xc0\x19\x34\x6b\xf4\x81\x62\x85\xeb\x0e\xc1\x96\xb4\x96\xb6\x90\x51\x35\x2e\xa2\x9d\xca\xe9\xf5\x06\xf1\x35\x1a\x85\x7c\x8d\xd0\x10\x19\x78\x12\x76\x4d\x78\xdf\x33\x59\x30\xa4\x65\x39\x0e\xf0\x7c\xbf\xce\x7d\xe7\x79\x6e\xab\xfb\xec\x5a\x68\x7d\x41\x5f\xd1\x63\xcc\x32\xb9\x92\x0d\xbb\x91\x61\x53\x6d\xa8\x68\xf8\x96\xd3\xc4\x1b\x2f\x63\xb8\x6a\xcf\x30\x3b\xf0\x81\x10\x99\xe8\xea\x19\x0f\x4f\x62\x37\x36\x82\x6b\xe2\xd0\x98\x9a\xe1\xa7\x15\x64\xa6\x02\xa2\x75\xdc\xe8\xae\x2a\xcc\x94\xc1\x7d\x6d\x3f\x4d\xb1\x3f\xdd\xee\x32\xe7\x92\xc3\x09\x65\x0d\x7c\xe8\x69\xb8\x55\xf1\x9d\x42\xbe\x28\xdc\x67\xd8\x76\x12\xa6\x57\x05\xde\x1f\x36\xbb\xe9\x73\x26\x56\x3b\xd4\x5a\x44\xeb\xae\xfd\xab\x3d\x1f\xcc\x39\xba\xd4\x0c\xa4\x9d\x85\x02\xdc\xe8\x4f\x7e\x52\xe0\x75\xee\x6f\x0e\x51\xf8\x78\xf3\xd0\x40\x07\xc9\x3e\xa1\xa9\x21\xb3\x0a\x3a\x4a\x86\x4e\x05\xf5\x4e\xa8\x9d\x67\xeb\xfa\x2f\x23\x5e\x96\x50\x49\x66\x4d\xc1\xd3\x12\x2e\xdb\x5b\x48\x04\x55\x89\xbd\x66\xea\xa7\xab\x05\xb1\xd7\x3d\xf7\x66\x68\x10\x7f\x12\x7e\x62\xab\x60\xb6\x6a\xd5\xaf\xb6\x3b\x46\xe0\x08\xfc\xc6\xa1\x47\x30\x28\xa0\x65\x40\xa0\x90\x02\x43\x75\x9a\x9c\x16\xdb\xd5\x8f\xda\xe8\x92\x3d\x1d\x73\x2a\x69\x18\x4c\x4b\xbf\x47\x3e\x17\xa3\x79\x3a\xad\x41\x87\xfd\x60\x54\xe5\x39\x50\x5d\xc5\x1b\xa5\xe8\xa1\xf7\x5c\xcc\x28\xcd\xe9\x45\xdf\x51\x67\x3a\x7d\xc8\x65\xb7\x48\x7d\xe6\xa8\x17\x21\xb1\x64\x56\xdc\xb0\xf2\x10\x8d\xb6\x62\x18\x21\x4d\x34\xd3\x1c\x6c\xde\x5e\x35\xa4\x4b\xd5\x6f\x35\xcc\x3c\x6e\xcd\xcb\x9d\x91\x6f\x6d\xc4\x30\x86\xff\xe3\xe1\x57\xa1\x66\xf0\x5a\xec\x9f\xde\xb2\xcc\x58\x40\xc0\x30\x39\x53\x0a\x13\xf0\xb3\xd6\x9c\x27\x2f\x65\xa9\xda\x67\x85\xc2\x74\x12\xa2\x97\x96\xfa\x63\x76\x5e\x21\x8c\x13\x54\x3f\xcc\x65\x48\x6e\x7b\x5e\xb7\x20\x4b\x96\xee\xa7\x7f\x68\xc3\xb3\x54\x37\xb4\x44\x12\xd6\x81\xb0\x7e\x28\x95\xe5\x6f\x99\x39\x6a\xd3\x8b\x68\xa4\xdd\x23\xc5\x71\x08\x00\x4a\x50\x04\xaf\x99\x11\x37\x27\xce\x95\xd5\x70\x1e\x9e\x1d\xe7\x9a\x32\x95\xca\x86\x83\x8e\x61\xc0\x36\x5a\xc8\x26\x8d\x73\x61\x12\xe1\x36\xf7\x26\x67\xa5\xc0\xc9\x82\x24\x85\x96\xf4\xb2\xfd\x91\x7a\xeb\x15\xae\x4c\x6e\xf8\x2b\xe2\xa4\xfd\x5b\x0c\x49\xd7\xfd\x2f\x21\xe7\x28\x3a\x89\x57\xd0\x1b\x00\x26\x0d\xa0\x62\x53\x52\x0f\xdf\x51\xba\xd3\x56\x99\xb9\x5d\x8b\x7e\xe2\x7e\xba\x41\x13\xad\x35\x56\xfa\xdc\x74\xdc\x7e\x41\xdd\xf6\x78\xc4\xbc\x08\x87\x12\xf4\xdb\x2f\x9c\x5d\x26\x48\x3c\x4a\x3c\xbd\x5e\x9b\xb3\x7f\xec\xbd\x95\x55\xbf\xec\x89\x11\x35\x66\x7e\x6d\x8c\x05\xff\xf2\xd9\xa0\xda\x1d\x0b\x65\xf1\x96\xf0\x95\x6e\x35\x0e\xe3\x6a\xe2\x20\x5e\x9f\xa6\x34\x48\x4e\xb8\x0f\x1a\xa4\xec\xb3\xf0\x1d\x2b\x86\x58\x3a\x5d\x1c\x7c\x21\x44\x2b\x3f\x1c\xad\xd7\xca\x6c\x2c\x86\x90\x4c\xc6\xc3\x76\xd4\xa1\x9e\x4e\x18\x59\x67\xa0\x2d\xec\x7b\x9e\x4a\xc0\x63\xff\x68\xbf\xbf\x6e\xd2\xf8\xb2\x14\xfd\xd4\x63\xe8\xa9\xbe\x42\x1a\xe1\x88\xd9\xd3\xf5\x7c\x64\xca\xc0\xe6\x45\xd2\xac\x85\xca\x83\xfa\xf1\xa6\x80\xde\x08\xbb\x88\xc6\xe6\x45\x78\x0b\xf3\x9a\x79\x21\x92\x45\xc4\xe2\x19\xef\xc4\x8f\x09\x4a\x77\x37\x09\x3b\xea\x35\x5e\xab\x4b\x18\xfb\x80\xfd\xa1\xa6\x21\x11\x84\x2e\xfc\x7b\xc6\xb8\xea\xb4\x45\x7b\xaf\xb1\xfd\x58\x76\xf5\x1f\xd2\xe7\x5c\x8b\x8a\xf5\x33\x7d\x52\xc4\x53\x1f\xd1\xeb\xfa\xe8\x1f\x77\x0b\x03\x63\xa6\x63\x66\xb4\x63\x65\x2a\x56\xe8\x2b\x84\xa9\xc8\x44\x33\xcb\x03\xd1\x4d\x64\x79\x91\x42\xc7\xc9\x14\xd2\x1c\xe7\xe2\x86\xa4\x50\x15\x10\x56\xf2\xa5\x0d\x58\x54\x79\x31\x32\xd8\xb2\xdf\x8a\x9c\x18\xa2\x7d\xda\xd9\xa5\xe0\xd0\xc2\x45\xc2\xfa\x62\x51\x81\x69\xac\x85\x08\x23\xb1\x3f\xcb\xf0\xff\x88\x3c\x8a\xc8\x6d\x15\xb2\x5d\x8b\x39\x8b\x27\x81\xc1\x28\x14\xe7\x84\x15\x2e\x8f\xe0\x77\xb1\x77\x74\x51\x6e\x78\x08\x34\xac\x47\xa7\xa8\xd3\xd5\x59\x55\x6b\x7b\xac\x50\x4d\x25\x7c\x59\x0f\x85\x9f\xa9\xd7\xf2\x9a\x8c\xc4\xe8\x96\x12\xf1\xb9\x0c\xce\x5c\xe0\xda\x3d\xbd\x80\xd4\x60\xc6\xbc\x95\xa5\x2d\x25\xf0\x89\x2c\xce\xc5\x38\xa4\xbf\x31\x68\xb5\xdf\xa9\xde\xb0\x38\x3a\x58\x15\x9d\x48\x95\x8b\x64\xe0\xec\xec\x84\x6e\x70\x15\xa5\x76\x12\xb1\x25\x4a\x2f\x96\xe7\x6a\xff\x8a\x93\x0e\xa5\x2e\xaa\xd9\x02\x02\xfc\x14\x2f\x2c\x9d\xaa\x9f\xaa\x52\x73\x78\x14\x53\xcb\x4f\xbe\x18\xae\xa0\xb5\x79\x14\xcf\x61\x68\x09\xa4\xb9\x55\xdb\x16\xa9\xd6\x07\xd7\x07\xd4\x4b\x02\xad\x4b\x4e\xb5\xd4\x7c\x14\xbc\x33\x88\x14\xfb\x4f\x8d\x6a\x92\xa3\x94\x59\x10\x22\x70\x70\x37\x50\xaa\xff\x16\xf1\x68\x5a\x7e\xe9\xb0\xb1\xad\xc9\xf2\xf8\x3d\x91\x79\xf8\x3e\x34\x7d\xbd\xb5\x79\x5c\xe8\x3d\xf0\xd3\x3a\xe8\x72\xdc\x3e\x36\x29\x74\xa9\xdf\xae\x06\xa4\xaa\x6c\x42\x2d\x1e\xe2\xbc\xb5\x5a\x44\x57\x62\x12\xf0\x7e\xdd\xad\x2a\x39\x78\xf0\xdf\xbd\xc1\x48\xd4\x83\x30\xa8\x97\x60\xca\xf3\x98\x3a\x2d\x85\x06\x10\xcf\xb8\x15\x20\x85\x50\xce\xd2\x6d\xb9\x50\x80\xd0\xa1\x3e\x73\xcc\xc8\x33\xcc\x7c\xdf\x11\x43\x55\xde\x1c\xe1\x3b\x66\xcf\xec\x7e\xe4\x09\x0f\x84\x83\xb2\x0f\x9b\x6e\x8b\xb3\x86\xe4\x02\x2b\xa1\xe6\x2e\x1e\x77\xa7\x0c\x25\x7b\xe2\x9b\xe6\x55\x4d\xe0\xbb\x1e\x57\x7b\x0e\xe7\xbd\x66\x21\x5f\x21\x3a\xf6\xa6\x58\xe7\x16\x9f\x5e\x11\xf1\x84\xfa\x98\xdf\xf0\x36\x35\x10\x7d\xcf\x10\x33\xc8\xb9\xf4\xa6\x45\xc1\x4a\x1c\xfb\x87\xaa\x02\x33\xb0\x66\x74\xbd\x82\xb8\x9f\x5e\x54\xb3\x60\x7f\xd5\x92\x2e\x37\x1c\x1d\xe8\xc4\xab\xa2\x61\x7c\xd5\xb0\x83\x07\x34\x9b\x7e\x20\xd9\x21\x40\xec\x23\xe4\x21\xeb\x7b\xf7\xd7\xa5\xd4\x3d\xee\xef\xe2\xb1\xf3\x41\x50\xe2\x36\x1b\xc2\xd4\x6c\x40\x4f\xf2\x51\xa1\xf3\x0b\x82\x85\x43\xa1\xff\x5e\xfb\xbe\x49\x46\xc8\xf4\xbd\x44\xba\xe8\x3b\xe7\x79\x94\xa0\x05\xe5\xbc\xb3\x7f\xcf\xaa\xaa\xed\xd6\xfe\xa0\x92\x5f\x13\x38\x17\x60\x3e\x43\x3a\x54\x68\x36\x40\xf8\x30\x50\xf0\x6f\x4c\xba\xdd\x72\xf2\xd6\xcd\x21\x9c\xb8\xf8\xe1\x0d\x4a\xa5\x3f\x0a\xad\x59\x9c\xd4\xbb\x8f\xd5\x64\x59\x9a\x7b\xc6\x4b\x3b\x40\x3d\x32\x1f\x25\x0b\xaf\x89\x41\x9e\x4b\x1c\xae\x7e\xb9\xf4\xa4\xf1\x64\xf5\x72\x52\x98\x7b\x85\x98\x47\x4b\x80\xa5\xac\xf6\x8d\xd8\xf7\xc1\xe6\x4b\x91\xfa\xd0\x2a\xa0\x68\xcb\xab\x30\x2e\x9e\x98\x10\xe4\x48\x2e\x62\x90\xd3\xb2\xc1\xf7\x2b\xf6\xef\x49\x6a\xab\x91\xe3\xf0\x7a\x78\x8a\xa2\x08\xd1\x4b\x65\x2c\x64\x81\xed\x67\x4f\xe5\x93\x52\x24\xb9\x80\xce\xf2\x5d\xd1\xb3\x00\xff\x05\x4d\x50\x1e\x52\xff\xc3\x80\x04\x5b\x04\x52\x5e\x9b\x00\x35\x4c\xae\xba\x04\x63\x28\x9a\xd4\x35\x61\xd5\xcc\x0d\x34\xb8\xc8\x01\x9f\x79\xea\x60\xab\x21\xfa\x62\xe0\xbf\x02\x29\x29\x54\xff\xc9\xe1\xdf\x70\x0e\x6d\xcc\x27\x6c\x98\xcd\xbb\xee\x85\xd8\x7c\x04\xbc\xbb\x1c\x6f\x48\xea\x9f\x50\x2f\x0f\xb8\xc9\x18\x3b\xaf\x3f\x52\xbe\x7a\x58\x46\x8b\x3d\x55\xd5\xfc\x78\x7c\x17\x4d\x78\x22\x26\xf6\x88\x15\xd0\xfa\x97\x9a\x24\x15\x10\x77\xf8\x38\xe2\x8c\xd8\x4d\xd9\x9c\x55\xe0\x78\xcd\x38\x22\xc1\xe3\x1a\x6c\x87\x6c\x97\x6e\x6e\x94\x4d\xac\x94\x01\x1e\xd3\x99\xdc\xdf\xc7\x94\xa7\x2c\x12\x99\x41\xdc\x31\xb1\x8a\x37\xfb\xb1\x0c\x17\x69\x2e\x9d\x77\x73\xbf\x6c\xd3\xfc\x27\xa4\x99\xdc\x36\xa1\x88\xf2\xa8\xd9\xeb\x96\x19\x8c\x32\xaa\x2f\xfd\x0f\x53\xe7\xda\xf2\x3b\x3b\x24\x63\xa3\xe3\x8d\xd5\x9e\xce\xaf\x36\x7e\x26\x54\x62\x7a\x7c\xb7\xbd\xbb\x48\xf3\x64\x5c\xd8\x6c\xab\x9a\xa8\x0f\x6c\x96\xf5\x6f\x0e\x0d\x1e\x88\xa7\xc2\x04\xf2\xbd\xb5\x23\x54\x22\x8a\x30\xbb\x63\xd1\x71\x27\x2b\x87\xa0\x9f\x36\xe9\x53\x63\x77\xfb\xcf\x1f\xe6\xc9\xc6\xc1\x2a\x38\x28\xc2\xd8\x26\xd1\xaa\x77\x89\x90\x32\x87\x02\xe5\x89\x23\xaa\x85\x86\xa3\x86\x5d\x46\x61\x89\x91\xcb\x79\xff\x0a\x9f\x86\x30\x8c\xff\x68\xbd\x51\x69\x72\x5e\x58\xfc\x6c\xc3\xe8\x49\xee\xa9\x0a\x64\x76\x8b\x78\xc4\x2a\xb7\xc5\xa5\xea\x0d\xb9\x22\x40\xf2\xba\x17\xd7\xac\xa3\xc8\xa7\xe0\x71\x24\x12\x67\x5c\xfa\xb9\x9b\x93\x38\x9f\xa0\x3d\xa3\x67\x5f\xea\x2d\x67\x3f\xb5\x2f\x62\x8a\xdb\x39\x64\x44\x30\x03\x15\x60\x06\x77\xd1\x7e\xa9\xcc\xba\xb0\x20\xb4\xc4\xe5\x9e\x1d\xf1\x51\x06\x66\x02\x7e\xb5\x7f\x84\xe0\x8e\x0a\x2e\xb3\x9e\x3c\x20\x9a\x29\x94\x4e\x1b\x87\xf5\x5d\xcb\x21\xb1\x17\x33\x9e\x74\xe3\xde\x5a\x74\xbe\x33\xee\xe6\xdc\x35\x59\xdb\x6b\x3e\x76\x54\xd9\x0b\x6f\x61\xe2\xaa\x86\x6f\xac\xc7\xb0\x5e\xb0\x78\x14\xa4\x03\xfe\x6d\x3e\xf5\x3c\xe9\xf4\x6f\xf2\x14\xb3\x7b\xff\x64\xb8\xd9\xbc\xc1\xf5\x57\x42\x71\xf3\x86\xb8\x06\xea\x41\x71\x32\x8c\xc1\x68\x33\x4d\xed\xbc\xda\xd6\xbf\xb5\x00\xff\x4b\xb7\x68\x82\x1b\xbd\xaa\x92\xa9\x19\x2e\xc8\xc2\x67\x7c\x11\xc6\x01\x54\x7b\xf5\x1f\xf4\xf3\x7b\x6d\xe5\xac\x63\xfd\xe0\x19\xb5\x8d\x11\x96\x74\x43\xaf\x39\xd1\xe4\x0f\x2d\xd0\xa3\xda\xb6\x5b\xfb\x36\x2e\xea\xbd\x40\x95\x81\x09\xb2\xb4\x16\x6c\xed\xb4\xd8\xc6\xf4\xae\x3f\x6b\x11\xa9\x93\xf7\xb0\xdb\x8a\x1a\x6d\x95\x02\xff\x0e\xf7\xcb\x53\xfe\xe0\x0b\x81\xdc\x21\xde\xa2\x11\x6b\x4c\x62\x7e\x8d\x63\xe9\xb4\x93\x1c\x63\x47\xb1\x6a\x76\xb3\x14\x72\x92\x81\x19\x42\xfe\xae\x75\xdb\xa6\x3d\xe6\x1e\xb2\xc1\x55\xad\xc5\x9a\x86\xfa\xa5\xc4\x7d\x26\xa7\xc7\x1a\xf6\x85\xcb\x65\xf8\x28\xfc\xab\xb4\xf8\xab\x8a\xa0\x21\x39\x8a\xfc\x74\x5a\xed\xb6\xd7\xe2\xe7\xa3\x43\xf8\x14\x52\xb4\x08\x6d\x00\x96\x69\xa1\x6e\x41\x07\x54\x8e\x32\x15\x43\xa6\xb0\xb3\xc7\xaf\x22\x89\x3f\x51\x86\xce\xed\xe3\x9b\x79\x1f\x09\x27\x4a\x55\x5f\x24\x73\x4a\xa3\x22\xf8\x84\x3f\x14\x30\x93\x85\x03\x0e\x98\x7f\x64\xf7\x3b\xd4\x40\x20\x0c\x16\x2a\xd5\x60\xf7\xea\x1b\x39\x1a\x45\x58\x5c\xa7\xfa\x6f\xed\xc4\x87\xeb\x16\xa5\x2a\x12\xcb\x59\x0d\x93\xeb\x47\xf7\x96\x46\xdf\x72\xab\x06\xd5\x79\xec\x3f\x82\xea\x3f\x99\x64\x16\x2a\x0e\x13\x02\x9d\xab\x75\xb0\xa8\xc8\x19\xc9\xfd\xcb\xb4\xd5\x96\x64\x4e\xcb\x8d\x87\xd8\x71\x13\x15\x71\xd1\x98\x98\xc4\x2c\x0d\x45\xad\x61\x2f\xff\x76\x0d\x4d\x1e\x06\xc6\x92\xff\xb4\x43\xe0\xc1\xd0\xa4\x66\x90\xbe\xb1\xec\x46\x72\xb4\x75\xee\xf3\x1d\xf5\x7d\xcf\xb5\x34\x59\x94\x52\x60\x41\xec\x99\x43\xf5\xb5\xdf\x6f\x10\xc8\x66\x95\x38\xb8\x43\xd1\xd2\xad\xd1\xaf\xbf\x00\x32\xf1\x04\xec\xf7\x2f\x2f\x2d\x0f\x98\xf5\xa5\x57\xf6\x3c\xee\xf7\x85\x4a\xdf\x54\x06\x6d\x71\x01\x97\xf6\x7e\xa2\x4e\x26\xe3\x3d\x1d\xc5\x45\xb6\xe3\x2f\x5d\xf6\xb6\x02\x05\x45\x07\xab\x43\x91\x0c\x5d\xfc\x50\xbd\xd3\xf5\x98\x4a\x88\xde\xd5\x89\x08\x86\xcd\x77\x99\x51\x94\xf6\x6e\x46\x3f\xa5\x75\x04\x99\xe7\x24\xc0\x78\x89\x30\x96\x36\x80\xb0\x56\x60\x94\x9f\x84\xc7\x0d\x77\xc3\x0a\xfa\x33\xa8\x4f\x24\x8e\x2a\x2b\x8d\x59\x85\x26\xad\x50\x51\x47\x44\x51\x39\x44\xb0\x15\x7c\x52\x6c\x6b\x06\xf6\x4f\xf1\xda\xf2\x66\x32\x2c\x4b\xeb\xf3\x8b\xbc\x6c\x28\x5f\x8e\x36\xdf\x11\x51\x5d\x5f\xef\xd3\xdd\x14\x54\xa8\x47\xa3\xe9\xc4\x01\x14\x7d\x3e\x9f\xc3\xc6\xf9\x2b\x59\x3a\x99\xf5\xf3\x29\x8a\xc9\xa3\xc5\xd3\xcd\x5d\xdb\x5b\x97\x0a\xb9\xae\x25\x4e\xdf\xd1\x83\xeb\xd4\xa8\xcd\x20\xc7\xf6\xda\x02\x35\x36\x0b\xe8\x62\x1b\xf1\x6d\x28\x63\x6d\x41\x1d\x26\x35\x87\x05\x7b\x23\x33\x4b\x6b\x0e\x1f\xb3\x98\x25\xd4\x5b\xa2\x6f\x0c\xc2\x04\x32\xab\x42\xe4\x99\xfa\x6b\x38\x8e\xbd\x84\xf8\x6f\x21\x92\x22\x6a\x16\xf7\x09\xb4\x05\x45\x4e\xd3\xa6\x4d\xea\x30\xa5\xe9\x87\x87\xcb\x0c\xc4\xd4\x3e\x6c\x64\x1c\xfd\x80\xd5\xc3\x57\x1a\xf2\x39\x0b\xf7\x8b\x69\x17\xa2\x37\xf5\x6f\xb1\xc7\xe1\x3e\x63\xba\x94\xb1\xcb\xdb\x1d\x1c\xda\x59\x3d\x9c\x3e\xed\x6c\x96\x05\xeb\x06\x5b\xce\x2f\xf0\xd1\x45\x73\x04\xf2\x3d\xa0\x31\x32\x70\x4c\x9f\xca\x54\x24\x58\x69\x69\x7e\x34\x09\x4b\x82\x0f\x67\x8e\x48\x4d\x02\x76\x8b\x43\xb6\xa6\xf4\x49\xdc\xa9\x79\x25\xe1\x00\x42\xe7\x84\xd0\x71\xc7\x2c\x35\x30\x15\x44\x4e\x1b\x61\xbc\x88\x36\x1a\x43\x3b\x12\x52\x8e\xb5\x2f\x18\xf5\xef\x9b\xa7\x0d\x7b\xe1\x3e\x7d\xa0\xad\x7a\xa6\xbb\x3e\xdf\xfc\x28\x92\xc3\x74\x30\x52\x1d\xdd\xb6\xa3\x9a\x27\x33\xd7\xe5\x8e\x45\x59\xde\x5e\xb7\x11\x58\x55\xa7\xae\x00\x5d\x72\x87\xed\x2a\xcb\x6d\x7d\xe5\x50\x02\x11\xbf\x00\x61\x3e\xc7\x75\x7b\x98\xad\x46\x26\x8c\xed\xfc\x3a\xca\x75\x70\xfb\xdb\x54\xfa\xcb\x29\x1c\xb9\xac\xb9\x9a\x81\xc1\xeb\x59\xba\xf9\x3f\x5f\x99\xb1\xa1\x00\xd6\xf3\x34\x7f\x50\x1c\x0c\x91\x51\xe6\x9d\xf1\xde\x7a\x19\x3b\x21\x66\x9a\xe2\x5a\xdd\x28\x9e\xe8\xdc\x7e\x54\x52\x36\x29\x15\x31\x79\x0b\x8d\xd6\x54\xf1\x5d\x69\xa7\x3c\x18\x16\x33\x0b\x2a\x73\x65\xd6\xf1\x83\x84\x64\x35\x21\x7a\x59\x69\x4c\x5b\x3b\x1b\x87\xa9\x62\xa1\xa9\xc9\xfe\x92\x14\xf7\x85\x51\xb5\x92\xfe\xdf\x30\x26\x6d\x39\x7a\x8e\x03\x5b\xb2\xbe\x57\x5b\x37\x69\xbf\x3f\xb7\x4b\x24\x72\x38\x9c\x26\xcb\x03\x6a\xbe\x74\xbf\x63\x9f\x32\xd6\x0f\x87\xcc\xe5\x73\xe7\x1e\x3b\x1d\xd8\xab\xd7\x02\xde\x0c\x8b\x9e\xda\x65\x6c\xde\x4f\xb4\x91\x8c\xe3\xae\x55\x65\x6c\x77\xa3\x2c\x0a\xf3\x10\x20\x39\x4e\x5b\xd9\x85\xf4\x1d\x73\x92\xf6\xb0\x1e\xc2\x01\x93\x6e\x01\xa0\x57\x03\xa1\xd4\x69\x7e\xc2\x5a\x75\x81\x29\x6b\x0f\x4e\xa7\xdc\x11\x61\xec\xbe\xe8\xb8\x5b\x04\x19\x2e\x1b\x87\xec\x83\xfe\xd0\x8a\xc4\xf2\xe7\x51\x5a\xac\x9a\x12\x01\xaf\xd9\x31\x4b\xd1\xe8\xb5\x38\xce\x54\x68\x8a\x78\x3b\x81\xef\x12\x0d\x92\x86\xc2\xa5\x81\xee\x32\x3a\x11\xcf\x4d\xcb\x5a\xed\xb9\xff\x07\xac\xd5\x05\x5c\xd9\xde\x67\xea\xd4\x6b\xb8\x6d\x2e\xef\xcd\x23\x56\x27\x96\x61\x33\x86\x83\x28\x8e\xec\x0a\xc5\x78\x1a\x71\x08\x73\xf9\x4e\xfa\xdf\x4f\x8d\x4a\xc5\xeb\x7a\xdf\x5a\x07\x37\xd4\x38\xab\xb0\x58\x6d\x84\x47\x84\x36\xfd\xa3\xe5\x60\xf5\xaa\x45\xd3\x47\xcd\xa0\x11\x27\x0d\xd4\x34\x99\x38\xea\x5c\xe7\x71\x95\xe0\x92\x48\x34\x0c\x99\x79\x69\xe1\x62\x3b\x6d\x82\x17\x90\x16\x68\x19\xf5\x26\x30\xb9\xac\xd5\xbc\xc2\x78\xa3\x3d\x9e\x8f\xf0\x41\x39\xbf\xdb\x0d\xae\x0c\xf6\x08\xb7\xcf\xae\x3f\x4b\x37\xb9\xdb\xec\xa7\xf7\x13\x63\x04\x3c\xfb\x1f\x22\x79\xfe\x09\x6a\x74\x9c\xfe\xcb\xdd\x8b\x8b\x5e\x24\xf1\x3c\x8b\x8a\x5d\x15\x68\xf4\xbb\x7f\x6f\xed\xba\xb2\xac\x0d\x22\x29\xe6\x04\xcc\xae\xe7\x0f\xaa\xdf\xaa\x68\xbe\xb7\x73\x8c\xb7\xb2\xb6\x14\x9f\x04\xed\x31\x12\x4d\x3e\xb0\x6c\x6b\x64\x35\xa7\x14\x10\x0d\x1f\x20\xd1\xe9\xae\xee\x31\x95\xf8\x23\x8a\xa1\xe0\x74\x0d\x72\x1e\x19\x26\xf5\x0c\x14\xd6\xf8\x74\x70\xd9\x5a\x50\xfc\xc7\xfa\xb1\x82\xc9\xde\xda\x19\xa6\xb9\x2b\xfa\xf6\x43\x15\x93\x9f\x92\x16\x0f\x6b\x41\xd9\x0b\xd8\x0c\x52\x51\x51\x41\xa4\x81\x69\x40\x86\x47\xb2\x19\xf5\x65\x2c\x50\x7b\x14\x8d\x6a\x24\x12\x42\xb7\x72\x9b\x0a\x17\x89\x7a\x9d\xe4\x57\x4b\xd3\xf7\xfd\xfa\xc9\x4e\x5d\x0e\x8b\xcd\xe9\x3c\xd7\xc9\x99\x6b\x9f\x33\x84\xf7\xc8\x15\xb9\xec\xb7\x61\x17\x7f\x50\x72\x85\xcf\x2c\x57\x69\x43\xed\xbb\x3d\xb5\xdb\x2c\xf9\xb7\x32\x5c\x9f\x3c\x64\x16\x41\xa2\xd6\xcc\x25\x9f\x54\xe4\x66\xb4\x15\x31\x84\x4b\x6a\x33\x56\x44\x49\x7d\x2e\xbd\xd2\xf0\x95\x4f\x1e\xb2\xbf\x4e\x10\xf1\x9e\xbd\x4a\x98\xf8\xab\x5a\xac\xcf\x45\xcb\xf5\xc2\x54\x57\x7e\x7b\xb0\x9a\x54\x46\x25\x4f\x80\x82\x77\x5b\x52\xcf\xc7\xaa\x0e\xb6\xcf\xee\x12\x45\xfd\x77\xbf\x37\xfa\xb8\xac\x84\x70\x49\xa4\x8d\xa3\xa1\x79\xd6\xef\x61\x08\x67\x4e\x56\xc2\x6a\x15\x47\x31\x94\x49\x03\x50\x2b\xfc\xb2\x81\x5a\x7f\x05\xbb\xc8\x2c\xe8\x20\x83\xc3\x4d\x11\x8c\x54\x61\x95\xd3\xcc\x78\xf2\xee\xa4\x2f\xb2\x10\x09\x5b\xc3\x04\xfe\x35\x2d\x81\x4b\x14\xf5\x92\x39\xbf\x39\xeb\x5c\xff\xf2\x66\xf6\xda\x9b\xf6\x83\x03\xac\x3f\xab\xdf\xdd\x7f\xc3\x13\xd7\xa2\xde\x8d\xf8\x98\x0e\x3c\x6f\xe2\x54\x1d\x20\x29\xae\x9a\x08\x03\xb0\xdd\x06\xc3\xe1\x9a\x95\x55\xd8\xeb\x30\xc9\xa8\x5a\x38\x89\x50\x44\x46\xd0\xf5\x7f\xf6\x17\x1b\xc3\xc6\x8f\x0c\x17\x1b\xd7\xdb\xec\x2a\x37\x62\x1e\x78\x0a\x03\x1e\xb4\x5c\x43\xc6\x90\x43\xcc\x7f\x52\x99\x65\x78\xcf\x32\x62\x07\x38\xd1\x1f\x23\x79\x10\xb1\x44\xce\xf8\x06\x52\xd1\xdc\x9e\x13\xb7\x66\xd9\x49\x7b\x1e\x1e\x19\x88\xd7\x18\x96\xfa\xd6\xb0\xc4\x38\x1c\xdc\x99\x9f\x15\xbc\xb8\xd0\x08\x0e\x95\x93\x1f\x5e\xf4\x95\x67\x19\xde\x34\x46\x45\x11\x1a\x3a\xdf\x30\x69\x68\x2f\x95\x5c\xa9\xeb\x61\x5d\xaf\x1f\x6b\xba\xbf\xb2\x21\xfd\x49\x49\xba\x49\x4d\xa1\x14\xe3\x94\x60\xd8\x0c\x58\x08\xc5\xa1\xc9\x2a\xdf\x34\xc4\x3a\xe4\x0a\x7f\xad\x84\xa8\xc6\xf8\xb8\xc6\x57\xd0\x51\xb1\xf5\xc8\xd9\x04\x3f\xb1\x96\x38\xa1\xc8\x51\x69\x2a\x74\xc2\x30\x2c\x81\xf5\x17\x67\x7d\x68\xb3\x61\xcb\x41\x74\x17\xfe\xe6\xde\x23\xae\x2c\x85\x54\x72\x43\xdd\x55\x1c\x80\x92\xb3\x3a\x0b\xfe\x28\x23\xb2\xb9\xad\xdf\x7b\xac\xd1\xa6\x89\xbf\x28\x63\x82\x41\xe1\xb1\x5c\xc2\x8b\x0e\x82\xcd\x81\x1f\x40\x9f\xd1\x8b\x1d\x28\xea\xc5\xf9\xd4\xc8\x3a\xa3\xfc\x85\x98\x36\x90\x4d\xd0\xcd\xaf\x30\x6f\xa9\x4b\xba\x19\x21\x16\xfe\xd6\x3a\xcf\xdc\x3a\xb1\xe3\xfc\xb9\x20\xb3\xba\x5a\xec\xc0\xfb\x35\xfa\x5e\x7b\xee\xff\x9a\x13\x52\x86\xcf\x58\x26\xaa\xbb\xf0\x39\x13\x1d\x82\x44\xc8\x5b\x05\x0f\x01\xc3\xee\xb4\x72\x8c\xe3\x72\x46\xd0\x7a\x97\x8b\xf4\x04\x36\x6e\x9d\xcf\xe9\x22\xe4\xe3\x52\x3f\x5c\xa5\xf3\x3a\xb4\x94\x60\x5b\x79\xdb\x9b\xb1\x15\x57\x51\x24\x90\xdc\xd7\xeb\x9e\xef\x5f\x15\xd8\xe5\x35\xb7\x12\xb1\xb5\xe9\x10\x81\x41\xc7\xf6\xeb\x4c\xc5\xdd\x45\xb7\xbf\x96\xd9\x34\xa3\x82\x7c\xc1\x8f\xab\x56\x2e\xaf\x15\x0f\x73\xd7\x99\xc1\xb3\xb6\xc9\x62\x16\x97\xb5\xcd\x57\xec\x39\x3b\x03\x0c\x6f\x55\x21\xff\x3d\xa1\xed\xc9\xfb\xb7\xd7\xd6\x22\x57\x45\xf8\x0d\x94\x5c\xd6\xeb\xc7\x06\x72\x81\x57\xc2\x2e\xeb\xbb\xdd\xc3\x46\x6a\x2f\x4c\x62\xcb\x41\xa8\x89\x5b\x1d\x1a\xe5\x50\xe6\x6d\x55\xdd\x2f\x85\xef\xd3\x29\x87\x47\x07\xcd\x95\x64\x95\x74\x22\x97\x6b\x29\x0a\x3a\x14\xb0\x03\x07\xad\xaa\xde\xa7\xae\xbb\xe7\x37\x38\xda\x87\xcf\xcd\xd9\xed\xdb\x21\x9b\x9b\x5e\x1f\x84\xd7\x25\x6f\xbf\x20\x5f\xba\x6a\x1a\x6a\x55\x38\x2c\x18\x5e\x3b\x7a\xa6\xa5\xd3\x49\x50\x9c\x79\xc9\xa8\xd8\x1d\x0b\xdc\xdd\xc8\x3b\xbd\xed\xdf\xae\xea\x85\x21\xa6\xb0\x96\x96\xec\xc2\x66\x12\xa4\xe0\xa0\x4a\x2f\xa4\x85\x5c\x7d\x85\xa2\xb2\xab\x63\x18\x33\x26\x62\x7a\x4f\xa1\x4e\x9e\x6c\xa0\x0a\x69\xfb\xb4\x11\xe6\x18\xa9\xbb\xd7\x73\x67\x2b\xe6\x08\xbb\x34\x6d\xb5\x16\x1e\x9e\x50\xba\xac\x57\x1b\x1e\x7b\x7e\xde\xa3\x10\x15\x34\xf3\x02\x14\x32\xa7\x71\xfc\xff\xc6\x47\xc6\x62\x73\x34\x40\x0f\x39\x2d\xa6\x45\x3f\x6f\xbb\x42\xef\xd6\xde\xb6\x86\xc2\x2f\x15\x4c\x62\xa4\xf8\x0b\xde\x0b\xbf\xc0\xec\xbb\x98\x3f\xc6\x22\xb6\x16\x47\xf3\x40\xe6\xfb\x40\xce\x91\x44\xd4\xdc\xf2\x1a\x96\x34\xb7\x69\x3c\xca\xf7\x3b\xc0\xe2\xe1\xbb\x02\xff\x51\xa3\xaa\x80\x5b\x26\x24\xce\x56\x94\x5c\xf8\x95\x13\x64\x75\x23\x59\x65\x84\x08\x96\xab\x14\xca\xfe\x8c\x04\x75\x7b\xeb\x0f\x50\xf7\xf4\x4c\x6a\xb0\xa0\x1f\x90\xba\xe1\xb1\xca\xf5\x72\x72\x69\xc6\xdb\x59\x0b\x54\x5b\x8a\x4d\x75\xb3\xd7\xda\xc8\xc9\x4b\x75\xbb\x17\x3a\xfb\xbe\xe7\x43\x9d\xde\x0c\x87\x0f\x4b\x7d\xaa\xd4\x51\xf9\xdc\x80\x02\xd3\x26\x7c\x45\x7b\x5d\x65\x4a\xbc\x8d\xfb\x91\x95\x71\x67\x2d\x05\x77\x4f\x00\x5d\xc5\xd4\x87\x95\x81\x07\x6b\x8b\x14\xac\x1e\xe9\x4e\xd8\xd8\xab\xe8\xbf\xf5\xe3\x98\x65\x2b\x64\x59\xee\x6f\x18\xfc\x2b\x6c\x16\xcd\x38\x9a\x26\x63\xc5\x5d\x1e\x39\x46\x9a\xb5\x8f\xac\x15\x7c\xa6\xf2\xcc\x85\x4a\x81\x22\x83\x80\xdf\xcb\x8f\xa4\xa9\xae\x7c\x51\x9e\xce\x83\xc4\x57\xf6\x98\xaf\xa2\xd4\x9b\xbd\xcf\x1a\x23\xc1\xe5\x90\xf4\xdd\x54\x0a\xd8\xa7\x76\x87\x30\x2e\x6b\xfa\x1f\x70\x74\xf5\xb3\xe0\x76\x29\x14\x93\x86\x72\xa8\xf4\x7b\x33\xf9\xee\x2a\xa4\x8e\x5b\x0d\x3f\x2f\xc7\xb6\x1a\x57\xf3\x46\x9b\x97\x2c\x65\x43\x26\xdd\xd2\x53\x47\xaf\x18\x67\xaa\x94\x5b\x25\x21\x66\xac\x6c\x17\x36\xca\x59\x96\x97\x72\x57\x1d\x5d\xfb\xca\xd8\x76\xd4\x35\x25\x4f\xe6\x66\x83\x46\x4b\x35\x85\x6c\x3a\x05\x78\x0e\x3f\xb1\xe6\x5e\x0d\xdb\x1f\x4d\xbd\x7c\xe5\xdf\x8b\x37\x22\x6a\xbd\xff\xfd\x25\x60\xc8\xf9\xbc\x57\xb5\xb2\xd1\xb3\x75\x7f\xa8\xf6\x7a\x98\xf3\x3a\x86\x71\x5a\x1b\x51\x88\xb3\x5f\xe9\x7b\xd7\x53\x1a\x09\xa2\x9b\x21\x89\xbe\x5a\x35\xf0\x9d\xf1\x3b\x12\x0f\xf0\x10\x23\xe5\xed\xf6\xeb\xcf\x4c\xde\x14\x00\x45\xc2\xf5\xb0\xc3\xfa\x36\xc2\x81\x68\xed\xec\x9f\x57\x6d\x33\x2a\xa8\x0c\xa3\xb8\x68\x6d\xf6\x9a\x17\x17\x1f\x8c\x99\x97\xbf\x28\x88\x0b\x23\x6a\x8e\x3a\x46\xda\x14\xb5\xac\xa3\xff\x79\x87\xc0\x2d\xe4\x02\xd5\x41\x1e\xbc\xec\xcb\xcb\xa5\x61\xd9\x99\xeb\xe1\xea\x35\xa1\xb4\x54\xc9\x6a\x6f\x3a\x11\x41\x64\x6f\x15\xcb\x91\x86\xc9\xc1\x80\xdd\x7e\x33\x97\x98\xce\x12\xf1\xb5\x87\xd5\xb9\x87\xbd\x6a\xde\xf0\xb5\x74\xd6\x45\x47\xb1\x6a\x54\x87\xf2\xb1\xe3\x72\x4f\x7c\xe7\x6e\x81\xad\x96\x84\xb0\x2a\x3d\x59\x3a\x3e\xfa\x9b\x6f\xb9\xa5\x28\x4e\x63\x37\x33\x5d\x68\xcc\xd8\xb9\x17\x0f\x61\x22\x65\x29\x32\x52\xbe\xcf\x4a\xef\x18\x35\x97\xb9\xa5\x40\xad\xcf\x58\x55\x4e\x3a\x90\x26\x37\x6e\x74\x10\x3c\x15\xcb\x41\x1a\xef\xea\x56\x0f\x0a\xf4\x47\xd4\x92\xe6\x4a\xea\x04\x14\x7d\x25\xe7\x2d\xaf\x7a\x8b\xb6\x00\xcf\xfa\xfd\x58\x58\x36\x21\xd4\x9f\x2b\xfd\xde\xc3\xf3\x52\xff\xc3\x75\xce\x12\xef\x0c\xd9\x9c\x7f\xab\x65\xd7\x28\x79\x3a\x42\x30\xf4\x0c\x50\x59\xb0\xde\x8b\xb6\x01\x3e\x8b\x03\x96\xa5\x65\x29\x3a\xb3\xad\x0c\xbd\xd4\x96\x08\x06\x0d\xa1\x76\xf9\x75\x02\xa5\x1e\x17\x09\x83\x1c\x55\x42\x3d\xae\x7f\x8d\xff\x29\x49\xaa\xf9\xf1\x30\xa4\xce\x16\xdf\x86\xfa\xae\x79\x13\xfb\x5a\xa0\x2b\x70\x49\xbc\xf8\xd3\xb5\xc9\x65\x97\xcd\xf9\xb3\xfa\x32\xbd\x64\xcb\xc3\x95\x33\x08\xe4\x5a\x34\xb3\xb0\x98\xcb\xa8\x48\x2f\x7e\xb7\x5c\x3f\xa4\x60\xe9\xe4\xfb\x38\x57\xb9\x2d\x50\x5d\x3f\x94\x10\xf9\x7f\x57\x3f\x6d\xdc\xf2\x0f\x9a\x89\xba\x8a\x6d\x2f\xf2\xc5\xfb\x11\xa8\xa9\xdd\xce\xc2\x0d\xc3\x75\xce\x25\xcf\x32\x1f\xfd\x2b\x21\x5d\x42\xf1\x7b\x4e\xd0\x32\xf8\x34\xd1\xff\x30\xca\xf0\x8c\x19\xba\x88\xc6\x3c\xe1\xe8\x8c\x53\x77\x6a\xee\xa9\x57\xd3\xb5\x89\x09\xa7\xc1\x6c\xc0\xfd\x3c\x12\xbb\x5e\x22\x71\xe8\xb0\x42\xb9\xd2\x2e\x0f\x98\xad\xc4\xba\x9a\x4c\xf2\xb0\xe5\xb6\x6d\xca\x27\x18\x41\x54\x5b\xe6\xd9\x61\xe8\x39\xee\x55\x51\x7b\xec\x3b\xc7\xfb\xc8\xbe\x75\xec\x7b\x4d\xbf\x42\x3c\xd4\x80\xb7\x1e\x88\xab\x1f\x65\x3e\xc6\x8a\x1a\xb3\x72\x9c\x38\x08\x87\xa8\x90\x8e\x96\xd8\xf2\x8c\x46\x5a\x98\xdf\x50\xb8\x57\xc7\x65\x57\x91\xf3\x4f\x63\x11\xd1\x2c\xa6\x17\x97\xe3\x88\x6d\xc8\xc4\xe6\x34\xa9\x99\xeb\xb4\x2a\xc1\xd6\x2c\xce\x4f\xed\xfc\x0a\xbf\x44\x89\x4b\xdb\x6d\xb7\xd9\x3e\x76\x14\xee\x43\xeb\xc0\x5a\x44\xca\x9b\x5e\xa7\x47\x3f\x8c\x4f\x90\xef\x19\xf8\xf3\x96\x41\x99\x60\x97\x2b\x7e\x18\xfa\x34\x03\xbe\xf7\x8e\x59\x3d\x17\xe2\xc3\xf6\xda\xcb\x18\x27\xd7\xfe\xe2\x45\x1a\xdd\x9d\x8c\x12\xec\x24\x99\x3d\x8b\xa2\x68\x81\xbd\x35\xa8\xb5\x11\x5c\x4a\xbc\xd5\x11\x84\x4d\x70\x58\x1d\x43\x0d\x93\xd1\x2f\x83\x23\x89\xe5\x48\x3b\xdc\x90\x70\x5a\x3f\x98\x3d\x34\x29\xab\xb4\xf8\x7d\xe5\x6d\xa0\xbd\xfe\xc9\x72\x75\xeb\x7f\x5b\x77\x68\x50\x67\x3c\xe5\x70\x9b\xd7\x2c\x6e\x20\xf2\x56\x66\x40\x91\x67\x44\x40\x3d\xfc\x83\x86\x7d\x56\x6e\xf1\x83\x3c\xdf\x28\x7d\x49\x7b\x3c\x1e\x53\x56\x04\xb1\x10\xf5\xfe\x47\xf0\x28\x78\xa7\xa0\xb9\x72\x3f\xf9\x77\x50\x99\x79\x1c\x82\x4c\xf5\x8b\x55\x97\xf3\xac\x51\x1b\x3f\xd3\xdd\x3c\x98\xc5\x50\x00\x14\x21\xf7\x5d\x94\x0e\x12\x5a\xcd\x1c\xbd\xde\xe3\x47\x69\xdd\x66\x1d\xc3\x5e\xfb\xe1\x2b\x19\x07\x5b\x89\xbd\xf6\xc7\x47\x74\xdc\x09\x47\x73\x40\xcf\xc5\x2b\x89\xc2\x3e\x6f\xb7\xe0\x77\xba\x59\x79\x99\xee\x86\x0b\x3b\x62\xf6\x32\xea\x0c\x16\x5e\xc0\x34\x79\x53\xb2\x12\xfd\x7a\x75\x80\x8d\xdf\xcb\x59\xd2\xb2\x41\xaf\x7c\x8e\xcd\x22\x9a\xdc\xc9\x4f\xbe\x47\x49\x55\x9a\xf4\x75\xa6\xb1\x1f\xde\xd2\xa4\x61\x19\x5f\x49\xe5\x83\x12\x2c\x45\x9c\x35\xf2\x11\x38\x96\xaf\x7f\x72\x72\x64\x33\xdf\x2c\xd5\xb3\xaf\x12\x99\x5c\xce\xe6\xf2\x79\x4e\x13\x83\x12\xf6\xdc\xcf\x73\xb8\x22\x76\xff\xbd\xb8\x88\x8e\xc6\xc9\xc9\x71\x10\x84\x98\xea\xee\x7d\xad\x94\x9e\x61\xd1\xf9\xfd\x0b\x25\xc9\xdf\x7b\x74\xe3\x59\x74\x46\xd7\xa1\x12\xa0\x75\x83\x1e\x19\x24\x05\xf9\x49\x07\xdb\xbb\xf4\x43\xec\x7a\x59\xcc\xd8\x3a\x56\x18\x0b\x31\x11\xf3\x81\x40\x2c\xa1\x48\x86\x46\xe8\x17\x16\xde\x8e\xa4\x66\x2e\x51\x82\x21\xc6\x51\x2c\xc3\x6c\x50\x07\x1f\x01\xdf\x42\x94\x44\x21\xa5\x18\x19\x89\x3c\x81\xdb\x1a\xd9\xd2\x9a\x9c\x65\xde\x7a\x22\xce\x77\xce\xbf\x2e\x1c\x1b\xf2\x32\x0a\xf6\x56\xfc\x61\xc2\x9e\xd7\x16\x25\x92\x6c\xeb\x8c\x58\x9a\x8e\x8b\x1a\x23\x13\xdc\x2b\xcc\x84\x92\x8f\x73\xdf\x4f\x65\x77\x9e\x73\x9a\xd9\x85\x35\xb8\xe5\xd5\xc1\x5a\x36\xb9\x97\x5b\xc4\x06\x62\x1c\x64\x38\x5f\x38\xb4\x42\x8c\x59\x8b\x95\x37\x9d\x3b\x97\x0a\xd7\xbd\xd9\x86\x7b\xf3\xd1\x47\x3d\xc1\x87\x81\x2e\xdd\x46\xc3\x0a\x94\xca\x50\x13\x70\xb6\xa4\x49\xb1\xd7\x57\xcf\x3e\x2f\xe5\xdd\x6b\x18\x5c\x16\x30\x98\xdd\xec\x5a\xc7\xfd\x0c\x53\x1a\x54\x55\x5e\xae\xb8\x56\x43\x31\x50\x9a\x3c\xca\x38\xc4\x7d\x33\x2f\x33\xa8\xf0\xb0\x6a\x1a\xf5\xe8\x19\x1b\x38\x53\x7d\x79\xfb\x55\x3a\x10\xff\xf5\x9e\x84\x55\x8b\x50\xc4\xee\xb5\x48\x28\x81\x87\x7e\x96\xb1\x4f\x37\xc9\xba\xd5\x32\x91\xe4\xbc\xae\x83\x5f\x50\xf9\x98\x7c\x7f\xcf\xb4\x1a\x6f\x52\xda\x72\xd0\xc2\xff\x59\x07\xd4\xbe\x5a\x3c\x2e\xfd\x51\xa3\xb5\xca\xe9\x01\x23\xe2\x9a\xbb\x47\x9f\x4f\x47\x6b\x74\x6a\xbe\x75\xd6\xa7\x3a\x74\xab\x1d\x66\x74\x32\x41\xe2\xba\x6a\xc9\x0a\x11\xe6\x0a\x1a\xa9\xc9\x83\x64\xeb\x07\xf3\xa2\x94\x93\x45\x6e\x3b\xd0\xca\xa9\xc6\x66\x1c\x83\xde\xf7\xc0\x87\x37\x78\xac\x92\xca\x49\x0e\x67\x65\xc5\x93\x3a\x4d\xb9\x09\xcc\x77\x2d\x5a\x5e\x2d\x49\xc7\x75\x59\xa6\xa7\xc8\xed\x74\x14\x1e\x0d\xb9\x8e\x26\x7d\xc5\x4f\x96\x59\xa8\xf6\x0c\x1f\x89\x3a\xe9\x62\x22\x37\x66\x3d\xb1\x96\x72\xb9\x4f\x04\x16\x44\x39\x41\xde\x4c\x8e\x24\xd0\x59\xa0\xea\x57\x37\xe3\x9f\xfe\x39\xe4\xf9\xfc\x81\xd3\x5a\x16\xc8\xe2\x31\xbf\x1e\x90\x77\x4f\xf5\xcf\xe6\x35\x25\xf6\x99\xfb\xdc\x9d\x45\xb5\xa0\x26\x8b\x41\x13\x58\xff\x37\xb9\x76\xbb\x63\xa2\xc7\x68\x31\xe2\xb4\xc5\x9f\xc9\xe4\x25\x07\xd5\x9e\xf2\xbc\xd3\x36\xab\x1d\xc9\xcd\x66\xb7\x46\x91\xbe\x70\xcf\xe1\x2a\x7d\xa1\x5b\xd4\xa4\x97\x1c\x6a\xa9\x0e\xb7\x21\xa8\x22\xfd\x30\xfe\xe1\x9a\xdc\x4d\xa7\x31\xf2\x03\xf9\x05\x51\x8c\x7e\x10\x21\x7b\xf6\x47\x50\xc8\x95\x29\xbb\x04\x6a\x53\x8b\xbf\x74\xd9\x92\x02\x32\xb4\x35\xe9\x7c\x05\x78\x8c\x0c\xa5\x53\x15\x5d\xc4\xf3\x30\xf8\x97\x70\x0a\xa8\x03\x92\xf1\x9d\x12\x5f\x90\x7c\xd7\x12\x51\x01\x27\x6b\xac\x13\x7e\xe8\xa6\x3b\x89\x80\x5d\xc2\x26\x27\xb8\xf0\xf2\xa8\x4b\x98\xb6\xce\xc1\x42\xb1\x55\x9f\xcd\x2c\xbc\xad\x9e\xcb\x48\xda\xd1\x0a\x09\xa6\x29\x85\xae\xdf\xc9\xe6\x74\xbf\xec\x65\x23\x0d\x43\xa6\xeb\x9e\x52\xcc\x4d\x6e\xbd\xf5\xa4\x46\xf6\xd7\xfd\x8a\x46\xc0\xc6\xe3\x4a\xb4\x0c\xb9\x3b\xbd\xae\xeb\x5e\xea\x5e\x5d\x47\xa7\xdf\xf8\x7c\x90\x4d\x9d\x3e\xc7\x6b\x5e\x51\xfc\x3c\xb9\xae\xd3\x93\x98\x88\x44\x3c\xb6\x77\x50\xfb\xfd\xae\xde\x9b\xdf\xf3\x39\xf7\x1a\x5e\xce\xdf\x31\xad\x96\xe2\xbb\xb1\x1d\xef\x7a\x9f\x6b\x87\x53\xe9\xa9\xe8\x3b\xfc\xa2\xe4\x05\x69\x33\xdb\xe9\x53\x6a\xd4\x47\xf0\xd0\x5d\xd8\x4d\xf4\x12\x6a\xb2\x56\xb9\xb8\xdb\xdd\xdf\x4f\x85\xc9\xc5\x3e\x1e\x56\x34\x96\xe8\x2b\x96\xcb\xc6\x3d\xa8\xf1\x7f\x5a\x59\xb2\xce\x5d\x2c\x58\xd1\xe4\xe7\xbf\x47\xff\x4a\x7c\x09\x54\x61\xc5\x88\x0b\x98\xfb\xd9\x36\x6b\xba\x66\x7f\xe5\xdf\x3e\x41\x6d\x58\x7e\x0e\x4c\x75\xb5\x55\xaf\xdd\x1a\x2f\x1d\x8c\x95\x7c\x43\xb5\xc9\xf1\x71\x12\x9e\x04\xa9\x16\xf9\x9c\xd5\x58\xec\x31\x13\x34\x7d\x5c\xb4\xe5\xf8\x55\x51\xa6\xcc\x75\x40\x7f\xbc\x9b\x41\xb6\xc2\x79\xbe\xec\xfc\xd5\xbd\xde\xde\x58\xf7\xf0\x60\xc7\x62\x8a\xe9\x05\xf3\xef\x4d\x93\x76\xf7\xff\xc9\x47\xf2\xb5\xfe\xe7\x98\x6d\x17\x9e\x8f\xa4\x0e\x22\x7b\x1a\x1a\xca\x78\x2c\x08\x71\xc8\xe8\x8f\xdd\x74\x95\x57\x10\xc8\x04\x3a\xe2\x33\xa3\x1b\xbc\x9f\x8c\x9c\xb6\x0d\x48\xef\x4a\xc9\xeb\x04\xe7\xa3\x08\x9d\x7f\x8d\xc0\xcb\x0f\x87\xac\x52\xdf\x6d\xce\xe9\xa2\xd1\xbb\x91\x42\x43\x43\x11\x15\x6d\x78\x78\x5b\xda\x51\x41\x9a\x37\xb3\xeb\xfe\x47\x8d\x70\x1e\x0c\x09\xd6\x8d\xf9\x6d\x26\xcb\x17\xca\xe5\xae\xe8\x40\x75\xd1\xa2\x6f\xe9\x10\xd4\xf6\xad\xcb\xda\xf2\x0a\x3c\xd6\x4a\xac\x50\x50\xc2\x8b\x0d\xb4\xd8\xa1\x1c\x4f\x9c\xd1\x4a\xb8\x79\x9e\xca\x8b\x27\x4a\x82\xf7\x8a\x12\xbb\x56\x9c\x08\x7c\xdf\xfd\xa0\xea\xe3\x98\x5b\xad\xfe\x9f\x97\xdf\xfc\x47\x2f\x29\xe9\xf9\xe5\x5f\xcf\x0f\x22\xa5\xb1\xfc\x8a\xdf\x8f\x31\x73\x8f\x67\xb4\x3f\x63\xf4\xfc\x3e\x9c\xca\x72\x9d\xce\x90\xf2\x9b\x2a\xd1\x9a\x27\xc1\x52\x5a\x10\x2c\x76\xb4\x38\x3a\xbb\x4b\xb5\x69\xb3\xbc\xac\x54\xde\xa2\xc3\x02\xfc\x5e\x77\x2c\xaa\x59\x14\xf8\x6d\x97\x43\xa5\xc0\xc2\x05\xee\xd6\xb8\xb0\x38\x4c\x6b\x39\x85\x7d\x4e\x2f\x38\x6a\xae\xd7\x3b\x96\x24\xe2\xb2\xb2\x08\xbf\xfa\xf7\xca\xe4\x6d\x9c\xc2\x75\x93\xfe\x82\x8d\xce\xda\x3b\x89\xef\x07\xbf\x74\x8b\x7f\x69\x76\x56\x42\xa5\x44\xb0\xae\x51\xca\x9a\x9a\x38\x8a\x8f\xdf\x52\xa6\xe0\x93\xf1\x43\x98\x5c\x25\x91\x95\xab\x43\xfa\xaf\x32\x6a\x60\xb9\x4c\x10\x39\x84\x7d\x5b\x66\xb8\x7d\xd4\xfe\x49\xb7\x4b\xa7\x80\xc0\x32\x1d\xac\x19\x34\x3f\x52\x4d\x56\x18\xa5\x33\xf0\xff\x20\x93\x5d\xeb\x90\x0d\x11\xb9\xef\x27\xfa\x92\x16\x81\x14\xdb\x4e\x04\x85\xd2\xd1\x16\x63\x48\xbd\xc7\xaa\x2c\x8f\x53\x55\x0b\x32\x53\xc6\x23\x43\xc2\xdf\x86\x74\x62\x8a\xe6\x0c\x86\xe6\xaf\x3c\x32\x56\x28\x76\x01\x7b\x41\x3b\xb1\x72\x0b\x34\x80\x7b\xc4\x37\xb7\x8e\x78\x7a\xae\x03\xf3\xe2\xf6\x35\xaa\xa8\x64\x15\x21\x57\x81\x00\xdd\x35\x76\x83\x9a\x84\x00\xfb\x19\x32\xd7\xb8\x70\x4b\x9c\x5b\xaf\x71\x1e\xd8\x03\xc2\x79\x68\x22\x85\xda\x81\x93\xc4\x8c\x9c\xd4\xff\x10\x6b\xc1\x51\xcf\xad\x3e\xc5\x7e\x09\xf7\xc8\xf1\xb4\xf6\x14\x46\xb3\x61\x24\xe0\x3b\x87\xb8\x74\xfb\xf1\x25\xf1\xc9\x40\xc4\xeb\x7a\xf4\x94\x45\x5b\x9b\xcb\xe7\xf3\xa5\x24\x31\x93\xcf\x67\x53\x43\x59\xb5\xb6\xf7\x92\xf8\x02\x89\x37\xad\xfa\x69\xf8\x49\xf5\x29\xe5\xc7\x3c\xd5\xf8\xe3\x4d\xe1\x8d\xdb\x1d\xbe\x89\x05\xcf\x88\x82\xd7\x75\x53\x6f\x8b\x5d\xdf\x26\x57\xe0\x68\xf1\xa4\x2c\xdf\x77\xe2\x11\x62\xd5\x6d\xad\x6f\xf2\x8f\x69\x6f\x26\x9a\x47\x60\xae\x2a\x34\xc2\x20\x75\x50\xbe\x50\xeb\x52\x07\x83\x64\x86\x8b\xda\x30\x67\x4b\x5e\xbc\xb7\x17\x93\xf4\x92\xbc\x34\xfd\x00\x4e\xca\x9d\x4a\x91\x04\x3d\x08\xd4\x88\x90\xad\xa5\x04\x59\x10\x0f\xb5\x3d\x43\x2e\xec\x4c\xe7\x87\x93\x30\xda\xc0\x27\x9a\x7f\xad\x46\x4c\x7a\x3f\xda\x93\xa1\xc9\x69\x3c\xb3\x69\xa3\x2f\x7d\xb3\xa1\x06\x57\x8e\x31\x9b\xdd\x68\xa9\x33\xab\x95\x3d\x55\xdb\xb3\x2d\xd5\x5c\xdf\xc3\xa9\x0c\xa4\x47\x2c\xef\xb9\xba\xf9\xe7\xd4\x09\x96\xde\xed\x3f\x6b\xf7\xb2\x54\x4e\xa7\x7b\xab\x33\x07\x42\x56\x4e\x97\x6e\xe7\xbf\x2f\x17\x8b\x6e\x14\x79\x79\x5c\x86\xa2\x32\x93\x26\x7a\x9e\x5f\x69\x58\x17\x01\x73\xd3\xd7\x58\xf2\x23\xca\x22\x1a\x79\xf3\xf3\xac\xa4\x5e\x8f\x8e\xfe\xad\x52\x98\xf2\x49\x98\xd2\x7d\x11\x36\xd9\xfb\x23\x2e\x01\x35\xb4\x24\x10\x29\x42\x5f\x12\xe6\x62\x48\xbe\x9f\x4f\x60\x14\x0f\x02\x65\xf5\x31\xc1\xd7\x3f\xfd\x7e\xf5\xf2\x06\x08\xf5\x7e\x90\xb6\x0a\x6f\xfe\x54\x83\xc3\x34\x0a\x34\x7c\xac\x92\xa3\x84\xa7\x9e\xaa\x71\x65\x56\x76\x16\xa4\x57\xd0\x83\xc5\x69\x72\xd7\x21\xbc\xf9\x59\x91\x43\x1a\xe7\x2d\xae\xdb\x21\x95\x3f\x69\x9a\x2a\x83\x84\x19\x06\xff\x64\xc8\xc0\x0a\x2b\x83\x84\x0b\x21\x8f\x78\x37\xad\xc3\xee\xeb\x66\xdc\xb2\xbe\xd8\x93\x16\x48\xb5\x2f\xd0\x91\x81\x50\x12\x36\x30\x48\xe2\xd3\xf6\xfb\x14\x1e\x47\x86\x25\xa0\xe4\x57\x75\x39\x0e\x28\xf8\xcb\xb0\xae\x2d\x63\x0f\x26\x4b\xb3\xa1\x24\xd1\x6a\xca\x69\x02\xb3\x15\xdb\x1f\x89\x6e\xa0\x85\xcf\x2e\xfc\xbe\xb1\xd9\x4a\x47\xad\xe7\x1a\xba\xc1\x1b\x77\x09\xb9\x7e\x22\xbe\x9c\xa8\x48\x3d\x30\x9d\xf5\x88\xdc\xa1\x51\x64\x86\x92\x8b\x91\xb2\x10\xd4\x00\xd7\xd6\x96\xf1\xcf\x48\x25\x31\x36\x32\x6a\x9c\x96\x5d\x68\x0a\xaf\x81\x83\xe1\xc8\x74\x4e\xdc\x76\x9b\x5d\x83\xb5\x7a\xf7\x8d\x43\x08\x24\xa2\x75\x0b\xd7\x1a\xcf\xb1\x12\x9a\x43\xbb\xe7\xf5\xe0\x84\x44\xce\xb7\xcd\xe8\x0a\x9f\x46\x96\xfb\x5f\xae\x10\x44\x9a\x04\x06\x02\x81\x7a\x7f\xd1\x75\xa2\xbc\xcd\x3a\xbb\x6b\x4b\x3f\x16\x1f\xbb\xf1\xfe\x10\xc8\x20\x7b\x5d\x13\x27\x19\x19\xba\x7d\xa8\x42\x50\x26\xdd\xdf\xdb\x69\x7d\x94\xf8\xf1\x20\x20\xfa\x24\xbd\x66\x4e\x7b\xde\x34\x97\xfd\x0d\x8b\x74\x87\x62\x86\xd9\x94\x5d\x13\xc2\x85\xd5\xc8\x7f\x86\x2d\xc6\x7f\x5b\x72\x68\xa1\xdf\x61\x8d\xd5\x83\xd9\xd7\x73\x46\x84\xfe\xa0\x84\xb7\x5d\xa9\x16\x56\xa8\x40\xa6\xef\x67\x3d\x54\xf7\xb8\x8e\x9b\x92\x6f\x3f\x78\x43\xcb\x70\xf8\xf8\x6c\x4f\x4f\x67\x32\x61\xa1\x3b\x3a\x9e\x35\xe3\xd8\xeb\xbe\x2e\xbe\x72\xd0\xdc\xe5\x76\x97\xd5\xd9\x7a\xf9\x7f\x00\x7c\x2f\x83\xd0\xf1\xdc\x6f\x40\x5d\x25\x6d\xb3\xc4\x61\x6d\x3e\x61\x8e\x90\x75\x0b\x7c\x2a\x81\xc3\xc1\xd0\xb9\xdb\xbd\x63\xc1\xf8\xf3\x58\x30\xf6\x7d\x60\xc1\x28\x7b\x60\xc1\xe0\xbe\xdc\x48\x36\x89\x09\x6c\xac\x7e\xdf\x2e\x41\xff\x4c\x1a\x29\x3e\xff\x19\x3b\x4e\xbf\xf6\x33\x7d\x15\x3b\xb7\xbb\xed\xe3\x8f\xc9\x16\x17\x89\xeb\xc5\x37\x2c\x4f\x0b\x31\xac\xaf\xbc\xa9\x9c\x8b\x8e\xa9\x42\xa5\x65\x1c\x58\xed\x75\x30\xb7\x84\xe6\xc6\xac\x60\x98\x41\x4a\xcc\x83\x5e\x73\xd3\xcb\x85\x47\xf4\x7d\x90\x5e\x2a\x26\xd3\x6a\xf2\x70\x47\x98\x21\xb7\x56\xe7\xb1\x3b\x92\x8b\xac\xda\xda\x35\xd7\x1f\x77\xd6\x52\x91\xcd\xee\xbe\x9a\xb5\x0d\x49\xa6\x9a\xdb\x07\x3e\x2b\x3f\x7d\xec\x1f\xce\x5f\x31\xed\xec\xa3\xe7\x59\xd7\xaf\xdf\x99\x1e\x55\x5f\xdb\x3a\x24\xc5\x7b\x02\xe2\x55\xe2\x76\xcb\xdf\x85\x7e\xe8\x75\x11\x9b\x23\x17\xe2\x6b\xeb\x81\xe7\x50\xeb\xa0\x38\xe2\x4f\xf6\xe0\x78\xa8\xee\x54\xce\x63\x48\xde\x80\xec\x80\x1a\x09\x22\x54\xb5\x5f\x53\xe0\x4a\x49\x65\x15\xda\x6a\x52\x3c\x06\x6c\x47\xf5\x7e\xc0\x76\x64\xfa\x84\xed\x48\xd6\x9a\x04\xdb\xcc\x2e\xe7\x4c\xf1\x99\x61\x43\x06\x8e\x1e\x33\x72\xd9\xb2\x03\x06\x0f\x1c\x98\x19\xf8\x8c\x68\x55\x2f\x5a\xa7\x8d\x1d\x3a\x76\x42\xe7\x1f\xaf\x7e\x50\x3a\xdb\xda\x2f\x35\xa0\x31\xdd\x76\x61\x73\xff\x9a\x4c\x63\xb9\x75\xd1\x99\xa7\x9d\xd0\x3e\xa7\xb8\xe8\xf0\xd1\xcb\xce\xc2\xfd\xb6\x69\xf2\x83\xe2\xc1\x34\x0f\x55\x2f\xe4\x67\x69\xf7\x9c\x87\xd2\x24\x8c\x21\x22\xdf\x00\x29\x61\x89\x28\x9b\xf6\x34\x6b\x15\xf5\xff\xc8\x0f\x32\xa7\x55\xdf\xc9\xcf\x28\xe9\x0b\x2c\xd5\x50\xa7\x96\x22\x36\x56\xc4\xec\x37\xd2\xa0\xa0\x7f\x8f\x7e\x23\x08\x9a\xce\xd9\x94\xf0\x73\x36\x52\x3a\x5b\x42\xf9\x71\x09\x76\x1d\x63\xbc\xeb\x48\xfd\x6e\xde\xc8\xc7\xe9\xc1\x9e\xf6\x3e\xdf\xd7\x88\x11\xc0\x86\xea\x53\xb4\x40\x90\xc6\x36\x70\x2b\x29\x08\x45\x38\xb6\x20\x7d\xd4\x82\x2c\xdd\xa3\x05\x59\xd0\x81\xac\x05\x1d\x6e\xdf\xc0\x92\xb3\x66\x4f\x3c\xaa\x74\x03\x7b\xe4\x0a\xfd\x28\x6b\xe3\xf2\xd1\x99\x43\x93\xfa\x3b\xd8\x85\x5c\x7b\xed\x71\xed\xad\x62\x9a\x77\x21\x47\x37\x36\x85\x23\xfa\x78\x8b\x9b\xdb\x5b\x1b\x38\xf3\x16\x3a\xbf\x19\x10\x8e\xe6\xe8\x13\xb4\xe7\x0c\xd5\x31\xc6\x6c\x04\x38\xf1\x99\x60\x22\x01\x74\x2a\x41\x72\x0b\xb2\x1b\x21\x91\xa8\xab\x8a\xe3\xe7\xa9\xac\x93\x5a\xad\x4e\xa3\x93\xe4\x73\x35\xe4\x02\xdc\x73\x40\x7a\x1d\xa2\xa3\x9d\xd8\x4f\xb0\x18\x4e\x42\xc8\x98\x9b\xa7\xe8\x62\xa1\x94\x6e\xc3\x08\x74\xda\xfa\xee\x5b\x37\x4c\xef\xd2\xbb\xa5\x23\xd7\x4b\x6f\xbf\xc8\x2c\x1c\x7b\x07\xdc\xa4\xc4\x5e\xfb\x87\x4a\xb2\xb9\x5a\x1c\xc8\xb6\x48\x43\x40\xb8\x79\xec\xad\x3a\x79\xdf\x60\x48\x98\xd3\x5f\xcd\xaa\xe0\x1f\xca\x28\x60\x26\x4c\xd7\x5b\xd9\xeb\x82\x15\x3c\xcc\x10\xc1\x18\x1d\xa2\x8f\x32\xd4\x1f\xdc\x88\x87\xc3\x3c\x29\x78\x92\xde\x93\xdf\x8d\xc0\x19\x65\xdc\x28\x65\x7c\x7c\x3e\xda\x9e\x31\xf4\xb7\x96\x54\x7b\x7a\xf9\x5b\xae\xe1\x87\xde\x73\x87\x2d\x33\x64\xf8\xc5\x57\x76\xb8\xa6\x1d\x7c\xdc\x79\x37\xd5\xf7\xab\x4f\xe0\x77\x2e\x16\xff\xc8\xee\x01\x9f\x6b\x01\xcb\xa4\x79\xbd\xfc\xe6\xf3\x3e\x23\x78\x35\x44\xf0\xc5\x6c\xea\x2b\x16\xdf\xc6\xe8\xce\x57\xc5\x15\x24\xb3\xa5\x62\xa7\x54\x69\x9c\x4d\x19\xcd\xa7\x2c\x73\x45\x3c\xb7\x72\xa5\x72\x8a\x41\x46\xa9\x89\x73\xe7\xea\x85\x73\x87\xfe\xbb\x8f\x9d\xc0\xbd\x62\xd1\x2d\x7d\xf0\x86\x1b\x1e\x7a\xf0\xfa\x8d\x0f\x6d\x9e\x39\x63\xda\xcc\x59\xd3\x0f\x39\x4c\x66\xa7\xae\x7d\xe0\x81\xb5\xa7\x5e\x7b\xdf\x7d\xd7\xce\x38\xfa\xe8\x19\xa7\x4e\x5f\xb2\x64\x3a\xe6\x3b\xc3\x85\x75\xd2\x9d\xd2\xdd\xc0\x59\x9e\xef\x04\xa5\x0c\x0b\xb3\x64\x82\xff\x1d\xfe\xd5\x57\x0f\xb0\x22\xfd\xb3\x07\xd8\x1f\x8c\xab\x75\xec\x2a\xb6\x46\x5f\x19\xd4\x57\xe6\x2f\x80\x3e\x8b\x70\x2a\xfc\xc2\x33\x02\x02\x7c\x92\x53\x88\x00\x95\x37\xf1\xe9\x2f\xea\x6d\xf2\x78\x15\x89\x86\x20\x71\x50\x7d\x99\x5c\x84\x7b\x61\x25\x9d\x8d\xd2\x96\x44\x14\x1d\x94\x28\x11\x08\x14\x31\xb8\x94\xb7\x3b\x81\xc1\x16\x39\xef\xee\x64\xbe\x2f\xea\x2e\x4a\xa7\xb5\xa0\x03\x4f\xfe\x11\x57\x68\x30\xd6\x89\x78\x1c\x5b\xec\x0e\x57\x24\xca\x8b\xff\x48\x88\x3f\x1b\x55\x34\x97\xad\x03\x37\xa2\x72\xb2\xc3\x1d\xa3\x89\x1e\x91\x0f\x89\x65\x14\x92\x95\x84\xc8\x7e\xa0\xd0\x04\xe6\x93\x6c\xc5\x46\x47\xad\xed\x54\x10\xa0\xcc\x01\xfc\x46\xb2\xdb\xff\xb9\x68\xd1\x3f\xf5\xc5\xcf\xbd\x64\xf5\x58\xbc\x5c\xa8\x3b\xb2\x04\xd7\xb7\x56\x8c\x88\xba\xed\xfa\xcb\x2e\xbb\x9e\x31\x31\x04\x9e\x6c\x31\xf0\xe1\xaf\x79\x3e\x54\x0b\xb7\x09\xd9\x62\xcc\xb1\x38\xc5\x05\xcc\x48\x78\x8b\x31\x8b\x4a\x70\x4e\x40\xe4\x4b\xd0\x7c\x72\xa2\x7a\x37\x4e\xd4\xec\x85\x13\xe8\x85\xc0\xc9\x67\xe3\xb4\xe7\x1a\xc7\xc3\xb3\xb5\x06\x33\x34\x9b\x93\x36\x5a\xef\xb6\x3b\xdc\xde\x70\xa4\x9a\xef\x62\xe1\xae\x80\x4d\x71\xc5\x10\x1f\x88\x61\xf7\xd0\x81\xef\xea\xcd\x8a\x20\x8b\x3a\xd8\xde\x23\x1b\x6a\xb5\x83\x33\xe5\xc1\xbe\x83\xdc\x6e\xec\x61\xf7\xf4\x1d\xf3\x2c\xc2\x38\x60\xd0\x6c\x88\xcb\xc0\x0f\x21\x05\xb9\xe8\x70\xe1\x75\x21\xdb\x61\xea\x8b\x3a\x38\xa5\xb6\x65\x72\x43\x38\x73\x5a\xd2\x58\x75\x58\x39\x07\xad\xf5\x48\xaf\x55\x04\x2e\x78\x52\x39\x2f\x4f\x81\xc2\xa9\x5c\x19\x7f\x39\x5c\x46\x8d\x8e\x62\x0c\xe7\x23\x52\xaa\x63\x9b\x56\x03\x9a\x52\x91\x56\x6b\x20\x1b\x72\xe0\x24\x4e\x36\x50\x43\x33\x9f\x58\xf6\xc3\x93\x1d\xc0\xb4\xe6\xa1\xa0\x51\x03\xe1\xd5\x4c\x5a\x1b\x09\x8f\x6b\xd0\xef\x25\x53\xc0\x9e\x0e\x65\x4b\x53\xff\x01\x83\x87\x0c\x27\x1e\x0e\x19\x0c\xcf\x0f\x68\xe4\x15\xcb\xb0\xe1\x38\xf0\x14\xe8\x6c\x68\x4e\x67\xa8\xab\xa4\x68\xac\x06\x9e\xf2\x52\xba\x1a\x56\xb2\xb1\x8a\xfe\xfc\x80\xdb\x6f\x88\xa9\x8e\xbe\x74\x71\x9c\xf5\x57\x22\x2d\x3b\x97\x0b\xa5\xba\x50\x53\xa5\x73\xf6\x15\x7e\xbb\x3b\xfb\xd2\x5f\x51\x68\xd2\x57\x48\x6f\x43\x1c\x45\x2c\x93\xc5\x90\x8d\x30\xde\xb5\x44\x40\xbf\xa2\x14\x4d\x36\xfa\x69\xc3\xd5\x1f\x34\x90\x4c\xc0\x75\x7b\x20\x9c\x78\xa8\xf5\x88\x91\x23\xce\x51\x64\xb0\x81\x6e\xe0\x19\xe1\x06\xbf\x8c\xa8\x38\x50\x00\x16\xd1\xc0\x7a\x89\x9f\x90\x4c\x38\x10\x5a\x7b\x4b\x1b\x82\x97\x24\xbc\x88\x0f\x19\xe6\xc1\x32\x11\x8d\xe0\x30\x1d\x66\x79\x4d\x6b\x97\x0f\xa9\x65\x49\x71\xea\x69\x07\xcd\x38\x62\xce\xb8\xc5\x12\x2b\x11\x45\xbd\xfb\x1f\x1f\xea\x6c\x31\xab\x29\x39\xfb\xf5\x09\x4d\x87\xcf\xb8\x62\xf5\xdc\x41\xbf\x9b\x36\x7b\xc9\xa1\x33\xac\x8f\x3c\xff\xa1\xf4\xe9\x8e\x1d\x94\x55\x08\x96\x75\xb6\x7e\x10\x33\xfc\x42\x58\x28\x16\xc6\xf4\x89\x9d\xe1\xcf\x9b\xa4\x3b\xd2\x03\xa0\x11\x4b\x21\x3d\xbd\x00\x34\x22\x34\xf7\xb7\x27\x80\x46\x82\xe1\xb4\xb6\xd4\x17\x8c\x86\xee\x67\x53\x68\x8a\x7b\xca\x9e\x78\x1a\xb6\x2a\xab\xfe\xe3\xce\xe1\x04\xaa\x61\xae\xb5\x32\xbf\xd6\x71\xfb\xbd\x56\x48\xf3\x7e\xe3\x72\x83\x90\x42\xed\x65\xb9\xa2\xc8\x53\xab\xb7\xf7\x5c\xaf\xb5\x88\xb2\xad\x9d\x07\xc1\x8a\xcd\xf5\xb6\xd3\x7a\x8b\x85\xb2\x5f\xe7\x6d\xac\x87\xb7\xe6\xde\x5b\xc1\x62\x63\x0a\xcf\x97\xf6\x5c\x6c\x6b\x75\xc6\x02\x96\x62\xdb\x1b\x7f\x47\xb1\xd8\x9d\xac\xfc\x8d\xf5\x7f\xb2\xf5\xb1\xe4\xa6\xd8\xd7\xdf\x45\xaf\xb9\x66\x67\xa6\x60\xcd\xb3\x68\xcd\x55\x90\x8b\xfc\xe5\xd7\xd6\x5c\x9d\xe7\x31\x2c\x39\x2a\x77\x75\x26\xa2\x71\x3b\x84\x61\xf4\xcb\xf5\x29\x55\x29\xec\x4f\xe3\xc9\x3e\x7b\x3a\x57\xc2\xb1\x93\x8d\x7c\x12\xca\x18\x6c\x5c\x6b\x55\x8a\xb1\x31\xa3\xc6\x94\x7b\x64\xc9\xeb\x0b\xc5\xab\x6b\x38\xd6\x8d\x86\x68\x81\xbd\x78\x51\x0d\xbc\xa8\x45\xff\xad\x56\x41\xf8\xc2\x99\xd3\xbe\xf8\x42\xd1\xbf\x67\x73\x87\x20\x6a\xf7\xc2\xa2\xe6\xd3\x66\x0f\x7c\xa4\x25\x99\x59\x7f\xda\x9c\x31\x5a\x4b\x55\xf3\xe8\x3e\x38\x35\x73\xfe\x65\x87\x0d\x4f\x35\x2d\xf8\xdd\x61\x23\x9a\x76\xa6\x51\x29\x2d\x06\xbf\x3c\xc4\xaf\x90\x50\x04\xb9\xf5\xc5\xbf\xc6\xb1\x70\x81\x56\xaa\xc5\x19\x84\x7c\x53\x63\x69\x4a\xb6\x95\x6d\xb4\x57\x18\xf2\x53\x29\x5a\x6a\xe7\x88\x89\x21\x05\x9b\xcd\x6e\xaf\xcf\x43\x58\x62\xc5\x8a\x16\x2d\x42\xdc\x07\x88\xd6\x76\x97\x33\x42\x6e\xb7\x80\x37\x02\xed\xfb\xf7\xa9\x27\x89\x30\xaa\x08\x96\xcd\x7d\xf1\xa0\x9a\xb9\x08\xd3\x66\x11\x73\xed\x46\xf9\x88\xad\x5b\x77\x96\x8b\x8c\xbd\xbf\x75\x6b\x9e\xe6\x6b\x89\xe6\x52\xa1\x42\x68\x14\x36\xfe\x1a\xcd\x65\x79\x9a\x63\xf9\x2e\x59\xbf\x14\xd6\x70\x94\xd3\x35\x91\xa2\xf4\xea\x92\xe5\xa2\x3c\xa7\xeb\x8f\x0d\x32\x60\x40\xa7\xe4\xf3\x96\x21\xf9\xb5\x4a\x67\xac\xbc\x22\x84\x97\xd1\x40\xa7\xec\xb0\xc7\x77\x67\x00\x82\xc6\x94\x77\xd0\x01\x0d\x2d\xaa\x74\xec\x5d\x35\x78\x3c\x41\x95\x90\x0a\x6a\xfa\xbe\x58\xf3\xee\x99\xb3\x67\x9e\x71\xc6\xcc\x39\x2b\xd3\xc8\xa0\x23\x07\xf6\xab\x6f\x69\xa9\xef\x37\x70\x37\x36\xbd\x3c\x7d\xf9\xf2\xe9\x87\x1c\x7f\xfc\x8e\x8f\x44\x26\x2e\x6b\x68\x6f\x6f\x68\x1c\xd8\x61\xd6\xff\x82\xed\x36\xa8\x47\xd0\x0f\x3c\xc5\x27\x8a\x54\x21\x43\x07\x13\x02\xc6\xf9\x66\x2d\x08\x49\x1b\x3d\xca\xf9\x0a\x60\x37\xed\xc6\x39\xd2\x9c\x95\x9e\xcc\x45\x62\x01\xe4\x65\x44\xea\xca\x39\xdc\x74\xe9\x90\xf2\xd3\x7f\x76\x67\x17\xa2\x3d\xe3\xf6\xb6\xdf\x06\xc5\x19\x8d\x84\xf8\x02\x10\xc6\xfd\x7e\xd5\x42\x48\xc7\x36\x42\x3a\xb6\xd8\xba\x68\xde\xcf\x8e\x78\x59\xa1\x70\x49\x07\x4d\x26\x67\x1d\x68\x80\x50\xb2\x05\x10\xa2\xcd\xa2\x68\x4e\x17\x8d\xa1\xd1\x59\xdb\x50\x14\xc7\x59\x25\x9c\x22\x29\x33\x79\x8a\x87\x30\x83\x90\x01\x05\xf9\xd6\x57\x1e\x2d\xa9\x76\xe4\xc5\xe2\x6d\xd2\xcf\xef\xb9\xf4\x3f\xf8\xd9\x77\x7a\x44\x61\x67\xbb\xdf\xdd\xf1\xf1\x35\x56\x7d\xda\xf4\x43\x96\xb3\x74\xd4\xb2\x39\x24\x7f\xa1\x5f\x75\x85\x7e\xcd\x47\xfa\x92\x2b\xf4\x35\x9b\x4b\xd7\xdd\xea\xdd\x2c\x8e\x11\xfb\x31\xea\x31\xb6\xe8\x19\xc2\x10\x12\x40\xbf\x06\x08\x57\xf3\x7d\xc2\x5c\x25\xef\xb5\x51\x86\x68\x31\x0f\x99\xf6\x4b\x69\x0d\xe8\x6d\x9a\x53\x2a\xdb\x66\xe0\xf2\x91\xda\xd4\xda\x09\x60\xab\x98\xe3\x85\xc4\x1c\x78\x36\x55\x4b\x63\x2f\x1a\x68\xe8\x4c\x54\xf6\x6b\xe0\xfa\xb4\xc5\x12\x8e\x7b\xab\x68\x97\xac\x18\x7c\x4d\x11\x92\x1c\x6f\xc0\xb7\x54\xd5\x22\xae\x96\xe6\xad\x04\xfa\x1d\x15\xc4\x24\x4b\x3e\x19\xdc\x37\x02\x11\xdb\xad\x8a\xfa\x15\x44\x22\xb6\xa3\xa0\xca\xda\x37\x3c\x51\xf7\x0f\xbd\x8a\x30\x89\x63\x00\x41\x0c\x0f\x41\x54\x8c\x09\x7f\xfb\x35\x1c\xa0\x30\xa1\xdb\xed\x37\x18\x50\xc9\x6f\x00\x03\x2a\x45\xbd\x13\xc1\xec\x22\x51\x42\xdb\xe8\x54\x8a\x8a\x31\x99\x56\xed\x81\xdf\x84\x0c\x94\xa0\xc3\x5d\x7b\xe2\x03\xed\x38\xef\x53\x4a\x15\xf6\xc0\x09\xa2\x44\x41\xc8\xf3\xa2\xd2\xe0\xc5\xe6\xff\x53\x5e\xa8\x91\xd4\xff\x8c\x1d\xd8\x05\x41\x66\x44\xf7\xc6\x0c\xc7\x3e\x99\x41\xc9\x48\x5f\xcc\x60\x7f\xe2\x99\xc8\x1e\xec\x30\xf2\x90\x3c\x3f\xda\x89\x1f\x71\xdc\x6f\xff\x3f\xd5\x8d\xf2\xdf\xc0\x8c\x0a\x83\x19\xd9\x48\x94\x76\x38\x1c\x4a\x0e\xb4\xa3\xb4\x8c\x73\xa4\xd3\xe3\x8d\xf1\xa2\x74\x7f\x35\xc4\x4c\x7a\xfa\x62\xcc\x5b\x66\xc2\xb3\x27\x67\x8c\x74\x07\xf3\x49\xce\x1b\x0f\xf1\x06\xfd\xf2\xf3\xff\xd7\xda\xa2\xc6\x32\x78\xbe\x4e\x2d\x49\x9b\x08\x47\xc0\x2a\x70\x30\xe9\x3e\x98\x15\xb1\xd3\xbf\xd8\x9d\x6d\x9d\x65\x76\x07\xa4\x53\x31\x3b\x46\x4e\xad\xcc\xce\xbd\xb6\x43\xe4\xa7\xba\xca\x94\xdf\xa6\x49\xe6\xd6\x61\x5f\x3c\x7b\x88\xb6\x13\xf7\x64\xd8\x08\x73\x7f\x71\xd7\xb7\x88\x71\x64\xab\x07\xce\x59\x04\x05\xb1\xdd\xf2\x67\x0e\x10\x8b\x0b\x79\x93\x07\x1c\xf2\xd0\x90\x1f\xb6\x5b\xa9\x47\x68\x37\x87\x7d\xf1\x9d\x76\x9f\x09\x34\x84\xa5\x10\x82\xc4\xf8\xec\x18\x5f\x64\xa9\x83\xba\x36\x12\xda\x3e\x2b\x84\x3f\xf2\x92\xd1\xeb\xba\x01\x83\x64\x4b\x82\xb1\xff\xfc\x41\x2f\x34\x24\xb4\x7d\xc4\x60\xba\xd9\x96\x10\x5c\x82\x1b\xd6\x37\xab\x37\x0e\x93\x3b\x1f\x33\x38\x18\x13\x54\xc6\x26\x2c\xd8\xaf\xe1\x31\x05\x0d\x8e\x6b\x5e\x85\x16\x58\xb8\xb4\x04\x35\x5b\x8d\x85\x75\xdf\xba\xb4\xd0\x20\xf9\xd2\xac\x51\xc3\x16\x77\xfd\x1b\xd6\xf7\x8c\xad\x4d\xb0\x0b\x0e\xd0\xb8\x59\x05\x98\x09\xa1\x34\xed\x32\x65\x7d\x22\x3f\x01\xa8\x2a\xfc\x84\xb6\x7b\x1b\x87\xb9\x72\x17\xc2\x5c\xb9\xe9\xbc\xb6\xdb\x4b\x4b\xa5\xc9\xe2\xa0\x1b\x0f\x9b\x5b\x25\x9a\xc5\xc5\x43\x97\x66\x3d\x50\xb8\xd2\x98\x69\x13\xf7\x1b\xab\xb5\x36\x72\x53\xf8\xf9\xd5\x5e\x9c\x94\x77\x3d\x03\xeb\x7c\xda\xe6\xa6\xbd\x34\xcc\x6a\x4f\x10\x48\xba\x74\x24\xc6\x97\xe6\xe8\xa8\x4e\xd1\x68\xa8\xba\xf1\xb8\x09\x01\xe4\x48\x7c\xf0\x3d\x5c\xb8\x73\x6d\x73\x71\x08\x20\x2f\xe1\x27\x78\xdd\x84\xf6\x93\xb5\x79\xf3\x10\xd2\x96\x74\xa7\xe2\xb5\x61\xc1\x00\xaa\x1d\xe1\xe7\x7b\x30\x4d\x2d\x5c\x39\x3e\x31\x90\xb9\xfe\x69\xac\x7b\x1b\x73\x59\x87\x6f\xdd\xfa\xf3\xa3\xbd\xb8\x3c\x1c\x95\x54\x14\xfa\x43\x6e\x3a\x9e\x30\x11\xca\xf1\x6c\x25\xcd\xea\x07\xf0\xf4\x27\x01\xf8\xc9\xdc\x6a\xf9\xf4\xbe\x69\xb2\x4c\xf0\xe0\x54\x51\x3c\x83\x9d\x52\xec\xa5\x94\xf2\xbb\xc2\xf8\x69\xcf\x05\xf3\x89\x12\x48\xcb\xc8\x5e\x03\x88\x73\xe4\xa7\x49\x23\xbf\xc0\x87\x89\x4c\x28\x99\x04\x56\x6b\x01\x5f\x7e\xa8\x2f\x83\xcb\xe7\x08\x39\xf5\x0c\x27\xf3\xf3\x10\x7f\xd8\xb7\xe8\xff\xc4\x7a\xf1\x2a\x13\xe5\xaf\x7b\xf9\x7a\x56\xc5\x91\xfe\xb6\x6d\x13\xff\xb8\x9e\xfd\xad\x00\xec\x6f\x73\x9c\x6d\xd5\xc7\x12\xe2\x9f\xbe\x68\xbd\x89\x2d\x69\xb5\x43\x8d\x16\x85\x7a\xa3\x51\xf8\x74\x0f\x8c\xa2\x22\x53\xd5\x0b\x81\x8a\xd4\x1a\xa8\x28\xa1\x3c\xab\x2f\xaf\x01\x6e\x97\x62\xc2\xd4\xb4\x3f\xc8\x45\x6a\x23\xde\x66\xc5\xbc\x3d\x4e\x2a\xd7\xc8\xaf\x7e\x0d\xd2\xa8\x33\xa9\x80\xdf\xca\x55\xf2\x77\x57\xa6\x72\xc9\x9e\x74\xbe\x11\x3b\x6b\x41\x6c\x38\x56\x2a\x5a\x29\xf6\x83\x92\x01\xcd\x1e\xe8\xe8\x8d\x7a\xa4\xd5\x60\xcf\xb2\xb1\x43\x2d\x57\xd4\xe2\x7d\x60\x20\xf5\x59\xe6\xf5\x05\x8c\xd4\x7d\x2b\x9b\xb5\x5b\x95\xb7\x37\xac\xa4\x5e\xa5\x1e\xf5\x1e\x08\x37\x09\x7c\x9f\x20\x78\xa1\xe6\x49\x08\x13\x8c\x3d\xbc\x80\x11\x2b\xb8\x6b\x31\xf1\xfb\x58\x1e\x06\x12\x8f\x2b\x39\x8c\xe3\xd2\xb8\x9f\x98\xb3\xb8\xcb\x2a\x12\x14\xe8\x8a\x03\x66\x41\xaf\xec\x03\x4d\x89\x32\xa1\x7d\x40\x2a\x79\xc8\x37\xfe\x2a\xb0\x92\x7c\x00\x26\x48\x26\x1d\x89\x3c\x1d\x93\xf7\x46\x07\x94\xa3\xff\xd7\xa4\x90\xab\xdc\x07\x29\x8f\x72\xe7\xf9\xab\xb4\x48\x69\x73\x4f\xcb\xa4\xa7\xcd\xa0\xa7\x5a\x38\x64\xef\x72\xa9\xe9\x8b\x98\x5a\x83\x98\x2d\x48\x4c\x92\xee\x04\xe4\x50\xb4\x04\xa1\xe8\xee\xa7\x80\x4c\x6f\xbb\x0f\xca\x98\xe9\x7b\x7f\x9d\xb6\xb1\x3d\xf9\x09\xa7\x6d\x26\xd1\x56\x09\x55\xd0\xe9\x06\x6d\x35\xbd\x68\x6b\x02\x59\x95\xd2\xb9\xa3\xce\xf2\x70\xa9\xdd\xd8\xce\xe2\xc5\x50\xd2\xd2\xd5\xe9\x4b\xb2\x1e\x43\x4c\xf2\xd9\x83\x9e\xbb\x5d\xd5\x1b\x7c\xc0\xb2\xa8\x08\xca\x9c\x2d\xee\x80\xa5\xb4\xa6\x89\xa4\x1a\x2e\xa5\x0d\xdd\x3d\xe9\xef\xc3\xe0\xa4\x5f\x81\x00\x0b\xee\x66\x79\x97\xee\x1d\x12\x4c\x7e\xae\xb0\xcf\x72\xe3\xee\x40\x54\x16\x83\x2f\x6e\xe2\x4b\x00\xea\xc3\x2a\xe1\x24\x83\x33\x91\x5e\x9c\x29\x93\xf0\x8c\xa9\x9a\xc8\x60\x46\xa7\x56\xf2\x71\x51\x46\x21\xb5\xd3\x17\x64\xc8\x2a\x88\x52\x41\xde\x6c\x01\x26\x74\x56\x39\x8a\xe1\xc9\x84\x9d\x60\x75\xab\xec\x7c\x1c\x34\x81\xe0\x73\x16\x77\xa4\x8c\x78\x52\x86\x2d\xc3\x8a\x3e\x78\x82\x41\xab\x17\x0f\xf0\x99\x3d\xf9\x60\x63\xae\x2f\xf3\x5a\xf1\x1a\x73\xf5\x41\x7e\xe7\xd6\xad\x3b\xaf\xe8\xad\x14\x73\x20\xb8\x31\x61\xa8\xf0\xa2\xf4\x9d\x7c\x05\xe4\x37\x42\xd0\xc1\xda\x1d\xb8\x11\x61\x73\x40\xa5\xd8\xaa\x3f\xbf\x89\x0d\x60\x03\x36\xe9\xcf\xb3\xd6\x4d\xfa\x4b\xfa\x4b\xec\x64\x36\x98\x0d\xbe\x45\x7f\x8e\xb5\xdd\xa2\x3f\xa5\x3f\x75\x0b\x6b\xd3\x9f\xc3\xd8\x71\xd0\xae\x9b\x2c\xcb\x2c\x5f\x42\xbe\x5b\x2d\x34\xe3\xce\x28\x6d\xff\xd6\x9b\x68\x64\x95\x68\x28\x69\x8a\xe0\xb8\xeb\x1b\xa3\xc9\x14\x8c\xe0\x5a\x06\xd1\xc8\x04\x7e\x97\x81\x46\x65\x8b\x5d\x0e\x29\xe5\xd4\x9e\xf3\x06\x34\x27\x0d\xd1\xd7\x63\x03\x0f\x9b\x04\xe8\xd6\xe3\xcd\x04\xd6\x4b\xdb\x2c\x26\x04\x29\x1e\xda\xb2\x45\x02\x65\x0c\x1e\x10\x14\x44\x7b\x0d\x1e\xdc\x2a\x67\x8c\x2a\xe8\x70\x10\x27\xb1\x91\x7f\x35\x29\x76\x10\x72\x6e\xfa\x75\xa3\x47\xae\x39\x76\xe5\x45\xc8\xbd\xf9\x77\x8c\x3d\x7c\xcd\x65\xc7\x9f\xca\xaa\x2a\x93\x56\xf6\x46\xed\xdc\x96\x7b\xb7\xac\xaf\x3f\x66\xc4\x7d\xf7\x0f\xe8\x6f\x35\xb8\x58\x9d\x5c\xbe\x65\x91\xfe\xec\xfd\xc4\xc9\xa6\xc6\x3f\x7f\x75\x14\xab\xd3\x8e\xba\x73\x30\x93\x1a\xa3\xc8\x47\x7d\x40\xb2\x0a\xb9\xba\xec\xc1\x03\x18\xf0\x82\x30\xa1\xa0\x6e\x16\xc8\x13\x5e\x6a\xcc\x94\x9a\x58\x8d\x7c\x37\x53\x31\x3a\x5a\xfe\x20\x1d\xd5\xa8\xa4\x0d\x71\x3b\x44\x3d\x3b\xc1\x92\xe2\x01\xda\x6c\x09\xa5\xb7\x25\xb8\xe9\x64\xf7\x6b\x5e\x8e\xea\x95\x0d\x7b\xcd\x53\xa9\x26\xd6\xa1\xdf\x00\x6f\xb5\xe3\x3e\x78\x59\x1c\xf7\x41\x94\xce\xa2\x72\xc3\x87\x32\x44\xb7\x0a\x95\x76\x70\xdd\xda\x3b\x54\x14\x05\x84\xbe\xf1\xa2\x3e\xe1\x68\x28\x7b\x47\x8d\x12\x47\x72\xa0\x14\x93\xf6\x4a\x83\xf6\x2b\x7e\x9d\x76\x33\x1e\xfc\xef\xc9\xf7\x42\xb6\xdf\x59\x54\x16\x4f\x18\x77\xb0\x28\xaf\xe8\xf8\x0d\xe4\x53\x31\xdc\x37\xf9\xec\x3a\x1e\x40\xf6\xc1\x00\xd6\x66\x86\x8e\x3c\x0f\xda\x89\x07\xd5\xc2\xef\xf7\x47\xfe\x35\xff\x5b\x06\xd4\xee\x26\xff\x1c\xc8\x9f\x87\x9d\x70\xc0\x08\x3b\xfb\xad\x08\x66\xe0\xe9\x9b\x1b\x6f\x98\x31\x67\x5f\xec\x98\x60\x46\x1b\x8c\x37\x9c\x1f\x1e\xe2\x07\x7a\xd5\x8d\xfb\xa5\x15\xe8\x5f\xe3\x3d\xfe\xd5\x60\x4f\x0f\x4f\xa0\x82\x2d\x01\xaf\x5a\x61\xc7\x11\xa7\x5f\x65\x50\x67\x55\xd8\xdb\x87\x0f\xae\x00\x96\x14\xb9\x7e\x1b\x77\x78\xa9\xdb\x37\x73\x1e\xa0\x62\x77\x5f\x9c\x39\xdc\x28\x7b\x41\x4f\x08\x57\x8b\x6c\x25\xc2\xf1\x3f\x0a\xcf\x83\xf6\x30\xc6\xc9\x19\x23\xf3\x43\x54\xd1\x14\xed\xd0\xef\xf3\x54\x68\x99\x71\x2a\xf4\x1e\xd9\x6a\x73\x38\xa5\x22\xde\x00\x61\x41\x1c\x3b\x8b\x18\x14\xf6\x01\xb4\xe5\x20\x1b\xe8\x03\x6d\x8b\xad\xec\x31\x80\x3e\x51\xb7\x58\x23\x57\x7f\x51\x18\x05\x02\xff\x85\xb0\xc2\xe2\xbd\x50\xb5\x43\x05\x88\xc5\xf6\x74\x2e\x10\x21\x8c\x66\xc8\xa6\x72\xce\x38\x5d\x3a\x7b\xfa\x3e\x41\x3c\xcb\x12\x49\xa7\xb3\x41\x2a\x1f\x82\x76\x5e\x9f\x8a\xc1\xc2\xd6\x46\x90\x43\x06\x79\xf9\x8d\x1b\xa0\x44\x32\x3a\x15\x71\x0c\xa4\xde\x0e\x4d\xde\x0d\x55\x1b\xe4\x19\xa6\x9b\x36\xc8\x0d\x2c\x5c\x00\xd4\x38\x6a\xc3\x06\xf6\xe8\x86\x0d\xef\xe8\xac\x54\xff\x58\x7f\x07\xae\xce\x84\xff\xde\x31\x6b\xc0\xe1\x3f\x3d\xf3\xec\x4f\x87\xc4\x37\x8b\xe2\xb9\x87\x1f\x7e\x3e\x3f\x2f\x80\xfa\x6c\xb5\x56\x0b\xf5\xc2\x25\x86\xcc\x8a\x0b\x3a\x3b\xa0\xac\x1c\xaa\xa5\x1f\x11\x53\x8f\x67\x48\xea\xf3\xb5\x4f\xbd\x5f\xab\xc4\xac\xc0\xd9\xa5\x3a\x8c\xbb\xbc\xe0\xad\x28\xcb\xe9\x2e\x2f\x9d\xa5\x8e\x4a\x3b\x8d\x3f\xd1\x11\xd9\xf2\x7a\x70\x68\xd6\x48\x98\xcc\xd8\xad\x68\x01\xc2\x19\x60\x3c\x58\x6a\xd5\xc5\x58\x9c\x3b\x7c\x91\x3c\x78\x2d\x8e\xb0\xe3\xde\x43\x38\x24\xf0\x1d\x08\xe3\xec\x5c\x6b\x8b\xd0\xda\x62\x6e\x7c\x23\x24\xa0\xf8\xde\x96\x2f\x8e\x65\x0d\xff\x7e\x63\xd2\xb5\xd5\x6d\x55\xc7\x0d\x99\x78\xa8\xfe\xea\x09\x53\xc6\x4c\x9c\xbf\x39\x2e\x9d\xf7\xe1\x8f\x8f\xa8\xc7\x3f\x31\x7a\xa0\xfe\xc9\xe5\x0f\x3d\x18\x8f\xbd\x17\x49\x4c\x1c\x31\x96\x79\xae\x9c\xfd\xcc\x84\xb1\x87\xfd\xee\xd4\x1d\xf7\x98\xf3\xac\xf2\x08\xcb\xbf\xe1\xba\x0a\xf8\xd0\x22\xdc\x28\x64\x2b\x05\x9e\x35\x72\x10\x98\x98\xd1\xe3\xca\x06\x98\x09\xc0\x46\xf5\xad\xc3\xe3\x68\xc8\xa5\xe5\xca\x00\xc8\x3c\x8d\x19\x65\x2b\xe5\x4e\x78\xab\x1b\x4f\x5a\xed\x07\x66\x8c\xd3\x25\x29\xbc\x1a\xc0\xb0\x8e\xc7\x83\x36\x5a\x1b\x02\x63\xe1\x04\x4e\x35\x96\x75\x03\x10\xca\xb2\xb2\xb6\x9e\x1f\x3a\xc9\x96\x96\xd7\xd1\xce\x76\x0c\xfd\x5f\x55\x39\xbc\x21\xad\x64\x23\xac\x05\x8b\x3d\x87\x4c\xdc\x42\x95\xdf\x0f\xa4\x2c\x8a\x81\xd2\xfe\xc2\x65\x5d\x4d\x61\xf1\x9c\xfd\xc1\xcc\xb2\x1c\x84\x1b\xce\x73\x4d\xe4\x2c\x93\x7f\xef\x12\xff\x52\xc0\xbf\x3f\x19\xfc\xab\xdb\x2f\xfe\x35\x71\xfe\x35\xf5\xf0\xaf\x9a\xf3\xaf\x3a\xcf\x3f\xb8\x6a\xe8\xcd\xbf\x86\x6a\x4a\xc3\x2b\x07\x34\xb7\x10\xe3\x94\xce\xd2\xf2\x34\x9f\x99\xef\xe1\x5c\x13\x72\x2e\xf5\xdb\x39\x57\x80\x31\x46\xe5\xd8\xfe\x02\x8d\x25\xb8\x67\xd9\x0f\xbc\x31\xe9\x70\xee\x63\x4c\xde\x7d\x47\xbc\x6b\x12\x06\x0a\x37\x1b\xbc\x6b\xde\x2f\xde\xb5\x71\xde\xb5\x21\xef\x3a\x88\x77\xfd\x39\xef\xfa\xe7\x79\xc7\xef\x64\x6a\xf2\x0e\x6f\xa4\xd2\x3f\xaf\x7b\x2d\x0a\xf2\xb0\xb6\xae\xd1\x38\xf1\x54\x5a\x5e\xdf\xb0\x1b\x0f\xdb\x90\x87\x03\xff\x07\xda\x97\xef\xaf\xed\xaf\x06\x5e\x68\xc6\xe2\xb6\xfd\x51\x42\x79\xaa\xb1\x25\x3f\x65\x37\x3d\xb4\x86\x89\x97\x03\xc1\x7b\xbf\x65\xf0\x72\xc8\x7e\xf1\x72\x04\xe7\xe5\x08\xf0\x7a\x69\xda\x2d\xeb\x6c\x6d\x48\x83\x07\xab\x43\xe6\x8e\x26\xe6\x76\x70\xe6\x76\xe4\x99\xdb\xe1\xcf\x55\xf3\x32\xb1\x1a\x1f\x68\xc3\xf2\x9c\xee\x4c\x45\x86\xd9\xe9\x76\xb2\xf8\x6a\xff\x54\x2e\xd5\x73\xcf\x9a\x61\xa0\xbc\xb9\x40\x65\x43\xeb\x40\xdc\x38\xeb\x8f\x9b\xb2\xa5\xe9\xde\x46\x3f\x02\xd9\x3e\xaa\x80\xed\x6a\x00\xc7\x41\xb5\x86\x34\x3c\xaa\xde\x6f\x21\xf4\xb5\xb9\xbf\xbf\xf2\x38\x79\xb7\x6a\x34\xbc\x5f\x62\x39\xab\xb0\x2e\x9d\x6c\xca\xc6\x62\xe8\xf9\xb3\x24\x9b\x3a\x21\x23\xb4\xe3\x4e\x02\x49\xa7\x71\xbf\xa4\xd3\xcc\xa5\xd3\x4c\x31\x49\x6d\xc9\x60\x81\xaf\xb6\x42\x3a\x35\x10\xdc\xc3\x36\xad\x0e\x72\xa1\x3a\xbf\x5a\x8f\x31\x88\x23\x39\x62\xb0\x42\x61\xd5\xe7\x85\x55\xe7\xc7\x3b\x1e\x1b\xf2\x51\x5b\xf0\xad\xed\x90\x3b\xe1\xe0\x56\x5d\x35\xce\x55\x54\x92\x49\xc0\xb7\x36\xe2\xde\x4b\x3b\x48\xa5\xbc\xb7\x54\x9a\x51\x2a\x99\x3d\xa4\xb2\xdf\x26\x81\xe5\x6f\x9e\xfb\x58\xfb\xee\x5b\x02\x47\x33\xd7\x94\x3c\xd3\x07\x32\xd7\x3e\x19\xbf\x08\x2a\xe2\xc1\x86\x77\xb9\x18\xb3\x32\x83\xe7\xd6\xa9\xc4\xf3\x01\xc2\x60\x61\xac\xf0\xae\xc1\xf3\x96\xfd\xe2\x79\x07\xe7\x79\x07\xf0\x1c\x14\x78\x18\x9f\x48\x38\x30\x95\xab\x33\x26\x12\x0e\x22\xa3\x68\xe6\x7c\x6e\x36\xf9\xdc\x59\xdd\x8c\xcd\x94\x21\x5c\xf3\xe1\xe9\xf6\x1e\xa6\x8f\xc4\x3e\x69\x03\xb7\x84\x71\xc0\xf7\x21\x5e\x93\xef\x23\x95\x9c\x23\xd0\xbf\x85\x10\x34\x1a\xf6\xe4\x7c\x07\x72\x7e\xf0\x9e\xf6\x70\xe0\x30\x48\x1c\xaa\x1b\xc6\xf2\xe3\x51\xfb\x25\x86\x5e\x63\x0d\x3d\xe2\x28\x3c\x9c\xf9\x2b\x0e\xbf\xc2\x1c\x74\x90\x4c\xe9\x2c\x33\x87\x1d\xf6\x29\xa2\x1f\xcc\xd1\x87\x5d\x5c\x4e\x72\x91\x39\xfe\x20\x09\xe3\x76\x6d\xb7\xde\x21\x4f\x16\xfa\x0b\x1d\xc2\x48\xe1\x2e\x21\x5b\x83\xfd\xea\xc6\x0c\x1e\xfb\xa5\x6b\x2d\x8d\x33\x73\x8c\xc3\x89\xdb\x41\xf9\x87\xa7\x73\x83\x4b\x6a\xfc\x9e\x06\xb5\x2d\xa3\x0d\x96\xbb\x08\x39\x7a\x14\xb5\x25\x52\xc0\xea\x94\x1f\x03\x25\x1e\x74\x2c\x85\x47\x83\xe8\x66\x03\x43\x80\xe5\xc5\xce\x2e\x6d\x34\xfc\x4d\xe5\x0f\x54\xb5\xe1\x81\x2a\x52\xf9\xd2\x80\x16\xac\x87\xbf\x43\x94\xce\x92\x08\xef\x5c\x14\x07\xb4\xca\x24\xca\x62\x70\x0d\x8e\xda\x55\xd6\x17\xa0\xac\xab\xfe\x00\xc7\x16\x2c\x38\x61\x55\x4d\xb7\xe5\xe4\xf0\x50\xbb\x43\x0d\xd6\xec\x11\x5e\xf3\xd8\x83\xe3\xf4\xef\xb6\x4c\x1b\x3f\x75\x2e\xde\xb0\x53\xd8\xf5\xea\xe2\x3b\x06\x0f\xfd\xf3\x91\xaf\x7e\xdb\xbd\x42\x94\xcf\x3a\x6b\xee\x59\x93\x27\x1d\xb0\xed\x9c\x55\xcf\x8e\x1a\xf2\xfc\x65\x8f\xbe\xcc\xaa\xa6\x4f\x1b\x74\x4e\x75\xe7\xc2\xa5\xa2\x26\xb2\x63\x67\x4c\x3f\x7c\x3e\x1b\xba\xf1\xaf\x83\xa7\xcc\x99\x30\x30\x60\x5d\xf3\x60\x7b\x4b\x4b\xbb\xfe\xd3\x87\x37\x58\x97\x5d\x58\x57\x7f\xef\x80\x71\x53\x27\x8e\x9e\xb5\xe5\x8f\x83\x0f\x1c\xda\x4f\x9d\xc9\x14\x4b\xe9\xfc\x13\xcf\xe4\x35\xcb\x28\x3d\x43\xb8\x98\x82\x50\x0e\x79\xcb\x45\xfc\x3e\x4c\x38\x49\xdb\x33\x3f\xc1\xcc\x03\xd6\x04\x96\xe0\xc5\xfd\xb8\x7a\xba\x63\x19\x1d\x2c\xee\x19\xa5\xc0\x23\x6a\x35\x76\x7e\x6b\xc3\x26\x9c\x9c\xa8\x48\xd4\xf7\x43\xfe\xd5\x28\xf7\x38\x2d\xde\x70\x59\x51\x92\xdf\x59\xbd\x0c\xef\xb3\x5e\x91\xa4\xee\xa1\xe6\x4d\xc0\x83\xf2\x70\x11\xed\x78\xf7\x0c\x4d\xec\x0d\x59\x13\x0f\xf3\xed\x31\x33\xd1\x37\xcc\xa6\xac\x23\xcc\x26\x2b\x1c\x4b\xef\x13\x73\xf3\x96\x77\x58\x5a\x9f\xd5\x6b\x56\x42\xe6\x58\x94\x96\x4f\x81\x03\x51\xaa\xfa\x67\x1a\x77\x80\xf4\xe6\x3b\x87\xc8\x96\x24\xd4\x3b\x71\x67\x18\xeb\x9d\xb8\x31\x60\x5c\x4e\xc3\x35\xd9\x72\xaa\x6b\xcb\x99\x59\xca\x97\x23\x40\x13\x6d\x5d\x78\xc3\x74\xf3\x30\x04\x30\x52\x4c\x5a\xa3\x7b\x42\x52\xf2\xd4\xb5\x07\x97\xd2\xf1\xde\x9e\xa0\x94\x2b\x28\x61\x9d\x59\x80\x4c\x09\x2e\xb2\x37\x34\xa5\xfc\x1c\x24\xaa\xdd\x9b\x0d\x7c\x4a\x93\xae\xf7\xf2\x74\xcd\xf9\xdf\xd3\xd5\xa9\x04\x8c\x2d\xf9\xfd\x24\x8d\x0f\x4d\xee\x9b\x34\x56\xcf\x13\xc9\x4f\xf6\x45\x9c\xf4\x30\xa5\x90\xdd\xf7\x18\xe4\xe5\xe9\xfb\x9e\xe8\xab\x80\x4a\xa6\x6f\xfa\x6a\x81\xbe\x4a\x4e\x5f\xa5\xcc\x4b\xbb\x24\xa7\x2f\x49\xf4\x25\x91\x3e\x2c\xd9\xec\x49\xa2\xaf\xb4\xec\xb7\xd0\xd7\x93\xf7\xed\x9b\xc6\x63\xcd\x6c\xcf\xbf\x4f\x22\xff\xc9\xb3\xbc\xee\x9b\x39\x95\x16\x83\xc6\xe7\x88\xc6\x12\xca\x25\xd6\xf6\x49\x65\x25\x50\x59\xc6\xa9\x2c\x03\xdf\x58\x04\x59\x42\x86\xb6\x6c\x6a\xd2\x34\x73\x59\xb4\x8d\x10\x3a\x4a\x38\x9a\x1e\xa6\x0f\x71\x4c\x08\x90\x0d\x71\x62\x43\x9c\x19\x33\x97\x25\x45\x50\x6a\x38\xdd\xae\x2a\x3e\x86\x51\xad\x64\xbd\xe1\x4a\x8c\x44\xf6\xba\xbc\x5e\x3b\xbd\x1c\xd3\xb3\x12\xc7\xea\xaa\xf6\xc9\x1e\xc8\x01\x4c\xce\xf0\xee\x77\x5f\xdc\x99\xc4\x5c\xfd\x4c\xbe\xd8\x21\xf0\xf7\xc9\x9b\x4f\xb7\x6e\xed\xbe\x92\xf8\x22\x7a\x20\xe0\xe3\x69\x69\xbc\xbf\xd2\x67\xd4\xff\xf7\x21\xb6\x13\x3f\x41\xc7\xf7\xf6\x89\x35\x26\x6a\x23\x1d\x74\xf1\x6e\xcb\xe3\x39\x79\xf3\x70\xe2\x5e\xda\xa8\xf4\x5a\x1d\xc6\x56\x34\x9d\x83\x71\x60\x98\x96\x2c\x79\xf4\x62\x87\x8f\x37\x5e\xc8\x4c\xf3\x58\x88\x36\xb2\xc8\x97\x39\xc8\xa5\xe5\x43\xb0\x3d\xfd\xaf\x79\x9c\x4b\xf4\xb7\x63\x60\x7d\xf7\x58\xde\xa7\xfb\x7c\xfa\x84\x79\x42\xd6\x86\xeb\xb3\xcb\xfc\x5c\x1f\xf5\x88\x18\xef\x3b\xd0\xfa\x1c\x1c\xc8\x49\xa6\x15\xc9\xd8\x44\x74\xd0\xc9\x05\x07\x36\xcc\x68\x0c\x81\x16\x47\x37\xad\x72\xfb\xa8\x9d\x80\xf7\x31\x96\x1d\x66\x57\xc8\x58\x97\x84\x26\x37\x86\x2f\xcb\xb0\xac\x42\x00\xce\x63\x8d\x6e\xa7\xb4\x6b\x07\xac\xef\x1d\xcb\x0f\x34\x7b\x10\x14\xe6\x1b\xf7\xf9\x56\xe8\xde\x50\x7c\xf6\xc0\xc5\xf8\xec\x06\xdd\xf1\x39\x40\x13\xeb\x59\x4f\xc0\xbc\xab\x41\x36\x40\x50\xc3\x01\x27\xae\x2f\xe0\xe7\xb7\x7b\xd6\x3c\x81\x82\xc1\x03\xcd\xa9\xd0\xbd\x39\x0a\x07\x10\x7a\xd0\x24\x2d\xa6\x51\xbc\x68\x2c\x57\xde\xce\xf5\x7f\x47\xb8\x60\xc5\x68\xeb\xbb\xde\x81\xb5\xbe\x6d\x79\x9e\xe6\x0f\x70\x87\xe7\x0c\x03\x0b\xd0\x4d\x90\x9c\x3d\x77\x67\x45\x10\x25\x1c\x3e\xf0\xf1\xe1\x03\x7f\x9a\x4e\x71\x79\x8c\xfe\xac\xc7\x9c\x32\xc9\x7a\x48\xe9\x3d\x16\x5c\xba\x07\xf7\xa6\x25\xbb\x07\x8a\x1f\xc1\x4e\xa8\xaf\x92\xbd\xab\xd3\x47\x4f\x04\x20\xc8\xd1\x99\x2e\x8b\xdb\x80\x01\xa2\x51\x84\x1e\x1a\x50\xc3\x93\xcc\xf5\x99\x41\xc1\x57\xcc\x25\xef\xda\xba\x15\x32\xa8\x02\x96\xff\x9e\xcf\x21\x0c\x81\xfc\xf4\x2c\xcb\x17\xe0\xab\x9a\x70\x4f\x92\x50\x4e\xaa\x60\x91\x0d\x04\x5f\xc3\x20\xe9\xc4\x64\x86\xee\xe0\xc8\x0f\x85\x97\x40\x05\x9b\xc2\xa1\x45\x88\x9b\x39\xc9\x6d\x0b\xc5\x69\xf6\x59\xd1\xc2\x04\xdc\xd2\x50\xc5\xef\xab\x2d\xe1\x04\xa7\x79\xd8\x0c\x77\x54\x20\xf5\xb3\xd5\xe2\xef\xf6\x38\x43\x60\x0e\xbe\xbf\x52\x00\x7c\x48\x81\x76\x08\x73\x7f\x3a\xe1\xe2\xb4\x1c\x9a\xdc\xfa\xe9\xe4\x87\x93\xe3\xaa\xe7\xce\xd8\x30\xfa\xa5\x49\xda\x09\xa7\xeb\x4f\x6d\xff\x52\x7f\x95\x25\x2f\x39\xe9\xd4\x4b\x2a\x57\xcd\x3c\xe3\x42\xf6\xea\x87\x4c\x69\xac\x95\x27\x9c\xdf\x7a\xde\xf2\x63\x82\xe5\x9e\x37\xc3\x63\x9a\x4f\x59\xbe\xf0\x54\xfd\xa9\x87\x26\xea\x3f\xe8\x77\xb1\xe2\x97\x4e\xfc\xd3\x6b\xb7\x4f\xae\x6b\xb9\x81\xe7\x1a\x84\x55\x49\xb5\x69\x5c\x48\x0b\xff\xe2\xe8\xc2\x78\x92\xb0\x14\x32\x70\xb7\xaf\x18\x67\x81\x7b\x4c\x14\xf1\xb9\x4d\x5b\x50\x1b\x53\x5a\x35\x54\xa3\xa9\xea\x46\xbb\xe1\xb2\x33\x29\xb5\x8c\xee\xb8\x9c\x2d\xa2\x63\x2a\x45\x31\x90\x60\x19\x9d\xa7\x28\x2b\x01\xd9\x95\x17\x95\xd9\xf3\x87\xa7\x8b\xfc\x78\xaf\x5c\xb5\x2e\xcd\xef\x9a\x45\x33\x1a\x2e\xbc\xa3\x9f\xdf\x65\xde\xd7\x4c\xf5\xfb\x73\xf5\x3c\x2b\x6f\xc1\x3d\x4e\xf0\x62\x9d\xb2\x54\x99\xaa\x22\x68\xb4\x4e\x5b\xa8\xba\x91\x94\x37\x84\xc0\x97\xae\x32\x7e\x38\x51\xee\xd0\x1a\x71\xc4\x2a\x4d\x18\xa2\xe5\x86\xcd\xed\x03\xf0\xb2\xaf\x6a\xb4\x6f\x10\xcc\xdd\x07\xcd\xf7\x05\x8a\xc9\xee\xe8\x3d\x86\x00\xf6\x40\x18\x99\xe4\x07\xbd\x84\xe5\x3e\xde\xf0\x84\xd1\x5e\x11\x22\xde\x33\x87\x50\x70\x53\x21\x73\xf3\x1e\xef\x0f\xaa\xf9\xfc\x34\x69\xdf\xe9\x56\x2c\x01\x3e\x36\x64\x64\x67\x26\x70\x66\x41\x8f\xad\x4f\xf4\xcc\x0d\xe4\x12\x2f\xde\x0b\x84\xa6\xfc\x24\xe6\x27\x2d\x05\x40\x9a\xe6\xda\xdf\xcf\xcf\x1e\x4c\xdf\x63\xaf\x9e\xed\xdf\x0c\x85\xdb\x62\xec\x1e\x39\xcc\xdd\xa3\xc2\xad\xfa\xbd\xa3\x7f\x52\xc7\x6b\x2f\x10\xa0\x0d\xc6\xf0\xc1\xde\x90\x40\xc5\xcd\x86\x2f\x35\xe9\xf8\x81\xe8\x40\x4c\x50\x93\x8e\x92\xdd\xa3\xb4\x39\x73\x50\xd4\x73\xdb\x70\x73\xe6\xa0\x28\x2f\x83\xb8\x92\x03\x77\x13\xb6\x10\x3d\x06\xc2\xf9\x9e\xc2\xe8\xdd\x72\xea\x53\x20\x6b\x4c\x0f\x3b\x7c\x2f\x32\x91\x5e\x30\x32\x8e\xda\x42\x7c\x53\x83\x1e\x6b\x34\x3f\x67\x70\xde\x1e\x73\x06\x6c\x2f\x73\x06\x90\x7b\x14\x8c\x1a\xa8\x49\x7f\xce\xc7\x0d\xd3\x97\xc2\x51\x83\x7a\xb0\xcd\x22\x42\x56\x34\x26\x0e\x68\xcc\xa0\x1e\x72\xaf\xbb\x71\xcc\xa0\xbc\xf7\x9c\x81\x16\x28\x27\xe0\xa5\x3d\x89\xdf\x6b\xab\xa7\x4f\x3e\x9c\xb3\x9b\x85\xb9\xf6\xc6\x8e\x9f\x0a\xac\xab\xbb\xa6\x90\x27\x16\x43\xc6\xcf\x17\xcc\x18\x9c\xbc\xc7\x8c\x01\xdb\xf7\x8c\x81\x1a\xf4\xab\x01\x4c\xbc\x7c\x76\xc2\xba\xee\x3d\x6c\xa0\x26\xe8\x86\xf2\xe6\x06\x17\x06\x52\xb7\xa5\x8f\x21\x83\xde\x5a\x60\x76\x59\x4c\xc2\x31\xcd\xea\x45\xfc\x49\xcc\x35\xcb\xa4\x97\x8d\x64\xae\xdd\x69\xfe\x00\x12\xab\x60\x8f\x52\xbf\x6e\xee\x71\x0d\x14\x6e\x91\x87\xc8\x77\x53\xa6\xe5\x82\x4a\xdd\xb8\x0d\xb8\x79\x53\x70\xbc\x19\x38\xea\xb3\x1b\x0f\xf5\xe2\x18\xbd\x8d\xee\xce\x65\xdc\xaa\xd2\xbc\x43\x38\xfe\x0c\x94\xe5\xee\xa5\xac\x4a\x7f\x9b\x55\x89\x43\x3f\xfa\x48\x3f\xba\xab\x4b\xaa\xef\xea\xc2\xef\x98\xb8\xeb\x64\x79\x9c\xfc\x88\x31\x7b\xb0\xa8\x70\xf6\x80\xfd\x96\xd9\x03\xbc\xef\xa4\x39\x7b\x00\x61\x7a\xf7\xc9\x83\x01\xbd\x27\x0f\x8c\x38\x99\xe1\x48\x17\x02\xbf\x09\x45\x3b\x61\x03\x95\x33\x7e\x3f\x6b\x3e\x79\xd0\xc6\xef\x0e\x36\x11\xd8\xd9\x74\x48\xfd\xa8\x9b\x17\x2e\x5a\x0a\x3c\x6d\x5d\xd0\x30\xfe\xe6\xe3\xe7\x2f\x64\x55\x1e\xaf\xa5\xdb\x5f\xa9\x9c\xb4\x64\x75\xa0\x29\xb6\xfc\x98\x50\xd0\xca\x99\xeb\x71\x5d\xf2\xec\x41\xdf\xfc\x01\x19\xec\xf7\xad\x7b\xe7\xa0\xae\xab\xdb\xe7\x96\x33\x51\x96\xad\x77\xaf\xd1\xef\x76\x38\x80\xd7\x07\x1c\x57\x05\xf4\x13\xde\x27\xf9\x6e\xf4\x7e\x17\x1a\xbb\xab\x76\xf3\x9e\xd0\x01\xb3\x5f\x85\xd1\x11\x21\xc9\x99\x31\x48\xcb\x77\xdd\x2d\xb8\xab\x6a\xc9\xef\x34\x5b\x38\xae\x21\x0e\xe0\xb9\x14\x33\xee\x91\x8b\xb4\xe4\xb7\x97\x5d\xf9\xf1\x02\x15\x19\x14\x46\x4f\x19\x08\x72\x3e\xda\xf3\xb5\xce\xde\x01\x40\x29\x04\xf4\x8d\x02\x7a\x14\x79\xff\xbd\x61\x81\x8a\x2b\xcc\x39\x03\x4e\xf3\xfb\x06\xcd\x97\xfd\xff\xa4\x19\xd1\xa9\x5d\x4a\xb6\x28\x4e\xb7\x64\x01\x7b\x0a\x85\xcb\x2b\xc8\x9e\x7a\xd1\x8c\x70\xbb\xa5\xbf\x46\x39\x95\xb2\x7d\x53\xce\xa2\xf9\x3c\xbb\x4f\xda\xcd\xa4\xdb\xa4\xfd\x07\x63\xbe\xe0\x92\xfd\xa6\xbd\x66\xff\x69\xaf\xdd\x4d\xde\x3d\xe3\x04\x44\x7f\xa2\x72\x4f\xfa\x7f\x4d\xe6\x66\xa4\xe9\x9b\xfa\x99\x66\x90\xd9\x2b\xf9\xe7\x1a\x23\x05\xb2\x41\xff\xf3\xf9\x79\x82\xdb\xf6\x93\x03\x7d\x0e\x15\xec\xc1\x0e\xb5\x02\x1d\x68\x99\x1d\x27\x15\xf9\x74\x41\x5f\x1c\x52\x5d\xfe\xdd\x3c\x2d\x8e\x12\xd8\x8b\xe8\x46\x7b\xbb\x99\x04\xdb\x2f\xf6\xf0\xb1\x82\xbe\xb9\x33\x88\xc6\x0a\xf6\xca\x9a\xdf\xf7\xcc\x14\x10\x06\xab\xe5\x65\xca\x99\x93\xe0\x7d\x39\x0b\x5c\xc6\x08\x01\xc1\xe4\x22\x4a\x2e\x25\x43\x55\x29\x2c\xe4\x8d\x24\x87\xd6\x99\xb5\x7b\xe3\x1d\x05\x03\x02\x7b\x81\x62\xe5\x83\x02\xfb\xc6\x63\x65\xe5\x79\x75\xde\x3b\x2e\x2b\x9b\x64\xce\x0d\x54\xea\x0b\xe4\x2b\xad\x45\x94\xf7\x5c\xda\x07\x16\x7a\x0f\x04\x7a\x1e\x08\x22\x8f\x84\xae\x89\x78\xf2\x61\x4f\x2c\x74\xc2\x6c\xec\x0b\x11\x3d\x8e\x7e\x9d\xdf\x59\x68\x0f\x24\xf4\x4a\x7e\x6c\x5a\x50\xd4\x68\xc1\x7d\x34\xf6\x8d\x87\x5e\xc9\x1e\x49\x9d\x3f\x63\x2f\x70\xe8\x78\x5f\x0d\x6d\xf8\x81\xbb\xe3\xa1\x5b\x4b\x77\xbc\xd7\x0b\x0f\x5d\x36\x64\xf7\x20\xc9\xae\x52\xa8\xc1\x39\xf3\x0a\x1c\x00\xa9\xa2\x8e\x36\xde\xde\x72\x1f\xc2\xac\xa5\x96\x5b\x25\xe8\x6b\xa5\x9f\x5c\x17\xb6\x56\xeb\xe0\x6f\x25\xb6\xdc\x02\x91\x62\x4a\x04\x93\xca\xdd\xb2\xcd\xee\x74\x49\xd4\x97\xa9\x41\xe0\xc9\xff\x81\xfc\x99\xa9\xad\xfb\x56\x81\x91\xa6\xd6\xee\x43\x01\x56\x90\xea\x8a\xc2\xd1\xbb\xb6\xdb\xd6\x58\x9e\x12\x4a\x84\x7a\xe1\x76\x03\x45\x06\x71\x02\x8b\x0d\x18\x4f\x7a\x26\x17\xe4\xa7\x62\x6c\xc6\xed\x2f\xe9\x22\xe7\xe4\x4f\xd2\x9c\x21\xa4\x96\x39\x8f\xbf\x18\xef\x79\xee\xc9\xdf\x1e\x93\xba\xf9\xa5\x7c\xf0\x42\xe1\x08\x82\x0a\x01\xcd\xe0\xf1\x21\x87\x0d\x87\x53\xa8\x79\x57\x89\xa5\x5a\xb1\x8c\x4e\x5e\xc1\xa3\x55\x4e\x6a\xde\x41\x2d\xe0\xa5\x4e\x09\xe2\xe8\xab\x95\x1d\x90\x00\x10\x2a\x16\x02\xa5\xf0\xe9\xc3\xdd\x0e\xc3\x18\xb7\x4b\x2d\x04\x8e\x3f\x9a\x4d\x61\xde\x03\xaf\x9c\x22\xdd\x51\x78\x36\x66\xe7\xa1\x73\x57\x8d\xd2\xbf\xd5\x37\xb3\xe4\x1d\x6b\x07\x9d\x3c\x70\xf0\xc9\x1d\x6b\x6f\x13\x87\xb3\x01\x60\x60\x13\xdd\x8e\x82\xc3\x32\x4e\x17\x9b\xc8\x1c\x77\x3f\xec\x70\x48\xdf\xd9\x5d\x0f\x6d\xe1\xb6\x3e\x77\xd7\x76\xeb\x0f\xf2\x64\xca\xad\x3b\x48\x5b\xb0\x3e\x8e\xf1\x7d\xbe\x60\x9a\xb2\x1f\x9c\x1e\xc2\x0c\xbb\x3d\x9d\x4b\xfb\x2a\x64\x73\xe8\x62\x10\xf1\x85\xe7\xd6\x94\x06\x79\x9c\x5d\xda\x60\xf8\x9b\x81\x24\x7a\xb8\x43\x76\xfa\x82\xb1\x0a\x7f\x7d\xb3\x01\xae\x10\xa1\x5e\x41\x0d\xba\xb8\x68\x19\xbf\x87\x43\xa4\x43\x93\x9b\x0c\x68\x5e\x33\x19\xda\xfb\x06\xc6\x6e\x05\x53\xb5\xd9\xce\x9b\x0b\x49\xd1\xc9\x0f\x8c\x1a\xae\x1d\xff\xd6\xb7\xdd\x67\x88\xf6\x73\x4f\x38\xe2\xbc\x09\x07\x8f\xdc\xb6\xfa\xd4\x87\x46\x8d\x7c\xe0\x94\xde\x37\x53\xf8\x52\x64\x47\x63\x7b\x8f\xa7\x47\x93\xc6\x8c\x9d\x58\xd8\xdd\x9b\x78\xd0\x41\x13\x0b\x0b\xab\x45\xf9\x1e\x36\x9f\xb3\xf2\xd0\x9c\x15\x62\x2b\xfc\x65\x7f\x27\xad\xd4\x92\x0c\x22\x56\xd3\xc1\x8d\xf2\x7d\xcf\x5c\x75\xc6\x7c\x21\xa8\x5d\xa2\x60\x7f\xd1\x14\x1d\xab\x92\xd2\xd9\x28\x9d\x44\x8f\x62\xef\xad\x84\x5e\x8e\xdb\xbb\x38\x5a\x73\x94\x60\x3d\xb5\x92\x18\x4e\xf8\xd8\x1c\x4e\xdc\xd9\x88\xfb\x14\x9e\x76\xfe\xea\xa0\x56\xde\xfe\xfa\x98\xd5\xba\x3e\x3f\x81\xd6\xf7\xa4\xd6\x0c\x33\x56\x30\x61\xb6\xfc\xb1\x34\xc4\xf2\xa5\x60\x87\x0c\x0a\xfb\x5d\x96\x4c\x4e\x34\x40\xa0\x10\xe5\x07\x43\x83\x28\xe4\x45\x6c\x84\xef\xd9\x66\xa0\x96\x3f\xee\x99\xf1\x63\xc2\xf1\xf2\x3f\xa4\x59\x96\x9f\x85\xa0\x30\x45\xa0\x9b\x55\x41\x39\xe7\xb7\x62\xf7\x4b\x32\x5a\x7f\xc2\xb6\x5c\x90\x17\x71\x41\x3a\xe3\x91\x73\xf2\xd2\x8d\xaa\x70\xa4\x58\x22\x87\xec\xf7\x50\x43\x4a\x93\xac\x84\x21\x63\x42\xa4\xf5\xae\xd2\x8e\xdf\xad\x14\x93\x7f\xea\xdd\xd0\x60\x05\xb8\x7d\x54\xdd\xac\x16\x5b\x4c\x2c\xbe\xff\xe9\x6b\xa2\x70\x83\x38\x4b\x7e\x4b\x1a\x4a\xfd\xc3\xf2\x3d\xb0\x00\xfb\xc0\x00\xbc\x41\x1e\xba\xe3\x39\x71\xd6\xc7\xc6\x7d\x8e\xcf\x13\x67\x59\xee\xfe\x2d\xff\xfe\x3c\x4b\xdb\x2f\x5f\x9b\xff\x9e\x09\x0b\xa4\x6f\xd8\xed\xd6\x81\x82\x03\x62\x24\x02\x30\xc9\x12\x82\x4a\xd1\xed\x78\xc0\x98\x1d\xa0\x5b\x98\xa7\x38\xf8\x47\x18\x30\x45\x1c\xfd\x7b\xc1\x31\x93\xd7\xd4\xd5\x4b\xdf\x3c\x76\xe4\xdb\x63\x27\x8f\xb9\x76\xde\x63\xf4\x79\x83\xa5\x57\xd8\x2a\xba\xcf\x4f\x35\xe2\x3a\xe1\xe7\xd9\x8d\xcf\x93\x38\xa0\x13\x7e\x1e\x61\x97\x3b\xe8\xf3\x10\x81\x3b\x83\x90\x29\x83\x6b\xfb\xfd\x70\xec\x44\x39\x71\xe0\xb5\xf3\x1f\x79\xe4\xa8\x77\xc6\xf0\xf5\x8d\xd2\x1f\x62\x97\xb2\xf2\xc2\xcf\xb3\xed\xeb\xf3\x08\xd1\x3b\x63\x83\xcf\x1b\x55\xdb\xef\x47\x76\xec\xc4\x1f\xc6\x5c\x3b\xf7\x9d\xb7\x8f\xe4\x9f\x27\x09\x8b\xa4\x6f\xc4\x6e\xa2\xd7\x29\x84\x84\xf1\xa4\xa3\xae\x8c\xf1\xb1\x04\xb5\x1b\x36\x29\x57\x1d\x3c\x49\x33\x4e\x7b\x99\x4c\x80\xcc\x15\xcc\x0c\x41\x2f\x7d\x78\x08\x48\x30\x55\x2a\xcf\x98\x64\x22\x7f\xb9\x88\x78\xf4\x23\x9b\xba\x3b\xaf\x0a\x98\x26\x09\xe3\xa4\x57\xc4\x8f\x80\x67\x02\xad\x69\xa4\x80\xc4\x85\x32\x08\x9e\x6d\xef\x59\x93\xbc\x0d\x61\x55\xf1\x8e\xbe\x38\x93\xaa\x18\x6b\xb2\xc9\x1c\x15\xc9\xab\xa8\x2e\xcc\xa3\xd5\x10\x17\x52\x9e\xab\xed\xf9\xab\x71\xc4\xdf\x27\xe9\xb7\xf4\xca\x14\x93\xcd\x53\x0a\xf9\x8d\xf7\x4f\x79\x48\x7c\x8b\xf8\x1d\xc4\x95\x38\x52\x6a\x30\xcf\x1d\x6f\x9a\x8c\x8e\xf3\x1d\xef\xd5\x89\xf7\x16\xf6\xc3\x4a\xc2\x3d\x22\x40\xfc\x39\xa7\xb1\x23\xdd\x4b\x1c\xed\xbb\x0b\xe6\xb1\xdd\xe4\x33\xb9\x40\x50\x4c\x38\x9d\x6d\x17\x0f\x91\x9d\x82\x07\xeb\x7b\x97\xa9\x47\x79\x75\xf2\x92\xed\xdb\xdd\x42\x31\x3c\xc9\xff\xd0\x2d\xbf\x76\xc7\xd1\x3a\x7d\xd5\xf1\x27\xac\x5a\xb5\x74\xe9\x2a\x71\xeb\xec\xa3\xce\x3b\x77\xd1\xec\x45\x67\xf1\x3d\xba\x4b\xc0\x7f\x1f\xca\x38\x42\xa8\x5d\x70\x0b\x07\x1b\x73\xa5\x16\x47\x26\x63\x20\x99\x69\x56\xa7\xd1\x0c\x36\x9e\xa0\x6e\x3e\xc3\x3b\x6c\x72\x7c\x33\x3c\x34\x68\xe1\x37\xf6\xc1\x59\x61\x3c\x63\xe6\x86\x6c\xd0\xcb\xef\x15\xaa\x24\x94\x7a\x84\x31\xc6\x8b\x4b\x58\x52\x7f\x87\xbd\xc1\x92\x7f\x63\x49\x26\x20\x66\x3a\xff\xe1\x3a\xde\x28\xac\x63\xbb\x08\xb3\x2b\x21\x30\xd5\x46\xa4\x59\x88\x26\xbc\x23\xab\x1d\xcb\xa6\x02\xfb\x23\xe0\xd2\x46\x8e\x58\x2a\x96\x15\xe2\x94\x8e\x15\xd6\x89\xb1\xde\x9f\xa3\x8a\x69\xe3\xa3\x7a\x3e\x87\xe1\xe7\x18\xc0\x60\x63\xf7\x80\x01\x83\xcf\x19\xb4\x6b\xbb\xf4\x3e\xe4\x4d\x0d\xc2\x6a\x21\x5b\x2b\xf0\x7b\xe6\xf0\x53\x94\x90\x3e\xe5\x04\x56\xeb\xf4\x34\xa8\xc5\x99\x1c\xf0\xae\x15\x16\x59\x02\xdf\x21\xd3\x73\xd1\x0c\xa2\x1a\xe2\x73\xe1\x34\xe1\xc9\xf6\xdb\xa6\x89\xd6\x74\x5a\xfb\x7f\x95\x9d\xcf\x4f\x13\x41\x14\xc7\x77\xfa\x3b\x15\xe8\x2e\xfd\x41\xb1\x14\x0a\x9b\xd0\xa4\x09\x52\xb6\x94\x6e\x6b\x5b\xa8\x31\x31\x10\xf4\x64\x34\x24\x1a\x63\x22\x07\x8c\x88\x68\x22\xc4\x93\x26\x26\x10\x13\x08\xa9\x86\x88\x12\x95\x9b\x07\x0e\xdd\xca\x1f\xe1\x41\x2e\x5e\x8c\x89\x5e\x44\xbc\x98\x10\x0e\x7a\x50\x42\xe3\x7b\x6f\x76\x97\x9a\x94\x12\x0e\xdd\xce\xce\xce\x36\xe9\xbc\xb7\x3f\x66\xe6\xbd\xef\x27\x0c\xfd\xe2\xc3\x37\xea\x70\xcc\x98\x1d\xc7\xec\xbf\x18\x4d\x9b\xc7\x78\x02\x1f\x2e\xde\x0b\x9a\x10\xa1\x37\x21\x78\xa9\xa2\x98\x5b\xce\x15\x94\x91\x2d\x28\x54\xb3\x05\x3b\x75\xb5\xea\x2a\x9c\x89\x90\x63\x99\x62\xb1\xc8\x7a\x7e\x65\xef\x9d\xf5\x27\xa7\xd5\xfb\x73\x6c\xbd\x72\x11\x3f\x73\xb3\x99\xa9\x84\x3f\xfd\x20\xff\xbb\xf2\x91\x6d\xaf\x2c\xaf\x34\xee\xb0\xb0\xe8\xd9\x16\xbd\xaf\x9e\x78\x60\xd7\xf5\x78\x51\x92\xb6\x3c\x22\x6b\xfa\xee\xe2\xd7\xc1\xa8\xf5\xa9\x0d\xf9\xc4\x4e\x18\x3d\x14\x75\x8d\x69\xd6\x08\xbe\xe1\x22\x0f\x2c\xdb\x3d\x18\x52\x4e\xf5\x46\x15\x95\x05\x9b\x4e\xd2\x25\xf1\x4e\x07\x18\x92\x0b\xc8\xd8\x49\x80\xd2\x6e\x45\x52\x30\x8d\x0c\x1d\x02\x1f\x28\xbb\x4c\xf9\x10\x84\x5e\x89\xb0\xe7\x39\x10\xf8\x44\x78\xa4\xe6\xa6\x67\x98\x80\x99\x08\x27\x1a\x9a\xfd\x26\x05\x44\x96\x64\x89\x49\x44\x02\x81\x52\xd4\x2a\x5b\x9d\xd2\x28\x5b\x7c\xb8\xc4\x2e\xbf\x9e\x71\xcc\xbe\x78\xe4\x98\x18\xbe\xed\xb0\x9f\x9b\x98\x40\x69\xd3\xca\xa8\x25\x5c\x59\x66\x37\xf7\xb7\xd8\x49\x56\xd9\x66\x31\x56\xf9\x24\x30\x1a\x24\xa8\x36\x15\xae\x83\xa4\x60\xfa\xba\x53\x8f\xbb\xd0\xcb\x26\x8e\x81\x04\x07\xf5\x2f\x5d\xd8\xaf\x0f\xbc\x1b\x7f\x60\xef\x3d\xf7\x65\xe4\x7c\x37\x3b\x7a\xc0\x03\xd7\xf8\x4a\x52\xc9\x9f\xc0\x5c\xce\xb2\xaf\xa5\x0d\x3b\xac\x1a\x41\xd9\x7a\x80\xa0\xec\xea\x2d\x45\x28\x85\x35\xc4\xf5\xcd\x43\xc4\x51\x0b\x21\x05\x28\x42\xc9\x0b\x11\xec\xae\x10\x65\x84\xf1\x34\x63\x5a\x65\xf1\xfa\xa1\x41\x90\x62\xb8\x83\x01\x7d\x7a\x25\x88\x53\x0c\x88\xa4\x2a\x79\x25\x3d\xdb\x47\xc0\xc9\x5a\x6f\xfa\x68\x62\xa5\x09\x69\xd7\xbf\xbb\xd6\xfe\x7c\xbb\xf0\xfc\x46\x6c\x78\xe6\xfc\xf8\xb8\x65\xe9\xe5\xfe\xc6\x42\xe5\xd9\xc2\xfe\xbb\x55\xeb\xe4\xe6\xc8\x87\xaf\x1d\xe1\x1f\x81\xe0\x95\xb1\x11\x7d\x41\xed\x8d\x09\xb1\x24\xce\x8b\xfd\x2a\xf4\x43\x17\x8e\x3c\xaa\x72\x5e\xcb\xa2\xb7\x13\xfb\x01\x27\x64\x4b\x6d\x09\x82\x0a\xb6\x2b\xa8\xc5\x45\xc1\xea\x32\xc6\x77\x63\xaa\x79\x84\xa7\xf2\x46\x2c\x06\x5a\x0e\xb6\x98\xd0\x6b\x89\x54\xa1\x03\x6c\x1c\x33\xe7\x33\xe4\x2d\x6b\x06\xee\x23\x20\xc9\x17\xa1\x3f\xce\x73\x56\x35\x8f\x2f\x9d\xd6\x82\x76\x3e\x40\x73\xf3\xb4\x7c\x1e\xed\x4d\xd7\x19\xc5\x0d\x19\xc4\xaa\xff\x50\x9e\xd1\xd5\xf9\x79\xe6\xd8\xb9\xf4\x76\x6a\x1d\x71\x55\xa9\x5b\x83\xd3\x77\x77\x77\x17\xf0\x2f\x6f\xf6\x7e\xfe\xd9\x11\xfe\xfb\x85\xe0\x7b\xd7\x1a\x9a\xee\x4c\xf6\x12\xd3\x13\xef\xb0\xa7\x05\xc1\x85\x3c\x52\x9c\x5b\xc9\x33\x0b\x57\xd0\xd3\x94\x4c\x22\x81\x71\x6f\x1b\x2d\x7d\xfd\xe9\x2c\xb2\xf8\xcc\xe9\x95\x72\x73\xfb\x29\xa4\xb3\x33\xc4\xe3\x86\x07\xf0\xc5\x39\x86\x8f\x69\x8c\x09\xc1\x74\x78\x18\x5f\x34\x61\x6f\x0d\x12\xb4\xc4\xca\x63\xda\x24\xa5\x1c\x08\x19\xe8\x04\xd8\x22\x50\x37\x14\x30\x33\x3b\x86\x42\xad\x78\xcf\x11\x51\x98\xb8\xd4\xa1\x68\x2a\x9c\xd2\xa3\x94\xd5\x1c\xb6\x50\x33\xd0\x38\xa7\x62\x31\x07\x3e\x57\x52\x45\xa2\xf3\xc5\xa1\x53\xe3\x49\xac\x8d\x2b\xd0\x20\x19\xc7\x62\x32\x01\x9d\x3a\x04\x47\x73\x30\x76\x2b\x3b\xdd\x14\x0d\x97\x54\xa1\x5f\x63\x32\xc5\x91\x6b\xd1\x6e\x5a\x04\x47\x0d\xac\x78\x5a\x8b\xb5\x92\xfe\x93\x26\x13\x25\xac\xdb\x48\x06\x39\x94\x95\xda\x79\xa4\x57\xd6\xa0\xa9\x5a\x86\xea\x78\x6a\x2d\xce\x6a\x5d\xf7\x85\x9b\x18\xda\xec\xba\x6e\x33\x55\x80\x51\xb7\x6e\xb5\xfe\xbc\x61\xb5\xc4\x40\x6e\xa8\x8e\xd5\xe2\x68\x35\x78\x4c\x47\x13\xa8\xdc\x5a\x92\x15\x74\x70\xad\x3b\x03\xb5\x6e\x11\x63\x19\x29\x48\xee\xf8\xe6\x4b\x71\xf3\x29\xdc\x7c\x4a\xca\x00\x32\xc2\xb6\x1f\x4e\x49\x11\xac\x31\x15\xc6\x8a\x54\x12\x4e\x51\x44\xad\x80\x11\x8e\x60\xca\x6c\x01\x8f\x65\xf3\xd0\xac\x90\xc5\x62\x21\x8d\xcd\x0a\x83\x60\x50\x0c\xc5\x4b\x05\x74\xad\x45\xad\x80\x58\x46\xd9\x34\xa3\x96\x2d\x40\xa5\x1b\x0d\x79\xe6\xf8\xe6\x3b\x38\xc6\x92\xf5\x4c\x38\x56\xa3\x2e\xcf\xb9\x96\x87\x19\xb1\x56\x25\xdb\x33\x19\x98\xff\x00\x6c\x25\xfa\xf7\x00\x00\x78\xda\x63\x60\x64\x60\x60\x00\xe2\x3b\x4c\xea\x3b\xe3\xf9\x6d\xbe\x32\xc8\x73\x30\x80\xc0\xf9\xfa\x39\xe7\x60\xf4\xff\x13\xff\x8c\x39\x12\xd9\xa7\x02\xd5\x71\x30\x30\x81\x44\x01\x58\x33\x0c\xff\x00\x00\x00\x78\xda\x63\x60\x64\x60\xe0\x48\xfa\x5b\x04\x24\x1b\xff\x9f\xf8\x7f\x8a\x23\x91\x01\x28\x82\x02\xde\x00\x00\x9e\x4a\x07\x4a\x00\x78\xda\x6d\x93\x6b\x68\x8e\x61\x18\xc7\x7f\xcf\x7d\x5f\xf7\xfb\x2c\x5b\xcb\x07\x49\x1a\x66\xd4\xeb\xcd\x0e\x0d\xd9\xbb\xbd\x66\x87\x57\x63\x6f\x3e\x60\x39\x6e\xc9\x9a\x6d\x72\x2a\x72\x98\xc3\x07\xb6\xa1\x35\x73\x58\x14\x8a\xf2\x09\xc5\xa2\x10\xb5\xd2\x3e\xc8\x88\xcf\x4e\x39\x7d\xa0\xc8\x07\xd6\x42\x68\xaf\xeb\x79\xb5\x85\x3c\xf5\x7b\xfe\x77\xf7\xe1\xea\x7a\xfe\xff\xfb\x31\x1f\x99\x97\x06\x78\x5f\xf4\xf5\x86\xd4\x13\x8c\xbd\x1f\xec\xb4\x99\x1c\x96\x1e\xc2\x52\x43\xb1\x3b\x49\xa1\x0c\x91\xe7\xf5\xd1\x69\xae\xb0\xd2\xf4\x53\x6a\xbb\xc9\x91\x04\x85\xde\x57\x4a\x6c\x01\x6d\x66\x14\xfb\xcd\xc7\xe4\x7b\xe9\xa6\xde\x76\x30\x57\x36\x32\x43\x56\x50\x2c\xad\x4c\x95\x79\xc4\xa5\x85\x5a\xad\x55\x28\xb5\x3a\xde\x4e\x99\x77\x8f\x5a\xef\x2e\x59\x76\x90\x12\x69\x60\x8f\xf8\xac\xb3\x4f\xc9\xf1\x33\x89\xbb\x3b\x44\x5c\x82\xa8\x2b\x60\x96\x6b\x53\xcd\x22\x2a\x9f\x55\xab\x29\x08\x55\x10\x35\xf7\x29\x92\x8b\x4c\x71\xb7\x74\xfe\x2a\x51\xbf\x83\x68\x28\x5f\xd7\x2f\xea\xd9\x3c\xd5\x4b\xaa\xfb\x74\xed\x19\xf5\xae\x9e\x69\xa1\x74\xc2\xae\x57\x6b\x5f\x67\x82\x3b\xc7\x64\xb7\x43\x7b\x7a\x40\xc2\x54\xd2\x69\x97\x91\x61\x8a\x49\xb7\xdb\xc8\x93\x2a\xea\xcc\x66\xca\xa5\x91\x84\x9c\x4d\x7e\x90\x22\xed\xb5\x57\x89\x13\x37\xdf\x89\xe9\xb7\x2d\x76\x63\xc9\x36\x27\x08\x9b\xe5\xc9\x57\xf2\x46\xc7\x5d\x64\xfb\x5b\xb4\xee\x18\xb2\x65\x2f\x65\xf2\x84\x88\x7e\x73\xdc\xae\xa6\x4a\x26\x52\x6f\x7e\x92\xab\xde\x4d\x96\xa3\x4c\x0a\xad\x57\x3f\x2f\xe8\xbe\x5e\xc6\x4b\x3e\x2b\xcc\x11\xc2\xde\x65\xda\x4d\x27\xe9\x6e\x3a\x6b\x03\xef\x4d\x06\xad\xea\xd7\x22\x39\xad\xbe\x9f\x62\x89\xdb\x45\xc4\x78\x1c\x94\xe7\x2c\x55\x8f\x8e\x85\x26\x92\xb0\x0d\xac\xb6\xb7\x11\xf5\x7f\x6b\xe0\x7d\x6a\xee\x13\xdd\xe6\x3d\xeb\x65\x34\x95\xb6\x88\x46\x5b\xa1\xf5\xdb\xf5\x7c\x5c\xbd\x6a\x66\xb6\x89\x70\xdc\x1b\xa4\xc6\x8c\xa3\x49\xb3\xdb\x64\x1f\x51\xee\x0e\xb0\xdd\x5d\xa3\x29\xd4\x40\xb5\xbd\x46\x5e\xca\xf7\xff\xe0\x27\xa9\x4c\x65\x91\xf5\x3b\x8b\x61\xcc\xfd\xe4\x40\x90\x85\xea\x3b\xa5\xdf\x9d\x27\x7f\x24\x87\x7f\x90\x5c\x4a\x5d\x0b\x0b\x82\x2c\xfe\x24\xc8\xc2\x8d\xd7\x3d\x11\xf5\x26\xf0\xfd\x3f\x84\xbe\x51\x9d\xca\x22\xfe\x37\xa6\x07\x5f\xa9\x32\x3d\xc9\x1f\xca\x0b\xe9\x63\xce\x48\x0e\xff\xb2\x49\xef\xc3\x19\x16\xa6\xb2\xf8\x93\x20\x8b\x97\x7a\x97\x55\xfd\x87\x34\xfb\x35\xd4\x05\x3d\xd9\xdd\xac\xb2\x37\xd9\x68\x1f\x80\x7f\x12\x86\xd5\x1c\xd2\xff\xe3\xad\x12\xff\x0d\x03\xaa\xed\xaa\x1b\x74\x8f\x66\x31\x8c\xab\xe3\x5c\x28\xc6\x3e\xef\x35\x6b\xbc\xc7\xc4\xbc\x21\xbd\x13\x15\x9a\xcb\x02\xf5\x3a\xa6\xbd\xdf\xa1\xc5\xdd\xa0\x23\x38\x6b\x4a\xc8\x35\xe5\xcc\x0f\xea\x4a\x58\xff\x87\xc7\xda\x67\x14\x5c\x31\x39\xae\x8b\x70\xda\x4c\x62\x69\xfb\x89\xfd\x02\x8e\x79\xbf\x05\x00\x78\xda\x63\x60\x60\xd0\x41\x82\x31\x0c\x13\x18\xab\x98\x58\x98\x96\x30\xbb\x30\x67\x30\x4f\x63\x3e\xc2\xfc\x81\xc5\x84\x25\x86\xa5\x82\x65\x0e\xcb\x16\x56\x16\x56\x07\xd6\x5d\x6c\x66\x6c\x3d\x6c\x9f\xd8\x73\xd8\xb7\x71\xb8\x70\xec\xe2\x78\xc7\xa9\xc6\x69\xc3\x19\xc7\x59\xc4\x79\x8b\x6b\x11\xd7\x2b\xee\x0c\xee\x53\x3c\x72\x3c\x13\x78\x3e\xf1\x26\xf1\x3e\xe2\x93\xe1\xab\xe0\x7b\xc1\x6f\xc7\x7f\x42\xc0\x4c\xa0\x43\xe0\x83\x60\x88\xe0\x23\xa1\x18\xa1\x4d\xc2\x32\xc2\x61\xc2\xc7\x44\x54\x44\x6a\x44\x2e\x89\x32\x88\x4a\x88\x7a\x89\xe6\x88\xb6\x89\x2e\x13\x33\x12\x9b\x27\xf6\x43\xbc\x40\xfc\x92\x84\x91\xc4\x3a\x49\x0d\xc9\x02\xc9\x1d\x52\x32\x52\x61\xd2\x5c\xd2\x2d\xd2\x17\x64\x02\x64\x4e\xc9\xaa\xc8\x2e\x93\xfd\x23\x97\x26\xb7\x40\xee\x99\xbc\x85\x7c\x87\xfc\x03\x05\x2d\x05\x0f\x85\x09\x0a\x0f\x14\x1e\x28\x72\x29\x56\x28\x71\x29\x4d\x51\x96\x52\x76\x52\xfe\xa6\xa2\xa2\x72\x4d\x35\x42\xb5\x4a\x75\x91\xea\x31\xb5\x0e\xb5\x25\x6a\x9f\xd4\x1d\xd4\x27\x69\xf0\x69\x98\x68\xac\xd2\x64\xd2\x54\xd1\x8c\xd3\x6c\xd1\xbc\xa0\xf9\x45\xab\x42\x9b\x47\xfb\x86\x8e\x9d\xce\x14\x9d\x37\xba\x6e\xba\xf7\xf4\x22\xf4\x3e\xe9\x77\x19\x28\x18\x2c\x33\xd4\x33\xdc\x63\x14\x62\xb4\xc4\xe8\x8b\xb1\x87\xf1\x32\x13\x09\x93\x4b\xa6\x66\xa6\xf3\xcc\x78\xcc\x66\x98\x8b\x98\x9b\x99\xef\xb1\xb0\xb2\xd8\x63\xe9\x62\x79\xc1\xca\xca\x6a\x8d\xb5\x9e\xf5\x39\x9b\x1c\x5b\x21\xdb\x07\x76\xb3\xec\x0b\x1c\xb4\x1c\xb6\x39\x2a\x39\x4e\x72\x62\x71\x9a\xe4\xf4\xc8\xd9\xc8\xb9\xc3\xf9\x95\x4b\x82\xab\x98\x6b\x89\xeb\x0d\x37\x07\xb7\x53\xee\x4e\xee\x25\xee\x5f\x3c\xf2\x3c\xde\x78\xe6\x78\xfe\xf2\x0a\xf3\xba\xe1\x1d\xe6\xfd\xc1\xa7\xc5\x57\xc0\xd7\xcc\xb7\x0e\x07\xec\xf1\x9d\xe5\xbb\xc2\xf7\x84\xef\x0b\x3f\x01\x3f\x0b\xbf\x04\xbf\x55\x7e\x1f\xfc\x4d\xfc\x53\xfc\x57\x01\xe1\x39\xff\x4f\xfe\x9f\x02\x4a\x02\x5e\x04\x0a\x04\x4e\x09\x92\x0a\xfa\x12\x7c\x03\x00\x96\x1e\x9a\xe2\x00\x00\x00\x01\x00\x00\x00\xec\x00\x48\x00\x05\x00\x00\x00\x00\x00\x02\x00\x01\x00\x02\x00\x16\x00\x00\x01\x00\x01\x66\x00\x00\x00\x00\x78\xda\x85\x92\xcf\x4e\x14\x41\x10\xc6\xbf\x99\x5d\x15\x02\x1a\x21\x86\x23\x99\x78\x30\x9a\xb8\xc3\xb0\xac\xa8\x6b\x62\xa2\x06\x08\x86\x78\x40\x22\x17\x2e\xc3\xba\xb0\x1b\x61\x97\x0c\xa3\xe8\x2b\xf8\x24\x86\x93\x67\x1f\xc0\xe8\x85\x07\xe0\xe0\x23\xf8\x0c\xfe\xba\xa6\x67\xdd\x31\x41\xd2\xe9\xee\xaf\xaa\xba\xbe\xfa\xd3\x25\x69\x56\xbf\x54\x53\x50\x9f\x94\xf4\x94\x5d\xe0\x40\x73\x48\x05\x0e\x35\xa1\x2d\x8f\x6b\x8a\xb5\xe3\x71\x5d\x91\x3e\x7b\x7c\x45\x5f\x74\xea\xf1\x55\xcd\x07\x9b\x1e\x5f\xd3\xcb\xe0\xc8\xe3\x49\x4d\x07\xdf\x3c\x9e\xd2\xad\xe0\xbb\xc7\xd3\xba\x13\x9c\x7b\x7c\x5d\x3b\x61\x99\xc3\x0d\x6d\x85\x65\xac\x9b\x9a\x0b\xbf\x7a\x3c\xa3\x89\xb0\xf4\x9d\x55\x14\x9e\x79\xfc\x83\x37\xbf\x3d\xfe\xa9\xa4\x56\xd7\xaa\x86\x1a\x28\x27\xcf\xb7\x4a\xb9\x53\x50\x07\xdd\x91\x3e\x29\x53\x5f\xfb\xea\x99\x75\x0d\xdd\x10\xe9\x40\x5d\xa4\xa6\x12\x2d\x6a\x49\x9b\xe8\x76\xd9\x39\x3b\xd2\x6b\xac\x29\xf2\x73\xa4\x03\xf8\xc6\x7d\xda\x17\xbc\x6d\x5f\xc2\x15\x8d\xd8\xde\xc0\x92\xe9\x98\x9c\x5c\xc6\x11\x3e\x31\x3b\x61\x35\xb5\x8c\xff\x93\xb1\xbc\x1c\xce\x59\x7b\x70\xbc\x37\xc6\x1e\x7e\x45\x9d\x77\xf5\x81\x57\xb1\x1e\xab\xc5\xe9\x3c\x1a\xf8\x74\xf4\x10\xf9\x1e\xf6\x06\xd1\x22\x3d\x32\x94\x59\x9c\xa6\xe1\x35\xcf\x9f\x98\xf4\xd1\x2c\x2d\xc3\x27\x9c\xb7\x59\x0e\x6f\x57\xea\x28\xab\x68\x8c\xaa\xb8\xa8\xca\x3e\x95\x45\xd6\xfd\x9c\xa8\x29\x2f\xbb\x3a\xe4\xce\xf4\x0e\xdd\x90\x4a\xaa\x7f\x10\x57\xa4\xaa\xc5\xfd\xdf\xa1\x5e\x50\x73\x66\xbc\x39\x67\x6a\x3d\x2b\xa2\xbb\x3e\xe6\xe8\x5d\x1f\x37\xb0\x75\xd0\x0c\x90\xbb\x44\x8d\xe8\xd7\xc0\xa2\x67\x96\x4b\xcf\xfe\xfb\x19\xf3\x90\xf2\xae\x90\xaa\x3e\xf7\xd1\xfc\xfb\x37\x4d\xb2\x48\x6c\x72\x72\x3c\xdb\x5a\x60\x9d\xd8\x8a\xe1\xf9\xcb\x15\xf3\x3e\x23\xef\x05\x32\x1f\xe7\x3c\x46\xb3\xa1\x75\x6a\x58\xd1\x2b\xba\xb4\x42\x07\x0b\xce\xff\x4f\xdc\x65\x33\xb4\x0d\xf7\x2e\xbd\x2c\x67\x7e\xd1\x38\x57\xad\x4f\x45\x95\x99\x65\xff\x80\xd3\x4d\x52\xdb\xa6\xcb\x9d\xcb\xa3\xe9\x6a\xfd\x01\x78\x3b\x95\xca\x00\x78\xda\x6d\xd1\x47\x6c\x53\x41\x10\x80\xe1\x7f\x12\xc7\x4e\x9c\xde\x7b\xa3\x77\xfc\x9e\xed\x14\xba\x9d\xc4\xf4\xde\x3b\x81\x24\xb6\x43\x48\x82\x83\x81\xd0\x02\xa2\x57\x81\x90\xb8\x81\x48\xe0\x02\x88\x5e\x05\x02\x0e\x80\xe8\x4d\x14\x01\x07\xce\x74\x71\x00\xae\x60\xfc\x96\x1b\x73\xf9\xb4\x33\xbb\xa3\xd1\x2c\x11\x84\xe3\x77\x3d\x35\xfc\x2f\xbe\x80\x44\x48\xa4\x98\x24\x8a\x48\x4c\x44\x61\xc6\x42\x34\x31\x58\x89\x25\x8e\x78\x12\x48\x24\x89\x64\x52\x48\x25\x8d\x74\x32\xc8\x24\x8b\x6c\x72\xc8\x25\x8f\x7c\x0a\x28\xa4\x88\x62\x3a\xd1\x99\x2e\x74\xa5\x1b\xdd\xe9\x41\x4f\x7a\xd1\x9b\x3e\xf4\xa5\x1f\xfd\xb1\xa1\xa1\x63\xc7\x81\x93\x12\x4a\x29\xa3\x9c\x01\x0c\x64\x10\x83\x19\xc2\x50\x86\xe1\xc2\x4d\x05\x95\x54\xe1\x61\x38\x23\x18\xc9\x28\x46\x33\x86\xb1\x8c\x63\x3c\x13\x98\xc8\x24\x26\x33\x85\xa9\x4c\x63\x3a\x33\x98\xc9\x2c\x66\x33\x87\xb9\xcc\x63\x3e\x0b\xa8\x16\x33\x47\xd8\xc4\x66\xae\x73\x80\x0f\x6c\x61\x0f\x3b\x39\xc8\x31\x8e\x8a\x85\x1d\xbc\x63\x23\xfb\x25\x5a\x62\xd8\x2d\x56\xb6\x71\x8b\xf7\x12\xcb\x21\x8e\xf3\x93\x1f\xfc\xa2\x83\x93\xdc\xe7\x2e\xa7\x58\xc8\x22\xf6\x86\xb6\xf5\x90\x5a\xee\xf1\x80\xa7\x3c\xe2\x31\x4f\xf8\x48\x1d\x2f\x78\xc6\x73\x4e\xe3\xe5\x3b\xfb\x78\xcd\x4b\x5e\xe1\xe3\x33\x5f\xd9\x4e\x3d\x7e\x16\xb3\x84\x06\x1a\x39\x4c\x13\x4b\x69\x26\x40\x0b\x41\x96\xb1\x9c\x15\x7c\x62\x25\xab\x68\x65\x35\x6b\x59\xc3\x15\xda\x69\x63\x1d\xeb\xd9\x10\xfa\x83\x6f\x5c\xe5\x0c\x67\xb9\xc6\x1b\xde\x4a\x9c\xc4\x4b\x82\x24\x4a\x92\x24\x4b\x8a\xa4\x4a\x9a\xa4\x4b\x86\x64\x4a\x96\x64\x73\x8e\xf3\x5c\xe2\x32\xb7\xb9\xc0\x45\xee\xb0\x95\x13\x92\xc3\x0d\x6e\x4a\xae\xe4\xb1\x4b\xf2\xa5\x40\x0a\xa5\x48\x8a\xcd\xde\x86\xd6\x66\x9f\x66\x09\x36\xfa\x6d\x36\x5b\xa5\x52\x57\x96\x1b\xba\x6c\x4a\x55\x77\xab\xba\xdb\xae\x74\x2a\xc3\xf7\xf5\xd0\x43\xa5\xa6\xd4\x95\x76\xa5\x43\xe9\x54\x96\x28\x4b\x95\x65\xca\x7f\xfd\x5c\x86\x9a\xea\xab\x69\xd6\x3a\xbf\x37\x18\xa8\xad\xa9\x6e\xf1\x19\x29\xdd\x63\xe8\xf4\x98\xaa\x82\x81\xa6\xf0\xc1\xe9\xa9\xf8\xab\xc7\x6d\xcc\x11\x52\x57\xda\x95\x8e\x3f\x6b\x51\xa3\x5a\x00\x00\x78\xda\xdb\xc1\xf8\xbf\x75\x03\x63\x2f\x83\xf7\x06\x8e\x80\x88\x8d\x8c\x8c\x7d\x91\x1b\xdd\xd8\xb4\x23\x14\x37\x08\x44\x7a\x6f\x10\x09\x02\x32\x1a\x22\x65\x37\xb0\x69\xc7\x44\x30\x6c\x60\x56\x70\xdd\xc0\xac\xed\xb2\x81\x45\xc1\x75\x13\xb3\x38\x93\x36\x88\xc3\xb8\x81\x15\x2a\xca\x05\x14\x65\xdd\xcc\xa4\xbd\x91\xd9\xad\x0c\xc8\xe5\x04\x72\xb9\x84\xe0\x5c\x0e\x20\x97\x53\x02\xce\x65\x07\x72\x39\x74\xe1\x5c\x36\x20\x97\x5d\x0c\xce\xe5\x56\x70\xdd\xc5\xc0\x5a\xff\x9f\x01\x2e\xc2\x03\x54\xc0\xcd\x01\xe3\x46\x6e\x10\xd1\x06\x00\x33\xcf\x35\x6c\x00\x01\x53\x59\xec\x4e\x00\x00\x01\x00\x00\xff\xff\x51\xd8\x44\x79\xdc\x6f\x00\x00") func fontsRobotoslabBoldWebfontWoffBytes() ([]byte, error) { return bindataRead( _fontsRobotoslabBoldWebfontWoff, "fonts/robotoslab-bold-webfont.woff", ) } func fontsRobotoslabBoldWebfontWoff() (*asset, error) { bytes, err := fontsRobotoslabBoldWebfontWoffBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "fonts/robotoslab-bold-webfont.woff", size: 28636, mode: os.FileMode(509), modTime: time.Unix(1492020681, 0)} a := &asset{bytes: bytes, info: info} return a, nil } var _imagesBulletConnections2Png = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x9c\x53\x4f\x68\xe4\x54\x18\x7f\x6d\xd5\x5d\xbb\xb6\x07\x17\x0f\x5d\x70\xf7\x91\x8a\x56\x71\x26\x79\xf9\x3b\x89\x93\x69\x33\xc9\x8c\x33\xb0\xa9\x43\x3a\xb0\x23\x08\x6e\x26\x79\x33\x13\xda\xe4\x65\x93\x57\x27\x2d\x15\x74\x2f\xce\xaa\x08\x7a\xf0\x24\x2c\x42\x2f\x82\x08\x5e\x44\xfc\xc3\xba\xb0\x05\xf7\xe8\xc5\x83\x17\xa1\x78\x56\x7a\xf3\x50\x41\x52\x27\xbb\x22\xa5\x07\x3f\x78\xf0\xde\xc7\xef\xf7\xfb\xfe\xbc\xef\xbb\xd5\x59\x7f\x79\x61\xfe\xd2\x3c\x00\x60\xa1\xdd\xb2\x1c\x00\xc0\x85\xfc\x9c\x7f\x0c\x00\xf0\xd9\xe7\xe3\x67\x01\x00\x4b\xb4\xd1\xa3\x1b\x64\x40\xc7\x6e\x82\x81\xe1\x93\x3e\x86\xed\xd0\x1d\x62\x07\xbb\xfe\xce\x8d\xfb\xb8\x0a\xc0\xdc\x28\xe8\xf6\x68\xcf\xbe\xaa\x79\x24\x2c\xbb\x39\xa6\x9c\x85\x31\xc8\xad\xba\x9a\xc5\xae\xb7\x89\x29\xec\xe3\x61\x10\xe9\xcc\x1f\xdf\xde\x61\x60\xe0\xeb\xcc\x35\xc9\xe6\xec\xd8\xc4\xa3\xa0\xb5\x9b\xe0\x8d\xdd\xf5\xae\xb7\xbb\xe9\xa9\x3e\xb3\x5a\x83\xd5\x4c\xcb\xc2\x38\xc4\xd4\x85\x59\xb8\x15\xa5\x5a\xa6\x33\x27\xba\x5a\x94\x6a\xb9\x9b\x65\xe0\x09\x84\x6e\xea\xcc\x3f\x49\xf5\xec\x0e\x34\x49\x82\xa1\x54\x16\x4a\x1e\x87\x10\x94\xe5\x32\x12\x25\x59\x46\x2f\x42\x9e\x43\x3c\xcb\xf1\x2c\x27\x97\x90\xa8\x49\xb2\xc6\x2b\x70\x6a\x4c\x0d\x56\x13\x7f\xa0\x39\x56\x73\x1a\x2b\xf1\x07\x3a\x33\xa2\x34\xd6\x58\x76\x3c\x1e\x97\xc7\x42\x99\x24\x43\x16\xa9\xaa\x9a\x6b\xf0\x7c\x29\xf1\x07\xa5\x74\x27\xa2\x6e\x56\x8a\xd2\xe5\x42\xc1\xc2\xa9\x97\x04\x31\x0d\x48\x04\xf3\xb7\xdb\x27\xdb\x54\x67\x98\xa2\x84\x30\xb6\xed\x07\xc2\x51\x3a\x6d\x94\x47\x42\x36\x73\x63\x16\x95\x39\x36\x0c\xd9\x02\x9d\x52\x07\x0f\xce\x46\xa7\xdd\x9d\x18\xb3\x0e\x4e\xc9\x76\xe2\x61\x07\x0f\x96\xff\x15\xea\x6c\x6a\x0e\x8c\x6d\x5b\x7b\x25\x09\x86\x41\xe4\x6e\x59\xc4\xdb\x0e\x71\x44\xdb\x96\xce\x64\x61\x5c\xf6\x03\x5f\x93\x14\x41\x51\x55\x41\xe0\x11\xcf\xc9\x15\x84\x2a\x86\x6c\x35\x24\xb1\xae\xca\x86\x58\x57\x44\xa1\xd0\x38\x8d\xab\x58\x82\x82\xd4\x8a\xa9\x48\x16\x87\x50\x43\xac\x88\x8a\xda\x90\x45\xb3\x2e\x5b\xbc\xc4\x99\x62\xc1\x6d\x47\x29\x75\x23\x0f\x17\xdc\xe0\x21\xb7\x7e\x26\x57\x33\x13\xec\x52\x92\x74\x09\xd9\x2a\x26\xa0\x33\x22\x94\xa4\x23\x12\x43\x73\x43\x86\x2b\xb6\xeb\x05\x51\xee\x78\x3e\xff\xa0\x69\xae\x38\x09\xde\xc0\x7e\x33\x21\x21\x3c\xe9\xb0\x16\x9c\x92\x41\x5d\xae\x88\x8a\xd1\x34\x11\x3f\xad\x9c\xe7\x8d\x86\x29\x1a\x6a\x03\x19\x92\xd5\xe4\x98\x29\xd7\xff\x3f\x5d\x63\x6b\xb0\xca\xfe\x67\x5c\x0a\x97\x63\x35\xf3\xeb\x83\xe1\xaf\xc1\x87\xeb\x83\x23\x5f\x67\x12\x66\xb5\xe6\xfe\x3c\xd9\x03\x00\x7c\xdc\xb6\x8c\x6e\xf6\x4b\xff\xf8\xaf\xaf\x6e\xcf\xcc\xff\xf6\xf6\xd7\xb3\x93\xef\xdf\xea\xcd\x4e\x5e\x07\x47\x32\xfc\x1d\x1c\xbe\x03\x1f\x7d\xbf\x73\x70\x79\xed\xbb\xf9\xc9\xce\x12\x77\x77\x08\x17\xe7\x0e\x9f\xbe\xba\x56\x9f\x99\x5c\x3b\xec\xfc\x08\x9e\x3a\xb7\xb4\x0f\x9c\xd7\x1e\xbf\xb7\xf7\xc4\x9f\x33\x2d\x53\x6d\x7d\xf9\xdc\xdc\x8d\x1f\x2e\xec\xf7\x3e\x69\x1d\x3c\x09\x0f\xd8\x5b\xdd\xe3\xd9\xfd\xec\xa5\x0f\xdf\xbd\xfb\xe9\x4f\x8b\x0b\x97\xf7\xc0\x33\xbf\x2e\x3a\xc7\xe0\xd2\x07\xb7\x8f\x56\x1e\xb9\xbf\x7a\xfd\xe6\xab\x33\xf7\xbe\x59\xab\x5e\x9c\x5c\x99\x3b\x62\x57\xf4\x8b\x2f\x2c\x7e\x34\x04\xe7\x39\x20\x2c\x5f\xb9\xf3\xe6\x7b\xfd\x73\xf9\xee\xb7\x1b\xeb\xd6\x17\xf5\xeb\x37\xff\x0e\x00\x00\xff\xff\x46\x0f\x29\x11\x68\x04\x00\x00") func imagesBulletConnections2PngBytes() ([]byte, error) { return bindataRead( _imagesBulletConnections2Png, "images/bullet-connections-2.png", ) } func imagesBulletConnections2Png() (*asset, error) { bytes, err := imagesBulletConnections2PngBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "images/bullet-connections-2.png", size: 1128, mode: os.FileMode(436), modTime: time.Unix(1492020681, 0)} a := &asset{bytes: bytes, info: info} return a, nil } var _imagesBulletConnectionsPng = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x9c\x53\x4f\x68\xe4\x54\x18\x7f\x6d\xfd\xb3\x76\x6d\x05\x17\x0f\x5d\xb4\x3e\xb2\xa2\x75\x71\x26\x79\x99\x49\x32\x89\x93\x69\xf3\x6f\x9c\x91\x4d\x1d\xd2\x81\x8e\x20\xb8\x69\xf2\x66\x26\xb4\xc9\x4b\x93\x57\x27\x53\xf6\xa0\x7b\x71\x76\x11\x41\x05\x4f\x82\x08\x55\x10\x44\xf0\x26\xba\xa2\x0b\x5b\x70\x8f\x5e\xbd\x08\x55\xf0\xa6\xf4\xe6\x61\x0f\x92\x3a\xd9\x15\x59\x7a\xf0\x83\x07\xef\x7d\xfc\x7e\xbf\xef\xcf\xfb\xbe\x6b\x9d\xf5\x97\x16\xe6\xcf\xcf\x03\x00\x16\xda\x2d\xd3\x01\x00\x9c\xcd\xcf\x99\x87\x00\x00\x9f\x7f\x31\x7a\x16\x00\xb0\x44\xad\x1e\xdd\x20\x7d\x3a\x72\x13\x0c\x34\x9f\x6c\x61\xd8\x0e\xdd\x01\x76\xb0\xeb\x8f\x77\x6f\xe3\x3a\x00\x73\xc3\xa0\xdb\xa3\x3d\xfb\x92\xe2\x91\xb0\xec\xe6\x98\x72\x16\xc6\x20\xb7\xfa\x6a\x16\xbb\xde\x36\xa6\x70\x0b\x0f\x82\x48\x65\xfe\xfc\xf6\x7b\x06\x06\xbe\xca\x6c\x0a\x36\x67\xc7\x06\x1e\x06\xad\xfd\x04\x6f\xec\xaf\x77\xbd\xfd\x6d\x4f\xf6\x99\xd5\x06\xac\x67\x4a\x16\xc6\x21\xa6\x2e\xcc\xc2\x9d\x28\x55\x32\x95\x39\xd1\x55\xa2\x54\xc9\xdd\x2c\x03\x4f\x20\x74\x5b\x65\xfe\x49\xaa\x67\x77\xa0\x41\x12\x0c\x85\x72\xa5\xe4\x71\x08\x41\x51\x2c\xa3\xaa\x20\x8a\xe8\x05\xc8\x73\x88\x67\x39\x9e\xe5\xc4\x12\xaa\x2a\x82\xa8\xf0\x12\x9c\x1a\xd3\x80\xf5\xc4\xef\x2b\x8e\xd9\x9c\xc6\x4a\xfc\xbe\xca\x0c\x29\x8d\x15\x96\x1d\x8d\x46\xe5\x51\xa5\x4c\x92\x01\x8b\x64\x59\xce\x35\x78\xbe\x94\xf8\xfd\x52\x3a\x8e\xa8\x9b\x95\xa2\xf4\x42\xa1\x60\xe2\xd4\x4b\x82\x98\x06\x24\x82\xf9\xdb\xdd\x22\x7b\x54\x65\x98\xa2\x84\x30\xb6\xed\xbb\xc2\x51\x3a\x6d\x94\x47\x42\x36\x73\x63\x16\x95\x39\x36\x0c\xd9\x02\x9d\x52\x07\xf7\x4f\x47\xa7\xdd\x71\x8c\x59\x07\xa7\x64\x2f\xf1\xb0\x83\xfb\x17\xfe\x15\xea\x74\x6a\x0e\x8c\x6d\x5b\x79\x25\x09\x06\x41\xe4\xee\x98\xc4\xdb\x0b\x71\x44\xdb\xa6\xca\x64\x61\x5c\xf6\x03\x5f\x11\xa4\x8a\x24\xcb\x95\x0a\x8f\x78\x4e\xac\x21\x54\xd3\x44\xd3\x12\xaa\xba\x2c\x6a\x55\x5d\xaa\x56\x0a\x8d\xfb\x71\x2d\x59\xe4\x35\xde\x32\x25\xc1\xa8\x21\x64\x55\x35\x24\x4b\x16\x92\x74\x5d\xaf\x34\xf9\x9a\x26\x15\xdc\x76\x94\x52\x37\xf2\x70\xc1\x0d\xee\x71\x8d\x53\xb9\x8a\x91\x60\x97\x92\xa4\x4b\xc8\x4e\x31\x01\x9d\x21\xa1\x24\x1d\x92\x18\x1a\x1b\x22\x5c\xb1\x5d\x2f\x88\x72\xc7\xf3\xf9\x07\x4d\x73\xc5\x49\xf0\x06\xf6\x9b\x09\x09\xe1\x49\x87\x95\xe0\x3e\x19\xe8\x52\xad\x2a\x69\x4d\x03\xf1\xd3\xca\x79\x5e\xb3\x8c\xaa\x26\x5b\x48\x13\xcc\x26\xc7\x4c\xb9\xfe\xff\xe9\x1a\xdb\x80\x75\xf6\x3f\xe3\x52\xb8\x1c\xb3\x99\x5f\xef\x0e\x7f\x03\xde\x5b\x1f\x1c\xf9\x2a\x93\x30\xab\x8d\x97\xa5\x27\x37\x01\x00\x1f\xb6\x4d\xad\x9b\xfd\xbc\x75\x63\xf7\xe2\x07\x33\xf3\xbf\xbd\xf5\xf5\xec\xe4\xbb\x37\x7b\xb3\x93\xd7\xc1\xb1\x08\xff\x00\x47\x6f\xc3\x07\xdf\xe9\x1c\x2e\xaf\xdd\x98\x9f\x8c\x97\xb8\x9b\x03\xb8\x38\x77\xf4\xd4\xa5\x35\x7d\x66\xb2\x79\xd4\xf9\x11\x3c\xf1\xf0\xd2\x01\x70\x5e\x7b\xe4\xd6\x95\x47\xff\x9a\x69\x19\x72\xeb\xab\xe7\xe6\x76\x7f\x38\x7b\xd0\xfb\xa8\x75\xf8\x38\x3c\x64\xaf\x75\xef\xcc\x1e\x64\x2f\xbe\x77\xfd\xe6\x27\x3f\x2d\x2e\x2c\x5f\x01\xcf\xfc\xb2\xe8\xdc\x01\xe7\xdf\xfd\xf8\x78\xe5\x81\xdb\xab\x97\xaf\xbe\x3a\x73\xeb\x9b\xb5\xfa\xb9\xc9\xd3\x73\xc7\xec\x8a\x7a\xee\xe2\xe2\xfb\x03\x70\x86\x03\x9f\x3d\xb6\xfc\x3b\xf9\xf5\xfa\xa7\xf9\xee\xb7\xad\x75\xf3\x4b\xfd\xf2\xd5\xbf\x03\x00\x00\xff\xff\x17\x95\x74\x91\x68\x04\x00\x00") func imagesBulletConnectionsPngBytes() ([]byte, error) { return bindataRead( _imagesBulletConnectionsPng, "images/bullet-connections.png", ) } func imagesBulletConnectionsPng() (*asset, error) { bytes, err := imagesBulletConnectionsPngBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "images/bullet-connections.png", size: 1128, mode: os.FileMode(436), modTime: time.Unix(1492020681, 0)} a := &asset{bytes: bytes, info: info} return a, nil } var _imagesBulletDevices2Png = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x9c\x53\x5f\x68\x1c\x45\x18\x9f\xa2\xc4\xd8\x52\xf5\xa9\x92\x52\xc3\xb0\xd5\x6a\xa8\x77\xbb\xb3\xb7\x7f\x6e\x97\xbb\x4b\xf7\x76\xef\xda\x83\x6e\x9a\x6e\x8e\x36\x45\x10\x37\xbb\xb3\xb9\x25\xd9\x9d\x75\x76\x92\xdb\x9c\x60\x43\xa9\x4a\xa1\x18\xab\xa0\xf8\x20\xd6\x27\x2b\x8a\xaf\x2d\x14\xda\xbe\xd6\x82\x20\x12\x02\x2a\x08\xea\x9b\x42\x35\x2f\x5a\x04\x91\x8d\xb7\x51\xa4\xe4\xa1\x1f\x0c\xcc\x7c\xfc\x7e\xbf\xef\xcf\x7c\xdf\x85\xe9\xa9\xa3\x7b\x77\xef\xdf\x0d\x00\xd8\xdb\x39\x66\x39\x00\x80\x3d\xf9\x19\x1d\x01\x00\x7c\xf2\x59\xff\x10\x00\x60\x8c\xb5\x66\xd9\x0c\x09\x58\xdf\xa5\x18\x18\x3e\x99\xc3\xb0\x13\xb9\xf3\xd8\xc1\xae\xbf\xf2\xf2\x6d\x5c\x03\xe0\xa1\x5e\xd8\x9d\x65\xb3\xf6\x71\xdd\x23\x51\xd9\xcd\x31\xe5\x2c\x4a\x40\x6e\xb5\xc9\x2c\x71\xbd\x05\xcc\xe0\x1c\x9e\x0f\xe3\x3a\x77\xf7\xfa\x4d\x0e\x86\x7e\x9d\x3b\x2d\xdb\x82\x9d\x98\xb8\x17\x1e\x1b\x50\x3c\x33\x98\xea\x7a\x83\x05\x4f\xf3\xb9\xc9\x06\xac\x65\x7a\x16\x25\x11\x66\x2e\xcc\xa2\xc5\x38\xd5\xb3\x3a\xb7\xa5\xab\xc7\xa9\x9e\xbb\x79\x0e\x6e\x41\xd8\x42\x9d\xfb\x27\xa9\x59\x7b\x1a\x9a\x84\x62\x28\x97\x2b\x25\x4f\x40\x08\x2a\x4a\x19\x49\xb2\xa2\xa0\xe7\xa1\x28\x20\x91\x17\x44\x5e\x50\x4a\x48\xd2\x65\x45\x17\x55\x38\x34\xae\x01\x6b\xd4\x0f\x74\xc7\x6a\x0f\x63\x51\x3f\xa8\x73\x3d\xc6\x12\x9d\xe7\xfb\xfd\x7e\xb9\x5f\x29\x13\x3a\xcf\x23\x4d\xd3\x72\x0d\x51\x2c\x51\x3f\x28\xa5\x2b\x31\x73\xb3\x52\x9c\x1e\x2c\x14\x2c\x9c\x7a\x34\x4c\x58\x48\x62\x98\xbf\xdd\x39\xb2\xc4\xea\x1c\x57\x94\x10\x25\xb6\xbd\x2d\x1c\xa7\xc3\x46\x79\x24\xe2\x33\x37\xe1\x51\x59\xe0\xa3\x88\x2f\xd0\x29\x73\x70\xb0\x33\x3a\xed\xae\x24\x98\x77\x70\x4a\x96\xa8\x87\x1d\x1c\x1c\xfc\x4f\xa8\x9d\xa9\x39\x30\xb1\x6d\xfd\x04\x0d\xe7\xc3\xd8\x5d\xb4\x88\xb7\x14\xe1\x98\x75\xac\x3a\x97\x45\x49\xd9\x0f\x7d\x5d\x56\x2b\xaa\xa6\x55\x2a\x22\x12\x05\xa5\x8a\x50\xd5\x50\xac\x96\x2c\x35\x35\xc5\x90\x9a\xaa\x54\x29\x34\xee\xc7\x55\xad\x8a\x8a\x34\x4d\x50\x65\x4b\x40\xa8\x25\x55\x25\x55\x6b\x29\x92\xd9\x54\x2c\x51\x16\x4c\xa9\xe0\x76\xe2\x94\xb9\xb1\x87\x0b\x6e\xb8\xcd\xad\xb6\x77\xe4\xea\x26\xc5\x2e\x23\xb4\x4b\xc8\x62\x31\x01\xd3\x3d\xc2\x48\xda\x23\x09\x34\x67\x14\xf8\x9c\xed\x7a\x61\x9c\x3b\x26\xf2\x0f\x1a\xe6\x8a\x69\xb8\x8c\xfd\x36\x25\x11\xdc\xea\xb0\x1e\xde\x27\x83\xa6\x52\x95\x54\xa3\x6d\x22\x71\x58\xb9\x28\x1a\x2d\x53\x32\xb4\x16\x32\x64\xab\x2d\x70\x43\xae\xff\x20\x5d\xe3\x1b\xb0\xc6\xff\x6f\x5c\x0a\x97\x63\xb5\xf3\xeb\xf6\xf0\x37\xe0\xbf\xeb\x83\x63\xbf\xce\x51\x6e\xb2\xb1\xfc\xe4\xb7\xa7\x00\x00\xef\x76\x2c\xa3\x9b\x7d\x73\xf1\x2d\xf4\xd8\xb9\x23\x4f\xb4\x1e\x19\xfc\x72\x91\xd1\x5d\x77\x3f\x3a\x70\xeb\xd3\xd1\x67\x57\x0f\x27\x0f\xdb\x8b\xeb\x3f\x5e\x56\xa6\xbf\x3e\xf3\xdb\x8d\xb1\xc3\x3f\x04\x67\x37\x97\xdf\x79\x5f\xbd\x7e\xfb\xe9\x9f\x37\xd6\x6b\x2f\x5c\xb9\x7c\xfe\xc0\xc8\x35\x63\xcf\x89\x47\x2f\xdc\x79\xe5\xda\x91\xe0\xce\xf1\xe4\xfc\xd1\x2f\x4e\xde\xba\xb7\xd6\x7b\x71\xc3\x7c\xed\xa7\xfd\xa7\xf6\xbd\x39\x32\xf5\xf6\xe3\xfb\xde\x73\x36\x0f\x39\x5f\x3e\xb3\x76\x69\x13\xde\x1b\x9f\x38\x7b\xf5\xab\x3f\x06\xcd\x93\x37\x2f\x7d\xf7\xe7\xf8\xc7\xab\x57\x5e\xfd\xf0\xaf\x1b\xab\x4f\xb1\x5f\x5f\x5f\xfb\xfe\x83\x8d\xf5\xab\x67\x56\x77\x81\x89\xd3\xe3\x63\xa3\x6f\xfc\xbe\x94\xef\x7e\xa7\x35\x65\x7d\xde\x7c\xe9\xdc\xdf\x01\x00\x00\xff\xff\xe9\xee\x70\x38\x68\x04\x00\x00") func imagesBulletDevices2PngBytes() ([]byte, error) { return bindataRead( _imagesBulletDevices2Png, "images/bullet-devices-2.png", ) } func imagesBulletDevices2Png() (*asset, error) { bytes, err := imagesBulletDevices2PngBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "images/bullet-devices-2.png", size: 1128, mode: os.FileMode(436), modTime: time.Unix(1492020681, 0)} a := &asset{bytes: bytes, info: info} return a, nil } var _imagesBulletDevicesPng = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x9c\x53\x5d\x68\xe4\x54\x14\xbe\x8b\xa5\x4a\x65\x44\x64\x51\x5c\x54\xae\x59\x94\x5d\x70\x26\xb9\x99\xfc\x4c\xc2\x64\xda\xcc\x24\xe3\x0e\x98\x5a\xa6\x03\x1d\xfc\xc1\xa6\xc9\x9d\x99\xd0\x26\x37\x26\x77\x76\x32\x7d\x10\xec\x22\xa2\x28\x15\x74\x45\x04\x59\x7d\x11\x16\x56\x61\x41\xf1\xa1\xe0\x56\xc5\xb2\x8a\xb0\xf4\x51\x85\x55\xea\xcb\xae\x88\x83\x3f\x58\x17\x7c\x90\xd4\xc9\xae\x48\xe9\x83\x07\x2e\xdc\x7b\xf8\xbe\xef\xfc\xdc\x73\x5e\x98\x9b\x7d\x38\x37\x75\x64\x0a\x00\x90\x6b\x9c\x30\x9a\x00\x80\x5b\xd3\x73\xcb\x24\x00\xe0\xec\xb9\xc1\x83\x00\x80\xbb\xa9\xd9\xa6\xf3\xa4\x43\x07\x76\x84\x81\xee\x92\x25\x0c\x1b\xbe\xdd\xc5\x4d\x6c\xbb\xc3\xa7\xbf\xc0\x65\x00\x6e\xea\x79\xad\x36\x6d\x5b\x8f\xa8\x0e\xf1\x0b\x76\x8a\x29\x24\x7e\x08\x52\x2b\x4f\x27\xa1\xed\x2c\x63\x0a\x97\x70\xd7\x0b\x34\x66\xb4\x71\x81\x81\x9e\xab\x31\x0b\xa2\xc5\x59\x61\x0d\xf7\xbc\x13\xab\x11\x9e\x5f\x9d\x6d\x39\xab\xcb\x8e\xe2\x32\xd3\x15\x58\x4e\xd4\xc4\x0f\x7d\x4c\x6d\x98\xf8\x2b\x41\xac\x26\x1a\xb3\xa7\xab\x06\xb1\x9a\xba\x59\x06\xee\x41\xe8\xb2\xc6\xfc\x93\x54\xdb\x9a\x83\x35\x12\x61\x28\x16\x8a\x79\x87\x43\x08\x4a\x52\x01\x09\xa2\x24\xa1\x87\x20\xcf\x21\x9e\xe5\x78\x96\x93\xf2\x48\x50\x45\x49\xe5\x65\x38\x36\xa6\x02\xcb\x91\xdb\x51\x9b\x46\x7d\x1c\x2b\x72\x3b\x1a\xd3\xa3\x34\x54\x59\x76\x30\x18\x14\x06\xc5\x02\x89\xba\x2c\x52\x14\x25\xd5\xe0\xf9\x7c\xe4\x76\xf2\xf1\x30\xa0\x76\x92\x0f\xe2\xa3\x99\x82\x81\x63\x27\xf2\x42\xea\x91\x00\xa6\x6f\x7b\x89\xf4\xa9\xc6\x30\x59\x09\x7e\x68\x59\xd7\x85\x83\x78\xdc\x28\x87\xf8\x6c\x62\x87\x2c\x2a\x70\xac\xef\xb3\x19\x3a\xa6\x4d\xdc\x39\x18\x1d\xb7\x86\x21\x66\x9b\x38\x26\xfd\xc8\xc1\x4d\xdc\x39\xfa\xaf\x50\x07\x53\x53\x60\x68\x59\xea\xa3\x91\xd7\xf5\x02\x7b\xc5\x20\x4e\xdf\xc7\x01\x6d\x18\x1a\x93\xf8\x61\xc1\xf5\x5c\x55\x94\x8b\xb2\xa2\x14\x8b\x3c\xe2\x39\xa9\x84\x50\x49\x97\x0c\x53\x14\xaa\x8a\xa4\x0b\x55\x59\x28\x66\x1a\xfb\x71\x4d\x45\xe2\x75\xbe\x2e\xca\x62\xad\x84\x90\x29\xe8\x48\x91\x4d\x24\x57\xab\xd5\x62\x9d\x2f\xe9\x72\xc6\x6d\x04\x31\xb5\x03\x07\x67\x5c\xef\x06\x57\x38\x90\xab\xd6\x22\x6c\x53\x12\xb5\x08\x59\xc9\x26\x60\xae\x47\x28\x89\x7b\x24\x84\xb5\x79\x09\x1e\xb3\x6c\xc7\x0b\x52\xc7\xf1\xf4\x83\xc6\xb9\xe2\xc8\x3b\x89\xdd\x7a\x44\x7c\xb8\xd7\x61\xd5\xdb\x27\x83\xaa\x5c\x12\x64\xbd\x5e\x43\xfc\xb8\x72\x9e\xd7\xcd\x9a\xa0\x2b\x26\xd2\x45\xa3\xce\x31\x63\xae\xfb\x7f\xba\xc6\x56\x60\x99\xfd\xcf\xb8\x64\xae\xa6\x51\x4f\xaf\xd7\x87\xbf\x02\x6f\xac\x0f\x0e\x5c\x8d\x89\x98\xe9\x4a\x49\x7f\xe7\x35\x00\xc0\x9b\x0d\x43\x6f\x25\xdf\xbc\xb4\x7d\x3e\xb7\x36\x73\xf8\xf9\x5f\xee\x72\xae\x7c\x70\x7a\xea\xc9\x4d\xed\x95\x43\x6f\x3c\x9b\xdb\xbc\x3c\xb1\xb0\x38\x71\xef\xcc\xd7\x9f\x6d\xdd\xb1\x74\x4a\x7c\xeb\xf4\x77\xd3\x43\x3a\x39\x7a\xe0\xc2\x13\xbf\xfe\xbc\xf1\xe3\xeb\xd7\x7e\x73\x2b\x8f\xb7\x2e\xde\xee\x6c\xe6\xba\xbf\x4f\xdd\x79\xdf\xbb\xc9\xdb\x33\x6b\x17\x2f\x7d\xba\x7b\xf5\xf0\x28\xfc\xe4\xcb\x67\xd6\xff\x58\xe8\xbf\xb8\xde\xfe\xf6\xaf\x2b\xfa\xd9\x3f\x17\xed\x57\x8f\x5f\x9e\xd8\x3a\xbf\x33\x58\x2c\x1f\xfb\xf8\xe6\xad\xf7\x76\x8e\xfc\x70\x66\x6e\xf7\xc3\x9d\xdb\xae\x7d\x75\x6a\x7b\xb4\x71\x75\xfe\xb1\x9f\xb6\xbf\x7f\x6e\xfd\xcc\xcb\xa3\x3e\x79\xea\xd0\x24\xd8\xfd\xfc\x9e\x4b\x27\x3f\xba\xff\x5c\xba\xff\x0d\x73\xd6\x78\xbf\xba\xb8\xf6\x77\x00\x00\x00\xff\xff\xc6\xeb\x34\xbb\x6c\x04\x00\x00") func imagesBulletDevicesPngBytes() ([]byte, error) { return bindataRead( _imagesBulletDevicesPng, "images/bullet-devices.png", ) } func imagesBulletDevicesPng() (*asset, error) { bytes, err := imagesBulletDevicesPngBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "images/bullet-devices.png", size: 1132, mode: os.FileMode(436), modTime: time.Unix(1492020681, 0)} a := &asset{bytes: bytes, info: info} return a, nil } var _imagesDeletePng = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x00\x3e\x03\xc1\xfc\x89\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\x00\x00\x12\x00\x00\x00\x12\x08\x06\x00\x00\x00\x56\xce\x8e\x57\x00\x00\x03\x05\x49\x44\x41\x54\x38\xcb\x63\x60\xc0\x01\xba\x7b\x7a\xac\x03\x83\x83\x6b\x2d\xac\xac\xe6\x1b\x99\x98\xcc\x8f\x8a\x8e\xee\xe9\xe9\xed\x75\xaf\xad\xaf\x67\x66\x20\x06\xcc\x9e\x33\xc7\xdf\xda\xc6\x66\xaf\x90\x88\xc8\x5f\x06\x26\xa6\xff\x60\xcc\xcc\xfc\x1f\x28\xf5\x5f\x50\x58\xf8\xbf\xaa\xba\xfa\xf1\xaa\x9a\x9a\x50\xbc\x86\x74\x76\x75\x75\xf1\xf0\xf0\x80\x35\x31\xb2\xb0\xfc\x67\x61\x67\x47\xc1\x20\x31\x90\x1c\x07\x27\xe7\xff\xf4\xcc\xcc\x55\xdf\xbf\x7f\xe7\xc2\x30\x64\xc2\xa4\x49\xdd\x20\x45\x60\xdb\x19\x19\xc1\x2e\xc1\x65\x10\x8c\xce\x2f\x2c\x5c\x8b\x62\xc8\xc1\x83\x07\xdd\x39\xb9\xb9\xe1\x5e\x70\xf7\xf4\xdc\xaf\x6b\x60\x70\x17\xc4\x86\x19\x02\x32\x5c\x5e\x49\xe9\xae\xaf\x9f\xdf\x7e\x90\x38\x13\xd4\xb0\x85\x8b\x16\x65\x82\x0d\x39\x7a\xec\x18\xa3\x85\xb5\xf5\x15\xb0\x4d\x40\xc5\x7e\x01\x01\x5b\x40\xe2\x73\xe6\xce\x55\x51\x52\x51\x79\x01\x76\x25\xd0\x75\xa2\x12\x12\x2f\xa2\x63\x63\x55\x40\x72\x31\x71\x71\x87\xc0\xae\x06\xca\xa9\x69\x6a\xbe\xbb\x7e\xe3\x06\x0f\xc3\xe6\x2d\x5b\x8c\xb9\xf9\xf8\x7e\x33\xb1\xb2\x82\x0d\x0a\x0a\x09\xd9\x7b\xf5\xea\x55\x41\x90\x86\x19\x33\x67\x6a\x2a\x2a\x2b\xbf\x01\x06\xfc\x9b\xd0\x88\x08\x4d\x90\xd8\xb7\x6f\xdf\x04\x23\x22\x23\x4f\x83\xd4\x32\xb3\xb1\xfd\x67\x06\xba\xac\xa6\xae\x2e\x98\xa1\xa4\xac\xac\x11\x64\x3a\xdc\x0b\x40\x5b\xfc\x03\x02\x8e\x5d\xbb\x7a\x55\x04\xa4\x71\xca\xd4\xa9\xfa\x11\x51\x51\x3a\x20\xf6\xcf\x9f\x3f\x45\x12\x12\x13\x8f\xa1\x78\x19\xc8\x8e\x8a\x89\x99\xc3\x90\x92\x96\xb6\x0d\x59\x02\x26\xe9\xed\xeb\x7b\xf6\xc2\x85\x0b\x92\xb0\x70\xfc\xf8\xf1\xa3\x64\x64\x74\xf4\x59\x74\xb5\xa0\xb0\x12\x93\x94\x5c\xce\x90\x98\x9c\xbc\x0f\xc3\x20\xa0\x0b\x05\x45\x44\x5e\xe7\xe4\xe5\xa9\xc2\x0c\x5a\xb5\x66\x8d\xaa\xac\x82\xc2\x6b\x6c\x06\xc9\xc8\xc9\xad\x63\x00\xc6\x50\x27\x72\x54\x83\x0c\x11\x97\x92\x7a\x14\x1c\x1a\xaa\x07\x32\xe0\xd9\xb3\x67\x7c\xe7\xcf\x9f\xe7\x03\xb1\xa7\x4e\x9b\xa6\x07\x4c\x90\x8f\x90\x0d\x63\x04\xea\x05\xa6\xfc\x85\x0c\x13\x26\x4e\xf4\x63\xe3\xe0\x00\x07\x1c\xc8\x74\x29\x19\x99\xab\xc0\x00\xd7\x06\x69\xfc\xfb\xe7\x8f\x00\xd0\x3b\x17\x3c\xbd\xbd\x2f\xdc\xb8\x71\x43\x00\x24\x36\x69\xf2\x64\x6d\x55\x35\xb5\x7b\x4c\xc0\xa4\x02\x0b\x86\xea\xda\xda\x2a\x86\x9b\x37\x6f\x72\x29\xa9\xaa\x82\x9d\x0c\x72\x4d\x78\x64\xe4\x7c\x90\x06\x60\xaa\xe5\x8b\x4d\x48\x38\x0d\x16\x07\x62\x60\xfa\x39\x7d\xed\xda\x35\xb0\xcb\x32\xb2\xb2\x36\x81\x93\x0b\xd0\x30\x21\x51\xd1\x5f\xeb\xd6\xaf\x97\x05\xfb\xbf\xab\xbb\xbb\x0e\x9c\xc8\x80\x49\x80\x0b\x98\x30\xfb\xfa\xfb\xa7\x02\xc3\x07\x1c\x76\x20\x97\xc2\x6c\x06\xa6\xa3\x7d\xd3\xa6\x4f\x9f\xca\xc9\xc5\xf5\x9f\x19\xa8\x16\x24\x96\x9e\x91\xb1\x08\x25\x75\x07\x04\x05\x9d\x86\x19\x06\xce\xa8\xa0\x24\x01\x35\x04\x39\xfc\x40\x72\x4c\x50\x43\x8c\x4c\x4d\x1f\xbc\x7e\xfd\x9a\x0f\xc5\x20\x60\xa0\xca\x39\xb9\xba\x5e\x87\xe5\x25\x66\x34\x43\xd0\xf3\x1b\x30\xd0\x9f\xdd\xba\x7d\xdb\x02\x6b\xee\x3f\x7b\xf6\x2c\x0f\xb0\xdc\x59\xc8\xcd\xc3\xf3\x15\x6c\x3b\x10\x83\x34\x82\x35\x43\xb3\x04\x0f\x1f\xdf\x5f\x17\x37\xb7\x35\xad\x6d\x6d\x22\x04\xcb\xa4\xfc\x82\x02\xa5\xd8\xf8\xf8\x7a\x1d\x5d\xdd\xb5\x72\x8a\x8a\xfb\x24\x65\x64\xf6\x19\x9b\x98\x6c\xf5\xf0\xf6\x6e\x2f\x28\x2a\xd2\xc6\xa6\x07\x00\x50\xd8\x60\x02\xfe\x46\x33\x06\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\x01\x00\x00\xff\xff\x3a\x61\xd7\x35\x3e\x03\x00\x00") func imagesDeletePngBytes() ([]byte, error) { return bindataRead( _imagesDeletePng, "images/delete.png", ) } func imagesDeletePng() (*asset, error) { bytes, err := imagesDeletePngBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "images/delete.png", size: 830, mode: os.FileMode(436), modTime: time.Unix(1492020681, 0)} a := &asset{bytes: bytes, info: info} return a, nil } var _imagesDevicesImage2Png = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x9c\x94\x7d\x4c\x13\xf7\x1f\xc7\xbf\x3e\xfc\xea\x0f\x8d\x82\x3f\x84\xe4\x47\x50\x2f\x47\x54\x36\x69\xaf\xd7\x5e\xaf\xed\xd9\x03\xfb\x38\x4b\x2c\xd4\x52\x27\x51\xa7\x9e\xed\x95\x56\xbd\xbb\x72\x77\xac\x0f\x9a\xa9\x88\x9d\x86\xf9\x40\x60\xb8\xc5\x29\x45\x98\xd3\x66\xa9\x61\x53\xe7\x22\x88\x0f\x80\x4f\x73\x1a\x67\x7c\xda\x50\xe6\x73\x74\x6a\xa2\x6e\xc6\x01\x73\xa9\xa3\xba\x2c\xc6\x3f\xf6\xfd\xeb\xee\x93\xf7\xeb\xfd\x79\xb8\xcf\x7d\xd7\xda\x8b\xde\x19\x39\x3c\x6b\x38\x00\x60\xa4\x75\x9a\xc9\x01\x00\x18\x0b\x00\xc8\xfe\xaf\x04\x00\xb0\xe5\xf4\xee\x18\x00\xe0\xff\xa2\xb9\x54\x2c\xe1\x3c\x62\x80\xe2\x69\xa0\x77\x73\x0b\x69\xc8\xca\x50\x65\xb4\x83\xa6\xdc\xa1\xf2\xe3\xb4\x0e\x80\x21\x5e\x9f\xb3\x54\x2c\xb5\x4d\x27\x5c\x1c\x23\xa3\x12\x1a\x59\x90\xf1\x83\xc4\xd1\x15\x04\xfd\x94\x6b\x31\x2d\x42\x0b\xe9\x32\x1f\x4b\xc2\x0f\xf7\xb7\xc3\x90\xcf\x4d\xc2\xb3\x54\x36\xb9\xcd\x6f\xa4\xbd\xbe\x69\x61\x9e\x2e\x09\x17\x39\x5d\xe1\xc5\x2e\xad\x1b\x2e\xc8\x87\x74\x41\x22\xc8\xf8\x19\x5a\xa4\xa0\x20\xb3\x84\x15\x88\x20\x09\xbf\xf0\x25\x58\x81\x48\x84\x11\x18\x7a\x21\x11\x17\x93\xf0\x5f\x45\x95\xda\xec\x90\x91\xe3\x69\x48\x25\x53\x4a\x5d\x72\x14\x85\x70\x5c\x86\x62\x2a\x1c\x47\xf3\x20\x85\x1c\x55\x20\x72\x05\x22\xc7\xa5\x28\x46\xa8\x70\x42\xa1\x86\x06\x0e\x9c\x0f\xe9\x78\xb7\x87\x70\x98\x2c\x03\xb9\x78\xb7\x87\x84\xbd\xa2\xe8\x27\x10\x24\x10\x08\xc8\x02\x4a\x19\xc7\x97\x21\xa8\x56\xab\x4d\x78\x28\x14\x52\xde\xed\x91\x0a\x21\x56\xa4\x82\x52\x56\xc8\x49\x3a\x98\x68\xc1\xc5\xfb\xfc\xa2\x8f\x63\xa1\xc4\x3b\xb5\x90\xab\x10\x49\x18\x4e\xb6\xc0\xf8\x6d\xb6\x97\xc6\xac\x30\x30\x28\x17\xc7\x20\x41\xca\x8f\xa0\x32\x39\xc2\x30\x48\x52\x2d\x88\x0e\xda\xf3\x66\xb5\xe0\x0c\xf9\x69\xc4\x41\x0b\x5c\x05\xef\xa2\x1d\xb4\x27\xe7\x6f\xa9\xde\x8c\x26\x84\x7e\x9b\x8d\x28\xe6\x7d\x65\x3e\x96\x5a\x62\xe2\x5c\x15\x0c\xcd\x8a\x56\x13\x09\x07\x19\xbf\xcc\xed\x73\x13\x2a\xb5\x52\xad\xd5\x2a\x95\x0a\x54\x21\xc7\x35\x28\xaa\xd1\xe3\x26\xb3\x0a\x33\x68\x71\x3d\x66\x50\x63\xca\xa4\xc7\xeb\x58\xb5\x49\xa5\xb1\x28\x0d\x2a\xb5\xca\x24\x47\x51\x33\xa6\xc1\xd4\x5a\x33\x8e\x19\x0d\xb8\x49\xa1\x92\x1b\xb1\x24\x6b\x65\x05\x91\x62\x5d\x74\x92\xf5\xbd\x62\xb1\x37\xb2\x84\x91\xa7\x29\x91\xe3\x9d\x1c\xb7\x24\xb9\x01\x76\x2f\x27\x72\x82\x97\xf3\x43\xc6\x12\x1c\xca\xb5\x51\x2e\x1f\x9b\x08\xbc\x95\xf8\x40\x03\xb5\xd2\xbc\xef\x7d\xda\x6d\xe1\x39\x06\x7a\x31\x61\xc2\xf7\x9a\x0a\x0c\xb8\x06\x53\xeb\x2d\x46\x54\x31\xd0\xb9\x42\xa1\x37\x1b\x31\xbd\xd6\x8c\xea\x55\x26\x8b\x1c\x1e\x60\xdd\xff\x66\x6a\x48\x3e\xa4\x43\xfe\xb1\x2e\xc9\x90\xc3\x64\x49\x3c\xbe\x5c\xfe\x7c\xe8\xd5\xef\x43\xb3\x6e\x12\xe6\xe1\x82\xfc\xda\x53\xbf\xef\x03\x60\x30\x6a\x35\xe9\x9d\xc1\xcb\xad\xf5\xf3\x73\x8d\x33\xb2\x8f\xee\x62\x0a\xbf\x0c\x41\x8b\x72\x53\x6b\x27\xd0\x8d\xad\x6b\xce\x9d\xff\xee\x24\xab\xfb\xe5\xbd\xd0\xd3\xc2\xc2\xc2\x79\xe4\xa3\x8e\xa6\x49\x78\x6a\x73\x5e\x68\xc6\xbc\x5b\xc5\xf5\x13\xc7\x55\xed\x1c\x99\x9a\x79\xb6\xf9\x5e\xef\xc9\xe2\xee\x78\xf7\x7e\xe5\xd8\x29\xbf\xde\x0f\x7c\xf3\xb8\xad\xfd\x34\xf9\xe3\xc3\xbe\x07\x3b\xcf\x60\xb6\xc6\xd1\xd5\x9d\x97\xd3\x3c\xd1\xd1\x3b\xc6\x85\xab\xf6\x36\x86\x66\xce\x44\x32\xd6\x36\x55\x46\xc1\xa8\xeb\xe1\xb1\x31\x59\x4f\x68\x55\x17\xb8\x52\x23\x59\x67\x69\x92\xae\xb9\xbd\xf1\x87\xc3\x4f\x07\x57\x80\x65\x93\x87\x2c\x5a\x35\xb1\x1a\x64\x6c\x6d\xa8\xdb\xe3\xa8\x94\x0c\x6d\x1b\xf4\xa9\x7d\x53\xf4\xc2\x84\xf4\x30\x7c\x87\xac\x49\xd9\x12\xe1\xcd\xcb\xb4\xbf\x1d\x5f\xb9\x0d\xde\xc9\xf7\xdb\xcf\x77\x18\xaf\xf6\x5e\x9a\xc4\x35\xf0\x82\xd7\x1c\x6d\xbb\x18\xdf\xdc\xbe\x22\x32\xa8\xb5\xfe\x4a\xf6\x07\x92\x83\x6c\x55\xce\x8e\xd1\x27\xa6\x92\x60\x7b\xc6\xf1\x23\xdb\x9f\x83\x83\xe4\x61\x78\xf9\xdc\xbe\xd4\x1e\x24\x77\x03\x69\xcc\x1b\xf1\x24\x72\x9d\xd1\x36\x86\xd6\x8f\xbf\x59\x85\x0b\xe2\xa6\x74\xa2\xa3\xe5\x79\x7b\xb4\x4b\x7a\x5d\xaf\x59\x91\x05\xc5\x7e\x62\x9d\xfe\xbd\xe7\x9a\x8f\x19\xe7\xb0\xc3\xef\x5e\x63\x33\x3f\x7c\xb7\xe6\x5e\xe7\xc5\x6c\x49\x1a\x1e\x25\xba\xfb\x53\xbc\x69\xb7\x2e\xfc\x6f\xc5\x93\x9e\x5e\x7b\x2d\x75\xf7\xc1\xd2\x59\xb1\xb5\x0d\xb5\x47\x34\x07\x4a\x23\x6f\x8f\xb8\xd1\x28\xcb\x88\x68\x11\xd0\x3c\x2c\xbf\x4a\x37\xb1\x7e\xd8\xec\xb6\xee\xdb\x8f\x57\x97\xb7\x48\x2e\xd9\x3e\xaa\x8b\xaa\x3f\x2e\x64\xc2\x6d\x57\x5a\xff\x73\xa6\xb3\x2c\x26\xab\xbe\x1d\x5b\x19\xbb\xb3\x8f\x8f\x54\x17\xad\x9c\xbf\x3e\xeb\x8f\xbc\xdd\xd5\x33\x0b\xee\x2d\xd8\xd3\x57\xd9\xd0\x94\xb3\x6e\xea\x56\x4c\xbf\xa7\x60\x4c\x4f\x7a\xc3\xe6\xcf\x22\x59\x69\x59\xa3\xe2\xb2\x9a\x92\x43\x53\x76\x1b\x26\xaf\x8e\x8b\xf6\xd4\x5d\x75\x77\xb7\x15\x42\xc5\xdf\x1f\xba\xa9\x9b\xdd\xf1\xc9\xcf\x81\x45\x5f\x1d\x9c\xfb\xa8\x77\xd6\x7a\x69\x79\xbc\x0b\xfe\xf6\xda\xb9\xec\xcc\x68\xf1\x88\x74\x66\xd3\xc6\x14\xfb\xf3\xc8\xb6\x67\x69\xbd\xa7\x24\xe5\x99\x77\x6e\x4c\x5d\x5a\x7e\x78\xe8\xf4\x7e\xf5\xe0\xd3\x2d\xc7\x96\x77\x1e\x58\x63\xbd\xba\xbd\x2f\xbd\xe3\xeb\x96\x50\x46\xe3\x86\xcd\x43\xfa\x8f\x3a\xe7\x7e\x61\x4f\x13\xe6\x7c\x3e\x26\xa5\x77\xd5\xb2\xf6\xae\x67\xb9\xdc\x78\xa1\x0e\x19\x24\x01\x67\x27\xec\xbf\x1f\x77\x9d\xb8\x91\xb8\x96\xad\xe6\x22\x53\xdc\xb0\xa0\xf2\xcf\x00\x00\x00\xff\xff\xd3\x5d\x7b\x19\x03\x06\x00\x00") func imagesDevicesImage2PngBytes() ([]byte, error) { return bindataRead( _imagesDevicesImage2Png, "images/devices-image-2.png", ) } func imagesDevicesImage2Png() (*asset, error) { bytes, err := imagesDevicesImage2PngBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "images/devices-image-2.png", size: 1539, mode: os.FileMode(436), modTime: time.Unix(1492020681, 0)} a := &asset{bytes: bytes, info: info} return a, nil } var _imagesDevicesImagePng = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x9c\x94\x7d\x50\x14\xf5\x1f\xc7\xbf\xa0\xde\x29\xfe\x44\x7e\x02\xfe\x94\xdf\xd9\xad\xeb\x53\x66\x77\x7b\xbb\xf7\xb0\x77\x1b\x07\xec\x3d\xc1\xa5\xe7\xc1\x71\x0c\x94\x66\x2d\x77\x0b\xb7\xc2\x3e\xb8\xbb\x74\x0b\x93\x0f\x63\x2a\x3e\x65\xa6\xd2\x58\x60\xc3\x99\xcc\x50\x96\xcd\x14\x14\x1a\xa6\xa1\x96\x98\x24\x3a\x4e\x53\xce\xe8\x8c\x63\x6a\xe1\x63\x88\x89\x0d\x3a\xcd\x19\xa7\x4d\xe3\xf8\x47\xdf\xbf\x76\x3f\xf3\x7e\xbd\x3f\x0f\xfb\xd9\xef\xba\xc2\xf9\xf9\xe3\x52\xb2\x52\x00\x00\xe3\xbc\x05\xae\x00\x00\x60\x0a\x00\x40\x33\x5a\x05\x00\xd8\x71\xa2\xed\x43\x00\xc0\x64\xd9\x5d\x26\x17\xf3\x15\x72\x94\x12\x69\x40\x86\xf9\x72\x1a\xf2\xb2\x54\x25\x1d\xa0\xa9\x70\xed\x92\x6e\x3a\x1b\x80\x11\x11\x26\x58\x26\x97\xf9\xe6\x11\x21\x9e\xd5\x53\x71\x8d\x5e\x61\x05\x10\x3f\xd9\xb9\x8a\x40\x85\xaa\x68\x19\x2a\xa7\x2b\x19\xce\x0e\xdf\xf8\xf2\x00\x0c\x31\x61\x3b\x5c\x6a\xf6\x19\x7c\x82\x93\x8e\x30\x05\x75\x22\x5d\x5c\x37\x3f\x18\xaa\xab\x0a\xd9\xc2\x70\x6e\x0e\x94\xad\x10\x0a\x2b\xb0\xb4\x4c\x41\x0a\x5b\xcd\x49\x84\x62\x87\x1f\xf8\x12\x9c\x44\xc4\xc3\x08\x0c\x3d\x90\xc8\x55\x76\xf8\xaf\xa2\xca\x7c\x85\x90\x93\x17\x69\xc8\xac\x37\xea\x42\x06\x14\x85\x2c\x16\x3d\x6a\x32\x5b\x2c\xe8\xb3\x10\x66\x40\x31\xc4\x80\x21\x06\x8b\x0e\x35\x11\x66\x0b\x81\xe1\xd0\xf0\x81\x73\xa0\x6c\x31\x5c\x41\x04\x5c\x9e\xe1\x5c\x62\xb8\xc2\x0e\x47\x64\x59\x20\x10\x24\x1a\x8d\xea\xa3\x46\x3d\x2f\x56\x22\xa8\xcd\x66\x8b\x7b\x60\x98\x4e\x0c\x57\xe8\xa4\x5a\x4e\xa6\x14\x1d\x27\x4d\x4b\x38\xb8\x68\x29\x24\x32\x82\xcc\xf0\x1c\x14\x7f\xa7\xca\xf9\x1a\xd9\x0e\xc3\x89\x16\x58\xc1\xe7\x7b\x68\xcc\x49\xc3\x83\x0a\xf1\x2c\xa2\x50\x02\x82\xea\x0d\x08\xcb\x22\x09\xb5\x24\x07\xe8\x8a\x27\xab\xa5\x60\xad\x40\x23\x01\x5a\xe2\x6b\xc4\x10\x1d\xa0\x2b\xa6\xfd\x2d\xd5\x93\xd1\xb8\x50\xf0\xf9\x08\xbf\xc8\x54\x32\x1c\x55\xed\xe2\x43\x35\x2c\xcd\xc9\x5e\x97\x1d\x56\x58\x41\x1f\x66\xc2\x84\x19\x37\xe2\x36\x9b\xd1\x88\xa1\x98\xc1\x62\x45\x51\x2b\x69\x71\xb9\xcd\x26\x87\xcd\x42\x9a\x1c\xb8\xc9\x98\xf0\x78\x1c\xeb\x26\x0d\x2e\x17\x66\xf2\xe0\x66\xa7\x15\x45\xdd\x26\x12\xb5\xe1\x6e\x14\x77\x38\x1c\x46\x0f\x66\x25\xf1\x04\xeb\xe5\x24\x99\xe2\x42\x74\x82\x65\x1e\xb1\xee\x27\xb2\x84\x53\xa4\x29\x99\x17\x83\x3c\x5f\x9d\xd8\x80\xc2\x08\x2f\xf3\x52\x84\x17\x20\x67\xb1\x05\x7a\xda\x47\x85\x18\x2e\x1e\x98\x1d\xff\x40\xc3\xb5\xd2\x22\xf3\x2a\x1d\xf6\x88\x3c\x0b\x3d\x98\x30\xc1\x3c\xa6\x02\x07\x6e\x35\xe1\xa4\xc7\x89\x62\xc3\x9d\x63\x18\xe9\x76\x9a\x48\x9b\x1b\x25\xcd\x2e\x8f\x01\x1e\x66\xc3\xff\x66\x6a\x48\x0e\x94\x8d\xfc\x63\x5d\x12\xa1\x80\xcb\x13\x7f\x7c\xb8\xfc\x39\xd0\xa3\xdf\x87\xe6\xc2\x76\x58\x84\x73\x73\xc6\x8f\x69\xad\x01\x20\x79\x86\xd7\x45\x06\x95\x33\x9d\x6f\xf7\xcc\x4d\x2e\xca\x38\x92\x8f\xae\x4d\x5b\x90\x31\xa6\xa5\xb7\x2b\x0d\x1e\xbd\x78\x2a\x99\xf1\xd6\xce\x76\x34\x45\xd4\x76\x44\x17\x8c\xfc\xef\xaa\x05\xa5\x45\xbb\x87\xc6\xa6\xe0\x4b\xf3\x26\xb2\x2b\x2d\x0d\x45\xae\xc0\x86\xa3\xff\x69\x7b\x71\x7a\x66\xd1\x61\x59\xbf\x90\xda\xae\xb9\x3c\x19\xd1\x6a\xae\x5b\x6f\x1c\xbf\xd7\xb3\xf1\xce\xd9\xda\x89\x25\x25\x99\x59\xd7\xf7\x57\xff\xaf\x2b\xdb\x94\xda\xee\xf0\xf7\x4e\x6c\xdb\xf6\xff\xdb\x8b\xe6\x4c\xa8\x5f\xdd\x0c\xd6\x08\x9d\xa9\xe6\x92\x9b\x9d\xce\x62\x70\xa3\xe0\xf5\x7d\xa7\x4a\xb9\xc3\x73\x8f\x2e\x3a\x72\x27\xa5\x66\x44\xd3\xd6\xa4\x76\x07\x9a\xde\xdc\x75\x0b\x7d\xc1\xff\x7c\xef\x8a\x66\x1c\x4a\xef\x4b\x1b\x20\xc2\x0e\xe3\xca\x73\x1b\xe7\xfd\xa2\x09\x62\xbf\x35\xfc\x38\x4b\xbd\x7e\xfd\xae\x63\xb7\x9d\xee\x11\xe3\x77\xdc\xf9\xcc\x7f\x8e\xb8\x78\xa9\x77\x5d\x5e\xd5\xc9\xdd\xef\x9c\x70\x4c\x05\x7c\x0b\x5e\xdf\x0f\x3a\xa6\x9c\x1f\x29\x3a\x46\xb5\x6a\x0f\x76\xc2\xb5\x65\xed\xb9\x40\xc9\x2b\xb8\x79\xe2\xf0\x72\xb0\x9c\xac\xbd\x7a\xa5\xfc\xa5\xe6\xe8\x45\xf5\x27\xb3\x06\xb6\x5e\x28\xb5\xc7\xf4\x9b\xae\xdd\x5e\xb5\x49\xd0\x0c\x21\xad\xcb\xba\x95\xb4\xd4\x98\x65\xed\x33\x5f\x8c\xcf\x5c\xf8\x91\x79\x76\x7f\xef\x96\xc6\xd5\x75\x7b\x1b\x5b\x62\xd3\xc5\xfd\x7d\x8d\x87\xd2\xba\x54\xa7\x77\xee\xbd\x3f\x29\x6b\xcd\xdd\x8f\x55\xd0\xd9\xc1\xa4\xd3\xb1\xc6\x7d\xf5\x33\x37\x5f\xe9\xe8\x94\xb6\x7f\xbd\xae\xa4\x35\xe6\x78\xaa\x2f\x40\x6d\xcf\x1d\xb5\x42\x3e\x94\xbf\xf9\xdb\x83\xfd\x05\x7e\xff\x73\xf5\x86\xd4\xc0\xcc\xbb\x9f\xc7\x7e\xed\xbf\x82\x02\x62\x50\xa5\x9e\x27\xea\xd2\x07\x34\x6a\x7b\x32\xbf\x29\xeb\x7e\x72\xdb\xd8\xc1\x0d\xaa\x1f\x8e\x6b\x07\xdd\x67\x4e\x8d\xfe\xb9\x3b\x3d\x78\xcf\x99\x94\x73\xeb\xab\xee\x3d\xbb\x93\x62\xd4\x85\xbe\x09\x3f\x65\xbe\x96\x57\x35\xb0\xab\xf7\x0d\x55\xdf\xf9\x59\x2d\xfb\x22\x19\x47\x8b\x3f\x5d\x62\xf3\xbf\x3b\x69\xec\x90\x6f\x7f\xab\x21\xff\x72\x40\xe9\x99\xd3\xf4\x1d\xb3\x65\x8e\xaf\x67\x6a\xea\xd2\x52\xf4\xa4\x38\xd9\x08\x16\x1f\x28\x34\xe5\x7e\xb3\xec\x7d\xb2\xc9\x7a\x4d\x13\xd1\x79\xc6\x1d\x3c\xbd\x7c\xda\xcd\xa6\xf5\x43\xa5\x57\x37\x4c\x1a\x60\x8f\x69\x67\xbc\xd7\xd0\xe3\x1d\xa9\xc5\xd5\x7f\xbc\xf9\x41\xc7\xf7\xcd\xd0\x25\x4b\xd5\xec\x09\xbf\xab\xef\xd6\x35\xdc\x2a\x5a\xa4\x95\xb6\x69\x93\x54\x40\xfd\xf2\x81\x8d\x99\xb1\x72\x29\x7e\x15\x7b\xdd\xf3\x5d\x7b\x1c\xaf\xac\xfc\x33\x00\x00\xff\xff\xcb\xa3\xb9\x1c\xf7\x05\x00\x00") func imagesDevicesImagePngBytes() ([]byte, error) { return bindataRead( _imagesDevicesImagePng, "images/devices-image.png", ) } func imagesDevicesImagePng() (*asset, error) { bytes, err := imagesDevicesImagePngBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "images/devices-image.png", size: 1527, mode: os.FileMode(436), modTime: time.Unix(1492020681, 0)} a := &asset{bytes: bytes, info: info} return a, nil } var _imagesLogoRobeauxPng = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x9c\x97\x79\x38\xd4\x7b\xdf\xc7\xc7\x12\x42\x8b\xb5\x10\xc6\x58\x42\xcc\x66\x16\x33\xcc\x88\x19\x44\x33\xb6\xec\x5b\xc6\xcc\x60\x30\x4b\x33\x83\xa1\x30\x1c\x4b\x3a\x5a\x2d\x15\x59\x8a\x88\xa4\xa4\x4d\x84\x53\x96\x8c\x0a\x09\x27\xca\x92\x24\xa7\xa2\x11\x11\xe2\xb9\x3a\x4f\xdd\xf7\x73\x3d\xd7\x7d\x9d\x3f\xee\xef\x5f\xbf\xdf\xe7\x7a\xbf\xde\x9f\xe5\xf7\xf9\xfd\xf1\xcd\x72\x73\x71\xdc\x22\xaf\x29\x0f\x00\x00\xb6\x38\xed\x23\x7a\x00\x00\x80\xcb\x00\x00\xc0\x58\x4e\x06\x00\x00\x94\x6c\xc2\xbe\x02\x00\x00\x1a\x7c\x7b\x5f\xfe\x01\x76\x18\x3f\x8e\xc2\xa5\x03\x6c\x69\xec\x50\x3a\xd0\x89\x49\x09\xa7\x7b\xd0\x29\xb4\xf8\x43\x5d\x74\x6b\x00\x40\x2a\x82\xe1\xe9\xcb\xf7\x25\x93\xb0\x54\x36\x13\x4c\xf9\xa1\x01\x0b\x98\x1c\xc0\x8f\x63\x6d\x23\xe0\x50\xa8\x51\x74\x3e\x30\x94\x1e\xce\x60\xe1\x40\x73\x8d\x2d\x20\x20\x83\x86\x03\xf9\x20\xc9\x50\x32\x87\x40\x8f\x60\xec\x4b\xe0\xd2\x0f\x24\xb8\x78\x52\x13\xa2\xa8\x18\x1a\xc8\x06\x0f\xb4\x16\x60\x05\x4c\x0e\x93\xce\xa7\x00\x05\xcc\x68\x16\x0f\x2b\xc0\x81\xfe\xf6\xc5\xb2\x78\xd8\x1f\x61\x08\x08\xf8\xb7\x84\x1f\x85\x03\xfd\x6f\x51\xbe\x64\x37\x20\x81\xcd\xa5\x03\x91\x60\x0b\x73\x2a\x14\x06\x03\xa2\x50\x60\x18\x02\x89\x42\xc1\xcc\x80\x70\x28\x0c\x0e\x81\xc2\x21\x50\x94\x39\x0c\x81\x45\xa2\xb0\x70\x34\xf0\xe7\x01\xe1\x81\xd6\x5c\x5a\x18\xd6\x83\xe8\xf0\x33\x17\x97\x16\x86\x03\x45\xf0\xf9\x1c\x2c\x04\x12\x17\x17\x07\x8e\xb3\x00\xb3\xb9\xe1\x10\x18\x06\x83\xf9\xe1\x01\x87\x9b\x73\x69\x61\xe6\xbc\x78\x16\x9f\x22\x30\x67\xf1\xf4\x7f\x39\x10\xe9\x3c\x2a\x97\xc1\xe1\x33\xd8\x2c\xe0\x8f\x77\x4a\x28\x3b\x86\x8f\x03\x81\x7e\xb5\xc0\xe4\x90\xc9\xff\x32\x66\xf1\x7e\x0e\x8a\xca\x66\x42\x04\x14\x0e\x04\x06\x86\x42\x98\x4c\xc8\x2f\x35\x8f\xef\x41\x0f\xfb\x67\x35\xcf\x33\x9e\x43\x87\x78\xd0\x79\xec\x18\x2e\x95\xee\x41\x0f\xd3\xff\x3f\xa9\xfe\x19\xfd\x21\xe4\x90\xc9\x58\x57\x2e\x23\x9c\xc1\xa2\x44\x13\xd9\xd4\x18\x26\x9d\xc5\x77\x22\xe2\x40\x02\x26\x07\x4c\x63\xd0\xb0\x48\xb4\x05\x1a\x83\xb1\xb0\x80\xc3\xe0\x50\x94\x25\x0c\x66\x69\x8b\x22\xda\x23\x11\x76\x18\x94\x2d\xc2\x0e\x8d\xb0\xf8\xe5\xf1\x9f\x58\xa8\x03\x8a\x88\x46\xc3\x2d\x91\x0e\xb6\x68\x18\xcc\x1e\x61\x8b\x20\xa0\x6c\xd1\x68\x18\xc6\xd6\xde\xce\x12\x66\x09\xfd\xc5\x3a\xb1\x78\x7c\x0a\x8b\x4a\xff\xc5\x32\xfe\xcd\xa2\xff\x91\xc5\x12\xb8\x74\x0a\x9f\xcd\xf5\x64\xb3\xa3\x7f\x6d\x80\x5b\x04\x9b\xcf\xe6\x45\xb0\x39\x40\xc2\x01\x14\xd0\x98\x4c\xa1\x32\x58\x3f\x02\x26\x3f\x3e\xd0\xcf\x5a\xe9\x5c\x46\x2c\x9d\xe6\xc0\x65\x33\x81\x7f\x4f\x18\xcb\xf8\x0f\x15\xd8\xa1\x2d\x11\x68\x5b\x07\x02\x0c\xfe\xb3\x73\x38\xdc\xd6\x9e\x80\xb0\xc5\xd8\xc3\x6c\x91\x44\x07\x28\xe8\x27\x4b\xfb\x6f\xa6\x06\xc1\x03\xad\x21\xff\x6f\x5d\x7e\x85\x3c\x88\x0e\x3f\x1e\xff\xb5\xfc\x78\xe0\xbf\x7f\x1f\x3a\x8b\x86\x03\x71\x41\x36\xf8\x2d\xcf\x03\x5e\x01\x00\x0a\xa7\x9c\x88\xb6\x9e\x82\xe1\x8f\x81\x0a\xa7\x3c\xdb\xd5\x8a\x52\xd4\xd4\xdc\x50\xc0\x4b\x12\x69\xc6\x44\xa0\x31\x30\xf9\x62\xea\x1e\x79\x3d\xf9\x4d\x67\x8e\xea\x6e\x57\x56\xa9\xba\x92\x45\x34\xd4\x85\xa5\x52\x94\x6c\x73\x6e\xca\x69\x7a\x8a\xa4\xc9\x7a\x32\x76\xbd\x11\xd0\x3d\x0e\x40\x13\x83\x8c\xc7\xa0\x8d\x93\x42\xa1\xed\x43\xb6\x6d\x7e\x50\x73\x0e\xaf\xe8\xcb\x67\xee\xa7\xa5\xf3\xf4\xb0\x63\xa6\xa3\xd7\xb0\x48\xf6\xfd\xd5\xd8\xa5\xc3\x89\x95\xab\xeb\xa3\xaa\xe5\x1e\x55\x44\xf8\x79\x92\x67\x5e\x6b\xb2\x06\x3e\x41\x22\x28\x45\x7d\xaf\x4a\x29\xd8\x2d\xa4\x40\x47\xe2\x2b\xa0\x30\x45\xad\xb5\xb1\x35\x30\xfb\xfb\x18\x91\x04\x33\x71\xf6\xb6\x37\xfe\xe3\xc0\x16\x5d\xb4\xd4\x92\x44\x90\xe7\x40\xb0\xfc\x6b\x56\xe9\xab\x1b\x03\x32\x60\x40\x81\x64\x4c\x53\xad\xf0\x5b\x2b\xf1\xc9\xc4\x53\x01\x26\x74\x5e\xda\xac\xff\xeb\xb5\x14\xc3\x2a\x84\x97\x64\xb2\x24\x4b\x56\x33\xfc\x66\xa3\x24\x21\x65\x28\xa5\xec\xe3\x55\x83\x1c\x7c\xe8\xb1\xf4\xe7\x51\x23\xdb\x2c\xe5\x76\xc9\x16\xcb\x80\x9f\x3d\x5c\x7e\x2a\xd4\x50\x7d\x52\xb4\x77\x5a\xe0\x15\x7a\x31\x7b\xb8\x16\xcd\xc9\x4e\xed\xc7\xc9\x7e\xb9\x97\x25\xd9\xa2\x7b\x0f\x1e\x7c\xde\xd7\xf8\xd1\x30\x42\x5a\x24\x0c\xba\x59\x3f\xc5\x01\xbf\xae\x52\x8e\x96\x8c\xec\xb8\xaa\xa2\x40\x77\x2b\x64\x58\x07\xff\x3e\x0f\x2d\xb1\xc2\x0c\x42\xde\x0c\x64\xa5\x3f\xbf\xde\x2c\xc1\xd9\x29\xd0\x77\xfd\x52\x25\x53\xb3\x29\x16\x80\x7c\xa3\x86\xfd\x72\xc5\x3f\x0d\x25\x25\xac\x17\xda\xec\x9c\xc0\x9c\xf5\x5e\x62\xa7\xd4\xb5\x1e\xf7\x88\xad\x56\x71\x36\xca\xe9\xc4\x0c\xa6\xef\x75\x6f\x22\x8a\x5d\x66\xaa\x93\x8f\x0f\xc6\x5e\xec\xfb\x8e\xaa\x6c\xde\xb7\x2a\xcc\xf2\xaa\x13\xcd\xac\x2e\xd4\x8e\xd4\xb5\x38\x89\xe5\xdb\xed\x66\xaa\x77\x4c\x86\x5d\x5e\x19\xcd\x55\xe7\x6e\xef\x3a\xb4\x61\xdd\x6b\xaf\x50\xe8\xba\xf1\xa6\x75\xae\x5b\xbf\x51\xa3\x5b\x5e\xc8\x15\x67\x16\x3f\x4c\xbc\x4d\xb6\x2f\x23\xb4\xaa\x87\xa8\xe3\x00\x5d\x66\xf8\x91\xca\x17\x96\xf4\xba\x5b\xf6\x65\xa9\xa7\x32\x13\x94\xf0\x7f\x49\x60\x87\xe7\xa9\xe3\x4d\xa7\x92\xa6\xee\x6d\xe8\xd4\x69\x7f\x6f\xfa\xad\x67\x03\x10\xa0\x3c\xe3\x56\xf6\x62\x3f\xbf\x52\x9f\x23\x35\xee\xb7\x10\x27\x69\xd3\xa9\x04\xde\xba\x48\xbf\xc7\x82\xd8\x3d\xd5\xc7\xf9\x18\x24\x44\x51\x43\x81\x37\xe4\xa8\x49\x0a\x54\xd6\xc9\xf6\x49\x84\xaa\x73\x2f\x7d\x2d\xf0\xba\xa8\xb9\x78\x62\x27\x37\x77\xcc\x21\xcd\x7d\x77\xcc\x03\xf0\xe9\x13\x95\xbf\xdf\x38\x92\xdb\x19\xce\x45\x7e\xbe\xf3\x71\x7e\xfb\x93\xef\x75\x47\x2f\x24\xd9\xcd\x7c\x0a\xf1\x37\x6e\xa6\x0d\xef\x6b\x6a\x94\x5c\xe6\x66\x50\xf7\x83\x3a\x1a\x2a\x5a\x14\x06\x16\xc3\x92\x50\x3d\x67\xdc\xd6\xbb\x3f\x2e\xeb\x14\x3d\xd5\x6e\xac\x34\x8d\xda\x6c\x2d\xbd\x66\xa6\x7e\xba\xdf\xd5\x18\xa7\xf7\xb2\x4a\x64\xfa\xcd\xc4\x51\x1c\xd4\xaa\x57\xaa\x9e\x1e\x6d\xdd\x6b\x55\xde\xd3\xd2\xa5\x44\xd6\x03\x57\xba\x59\xcb\x06\x86\xbe\x48\xd5\x8e\xac\x7c\x2a\x63\xde\xf1\x0c\x6d\xb4\xd7\xeb\xb4\x74\x8e\x8f\x67\x1f\x27\xf7\xb8\x64\x4f\x9d\x2f\xc9\x05\x72\x71\x21\x8d\x98\xad\xdd\x50\x5b\x1b\xeb\x70\x48\x0d\xa7\xc0\x07\x74\x48\x2a\xd7\xeb\x74\x16\x5d\xcf\x71\x4d\x9e\x93\x38\xd9\x25\x96\xdb\xb5\xc9\x48\x72\xe8\xe6\xf5\xe4\x63\xbf\x1f\xf3\x5e\x57\x5a\x24\x18\x3f\xe9\xfc\x4d\xf8\xf9\xbb\x12\x35\x59\xf6\xec\x98\xdb\xe4\x1d\xc9\x7c\xab\x85\x8f\xa0\x6a\xb5\x51\x13\xb8\xee\x9a\x15\x1c\x2a\xac\x6d\xed\x5c\x14\x2e\x18\xca\xf4\xca\xb6\x4a\x2e\x88\x19\xd2\xdb\xec\xd1\xa5\xb2\xbd\x47\x3f\xd4\xed\x4f\xe2\xcc\x93\xfe\x48\x06\xa6\x6d\x58\xcf\x07\x77\xad\xe6\x84\xaf\x6d\xfb\x6c\xfe\xb5\xc9\xd4\xd9\x08\x55\x7a\x44\x4b\x54\xeb\x1e\x74\xc4\xfb\x5d\xb8\x6f\xf5\x6d\x53\x42\xa3\x47\x7f\x49\x2f\x3c\x77\x0e\x79\xe4\xa6\x46\x50\xf5\x31\xd1\x91\x6b\x6c\xa3\x83\x35\x95\x53\xc6\x7e\xb8\xcb\xa2\x33\x17\xe4\x49\xe3\x8b\xfb\x56\xcc\xa2\x24\x79\x29\x12\x12\xf9\xb5\x2f\xae\xd1\xd6\x9a\xd0\x9d\x33\x4f\x9a\x2b\xaa\x63\x79\x6f\x29\x9f\x13\x34\x7a\xf5\x15\x06\x97\x0e\x28\x09\x3a\x34\x8b\xa3\xb2\x87\x28\xea\xaf\xa9\xf9\xe5\xd1\x46\xbd\x06\x8f\x57\x64\xfc\x01\xbf\x1f\x29\x3e\xfe\xe2\xa4\x64\xf5\xea\x93\x4f\xfe\x21\x5e\xad\xf5\x6a\xeb\x87\x13\x05\xed\x85\xb0\x0c\x66\xe0\x82\x0e\xc7\xe4\x73\x95\xa9\x96\xed\x68\xae\xf9\x17\x0d\x6a\x73\x24\xba\x84\x9e\xa3\xb8\xb1\x3f\xa3\x12\x3b\xe4\xd3\x0f\xad\x74\x9b\x37\xda\x7a\x25\xe3\x78\xb6\xdb\xe8\xb6\xa3\xb0\x1b\x7d\x9f\x1f\x18\x77\xa9\x4a\x6c\x7b\x76\xf5\x70\xc7\xe7\xa7\x61\x25\xfe\xc6\x23\x55\x73\x5a\x5f\x0c\x72\x2d\x14\x5d\x0f\xe7\xdf\x9d\xde\x66\x92\x5d\x4e\x96\xd5\xbd\x58\x43\xcb\x35\xcd\x0e\xce\x9b\x66\xbf\x8b\x91\xcd\xa1\x5c\xea\x25\x3e\x3a\x8c\x82\x42\x24\xc7\x1c\xce\x02\x8a\x2f\xb9\x0d\x7a\x6a\x15\x3a\x06\xa9\xf5\x6c\x23\xbd\x8e\xf2\x98\x9d\x26\xd4\x90\x71\x7d\x65\x52\x5b\xaf\x1e\x41\x02\x1b\x3b\x81\xf2\x87\x24\x62\x7a\x33\x24\x3e\x8c\x9e\x92\x21\xe9\xde\x62\x3f\xca\x72\xba\xb3\xd2\x29\x7a\x6e\x03\x0b\x8f\x09\x42\x6f\x5b\xf7\xc7\x24\xad\x5c\x05\xf5\xe5\xf9\xb8\x17\x2d\x5b\x04\xf9\xae\xc4\xe7\x02\xd8\x86\x2e\x2e\x61\xf9\x28\x90\xe7\xe2\x11\x45\x53\x57\x47\x1b\xb3\xda\xdd\x5f\xeb\x46\x6e\x7d\x70\xbc\x5b\x88\x86\x60\x22\x4b\xd0\x51\x86\x4d\x2a\x42\xf7\x56\x44\x3d\x5e\x9f\xac\x3e\x14\x41\x6d\xdb\x6c\xbe\xa9\x02\x00\x01\x14\xfa\x7e\xcd\xdb\x75\x85\x28\x2b\x86\x49\xf7\x82\x1f\x38\x29\x1a\x76\x17\xa8\x5f\x9d\xc7\xdd\x72\x7f\xfe\x8c\x37\xbe\x2b\x44\xee\x64\xf4\xa1\xb0\x1d\x9a\x9b\xc1\x08\xab\xa9\xe0\x59\x62\xb0\xe7\xb4\xce\x6c\x2c\x1a\xea\x37\x74\xd2\x79\xe7\x09\xd5\xcc\xc5\x58\xf9\x85\xb1\x97\x3e\xe7\x5f\x9a\x8c\xf8\x77\xd6\x9b\xa1\xa0\x9a\x82\x5c\x74\x5e\x97\xcb\xb7\x1d\xa5\x2d\x52\x77\x01\xae\x05\x39\x13\x6d\xee\x8f\xa8\xae\xfd\x7b\x5a\xbf\x45\x5e\xb8\x4f\xf2\x1e\x5c\xb8\x47\xad\x7c\xb1\x14\x5b\xf7\xe6\xfa\x1f\xd4\x80\x7e\x30\x64\xb6\xc7\x20\xf2\x9a\x91\x22\xef\x55\x14\x55\x06\x60\x9d\xe0\x87\xbb\x2e\xef\x05\xae\x4a\xf9\xae\xed\xf8\x3e\xa2\xd3\xda\x35\xbe\xd2\x33\x66\x92\x6c\x73\x86\x6f\xf1\x32\x37\x31\xc0\x42\x6e\xbd\xda\xd4\xfe\x7a\xa4\x32\x28\xd7\x24\x69\x0e\xa0\x28\xd3\xe6\xc1\x2c\xbb\x99\x95\x1a\xa1\x39\xb2\x75\x37\x5b\xd6\x71\xcc\xdb\x78\x49\xbc\x1a\xe8\xf5\xd5\x21\x1f\x84\x05\xaf\x94\x9c\xdd\xc4\x3e\x71\x3b\x86\xbb\x0b\xdb\xa1\x5c\xb4\x42\x18\x98\x55\x59\xbf\x77\xcd\x0d\x2c\xde\x0f\x3f\xf4\xfe\xa0\xfd\x47\x1f\x85\x81\x39\xa9\xd9\x25\xf0\x00\xcb\xa6\x5b\xa6\x10\x3f\xb7\x65\xbc\x24\x8f\x70\x51\x55\x2d\xb4\xa1\x7a\xec\xda\xa8\xe5\xf6\x02\x8a\x95\xca\x2e\xd8\xfd\x9e\x7c\x39\xbb\x99\xd3\x8a\x5f\xc1\x71\x05\xe1\x42\x47\x90\x59\xc2\xa6\xf8\xfc\xd5\x17\x01\x17\xcd\xa6\x97\x13\x52\xee\xbc\xdb\x67\xec\x23\x75\x90\xaa\xbb\x85\xf4\xda\x55\xaa\x43\x8b\x31\x8c\xe2\xc9\x4d\x7d\x92\x58\x3b\x78\x5b\x52\x3a\x90\x2e\xda\x3a\x4f\x3c\xf4\xc7\xec\xc2\x96\x5c\x58\xc1\x1b\xcd\x21\xf9\x9d\x2d\xc6\x3e\x76\x55\x83\x93\x47\x27\xe3\xd9\x77\xff\x3a\x51\x59\xf9\x3e\xa8\xf2\x1c\xf8\xb7\x2b\x2f\xb0\xa7\x93\xe2\xa3\x2b\xde\x5b\x28\xea\x65\xf4\x61\xde\x32\xb4\x0f\x65\xeb\xf7\xba\x12\xa7\xfb\x31\xf9\x2d\x5d\x37\xe5\x0d\x12\x0a\x76\xe9\xf9\x84\xd4\xe4\x6d\x0d\x6f\xee\x1d\x06\xac\xab\xbd\x3b\x2c\xe5\x58\x38\x20\xb1\x32\x84\x3d\xe0\xd9\xa3\x74\xe5\x54\x08\x41\x5b\xf7\x05\xf7\xd6\x40\xc2\xe7\xd8\x6c\x77\x1d\xe8\xc6\x6d\x4c\x6c\x43\x9e\x47\xe6\x6d\x84\x4c\x4c\x63\x50\x92\xb3\x5f\x76\x73\x6b\x12\xe2\x5c\xa5\x45\x2a\x1c\x28\x6e\xcc\xf3\xa8\x53\xcb\xe4\xc5\x65\xea\x7a\xae\x25\x2d\xba\x4e\x74\x10\x97\x0a\x8b\x9a\x49\x49\xe7\xf4\x56\x55\xb1\x9f\x5c\xad\xb3\x89\x2b\x4c\xd2\xc9\xb6\x71\x7f\x93\x43\x71\x5e\xde\x94\x15\x4b\x9b\xd2\xe4\x3d\x7b\xa7\x94\x86\xdf\x17\xb5\x0d\x6a\xf3\x77\x9e\x93\x9d\x79\x74\xdc\xae\xf3\xe5\x68\x19\xf6\x92\x87\x70\x0d\xce\x59\xe3\x2f\x94\x45\x6a\x7f\xd8\x94\xed\xb3\xe7\xed\x5b\xe5\x98\x88\x53\x65\xce\x2e\x69\x8c\x73\x3e\x53\x4e\x76\x59\x92\x0d\x7d\x2f\xc3\x60\x27\xfa\x30\x85\x47\x97\x81\xd6\x57\x0f\x4b\x00\xef\xf7\x7c\x38\x81\x1a\x80\x6f\x17\xc9\x0f\x21\xdf\xdd\xaf\x3b\x06\x4f\x94\x6b\xa2\xff\xa5\x87\xdb\x2b\xbb\x4c\x8e\x74\x1f\x55\x3d\x9b\x9e\xb0\x23\x51\xa1\xf3\xeb\x3c\xd1\x30\xfe\xad\x7d\xc9\xfa\xea\x95\xa8\xf8\xd8\xda\xf8\xad\xb4\xf1\x56\x7b\xa9\x27\x4b\x8b\x1f\x09\x69\x8f\xbb\x03\x35\x4f\x36\xa8\x85\x8f\xbb\x2f\x3f\x5e\x2b\xbd\x0f\xdb\x37\x71\x49\x2b\x51\x14\xd7\xd7\x55\x12\x22\x6c\x43\x9e\xd8\xc9\xfa\x64\x77\x61\xbd\x5f\xb9\xa4\xc5\x9f\xe9\xea\xbf\xf9\xca\xab\xe4\x33\x2e\x33\xfd\x7d\x04\xa1\x60\xe1\xf7\x6f\x0f\x10\x79\x36\x05\x04\xc2\x04\x26\xfe\xc6\xa5\xb6\xe9\x87\xae\x4e\x36\xc3\xa0\x4c\x09\x1f\xc7\xdb\xf1\x03\xbe\x2d\x63\xfc\x05\x5e\x91\x58\xbf\x79\x92\x9a\xa8\x5b\x3f\x08\x19\xb9\x5d\xde\x7e\xed\xc0\x86\xbc\xdf\xdd\xb6\x9d\x72\x4f\x13\x67\x97\x94\x5d\x77\x78\xd3\x3f\x69\x2f\x79\xbf\xb7\x58\xc7\xeb\x16\x71\x4f\x34\x6c\x04\x67\xdc\xcd\x88\x77\x00\x13\xa6\x25\x0e\x6c\xa4\x36\x40\x2e\x16\x5f\xb4\x9b\x39\xb7\x7c\xc6\x5a\x7e\xea\x63\xf4\xb2\x76\x99\x65\x8f\x7b\xf0\xd8\xc4\x78\xe2\xfe\x06\xda\xfd\xf3\xd8\x3a\xcd\x92\xbc\x05\x54\xe8\x31\x42\xca\x9c\xda\xb8\xf2\xfc\x25\x9b\x47\xef\x95\x0b\x89\x04\x97\x7e\x55\x64\x8b\x6d\x85\x0b\xd7\x4f\x77\x7a\xe4\xb2\xf6\x4e\xc3\xc2\x27\x11\xd9\x96\x73\x56\x05\xab\x01\xd1\xcb\xe8\xbe\xf4\xdd\x4d\x41\x29\x99\x89\x20\x9c\xfe\x91\x0e\x1b\xe2\x6f\xde\x66\xab\xab\x47\x50\x57\xbf\x0d\xf7\x38\xeb\x9c\xc4\x57\x4c\xbc\x1a\xb6\xbe\xcb\xdc\xed\x79\x4e\x31\x8d\x4b\xd2\x49\x9f\x77\xfc\xa6\xec\x7c\x87\x39\x7b\xf4\x4f\xd2\x92\x72\x92\x89\xb4\x3b\xe3\xa6\x2b\x71\x3a\x82\xb8\xbe\x65\x58\xb6\x5b\x85\x1a\x26\x33\x39\x47\xb5\x7e\x39\x39\x27\x2a\x42\x67\x9b\x26\xa6\xdd\x04\x02\x11\x91\x2a\x8d\x4c\xa2\x63\xa0\xad\xee\xb9\xd8\xef\x52\xb4\x48\x87\x0a\x3b\x13\x97\xc1\x50\xdd\x7a\x7c\x80\x81\x02\x1a\xac\xf5\x72\xec\x7c\x86\x86\x7b\x32\x32\x08\x5c\x50\xec\x96\x2a\x8e\x78\xfc\x46\xc4\x8b\x27\x75\xd6\x1e\x77\xab\x95\xd0\x51\x6c\xd8\x48\xaf\xf5\x71\x12\x10\xf1\x9f\x54\xe2\x86\xf8\xad\x8b\xbf\xe5\x17\x69\xfd\xa9\x02\x5f\xb2\x7a\xa2\xb5\x49\xff\xd6\x33\x39\xb3\xc5\x09\xdc\xb3\xd5\x0b\xe3\xdb\x45\x07\x31\xe9\xb3\xb4\x8d\x29\xf9\x0f\xa8\xee\xe5\x96\xb4\x65\x51\x2a\x49\x70\xe3\xe4\x1b\x7f\xb5\xea\xd2\xfd\x0c\xc9\x77\x37\x4d\xf7\x53\x08\x2f\xcd\x93\xaa\x8e\x39\xf7\x2e\x2d\x6c\x2f\x6e\x46\x38\x20\x70\x92\xcd\xe6\x35\x67\xdd\x5e\xc5\x69\xdc\xf9\xa2\x68\xb5\xf9\xf4\xb1\xad\xdf\xac\x6e\x8d\x84\xac\xe4\xb4\x85\xb9\xca\x06\x1c\x4f\xf0\xbb\xc7\x52\xac\x8c\xa9\x10\xeb\x4d\x20\xe3\x3f\x4d\xd2\x9f\xc1\xd4\xa0\x2d\xde\xbb\x5a\x8e\xfa\xd9\x21\xcf\xdf\x36\xf4\x73\xf8\x22\x3c\x5b\x73\xd8\x5e\x7c\xec\xf0\x7b\x56\x06\x2c\xa0\x4f\x90\xf3\x31\xa1\x0b\x56\xd4\x56\x53\xbc\x3b\x4f\x8b\x81\x15\x39\xf3\xf1\xd2\xf8\x8c\x33\x2d\xb0\xa1\x9a\xdc\xa5\x07\x69\xd8\x89\xed\xa8\x83\x52\x24\xba\xba\x2f\x52\x0d\xb5\xbe\x79\x78\xf6\x56\x02\x04\x9f\xb4\xd3\x64\xff\xe3\xe9\x8e\xd9\x77\x84\xc5\xa4\x07\x0f\xae\xf4\xd4\x54\x3d\xac\xbd\xe7\x05\x52\x6d\xdd\x5b\xe1\x19\x9f\x25\x7b\xd7\x30\x54\x84\xa1\x7f\x09\x2a\x0f\x24\x81\x23\x1b\xe7\xbe\xc8\x5d\xd1\x0d\x81\x2e\x94\x15\x43\x33\x21\xa9\xda\x53\xa7\xef\x66\xb0\xed\x45\xe2\xd8\xfa\xc1\xf8\x5d\xf7\x8b\xde\xa3\xbe\x87\xd6\x61\xea\x93\x61\xa7\x93\xbc\x10\xd2\x61\xd3\x14\x7c\x49\xba\xee\x64\x5e\x56\x3a\xbc\x86\x6c\x9e\xa7\xfd\x42\x34\x88\x2e\xb8\xfb\x6e\x85\xd4\x41\x5c\xad\x17\xb2\xf0\x1d\x0e\x97\xcf\xba\x6d\xef\x3f\xef\xe4\xbe\xae\xa7\xff\xc7\xb9\xaa\xb6\x8c\x76\xf1\x0a\x7e\x43\xad\xec\x32\x0a\x04\xa4\xed\x4f\x09\x48\x49\x05\x50\x6a\xb6\xec\xab\x2d\x4d\x93\xeb\xd4\xd8\x7d\x5d\xb0\xb6\xc3\xe8\x79\x7c\xa6\xa1\xf8\xf9\x85\x06\xd5\x97\x2b\x0e\x8d\xdd\x2a\x33\xc9\xaf\x1f\xec\x53\xeb\xd6\x4a\xb5\x3f\x3e\x16\x7c\x95\x5a\x53\x28\x51\xf7\xe6\xed\x5c\x59\xf2\x53\x78\x9f\x92\xa1\xdf\x64\x71\xdb\xb4\x78\x6c\x53\xc0\xe1\x60\xb0\x7a\x53\x9a\xfe\x88\x71\x92\xd2\x9f\xb3\xe7\xfa\x77\x8b\xe7\xdb\xac\xe8\x7f\xb2\x4c\xfc\x0c\x8a\x94\x77\xb7\x54\x0c\x9f\xb7\x2a\xac\xa8\x10\x5a\x9e\x9a\x62\xb6\xeb\xb4\x79\xb5\x3e\xca\x82\x18\x19\x04\x86\x48\x7b\x8c\x1a\x7d\x54\x56\xa0\x99\xe5\x66\x29\x4a\xf3\xf6\xf4\x66\xa6\x1a\x25\xb5\x3b\x97\x54\x9c\x59\x2e\x3d\x48\x56\xd3\xee\x83\x54\x11\x3c\xa5\x9c\xb8\xef\x8f\x36\xb3\x25\x62\xdb\xbb\x95\x15\xe8\xef\xc2\x93\xe0\x0d\xdb\x4f\x2d\x95\xb7\xe3\xca\x0f\x2a\xe4\x0d\x41\x74\x49\xe5\x45\x57\x37\x5c\xca\x2d\x0e\xca\x44\x37\xd6\xb6\xaf\xbe\xb2\x2d\x29\x15\x26\x18\x34\xb2\x13\x17\x90\x9e\xbb\x6e\x88\xb9\x6d\xb9\xa7\x5d\x34\x42\xc9\xd7\xcb\x5b\xc9\x99\x00\x9d\xad\x8c\x3d\x1d\xcf\x39\xa5\xe6\xc3\xa3\x9a\x10\x5b\x52\xfe\x3a\xa4\x15\xb0\x55\x45\xf0\xdc\x61\xec\x09\xee\xc7\xad\xd7\xc9\xde\x85\x58\x6b\x17\x92\xfa\x3f\x01\x00\x00\xff\xff\x57\x39\x99\xdd\x62\x0f\x00\x00") func imagesLogoRobeauxPngBytes() ([]byte, error) { return bindataRead( _imagesLogoRobeauxPng, "images/logo-robeaux.png", ) } func imagesLogoRobeauxPng() (*asset, error) { bytes, err := imagesLogoRobeauxPngBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "images/logo-robeaux.png", size: 3938, mode: os.FileMode(436), modTime: time.Unix(1492020681, 0)} a := &asset{bytes: bytes, info: info} return a, nil } var _imagesRobotsIcon_03Png = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x9c\x55\x7b\x54\x13\x67\xfa\x1e\x8b\x3f\xe4\x26\xd6\xcb\x8f\x85\x8a\xee\x34\x28\x8b\x96\x24\x33\xb9\x0c\x66\x36\x09\x04\x92\x41\x90\xc4\x18\xb2\x35\x2b\x6b\x35\x97\x09\x19\x93\xc9\x4c\x93\x01\x42\xa8\x8a\xa1\xb8\xe0\x8a\x5a\xad\x59\x84\xc5\x53\xa4\x58\x56\xa1\x45\xb9\xb8\xdc\x2c\x15\x05\xb5\x54\x4b\xd5\xca\x2a\x02\xae\x97\x56\xdd\x1a\x51\x7a\x55\xdc\x3d\x71\xc1\xdd\xb3\xa7\xc7\x3f\xf6\x3d\xe7\x3b\xe7\xfb\xde\xf3\x3c\xcf\x7b\xf9\xde\xef\x7c\xa5\x6a\x55\xea\xcc\x90\x57\x42\x00\x00\x98\x99\xb6\x5c\xae\x01\x00\x60\x91\x7f\x05\x05\x02\x00\x70\x1d\x28\x2f\x07\x00\x20\x8a\x51\xe8\x98\x4c\xca\xcc\xe4\xe9\x1d\x38\x20\x33\x51\x06\x1c\x4c\x23\xf5\xd9\xb8\x06\xd7\x9b\xf2\xdf\x3c\x83\x8b\x01\x20\xc0\x42\x68\x75\x8c\x4e\x99\x81\x1a\x29\x92\xa3\xf7\x63\x38\x2e\x92\x06\xfc\x26\x4e\x74\xd1\x7a\xa3\x15\x67\x40\x03\x9e\x4d\xd8\x25\x2c\x5f\xc7\xc7\x2c\x90\x30\x49\x58\xab\x85\x4a\x48\x49\xa7\xe0\x16\x62\xb9\xdb\x81\x67\xba\x55\x5a\xa3\xdb\x6a\x14\x99\x58\x89\x52\x50\xec\x42\x5d\x24\x4d\xe2\x8c\x1e\x74\x91\x36\xbb\x13\x75\x49\x58\xcf\x74\x51\xbb\x13\xf5\xbb\xb9\x2c\xf0\x19\x84\xb1\x4a\x58\xff\x4a\x4a\xa7\x54\x83\x29\x94\x03\x07\x85\x1c\x3e\xdb\x08\xc1\x30\x88\x20\x1c\x58\x20\x44\x10\x38\x1e\xe4\x41\x30\x8f\x0b\xf1\xb8\x10\xc2\x86\x05\xa8\x10\x41\x79\x09\xe0\xa4\xb1\xa4\xa0\xd8\x61\x32\xa3\x1a\x39\x36\x19\xcb\x61\x32\x4b\x58\x16\x86\xa1\x51\x2e\x37\x2f\x2f\x8f\x93\xc7\xe7\x50\x8e\x6c\x2e\x2c\x12\x89\xfc\x1a\x3c\x1e\xdb\x61\x32\xb3\x9d\xf9\x76\x46\xef\x62\xdb\x9d\x31\x53\x0a\x72\xdc\x69\x74\x10\x34\x43\x50\x76\xd0\x7f\xd6\x1b\xa8\x1c\x46\xc2\x62\x4d\x95\x40\xd2\x4a\xe5\x73\x61\xbb\x73\xb2\x51\x46\x8a\xe4\xba\xf4\x34\x17\xe6\x40\x5c\x92\xe4\x4e\xa1\x9d\x8c\x06\x37\xbf\x18\xed\xd4\xe6\xd3\x38\x57\x83\x3b\xa9\x1c\x87\x11\xd7\xe0\xe6\x98\xff\x08\xf5\x62\xaa\x1f\x48\x2b\x95\xe8\x4a\x07\x91\x4d\xd8\xf5\x36\x39\x65\xcc\x21\x71\x3b\x93\x26\x97\xb0\x5c\x24\xcd\x31\x11\x26\x54\x98\xc0\x4f\x10\x89\xf8\x7c\x1e\xcc\x83\x90\x65\x30\xbc\x4c\x86\xc8\x15\x42\x41\xb2\x08\x91\x09\x92\x13\x04\xfc\x29\x8d\x9f\xe3\x42\x50\x42\x32\x8c\x09\x20\x04\x16\x62\x30\xac\x10\x24\x63\x02\x0c\x53\x60\x0a\x19\x7f\x19\x22\xc7\x60\x64\x8a\x9b\x66\x77\x32\x7a\xbb\x11\x9f\xe2\x12\xcf\xb9\x7c\xec\x85\x5c\x34\xc5\x81\xeb\x19\xca\xa1\xa5\x28\xdb\xd4\x04\xa8\x2d\x14\x43\x39\x2d\x14\x0d\xa6\x64\x22\x60\x9c\x52\x6f\x24\xec\x7e\xc7\x12\xff\x05\x4d\xe6\x8a\x3b\x88\x5c\xdc\x84\x39\x28\x12\x7c\xd6\x61\x94\xf8\x99\x0c\x92\x05\xcb\x04\x09\x32\x2c\x05\xe6\x4d\x56\xce\xe3\xc9\x14\x29\x02\x99\x48\x01\xcb\x84\x72\x0c\x62\x4d\x72\x4d\xff\x4b\xd7\xb8\x52\x50\xcc\xfd\xaf\x71\x99\x72\x69\xe4\x98\x7f\xfb\x7c\xf8\xa5\xe0\xbf\x9f\x0f\x6e\x37\x49\x58\x0e\x56\xa2\x54\x3d\x64\x91\x02\x40\x40\x67\x9a\x5c\xa6\x75\x5d\xa9\x2f\xdf\x6c\x29\x5b\x15\xd9\xe7\xbb\x06\xf5\xb4\x1a\xde\x2d\x17\x5e\x0f\xdf\xb3\x35\xf2\xd6\x8e\x2f\xd2\xd3\x93\x5f\xbb\xdd\x17\x5b\x9a\xe8\x5d\x37\x73\xf1\xd8\x8c\xc5\x4b\x62\x32\xae\xff\x92\xad\xa9\x88\x8f\x35\x7a\x37\x7b\x05\xc4\x3b\x96\x4d\x48\xe5\xab\xd6\x9a\xb2\xa8\x4a\x5f\xdb\xf1\x8f\xf6\x17\xb8\x7d\x1b\x47\x9c\x23\x05\x77\x2f\x14\xf8\x1e\xef\x77\x0e\xfb\x0a\xce\x3d\xfa\xd3\x23\x71\x5f\x22\x04\x8d\x3e\x7a\x3c\x21\x2d\x3a\xb0\xf4\xfc\xb4\xff\x03\x67\x99\x8a\x06\xc0\x99\xe3\x85\x9c\x07\x73\x04\x5b\x50\x7a\xd6\x13\xfa\x5a\xc7\x9c\x9b\x47\xc3\x02\x3a\xba\x5f\xbb\xd4\x5f\xe8\x1b\x8d\x3f\xbd\xed\x8f\xa0\x90\x35\x3f\xa9\xc3\x95\xf6\xab\xbf\x84\xb4\x6e\x79\x0b\x9a\xbd\xfd\xa5\x7d\xeb\x23\x74\xa1\xaa\xa2\xcb\x07\x3e\xe3\xaa\xc3\x35\x9d\x41\x1a\x6e\xdb\x12\x74\xe3\xb4\xf4\xa4\xa3\x9f\x8c\xdf\x6e\xda\xb9\xe9\xbb\xb1\x85\xfd\x65\x0a\xb5\xb7\x7c\xbf\xbd\x31\x20\xec\xe1\xa9\x37\x22\x06\x5a\xb5\x9b\x13\x65\xd5\xa5\xa0\x70\x9c\x6d\xab\x47\xcf\x8c\x9d\xfa\x60\x3b\xb0\x7a\xd0\x47\xa9\x6f\x62\xbb\x1e\x7a\xcd\xc8\x86\xe9\x77\xb6\x72\x7f\x53\x13\x09\x34\xfd\xa8\xcf\xbd\xe0\xda\x3d\xf1\xbd\xe7\xbd\x3d\xef\x59\xeb\x87\x32\xf2\x72\xb3\x78\xdd\xa2\xcf\xab\xf3\xff\xba\x60\x97\x25\xe6\xd0\xee\xf3\x59\x3d\xd2\x35\x73\x9b\x2b\xf6\x5e\x6c\x87\x2f\x24\xf5\x87\xb4\x1f\xbb\xff\xf0\x6e\x4d\xaf\xc2\xc2\x9f\x2e\x36\x77\xad\xc8\xf5\x68\x8b\x8f\xd5\x37\x9e\x4f\xea\x4f\x0e\xef\x9a\x77\xc0\x5b\xe2\x86\x86\xab\x1b\x8e\x7e\x26\x75\x8f\x8a\xd7\xaa\x83\x7f\x9d\x69\x4d\xdd\xbd\x02\x4e\x63\x8c\x6d\xf1\xf1\x48\x73\x5b\xa6\x2d\xab\x21\x74\xc3\xcd\xa2\x86\xc0\x2a\x32\xc2\xf0\x2e\x7b\xfb\x9b\x03\xe6\xfa\xd6\x0d\xd9\xf4\xdb\x8f\x53\x54\x49\xb2\x69\x47\x86\xdf\x8f\x0c\x3a\x14\xe1\x19\x7a\xab\x64\xce\x93\xe8\xbf\x0f\xdc\x5f\x7d\x64\x67\x57\x70\xe7\xaa\x6e\x2b\xbb\xec\x02\x19\x5c\x32\x72\x6c\xc1\xdd\x83\xce\xa6\xaa\x43\x2d\x4d\xd3\x8b\x19\x9d\x27\xe2\x81\x7b\x84\x7e\x5a\xdb\x90\xd3\x01\x3d\x8d\xbe\x9e\x74\x54\xdc\xc8\xe8\x3c\x07\xc7\xae\x98\xe2\xbe\xae\xf9\x41\xd2\x53\x9c\xfa\xdb\xda\xb5\x05\x5f\x9e\xf8\xd6\x5a\x87\xa7\x7c\x69\xf0\x12\x71\x5f\x97\x37\x56\x57\xc4\x7d\xab\xf9\x64\xc6\xaa\xbc\x7d\xca\xaa\xd4\xea\xec\x79\x17\xfb\xb6\x11\x81\x86\x83\x85\x08\x39\x21\x0a\x9b\x63\x3b\x79\xb1\x04\xa5\xba\xd7\x57\x3e\xbd\xdb\x19\x54\xb1\x08\x59\x57\xf5\xc1\x28\x30\xf8\xd2\x8e\xa2\x95\x7f\xdb\xe7\xf8\xe6\xd6\xec\x9f\xc2\xe6\x9a\x50\xfc\xec\xc2\x73\x45\x89\x5b\x07\x8c\xcd\x0b\x40\xdb\xd9\x8a\x41\x30\xf2\x14\xbe\xb3\xf0\xf7\xa3\xc1\x75\xc0\x1e\x22\xf4\x1a\xe7\xed\x3a\x36\x51\xdb\x93\xba\x69\xaf\xa7\x3e\xb2\x56\x70\x62\xbc\x19\x2b\xd9\x7b\x09\x39\x92\x96\x91\x1a\xa5\x9b\xa1\x2a\x0c\x1d\x8d\xd3\x6d\xb8\x71\x3b\xf7\x9d\x13\x1f\x2b\xab\x3c\xe9\xf9\x37\xda\x95\xb7\x02\xa5\x1d\x41\xb1\xf4\xe2\x91\x33\xc0\xbd\xd0\x7f\x24\xde\xe8\xd2\x7d\xea\x3e\x5e\x33\x4c\xdc\x3b\x7d\x6b\x22\xb0\x17\x3a\xab\x9e\xf5\xc5\x8a\xb3\x3f\xd6\x0f\xe6\x60\xb3\xdb\x86\x7e\xa0\x8c\xe1\x95\xd6\x57\x7d\x0b\x0c\x66\xbd\xf2\xf2\xd2\xde\x24\xef\xe1\x82\x25\x51\xfd\xcb\x93\x2b\x0f\xff\x8e\x7f\xee\xc1\x9a\xd8\xdb\x9d\x29\x27\x07\xc9\xb0\xba\x35\x71\xc3\xdb\x72\xda\xc5\x21\x4b\x6f\x94\x8c\x84\x14\xf3\xc2\xa7\xad\xe1\x35\xac\xdb\xb9\xf1\xd2\xbc\xae\x9a\xab\x2b\xbf\x07\x63\x53\xb7\xab\xde\x68\x7e\xb9\x35\xb5\xb3\x4e\x67\x0a\x6e\xc9\x78\xb9\x81\x6e\x19\x2a\x8a\x8c\x3a\xf1\x3a\x16\xfa\xf0\xb0\xcd\xf3\x84\x45\x72\x7f\x0a\xfc\xee\xaa\x6d\x6e\xec\x57\x01\xaf\xef\x1a\x89\xf0\x66\x44\xbe\x2f\x2b\x8d\x6e\x19\xfa\xfc\xc3\xe8\x82\xb1\xd0\x59\xdf\xe0\xe6\x7b\xe5\x71\x66\xa2\xd4\x90\x1b\x3d\xf7\xd4\xa7\x07\x4b\x0f\xac\x5d\xda\x60\x33\x77\xf4\x69\xd1\xd3\x8b\xba\x5f\x89\xaa\xd1\xa2\x57\xf4\x3d\xbd\x91\xe1\xf3\x0f\xb5\xf4\x6c\x15\x7f\xd4\x07\xa7\x9f\xfc\x2a\xa8\x0f\x96\x71\x2a\x62\xda\x5a\xe2\xe6\x67\xf5\x8c\x63\x0b\xfb\xc6\xe1\x62\x55\xd9\xe5\x2d\x97\xe8\xc6\xac\x82\xd2\xab\x01\x87\x43\x8e\x5d\xfd\x43\x62\x6f\x8c\x24\xe7\x78\xd3\xf4\xfe\x5f\xa4\xba\xff\x2c\x36\xdf\xb9\xb8\x63\xfc\x7e\x45\xf4\x9d\x89\xff\x5f\x0f\x28\x43\xdb\xf7\x2d\xda\x52\xab\xf2\xff\x90\x69\x0a\x95\xfc\xc3\xe4\xf5\x9e\x7f\x06\x00\x00\xff\xff\x8a\xe5\xd7\x55\x8e\x07\x00\x00") func imagesRobotsIcon_03PngBytes() ([]byte, error) { return bindataRead( _imagesRobotsIcon_03Png, "images/robots-icon_03.png", ) } func imagesRobotsIcon_03Png() (*asset, error) { bytes, err := imagesRobotsIcon_03PngBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "images/robots-icon_03.png", size: 1934, mode: os.FileMode(436), modTime: time.Unix(1492020681, 0)} a := &asset{bytes: bytes, info: info} return a, nil } var _indexHtml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x34\x8f\x41\x72\xc3\x20\x0c\x45\xf7\x3e\x85\xaa\x7d\xa3\x6d\x17\xc0\x21\x7a\x03\x02\x4a\x51\x4a\x6c\x0f\x52\x32\xf5\xed\x3b\x1e\x91\x15\xff\xf1\x67\xf4\xa4\xf0\x51\xb7\x62\xc7\xce\xd0\xec\xd1\xd3\x12\xce\x07\x7a\x5e\x7f\x22\xf2\x8a\x69\x01\x08\x8d\x73\x3d\x03\x40\x78\xb0\x65\x28\x2d\x0f\x65\x8b\xf8\xb4\xdb\xe7\x17\xa6\xc5\x3b\x13\xeb\x9c\xbe\xb7\x2b\xe7\xe7\x5f\x20\xc7\xd9\x75\x59\x7f\x61\x70\x8f\xa8\x76\x74\xd6\xc6\x6c\x08\x6d\xf0\x2d\x22\x15\x55\xca\xfb\xde\xa5\x64\x93\x6d\xbd\x14\x55\x17\x93\x9b\xcf\x78\xdd\xea\x31\x77\xa8\xf2\x02\xa9\x11\x87\x9b\x70\x7e\x53\x95\xd7\x5b\xa7\x65\xc8\x6e\xa0\xa3\x44\xa4\xbb\x92\xf3\xe5\xae\x98\xc2\x04\x17\xf8\xd8\x40\x7e\xfc\x7f\x00\x00\x00\xff\xff\x96\xf5\xb6\x39\x0d\x01\x00\x00") func indexHtmlBytes() ([]byte, error) { return bindataRead( _indexHtml, "index.html", ) } func indexHtml() (*asset, error) { bytes, err := indexHtmlBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "index.html", size: 269, mode: os.FileMode(436), modTime: time.Unix(1492020681, 0)} a := &asset{bytes: bytes, info: info} return a, nil } var _jsKeep = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x01\x00\x00\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00") func jsKeepBytes() ([]byte, error) { return bindataRead( _jsKeep, "js/.keep", ) } func jsKeep() (*asset, error) { bytes, err := jsKeepBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "js/.keep", size: 0, mode: os.FileMode(436), modTime: time.Unix(1492020681, 0)} a := &asset{bytes: bytes, info: info} return a, nil } var _jsScriptJs = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\xfd\xfb\x73\xdb\x38\xb6\x20\x8e\xff\xbe\x7f\x85\xc4\x3b\x97\x4d\xb4\x10\xda\x4a\x3a\xfd\xa0\x82\x71\xa5\x6d\xf7\x74\x6a\xe2\x38\x6b\x3b\xdd\x7b\xbf\x6a\x8d\x07\x26\x21\x0b\x1b\x8a\xe0\x80\xa0\x1d\x8f\xc4\xff\xfd\x5b\x78\x91\xe0\x43\xb2\xdd\xb7\xf7\xee\x7e\xea\x4e\xa5\x2a\x16\xf1\xc6\x01\x70\x70\x70\x9e\xe3\x65\x99\xc5\x82\xb2\x6c\x44\x02\x01\x33\xc8\xc1\xa6\x4e\x61\x01\x85\x05\xd8\xd0\x65\x30\xce\xe6\x74\xa1\x7f\x09\xf5\xeb\x0e\xf3\x51\x89\x3c\x5b\xd4\x43\x48\x3c\xe4\x84\x2d\x47\x9c\xfc\xa3\xa4\x9c\xf8\xbe\xf9\x31\x93\x75\x0a\xdf\x2f\x01\x27\xa2\xe4\xd9\xa8\x0c\x28\x1c\x1f\x02\x99\x8e\x6d\x1a\x36\x69\xb2\xd5\x18\x65\xe4\x7e\x74\xca\x39\xe3\x81\x77\x8c\xb3\x8c\x89\xd1\x92\x66\xc9\x68\xcd\x92\x32\x25\xa3\xaf\xbc\x09\x9d\x78\x5f\x79\x60\x26\x56\x9c\xdd\x8f\xe2\x30\x66\x09\x41\xde\xd9\xf9\xc9\xa7\xf7\xa7\xd7\x1f\xce\xaf\xae\x7f\x3a\xff\xf4\xe1\xc4\x83\x71\x25\xdb\x4b\x91\x1c\x3b\xda\x90\x2f\x39\xe3\xa2\x88\x36\x55\x35\x93\x73\x98\x1f\x2e\xc2\x18\xa7\x69\x90\x86\x26\x0b\xda\xd9\x04\x44\x4f\x30\x43\xaa\xe0\x74\x31\x27\x8b\x99\x19\x2a\x0b\xb2\xed\x96\x80\x0a\xa6\xb0\xa9\x48\xa0\x06\x5d\x65\x0a\xc9\x1e\x6d\x66\xb5\x64\x3c\x90\xad\xe1\xa7\x80\x0b\x52\x74\x38\xa3\x6f\x78\x98\x92\xec\x56\xac\x66\x74\x32\x01\x2c\xe0\x12\xe6\xf5\x08\xaa\x60\x33\x8d\xe6\xcd\x60\x65\xe7\xce\xaa\xf1\x00\x6c\x34\x68\x1c\x40\x16\x44\x5c\xd1\x35\x61\xa5\x18\xad\x70\x31\x92\x40\xbd\x21\x24\x1b\x25\x64\x49\x33\x92\x78\xa0\x72\x56\x7d\xa0\x7e\x9c\x12\xcc\x9f\xda\x02\x96\x00\xa4\xcb\x20\x47\x08\x35\x1d\xdb\xc5\x6e\x52\x02\x02\xf5\x46\x50\x25\xf9\x76\x3b\xce\x81\xef\xf7\x6b\xe4\x4e\x2b\xb0\x5b\x5d\xf0\x87\x8d\x2d\xa7\x52\xaa\x18\x8b\x78\x15\x08\xb0\x71\xb3\xf4\x5a\x67\x65\x9a\xc2\x76\xa1\x76\x01\xb1\xa2\x85\x2e\x50\x35\xf3\xa1\x66\x3e\x09\x42\xc8\x05\x84\x1d\x9f\x9b\x16\x10\x3d\x23\x59\x96\x6d\xb7\xe3\x04\xf8\xfe\x50\x9d\xa4\xd5\x12\xec\x36\xe1\x0c\x3d\x09\xc8\xf0\x9c\x12\x77\x4e\xfd\x19\x25\xee\x8c\x5a\xf3\x29\x02\xb0\xb9\xf3\xfd\x95\xef\x07\x77\x68\x3c\x85\x2b\xb3\xdb\x8e\xd6\x68\x15\xc6\x2c\x8b\xb1\x08\xd6\x20\x7a\x40\x2f\xa6\x70\x6d\xf2\x7c\xbf\x0c\x80\xb3\xc6\x65\xa0\xd1\xc1\x9d\x3e\x2a\x04\xe1\xa0\x00\xb3\x3b\x34\x3e\x9c\xd9\x0d\x2f\x90\xad\x3c\x13\x33\xb0\x91\xc9\x2b\xb4\x86\x6b\x34\x5f\xcc\x26\x93\x87\x37\x62\x06\x56\xbe\xbf\x9a\x3f\x2c\x42\x5e\x66\x01\x98\xa9\x0e\x9b\x5a\xd5\x0a\xa9\xb9\xa9\x31\xca\x35\x70\xa6\x10\xcb\x6d\x2f\xf7\x29\x2d\xc2\x65\x99\x21\x02\xd5\x4f\xcc\x39\x7e\x40\xa2\x29\x97\x06\x60\xa3\xd0\x40\x0e\x13\xb8\x44\xc2\x9e\x4a\xb4\xa9\x66\x35\xea\x0b\x34\x58\xf3\xa1\x03\xda\x6c\xb7\xa3\xe6\x67\xc4\x0d\xb4\x09\xd8\xe4\x88\x57\xb2\x76\x32\x54\xdb\x5d\xd6\x23\xf7\x23\x62\x4d\x0b\x09\x62\x55\x15\x68\xec\xb7\x52\xe0\xd1\x53\x96\xe0\x98\x2d\xc3\x8c\x7c\x11\x57\x34\xfe\x8c\xba\xe8\x49\x28\x4c\xf9\x56\x4e\x39\xc0\xfc\xb6\x5c\x93\x4c\x14\x06\x76\x2f\xa6\x1a\xc3\x76\x92\xff\x3c\x05\x76\x75\x32\x34\x9d\x65\x6f\xba\x05\x66\xd9\x64\x02\xc4\x3c\x7b\x31\x5d\xa0\x3a\x6f\x9e\x2d\x66\xeb\x30\x2f\x8b\x55\x20\x7b\xd4\xb0\x07\x70\x3a\x46\xf5\x5a\x6d\xb7\x77\xdb\x2d\x0e\x4a\x50\xc1\x38\xcc\x39\x13\x4c\x42\x40\xae\x2b\x72\xa1\x6c\x96\x2b\xc4\x79\x9e\x3e\xe8\x9d\xdb\xac\x1b\xa8\xe0\x32\x14\x54\xa4\x04\x79\x37\x9c\xdd\x17\x84\x7b\x70\x19\x9a\x9f\x68\x7c\x08\x97\x21\xc9\xee\xd0\x46\x96\xc3\xfc\xf6\x4e\x42\x6a\x19\xde\x11\x5e\x50\x96\x21\xcf\x6b\x3e\x0a\x5d\x88\x65\x28\x95\x65\x93\xe4\x3d\x2d\x04\xc9\x08\x57\xdf\x2c\x8b\x89\xfe\xb1\x5c\xaa\xbf\x9c\xac\xd9\x1d\x69\x95\xd1\x49\x6f\xd3\xd4\xa6\x16\x2a\x99\xac\xa9\x50\x3f\x6e\x68\x96\xd0\xec\xb6\xb5\x28\x3d\xac\x99\x73\x16\x93\xa2\xb0\x85\x47\x54\xe3\xcd\xa2\xcc\xe5\x26\x54\x48\x13\x2e\xc3\xf8\x3e\x71\x81\xa4\x8f\xaf\x77\xe0\xa9\xbc\x55\x42\xf9\xd3\x3a\x51\x45\x77\x74\x51\xae\x71\xf1\xb9\xdf\xc9\xe8\xb0\xaa\xe0\xa6\x5a\xc0\x97\xfd\xfb\xc4\x2b\x0b\x32\x2a\x04\xa7\xb1\xf0\x66\xad\xcb\xa5\x6a\x4e\x11\xd7\xd5\x5f\x3d\x52\x5d\xee\x37\x8e\x48\xe0\x71\x82\x63\x71\x90\xd2\x9b\x03\x9a\xdd\x61\x4e\x71\x26\x3c\x00\x59\x3b\xeb\xf4\x0b\x89\x4b\xd9\xd6\x69\x76\x47\x39\xcb\xe4\x1e\xf4\x40\x18\xe3\xec\x53\x41\x4e\xce\xcf\x20\x46\x1b\xbd\xeb\xa2\x29\xbc\xc1\xf1\xe7\xc8\x9d\x58\xc0\xa0\x25\x1b\xe4\x10\x7e\xa6\x85\x60\xfc\x21\x94\xe5\x46\xf7\x54\xac\xe4\x05\x86\x47\x27\xe7\x67\x1e\x80\xd8\x9e\x16\x34\x85\xf7\x34\x4b\xd8\x7d\xb8\x72\xca\x07\x40\xd2\x0a\xf5\x64\x71\x05\x37\x8f\x0d\x33\xfa\xf6\x10\x0e\xce\x32\x9a\x7e\xf7\xba\x5a\xc0\x6f\x9e\x0e\x68\x93\x2d\x61\xc7\x10\x09\xe3\x15\x4d\x93\x0b\x56\x0a\x52\xc8\x93\xcd\xea\x83\x8c\x61\x09\x63\x74\x08\x53\xc4\xec\x21\x8e\xdf\xa4\xb3\xc9\x24\x06\x74\x19\x94\x88\xcd\xe3\x05\x1c\x97\x21\x2d\x4e\xc8\x12\x97\xa9\xf0\x7d\xf5\xf5\x81\x89\x9f\x58\x99\x25\xbe\x1f\x60\xc4\x83\x52\x75\x07\x6a\x92\x2c\xe4\xaa\xaf\xb0\xcc\x8a\x15\x5d\xca\x4b\x09\x62\xb5\x90\x39\x22\x61\xa2\x5b\x52\xc3\x91\xa3\xc9\x7d\x3f\x58\x22\x1a\x92\x2f\x82\xe3\x58\x7c\xc4\x1c\xaf\x8b\x20\x0f\x73\x2c\x56\x12\x57\xd8\x56\xe5\xb6\x2d\x02\x01\x97\x30\x83\x73\x02\xf3\x85\xc6\x7a\x09\x22\x61\x66\x86\x53\xb7\x99\x0c\xb6\x99\x3c\xd6\x66\x62\xda\xec\x57\x25\xb6\xaa\xa5\xa4\x96\x47\xed\xba\x0b\x10\x49\x94\x54\x69\x90\xbb\xeb\xa4\xef\xba\x80\x8c\x68\x56\x08\x9c\xc5\x12\xb7\x0b\x00\x9a\xb3\x78\xf5\x90\x93\x36\xcd\x2a\x2f\xdf\x11\x1e\xc5\x29\x2e\x8a\x11\x2e\x46\x78\x54\x5f\x0f\xa0\x82\xd8\x3d\x8c\x0e\x09\xae\xfa\x6a\x50\xf4\xe1\x2c\x7b\x23\x5c\xd4\xbc\xd1\x47\x49\x48\x94\xcc\x43\x92\x95\x6b\xc2\xf1\x4d\x4a\x90\xfb\xb1\xdd\x8e\xa7\x90\xcb\x9b\x7c\x49\x6f\x4b\x9d\x3f\x3e\x84\xde\x1d\x4e\x4b\xe2\xd1\x6c\xc4\x7d\x3f\xe0\xe1\x3d\xa7\xc2\xe4\x01\x78\x7e\xf3\xbf\x49\x2c\x42\x4d\xcd\x7d\xe4\x2c\x27\x5c\x3c\x04\x04\xf2\xf0\x33\x79\x90\xa4\xad\xa5\x6d\xeb\x71\x9b\xd7\x82\x5d\x05\xdf\x27\x81\x68\x50\x3f\xcc\x00\xe4\x2a\x0d\x72\x00\x85\xbc\xe0\x20\x95\xe7\x3c\x3c\xf8\x88\xc5\xea\x93\xa0\x69\xe1\x01\x58\xec\x80\x83\x6a\x1c\x62\xb0\x61\x96\x80\xd1\x17\x85\x5c\xc1\x0c\xaf\x09\x12\xf6\x5b\x2e\x2d\xca\xf4\xd7\x3f\x4a\xc2\x1f\x10\xd7\x1f\x7a\xff\x22\x5c\xd5\x8f\x0c\x02\xd5\x8d\x33\xdf\x7c\x26\x0f\x91\x27\x1f\x15\x67\xf2\x0e\xf6\xa0\x02\x4c\xd4\x5e\xf0\x66\x11\x68\x68\xf0\xc6\xff\x94\xcd\x07\x42\x22\xac\x7a\x6f\xd5\x69\x58\x13\x2b\x05\x3a\x84\x25\x22\xf5\x9a\x95\x69\x8a\x10\xf6\xfd\xe2\x4d\x39\x9b\x4c\x0a\x20\x8f\x1a\x99\x17\x0b\x98\x41\x56\x6f\x44\x5c\x55\x0b\x00\x89\x24\x02\x1a\x74\x53\x48\x74\xe3\x42\x2b\xfa\xb6\x5a\xc0\xd7\x4f\x45\xb5\xe1\x81\x5c\x45\xb9\x2f\x0b\x85\x62\x37\x31\xcb\x84\x24\x25\x64\x4a\xb4\x51\xd0\xe1\x11\xd7\x60\xe2\x21\x2d\x2e\xf4\x0b\x24\xa9\xe0\x1a\x7f\x26\xb2\xdb\xa8\xdb\x93\x19\xae\x02\xaf\x69\xce\xd6\xb7\x75\x4c\x51\xdd\xc8\xcf\x9c\x2c\x9f\xdb\x88\xac\x53\x37\x22\x38\xce\x0a\x2a\x6b\x5f\xb1\x5e\x43\x43\x2d\xb8\x15\xea\x56\x38\xc9\x53\x1c\x93\x5f\xe9\xc0\x94\x86\x1a\x71\xca\xd7\x6d\xdc\xb2\x1f\xbb\x37\xcd\xee\x79\xe8\xc2\x9d\xeb\x83\x99\xf5\xac\x57\x25\xfa\xae\x5a\xc0\x6f\x9f\x71\x21\x38\x58\x68\x54\x02\x4b\x04\xce\x17\x30\x43\xc4\x0e\x3a\x70\x9f\xb1\x0e\xb8\xb3\x23\x79\x3a\x15\x09\x07\xa0\x17\xcc\xff\x76\x70\xf4\x6f\x8b\x09\xf0\x40\xe4\x7d\xed\x21\x84\x48\x9d\xef\x15\x79\x8a\xe5\xb5\xec\x05\xe1\xd7\x47\xaa\xc4\x6f\xbf\x79\x13\x52\x81\x59\x39\x27\x0b\xb4\x59\xcb\x43\x43\x78\x24\xf1\xde\x05\xb9\x3d\xfd\x92\x07\xde\xdf\xbc\x49\x36\xf1\xfe\xe4\x41\x8f\x7a\x00\xaa\x53\xf9\x01\xaf\x49\x11\x89\x1a\x71\xc8\xca\x06\xb5\xee\xa4\x04\xb0\xcc\x62\x0a\x15\xbd\xc0\x45\x41\x6f\x33\xcf\xa0\x8d\x7f\x68\x6c\x71\x10\x05\x73\xfc\xe2\x9f\x6f\x5f\xfc\xff\xae\xff\xb4\x30\xbf\x0e\x5f\xfc\x70\xfd\xa7\xc5\xd7\x60\x3b\xff\x3a\x0c\xc0\x6f\xf3\xdf\x16\xbf\xfd\x36\xd9\x6e\xaa\xbf\xfd\x69\x71\x70\x0b\x4b\x49\x0a\xc6\x68\x43\x8b\xb7\x37\x05\x4b\x4b\xe1\x1e\x74\x87\xda\x92\x30\x08\xe3\x15\xe6\x6f\x45\x70\x08\x2a\xf8\xbf\x19\xcd\x3a\x28\xc1\x4c\xa4\x81\xf5\xc1\x6f\x07\x5f\xff\xe9\x00\x7a\x07\x1e\x98\x88\x0a\xba\xd7\x8d\x9e\x7d\xbf\x27\xb5\x8e\x61\x03\xa0\x76\xad\xa2\xd3\xa3\x46\x40\xb2\x0a\x64\x28\x0b\x0d\xe4\x25\xae\x71\x9a\x80\x14\x09\x9d\x15\x30\x45\xf5\x8f\x69\x7d\x37\x96\x69\xaa\x50\x82\x7a\xf0\xd4\x57\xfb\x92\xf1\x53\x1c\xaf\x82\x76\x67\x85\x5c\x5d\x3a\x17\x93\xe9\xa2\x02\xb0\xa8\x20\xcd\xe4\x42\x0c\x0e\x4c\x20\xb1\xdd\x6e\xaa\x99\xbd\xa6\xfa\xa0\xd9\xb5\x50\x47\x8b\xaf\xe7\x47\x8b\x23\xb9\x5a\x72\x79\xea\x66\x15\xb6\x97\x4f\x16\x84\xb7\x5b\xb3\x07\xa1\x77\x24\xd7\x05\x87\x45\x4a\x63\x12\xbc\x98\x02\x5b\xc4\xa4\x1c\xc2\x17\x53\x00\x35\x92\x15\x73\xbc\x30\xf3\xf6\xbc\x8a\xa4\x05\x19\x31\xf5\xc4\x18\xab\x2c\xf8\xd5\x19\x2d\x0a\x49\x85\x7b\xff\x5e\x78\x23\x05\x3e\x22\x08\x1f\x2d\x19\x1f\xc9\x6b\x45\xa5\x7f\x05\x31\x24\x9a\x80\xa0\x66\x52\x66\x2c\x48\xa1\x71\xf5\xda\x0a\x69\xa1\x5f\x5d\xaa\xcb\xa3\x80\xaa\x0e\xe6\xd9\x64\xb2\x80\xb6\x4b\xda\xf4\xa7\xea\x8f\xfe\x6d\xf4\xef\x45\xb7\xaf\x0c\x12\x00\x22\x5d\x1d\xd2\x0a\xb8\x1b\xeb\xb7\x83\xdf\x8e\xb6\xf2\xbf\xdf\x0e\xd4\x9f\x83\x5b\xb5\xcf\xea\xfd\xa2\x2e\x9e\xa8\xff\x26\x24\x66\x2b\x1c\xfc\x76\x14\x84\x5f\x83\x3f\x1d\xd4\xb7\x8c\xf0\x7d\x2a\xb7\x4d\x41\x02\x31\x9f\x2e\x40\x05\xdd\x7b\x6d\x68\xaf\xba\x3b\xdd\xb4\x06\x3d\xcf\x54\xec\xd6\x6a\xf6\x6b\xdc\xbe\x1c\x09\x98\x65\xbe\x1f\x08\x24\x8e\x70\x90\x41\x01\xa2\x0c\x98\x7b\x8a\x86\x12\xcf\x65\xb7\x74\xf9\x10\x08\xb8\x51\xcf\xc0\x9f\x18\x5f\x63\x11\x79\x37\x1c\xc7\x9f\x89\x28\xbc\xaa\x9e\x01\x3f\x8a\xdb\x77\x31\x01\x13\xef\xc8\x9b\xf0\xa8\x97\xde\x42\xbd\xb1\x44\xbd\x6d\xb4\x12\xbd\x7a\x0d\xff\x51\x44\xaf\xbe\xdd\x4b\xae\x7f\xf7\xfc\x87\x8d\x21\xa4\x6a\xec\xd5\x60\x3b\x0f\x84\x35\xf2\xd7\x98\x2e\x3c\x50\xd4\xae\xc2\x71\x3c\xd8\x54\x90\xc1\xcd\x12\xa7\xc5\x43\xef\x9a\xa2\xcb\x80\xcc\xc5\xc2\xa5\x79\x0d\xb9\xf9\x46\x62\xde\xaf\xfe\x3c\x2a\x56\xac\x4c\x13\xf5\xf8\x5b\xe1\x3b\x32\xc2\x23\xef\xab\x89\x98\x7c\xe5\x8d\x72\xce\xf2\xaf\xe4\x35\x28\xfb\x8a\x58\x68\x69\xd8\xf3\x65\x80\x01\x34\x84\x00\x93\xef\xf2\xb8\x72\x09\x10\xaa\x2f\x2c\x3d\xc4\xe8\x07\xa8\x26\x11\x4d\x7f\x78\x0d\x77\x4e\x37\xfa\x56\xd2\x28\xdf\x3f\xfb\x91\xa3\x2e\x51\xc1\x2c\x1b\xc7\x50\x75\xc2\xa5\xea\xb2\xfe\xb3\xf3\x87\xa7\xac\x0e\xfc\x17\x25\xff\x7f\x88\x92\xdf\xbd\xe7\x8b\xdd\x37\x7c\xd9\xce\xba\xc7\x3c\xa3\xd9\xad\x07\x60\xdc\x7f\x1c\xa4\xfb\x1f\x07\x90\xc2\x02\x96\x30\xed\x3d\x12\xda\x0f\x04\xb1\xb2\xcf\x83\xe6\xca\x6c\x50\x54\x73\x59\x07\x75\x79\xd3\x0c\xbd\xcd\x18\x27\x97\x31\x67\x69\xfa\x23\x59\xe1\x3b\xca\x38\x1a\x8f\xcd\xf3\xa2\x7e\x4e\xa3\xf1\x18\xdb\x24\xfb\xa6\x46\xe3\x31\xd5\x69\x2c\x3b\xcd\x04\xe1\xa8\xb0\x9f\xef\x09\xbe\x23\xa8\xd4\x9f\x2b\x9c\x25\x29\xe1\x28\x75\x1f\x29\xe6\x7d\x82\xf3\x9c\x64\xc9\xb1\x7c\xf6\xf7\x5e\x28\xf2\xb6\x0e\x84\xbb\x87\x09\xf4\xd4\x49\x0e\x9d\x6a\xa3\x75\x59\x68\x2e\x08\x1e\xdd\xe1\x94\x26\x23\x8b\x6e\x34\xd1\xda\x70\x14\xb6\xdb\xa0\x9b\x84\xe6\x8b\x7e\x39\x4d\x21\x0a\x50\x55\x50\x0f\x52\xb0\x4b\x85\xc0\x7b\x23\xb4\x6c\x61\xef\x8d\xee\x73\xe6\x92\xcb\x72\x81\x7c\x3f\x20\x13\xf4\xd5\x48\x2d\x96\x44\x55\x36\x63\xf2\x95\xf7\x15\x80\x2a\x4f\x2d\x9e\xcd\x93\x1f\x93\xaf\xbc\x3f\x7f\x55\x55\x0b\x0b\xa3\x98\x13\x2c\x88\xee\xa1\x07\x23\x85\x0f\xf4\xfd\x52\x73\x64\x03\x43\xb8\x00\x75\x21\x6d\x64\x9b\x91\xa8\xf4\x75\xc4\x10\x9f\xb1\xa3\x32\x30\xe4\x84\xdc\x2e\x24\xd3\x3c\x8e\xed\xb6\xf5\x89\x10\x62\xd0\xfb\x0f\x56\xba\x58\x57\xc2\xd9\x29\xa3\x98\x4d\x23\x67\x80\x72\xb5\x68\x42\x46\x38\x63\x62\x45\xf8\x48\x2d\xd7\x57\xc5\x48\x81\x57\x21\x99\x1b\x1c\x7f\x9e\x8d\xa8\x18\xd1\x62\xa4\x37\x5f\xe2\x81\x88\xb5\x87\x32\xd3\xb2\x24\xa1\x60\xa5\x48\x3f\x39\x89\xed\x16\xcf\xc6\x54\x0e\xb3\xde\x97\xfa\xc3\xee\xc8\x23\x8a\xd8\x11\x53\x65\x23\xef\xc0\x8b\xe2\xb0\x21\x88\x03\x0a\x8e\x98\xef\x17\x01\x95\x13\x33\xed\x1d\x9a\xdf\xf6\x78\x18\xdc\x05\xbf\x92\xd3\x8e\x35\x66\xcc\x48\x21\x1a\x7a\xc6\x4e\x50\xfe\x9e\x8d\xc4\xca\x82\xc3\x0a\xb9\x8a\xd1\xa7\x8b\xf7\x0d\xe1\x55\x7c\x05\x29\xd4\xbd\x49\x1a\x88\x1d\xc5\xa1\xa4\xb9\x03\x9d\x04\x29\x90\xe3\x9c\x50\x28\x5a\xbc\xaa\xf1\xc1\x6f\x5f\xff\xe9\x20\x14\xa4\x10\x01\x95\xab\x48\x27\xc8\xfb\xda\xd3\x2b\x98\x2a\x8e\x38\x09\x24\x6a\x10\x83\xe7\x17\x3a\x00\x6a\xb5\x0c\x85\x3d\xaa\xea\x97\x3a\xa5\x50\xd8\x03\xaa\xc8\x6a\xe6\xfb\x41\xda\x54\x3f\x0a\x0a\xb3\x55\x58\x8b\x1f\x06\xbd\x7f\x2f\x46\x6b\xfc\xd0\x5c\xc5\x6b\xc6\xc9\x48\xac\x70\x36\x62\x19\x19\x99\xb2\x7a\xfd\x3d\xc8\x00\x6c\xd7\x47\x29\x88\xd2\x36\x7f\xae\xe9\xa8\xc5\x25\x7b\xac\x27\x25\x3a\x95\xa5\x5b\x7d\xb5\x9a\x40\xa9\x4c\x72\x70\x46\x90\x02\x00\x07\x24\x19\x86\x13\x99\x23\x3e\xe3\x28\x85\x99\x91\x9d\xc2\x14\x40\x8e\x72\x8b\xbe\xd2\x1a\x31\xe8\x8d\x7f\xe2\xcc\x6b\x08\x89\xd5\x74\xa6\x73\x4e\x02\x2a\x29\x21\x01\x37\x35\xa4\xa3\xf1\x61\x05\x40\xa7\xe9\x0f\xee\x34\x7e\x47\xdb\xb6\xfe\x60\xe3\x17\x24\xa1\x9c\xc4\xe2\xd9\xed\x6a\x84\x62\x8e\x90\x08\x97\x9c\xad\xb7\x5b\xef\x6b\x0f\x9a\xcd\xe5\x12\x76\xea\xd2\x95\x24\xb6\xee\x2b\x10\xa1\x60\x50\x18\xe2\x67\xbb\xcd\xa0\xd0\xa4\xcf\x76\x2b\x2f\x6d\x39\xc6\x3e\x93\x28\xed\x33\x89\xf6\x52\x67\xbb\xa9\x5d\x38\x70\x2b\x47\xd3\x1f\xbe\xa9\x16\x70\x7a\xf8\x2c\x82\xce\xe8\x09\x18\x5a\x75\x7c\x28\xcf\x0e\x69\x38\x77\xc8\xa0\x2c\xf9\x61\xcb\x4c\xcd\x43\x92\x18\xae\x1d\xe4\xc8\x30\x53\x0a\x73\x71\x8c\xb3\x70\x49\x53\x41\x78\xd0\x7f\xa7\xbc\x98\x8e\x11\xe2\x21\xcd\x12\xf2\xe5\x7c\x29\x89\x7f\x10\x16\x6c\x4d\x06\x8a\x8e\xc8\x20\x5a\xa8\xc0\x93\x38\x13\xcf\x90\x51\x18\x5e\xe7\x2d\x11\xbf\x2a\xc1\x82\xee\xef\x23\xd3\xcc\x29\x45\x23\x6d\x0a\x81\x05\x8d\x8b\x68\xc3\x49\xcc\x78\xd2\x2e\x12\xb5\x85\x3e\xb4\x08\x0b\x95\x6f\x04\x1a\xf6\xc6\x6e\x25\xa2\x4d\x65\xee\xec\x56\xb2\x7a\xd7\x07\xa0\x82\xb7\x44\xec\xe9\xc4\xbd\xa1\xff\x33\x7d\x6d\xb7\x8a\x8b\x5e\xc1\x98\xad\x73\x96\x91\x4c\xfc\x4a\xd3\xf4\x8c\x95\x99\x70\xe9\x03\x66\x2f\x5a\xc3\x40\x2b\x04\x2f\x63\xc1\x78\x58\x8f\xd2\xae\x4e\x00\xb6\x5b\xdc\x92\xea\xe8\x2e\x47\x37\xa6\x40\x57\xb0\xe3\x74\x7d\x42\x93\x5e\xcf\xaa\xc7\xeb\x32\x4f\xb0\x30\xfb\x20\xe8\x54\xf9\xa4\xf2\xba\x3c\x8f\x7e\x35\x01\x2a\xd8\x4a\x69\x01\x94\x2e\x03\x6e\x20\x27\xb0\x20\xf2\xb1\x6f\x1e\xe9\x4f\x99\xf3\x4c\xf8\xbe\x08\xdd\xc6\xed\xaa\x05\xbb\xab\xb7\x8b\xa8\x6e\x5d\x92\x56\x27\x60\x35\x42\x50\xb5\xde\xc8\x86\xdd\xbc\x6b\xc3\x46\x2f\x5b\x18\xe2\x77\x09\xbf\xa6\x03\x6a\x2b\x7f\x38\xf3\xfa\x96\x88\x36\xef\x7a\x3f\xa7\x96\x88\xe3\x92\x4b\x2a\x45\x31\xaf\x41\x5d\x5f\x62\xa7\xdf\xd5\x86\xac\x58\xb7\xd3\xe6\x9c\x3d\xb9\x15\x25\xae\xd2\x6d\x74\xb8\x2c\x4f\x6c\x42\x73\x41\x74\x0b\x9a\x72\x7f\x76\x13\xba\x9a\x6c\x83\x16\x6f\x63\x41\xef\xc8\x73\x38\xf9\xb6\x8e\xe5\x9f\x3f\xce\x08\x9f\x3e\x43\x06\xdd\x1c\x47\xf5\x42\xb0\xca\x1f\x37\x8c\x8b\x0b\x82\x0b\x96\xa1\x46\xb5\x80\x13\xc1\x1f\x90\x50\x32\x78\x75\x2a\x1c\x54\x1f\x1e\x1c\xcb\xe7\x53\x9a\x62\x83\x94\x2d\x57\xc6\x5e\xff\x60\xc6\x1d\x6d\x06\xd5\x41\x4b\x18\xef\x60\x30\xa7\x77\xf9\xb6\xe8\x0e\x88\x6c\xb7\xde\xdb\x1f\xcf\x2f\xae\x24\x76\x72\x1b\xb5\xd7\x3f\x1a\x94\x4c\xa8\x26\x94\xd6\x05\x36\xe9\x9d\xea\xb1\x9a\x40\x4f\xc9\xa2\xa9\xc7\x54\x05\x49\x88\x74\x7a\x90\xd4\x87\x90\xdd\x97\xb1\x73\x53\x0a\xc8\x21\xab\x97\xb6\x4e\x36\xbc\xd9\xed\x96\xb8\xb3\x02\x22\xc0\x60\xa6\x58\xad\x12\xd7\x59\xba\x19\x28\x25\x25\xfb\x25\x29\x9d\x39\x5b\x40\x01\x60\x9d\x66\x1e\x13\x6f\x5e\xf9\xbe\x08\x40\xa3\x0a\x23\xe4\xe5\xad\xda\x93\xc9\x15\xe4\x20\x50\xc3\x17\xac\x37\x78\x39\x4a\x3b\xfc\x0b\x7a\xbb\x12\xee\x1c\x7e\xe7\x0c\x98\x7d\x03\xa8\x19\xd4\x5f\x9a\x56\x93\x13\xa8\x93\xec\x04\xbe\x79\x64\x02\x4c\x4d\xa0\xcd\xb9\xea\x6e\xbb\xe8\x25\x74\xf7\x5c\xf4\xbd\x3c\x0d\x4f\x53\xa9\xd8\x7c\xfc\x74\xf9\x73\xe4\xc9\x57\xb9\x07\x2f\x4e\x3f\xbe\x7f\x7b\x7c\x1a\x79\x86\x69\xeb\xc1\x8f\xe7\x1f\x23\x2f\x67\xb9\xe7\x1e\x3f\xc3\x3c\x9b\x3e\xa6\x8a\xd0\x20\xe3\xf0\x40\xdf\x18\xc5\xc1\x7b\x16\xab\x31\xbf\xd5\xdf\x1a\x37\x0f\x5d\x51\x9d\xab\xb3\xb8\xa7\x46\x39\x2d\xc6\x05\x19\xf1\x50\x8d\xdb\xfc\xb6\xe3\x36\x1a\x18\xfa\x6e\xbf\x62\xc1\x21\x3c\x04\xb3\x1b\x4e\xf0\xe7\x99\xad\x75\xfe\x31\x22\x47\xdd\x72\x24\xfc\x02\x49\xf8\x00\x06\x1b\xa8\x06\x50\xcf\xee\xf9\x44\xd3\x57\x12\x34\x4f\x13\xb2\x3e\x32\x71\xb0\x19\x1e\xcf\xc0\x52\x3c\x26\x04\xd4\xfd\xfd\x1f\x65\x63\xb2\xff\x8e\x6c\x4c\xdc\x87\x69\xf3\xf4\x1d\xdb\xa7\xaf\xf0\x7d\x2d\xd3\x41\x62\x18\xc0\x97\x65\x4e\xf8\x88\x7c\xc9\x39\x29\x0a\x09\x36\xc5\x77\x23\x54\xb1\x79\x6e\x88\x92\xc2\x8d\x18\x77\x20\x0e\xd5\xdb\xdc\x9b\xd8\x1e\xc0\x8c\x34\x23\x45\x66\xea\xfa\x7d\x19\x28\x32\xb0\x99\xc6\xc6\xa1\xfb\xa2\x8d\x7e\x9e\x12\xd8\xc0\x3a\x1a\x4f\xa1\x05\x64\x34\x3e\x84\x2e\xd0\xe5\x5b\x57\x52\xed\xbe\x1f\x90\xf0\xfa\x5a\x35\x7a\x7d\x8d\x24\x15\x4b\x1d\x31\x85\xab\x95\x41\x9c\xdd\x20\x94\x7e\x95\x62\xb5\x0a\x2d\x75\x1b\x23\xe2\xfb\xc4\xa8\xf3\xa9\x8c\x5a\x69\x10\x34\x2c\x4d\x01\x09\x80\x2c\x10\x96\x6b\xc7\x49\x96\x10\x3e\xc0\x32\x74\x09\x8a\x9c\xb3\xdc\xf0\x1e\x39\xc9\xd4\xdb\x57\x54\x01\x0d\x8f\x2d\x99\xde\xd5\x95\xa8\xc5\x13\xf2\x44\x3d\x4d\x70\xf3\x5f\x75\xa2\xfe\xbb\x6f\x2e\x6c\xae\x11\x97\xa8\xa7\x8e\x00\xec\x67\xcd\x65\xb3\x92\x83\x46\x2c\x56\xfe\x91\x1b\x91\xe9\x8d\x28\xaa\xa0\x00\xb3\x52\x6d\x30\x35\x18\xb4\x51\xc4\x3e\x36\xb2\x48\xa8\x78\x38\x38\x54\x82\x38\x68\x37\x60\x9d\x60\x38\x82\xf2\xbb\xcc\xe2\xd6\xd3\xa3\xb4\x7c\x3c\x39\xcf\x02\x6d\x6c\x51\xea\x52\x00\xa5\xb9\x82\x5c\xf2\x17\x36\x62\xb6\x97\x53\xd8\x85\x4a\xf4\xf2\xa5\xdc\xd2\xcf\x91\xaa\x35\x0a\x9e\x4a\xad\xe1\xa6\x14\x82\x65\xae\x8a\x7f\x5d\x62\x3c\x0e\x48\xb8\x26\x02\xff\x95\x3c\x28\xda\x28\x15\xe6\x57\x2c\x78\x6a\x7e\x2a\x0d\xc0\xbf\x92\x07\x4d\x3a\x0f\x60\xcd\x3f\xf2\xdc\xd0\xff\x8e\x37\x51\xf1\x2f\x64\x61\x91\x45\xe9\xde\x44\xf1\x7e\x41\x63\x3a\x80\x58\xf2\xdd\x38\x03\x3f\x1b\x67\x14\x1a\x67\xd0\xe6\xf2\xd2\x87\xfa\x38\xa5\xf1\xe7\xbe\xe2\xa0\xe1\xef\xc0\x0c\x8d\x0f\x67\xce\x35\xc6\x32\x55\x41\x6b\x41\xf4\x92\x03\x02\x00\x1c\xcb\x43\xe9\xfb\x5c\xfd\x1f\x8c\xa7\x72\x91\x7d\x7f\x7c\x38\x46\x8d\xbe\xed\x47\x4e\xee\x48\x26\x48\xb2\xdd\x06\x19\x1a\x4f\x01\x94\x8b\xa5\xd2\x0c\xab\x3c\x00\x30\xf3\xfd\x47\x35\xe3\x9c\x31\x08\x06\x9d\x2f\xcd\x7c\x76\x53\x14\x0b\xda\x61\x90\xdf\x12\xf1\x33\x27\xcb\x47\x6e\xef\x5d\x8a\x7d\xcf\xee\xd8\xed\xf7\x58\x22\x8c\x0f\x78\xdd\x67\xf7\x5b\x69\xa3\x4b\x39\xd8\xc2\x2d\xc9\xe3\x2d\x11\x9a\x31\x71\x29\xe4\x8e\x06\x5a\x0a\xe9\xc9\x03\xd0\x54\xc5\xaa\x44\xdd\x1b\x80\xc4\x1d\x85\x53\xff\x79\x40\xa8\x79\x22\xbf\x1f\x08\x3b\x29\x27\x3d\xfd\x58\x49\x21\xea\xda\x70\xb3\xe2\x64\x19\xd9\x89\xab\x05\x00\xb0\x06\x4c\x9d\x51\xcf\x34\x00\xd0\x6c\xc9\xc8\x11\x4f\xab\x04\x97\x7f\x02\x1a\x75\x2f\x6c\x80\xf1\x90\x12\xb3\xed\x86\x20\x1c\x16\xb2\x00\x6a\x15\x07\xb0\x0c\x4f\xce\xcf\x42\xc5\xd7\xe8\x13\x7c\xc0\x52\x7c\xa5\x4b\xf1\xe5\xa1\xcb\x08\x44\x96\x11\x98\x0e\x31\x02\x73\xf7\x86\xef\x2c\x69\x94\x9a\xcb\xde\xa9\x01\x05\x8b\xd2\x90\x65\xe4\x7c\x29\x2b\x05\x73\x5b\x06\x9a\xe6\x17\xc0\x2d\xad\xd7\x4a\xd6\x50\x38\x09\xaa\x95\x6a\x3e\x9d\x99\x36\x89\x16\xb8\xa9\x56\xb6\x81\x79\x87\x60\xe8\x8e\xd2\xd3\x09\x9e\xb3\x66\x9e\xe7\x12\x13\xf9\x10\x31\xf1\x64\x3d\x9d\xe9\x93\x14\x68\xfe\x45\x25\xff\x8b\x4a\xfe\xff\x0c\x95\xfc\xf2\x31\x51\xe5\xbf\xb6\xf4\xff\x4b\x5b\xfa\x8f\xe6\x35\x34\x9b\x97\x82\x59\xe1\x6e\x5e\xb3\x5d\xcd\xe6\x5d\x72\xb6\x6e\xbe\x04\x6b\x7e\x3b\x1b\x57\x6e\xe4\x0a\x16\x9d\xed\xea\xee\xd2\xe2\xb1\x5d\x2a\x77\xe4\xd3\x84\x5e\xff\x62\xee\xfd\x8b\xb9\xf7\x5f\xc5\xdc\xdb\xaf\x9c\xd9\x39\xae\xf1\xe0\x0d\x94\xfe\x5f\xe2\x10\x16\xc1\x78\xaa\xd4\x9e\x48\x4a\x54\x23\x23\xcc\x89\x52\xab\xd7\x14\xe0\xa8\x86\x88\x66\x74\x64\xe9\xc3\x08\x67\x89\xab\xa7\x77\x43\x46\xba\x79\x92\x78\xb0\x27\x49\x57\x5a\x29\x83\xdc\xc6\xb4\x77\x17\x96\xad\xbb\xb0\xec\xa2\x90\x52\xdd\x7d\x70\x48\xdf\x24\x2a\xc3\x1b\xc6\xd2\x0a\xa6\x3b\x2e\xc3\xd8\x45\x33\xe9\x3e\x34\xe3\xdc\x7f\xc3\x94\x5f\x4f\x0c\xff\xf2\x31\x49\xeb\xbf\x30\xd2\xbf\x30\xd2\x7f\x39\x46\x0a\x0f\x8e\xf5\xd3\xee\x57\x8e\xf3\x5c\x21\x99\x72\x3f\xf3\x27\x1e\xc0\x56\x29\xf2\xae\xaf\xb9\x73\x2e\xae\xaf\xbd\x7d\x1c\xa1\x3f\x02\x59\xc9\x17\xb4\xa4\x7f\xcd\xf8\x77\x32\x05\xf4\x6b\xf5\x84\xe4\x62\x15\xf5\xf9\x03\x2a\x7d\x32\xad\x1a\x4d\xc4\xae\x0a\xd3\x40\xc3\xae\x4a\x92\xc2\x06\x35\xbe\x0a\x8c\xf2\xc3\xb2\x98\xa7\x0b\x30\xd8\xa8\x56\x72\xfa\x43\x5b\xfd\x95\xa6\xe9\xa7\x6c\xfd\xfc\xd1\x4a\xe8\x37\xed\x0d\x96\x19\xe2\xb6\x0d\xb1\x59\x0a\xa3\xf2\x52\x57\x7c\x2b\x14\x6c\x03\xcb\x9e\xb8\xa8\xc1\x1d\x00\xe5\x19\xa5\xe1\xed\x34\x59\xcf\x61\xed\xa8\x0a\x1d\x0d\xd2\xe3\x5a\x69\xde\x22\xe8\x5d\xcc\x42\xb4\x43\x0f\x47\x55\xde\x37\x76\xa5\x94\x6c\x34\x50\x7a\x06\x7f\x19\x2a\x83\x4d\x05\xc9\x76\xeb\xf2\x83\x38\x59\x46\xa9\x65\x5d\x3c\x4d\x0b\xc9\x30\x36\x9e\xa6\x6f\x54\x73\x86\xa8\x41\x27\xa7\xfa\x9a\x0e\x6a\x4d\x6a\xa5\x0c\xf4\x34\x6e\x96\xee\x72\x18\x9a\x41\xc3\x83\x3a\xea\xf6\x55\x40\xe3\x12\x27\xea\xe6\x78\x45\xcc\x69\x2e\x3c\x68\xb6\xdb\xc0\x2d\x3f\xc8\x61\xd2\x67\x36\x0e\xb3\x72\x7d\xd3\xe2\x32\x59\xeb\xa9\x78\x98\x01\x15\x3b\x68\xe1\x49\xed\x3d\xca\xdb\xe9\xa3\xc9\x68\xfa\xed\xd3\x39\x3e\x2f\x07\xd4\x4a\x1a\xbd\x99\xc7\x34\xae\xea\x7b\x79\x44\xb3\x91\x00\x74\xa9\x96\xb5\x38\xbf\xcf\xea\x0b\x33\x03\xbe\x4f\xe6\xd9\x42\xde\x5e\xf3\x6c\xd1\xe8\xf7\x5a\x65\xe0\x96\x10\x4a\x69\xf2\x30\x88\x21\x75\xf4\x73\x7b\x9a\xbb\x74\x19\x90\x71\xb3\xc7\xc7\xd3\xda\xc3\x50\x01\x4b\x24\x5c\x4b\x58\xed\x07\xa3\x1c\xf0\x83\x51\xa0\x72\x1e\x2f\x20\x9b\x17\x72\x6c\xd9\xbc\xe8\x8d\x6d\xc4\x03\x39\x10\xdf\xe7\x01\x85\x18\x54\x6d\x87\x56\xad\xf9\x43\x8e\x0e\x21\x6b\xac\xfc\xf9\x1b\x36\x9b\x4c\x38\xc8\x10\x99\xf3\x05\xcc\xac\x81\x4b\x62\x8f\xe7\x5c\x27\x2d\xb4\xf5\xc4\x1e\x95\x7d\xb5\x3d\x94\x4d\x4c\x62\x6d\x44\x35\x49\x0a\xeb\x36\x50\x06\x60\xe6\x1a\xe5\xf8\x3e\x0e\x5a\x09\x50\x80\x96\xf3\xaa\x96\xed\xf2\x6e\xc5\x68\xab\x9d\xed\xce\xbc\xd8\xb5\xf2\xda\xec\x27\x90\x6b\x0d\xc6\x08\x99\x4f\xb5\xe6\xfb\x16\xbd\xfc\x83\xdb\x8b\xe5\x0c\x08\x22\xdb\xed\xa6\x82\x37\x5a\x76\x42\xcc\x29\x2b\x22\x62\x2c\x7b\x94\x91\x3c\x97\xeb\x65\xf4\x7d\xb6\xdb\x77\x92\x7c\x30\xaa\x39\x96\x2a\xdf\x6e\x2f\xe1\x5a\xbe\xf0\x3f\xcb\xff\xde\x6b\x25\xc2\xb7\xea\xcf\xac\x6b\x48\xa4\x69\x48\xed\xab\x2e\xe0\x00\x40\xee\xd2\xc6\xa7\x47\x79\x30\x5e\x6e\xb7\x9e\x20\x85\x32\x1d\xce\x42\x92\xdd\x85\x1f\xce\x4f\x4e\xaf\x4f\x3f\xfc\x32\x68\x3b\x84\x47\x5a\x1f\x7c\x64\x07\x29\x61\xa3\x14\x9a\x47\xa4\x51\xb2\x1d\xdd\x90\x18\xcb\xe2\x62\x45\xec\x9b\xe7\x9e\xa6\xa9\x7d\xda\x7c\x26\xb9\x90\x15\x8b\x87\x2c\xd6\x26\x48\xb2\x60\xac\xd1\xf4\xe8\xd3\xc5\x7b\x0f\x44\x49\xb0\x94\x24\x32\x42\x88\x87\x19\x21\x49\x71\x72\x7e\xa6\x87\x14\x37\x2a\xd6\xff\x5e\x74\xb4\xaa\x25\x1d\xcb\xc7\x08\x3d\x6c\xb7\x57\x01\xd8\x6e\x03\x8e\x6e\x35\x78\x3f\xa1\xd4\xe2\x69\x49\xed\x07\x9b\x84\x16\x79\x8a\x1f\x34\xc3\x5a\xed\x49\xee\xc1\x5a\xdb\x9d\x16\x17\x65\x96\xd1\xec\x56\xd2\x8e\x5a\x7f\xf1\x23\x51\x0e\x92\xae\x6a\x19\x95\x7b\x1b\xbc\xf7\xfd\xe0\xbd\x51\x74\x0c\x80\x59\x17\x50\x69\x9f\x69\x6f\xd3\xb4\xaf\xe0\xfa\x29\xdc\xd1\x6c\x00\xe0\x27\xb5\xcf\xad\x91\xdb\xa6\x82\x9f\xac\xa7\x90\xf9\xa2\x82\x38\x49\xba\xcd\x11\xb0\xa9\x37\xd6\x85\x12\xd5\x49\x74\xd0\x6a\x06\xd4\x8d\x28\x03\x39\x43\x40\xda\x34\x49\x63\x58\x1f\x14\x03\x8d\x7f\x0a\xdb\x13\x51\x63\xac\xc7\x11\x10\xd5\x38\x59\x72\x52\x28\xfd\x64\x65\xdd\x3d\xa4\xb7\x7f\x1e\xd6\x1e\x4d\xda\x5d\xef\x74\xe7\xa1\xde\x52\x92\x88\xf8\xe0\x1a\x83\x11\x00\x38\x22\x4a\x27\xd2\x3a\x1f\x72\xb7\xf6\xc9\x11\x89\x5a\x93\x9f\x93\xc5\x2c\x09\x58\xab\x0c\xfc\xca\xf5\xdc\x88\x07\xd0\x1a\x01\x90\x1b\x5b\x33\x4b\x59\x7f\x08\x6b\xb3\x72\x39\x22\xc7\xf9\x40\xa0\x94\x2f\xf7\x7a\x15\xd1\x23\xfd\xd4\xf5\x43\x52\xe3\x76\x84\xd0\xdd\x91\xf7\x6f\xde\x84\x45\xec\x11\xbf\x22\xbb\x9a\x7a\x7f\x54\xbb\x06\x09\x18\x88\xb8\x36\x86\x64\x8f\x38\x18\x69\xea\xf4\x5a\xdc\xe7\x56\xe4\xac\xf6\xd8\xb6\xdd\xca\xc1\xdf\x1e\x05\x3c\xcc\x59\x1e\x00\x38\x3e\x04\x51\x90\x2b\x46\x88\x75\x34\x32\xba\xc7\xb5\xc9\xa0\x8b\x21\x38\xd1\x0e\xc1\x2c\xa6\x30\xde\xad\x3c\x00\xc7\x53\x50\x19\x4e\xc5\xdb\x1b\xc6\x45\x44\x42\x96\xa9\x5f\xdb\x6d\xe7\xf2\x6d\x63\x36\xd0\x73\x40\xf6\x29\xd3\xed\x24\x23\xa5\x58\x4b\x92\x51\x03\xde\xf1\x48\xeb\xd9\x46\x23\x6f\x42\xc0\xac\xb5\x93\x3e\x6e\xb7\x6d\x8e\xc2\xf5\xd1\x30\xb0\x42\xc1\x20\xb1\xc2\x51\x62\x25\xd2\x91\x81\x47\x3d\x0f\x35\x1c\x35\x0f\xf5\xab\x3d\x0f\x3d\x6a\x62\xcb\x5a\xc5\xcf\xe3\x15\xce\x6e\x49\xe7\x3c\x4a\xf4\xa5\x15\x7a\xb5\x29\x22\x09\x25\xce\x07\x15\xb4\x19\x2d\x2b\xae\xbd\xe8\xc6\xf0\x52\xd6\xba\x21\xed\x23\x08\xa1\x4c\x1e\x3a\x89\x4b\xc9\x76\x8b\xc1\x86\xfb\x7e\x86\x10\x5a\x29\xad\x58\xdf\x97\xc7\xbd\x6f\x0f\x14\x70\xe3\x96\x42\xed\x4c\xad\x6e\x3c\xcb\x1b\x6f\x13\x1f\xcc\x22\x8f\xb4\x93\x90\xa2\xb1\xcb\x0c\x47\x67\xf8\x33\x19\x15\x25\x27\xa3\x07\x56\x6a\xb2\x43\x9b\xe5\x1a\x0b\xdb\x7f\x2f\xbc\x3f\x8f\x24\x61\x70\xaf\xb7\x4c\x26\xcb\x19\x96\x5a\xf1\x15\x24\xf2\xb4\xea\x91\x53\xdf\x0f\x28\xda\x98\x7b\xb5\x50\xae\xc7\xd6\x06\xd9\x6c\xb7\xf3\x05\x4c\xd5\x5c\xb5\x05\xdb\xa6\x82\x09\x5a\x5b\x23\xb6\x4d\x05\x97\x88\xba\x65\xef\x10\x75\xcb\x3e\x20\xda\x94\x9d\xc5\xd6\x29\x65\x50\xa0\x78\xb7\xed\xd7\x98\x05\x4b\x48\x60\x0a\xef\x60\x02\x1f\x40\xa5\xa4\x61\x7b\x8b\xc7\xad\xe2\x20\x0a\x24\xe6\x97\xb5\xf4\x9c\x6e\xd5\x9d\xfe\x45\xa1\x78\xe7\x5c\x6b\xf9\xf7\x27\x48\x00\x98\xbd\x47\xb7\xaa\xe8\x29\x12\xc6\x0f\x89\x1d\xec\x0b\x6b\x26\x0b\x66\x5f\x94\xce\x7d\x70\x0b\x0b\x78\xda\x78\x39\xd1\x5c\x1f\xb1\xdd\xde\xb6\xb4\xd0\xcd\xa1\x7f\xab\xad\x2a\x3f\x41\x01\x6f\x65\x0b\x82\x05\xb7\xb0\x84\x77\xf0\xa1\xd5\x82\x5b\xcc\x98\x1c\x12\xa8\x55\x9a\xa3\x0c\x5a\xdb\xba\x88\xd6\x66\x76\xd0\xd0\x43\x4b\xfb\xf4\xbb\x33\xaf\xba\x87\x0a\xa8\x7f\x15\xe4\x65\xdb\x18\x2c\x09\xc6\x9f\xc2\xfa\xa6\x86\xe6\x16\x97\xd8\x04\xa7\x9c\xe0\xe4\x61\xc4\x75\x96\x07\xe0\x5b\xd4\x65\x8a\x09\xb9\x8b\x9d\x53\x19\x08\x79\x6f\x23\x94\xc9\xab\x5c\xd3\x55\x99\x0b\x80\x23\x5b\xfa\xad\xb6\x5b\x68\x01\x27\x22\x76\xbe\x9f\xe0\x67\xc4\x95\x05\x44\x0b\x25\x49\x5a\x44\xde\x98\xfa\x30\x5b\x87\x8d\xbe\x3f\x90\x18\xd8\x8e\xda\x08\x40\xde\xb1\xf5\x64\x15\x3f\xb0\x75\xe7\x9a\x9f\x6d\x12\xa3\xc6\x12\x7d\x2b\x22\xf3\xbe\x84\x85\x60\xf9\x53\xe9\x12\x6e\x5c\x4e\xf6\x27\x31\x94\xfe\xb4\x79\x4c\x95\x01\x90\x2d\x32\x70\xcb\x70\xc7\x26\xb0\xe6\x4d\xf7\x8b\xc5\x8d\x21\x91\x61\x48\x0c\xb0\x31\xd6\x6d\x83\xcd\x91\xf0\x7d\x31\x27\x8b\x0a\xee\x62\xc8\x74\xb0\xa8\x2c\x8c\x32\xd5\x93\x03\xcc\x81\xd1\x68\x64\xda\x2d\xb8\xc3\x60\x6b\x5d\x1f\x82\x76\x85\x1d\x96\x59\x16\x79\xb9\x85\x77\x99\x60\x19\xcc\xe6\x16\xdd\x69\x6b\x65\x81\xf3\xb8\x35\x55\x87\x16\x3b\x92\x4f\x32\x3d\x89\x88\x06\xeb\x86\xae\xf3\xfd\x22\x58\xd7\x1a\x43\x92\x3c\x35\x77\xcb\x76\x5b\x06\x66\x68\x8a\xc6\xa8\xe0\x9a\x7e\xa1\x59\x11\xcd\x8f\x17\xb0\x16\x61\x44\x9b\x5a\x66\x7f\x6f\x45\x9d\x3d\x76\x45\xe4\xb2\x2b\xee\x77\xb3\x3f\xee\x77\x18\xe2\xb9\x6c\xd1\xfd\xfc\xd0\xa9\x6d\xea\x53\xa5\x6a\xbe\xcb\xa8\xa0\x38\x55\x3a\x44\x43\xe0\x44\x9f\x3b\xe6\xa5\x17\x24\x26\xf4\x4e\x71\xee\x8b\x1e\xcf\xb1\x20\x42\x6b\x23\xad\xd1\x67\xd0\xa9\x68\xd8\x95\xed\x63\x2a\x0f\xae\x3e\xf8\x59\x42\x78\x9f\x35\xf5\xa9\xc7\xa0\x3b\x74\x18\x52\x69\x87\xed\x44\x6a\xe6\x57\xc3\x8b\x33\xae\x26\x1b\x8e\xd9\xc0\x33\xc0\x5a\x43\x4b\x64\xea\x3c\x08\x4c\x2a\x80\x9f\x8c\x83\x73\x87\x95\x9e\xef\x72\xaf\x92\xec\x96\xfa\x2d\x9f\x69\xda\xbc\xd2\xec\xfa\xdd\x36\x41\x6b\x5d\xc0\x5a\xe7\x16\x07\xef\xd6\x54\x82\xff\x47\xed\xc9\xd7\x22\x1a\x0f\xc0\x3b\x5d\xd2\xbe\x78\x8b\x83\x9f\x71\xb1\xb2\x0d\x7a\x00\x3e\xf4\xf2\x35\x01\xeb\x14\xb9\xed\x16\xb9\xd0\xc8\xda\x29\x72\xda\x2d\x72\xa9\x9e\xa2\x4e\x89\x63\x5d\xe2\xd2\xb5\x64\xf6\x00\xbc\xd0\xc9\x8e\xa1\x7f\xf1\x13\x67\xeb\x0b\x09\xab\x63\x73\x7c\x3c\x00\x6f\x74\x31\xb9\xf9\xdb\x19\x5f\x74\x46\x83\xe7\x3d\x00\xef\xfb\xf6\xad\xd7\x5d\xab\x43\x78\xa6\x53\x9a\x91\x7c\x1c\x34\x57\x3c\xd7\xa9\xda\x8b\x25\x80\x27\x6d\xcd\x8a\x2b\xfd\x69\x5c\x01\x17\x4d\x63\x1f\xfa\xae\x76\xde\xa1\xe5\xd1\x5d\xe4\x1d\x78\xf0\x12\x2d\x8f\xd6\x6a\x73\xb6\x1c\x68\x01\xd7\x9b\x78\xe0\x5d\x1b\xaf\xc3\x9e\xbc\x8d\x77\x58\xb4\xd9\x0e\xa3\x57\xb0\x1e\x64\xf4\x0d\xec\xb9\x2b\x18\x10\x6c\x36\xb6\x70\xd0\xf5\x40\xd5\x5b\xa2\x68\x7a\x08\xdb\x00\x8e\xa6\xaa\xef\x3d\x06\x5e\xf0\x29\x5b\x33\x9a\xaa\x81\xee\x5f\xf9\xe8\xa5\x2a\xd4\x5d\xf7\xe8\xa5\x9a\xc4\x8e\x4d\x1d\xbd\xfc\x1e\xee\xdd\xd2\xd1\xcb\x1f\xe0\xde\x0d\x1d\xbd\x3a\x84\xfb\xb6\x73\xf4\x4a\x69\x47\x75\xd7\x3d\x7a\xf5\x0d\xb4\xcb\x26\xf1\xed\x10\xcf\xf8\xf9\x66\xdd\x7b\xdc\x46\xbc\x7c\xbe\xb3\x63\xc5\xc9\xf3\x3e\x65\x9f\x33\x76\x9f\x35\x92\x9f\x9a\xe1\xcb\x77\x73\x9e\x39\xb0\x2f\x77\x31\xe7\x8b\x20\x83\x1c\x12\x30\x6b\xb1\x25\x14\x29\xea\xfb\xb1\x7c\x3a\xb3\x70\x4d\x8a\x02\xdf\xb6\xbc\xca\xb3\x86\x9a\xd1\xd2\x13\x00\x33\x54\x8b\x2e\x66\x8d\xa8\x37\xa8\xbd\xc5\xa0\x2c\xbc\xa7\x69\x7a\xe5\x30\x14\x1a\x07\x32\xbd\x4c\xb9\x87\x00\x14\xfd\x50\x09\x45\x48\x8b\x5f\x70\x4a\x93\xfa\xce\x00\x8d\x43\x3f\x2d\x4f\xd6\x43\x12\x2d\x85\x01\xa5\xff\x2d\x6f\x93\x9a\xe8\x6a\x94\x14\x7c\x9f\x07\x22\x74\x58\x71\xd0\xc9\x84\x19\x80\x02\x21\x94\x1e\x2d\xc3\xbe\xab\x96\x80\x05\x19\x00\x91\x2c\x90\xd7\x05\x5a\x0e\x57\x9c\x12\x49\x5d\xc2\x1e\x5b\x93\xb9\x6c\x79\x48\x91\x69\xd0\xb9\x48\xb3\x5a\xd5\xd7\xf7\x69\x90\x39\x8a\xbf\xa0\x1b\x7a\xc1\xb2\x70\xed\x24\x8b\xd0\x9e\xb5\xda\x93\x25\x69\x05\xef\x08\x08\x92\x80\x05\x4a\x94\x5d\x16\x2b\xe5\x12\x04\x8a\x4a\x7b\xc2\x74\xae\xcb\xa7\x48\x98\x87\x6e\xd3\xd4\x5c\x0c\x76\x87\x16\x07\x2d\x4f\x37\xe6\x1e\x6e\x15\x68\xfb\xab\x31\x17\x72\xab\x84\x83\xff\x97\x2d\x4c\xbe\xc7\x27\xdf\x9e\x41\x44\xd3\xef\xe0\xbe\x21\x44\xd3\x6e\xf5\x06\xed\xbe\x3c\x7c\xa2\x4c\x69\xdf\xf1\x7f\xcc\x8a\xd6\x39\xfe\x35\x61\xc7\x82\xc6\xd1\xc7\x2d\x11\x35\xe3\xda\x38\xfc\xc8\x0d\x33\xa4\xe7\xc9\x7d\xf3\xc5\x5a\xff\xe6\xf8\x96\xfc\xaf\xf3\xe5\xb2\x20\x62\xbb\x4d\x58\xac\xc4\xf7\xa1\xfd\x61\x8e\x97\x61\xfc\xbf\x27\x4b\x01\x1f\xdc\x9a\xff\xf1\xc4\x9a\x57\x2c\xaf\xfe\x60\x97\x31\x1d\xbb\xe0\xff\xac\xb3\x8d\x97\x8f\x19\x15\x67\xa1\xbb\x5d\x1e\xdb\xd0\x59\xf8\x9e\x66\x9f\x7b\xa5\x64\xa2\xca\x6d\xed\xad\x47\x37\x7f\x16\xda\xbd\xb6\xef\x14\x64\xe1\x70\x6b\x4d\x2b\xfa\x29\x65\x64\xc2\xc3\xe5\x1a\x9d\x35\xd3\x9c\x2d\xdd\xa9\x0d\xb3\xd0\xbd\xa7\x1f\x21\x4c\xb3\xb0\x73\x6d\x3f\x4e\xa8\xca\x39\xb7\x2e\xf2\xc7\x09\xd7\x2c\x6c\x5f\xed\x8f\xd2\xb1\x59\x78\x45\x0a\xb1\xab\xb8\x9b\xa7\x0a\x0f\x13\x3f\x4f\xa6\xde\xb3\xf0\xd2\x1c\x86\x2b\x96\xef\xaa\x3d\x50\xc4\x85\x5f\x97\xd0\xcd\xc2\x0f\xf8\x8e\xde\x3a\xe3\x6f\xbe\x6b\x88\x98\x2d\xa1\x6d\x70\x94\x34\xb4\xb9\x68\x5a\x98\xd3\xcd\xa8\x8b\xf5\xb7\x7d\xbb\xb4\x9b\x5f\x57\x1a\xd8\xdf\xed\x5a\xad\x02\xcd\x90\x5a\xdb\xbc\x33\x2a\x93\xd7\x1e\x7f\x9f\xce\x7c\xda\x23\xc4\x36\xd2\x2b\xad\xc1\xcd\x4b\xd3\x0e\x2f\x33\x9b\xac\xef\x92\x36\x99\xee\x40\x3b\x7a\xdd\x23\xbe\x15\xc0\xa3\xe9\xf4\x39\x34\xf4\xfe\xad\x10\x4d\x5f\x3f\xef\x12\x53\x18\x27\x9a\x7e\xff\x9f\xb9\xdb\x86\xd0\x89\xb1\x29\xd8\x85\x3e\xa2\x97\x2f\x61\x17\xae\xd1\xcb\x57\x4f\x7e\x24\xfc\xdf\x7e\x0d\xec\xc0\x02\xd1\x2b\x35\xad\x66\x53\x44\xaf\x5e\xc9\xcb\xe3\x31\xfb\xf9\x41\x63\x63\xcd\x80\x22\xdb\x2d\xee\x53\xb3\x83\xc6\xc7\xaa\xf6\x76\xdb\x76\xaa\x4d\x80\xef\x93\x90\xdc\x11\x2e\x89\x7a\x63\x71\xdc\xd0\x6c\x1d\x6f\x1e\xae\xd5\xff\xcb\xe7\x99\x48\x13\x84\x50\x61\x64\x2e\x81\xd5\x19\x99\xa0\xa9\xd5\x19\xd0\x9c\xf5\xbc\xcf\xdd\x95\xf4\x78\x44\xaa\x59\x3c\xe0\x48\x1d\x6c\x0c\xb7\x3a\x87\xa2\xa5\x43\xc2\x6a\xe6\x51\xbf\xc5\xd9\x0e\x2f\xf4\xdb\x6d\x90\xd7\x12\x31\xef\xc0\x9b\x10\x2d\xb8\x73\x9e\x0f\xea\xf5\xc0\x02\x60\x1b\xa7\x33\xaa\xf9\xeb\x3c\x20\xdb\x6d\x11\x7e\x3c\xff\x08\x34\xa5\x42\x8d\x9e\xe5\x3e\xce\x8d\x55\x00\x6f\xf0\x71\x8c\x94\x50\x67\x3c\x85\x39\xda\xf4\xd8\xe9\x2d\x36\x70\x6c\x69\x6d\xc8\x02\x00\xd3\xed\x36\x30\x84\x15\x4e\x92\xd3\x3b\x92\x09\x5b\xeb\x68\x47\x7a\xe0\xad\x70\xb1\x8a\x55\x0f\x1e\xc4\x72\xaa\x96\x36\xc3\x42\xe0\x78\xa5\x4a\x07\x1e\xcb\x5a\xe5\x24\x39\x3e\x3e\x54\xdc\xba\x3e\xa3\xbc\x3d\xc2\x01\x49\x52\xa3\x1b\x23\xc6\x08\x91\x0a\xc0\x43\x84\x50\x5c\x87\x3d\xb3\x93\xd0\x8d\x0f\xce\x63\x20\x6b\xcf\x54\x9c\xd2\xc3\x53\x99\x82\x0a\x4a\x48\xb6\x7d\xc9\x99\xad\x6a\xe3\x14\xd9\xf3\x2c\x9f\xc1\x2b\x44\x6a\x19\x74\xaf\x92\xf1\xae\xd3\xab\x67\xb7\x55\x37\xdd\xb2\xcb\x27\xdd\x8c\x82\x60\x1e\xaf\x26\xde\xbf\xc9\x6d\x58\xc1\xbc\x2d\xda\x50\xe3\x3b\xff\x08\x4b\x1b\x39\xe9\x71\x3e\x7e\x42\x62\x96\x90\x4f\x17\xef\x7a\x63\x58\x71\xb2\x0c\x8b\x3c\xa5\x22\xf0\xfe\xcd\x03\xf3\xe9\x62\xbb\x55\x7e\xe7\xad\xbb\xe1\x7e\x6b\xde\x1b\x17\xaf\xfe\xd9\x6b\xf9\xd9\xb1\xaa\x74\xad\xab\xee\x31\x2f\x40\x2f\x1f\xb3\x8e\x6c\x63\x13\x17\x67\xc4\xbb\x71\x46\xb1\x0f\x67\xc4\x3d\x9c\x21\x1b\x66\x34\x19\x69\x33\x70\xe5\xbe\x4f\xbe\xeb\xb1\x3e\xd7\x35\x6e\xdc\x7b\xa8\x69\xef\x50\x1b\x89\xe7\x78\x0a\xe3\xc7\x0e\x75\x51\x1f\xea\xf2\xf7\x1c\xe8\x9c\xe5\x85\xb6\x94\x66\x7b\x8e\xb3\x53\x4a\xe2\xa0\xa7\x1d\xe6\x02\x15\x4f\x3c\xcc\x45\xef\x30\xef\x9a\xc0\xe0\x49\xde\x31\x87\xce\x39\xee\xce\x61\xf0\x14\x77\x82\x8c\xc9\x7c\x2d\x98\x30\x52\xdc\x0a\x7a\x9e\xf2\x37\xd0\xdc\x46\x50\xad\xf6\xa7\xcb\x9f\xc1\xf0\x19\xef\x34\x69\x8a\x0c\xb6\x2a\x5b\x32\xe8\xc0\x1c\x60\xaa\x4e\xeb\x7f\xe6\xa8\x3e\x82\x2e\x1e\x3b\xb3\x6d\x6a\xa7\x73\x6c\xe3\xdf\x73\x6c\x5f\x3d\xcd\x02\xd4\x7d\x76\x38\x6f\x22\xd6\x3b\x2b\x18\x6d\x76\x2d\x63\x5a\xbf\xb3\xf6\x2e\x4d\x0f\xe5\x5a\xf4\xc9\x06\xa1\xdf\x15\x27\xef\x05\x60\x87\x1a\xec\x00\x10\x0f\x01\x70\x88\xc4\x94\x70\x7b\xcc\x4e\xb1\xc5\xae\xa1\x4a\xfd\xc8\x51\x19\x5c\xb3\x84\x2e\x1f\xfa\x4a\x8c\x1e\xf8\x57\x38\xb5\xff\x9a\x20\x0c\x2e\xeb\x69\x67\x58\xb5\xc1\x80\x6a\x48\x0c\x84\x1f\x68\x6f\xc2\xc7\x9c\x75\x61\xc7\x00\x62\x4f\x4c\x00\x5d\xe7\xab\x37\xed\x37\xca\x6e\x3f\xff\xc6\xdf\x75\xe1\x38\xbc\x94\x87\x11\x71\x58\xb4\x5c\x68\xaa\x73\xd5\x49\xcd\x59\x8e\x78\xd7\x58\x77\x0f\xc3\xec\xd5\xbf\xcc\xe2\xfe\x6f\x99\xc5\xed\xdc\xc7\xf4\x51\xe2\xa6\xe8\x21\xec\x72\xf7\xde\xe7\xf5\xde\xff\x1f\xda\xbf\x89\xe1\x41\x09\xa5\x8e\xa6\x92\xd2\x3a\xdc\xab\x4d\x31\xc6\x48\x16\x6b\x2a\xa0\x07\x8e\xc5\x79\x7d\x62\xac\x2a\xb5\x27\x31\x7a\x7f\xd7\x8f\xa7\x5d\xfb\xa6\x56\x93\x43\xc6\xae\x66\x89\x91\x3b\x58\x1b\x1c\xb9\x6e\x2b\x63\x82\x2e\x1f\x8e\xcd\x13\xa2\x6f\x64\xd4\x84\x63\x36\xde\xe9\xad\xd7\x97\x21\xfa\x14\x66\xe8\x10\x72\xd4\x06\x45\xbd\xd3\xde\xf0\xd9\x64\x92\x81\x76\xee\x3c\x5b\x38\xb2\x61\x27\x36\x48\x8f\xb0\xdc\x69\xc1\xd5\xf4\x64\xa5\x35\x8d\x89\x50\x9f\x0a\x7c\xbc\x99\xee\xf8\x1f\x25\x13\xeb\xfe\xb4\x27\xd5\x1d\xed\xbb\x64\x5b\x60\x11\xe8\xf0\xf6\x30\x79\xee\xda\x04\xd4\x90\x71\xcd\xdc\x8c\x9b\xd6\x7e\x77\xda\x51\x55\x67\xc9\x5b\xf7\xad\xa9\xdc\xd2\xee\x57\x1a\x9f\x4a\xe7\x3f\x63\x8e\xaa\xaf\xdb\xd4\x7c\xa0\xdd\x17\xd3\x85\x75\xa1\xdc\x1d\x70\x4d\x2d\xd6\xf0\x61\xf9\x2e\xc3\xbe\x1a\x3a\x4a\x49\xf9\xf9\xb0\x51\x8c\x0a\xf8\x3b\x2e\x9f\xfd\x53\x7b\xfa\xb5\xe4\xbd\x71\x59\x63\x92\x94\xea\xc7\x5b\x28\x9f\x4d\x92\xee\x15\xd2\xbc\x7a\xcc\xcd\x6f\x5f\x44\x3e\x10\x9b\x43\xf8\x7e\x90\x21\x01\x85\xb6\x8c\x30\x17\x15\x0b\x6a\x33\x18\x68\xa9\x31\x15\xeb\xc6\xf2\xde\x54\xd4\x75\x89\x8f\x5d\x87\xd8\x6d\xc6\x71\x57\x26\xd5\x67\x80\xca\x49\x3c\x43\xce\x6f\xd9\x54\x99\x66\x33\x33\x1e\x96\x05\xe1\x6f\x6f\x49\x26\xcc\xb8\x82\x17\x53\xc5\x04\xb3\xd1\x1c\xbc\xb7\x59\xc2\xe5\x13\xf8\x65\xe8\x01\xdf\xdf\x95\xfb\x4d\x78\xe8\x81\xed\xb6\x9b\x7d\xc6\x6e\x68\x4a\x46\x97\x78\x89\x39\xd5\x05\xc6\xad\x02\xc7\x2b\xce\xd6\x64\x28\x47\xbb\xc1\x2f\x46\x1f\x57\x2c\x23\x1e\x00\xcd\xeb\xd1\xec\x31\xdf\xf7\xea\x07\x9c\xbc\x3e\xdb\xb9\x60\x20\x4c\xf6\x33\x24\xa2\x5a\x2d\xc0\x70\x54\x87\x29\x8a\x96\x30\xd6\xe2\x85\x1b\xa2\x48\x0c\x92\x18\x44\x60\x6c\xc1\xcb\x4c\x5f\xe1\x89\x57\xaf\xbf\xae\x2e\x91\x6d\x33\xd0\x56\x93\xae\x02\x7d\xdb\xfc\x8d\x41\xac\x83\x52\x52\x34\x9d\xd1\x7e\x10\x79\x2a\x49\x92\xcc\x09\x20\x4f\x17\x90\xd9\xc6\x3f\x93\x87\x22\x30\x9d\x67\x00\x34\xc6\x7c\xe8\x70\x56\xbc\xa9\x63\x58\x17\x93\x09\xc0\x73\x36\x2f\x16\x0b\x94\xe9\xbf\x55\x13\x2e\x57\xc3\x73\x40\xc4\xd9\xcc\x45\x0b\xbf\xe8\xcd\x81\x15\x74\xa8\xdf\xd1\xab\xef\x64\xcd\x01\xfe\xb6\xf3\x2e\xac\x83\x12\xd6\x2f\xc2\x03\x15\x37\xb1\x75\x20\x36\x75\xa9\x88\x43\x95\x1d\xb1\x4a\xf7\xa4\x0b\x47\xaf\x14\x6f\xbf\x69\x2c\x7a\xa5\x1e\x5a\x03\x5c\x6a\xa7\xef\xd2\x68\x64\x31\xb4\x49\x48\x4a\xd7\x54\x10\x1e\x79\xbe\x07\x13\xa5\x28\xf9\x1a\xaa\x20\x89\xef\x65\x46\xf4\xf2\x10\xd6\xe1\x94\x74\xca\x94\xbc\xaa\x66\x4c\x47\x79\xfc\x45\xa2\xb9\xae\x63\xc9\x86\x88\xdc\x54\xca\x84\x51\xb3\xd9\x24\x89\x67\x3a\xb3\x21\x68\xea\x46\x11\x42\xd3\x83\xc3\x23\xcd\x87\x8a\xba\xb9\x92\x7e\x3b\x84\xb4\x09\x3e\x8e\xdf\xd0\xd9\x64\x82\xf5\xa4\x0a\xc4\xe6\x78\x01\x4b\xa4\x0e\x66\xd1\x9c\xae\x05\xf2\xc0\x91\xf3\x8d\x3c\x10\x75\xb2\x27\xd3\x19\x5d\x6a\x74\x50\x82\x6c\xce\x43\xcd\x85\x08\x0a\xb0\x40\x9e\xd7\x18\x28\xc5\xa8\xc9\xaa\xe3\x82\x96\x00\xc0\xb4\x9f\x51\x4e\xa6\xda\x6e\xda\x6c\xc6\xe6\xb9\xd0\x51\x27\x8a\x01\x88\x59\x26\x68\x56\x92\x59\xd6\xcf\x3c\xca\xe6\xf1\x02\xcd\x17\x92\x9a\x8e\xb1\x08\xe4\x27\xb0\x1f\x29\x88\x54\x76\x5a\x53\xc7\x59\x05\xcd\xa2\xe8\x7e\x7b\xce\xfe\xe5\x3b\xc2\x9a\x93\x5a\x6b\x00\x61\x59\x15\xda\xff\xaa\xa2\x94\x37\x95\x1c\xbc\x37\x5f\x78\x08\x21\x0e\xb0\xa4\x52\x31\xc2\xb6\xe7\x56\x27\xd6\xca\xa8\x81\x14\x45\xde\x5c\x55\x9c\x1f\x2e\x7c\xdf\xd3\x8d\xcc\x79\x73\x59\x1e\x71\x03\x27\xf9\x50\xb0\xa9\x20\xe2\xb0\x40\xaa\xe1\x77\x99\x08\x28\x9c\x1e\x4a\x2a\xdb\xf3\x26\xc5\x6c\x4c\x8b\x0f\xf8\x43\x50\x00\xdf\xe7\x63\x65\x1e\x52\x22\xf5\xa7\xf8\x33\x3a\xf4\xfd\xe2\x0d\xca\xc2\x66\xc3\x1e\x05\x7a\xc0\xf3\x62\x81\x06\x87\x1a\xe1\x39\x1d\xce\x6a\xce\xbe\x85\xe4\x5f\xc9\x43\x31\x04\x47\x62\x8f\xd3\xc1\xdf\x82\xf9\xdf\x7e\x9b\xff\xb6\x58\x7c\x0d\x0e\x20\x46\x07\xc1\x6f\x73\x9b\xf0\xdb\x02\x1c\xdc\x42\x2a\xdf\x47\x5f\x48\x1c\x10\x1d\x37\xf7\xb1\x4d\x41\xe7\xd3\x05\xb0\x1b\x7b\xbe\x98\xc9\x6f\xdf\x37\x54\xab\xca\xac\xb1\x59\x29\x1f\x69\xda\x8d\x47\x40\x11\xb6\xdd\x00\xdf\x2f\xdf\x64\xa1\x3a\xcb\x33\x30\x99\x94\xf0\x29\x7d\x3a\x61\x58\xe7\xdb\xdf\x16\x07\xb7\xd0\xf3\x00\xd8\x6e\x5b\x3d\x5b\xcb\xfb\x7a\x40\xde\xdc\x9b\x10\xb3\x9e\x54\x1f\x2d\x30\xf1\x16\x12\xb7\xb4\x00\x5c\x98\x10\x1d\xae\xf1\x79\xef\x95\xeb\x29\xd1\x94\x0e\xed\xa3\x7f\x69\x7c\x20\x7f\x9b\x0d\xbb\xa9\x66\x26\xba\x1e\x74\xd0\x09\xea\x59\xce\x3a\x99\xdb\xad\xd6\x19\x57\x41\xa4\x9d\x74\x70\xe4\x7c\x44\xac\x85\x9c\x14\xec\x90\xa7\x95\xd1\xdb\xad\xe6\x62\x75\x64\xfe\xaa\x4a\xb9\x58\x41\xe1\xec\xbf\xa1\x5a\xce\xee\x74\x3f\x22\xe6\x7c\xf4\x51\xe2\x40\x43\xed\x12\x47\xdd\x84\x88\x75\x12\x66\x0d\x2a\xee\x81\x88\x1c\xb5\x70\xb8\x5a\x85\x88\xa8\xf3\x0f\x69\xeb\x22\xcd\x80\x09\x39\x4f\xeb\x8b\xd3\x44\x9a\x37\xb8\x91\xce\x8b\x05\x4c\x91\x73\x68\x82\x18\x4a\xf4\x04\x05\x98\x61\xc4\xc3\x35\xe1\xb7\x24\xc0\x30\xad\xcf\x18\x0f\x63\xb6\xce\x71\x2c\x02\x0c\xcc\x8d\xa6\x6f\xa5\xe8\x9b\x43\x79\x81\x0d\x08\x46\x9e\x72\x81\x29\x78\x7e\xe4\x64\x49\xbf\xfc\x45\xbe\xcb\x24\xf9\x57\x44\x1b\x1b\xe7\x77\x47\xb0\xed\x89\x44\x76\x15\xa4\x59\x42\x63\xb2\xa7\x90\x37\x11\x72\x73\x2b\x4e\x2c\xc1\x62\x47\xc1\xaa\x92\xd7\x63\x7d\x25\x0f\xe1\x0f\xb9\x23\x7f\x2c\x97\x4b\xc2\xb5\xf9\x05\x09\xed\xcb\x21\x00\x51\xdb\x14\x16\x0b\x62\x0a\xbc\xbb\x3c\xaf\xcb\xd8\x23\xa2\x2c\x86\x3d\x0f\xc0\xfe\xf2\x6e\xb7\xbd\x0d\x24\xd3\x6e\x18\x4b\x09\x76\x28\x7b\x7b\xb4\xe6\x24\x33\x0c\x78\xc7\x15\x0b\x98\x78\xc8\x9b\x0c\xe4\x10\xb0\x30\x51\x22\x25\x8e\x5a\x06\xbd\x93\x3a\xc2\xf5\xe6\x6b\xef\x26\xf2\x94\xdd\x34\xc3\xa8\x2b\xb1\x3f\x72\x6e\xa0\x26\xa2\x33\x91\xbb\x2c\x0b\x04\x8c\x81\x46\xee\x3b\x0b\x09\xb5\x80\xb1\x5c\x40\x65\xb3\xd2\x20\xfb\x5d\x28\xa9\x1d\x80\xbc\x9e\xa1\x83\x36\x8e\x1c\xb4\x11\xb9\xf4\x0d\x37\x60\x31\x11\xa1\x1b\xcf\x4b\x0e\x7a\xab\x03\x89\x6b\x40\xce\x30\x32\xc8\x41\x47\xa7\x1e\xd1\x6c\x64\x10\x44\x77\x43\x1f\xb5\x0a\x46\x9e\xd9\xb8\xf2\x81\x20\x91\x82\xf9\x3c\xaa\xd3\x15\x1f\x80\x60\xe1\x35\x45\x9d\xc5\xd9\xd1\x89\xa4\xa9\x8a\xee\xca\x95\xe8\x10\xc6\xb5\xb0\x6b\x56\xbe\x89\x67\x93\x49\xa9\x57\x2e\x45\xc5\xbc\x5c\xcc\x38\xe2\xc3\x6b\x90\x2e\x60\x0a\x29\x70\x50\x80\x8a\xc5\x99\x0d\x9d\xff\x6f\x06\x24\x2c\xe6\x96\xbf\x62\x3d\xfa\xa6\xc5\x80\xb2\xfc\x25\xd2\x65\x29\x35\x42\xce\x79\xb6\xf0\x7d\xe5\xf8\x41\xfd\x6e\x34\x9b\x2b\x98\x69\x5c\x35\xc0\x82\xad\xfd\xdf\x90\xc1\x85\xad\xb3\x7b\xfb\x96\xd8\x88\xb6\x11\x99\x8b\x05\x1a\x1f\xc2\xe1\x16\xea\x93\x43\xd0\x9c\xd4\x54\x9f\x00\xb3\xbe\xee\xca\xb8\x13\x23\x5e\x7b\x0e\xe8\x00\x48\x92\x02\x8d\x56\x7b\x6b\x25\x85\x44\x9d\x87\xf2\x85\x65\x81\xc4\xde\xe0\xd9\x64\xc2\x80\xa1\xe1\xf8\x9c\xc9\xd5\x17\x73\xba\x98\x91\x39\x5d\x1c\xc9\xff\x90\x01\x4e\x20\x3f\x60\x21\xe7\x43\x17\xa8\xa8\x6a\xc4\x07\x33\x43\x0b\xb7\xd6\x46\x45\x6a\xea\xc8\xf8\x1c\x44\xe2\x10\x1e\x13\x49\x75\x8c\x3c\x60\x83\x1d\xb5\x90\x2a\xcc\xec\x95\x31\x40\x39\x3c\x7e\xcc\x46\x44\x53\x0e\xf3\x85\x21\x79\x85\x13\xcc\x51\x3f\x02\xc6\x92\xdc\xb5\x5b\x61\xce\xd5\x01\xae\x95\xbb\x61\x77\x15\x9a\x4d\xc7\x34\x85\x2c\x5f\x28\xa4\xfb\x42\x71\x36\x1d\x5e\xf8\x3e\x33\xcd\xcd\x71\xb3\xeb\x98\xd1\x19\x6f\x1f\x35\xb5\x72\xba\xd1\x62\xf0\xd9\x53\x22\x79\x44\x67\x64\x5e\xca\x85\xb1\xb7\xa9\xfc\x84\x02\xb4\xd6\xc4\x52\x3f\xa8\x6f\xab\xec\xcd\x35\xe4\x46\xba\x84\xa2\xd6\x7b\xd4\xa2\xbd\x9b\x34\x0b\x96\x00\xdd\xa6\xbe\xbf\x06\xda\x1c\x19\x9a\x94\xf8\x7e\x33\x7b\xdf\x57\x51\x20\x1c\x4f\x6f\xbe\xdf\xfa\xac\x5b\xdc\x95\x2e\x41\x6e\x1e\xe5\xdf\x3c\x23\xc8\xdf\x92\xc5\x65\xf1\x81\x25\xc4\x06\xf9\x7b\x2c\x68\xa3\xf1\xcf\x5e\x0a\xf6\x93\xac\xaa\x4c\x1c\x0c\x3b\xfb\xe4\xfc\x4c\xb6\x14\x80\xc1\x60\x73\x4d\x4f\xd1\xf4\xb5\x7c\x85\x7f\xf3\x9c\x70\x73\x16\x7a\x41\x2b\x2a\x46\x13\x2a\xc3\xc4\xcf\x90\x87\xbf\x29\xa2\x3c\xc9\xa5\x3a\x6c\x46\x5b\xa3\xc3\x44\xc3\x22\x26\x1a\xd6\xc7\x50\xb0\x5c\x1d\x3a\xad\xdc\x7e\x29\x30\x17\x51\xed\xd5\x23\xee\xe4\xcc\x06\x2b\x9d\x66\xc9\x60\x95\xd3\x2c\x19\xae\x60\x42\x5c\x0e\xd5\xd1\x59\x55\xcf\xff\x51\x8d\x02\x11\x52\xad\xfd\x95\x3c\x9c\xb0\xfb\xcc\xf7\xd5\xc1\x38\x96\xb8\x05\xa1\xe3\x9e\xeb\xa1\xa1\xe9\xfe\x95\x3c\x7c\xca\x4d\xe7\xea\x70\x9f\xd6\x27\xbe\x6e\x0c\xcc\x5a\xe5\x65\x57\x51\x6d\xe6\x62\xca\x8c\x11\x3a\x6e\x17\xfb\xc8\x49\x51\x44\x4d\xd2\x19\x2b\x0b\xa2\xea\x36\x69\x3f\xa6\x25\x8f\xac\x33\xa1\x99\x31\xa8\x89\x1a\x31\x4d\x3d\x83\xa2\xd1\xec\x21\x61\x42\x04\xa6\xa9\xd5\xd5\x33\x58\xcd\x65\xc2\x7a\x09\x16\xd8\x5e\xf4\xf2\xb7\xb6\xf1\xac\x5b\x2b\x9b\xc0\x7b\x0a\x49\xc0\x58\x62\xb1\x8b\xa3\x12\xc9\x6d\x11\x5d\x1d\x49\x80\x71\x79\x5f\x94\xa8\xbb\x88\x20\xc2\x3b\x32\xd5\xa6\x00\x70\x5c\xb6\x7c\xc0\xdd\xfb\x7e\x70\xb5\xdd\x96\x63\x34\x50\xfa\x48\x3e\xd2\xbb\x3d\xf8\xfe\x95\xef\x07\x31\xba\x52\xa7\x09\x0b\x1c\x00\x10\x5d\xa1\xb5\xfc\xfc\x28\x09\xd3\x24\x10\xc0\xc6\xd9\xbe\x73\x52\x4b\x35\x25\x39\x95\x18\xa4\x6a\xde\x28\x6e\x78\x0e\x39\x2a\x02\x0e\xec\x5b\x38\x57\x31\xb4\x55\x99\xbc\x46\x84\xcb\x10\xc7\x71\xb9\x2e\x53\x2c\xc8\xd5\x3d\xfb\xb8\xc2\x05\x39\x31\xd6\xf5\xa4\x08\x52\x00\xd3\x96\xc7\xa7\x5d\x9b\x6a\xf8\x38\xc8\x1b\x75\x68\x8b\xd4\x5b\xe9\x7e\x45\xe3\xd5\x18\xa1\xeb\x23\x39\xc8\x28\x38\x91\x64\xc0\x99\x5b\xe7\x8a\x7c\x11\xef\xb2\xbc\x14\x91\x26\x37\xf5\xea\xd6\xf6\x60\x08\xa1\x33\xdf\x3f\xd1\xd5\xb3\xce\x7e\x1a\x69\x3b\xdf\x7a\xfc\x69\x7d\x31\x5e\x69\x76\x85\x3d\x4d\xed\xd1\x6f\xb7\xfa\xf4\xe8\xad\x92\xb9\xab\x32\x6b\x6c\xca\x49\x4a\x70\x41\x82\x2b\x00\xaf\x8c\x57\x85\xca\xed\x75\x08\x48\x1f\x71\xd1\x1c\x7b\xb5\x55\x1e\x85\x8d\xef\x8f\x79\x20\xc0\x91\xb9\x69\x96\x9c\xad\x8f\x57\x98\xcb\xf3\x17\x98\x22\xfa\xd5\xf3\x28\x6a\xba\xd7\x30\x32\xf0\xdb\x0f\xa8\xbc\x7d\x5a\x98\xe2\xd0\x04\x0c\x7d\x39\x8a\xd5\x49\x88\x52\xf5\x07\xf4\x5c\x1f\x62\xf4\xe0\xec\xce\xf3\xf0\x86\x2c\x19\x27\x6a\xfd\xf4\x4e\xb5\xaf\x0b\xbd\x0f\x19\x7c\x64\xff\x61\x00\xb1\x22\x03\x8c\xc9\x96\x52\xf9\x3a\x66\xea\x1d\x28\x8a\xc6\x5a\x4b\xa5\x7f\xe4\x2c\xc7\x4a\xb2\x21\x73\x8c\xa9\xf4\xb0\xe9\x8f\xb5\x93\xfe\xc9\x84\xfe\x6f\x5f\x01\xca\xb2\xc1\xd8\x47\x5f\x3e\x64\x62\x45\x04\x8d\x5d\xa8\xde\xe9\x46\x1e\x3a\x45\xd4\x3c\x6d\xa6\x31\x8e\xfe\x4c\x1e\xce\x97\xca\x10\x7a\xfe\x03\x9c\xbe\x82\x2f\xbf\x83\xaf\x5e\x2e\xe0\x31\x7a\xf9\xf2\x07\x78\x81\x56\x8d\x11\x92\xef\x7b\xbd\x3e\x6a\xd1\x06\xbc\xd1\xbe\xd0\xda\xe5\xad\x81\xd4\x99\xbc\x5d\x69\x36\xb2\xdf\xbe\x1f\xdc\xa0\x9e\x19\xd5\x99\x42\xec\x12\x9a\x5f\x3a\xfd\xca\x43\xd6\xe9\xd0\xf7\xc7\x37\xbe\x3f\xee\x99\xdf\x1b\x49\x0b\xcb\x09\xc7\xbb\xf0\x31\xf1\xfd\x01\x51\x19\x09\xef\x08\x2f\x28\xcb\x7c\xbf\x66\x68\xd6\x69\x01\x80\xd3\x43\xf0\x06\x4d\x5f\x56\x01\x80\xf7\xed\xf1\x05\xe3\x8b\xed\xf6\xc6\xf7\x6f\xfe\xfc\xbd\xef\xdf\xbc\x41\xd3\x29\x80\xd7\xe8\xd5\x4b\x78\x86\x86\xce\xc5\x35\x80\x1f\x51\x22\x4f\xc2\x7b\x72\x47\x52\x6d\x74\x79\x8e\x36\xce\x66\x8c\x36\xb9\xdc\x69\xc9\x05\xb9\xa5\x85\xd0\x1e\xab\x95\x1b\xc3\x68\x73\x53\xde\xdc\xa4\x24\x89\x6e\x83\x0d\xcb\x7e\x74\xaa\xa8\x33\x02\x60\x8c\x73\x51\xf2\x81\x02\xc7\x3a\xc3\x94\xab\x60\x42\x72\x92\x25\x24\x8b\x29\x29\xa2\xf9\xc0\xc9\x84\xad\x83\x0f\xdb\xe8\x0e\x36\x18\x63\x61\xdc\x26\x34\x47\xfa\x89\xa3\xef\x20\x82\xc1\x09\xb4\xcb\x3c\x61\x0e\xf2\x02\x87\xfb\x66\x23\x2f\xfc\xa1\xa9\x29\xba\x03\xb6\x09\x83\xf6\xd4\x34\xf5\xf5\xfc\xc9\xe9\x7a\x8f\x4d\x4f\x95\xfa\xbd\x13\x54\x95\xff\x80\x29\x1a\xd2\xef\xf9\x73\x34\x15\x1f\x9b\xa4\x2e\xf6\x7b\x67\xa9\x6b\xff\xce\x69\x56\xf0\x04\x8d\xa7\xf6\x36\xfc\x80\x36\x2a\x38\x96\x76\x66\x72\x0e\xc9\x17\xc1\x71\xac\xb1\x4c\xd1\x71\xc0\xd2\x28\x2d\xcd\x1b\x3a\x0d\x36\x97\xd0\xa2\xf5\xac\xf8\xa0\x9f\x15\x9d\xab\x20\x7a\xad\x6c\x7d\x7a\x17\x41\xf4\x5a\x19\xf1\xec\xb6\xe3\xdc\x73\x09\x44\xdf\x2a\xfb\x9d\xdd\x57\x40\x34\x7d\xf5\x0a\xee\xb8\x01\xa2\xe9\x2b\x65\x3f\xa5\x2f\x80\x68\xfa\xfd\x54\x3e\x7d\x9e\xa7\x74\xe0\x70\x59\x45\x63\x9a\x12\x0a\xf6\x29\xcf\x09\x3f\x96\xf4\x07\x98\x88\xb0\x28\x6f\x34\x43\x29\x98\x5a\x95\xcf\xcd\x0d\xfb\xf2\x53\x4a\xbe\x44\xe3\x43\x68\x7e\xfe\x85\xb3\x32\xd7\x7e\xc2\xd3\x72\x9d\x1d\xab\x57\xde\xf8\x10\x2e\x4d\xb1\xa5\x2e\x73\x6f\x7f\x6b\xef\x67\x77\xc4\x7e\x5f\xae\x38\xcd\x3e\xdb\xaf\x0f\xe4\x16\xd7\xb9\x2c\x13\xbf\x12\x7a\xbb\x52\xed\xa5\x34\x23\xc7\x29\x5e\xe7\xf6\xe3\xe7\x3a\x8b\xe5\x38\xa6\xe2\x41\xfd\xe4\x09\xe1\xfa\x47\xbe\xc2\x59\x21\x7f\xde\xd3\x84\xdd\xab\x5f\xff\x7c\x27\x5f\x24\xea\x17\x63\x6b\xd5\x07\x4d\xd3\xf3\xa6\x7a\x21\x38\xfb\x4c\x4e\x70\xb1\x62\xca\x6a\xb8\x49\xeb\x15\xfa\x95\x26\x62\x15\x8d\x0f\x2b\x88\xd1\xdc\xfb\x95\xdc\x7c\xa6\xc2\x83\xde\xba\xf0\xa0\x77\xc6\xfe\xe9\x41\xef\xdc\x5b\xcc\x5c\x2e\x03\x03\x83\x96\x02\xb8\x9f\x2a\xc0\x86\xcd\xb9\x72\x4b\xbe\x40\x6c\x4e\x16\x15\xa8\xac\xaf\xb8\x8d\xdc\x53\xb7\x9c\x95\x12\x61\x37\xbf\xdf\xad\xf1\xad\x82\x5a\x93\x54\x07\x30\x6e\xa5\x5e\x68\x66\x7a\x2b\xed\x98\xa5\x8c\xab\xb9\xdc\x68\x00\x6e\xf4\x5f\x3b\x47\x93\xac\x63\x5f\xd5\x9f\xdd\x5a\x3f\x32\x21\xd8\xda\xd6\xd5\x5f\x9d\x16\x74\x62\xa7\x1d\x9d\xd8\x6d\xed\x3d\x59\x0a\xdb\x96\xfc\xdd\x69\x49\x26\x75\xda\x91\x49\xdd\x56\x54\x1c\x71\xdb\x8c\xfa\xe8\xb4\xa3\xd2\x3a\x0d\xa9\xb4\x6e\x4b\x57\x2c\xb7\xed\x5c\xb1\xbc\xd3\xca\x15\xcb\x3b\x6d\x5c\x49\x0c\x68\x5b\x90\x3b\x39\xda\xc8\xff\xeb\x52\xf2\xe3\x17\xad\x3a\xd4\xdf\xeb\xaa\x24\xfd\x27\xe9\x6f\x75\x99\xf3\x13\x5e\xd3\xf4\x41\xb9\xe2\x87\x05\xda\xd0\xe2\x53\x46\x45\x4a\x8a\xe2\x83\x12\x40\x44\x0c\x16\x2b\xc6\xc5\x0a\x67\x89\x95\x39\x9e\x7e\xc9\x71\x26\x09\xa2\x22\xa2\x55\x27\xca\xae\xc4\x1f\x4f\x8f\x1c\x7e\x70\x7c\x79\x69\x5b\x6d\x74\x29\x76\x90\xc3\x18\x05\x5a\x05\x09\xaf\x49\x4a\xff\xa9\x83\xa7\xa9\x70\x7f\x00\xaa\x8c\x04\x67\xb7\x84\xb3\xb2\x50\x39\x4a\x34\xe6\x81\x3a\xa0\xd0\xea\x21\x5f\x91\x0c\x8b\x56\x3d\xa3\x06\xb2\x26\x6b\xa6\x5a\x94\x08\xea\x3c\x4b\xb5\x9e\xa8\xee\xae\xf1\xea\x50\x0c\xf9\x45\xa6\xca\x79\x04\x80\x31\xf2\xe2\xa2\xf8\x29\x65\x58\x78\x33\xe6\x52\x86\xb5\xf0\x61\xb7\xcf\x00\x39\xa2\xd0\x56\x57\xaf\x6c\x4f\xa5\xe9\xe6\xec\xa3\x7a\xa3\x95\xab\xce\x30\xff\x5c\xe6\x3f\x31\x7d\x82\x8a\x01\x57\x6b\x5e\x23\x22\x50\x5e\x82\x09\x90\x0f\xc9\xbe\x2f\xee\x5a\x2e\x37\xcf\x16\xe6\x05\xce\x7d\x3f\x10\x13\x54\x06\x19\x98\x78\x91\x07\xc5\x04\xe1\x40\xde\x6f\x13\x6f\xe6\xd5\x2f\x72\xa1\x59\xb4\xca\x77\x9b\x82\xf3\xd0\x68\xe4\xd5\xa0\x1f\xa7\x26\xc0\x5f\x3d\x28\xb6\xdb\x4d\x0b\x03\x96\x8d\x8d\x03\x06\xc5\x9c\x2d\x14\xe7\xc0\x5b\x2a\x48\x20\x84\x98\xef\x07\x0c\xc5\x00\x52\x90\xcd\xd9\x02\xd1\x86\x95\x50\x20\x1e\xee\xd9\xac\x73\xa6\xb8\xc2\x05\xa8\x65\xf0\xca\x11\x32\xc8\xe6\x65\xad\x30\x32\x52\x6d\x7a\x5e\xd5\x8e\x0b\x9f\x1a\x27\x46\xce\x6e\x8d\xbe\x79\xf5\xd8\x9d\xdd\xdf\xa8\xd1\xf4\x1b\xa5\xf3\x33\xb4\x53\xa3\xe9\x6b\xd5\xe2\xc0\x3e\x8d\xa6\xdf\xa9\xac\xfe\x36\x8d\xa6\xdf\xab\x9c\x8e\x6f\x8d\x6f\x9e\xe5\x5b\x43\xeb\x5b\xc6\x86\xc2\x28\x34\x6d\x64\x12\xb5\x73\x36\x9d\xe6\xea\x01\xea\xd7\xb3\xf2\xe7\x6c\x5d\x59\x84\x3d\xff\x28\xe6\xe4\x39\x1a\xdb\x33\x1c\x70\x37\x7a\x08\xc9\xfe\x51\x92\x92\x74\x76\x4d\x77\x40\x9d\xef\x46\x1b\xbb\x19\x5f\xfb\xd3\x2d\x61\x6b\x75\xd4\x72\x6d\x51\x2b\xe0\xa9\xa0\x56\x38\x7d\x9b\xa6\x3b\x42\x0d\x34\x4d\x41\xd1\xe9\x6f\xa6\xf5\x4a\x68\x60\x65\x08\x4a\xd4\x68\xd4\x75\xba\x03\xd9\x09\x5f\x47\xe2\xdf\x13\x82\x65\x93\x09\x20\x8d\x2a\xb5\x92\x7c\xd5\x9d\x1d\x42\x51\xff\xac\x2a\xc8\x49\x41\xfa\xbc\xf1\xa7\x2c\x30\x4c\x48\x1d\xcc\xa5\x5b\x5f\xb5\x1a\x80\xaa\x02\x90\x85\x38\x49\xe4\x0e\xa0\xd9\xed\x15\x0b\x38\x80\x3d\x3d\xd0\x01\x4f\x30\xed\x4d\x13\x7d\xab\x28\xcf\x9e\xca\xeb\x37\x8f\xf9\x25\x19\x62\xbc\x7b\x97\xa7\xef\x4f\x8f\xaf\xb4\x79\x74\xc6\x12\x75\x6c\xb6\x5b\xef\xdd\x87\x8f\x9f\x3a\xa9\xf2\xd9\x4f\x53\xa2\x13\xe5\x26\x1c\x74\xef\xf4\xa5\xc5\x21\xd2\xf6\xb7\xf0\x0a\x12\x30\x3b\xde\xcf\x0c\x12\x00\xde\x84\x37\xea\xc3\x04\x50\x29\x02\xdc\x72\xb8\xaf\x5c\x3a\x9d\x86\x66\xe7\xeb\xb7\x86\xdc\x96\xa7\xa1\x71\xbe\xa5\x92\xfe\xa7\xcc\x0c\xfa\x7e\xfa\x4f\x10\x81\x57\x48\xc0\x93\xae\x8d\xa4\xb5\x11\x66\x2d\xef\xfc\x60\x73\xe2\xfb\xc1\x89\xe2\x4d\x0f\x16\x86\x27\x7a\x37\x5c\x19\xaf\xe9\x5d\x66\x74\x87\x07\xa9\xbd\x88\xd6\x5a\x6b\x6d\xae\xab\xf6\xd0\x65\x8a\x2a\x01\xcc\x51\x50\x04\x3a\x3a\x72\x06\x40\x54\xe7\xc9\x77\x9d\xef\x17\xee\xf4\xd2\xf6\xf4\x3e\x20\x12\x2a\x35\x6c\xf8\xce\xca\xb4\x6e\x89\x70\x2e\x8a\x13\xa2\x63\x75\x30\xde\x96\x4c\x39\xc8\xc5\x18\xae\xec\x32\x52\x39\xb1\x05\xe0\x7b\xd0\x07\x67\x6e\x8a\x59\x48\x25\xc0\xe5\x3c\x6a\xb0\x26\x24\x25\x82\x8c\x4e\xcc\x48\x7b\x50\xee\xb7\xd1\x86\x36\xfc\xa0\xff\xbc\xeb\xc2\x3e\x31\xea\xbd\x66\x80\x6a\xab\xda\xc6\x54\xc4\xe1\x5a\xe6\x50\xf0\xd8\x12\x11\xaa\xec\x4c\x8c\x11\xfa\xe0\xfb\xc1\x07\x24\x20\xd3\x62\xb7\xba\xd9\xe5\xd0\x92\xaa\xd7\xe0\xc0\x8a\xae\x76\xad\x68\x1e\x00\x98\x0e\xaf\x68\xee\xae\xe8\xda\xe9\xad\xe9\xee\x92\xa4\x44\xe5\xeb\xad\xb4\xdd\xba\xd2\xa2\x4f\x79\xfb\x5b\xbe\xd9\x81\xef\x9f\xf8\xbe\x81\xb1\x9c\x9c\x1d\xeb\x07\x64\x01\x7f\xd5\x74\x7a\xe7\xe0\x84\xc1\xc3\x1f\x78\xf1\x8a\xc4\x9f\x6f\xd8\x97\x06\x03\x6c\xb7\x1e\xc7\x09\x65\x4d\x8a\x33\x8d\x87\xc1\x73\x90\xd2\xf8\x73\x03\x34\xed\x17\x7a\x98\xf9\x7b\xea\x32\x7f\xd3\xf2\x96\x66\x3f\x97\x37\x8d\x4b\xc9\x01\xa6\xf0\xc5\x5e\x2a\xf8\xc6\x3a\x83\xc4\xb1\x30\x08\xa6\xf1\x24\x59\xbf\xf1\x2d\x83\xf7\xde\xba\x9e\x54\x09\x97\xda\xe5\x1f\x49\x1a\xa7\x92\xb4\xa8\xb9\x79\x66\x23\x35\xee\x25\x2d\x5b\xf8\x23\xba\xed\x33\x2a\xf5\xa6\x7e\x02\x93\xe8\x4c\x71\x7f\x74\xe9\x2e\x67\xc8\xc9\x7b\x1e\x3b\x48\x23\xe4\x66\x2d\x60\xb3\x43\x61\xb3\xad\x87\x99\x44\x96\x2d\xd4\xd9\x8a\x9a\x39\xb4\xf3\x78\xc2\x4b\x34\x9e\xce\x2e\x5a\x2c\xdf\x4b\x74\x2f\xf7\x93\x3a\xdd\x2a\x2a\x7b\xb0\x93\xdb\x0d\x06\x5c\x86\xc9\x32\x7f\xfe\xde\xc8\xcc\x3e\xf7\x9b\xff\x2c\x9b\xa7\x72\x22\xbf\xbb\xf5\x1f\x4c\xeb\xef\xd1\x66\xd0\xe8\x6c\xf4\x4e\xe2\xd5\xc6\x3e\x0b\x28\x92\xbe\xf5\xa4\xf8\x80\x3c\x6f\x42\xe0\xbb\xb0\x70\x0b\xea\xc0\x58\x6f\x9f\xc3\x40\x33\x0a\x2a\x18\x52\xe5\xde\x5e\x49\x8c\x8e\x30\x2a\x23\x8a\xe2\xe8\x5a\x7e\x7e\x3e\xc2\x68\x19\x05\x18\xad\x21\x45\x2b\x10\xdd\x69\xed\x18\x8c\x1e\x00\xac\x15\xc6\xb1\x8d\xb7\xa0\x68\x79\xa3\xbd\x34\x78\x5f\x17\x90\xd5\xc2\x9c\x47\xae\x6d\x25\x43\xac\xa8\xef\x53\xab\x4f\xec\x92\xff\x6f\x1f\xe7\xe6\xd5\x27\x3b\x7a\xfd\xed\xef\xe5\xf1\xb5\xce\x74\x34\xd5\x6e\x42\x3b\x47\x3a\x9a\xbe\x7a\x0d\x87\x4e\x74\x34\xfd\xee\x5b\x38\x7c\xa0\xa3\xe9\x77\xdf\xf7\xb9\x7c\x8f\xb9\xf0\xd1\x4f\xc3\x43\xa5\x78\x61\xfc\x51\xe1\x58\x5c\x30\x26\x34\xdf\xab\xbf\x97\xf8\x64\xd2\xd3\xad\x90\x3d\x3d\xc7\xed\x8e\xb9\x73\x42\x9a\x15\x84\x0b\x2d\xb9\x08\x04\x24\xda\xff\xe3\x07\x96\x90\x62\x9e\x2d\xf4\xf3\x13\xb8\x0f\x92\x13\xf5\xa4\x6a\xde\x22\x6a\xb4\x67\x65\x2a\xa8\x72\xb5\xa4\xc1\xda\x89\x31\x5c\x10\x21\x81\xa5\x3c\x50\x67\x4e\xa4\xc1\x76\xcc\xd3\x4d\xfd\x5a\x4b\x1f\x2e\xb4\xbe\x93\x1c\xc7\xaf\x54\xac\xf4\x53\x3c\x62\xe1\x63\x45\xa0\xb6\x74\x73\x7a\x8b\x28\x34\xf4\x9e\x59\xf1\x68\x97\x35\x4d\xa9\xf1\x4f\xac\xff\xa4\xe8\x70\x96\xbe\xa9\xdf\x06\xe9\x64\x22\xdf\xd1\x19\x52\x3a\x7a\x99\xba\xbd\x10\x42\x38\x3c\x3b\xff\xe5\xf4\xfa\xf4\x7f\xbd\xbb\xbc\x7a\xf7\xe1\x2f\xdb\xad\x93\x73\x71\xaa\xf2\x3e\x9c\x9f\x9c\x02\x23\x82\xcf\x94\x70\x4a\xad\x2b\x4c\x50\x16\xe6\x98\x93\x4c\xc8\x29\xb8\x70\xcf\x17\x70\x59\x67\xbe\x3b\x99\x15\x41\x22\xe1\x53\x2a\x95\xee\x72\xbe\x5c\x20\xf9\x9f\x7a\x7b\xc9\x1f\xf3\x7c\x81\x12\x18\xa3\x58\xa5\x18\xef\x3f\x89\x5e\xb4\x15\xea\xc0\x2c\x4b\x08\xd7\xa0\x0a\x84\xd1\x15\xb0\x10\x58\xa3\xc3\xd9\xfa\x8d\xf5\xb8\x33\x5b\x4f\x26\x20\x9e\xaf\x17\xee\x20\xad\x19\x28\x4d\x93\x40\xe6\x35\xba\x73\x77\xe8\x70\x76\xd7\x80\xeb\x6e\x32\x01\x46\xea\x2d\x41\x76\x67\x41\x66\x24\xe0\x38\x7c\xf7\xe1\xf2\xf4\xe2\xea\xfa\xec\xed\xc5\x5f\x3f\x7d\x8c\x78\xe0\xc2\x02\xae\xe6\x59\xb8\x56\x83\x54\xa0\x52\x95\x99\xfa\x09\x66\x37\x9c\xe0\xcf\x33\xd3\x4a\x0b\xf8\xdd\x56\xca\x79\x03\xc3\xc5\xdc\x01\xfd\xee\xf6\xae\x4e\xff\xd7\xd5\xf5\xf1\xf9\x87\xab\xd3\x0f\x57\x11\x6d\x37\x97\x85\xa2\xd9\x55\x9d\x7a\xce\x52\x47\x6d\x8e\x86\x36\x54\xb4\xa7\x26\x7a\x3d\x85\xfb\xcf\x4c\x34\xd5\x8e\x93\xbb\xde\x7d\x7b\x87\x28\x9a\x7e\xaf\xf4\xa7\x9e\xe3\x1d\xa7\x11\x22\x04\xc4\x17\x40\x05\x19\x73\x8e\x76\xdb\x69\xe6\xe6\xec\xd3\xe5\xd5\xf5\xa7\xcb\xd3\xeb\xb7\x57\x57\x17\xef\x7e\xfc\x74\x75\x1a\x4d\x61\x9d\xf8\xf1\xe2\xfc\xe3\xe9\xc5\xd5\x7f\x44\x2f\xe1\xcf\x6f\x2f\xaf\x2f\xdf\x9d\x9c\x5e\x9f\xfe\xf4\xd3\xe9\xf1\xd5\x65\xf4\x8d\x4a\xfa\xf1\xfc\xfc\xfd\xe9\xdb\x0f\xd7\xbf\xbc\x7d\xff\xe9\x34\xfa\x5e\xa5\x7d\xf8\x74\x76\x7a\xf1\xee\xd8\xa4\x4d\xbf\x55\x89\x1f\xcf\x2f\xdf\x5d\xbd\x93\xf0\x6b\xe5\x7e\xa3\xab\x9c\xff\x72\x7a\xf1\xfe\xfc\xed\xc9\xe9\x49\xa7\xc5\x6f\xbf\x81\x3a\x38\xd1\xc9\xf9\x99\x7d\x6d\x1c\x2b\xa3\xfa\x01\x56\x1d\x09\x4d\x11\x4a\x74\x94\x93\x0c\x91\xf0\xe4\xfc\xec\xad\x10\x9c\xde\x94\x42\x91\xad\x3a\x87\xea\x9c\x8f\xce\x43\x40\x67\x94\x3a\xe3\xac\x14\x8a\xfe\x3a\x23\x62\xc5\x12\x95\x35\x23\x21\x2d\x8e\xcb\x42\xb0\x75\xdd\xa0\xef\x17\xe1\x75\x2f\xf5\x27\x33\x32\xcb\x26\xe9\xd7\x6b\xce\x54\xac\xd9\x77\x1b\x16\x8c\x8b\x90\x16\x97\x02\x67\x09\xe6\x89\x1c\xd0\x80\x99\x14\xec\x96\x99\xc7\x0b\x34\x3e\x34\x3c\xcd\x38\x14\xec\x3d\xbb\xb7\x82\x22\x75\xa9\xeb\xbb\xbc\x28\xe8\x4d\x4a\x5a\x15\xd3\x05\x8a\xe1\x80\xb5\x55\x8d\xc6\xe6\xf1\x62\xb6\xbb\x7a\x2e\xab\xab\xec\x16\x74\xe5\x78\xf2\x4a\x71\xff\x86\x33\x53\xd3\xa6\x03\x78\x99\x4c\x07\xcc\xbe\xe8\x3c\x5e\x44\x31\x2c\x07\xb2\x54\x1b\xed\x35\x92\xad\x94\xb2\xc6\x8e\xbc\x5a\x65\x25\x41\x42\x4f\x6d\x5d\x16\xe2\x53\x41\xea\x21\xca\x52\x3c\x48\x20\x0e\xfb\xa7\x42\x42\xde\x94\xb7\xe3\x18\x28\x6e\xcf\x8b\x2c\xbd\xc2\xc5\x25\x4d\xc8\xe9\x72\x49\x62\x51\x34\x85\xbb\x07\xc9\x94\xfd\x51\x9b\x23\x28\xf6\x65\xbb\x70\xeb\x40\x98\xd2\x1f\xca\x35\xe1\x34\x1e\x28\xdd\x3a\x5e\xa6\xb4\x15\xec\xed\xae\x35\x7c\x3a\x4d\xf5\xf3\x3b\xc2\x53\x86\x13\x92\xec\x1e\xe4\xae\x03\x0c\xa0\xda\xd8\x03\xa0\xde\x6e\xc7\x43\x20\x95\x15\x86\xd2\x55\xf1\x1e\x4c\x55\xf3\xe3\x21\x00\x4e\x4c\x72\x67\xce\x36\x79\xe7\x9c\xde\xa0\xa9\x32\xcf\xa2\x68\xa3\x64\x38\xef\x4e\x9a\x4d\x70\xfd\xe1\xed\xd9\x69\xa4\x34\x0f\x5f\x28\x43\x73\x9a\x78\xb0\x7d\x1e\xa3\x8d\x72\xc6\x36\x74\x64\x4c\x56\xeb\x44\xd8\xe2\xce\x69\x30\x49\xed\x0d\x2c\x13\xbb\x30\x74\xd2\x6c\x7d\x99\xd4\x86\x91\x49\x71\x27\x69\x92\x5c\xc0\x98\xa4\xa1\x7d\x62\xb2\x86\xe1\x25\x33\xf7\xa0\xbf\x68\xbe\x80\xbd\xdc\x1d\xfe\x32\x0e\x67\xe2\xcd\x7e\x5c\x6a\xa8\x0e\x31\x99\x68\x36\xc8\x21\xdc\x5b\x7e\x2e\x16\x40\xc5\xd7\xb3\x71\x2c\x6b\x95\x53\x09\x5e\xe3\xf8\xd4\xca\x5b\x6a\x00\x0e\x48\x5c\x20\x47\x74\x4e\x6a\x87\xe8\x7c\xbb\x0d\xe4\x37\xe2\x68\x53\x01\xa8\xcc\x53\x64\x5a\xd6\x88\xa4\x3a\x11\x49\x00\xe4\x73\xb1\x40\x99\x1c\x91\xfa\x59\x99\x3b\x8d\xb2\x2c\xc2\x5d\xa1\xdf\x10\x1f\xf7\xf5\x63\x7e\xb6\x76\x68\x11\x98\x88\xa8\xdb\x2d\xeb\x9d\x10\xb2\xf0\xfd\xb1\xcd\x69\x1d\x12\x99\xa3\x2d\x4d\xe5\x53\x98\xed\x44\x20\xb2\x9c\x78\x33\x35\x45\x76\x1c\x28\xd5\xcd\xb4\x4b\x84\x38\x37\x6f\xf3\xc8\xf8\x47\xc9\x44\xb3\xbb\xed\xca\x18\x47\xb7\xea\x9d\xd1\x95\x21\x76\x65\x78\xef\x4e\x86\x62\x35\xb2\xb0\x77\x86\x95\x31\x17\x56\x1a\xfc\x9d\x26\x76\x6c\x04\xba\x0c\xd8\x23\xb7\x33\x01\xbe\xdf\x2d\x33\x27\x0b\x6d\xe6\xa6\xd5\x4b\x5b\x76\x4e\x19\x62\xfd\x0b\xb2\xd9\x66\x43\x2b\xf6\x04\x50\x2b\xbb\xac\xa3\x2c\xca\xcc\x14\x1b\x0b\x08\xd6\xa7\x42\x02\x02\x8e\xcc\x16\x39\xf2\xbc\x88\xd4\x75\xa2\x9e\x40\x72\x10\x2e\x86\x93\xf7\x18\x64\xc4\x10\x64\xc4\xc2\x70\x30\x34\x18\x3a\xf7\xb5\x50\xd2\x45\x0c\xb0\x0a\x57\xa5\xa5\x89\x9a\xcf\x01\x33\xa0\x7d\xe2\x68\x86\x71\x77\x7c\x0a\xd0\x75\x79\xd6\xbf\x78\xc4\x02\x90\xb0\x70\xe0\x1e\x0c\x2c\x83\x58\x40\xcf\x9b\x64\x2d\x6b\x6e\xd6\x23\x5b\xc4\x62\xc6\xba\x57\x92\x58\xf8\xbe\xe7\x4d\x94\x41\x10\x92\x6d\x6c\xb7\x81\x36\x19\x02\x95\x26\x8b\x86\xd6\xc1\x0d\x29\x75\x64\x5f\x60\x6e\x76\xd4\x19\xb3\xd0\xe3\x53\xac\xbd\x21\x30\x3c\x7f\xfb\xee\x5d\xa4\x6c\xcf\x22\x65\x40\x76\xa2\xe5\xf2\x8f\x43\xbe\x3b\xb5\x41\xe0\x3b\x70\xe7\x83\x70\x87\x66\xd7\xec\xc0\xe2\x41\xc3\xa4\x86\x1c\xec\x59\x24\xbe\x90\x8f\x78\xb5\x44\x7c\x81\xf0\x63\x4b\x34\xb4\x32\x55\x35\x10\x32\xc2\xc5\x6f\xd1\x37\x8a\x57\xb5\x1f\xbb\x45\xd3\xef\xbf\x1b\x10\x3d\xbf\x7e\x86\x9f\x40\x37\xba\xb4\xa3\x1f\x06\x1d\x2f\x2b\xca\xa2\xcc\x41\xc3\x3b\x75\x43\x1c\xef\x34\x8a\x5b\xf1\x13\x67\x6b\x8d\x22\x1b\x7e\x0f\x59\xe7\xe2\xe1\xa7\xda\x9f\x9a\x65\xf7\xc8\x6d\xa2\x4a\xfe\xca\x71\x5e\x7b\x39\x6e\x3d\x3b\xe3\x0e\x17\xa8\x61\x57\xb4\xd0\x77\x19\x38\x9a\x1f\xcd\x83\x49\x40\xe5\x4e\x23\x46\x87\xb3\xb8\xe1\x45\xc4\x93\x09\x28\x95\x7d\x2b\x80\x02\xf1\xfa\x57\x11\x08\x70\x24\x22\xef\x6b\x0f\x66\xf6\x12\x56\x2c\x14\xf9\x43\x92\xb0\xb2\xa0\x79\x3e\xcd\x17\x30\x47\x87\xaa\x23\x75\xab\x67\x8a\x19\xd4\x3f\x28\xfa\x4c\x24\x70\xa9\x5a\x53\xe5\x13\x59\x7e\x29\xcb\x2f\xbb\xe5\x13\x53\x7e\x85\x96\xf3\x64\x31\x93\xff\xa1\x55\x63\xeb\xf7\xb7\xe0\xcd\xfc\x6f\xa3\xdf\x0e\xfe\xbc\x98\x80\x03\xf8\xd5\x9f\xa6\x23\x45\x5e\x6a\x00\xbd\x50\x4b\x87\xbc\xaf\x26\xc9\xe4\x2b\x6f\xf4\x15\xa8\x1a\x3e\x0e\x0e\x96\xda\x6e\xd4\x93\x6b\x02\xa0\x66\xce\xac\x2d\x40\x26\x93\x3b\xdd\xef\x03\x5a\xcf\xef\x16\xb3\x07\x39\x2e\xe7\xdd\xda\xfe\x0e\xbc\x5e\xaf\x8a\x4d\x9e\xa0\xc9\x43\xeb\x84\x0e\x16\x84\x0f\xbd\x83\x31\x58\xac\x0c\xc6\xe9\x00\x78\x60\x2a\x61\xf2\x00\xf3\x89\xa2\xbd\xcd\x2e\x2e\x83\x1c\x21\x94\xd6\x82\xff\x32\x48\x1b\x7d\x80\xda\x7d\x07\x4c\x2b\xf8\x28\x4b\xb1\x8d\x0c\xdb\xfb\x0a\x96\x81\x90\xff\x79\x2b\xb1\x4e\x3d\xe5\x95\x48\xe0\x5b\x85\x21\x5b\x8f\x69\x60\x2e\x6d\x1c\x08\x48\xc1\xfc\x70\x31\x23\x6d\xa6\x99\xea\x58\x73\xcd\x32\xc5\xd0\xef\x39\x57\xdd\xaf\xdf\x32\x78\xda\xa2\xe9\x6b\xc5\x29\x6a\x1f\xb6\x68\xaa\xb9\xe5\xed\xb3\x16\x4d\x77\x68\x01\xbc\x7e\x9a\xb3\xc5\x96\x98\x8a\xa1\x39\x0f\x36\x17\xa4\xc8\x99\x3c\x9e\x0e\x5f\xde\xca\x9d\x78\xb0\xb9\xa4\xeb\x3c\x25\xc3\x79\x57\x38\x1f\xce\x50\x91\x9c\x54\xc4\xa6\xe1\x7c\x2d\x40\xda\xd1\xa1\x92\x32\x0d\xe7\x39\x8a\xf9\xc3\x05\xde\x66\x38\x7d\x10\x34\x2e\x86\xb3\xb5\xf7\x2a\xed\xbc\x4a\x89\xc1\xfa\xc5\x16\x7d\x5b\xc7\x96\x18\xe0\xf5\x63\xca\xbe\x0e\xa0\x7b\xb2\x4d\xb6\x53\x86\x89\x3b\xf2\x48\xa5\x82\x6d\x85\x92\xd4\xe5\xd0\xb3\xd2\xe5\xbc\xdb\xb5\x2c\x11\xef\x88\x1c\x63\x44\xe5\xa9\xfe\x89\xf2\x42\xa8\x9a\x27\xe7\x67\x30\x45\x9b\xb5\x6a\x59\x2e\x50\xb4\xe1\x1d\x29\x64\x54\x04\x1b\x96\x9d\x35\x25\x0c\xe8\xda\xb2\xc5\xb2\xd6\x11\x3f\x2f\x05\x74\xbe\xee\x08\x5f\x54\x50\x75\xa0\x16\x7f\x6f\x07\xba\xc4\xef\xe8\xa0\x82\x39\x9a\x6b\xe3\xac\x32\x4d\x17\x30\x69\xc9\xd4\xd2\x47\x95\xd2\x8d\x5c\xba\xdd\xac\xf2\xd4\xc9\x49\x8a\x05\x49\xae\x30\xbf\x25\x62\xbb\xe5\x8a\xd3\x6c\x9e\x78\x6d\xb3\x28\xd9\xc6\xb8\xd5\x46\x29\x7c\xbf\x93\x74\x47\x78\xcf\x96\xaa\xd0\x76\xd6\xda\xe0\x46\xd2\xf1\xa0\x40\xa2\x21\x85\x12\x24\x42\x76\x9f\x11\x7e\x62\xde\x99\xb3\x02\x25\x47\x89\x8d\x51\xf6\x0b\x25\xf7\xdb\x6d\x62\x90\x92\x76\xa8\x66\xdc\x67\xab\x3b\x7f\x09\x57\xb3\xfe\xf4\x4a\x71\x14\x2c\x91\x80\x2b\x14\x0f\x4d\x52\x30\x3b\xc5\xed\xb6\x00\x51\xb0\x44\x05\x5c\x21\x01\xe0\x12\x21\xb4\xea\xcd\x60\x8d\x96\x47\x6a\x67\xbd\x3b\x09\x96\x20\xf2\x3c\x78\x87\x56\x75\xca\x4a\xa5\x3c\x20\xec\xc8\x17\xd3\xb0\xd9\x12\x70\x2d\xa9\xb5\x07\x2d\x5c\xf1\x54\x7a\x2a\xd3\x3d\xf8\x10\x0a\x35\x24\xb4\x54\x57\x8d\x33\x48\xb4\x32\x81\xa4\x07\x1a\x55\xdb\x14\xde\x39\x56\x68\xb7\x6e\xdb\x44\x66\x7b\xf0\xd6\xb6\xbd\x82\xb7\x9d\xb6\x97\x90\x39\x92\xce\x06\x71\x39\xb2\xce\x07\x78\x0b\xd7\xf0\x0e\xc0\x7c\x7e\xa8\xee\xb0\xf9\x74\x81\x6e\x61\xde\x42\xff\xc9\xef\x31\x60\x70\x4e\x74\x34\xd5\xa1\x17\x87\x30\x40\x34\x7d\xf5\x43\x4f\x1e\xf9\xfa\x19\x5a\xc3\x9f\xc9\xc3\x19\xe5\x5c\x45\x0a\x62\x88\x07\xb5\xae\x81\x16\x94\x59\xed\x02\x73\x18\xb1\x2c\x61\xad\x7a\xb5\xea\x9b\xd5\x20\x68\x3e\x25\xf6\x6c\xbe\xfa\x36\x49\x70\xc8\x06\x7b\x20\xc3\x31\x81\xd1\x39\x4a\xbd\xee\x8c\x64\xa5\x93\x96\x3f\x34\x1f\x65\xd3\xcc\x09\x2b\x6f\x52\xd2\x1e\xca\x09\xc7\xb7\xad\x0f\x77\x40\xfa\xdb\x22\xb6\x3a\xe5\x0b\x15\xad\x84\x06\x35\xd9\x14\x79\x96\x5b\x09\xed\xf9\x9c\x70\x96\xd7\x1f\x3a\x6c\xbe\xfd\x52\x2a\x16\xf5\x57\x63\x74\x06\x1d\x23\x6c\xe7\x5b\x9b\x8b\x3a\x09\x9f\x9a\x86\xdf\x33\xdc\x4c\xa5\x31\xc3\x6e\xa5\x9c\x31\x67\xe4\xf6\xf8\x77\x12\xdc\xb9\xa8\x14\xa7\x0f\x6d\xcd\x6a\xbf\x2e\x94\x62\xa4\xfd\xd2\xe1\x86\x9a\xcf\xb6\x3a\x48\x93\x5e\xde\xac\x1d\x80\x36\xb6\xbe\x75\x0a\x2b\xe3\x95\x8e\x6f\xda\x4e\x73\x97\x4a\x25\xb4\x66\xa3\x52\xda\x70\xff\x75\x45\x4c\x1b\x95\xbc\x25\x37\xad\x1b\x30\xc2\xd0\x1e\x39\xca\x32\xa5\xc0\x50\x44\xac\xea\xbf\xe4\x9a\xd3\x11\x4d\xbf\x3f\x94\x47\x6b\x40\x1b\xd8\x39\x4d\xdd\x57\x11\x43\x1b\xed\x1a\x77\x57\x08\x6a\xd2\x8f\x8f\x10\xf4\xd3\x94\xa7\xe7\xf1\x14\xc0\x8d\x26\xb4\x5d\x85\x01\x32\x18\x49\xc1\x54\xa8\x2a\x10\x11\x57\x1f\x4f\xb5\xde\x56\xcf\xf3\x26\x72\x40\xc3\x4d\x77\xb4\xf0\x74\x51\xd9\xa8\x7e\xf0\x57\x16\x41\xfc\x11\xd3\x3b\x7c\xee\xf4\x0e\xd5\x48\x6c\x1d\xae\xb4\x75\x25\x4d\x41\xb8\x61\x0c\xb8\xed\x0c\x79\xaa\xe8\x93\xd5\x72\x85\x1f\x53\x9a\xed\x52\x71\x9a\x46\x34\x5a\x5b\x0f\x5d\x52\x4e\x65\xda\xd0\xbf\xd8\x86\x73\xb6\x97\xca\xbb\x4c\xb0\x86\x8a\x33\xe6\x46\x6f\xeb\xec\x64\xa7\x1e\x45\xd5\xe8\x30\xb8\x8f\xe6\xc6\x27\x9f\x40\x4c\x39\xc2\x2b\x45\x7d\x5f\xc1\x0c\xa9\x80\x07\x7a\x4c\x67\x2c\x29\x53\xf2\x13\xd3\xc4\x7d\x40\xc0\x2c\xf3\xfd\xac\x5b\xc7\xf7\x03\x81\x7a\xa9\x00\xf6\x1a\x27\xc5\xbb\xec\x9c\x27\x44\xf3\x3a\x21\x09\x69\xf1\x91\xf0\x42\x2d\x98\x08\xc0\x76\xdb\x56\x2d\xb5\xe6\xf4\x4a\xf5\x29\xd7\x53\x49\xd0\xa6\x61\x8c\x9b\x9f\xda\x37\x09\x0b\xeb\x8c\xd0\x49\x37\x7c\xf4\x77\xc6\x4d\x98\x8e\x1f\xd6\x62\x22\xe4\x88\x98\x18\xe7\xc3\x45\xea\x8d\x9a\x5b\xa6\xbc\xb3\x6a\x6a\x3a\x11\x0f\x87\x33\xfa\xe5\x8b\x1f\xb5\x04\x67\xa0\x86\xc9\xaa\xa0\x22\x47\xe5\x4f\x0b\x37\x2d\xcd\x2e\x22\x1e\xee\xca\x82\x5d\x4a\x59\xaf\x9c\xac\xb2\x23\x07\xe6\xa5\x18\x88\xe3\xa2\xf7\x72\x11\x8c\xb3\xed\x76\xc0\x5e\x3b\x03\x30\x28\x15\x7f\x44\xfd\x41\x9b\x0a\x80\x39\x59\xa0\x4c\x41\x70\xb0\x3d\xcb\x1e\x94\xe5\x9d\x90\xbd\xd9\x9c\x2c\x2c\x6b\xf2\xf1\x7a\x99\xef\x1b\xed\x5f\xb7\xde\xdb\x34\xb5\x55\x8b\x61\x99\xd1\x88\x66\xa3\x12\x98\xaa\xb2\x25\x55\xfb\x31\xb5\xb9\xda\xdf\x17\x2c\x10\x0f\x73\xbd\x3a\x43\xfe\xbc\x4a\xeb\xeb\xdf\xf8\xf3\xa2\xcb\x20\xb5\xc2\xf1\x34\x6c\x75\x53\xb7\x3e\xcb\x7d\x3f\xa0\x08\x07\x14\xe6\xa0\xe1\x65\xd0\x0a\xb6\x54\xd4\x5b\xf3\x21\xca\x46\x09\x07\x31\x24\x00\x54\xb0\xa7\xb8\xde\xb7\xa0\x88\x67\xe6\xec\xd3\x80\xc0\x14\xc0\x22\x18\xc7\xa0\x82\xd7\xd7\x79\xc9\x6f\x5b\xe5\x25\xa2\x90\x19\xce\xfa\xfd\x88\xb3\xcf\x03\xfb\xbf\xdc\x49\xb1\x76\xd0\x5b\xf4\xfa\x3b\x38\x84\xdc\xa2\xd7\xdf\xc3\x3e\x6a\x8b\xa6\xdf\x28\xc5\x96\x01\xcc\x16\x4d\x35\xe7\xa3\xcf\xaf\x78\x46\x40\x3c\x1d\xd0\xb9\x56\x6f\x22\x7a\x4f\xd8\xb8\xd2\x73\xb2\x80\x99\xe3\x09\x57\x3b\xb8\xa2\x41\xf6\xe7\x17\x53\x00\xc7\xb1\x5d\xfe\x79\xb6\x00\x1b\x1a\x88\xf6\xaa\x02\xe8\x16\x40\xa2\xf6\x97\xd5\x3c\x29\x6b\xae\x24\x56\x62\x40\x40\x03\x16\xf0\x39\x5e\x40\x01\xb1\x5c\xff\x96\x3d\x84\x11\x98\x04\xe3\x78\xe7\x51\x1f\x30\x2b\x83\xbb\x4b\x2b\xbf\x6d\xb5\xe3\xda\x1d\xca\xc3\x4a\x3f\xd4\xf1\xd1\x65\x06\xba\x0c\xf8\x2e\x73\xb1\x42\x79\x3d\x9b\x61\xeb\xac\xb4\x2b\x41\x1d\x93\x1e\xde\xf1\xfd\x00\x07\xfd\x64\x55\x5f\xdd\xd3\x6d\xf7\x46\x35\x1c\x76\xe0\xaf\x39\x59\xc8\x79\xef\xce\x45\x62\x20\xfb\xc4\x61\x14\xa8\x32\xce\x42\xcd\xb3\x45\xe8\x32\x12\x74\x94\xbe\xfe\xcd\x6a\xec\x79\xcc\x05\xbb\x31\xcb\x1f\xcd\x17\xbb\x11\xf7\xa6\xda\x89\xa0\x07\xb2\xdc\x41\xca\xfc\x1d\x97\x4e\xeb\x4e\x0f\xc6\x85\x1c\x99\x76\xbc\xd6\xb8\x23\x53\xde\x66\xad\x2f\x32\xc8\x03\x30\xd0\x9a\xbd\x92\xfa\xca\x52\xe3\xe9\x73\xec\x1a\x99\xb6\x6b\xec\xe9\xe2\x64\xc0\xf7\x4b\xb9\x0f\x11\x62\xdb\x6d\x40\x83\xb1\xfc\x02\x50\xa5\x31\x28\x54\x7c\x31\xe1\xfb\xdc\x44\xa9\x1b\x22\x3d\x06\x35\xb9\x92\x16\x94\x35\x67\xa4\x0b\x4b\xcb\x7f\xd8\xbd\x53\xfa\x75\x8c\xba\x6b\x7b\xee\x62\xd7\xe1\xd1\x66\x95\x3b\x32\x77\xdb\x80\xee\x1b\xd0\x8e\xc6\xe6\xd9\x62\xa1\x8f\xaa\xd5\x33\x68\x79\x17\x82\xd7\xca\x64\xcc\x5d\xd9\x56\xf4\x92\xb6\xcd\x9b\x41\x83\xbd\xd5\x22\xa0\xbe\x6a\x25\x6e\x9c\xd5\xf8\xad\xb6\x78\x33\xe1\x38\x77\xe3\x9c\x0e\xe0\x40\xcf\xe8\x34\x6b\xfa\x50\x21\x72\x1e\x81\xc8\xac\x83\x98\x06\xb0\x52\xdd\x9e\x44\x4b\x43\x7c\xf5\xfe\x0d\xf2\xbc\xe0\xa4\x8e\xaf\xb5\xbb\xb0\x79\xf8\x6a\xfb\x19\x95\x62\x9f\xa0\xdd\x24\xfd\x52\x1d\x8e\xb7\xda\x6e\x4e\x3e\x57\xbb\xb5\x65\x5a\xc7\x96\x6d\xb0\xae\x7c\xca\x77\xeb\xaa\xc7\x6e\xcf\xa2\xcd\x9a\x08\x5f\xdb\xe3\x53\x93\x50\xca\x06\xb2\x4e\x7e\x77\xa2\xee\x85\xb6\x2b\xc7\x0c\x80\xc6\x93\xe3\xe1\x8c\xbd\xc9\xea\x58\x7e\x63\x45\xce\x37\x2f\xe6\x4b\xc1\xf2\x9c\x24\x01\x98\xb1\xc9\x04\x88\x80\xc0\x6c\xce\x16\x90\x2b\x13\x63\x6d\xfb\xeb\xfb\x2a\x19\xf2\x96\x0d\x5d\xad\x93\x6e\xe2\xa8\x18\x4e\xdb\x3a\x54\xf4\xbc\x7c\x9c\x28\xc7\x82\x99\x0d\xac\x21\xb4\x02\x40\xfd\x9a\x6c\x57\xd3\xc1\x57\x3b\x76\x76\xca\x74\x54\x3f\x41\xfa\x60\xd0\x55\xda\x90\x40\x6d\xcf\x71\xb1\x8b\x86\x06\x00\x99\x3d\x0a\x48\xe1\xf8\xc4\xe4\xe8\x70\xc6\xeb\x00\x52\xfb\x20\xc9\xb5\xf6\xb9\x98\xf3\x85\x82\x27\x5f\x34\x7c\xe5\x39\x5f\x54\x56\xb4\x2e\x0c\x64\x9b\xdc\x99\x8b\x29\x5c\x2b\x40\x3b\x0f\xe5\x74\xbd\x86\x61\x6f\xee\x7b\x20\x25\x5a\x3e\xc2\x9e\x07\x97\x55\xd0\x73\xcf\x5a\x2f\xeb\x91\x9e\x82\xf6\x64\xd6\x1f\xd9\xe3\xeb\xe5\x2e\x7b\xd2\x9c\x1c\x49\x9c\xf4\x5b\xd1\x0c\xf0\x1d\x82\x97\x55\x9f\x0a\x58\xa3\x8d\x7e\x77\x6a\x2a\xdb\x79\x88\xba\x57\x95\xd9\xb4\x88\x54\x15\xbc\x43\xcb\x8e\x8c\xe5\x01\x6d\x68\x71\x9a\x25\xb4\x58\x45\x1c\xd2\x42\x1e\x76\xf9\x9b\x69\x8d\x41\x2e\xe4\x07\x86\xf5\x2b\x9a\x93\x58\x58\x5c\x1b\xe5\xb0\xf3\xba\x8e\x8a\x6e\x4a\xfd\xde\x8e\xca\x9d\x59\x72\x73\xbd\x15\x57\xbc\x24\x51\x0a\x57\xb8\x68\x0a\x44\x89\xa3\x83\xb6\x86\x65\x41\x34\x8a\xd3\xcf\x93\xf1\xd4\xc5\xb2\x0f\xfb\xd8\xd7\x7d\xdc\xfb\x3c\x65\xf5\x86\x7f\x26\x3a\x77\xfe\x9e\x9b\xd2\xee\x98\x3b\xe5\x95\x6e\x80\xc8\xd6\x38\x4c\x1c\xad\x43\xcb\xcd\x5e\x87\x96\x95\xad\xe3\xa9\xe8\xe7\x1a\xf6\xfd\x20\x1b\xda\x76\xcb\xc1\x64\x88\x01\xcc\xda\x7b\xb1\x55\xf0\xdd\x49\xa1\x1e\x71\x6d\x9c\x4e\x7c\xbf\x4b\xcf\xec\x9a\x9b\xef\x27\x0e\xa7\xa3\xc7\xb7\x08\x40\x28\x38\xbe\x23\xbc\xa8\xed\xae\x82\xa6\xe9\x33\xcc\x3f\x13\x0e\x19\x24\x5d\x53\x67\xa3\xa8\xa5\xf8\x3b\x9d\x81\xf4\x68\x2a\xb3\x1a\x8f\x16\x84\x0c\x69\xf0\xcf\xd8\x33\x81\xc8\x9e\x06\xc4\x8e\x67\xd0\x21\x28\xf6\x9f\x21\xb4\x0f\x0f\x8d\x41\xda\xd6\xd8\x60\xb3\x0a\x08\xc4\xa0\x67\x74\x0d\x39\xd8\x3c\x75\x09\x1a\x81\x50\x90\x41\x0e\x29\x24\x2d\xdb\xf4\xd4\x76\x53\x68\xa5\x9b\x7c\x07\xfe\x49\x76\x18\xb5\x2e\x77\xf0\x0a\x57\x7b\x78\x85\x6b\x94\x87\x3d\xc6\x36\xbc\x43\x49\xe8\x70\x00\x24\x6a\xda\x67\xc0\x17\x95\xb0\xc9\x6e\x23\x26\x25\x44\xdd\x2f\x12\x8b\xe2\x27\xe3\x8e\x61\x6b\xbf\xe7\x71\x10\xaa\x05\xfc\xf6\x69\x51\x68\xc7\x81\xd7\x44\x66\xaa\x99\x5e\x5a\x42\xba\xdd\x8e\x8d\x9f\x43\xab\xc4\xdb\x4f\x69\xab\xf5\x6a\x27\xca\x56\x8d\x24\xe2\x50\xff\xfe\x95\xc9\x3d\x57\x44\x4e\x57\xb5\x2f\x6e\x9d\x67\x0a\xb6\xd8\xd9\x45\xc4\x7d\x7f\x1c\x8c\x77\x44\x4c\xf6\xfd\x71\x3f\x96\x33\x30\x0d\xfd\x42\xc9\xbd\x84\xb5\x6a\xc2\x96\x2b\x62\x4e\x48\x06\x69\xf1\x2e\xd3\xbd\x46\x63\x3e\x60\x4d\xf8\xed\xf3\xf4\xcb\xb4\x97\x0b\xce\x98\xa8\x63\xd8\x15\xf2\x26\xbb\x22\x5f\x8c\x13\x8f\x5b\x6d\xbf\x54\xc7\x9d\x5b\x1a\x37\x19\xaa\xc4\x7f\xc6\xed\xc9\x6d\xcb\x30\xea\x6d\x1c\x93\xa2\x60\xbc\xef\x03\xc5\x94\x1b\x08\x38\x57\x47\xde\x6c\x66\x71\xd4\xfc\xd4\xd6\xef\x51\x93\x30\xa7\x01\x58\x68\x55\x71\x2c\x70\x2b\xfa\xfa\x32\xe8\x4f\x0e\xb8\x41\xf2\x5a\x39\x6a\xf7\x29\xd8\xa2\x0e\xc8\xa0\xc4\xb2\x26\xdc\x20\xeb\xc2\x0f\x37\x41\x9e\x24\x29\x49\xd0\xe1\x8c\xbc\xe1\x9a\xb5\x2a\x1f\xdb\xf2\xf9\x46\x26\x13\xeb\x7b\x8c\xbf\xd0\x1e\x81\x04\x9a\xce\xc4\x1b\x44\x65\x41\xfe\x42\xe8\xa2\xf8\x85\x58\x28\xbd\x79\xad\x66\x80\xc4\x9f\xa7\x47\xd3\x17\xc2\xc8\x70\x66\x3b\x87\x8e\x98\x89\x68\x23\x71\xd8\xc0\x8a\xfe\xc1\xee\x4b\x76\xac\x71\x34\xfd\x4e\x9d\xf2\x27\x69\x31\xc1\x7d\x1a\xe6\x3b\xf4\x1d\x29\x72\xc5\x0b\x7d\xdb\x1f\x58\x0c\x17\xb0\xd6\x3e\xb0\x6c\xe5\xf7\x6c\x76\x60\xdc\xcb\x77\x0d\x80\x54\xc0\x98\x76\x76\xcb\x0a\x07\xe6\xbd\xfc\x61\x73\x1d\x98\xf4\x0a\xee\x32\xcb\x51\xda\xd5\x8e\x16\xdc\x46\x13\xc8\x35\xaa\x53\x8a\x5d\xf2\x97\xba\x46\x66\x1c\x2d\x7d\x5f\x69\x36\xfe\x44\xb0\x24\xa2\xda\x5f\x81\xb7\x12\x22\x8f\x0e\x0e\xee\xef\xef\xc3\xfb\x57\x21\xe3\xb7\x07\x57\x17\x07\x97\xbf\xfc\x65\x3a\x3d\x58\xea\x32\xff\xf6\x23\x2e\x68\x7c\xa9\xc4\x3f\x25\x27\x1e\xf4\xa6\xe1\xd4\xb3\x06\xac\x9b\xbe\x99\x88\x76\xc4\xef\x7a\xdf\x27\x85\x08\x6f\x68\x96\x04\x07\x7f\x0b\x12\x2c\xf0\x56\x12\x9e\xe0\xc5\x1c\xbf\xf8\xe7\xf5\x42\xfe\xff\x5b\x72\x1d\xfe\xf6\x62\xf1\xf5\x9f\x0e\x00\x6c\x2c\x01\x23\x79\xd9\x91\xdc\x10\xf3\xfa\xf7\xf1\x0a\xf3\x5a\x7c\x8d\xd5\x4e\xfb\x2b\x79\xb0\x9f\x8a\x28\xd6\xbf\xd3\x94\xdd\xff\x54\xa6\xe9\xa5\x42\xa8\x11\xdd\x96\x3a\xed\x8a\xe3\xac\x50\xaa\x36\xf1\x43\x44\x21\x4e\x6d\x5b\xc5\x43\x16\xcb\x0b\xb4\x14\xec\x98\x49\x28\x5a\x91\xb9\x4c\xf9\x98\xe2\x87\xa8\x84\x31\x49\xd3\x8f\x38\x49\x68\x66\xd4\x11\x64\xc2\x65\x8e\xe3\x26\x61\x85\xf9\x25\x11\x11\x85\xca\xc3\x06\x49\xa2\x62\x5b\x42\x15\xc8\xf8\xdd\x89\x4c\x95\xbf\xb4\xac\xe9\x88\x46\x05\x8c\x59\x5a\x44\x74\x9b\xcb\x1f\x97\x39\x36\xa3\x8f\x8d\x75\xb4\xfb\x71\x9a\xe8\x88\xc3\x4e\xa2\x51\xa9\xa0\xea\x8b\xcb\x96\x54\x67\x8c\xf1\xc4\xa8\x1b\xc4\x9c\x15\xc5\x39\xa7\x56\x15\x0e\xd6\x0e\xd7\xa1\xb2\x6a\xa5\x6b\x12\x51\x98\x90\xa5\x7a\x8d\x24\xd4\xe8\x10\x24\xb4\xc0\x8a\xf8\x96\x60\x4b\xd8\x7d\x96\x32\x9c\x44\x09\x4c\x38\xbe\xbd\x6d\x06\x41\xb2\x58\x3e\x99\xf4\xc7\x92\xf1\x75\x44\xd5\x1f\x1d\xd8\xd3\x7c\x9c\x9a\x42\xfa\xcb\x58\x45\xe9\x8f\x0f\xec\x17\x9c\x52\xa5\x2a\x52\xaa\x04\xcd\x1d\x90\xb9\x1c\xaf\xc9\x8f\xda\x71\x22\x85\x2b\x82\x13\x79\xd7\xaa\x7e\x56\xda\x71\x1f\x85\x2b\x9a\x24\x66\x65\x57\xf4\x76\x65\x72\x39\x59\x36\xbf\xde\x63\xbb\x2e\x2b\xb1\x4e\x7f\xb2\x1a\x1c\x72\xd3\x9f\xfe\xa3\xa4\x77\xe6\x99\x18\xdb\x5d\x43\x93\xa8\x80\x29\xbe\xb1\x3a\x0c\x69\x5d\x3f\xa5\x85\xec\x33\x65\x2c\x57\x40\x4e\xd9\xbd\xce\x58\xe3\x8c\x2e\x89\xca\x5c\x63\x2e\x09\x22\x3d\x3e\x93\x29\x53\xb4\x63\x43\x93\xf0\xa5\xfe\xa1\x23\xbd\xca\x7a\x24\xa1\xd8\xfe\xd5\xbe\x3f\x75\x19\x0d\x2b\xfd\xdb\x2e\xe0\xba\x4c\x05\xcd\x53\xa2\x46\xb1\x2e\x85\xd9\x61\x99\xdc\x52\x5a\x7f\xce\x05\x2a\xcb\x49\xa6\xfe\x08\xba\x2e\xd7\xba\x40\x8e\x85\x20\xdc\x34\xa7\x94\x5f\x57\x2c\x4d\xac\xfa\x48\xce\x8a\x5a\x95\x26\xe7\x24\xad\xd5\x53\x94\x73\x18\x67\x74\x9c\xe0\xe4\x3c\x4b\x1f\x54\xf7\xdc\x42\x8c\x93\x7f\x94\x94\x93\x24\x2a\x21\x67\xa9\x5c\x75\xce\xee\xf5\x0e\xe7\xec\xbe\xd9\xe1\x05\xce\x92\x1b\x66\x80\x51\xc4\xcc\xee\x22\xf5\x53\xd6\x2e\x94\x5e\x4a\x7d\xae\x0a\x82\xd7\x29\x29\x0a\xb5\xdc\x85\x52\x52\x31\x33\x2f\x56\xb8\xae\x4c\xff\x49\x54\x57\xf2\x47\x11\x51\x58\xc8\xfe\x72\x58\xe4\x24\x4d\x8f\xe5\x79\x34\xe5\x78\x5c\xff\x38\x61\x71\x54\xc8\x1f\xfa\xd4\xaa\x3b\x3e\x4a\x61\x21\x88\x99\xa7\x72\xda\x67\x94\x53\xf0\x8d\xf6\xfa\x60\xbe\xd4\x66\xd5\xbf\xa9\xa8\x0b\xd5\x27\xa2\x2c\xc8\x19\x36\xad\x68\x2a\xa5\xd8\xc6\xf0\x5e\xed\x06\x0a\xef\xd7\x2c\x91\xf0\x51\x08\x07\xe7\x54\xe0\x54\x0e\xbf\x46\x39\xc7\x8c\x4b\x02\xde\x6c\x4c\x41\xd6\x12\x31\x46\x54\xfd\xbc\x54\x00\x93\xa0\x90\x5f\xe6\x78\xc9\x9f\x0a\xc7\xc8\x1f\x17\x64\xa9\x7d\x2b\x68\xab\x12\x3d\x9e\x4c\x03\x4e\x1d\x60\x5a\xc1\x9e\x81\xb5\x45\xb8\x16\xc9\x7a\xfa\xf3\x45\xac\xbf\x3d\x07\x7b\x79\xea\xa7\x57\x9f\x2b\x6f\xc9\xb8\xe7\x1c\x2c\x75\xb1\xbc\x90\x9b\xe1\xce\x53\x3d\xb5\x0c\xb6\xa3\x4d\x67\xd6\x9e\xfc\x8e\xeb\x6f\xaf\x8d\x86\x75\xae\xf9\xf2\x5a\xd0\x31\x59\xea\x43\xe7\x68\xdd\x2c\x95\xae\xe2\x99\x78\x0d\x02\x57\x89\x79\x8a\x1f\xbc\x1a\x75\x79\x2a\x32\x98\x0a\x78\xfc\x3f\x6a\x8c\xe1\xc9\x5f\xf2\xec\x7b\xee\xae\xd7\xee\x91\x6e\xe5\x6f\xcf\xdd\x52\x9e\xfa\xad\xd0\xbd\x67\x77\x94\x57\xf0\x38\x61\xb1\x67\x37\x96\xfc\x96\x10\x6c\x31\xc1\x57\x3b\x6d\x4e\x76\xe9\x9b\x4b\x6a\xea\x39\x7e\x89\xc1\x26\xb6\xd1\x71\x4d\x54\x18\x73\x2b\xbd\xa7\xd9\x67\x1b\x60\xc8\x66\xa9\x2d\x2a\x33\xba\x91\x58\x54\x10\xdb\x6e\x43\xaa\xb4\xef\xb7\x13\xad\xda\x58\x97\x91\x32\xd8\x82\x19\xca\x13\xda\xa0\xf5\x1b\xa6\x33\xd2\x50\xa2\x1b\x52\x08\x13\x1f\x9b\x18\x8d\x50\x5d\x00\x74\xf8\x10\x4e\x03\x0e\x14\x76\x35\x61\x8a\x68\x3a\xa7\x74\x74\xb5\xe5\x5a\x59\x0f\x2a\x71\x9f\x03\x99\xa2\xcd\x4d\x29\x84\x76\x11\x6c\xbd\x6c\xc9\xdf\xd4\x7a\x13\x36\xf7\xd6\xf8\x50\x6f\x2e\xf5\x83\x58\xc7\xc8\x5a\xcd\x6e\x7c\x58\xc1\x1c\x6d\xce\xe8\x17\x9a\x45\x9b\xdc\xf6\x18\x6d\xba\x41\xd0\x5d\x95\xad\x31\x51\x2a\x20\xe9\x5c\x7b\xef\x5a\x6c\xb7\x24\x74\x3c\x8c\x85\x16\x61\xcb\xdf\xf6\x82\x37\xd1\x38\xc8\xfd\xc8\x84\x4b\xfe\x0f\x56\x8e\x72\xce\xee\x68\x42\x92\x11\x1e\xfd\x5d\x75\xf8\x77\x99\x94\x8f\x04\x1b\xe1\x91\xbc\xa6\x47\x4b\x4a\x52\x1d\x3b\x99\x95\x62\x84\xb3\xd1\xdf\x6d\x47\x7f\x1f\xad\x14\xb7\x85\x87\xa3\xab\x15\x2d\x46\xf7\x34\x4d\x47\x5c\x59\x0a\x8d\xf0\x48\x0e\xe1\x05\xcb\xd2\x07\xdd\x42\x38\x7a\xb7\x54\xb1\xd9\x75\x7b\xc5\x8a\x95\x69\x32\xba\x21\xa3\x75\xa9\x90\xd4\x48\xee\xeb\xbf\x27\x8e\xad\xd8\xdf\xc3\xd1\xb9\x58\x11\x7e\x4f\x0b\x02\x47\x05\x11\x23\x42\xe5\xb7\x3b\x00\xc6\x47\x7f\xb7\x73\xfd\x7b\xe8\x81\xaa\x26\xc5\xf6\xc2\xed\x0f\x00\x96\xe9\xe7\xff\x09\x70\x1d\x9b\xb1\xfc\x2e\x80\xd5\xea\x9f\x65\x28\x61\x56\xa9\xe7\xf4\x2f\x9d\xbd\xe7\xa8\x0a\x76\x8e\xe5\x51\x20\xf1\x06\xec\xa5\x9b\x73\x19\xb5\x32\x54\xdb\xc7\xbd\x15\xea\xb5\xee\x9c\xd9\xa3\x00\xbb\xed\xbb\xa7\xb9\xd3\x83\xc9\x52\x7d\x9c\xdb\x49\x3d\x63\x0a\xb4\xd7\x94\xd3\x7f\xd1\x64\x5a\x80\xb5\xf0\x7b\xae\xf1\x7b\x07\x6b\x44\xd3\xe9\xf7\x83\xfc\xf7\x6f\x9f\x11\x21\x9e\x34\xea\x95\x41\xcb\x32\x50\x75\x66\x8c\x13\x15\xb7\xe9\x74\x4d\x85\x70\x5d\x42\xfd\x01\x2a\x8c\x82\xe3\xfc\x47\xcd\x9e\xef\xea\x01\xa8\xa8\x43\x9a\xcd\x42\x0b\x25\x65\x21\x49\x63\x83\xd5\x0b\x43\x36\x2b\x1a\x89\x21\x0b\xbb\xed\x5a\x1f\x67\x9a\x81\x91\xb2\x18\xa7\x6d\xee\x1b\xc2\xc1\xce\x3c\xc8\x81\x89\xe7\x90\x29\xb3\x8a\x34\xfd\x94\xad\x07\xe3\xa5\x0d\xd5\xf6\x7d\xba\xbf\xe9\x01\x37\x42\x3b\x61\x1f\x7d\x77\xf8\x07\x69\x58\x7d\xfb\x98\x4b\xe3\x27\x18\x2a\x75\x35\x9d\x71\xcf\xca\x88\xb6\x8c\x6f\xf4\x53\xef\x69\xf6\x37\xb8\x2d\xe6\xae\x83\x31\x9a\x5b\x75\x46\x7d\x7f\x4c\x43\x96\xc5\x29\x8d\x3f\xfb\x7e\x50\xff\x46\x0c\xb4\x5d\x33\xd1\x7d\xfc\xe7\x41\xf5\xdf\x6f\x9f\xe3\x33\xd7\x18\x57\x1b\xd2\x03\x88\x15\x67\xf7\x23\x89\xda\xe5\x9c\x0d\x7a\x6f\xb1\xbf\x46\x7a\x06\xa3\x18\x67\x19\x13\x12\xeb\xca\xba\x12\x77\x36\x0c\x63\xe0\xf8\x2e\xae\x23\x58\x42\xde\x8f\x47\xd8\xd6\x94\x80\x0c\x4d\x67\xec\x0d\xe6\xb7\x8a\x87\x53\xeb\x32\x32\xab\xc7\x88\x51\x9d\x67\xdc\x77\x67\xca\x4d\x39\xb6\xf0\x35\x9d\xe1\x66\x00\xc5\x88\x66\x23\x0a\xb8\xd6\x32\xa2\xb0\x50\x86\xea\xf3\x62\xa1\x82\xd3\x02\x27\xe6\x7a\x9b\xeb\x27\xe1\xf8\x34\x9f\x78\x3d\xc4\xc0\x50\x5f\x1d\x48\x1e\x21\xad\x02\x64\x23\x02\x7f\x64\xac\x36\x0d\x35\x5a\x0f\x9d\xcc\x9c\xe5\x4d\xf8\x2e\xe3\x6c\x31\x83\x04\x38\x61\xbb\xc8\xfd\x48\x28\x27\x10\x18\x0d\x29\xa7\xda\x5e\xb3\xdd\xbd\x72\x94\xed\xe9\x35\xd3\xbd\x72\x25\x18\x82\xdc\xed\x57\x77\x54\x41\xda\x8b\x8a\x6c\x84\xa1\xa6\x6f\xbe\xbb\x6f\x86\xf8\x9e\xbe\xcd\x92\x31\x68\x94\xf0\x98\xdb\xbb\x95\xbc\x56\xb0\x1b\xd5\x1d\xf2\xda\xb5\x64\x3d\x06\xbc\x7b\x0c\x14\xe1\x3d\x63\xc0\x76\xdb\x34\x4d\x43\xea\x8e\x03\x3b\x9d\x56\xb0\xdc\xb5\xf2\x3c\x68\x85\x82\x56\xaa\x1d\x8d\x73\x6d\x25\x17\xac\xbf\x02\x00\x07\x77\xc9\x1b\x11\xe6\x8c\xa5\x97\xf4\x9f\xc4\xf7\xbb\x5b\x45\x3b\x33\xaf\x60\x8c\x58\x4b\x9f\xde\x51\xa9\x69\xd6\xd4\xad\x8a\xe6\x0b\x98\x35\x96\x67\x48\x6c\xb7\x31\xcc\xea\x9e\xb6\xdb\xa0\xf9\x40\xd3\x43\x00\x33\xab\xf8\x8e\x4a\x98\x29\xea\xdc\x65\x9f\x47\x29\x64\x19\x79\x6b\x4e\xa9\x6a\x93\x47\x0c\x8a\x7b\xd6\x49\xc3\x50\xac\x38\xe9\x96\xa4\x70\x49\xef\xba\x89\xc5\x00\x2d\xd1\xbf\x10\x1e\x53\x98\x1a\xb6\x79\xf8\x54\x87\x1f\x6f\xa8\x06\x65\x02\xcd\x49\xd6\xf1\x1e\x59\x07\xba\xed\xd8\xac\x5a\xf1\x4f\xd1\x2a\xab\xb8\x92\x8d\xf7\x00\x9d\xaa\x55\x7f\xce\xef\x33\x45\x87\xc4\x4e\x56\xe3\x6d\x37\x35\x4e\x62\xdc\x64\xc3\xc8\x52\x16\x6e\x4d\xe6\xc9\xf9\x99\x07\x00\xcc\x51\x2b\x49\x0b\x20\x9a\xa1\x26\x6e\xb6\x26\x89\xdf\x59\x0e\x7b\x23\xa3\x55\xd9\x6d\x39\xb1\xa3\x59\xd2\xb2\xcd\x5d\xbb\x6f\x40\xc2\x97\x4d\xe0\xb9\xde\xb3\xf0\xc1\x49\xbf\x20\x31\xcb\x62\x9a\xaa\xa9\xdf\x3a\x19\x97\x84\xdf\x11\xae\x9d\x28\x68\xaf\x38\xa7\xc3\x82\x34\xe3\x23\x79\x49\xb3\xc4\xd0\x4d\x8d\x7b\x64\xf9\x38\x50\xeb\xe6\x81\x99\x95\x7e\x07\x9a\xa0\xba\x41\x71\x5b\xf0\x09\xbf\xd4\x29\x3f\x61\x79\xe2\x1e\xe0\xbd\x4c\x49\x59\x56\x17\xb9\x46\xeb\x70\x4d\x70\xa1\x64\x03\x6a\x98\x1e\xf4\xf4\x7b\xc4\x83\xab\x50\xff\x02\xf0\x0c\x6d\xec\x6e\x89\x36\x6b\x9c\x47\x2c\x5c\xe3\x1c\x1a\x4a\x26\x62\x36\xfc\x0e\x8c\x8d\x11\x88\xfa\x0b\xe5\x68\xa3\x8b\x0a\xd6\xeb\x14\x61\x78\x72\x7e\x16\xa5\xb0\x86\x5e\x74\x07\x69\x46\x05\x55\x6c\x20\x57\xb3\xa5\x45\xb4\x87\x6d\xb5\x17\x44\xac\x3b\x20\xb5\x29\x23\x1a\x3a\x5f\xb0\x05\x84\xe8\x06\xba\x13\x8e\xee\x61\x0b\x22\xd1\x17\xeb\x57\x48\x3d\xbd\x87\x5e\x0a\x92\xa8\x34\xd6\x30\x6f\xb3\x44\xaf\x5f\x33\xa1\x55\xb8\x27\x77\x5f\xcd\x1f\x1f\xde\x9d\xec\xaf\x2d\x4b\x40\x67\x17\x44\xc7\x50\xaf\x47\x74\x6d\x7e\x5c\x99\x30\xc7\xd1\x6d\xd8\x4e\x70\xf2\xb1\xa0\xb1\xf1\xae\xe0\x96\x6a\x92\x61\xa9\xc9\xe4\xba\xdf\xb7\x4a\xb3\x2f\x5a\x85\xc3\x19\x90\x16\xea\x9c\x5a\x88\xc6\x61\x3b\x01\xca\x77\xaf\x41\x0c\x51\x11\x3a\x5f\xf0\xfa\xba\xc8\xe5\xc3\x33\x3a\xad\x66\x43\x72\xf7\xeb\xeb\x8b\xd3\xb7\xc7\x57\xd7\x27\xa7\xbf\x5c\x9d\x9f\xbf\xbf\xbc\xfe\xcb\xfb\xf3\x1f\xdf\xbe\xbf\xfe\xf9\xfc\xfc\xaf\xd7\xd7\x83\xa1\x0b\xf7\x57\x31\x27\xc4\xf7\x9f\x54\x2c\xd8\xb8\x98\x2b\x2a\x61\x07\x51\x44\x4b\xa8\x75\xcb\x56\xb0\x39\xe5\xd1\x03\x6c\xa1\xa2\x28\xaf\xc0\xec\xcc\x06\x4f\x44\xde\x61\x38\x7d\x15\xbe\xf2\x1c\x61\xeb\x59\xcf\x64\xa3\x65\x97\xb1\xcf\xf7\xc4\xa0\x80\xb6\x8d\xcc\xa3\xef\x5e\xc2\x36\xca\x8e\x74\x18\x95\x0e\x72\x8f\xbe\xfb\x06\x76\xd1\x78\xa4\x3d\x26\xf7\x91\x78\xf4\x5d\x63\xe9\x2c\xd1\x71\xf4\xfd\x21\xdc\x89\x8b\xa3\x1f\x1a\xb7\xaa\x3d\x4c\x1c\xfd\xd0\x74\x5b\x7b\x6a\xfe\xe1\xbb\x6e\x5a\x73\x13\x44\x3f\x34\x63\xea\x22\xee\x68\x7a\xf8\xed\x0e\x0b\xec\x06\x6d\x47\xd3\xe9\x6b\xb8\xfb\x59\xde\x45\xda\xd1\xf4\x65\x33\xfc\x2e\xce\x8e\xa6\x2f\xd5\xf0\x5d\xdc\x1c\x4d\xb5\x9d\x4d\x83\x9a\xa3\xe9\xf7\xea\x7d\xf2\x98\x7e\x9d\x73\x55\xb7\x91\x3d\x53\x7e\xcb\xed\xb1\x1f\x70\x39\x6d\xbc\x96\x0f\x85\xf4\xee\x8c\xac\x5a\xc0\xef\x9e\xe3\x93\xae\xee\xe3\x91\x37\x8c\xb1\x66\x80\x6b\xa0\x9c\x32\xad\x17\x68\x39\x99\xc0\x7c\x2e\x7f\x2a\x83\x34\xfb\xbb\xe5\xc6\xa8\xfb\x42\xc5\x3b\x34\xaa\xe8\x3e\xa3\x4d\x97\x00\x71\x9f\xdd\x0a\x85\x37\xa4\x88\x55\xb7\x39\x23\x72\x9a\x0e\xf7\xb6\x7b\xdf\xa6\x3b\xa3\x05\xe4\x68\x53\xc1\x04\x8d\xa7\x70\x89\x0e\xe1\x0a\xd5\xf6\xf4\xde\x4d\x5a\x72\xcf\xb1\xa8\xb7\xfe\xf0\x1b\xab\x7a\x4f\x3d\x73\xbd\x01\xc3\x7a\xcf\x09\x3a\x49\xb2\xa4\x5b\x44\x1b\x47\xbb\x85\x94\x8c\xaa\x5b\xcc\x98\xdc\xbb\xe5\xb4\xb7\x6d\xaf\x6b\x81\xef\x19\xd9\xf1\x9a\x64\xa5\x57\x9b\xe2\x7b\x31\xcb\x1f\x3c\x6b\x8c\xef\xc5\xa5\xee\xc1\xb5\xc6\xf7\x92\x9b\xb4\x99\x85\xb2\xc9\xf7\x12\x8e\x6f\x3d\xd7\x2a\x5f\xa5\xd8\x69\x34\xa6\xf9\x26\x59\x39\x6e\x70\x2d\xf4\x75\xfa\x17\x2a\xbc\xb6\x9d\xbe\x4a\x37\x4e\x24\x5c\x73\x7d\x95\xce\xee\x9c\x66\x0c\x7c\x64\x7a\x03\x18\x65\xbb\xef\x25\x9c\xe5\x5e\x63\xaf\xef\x19\x79\x50\x6d\xb2\x6f\xc2\x0a\xb8\x56\xfb\xde\x67\xf2\x90\xb0\xfb\xcc\x6b\x99\xee\xcb\xd4\x5c\xfe\xf2\x1a\x03\x7e\x99\x56\xea\xe6\x1b\xb3\x7d\xed\xa0\xa2\x6e\xa0\xb1\xde\xd7\x19\x6b\x66\xe6\x53\x1b\xf1\xeb\x74\x66\x46\xd1\x98\xf2\x9b\x74\x3b\x51\x6b\xd1\xaf\x93\x4d\xb7\xda\xac\xdf\xcb\xe5\x1f\xcf\xb1\xe5\xf7\xb4\xec\xd4\x1b\xb2\xe7\xf7\x0a\x9b\xe0\xec\xd0\xc6\x9a\xdf\x13\xf6\xa7\xd7\x35\xea\xf7\x84\xfc\x88\xd5\x87\xd7\xb2\xee\xd7\x39\x76\xcd\x1b\x1b\x7f\x9d\x5e\xcf\xd9\x31\xf5\xd7\x39\xcd\x72\x69\x93\x7f\xef\x5e\xfe\xf1\x2a\xb8\x46\xde\xb5\x72\xd3\x5a\x73\xdc\xde\x9d\x78\x13\x4d\xca\x04\x67\x58\xac\x42\x8e\xb3\x84\xad\x03\x00\x8c\x9e\xd3\x4b\x49\x8c\xc7\xc1\xa6\x82\x05\xdc\x34\x98\xa0\x36\x61\x75\xd4\xc1\x1d\x13\xe5\x81\x82\x2d\xfb\xce\xb0\x20\x42\xdf\x2d\x57\x86\x3f\x16\xdc\x85\xab\x56\x02\x80\x77\x61\xbf\x19\xa5\x59\x5e\x10\x71\x9a\x69\x35\x8a\xd6\xf3\x78\xa0\xbc\xef\x0f\xa5\x86\x4d\x0b\xea\x91\x4b\x8b\x5e\x7b\xb5\x0c\x23\x18\x0f\xb5\xb0\xdd\x0e\x26\x87\x75\x4b\x01\x00\x15\xd4\x7e\x0e\xae\xd8\x2e\xdf\xfb\x48\x28\xcd\xeb\x4c\xa2\x5a\xfa\x98\xf1\x9e\xd2\xa9\xea\x3a\x2d\x3a\x84\x79\x63\xa2\x1b\xbf\xc9\x95\xd7\x37\xe3\x1b\xa7\x98\xc7\x8b\x19\xee\x7b\x17\xf3\x7d\x3c\x4f\x16\xdb\x6d\x90\x58\xc7\x37\x6a\x97\x1c\xa5\x81\xd9\x27\xe0\x68\x70\x6e\x3d\x26\x72\x53\x17\x9a\x9a\x30\x03\x51\x1a\xe8\xb3\xf4\xfb\xdb\x72\xaa\xcb\x06\x9f\xdf\xc0\xc9\xf9\x99\x3a\xd7\x97\xe6\xb8\x66\x20\xaa\xe7\xaa\xd3\xe4\x64\xed\x61\x1e\x1f\xee\x19\xa4\x89\x1b\xe3\x76\xa2\x5b\x80\x75\xfd\xe7\x0d\xb1\x5b\x7b\xb0\xea\xaf\xef\x3e\x9c\x9c\xff\x7a\xfd\xf3\xdb\x0f\x27\xef\x4f\x9d\xc1\x2b\x74\xbb\xdd\xd6\xdf\xf2\x8e\x3c\x0a\xd2\xc0\x22\x60\x39\x95\xe0\x39\x73\xd1\x21\x6d\x6c\xf5\x6c\xf8\xd0\xed\xaa\xac\x02\xe6\x98\x1b\x3a\x03\x6a\xe5\x55\x43\x92\x38\xf0\xfd\xdd\xe3\xe8\x03\xc5\x1d\x06\xcd\xf6\x0f\xa4\x5f\x5b\x8f\x43\x55\x56\xf8\x3e\x03\x00\xe2\x79\x9d\xb5\x40\xe3\x43\xfb\xad\x3a\x92\x09\x20\x5a\x0d\x9d\x8c\xa7\xf5\x9a\xc0\xd5\x3c\x59\xc8\x51\xca\x93\xa4\x0c\x3a\x2b\xb8\x57\x76\xe3\xf8\xff\x78\x5a\x17\x96\x1b\xd9\x03\xfd\xb3\x9b\x6d\x2f\x9c\x6d\x97\x64\x45\xc9\xcd\x01\x51\xf2\xc7\x33\x96\x51\xc1\xd4\x23\xb7\xad\xd9\x3b\x4e\xac\x91\x7d\x19\x72\xb2\xe4\xa4\x58\x39\xd5\x8a\xd9\x60\xc7\x6b\xdd\x9a\x53\x30\x20\x40\x52\x78\x87\xd5\x1e\x87\x0f\xf8\xf9\x0e\x1f\xf0\x93\x1c\x3e\xe0\xd0\xf9\x6a\xb9\x6e\xc0\x2d\x33\x80\x8e\x7f\x06\x1c\xb6\x13\x86\xfc\x30\xd8\x32\x6e\x62\xcb\x01\xea\xdd\xef\x8d\xee\x33\xe8\x64\x60\xf7\xc3\xb4\x4f\xa1\x47\xd3\x43\xf5\xc2\xea\x12\xe8\xd1\xf4\x9b\x6f\x76\x06\xf9\x91\xef\x98\xc7\x74\xe0\x9d\xf7\x54\x9f\x15\x67\x9e\x20\xcb\x14\x0b\x41\xb2\x3e\xef\x53\x33\x8b\x05\xb5\x21\x7f\x06\xd8\xa0\x5a\x00\xaf\x09\xef\x5e\x99\x02\x6d\x9c\x26\x6a\x6e\xd9\xb0\xd0\x80\x05\x4e\x60\x09\xba\xdb\xd0\x9f\x3a\x86\xfe\x54\x5e\xb5\x38\x28\x94\x99\x0c\x98\xc9\x04\x54\x56\xb5\x0d\xb2\x89\xb5\xb3\xa3\x63\x68\x62\x46\x95\x88\x99\x48\x33\xe3\xd2\xf7\xc7\xa4\xe7\x18\x2e\x56\xc3\x8a\xb5\x59\x32\x5d\x06\x03\x31\x1d\xac\xaf\x0d\xe2\xfb\x64\x1e\x2f\x60\x8e\x52\xdf\x4f\xc3\x6b\x63\xf1\x69\xd9\x40\x89\x0a\xf2\xa0\xdd\x38\xe4\x30\x01\x80\x87\x9c\xc4\x84\xde\x91\x1a\x6c\x41\x0a\x13\x35\x36\x58\xea\x88\x13\xca\x85\x5e\xea\xfb\xbc\xc7\x7b\x0a\x52\x18\x6b\x3e\xe7\x12\xe1\x20\x31\x40\x50\xd5\x96\x55\x55\x8f\x99\x80\xf1\x40\x34\x8e\xed\xb6\xf4\xfd\x81\x99\x6c\xb7\x03\x1d\x29\x87\xb4\xb3\xda\xd9\x46\xcd\x1e\xeb\x03\xb6\xe3\xe1\x84\xd4\x22\x08\xe5\x63\xa5\xdf\x72\xd6\x11\x79\x16\x8e\x18\x79\x80\x03\xd1\xdd\xaa\xd1\xf4\xb5\x51\x24\xd8\xb5\x53\xa3\xa9\x66\xea\xec\xd9\xa8\xd1\xf4\x87\xa9\x3c\x4b\x8f\xe9\xe8\x77\x65\xa7\x4a\x36\x6e\xb8\xbc\x56\x10\x6b\x6d\x4b\x4c\xb2\x79\x73\x22\xd1\x33\xf3\x83\xbc\xf6\x4d\x30\x63\xdd\x56\x8c\xf8\xab\xd3\x0a\x14\x2d\x7b\x41\xec\x1a\xc7\x19\x19\xae\x65\xd0\xce\xb4\x10\x8c\x3b\x7e\x05\x95\x16\xc1\x32\x20\x90\x41\x0c\x60\xe3\xc3\x08\x0f\xd9\xdb\xa9\x39\xac\x71\x7e\x41\x8a\x32\xad\x0d\x66\xd6\x38\xaf\xe7\x29\xea\x24\x3b\xc7\xac\x67\x2a\xed\xcc\x51\x99\x84\xd4\x0d\x42\x8a\xc6\x3d\x72\x57\x07\x72\xa3\xf6\x74\x33\xb7\x3b\x0b\x90\xa6\x3b\x05\x8c\x19\x9e\x67\x0b\x54\x54\xc3\xc1\x4a\x07\x81\xc2\xd1\xa6\x82\x4c\xbb\x10\x35\x90\xe1\x5a\xc3\xc2\x14\x93\x20\x52\x66\x7e\xb4\x06\x11\x03\x30\x31\xec\xf4\x80\x0f\x9b\xdd\xed\x32\x62\x76\xe2\x19\xc8\x86\x63\x7d\x48\x5d\x93\xba\xb6\x21\x91\x2b\xb2\xf9\x89\xe3\x5b\x23\x19\x32\xa2\x1a\x6b\xbc\xf7\x36\x4d\x1d\x6c\xbd\xea\xc5\x16\xc8\xc3\x9e\xd4\x4d\x9b\xd7\x0d\x08\xde\x66\x79\xc7\x08\x06\xae\x64\x03\xad\x34\x0a\xd7\x1a\xd1\xdc\xa1\x8d\x15\x70\x60\xb8\xc6\x79\x54\x1a\xf1\x46\x5a\xf5\xef\xd1\x01\x2b\x99\xf6\xbc\xa2\xe9\xa1\x62\xc3\x0e\x4d\x2b\x9a\xfe\x30\x14\xcf\xfa\xbb\xe7\xa8\x7e\x36\x12\xd0\xfb\xbe\x23\xec\xa3\xfb\xb9\x58\x68\x13\xee\xb3\x21\x7f\xf2\xb7\x41\x86\x10\xba\x09\xcf\x7f\x39\xbd\xb8\x78\x77\x72\x7a\xfd\xe3\xdb\xcb\x53\x00\x07\x7d\xcf\xdb\xb2\x27\xa7\x3f\xbd\xfb\x70\x7a\x7d\xf6\xf6\xc3\x7f\x6c\xb7\xbd\xa4\xeb\xb3\xd3\x8b\xbf\x9c\x9e\x74\x4d\x7e\xb5\x51\x16\xd8\xdc\x06\x0d\x2f\xbf\x66\xff\x0b\x00\x6f\x83\x71\xd2\x91\x27\xd4\xc6\xe8\x99\x56\x19\xd5\xec\xc8\x59\xcf\x9d\xc5\x05\xf0\xfd\xeb\x70\x2d\x49\x0c\x75\x24\xcd\x4f\xf0\xb4\xf8\xeb\xbe\xcf\xc6\x08\x5d\xd4\x12\x75\xa3\x77\xc1\x83\x4c\x1e\x8f\xeb\x01\x0f\x3c\xd7\x73\xb6\x50\xa6\xa9\x6e\xec\x81\x1e\xec\x19\x80\x31\xea\xb9\x26\x67\x00\xa6\x08\xfb\x3e\x0e\xaf\x35\xe3\xe3\x84\x65\xe2\x47\x9a\x25\x30\x47\x03\x42\x0e\x0c\x97\x28\xf7\xfd\x31\xf5\xfd\x71\xec\xfb\x63\xe5\xba\x76\x09\x32\x5b\xfb\x6d\x29\x98\xac\x7d\x86\x73\x25\xc8\xee\x27\x2b\x8e\xec\x50\xc6\x9c\x2d\x10\x56\x3e\x21\x10\xae\x63\x02\xc4\xd6\x11\xfa\xbd\x04\xc3\x6d\x40\x7d\x3f\x58\xed\x58\xe1\xed\xb6\x97\x03\xe4\x31\x1d\x2e\x7d\xa4\x7a\x2a\x02\xe5\x84\x02\x83\xa8\x57\x4e\x69\xad\xb0\x05\x2a\x6d\x11\x50\x35\x11\xea\x71\xe5\x3a\x6a\xc2\xce\x86\xea\xf8\x3a\xb1\xba\x19\xf3\x6c\x31\x1b\x5a\xef\xc6\x59\x8e\xaa\x70\x3d\xbb\x0d\xc6\x0c\x98\x8b\x44\x3b\xd9\x91\x49\x18\x40\x22\x91\x2e\x77\xbb\x35\x0e\x3c\x6e\x03\xe2\xfb\xc2\xf7\x3d\xa6\x48\xdf\x66\xb1\xc8\x40\x9a\x00\x4f\xf2\xc6\x12\xdc\x06\xda\xd2\x0f\x21\xe5\xc5\xc7\x74\xaf\xe3\x9e\xd7\xf2\xc8\xf6\xcd\xd3\xa0\xdc\xb6\xf3\x31\x79\x5a\x70\x9e\xa7\x0f\x3a\x70\x69\xad\x50\x04\x20\x47\x62\x38\x67\x56\xdf\x23\x59\xed\xdb\xa6\x49\x6b\xdc\x20\xcf\x34\xe8\x36\x95\x1d\x13\x0d\x98\x7c\x75\xca\x3f\x1c\x40\xd6\xbd\xa2\x86\x86\xb8\x6b\x70\x3b\x86\x56\x75\x2e\xa2\x46\x95\x48\xd9\x99\x35\x4e\x33\xb2\x8e\x59\x77\x9b\x42\x1b\x38\x00\xda\x99\x52\x3f\x7d\x57\x34\x01\xe5\x3c\xa3\x7f\x8c\xc4\x62\x26\xc9\x3e\x24\x47\xb7\x0c\x6f\x4b\xcc\x95\x77\xf9\x96\x27\xc5\x84\x16\x79\x8a\x95\x45\xc4\xc4\x0b\xbd\x89\x00\xa0\x72\x6f\xc7\xde\x9b\x22\x71\x75\x24\x3a\x5a\x15\x03\x3a\x15\x6d\x2d\x07\xa5\xd4\x66\xf5\x3e\x56\x03\xea\x0f\x67\x2a\xec\x83\xab\xe6\xf0\x9e\x2e\xc9\xf1\x43\x9c\x12\xa5\xeb\x10\xf4\x95\x1d\xde\xb3\x58\x3d\x68\x8b\xd6\x00\xba\xb9\xca\xe4\xa3\x55\x42\x93\xa2\xca\x49\x9e\x1c\xe6\xc3\xb0\x20\xe6\xb6\xaf\x63\x76\xda\x77\x7d\x7c\xdc\xf6\x99\x7e\xd1\x23\x08\x8e\x83\x8d\x46\xfd\xc6\xa7\x2c\x80\x37\xe8\x34\xd8\x18\x24\x73\xfe\xe1\xf8\x54\xb3\x87\x1d\xac\xa3\x13\x5a\xb7\x5f\xaf\x8c\xc1\x60\xd6\x51\xed\x17\x34\x5f\xc0\x7b\x64\xbb\x6a\x21\x31\x58\x28\xf9\x7a\x37\xb5\xd1\xeb\x6f\xa7\x1b\xf9\xcc\x60\x96\x24\x11\x8e\x77\xe7\x37\xa1\x55\xe4\x22\x74\x72\xcd\x88\xb5\x57\x4d\xa5\x63\x71\x29\xb0\x20\x3b\x0b\x1d\x3b\x9d\x0d\x17\x32\xfa\x07\x75\x9e\x04\x66\x5b\xe7\x56\x0b\xc8\xbb\xf3\x33\x05\x4e\x68\xb2\x37\x5f\x36\x70\xa1\xdf\x88\x03\xd3\x81\xfa\x59\x53\x1f\x10\x23\x01\xdb\x33\x98\x6e\x89\xde\x68\xf6\x17\x70\x75\x88\xdb\x45\xcc\x5b\xbb\x96\xf9\x77\x28\xa7\x0a\x5e\xa3\x8d\x73\xda\x3b\x8c\x76\xe2\x62\x02\x24\x2a\x68\xf6\x50\xbb\x54\xfb\x5e\x43\x87\xb3\xac\x76\x4e\x34\xcb\x26\x13\xa0\xe8\x29\x79\x33\x54\x03\xbb\xa4\xdb\x61\xaf\x04\x7a\x08\x36\x15\x1c\xc8\x50\xca\x8e\xf1\xde\xb6\x86\x9a\xe9\xb6\xd0\xdd\x98\xdd\x46\x3a\xf9\x47\xbd\x14\x54\x04\xbd\x34\xa8\xe2\x2b\x75\x0b\x8a\xca\x39\x59\xdd\x7e\xea\x1c\x3b\xd2\x3a\x41\x0d\xd3\x1e\xd4\x76\x35\x4d\x59\x54\x15\x3c\x43\x1b\x13\x2f\x44\x9f\x9c\x8e\xc2\x61\x68\x7c\x85\x5e\x38\x65\x6c\x9c\x70\x28\x7c\xbf\x2e\x70\x6c\x6c\xf1\x75\xa6\x52\x27\xb5\xca\xf2\x7d\xa7\xa1\x2b\x39\x43\x2d\xe1\xaf\x2f\x7d\x1d\x96\x60\x6d\xbd\x6a\xa5\x0f\xaa\x36\xcd\x6e\x2d\x32\x57\xe2\xa7\x21\x50\xd7\x63\xb8\x34\xf9\x4f\x1c\xa0\x99\xf7\xde\x26\x2f\x9c\x32\x4f\x6b\xb6\x82\x1f\x91\x33\xe1\x6a\xf6\x10\x7c\x74\xbc\x42\x38\x56\xe4\xf0\x4c\xd3\x63\xe7\x36\x10\xb7\x56\xf5\xea\x2b\x9e\xb6\xc7\xa6\x75\xf8\x7b\xf7\xb3\xef\x9b\x48\xef\xb0\xb1\x0a\xb3\x2f\xfd\xd8\xf2\x2d\xf4\xa7\xdc\x12\xa4\x09\x42\xda\x18\x31\xb8\x38\xf4\x68\x28\x31\x30\x5e\xb2\x6e\x83\x1e\x01\x98\xf9\xfe\xb8\xe7\xc3\xad\xd5\x9f\x7c\x53\xd6\x93\x47\x19\xb9\x1f\x7d\x84\xae\xfa\x85\x43\x48\x20\x01\xbf\x58\x76\x49\xc0\x34\x05\xa4\x4d\x51\x01\x80\x2c\x10\x6a\x15\xba\xc7\xc4\xf7\x03\x61\x23\x50\x98\x73\xd3\x2d\x12\x00\xf9\x00\x73\x3b\x35\xfa\x7f\x6d\xe2\xf5\x1e\x38\x45\x54\x58\xf2\xa0\x9d\x80\x0c\x87\xd2\x6a\x74\xab\x19\x09\x28\xaa\xbe\x44\xb6\xaf\x76\xf7\xa5\x56\xf2\x6d\xf1\xca\xce\xf7\x78\xa8\xd8\xa7\xd9\xb4\x4b\x8b\x69\x50\xf7\xa8\xa1\x98\xa2\xe9\xe1\x61\x4f\xed\xe8\x4c\xc5\xee\x39\x6c\x2a\x34\xf4\x52\x34\x3d\xfc\xbe\xa7\x64\xd4\xa6\x87\xa2\xe9\xf4\xdb\x9d\x45\x54\xf6\x77\x70\x88\x5e\x8a\xa6\x2f\xbf\x1d\x8e\x41\xdd\x76\x79\xdf\x8e\x2d\x31\xc4\x4e\x78\x8e\xbd\x51\x7d\x96\x86\x8f\x4a\xcf\x04\xa9\x45\xe1\x35\x3c\xf5\x9a\x92\x9b\xb5\x89\xb4\x19\x77\xdd\xa3\x12\xa1\xce\x0f\xea\x62\xe1\xfe\xdb\x6a\xd0\x1d\x36\xa9\x2d\x5b\x95\xb7\xf3\x1a\xdd\xf5\xf0\x31\xfb\xff\x73\xf7\xfe\xdf\x6d\xe3\x48\xbe\xe8\xef\xf7\xaf\xb0\xf0\xee\xd5\x90\x6b\x84\x2d\xe5\x5b\x27\x50\xd0\x3e\x69\xdb\xd9\xce\x9b\x76\x92\xe3\x38\xdb\x3b\x57\xa3\x4d\xc3\x24\x24\x71\x42\x91\x1c\x92\x72\xa2\x95\xf4\xbf\xbf\x83\x02\x40\x02\x24\x28\xcb\xe9\x99\xb3\x73\xde\x0f\xb6\x48\x00\xc4\xd7\x02\x50\x28\x54\x7d\xea\xc0\x72\x67\xd4\x67\x9e\x15\x21\x97\x0d\xb2\x14\xdd\xeb\xcf\xdf\x34\x09\xd4\xaa\xc2\x7b\x33\xe7\xbe\x49\xc6\x85\x21\xf2\x3d\x6e\x90\xdb\x83\xf8\x00\x83\x20\xad\x9e\xf7\xf6\xe2\x7d\xce\x8b\x9a\x71\xcf\x1c\xca\xce\x8c\x6e\x15\x9c\xb5\x16\x4a\x69\xff\xfc\x85\xe9\xb1\xfe\x83\x33\x8d\xde\x2b\x6c\x67\x5e\xa0\xe0\x5a\x04\xf7\xf9\xfc\x02\x2d\x57\x25\x2a\x7f\x7b\xf1\xa6\xc8\x56\x86\xde\x23\xb1\xbb\x1f\x50\xb3\xdf\x5e\x78\x2d\xa7\x5d\xcc\xe8\xd4\x76\x73\xc9\x8b\xa7\x0e\x0d\x41\xd1\x91\x0f\x70\x1e\x60\x5b\xbd\x0c\xc6\xa2\xbb\x7a\xab\xac\x60\x11\xfa\x7a\x44\x01\x2d\x38\xfb\xda\xad\xb5\xd2\xd7\x1f\x85\x37\xc8\x7c\xcc\x82\xbe\x9a\x50\xde\x1b\x85\x59\xd0\x5b\x43\xca\xfb\xe3\x30\x0b\xdc\x55\x97\xa2\x39\x17\x6d\x64\x70\xb9\xea\x18\xae\x8e\x69\xc3\x8f\x0f\x40\x13\x37\x01\x2e\xed\x7b\xa7\xe0\x33\xb8\x5e\x52\xe0\xc1\x52\xda\xa8\x65\x05\x0b\x0e\x97\xb8\xd2\xe1\xba\x96\x71\xa0\x13\x30\x46\x05\x43\x5b\x65\x89\x2b\x81\x38\x4e\xb2\xf9\xc9\xef\xe8\x34\x3d\x45\xbf\x07\x68\xaf\x5d\xc2\x76\x56\xbe\x7a\xe3\x71\xfa\x66\x6c\x99\x49\xc4\xfd\x66\x12\xa5\xd3\x4c\x62\x7d\xb4\x99\x84\x75\xac\xb7\xad\x2e\xcc\x73\x7d\x62\x84\xbf\x63\x95\x79\x1d\x87\x6c\x23\x0b\x65\xf4\x10\x39\x8c\x1e\x4c\x39\xc0\xfc\x90\xa0\xa0\x2b\x0a\x30\x2f\x65\x6d\xb9\x84\xa2\x98\x46\x26\xd1\x96\x0f\xdc\x19\xf6\x8c\x32\xae\xb1\xbd\x30\xa7\xe8\xe2\x88\xeb\xda\xcb\x8e\xd8\x60\xec\xe3\x73\xba\xad\xd9\x2c\x6b\xaa\x49\xae\xd2\x26\xb4\x1a\x59\xad\xc8\x32\x50\x8c\x7f\x7b\xa1\x90\x58\x21\x54\x1b\x1f\x99\x61\x39\x4f\xa3\x38\x5d\xe8\x0c\xba\x31\xb0\x63\xc1\x8e\xe0\x88\x34\x4f\x19\x62\x11\xb2\x22\x8d\x2d\xa9\x89\x93\xe4\xcc\x9b\x23\xb3\x99\xab\xde\xcb\x8d\x20\x58\x2c\x00\x8f\x94\x8e\x74\x33\x4a\xad\xf9\xd6\x29\x52\xef\x73\x0a\x96\x17\xdb\xb7\x9d\x9d\x9b\xef\x56\xa9\xdd\x22\x2f\x4f\x4f\xbb\x3d\xaa\x2f\xb2\x54\xc9\x72\x8d\x69\x0e\x1c\x9d\xd9\x0f\xec\x8a\xaf\x51\xda\xf4\x07\x6a\x02\xba\x3f\xd1\x75\x12\x73\x36\x11\x6b\x44\xdd\x06\x38\x72\xbc\xc9\x8a\xfa\x26\xc2\xf1\xb9\x98\xd3\xd2\x42\xae\xc0\x99\x3f\x89\x15\xc3\x54\xe0\xb8\xe6\x96\x32\xb8\x5e\x9b\x97\xf4\xae\x4d\x1b\x31\x5e\x0b\xee\xc7\x8b\xb1\x3c\xee\xc9\xdb\xc0\x58\x9e\x09\x26\xb5\x2c\xb8\x04\xcb\x59\x79\x50\x90\xbd\xed\xe3\x4d\x97\x3b\x2a\x3b\x87\x8c\x52\x1f\x32\xfe\xd1\x04\x06\x35\xcd\x71\x84\x97\x34\xec\x3f\x94\x4e\x0e\xc4\x49\x83\xc1\xaa\xd8\x6c\x45\x47\xb5\x25\x48\xd0\xe0\x6e\xb0\xd7\xdb\x1c\xa3\x87\x6c\x52\x31\x12\x7a\x6a\x70\x9a\xa1\xf1\xc1\xae\x4c\x7e\x20\x11\x0f\x00\x48\x29\x32\x25\x61\x5e\x2a\xd6\x40\x73\x42\x35\xc9\xea\xab\xfd\xdc\xdf\xcf\xe3\x94\x25\xc9\x66\x7b\xa8\xcd\xcb\x7d\xdf\xc4\x34\x09\xc3\x71\xb5\xef\x45\xd8\x49\xbb\x62\xe4\x7d\xed\xd1\x2f\x68\xe9\x1b\xf4\x94\x05\x46\x9e\x6a\xf6\xf1\x62\xc1\xed\xc6\xe2\xdc\xaf\x8f\x6e\xc6\x10\x68\xd1\xdd\x70\x08\xdb\x68\xc3\x4f\x5d\x73\x16\x6d\x3c\x5f\x33\xbf\x9e\xe3\x1b\x1c\xfb\x78\xb5\xef\xd8\x19\x75\x25\x1f\xf6\xec\x00\x27\x88\x81\x4b\x1a\x57\xa3\x65\x37\x5d\xad\x62\x7a\x88\xaf\x1b\xdb\x90\x9f\xbb\x08\xcf\x39\xa0\xae\x7c\xf6\xfb\x79\x57\xd5\xa3\xa7\xeb\xfd\x63\x16\xe6\x7f\xce\x5e\xe0\x5c\xb4\xef\xdd\x97\x1c\x9b\x44\x7b\xbb\x5b\x6b\x5c\x0a\xee\xef\xf1\x67\x2d\x85\x7a\x9b\x56\xbc\x48\x59\xe2\x74\x26\xe4\x2a\x75\xb7\x73\x11\xf8\xc4\x59\xc1\x52\x1a\x31\x82\xc9\x9c\x21\x81\x4a\xf1\xca\xdb\xee\x71\xaa\x66\x39\x17\xfc\x85\xa6\x4b\xe3\xb4\x06\xe7\xbd\xcf\x2b\x56\x7e\xd1\xb2\xee\xae\x50\x49\x33\x8f\x48\x7a\xe7\x36\x6e\xf2\x7a\x67\xa1\x56\x78\x34\xa5\x46\xae\x84\x96\xac\x14\x34\xb1\xd2\xe6\xdb\x8a\x6e\xf7\xb5\xb4\xa5\x90\xbe\xad\xab\x69\x31\xa3\x7c\x5a\xd4\x60\xda\xd5\x1e\xb7\x36\x36\x47\x0b\xd4\x04\x6f\x5a\x69\x5c\x92\x89\x0c\xfa\x96\xbb\xde\xac\xf4\xb4\xc4\x8a\x93\x36\x3f\x52\xab\x82\xb5\x92\x28\x26\x7b\xeb\xd8\xa8\x2a\xeb\x5a\xac\x23\x82\xf6\xdb\x3d\xb0\xf1\x0a\xe9\xfc\xe3\x9e\xcf\xea\x3b\x40\xdb\x21\x47\x67\x95\x6b\x11\xa5\xee\x95\x33\x20\x1f\x0e\x52\xe6\xa6\x8b\xdb\x12\x50\xd3\x32\xf4\x33\x80\xc4\x7c\x70\x4a\x9f\x0d\x74\x73\x25\x2b\x54\x67\x0f\xcb\x13\x91\xdb\x99\x0b\x53\x97\x8d\x31\xac\x50\x1b\xcf\x25\xf4\x98\xb2\x19\x9c\x27\xa6\x6c\xe6\x55\x98\xe1\x0c\xa7\xfe\x3e\x64\x55\xb8\x04\x57\x34\x94\xef\xe3\xb9\x17\x9b\xe6\xf8\x20\xdf\x12\xe7\x46\xc9\x6c\x44\x30\x4f\xf6\xe0\x8c\xcf\xd6\xcb\xeb\xd1\x5a\x74\x91\x74\xcd\x69\x29\xaa\x76\x4f\xd8\x66\xf9\x68\xdd\x9c\x78\x15\x2e\x30\x97\x75\xc7\x39\x2f\xe6\x59\xb1\x92\x53\xf5\xed\xfc\x1d\x17\xdd\xcf\x8a\x8d\xd5\xf9\x12\x09\xc3\x55\xca\x70\x38\xef\x6a\x18\xca\x09\x7f\xf4\x7a\x83\xb9\xbd\xf0\xf9\x58\x41\x6f\xd0\x9e\xb5\x59\x67\xd3\x5d\x7a\xfd\xe1\xd0\xd9\x62\xee\xdc\xc9\x0f\x06\x6a\x2d\x30\xab\x66\x7b\xfc\x59\x1c\x5e\xde\xce\x15\x51\x97\x17\xf1\x7c\xde\xf1\xde\xc6\x9d\x0b\x01\x76\xad\x0f\x55\x17\xce\x24\xf8\xc2\x37\xa5\x57\xf9\x41\x99\x15\x82\xf9\x2a\xa8\x67\x13\x33\x1e\xf9\x93\xa2\x76\x3f\x02\x9e\x31\xb6\xe0\x03\x63\xdf\xb9\x23\x3b\x0c\x5f\x61\xac\x2f\x31\x65\x7a\x8d\xc4\x25\x65\x72\x35\x9f\x54\x03\x4a\x53\xf0\xd9\xe6\xe4\xec\x53\x63\xc8\x4a\xd7\x69\x21\xd5\x47\x03\x16\xf4\xde\x37\x0e\x87\x07\x22\xbd\x12\xc7\x4a\x13\x69\x7d\x80\xc7\x14\xa9\x70\x48\xfb\xa8\x62\xb7\x1b\xb0\xc0\x79\x91\xb9\xdb\xf5\x44\x78\x25\x5e\xe3\xd8\x9f\x84\x67\xde\x31\xdb\x3c\xcc\xa1\x76\x16\x29\x86\x4c\xc4\x54\xf3\x7d\xe2\x3c\xc8\xd4\x47\xb2\xe6\xd8\xa2\xfa\x9e\x96\x98\x29\xde\x7a\x8d\xeb\xb1\xa1\xb1\x6f\x2c\x92\x46\x17\x1c\xd8\xf2\xeb\x31\x2e\xfa\xe6\x53\x73\x72\xeb\x32\x3a\x93\x1a\xd0\xfb\x18\x2e\xa8\xcd\x3f\x0d\x1a\x05\x16\x75\xbe\x8a\xe7\x5e\x36\x1c\x8e\x29\xa5\x85\xc6\x4a\xd1\x6a\x2f\xd3\xd1\xac\x59\xa7\x29\xec\x0b\xd9\x99\x08\x25\xea\x63\x00\xa3\x3e\x1b\x93\xd1\x24\x7e\xa5\xbf\x9e\xc4\xda\xca\x49\xea\x6b\x4f\x56\x1e\xc3\x8e\xa5\xbb\x3c\x2b\x35\xca\x0d\x93\xdb\x4d\xa9\x7d\xb7\x9d\x30\xd1\xa7\xce\x31\x74\x4c\x20\x5c\x03\x02\xb5\xba\x57\x9c\x21\x25\x13\xb4\xd6\xa7\x49\x70\x25\xaf\x17\xe9\xd6\xd9\x4a\x16\x30\x1c\x3a\x83\x3d\xa9\xf5\xe9\x5c\xa0\x68\x6b\xb9\xa4\x0c\xeb\x03\x70\x85\xf5\x79\x2c\x35\x8e\xc2\x85\x4a\xbf\x56\x52\x99\x16\x1b\xec\x81\xbe\xae\x7d\x84\xd0\x95\xcb\x1e\x72\xee\x90\x1f\xc9\xab\xb1\x18\x68\x3f\xf4\x31\x10\x6c\x4f\xc9\x07\x88\xb6\x7b\x80\x2a\x68\xda\xbb\x0f\xf6\x1e\x23\x7d\xcc\xee\x3b\x45\x66\xc0\x33\x2d\xbc\x02\x33\xdf\x77\x6c\x66\x8a\x5e\x7a\x8e\x6e\x95\x98\xdb\xa6\x32\x62\x9b\x5f\xc7\xa5\xa8\x77\xf3\x3e\x71\x1c\x5c\xd2\xfe\x23\xca\x7d\x47\x54\x76\xdf\x11\x75\x7d\xfc\x11\x35\xbe\xb7\x9d\xfa\xcb\x1e\x49\xb5\x58\x34\xfd\x3d\x78\x63\xeb\x93\xc4\xdb\x23\x9e\xf5\x4b\xbd\x15\x02\x54\xef\xb8\xfd\x26\x81\x1e\x41\x90\xfb\xbe\xe8\xf0\x98\xee\xd3\x2d\xae\xa8\xbe\x5f\xf5\x2c\xc6\xbc\xaf\x94\x2e\x63\x8e\x53\xb1\x53\xca\xde\x9e\xd4\x4f\xb4\xb7\xdf\x0e\x09\xbf\x30\x87\x79\x67\x64\x01\xac\x67\x75\x0f\xc9\x3a\x9b\x6e\x9c\x9d\x9b\x5a\xa5\x46\xf6\xc0\x97\xab\x26\x6f\x94\x7a\x21\xad\x76\xbb\xc1\x58\xfe\x96\x0e\x15\x60\x5c\xed\xb1\x74\xaa\x71\xcd\xe7\xfd\xb3\x75\xc1\xab\x0f\xeb\xdb\x24\x0e\xf5\x01\xdd\xf3\x27\x5e\x2a\xc5\x6f\x94\xde\x9d\xa9\xc7\xed\x9e\xc8\x27\x5f\xfa\x9f\x74\x7c\xb6\xc7\xd2\xa5\xb6\x5d\x9c\xbf\xd5\x2e\xf3\x7a\x4a\x83\x5c\xc1\xbf\xad\x62\x92\xfa\x08\xc1\x31\x4d\x70\xfb\xac\xa5\x58\xc8\xfa\xdd\x3c\x00\x35\xce\xb8\x0c\x6d\xa2\xdd\x0e\xce\x62\x56\x08\x0f\xd2\x26\x46\x3e\xca\x83\x51\xa7\xf6\x0e\xa8\x09\xbb\xfc\x3d\xee\x9f\xff\x52\x31\x6e\x92\x6b\x3c\x21\x89\xfc\x5e\x7a\xe7\x18\x35\x09\xcb\xd8\x60\x09\x11\xde\xb6\x24\x42\xc8\x7e\x47\x1d\x26\x12\xb5\x02\xd0\x81\xf9\x82\x7a\xa3\xd0\x5e\x2e\x48\xd7\x1a\x72\xf7\xdc\xbc\x9f\xba\x3e\x5a\xd5\xc0\x42\x68\xf9\xf1\xf9\xf7\xe1\xa9\x7c\x37\x0a\xca\xb1\xea\x08\xed\x5b\x1e\x32\x1e\x3f\x39\x02\x22\xe5\xfb\xb5\x17\xfa\xd0\x54\xf4\x05\x0f\x19\x3f\xfe\x11\xb7\x2e\x72\xc8\xf8\xd9\x33\xf7\x05\xf8\x3d\xc6\x4c\xae\x3b\xf2\x07\x60\xa4\xb5\xef\x98\x32\xd7\x1d\x13\xeb\x5c\x16\x6d\xd5\xec\x25\x99\x05\x77\xe4\x58\x96\x70\xe6\x5c\xa4\x0b\x60\x29\x31\xf7\x61\x99\x4d\xa9\x7b\xd1\x6c\xb0\x00\xf7\x96\xf1\x26\x3b\x40\xa2\xae\x5e\x6d\x77\xd0\x71\xc8\x34\x75\x23\xe5\xcc\xee\x00\x47\xbe\xf8\x2e\x60\x99\xcc\xc6\x24\xf3\x78\x17\xcf\xb6\xb9\xfe\x64\xc7\x5c\x7f\xae\x58\xae\x87\x4a\xb0\xe5\xcc\xdb\x32\x82\x18\xc2\xec\xf6\xb6\x20\x48\xfc\x47\x98\x45\x91\x44\xf6\x50\x0f\x08\xb3\x82\x8b\x64\x05\x17\x29\x8b\x2a\x0e\x13\x2e\x5e\xe1\x01\x61\x56\xc6\x91\x78\x17\x3f\x08\xb3\x75\x14\x67\x04\xc1\x0f\xc2\xb7\x04\xdd\x22\x7c\xcb\x4a\x4e\x90\xf8\x8f\xf0\x6d\x14\x13\x74\x1b\xc5\xe2\x29\x13\x4f\x22\x55\xbc\x20\xe8\x36\x5e\x20\x7c\x9b\x64\xe1\x97\xbf\xaf\xb3\x4a\xa4\xaf\x9f\x11\xbe\xcd\xa2\x0d\x41\xe2\x3f\xc2\xa2\xa6\xa2\x9e\x0a\x4b\x1c\xc9\x5f\x84\x43\x96\xde\xb1\x92\x20\xf9\x2b\xde\x73\xd0\x0d\x40\xea\x01\xe1\x30\x06\x18\x98\x58\xe4\x18\x66\x11\x40\xc2\x44\xf0\x9c\x88\xc7\x04\x9e\x16\x12\xd1\x5e\x3f\x21\xe9\x17\x04\x89\xff\xf2\x19\xfc\x5d\x20\xfd\x84\x70\x14\x11\x14\x45\x08\x47\x3c\x21\x28\xe2\x09\x82\xdd\x30\x4e\x4a\xf1\x06\x0f\x08\x47\xf3\x94\xa0\x68\x9e\x22\x1c\xc5\x2c\xc9\x16\x04\xc9\x5f\xf1\x7e\x27\x5e\xee\x10\x8e\xc4\xe7\xe2\x6b\x91\x7b\x85\x30\x5f\x11\xc4\x57\xe2\xf7\x96\x47\xe2\xf1\x96\x47\x08\x03\xc0\x35\x78\x20\xd0\x4f\x22\x6c\x51\x37\xb6\x79\x86\xf0\x75\xc1\x21\x0c\xdc\xd3\xcc\xb3\x0c\x00\x67\xe4\x2f\x92\x7e\x49\x90\xf8\x8f\xf0\x72\x4c\xd0\x72\x8c\xf0\xf2\x31\x41\xcb\xc7\x08\x2f\x9f\x10\xb4\x7c\x82\xf0\xf2\x29\x41\xcb\xa7\x08\x2f\x9f\x11\xb4\x7c\x86\xf0\xf2\x39\x41\xcb\xe7\x08\x1c\x8f\x10\x24\xfe\x23\xe5\x84\x44\xbe\x01\x1a\x9e\x78\x2e\xa4\x07\x04\x82\xc4\x7f\x84\x63\x82\x62\x84\x63\xf0\x5e\x42\x90\xfc\x45\x38\x5e\x2d\x08\x8a\x57\x0b\x84\x63\x0b\x76\x26\x4e\x4b\xf1\x5c\x22\xfc\xe5\x36\x22\xe8\xcb\x6d\x84\xf0\x17\xbe\x59\x70\x09\x43\xb3\xe0\x29\x52\xce\x48\x10\xfc\x20\x9c\xf0\x05\x4f\x23\x82\xe4\x2f\xc2\x49\x4c\x50\x12\x8b\xdf\xf4\x8b\x78\x4a\xbf\x20\xbc\x62\x71\x4a\x90\xf8\x8f\xc0\x4a\x0d\xad\x58\x2e\x9e\x8a\x2f\xe2\xb1\x10\x29\x00\x05\x48\xc2\xff\x88\xff\x71\x25\x46\x41\x3f\x89\x30\x41\x0b\xe2\x3f\x3c\x03\x1a\x0d\x87\xbe\x4c\xd9\x1d\x41\x29\xbb\x43\x38\xcd\xca\xb0\x88\xf3\x8a\x20\xfd\x84\xb0\x14\xeb\x12\x2d\xde\xc5\x82\xe0\x04\xbd\x65\x79\xa5\xe8\x4d\x3f\x41\x18\x8c\x64\xa6\x46\x31\x5b\x57\xd0\x35\xf2\x17\xe1\x9c\xa0\x1c\xe1\x9c\x15\x6c\x45\x10\xfc\x20\x9c\xc7\xe0\x81\x88\x20\xf5\x80\x70\x0e\x6f\xf2\x29\x5b\xc8\x09\xad\x9f\x10\xfe\x3b\x41\x7f\x47\xb8\xc8\x09\x2a\x72\x84\x8b\x8a\xa0\xa2\x42\xb8\x58\xdf\x6e\x08\x12\xff\x11\x2e\x09\x2a\x11\x2e\xd9\x2a\x27\x48\xfc\x47\x58\xb7\x4a\xb7\xa9\x54\xba\x37\x48\x3d\x20\xe5\x7c\x44\x03\xe9\x20\x5c\xae\x18\x60\xee\x88\x1f\x84\xcb\x6c\x5d\x84\x9c\x20\xf9\x8b\xa4\x07\x12\x24\xfe\x23\x5c\x56\x45\x96\x2e\x08\x92\xbf\x48\x79\x16\x41\xf0\x83\x70\xb9\xbe\x25\xa8\x5c\xdf\x8a\xa7\xd5\x8a\x15\x1b\xf1\x06\x0f\x22\x44\x54\x10\x60\x7f\xc0\x79\x07\x82\x1f\x84\x2b\xb9\x64\x54\x72\xcd\xa8\x22\x82\xaa\x08\x61\xb1\xf5\xc8\xd5\x4c\x3f\x21\x5c\x89\xe9\x40\x10\xfc\x20\x5c\x2d\x09\xaa\x96\xe2\x17\x08\xbc\x92\x14\x5e\xc5\x82\x6a\xc5\x7f\xa4\x1c\x9a\x20\xf8\x41\xb8\x2a\x08\xaa\x0a\xf1\xcb\xc2\x2f\xe2\x91\x85\x5f\x10\x5e\x13\xb4\x46\x78\x9d\x10\xb4\x4e\x10\xbe\x63\x05\x41\x77\xac\x40\xf8\x2e\x8e\x78\x46\x10\xfc\x20\xfc\x55\x2c\x65\x5f\xc5\x5a\x16\xc6\x05\x2c\xaa\xf2\x17\xe1\x30\x89\xf3\x0f\x4c\xd4\x45\x3f\x89\x55\x65\x0e\x4b\xca\xbc\x44\x98\x27\x49\x9c\x8b\x45\x55\x3d\x20\xbc\x20\x68\x01\xd4\xce\x81\xda\xb9\x7c\x66\xc5\xbf\x17\x2c\x8a\x81\xc7\xb3\xdf\x05\xdd\x97\x40\xf7\xe5\x17\x41\x4d\xa2\xac\x1c\xca\xd1\x4e\x70\x90\x7a\x40\x38\xcf\x92\xcd\x42\x8c\xb4\x7a\x90\x21\xb2\x2c\xfd\x24\xfd\x81\xb0\xa4\x29\xcf\x7e\x47\x58\x3a\x25\x91\xde\x48\xca\x2a\x13\xc3\x56\x65\x82\xae\xee\xc4\xc0\xdf\x2d\xe4\xe8\xc8\x91\x41\xb8\x92\xe4\x01\x3f\x68\x8f\x0b\xbf\x0b\x80\xfd\x60\x9e\xb0\xd9\xfd\xc8\xf8\xc5\x63\xb1\x2d\x3f\x00\x27\xe1\xb5\x76\xa0\xa2\xc1\xd3\x1c\xb0\xf2\x35\xbf\xa5\xd3\x30\x07\x2a\x6c\xec\xdc\xbe\xcb\xae\xf9\xce\x9a\xc6\x2d\x06\x40\xef\x75\x3e\x0e\x69\xe9\x6d\xb3\x54\xa2\x8f\x0d\x46\x38\x4b\x4d\x38\x32\x08\x68\xa0\xb7\x9a\x57\x00\x9f\x6a\x5e\x3f\xe5\xf2\x05\xbe\x52\x30\x23\x9d\xdc\xac\xf0\x3a\xd3\x6e\xa8\xc8\xbb\x1b\xfa\x29\x6f\xc2\xf6\x60\xcb\x69\x22\x90\x7a\x96\xed\x07\xd2\x7a\x89\x3f\xab\x2d\xbd\x62\x0b\x19\xf1\xf3\xa7\x9b\x9b\xf7\xef\x90\x36\xff\x98\x16\x38\x9b\x69\x13\x9b\xce\xa1\xd1\xb8\x17\x04\x5b\xb6\x46\x39\xd7\x1f\x34\xcf\x5d\xab\x35\x75\x41\x21\x63\xb5\x67\x8b\xe1\x30\x04\x1f\x18\x1e\xd8\xac\x35\x09\xa6\x95\x01\x7d\xa0\x6f\x2a\xb4\x3b\x04\xa9\xd7\xe7\xdb\x9c\x68\x22\xa9\xb6\x45\x47\xe4\x69\xc3\xf5\xbb\xa9\x88\x3c\x7f\x79\x00\xa6\xb2\x45\xff\xb6\xa2\xb3\x20\xf1\x87\xc0\x17\x80\x47\x5a\x75\x8d\xc3\x4d\x7d\xd4\x8f\xbc\x7a\x9b\xa6\xbc\xf8\xe5\xe6\xea\xd7\xe1\xd0\xdb\xd4\xfe\x6a\xea\xb6\xba\xb4\x6c\x0e\x64\x81\x3e\x7f\x06\xbe\x00\x4c\x0d\x7b\x52\xf9\x22\x53\x5d\x10\x6c\x05\xbb\x9d\xa3\x0c\x88\xf1\xbb\x1e\x93\x1b\x98\x81\x28\x98\xc7\x69\x54\x9f\x37\x59\x9c\xf2\xe2\x4d\x56\x80\x7a\x2c\x88\xb6\xf5\xf5\x4a\x16\xa4\x59\xc4\xc5\x79\x8d\x52\xfa\xf5\x2c\x0b\x40\x41\xf2\x42\x79\x10\x24\xd9\xe4\xdc\xab\x30\xf3\xf7\x12\x40\xa1\x01\xa4\x01\xd9\x79\x23\x61\x35\x62\x34\x5c\x8f\xed\xf4\xe7\x42\x0a\xb5\xdf\x63\xee\xef\x76\xde\xc6\xfb\x00\x8e\x00\x3d\xee\xfb\xf8\xfd\x94\x4b\x3c\x22\xdb\xc5\x0f\x78\xd5\x90\x12\x86\x8a\x2d\x1a\x85\x3a\x2d\x0e\x54\xc3\x60\xa9\x2a\x14\xfc\x2e\xce\xd6\xe5\x47\xd1\x3f\xe7\x59\xbe\x39\xa0\x9a\xb0\x97\xa2\x78\x58\x82\xce\x3f\x7e\xd4\x93\xc2\x52\x86\x5e\xbb\xbc\x50\x86\x9d\x40\xeb\x9b\xe4\x5e\xd7\x1b\x4e\x83\x4e\x9d\xd4\x52\x13\x8d\x1c\xca\xd8\xa6\x15\xe7\xd5\x3a\xa9\x62\x85\xf8\x6c\x69\x4b\x2a\xed\xcc\x7b\x54\x25\xcb\x90\xe5\xdc\xf0\xd5\xf9\x26\x2b\x54\x35\xfa\x54\x27\xbd\x3e\x30\x4c\xd3\xea\xd2\xa5\x3f\x99\xb4\x50\x89\x7c\x7c\x4e\x93\x40\x63\xcd\xe1\x6b\x9a\xf4\x62\x22\xdd\xd2\xad\xd4\xb3\x10\x4b\x6c\xba\x5e\xdd\xf2\x02\x5c\x22\x7d\xa3\x0b\x6f\xdb\xf8\x63\xdb\xfb\xf8\x2b\x1d\xe3\xcf\x72\xc8\xaf\xe8\x16\x98\x9e\xc1\x48\x1e\xc5\xc4\x6f\x01\x4e\x98\xb2\x44\xfc\xc8\x13\xc6\x60\x24\x18\x77\x70\xc7\x04\xb9\x4b\x8e\x7c\x30\xd2\x8c\xf7\x60\x24\x99\xe9\xc1\x48\xb2\xc1\x83\x91\x62\x42\x07\x23\xcd\xdb\x0d\x46\x8a\x0f\x1a\x8c\x80\xb9\x11\x35\xfb\x40\x7f\xf8\xaf\x29\x7b\xf4\xdf\xaf\x1f\xfd\xdf\x99\xfa\x25\x9f\xff\x1a\xfc\xf5\xd1\x5f\xa3\xd9\xbf\xfd\xef\x1f\xf0\x7b\xba\xdd\xe3\x0b\xba\xdd\xb7\x16\xe4\x49\x6c\xd9\xfe\xd5\x7b\x83\x21\xd0\x8a\x03\x58\x21\x1f\xa6\x8a\x7a\xa4\xf6\xa5\xa9\x58\x89\x8b\x43\x1a\x94\xca\xc6\xfb\x6a\x5a\x4f\xcf\xd9\x19\x42\x04\xbd\xfa\x01\x9d\xd6\x41\xa7\xe8\x27\x64\x3b\xa5\x95\xbb\xe0\xfb\x9c\xa7\x37\x6c\x21\x25\xe8\xaf\xd3\xc8\x58\x3a\x4a\xaf\xf2\x4f\xcd\xb4\x8a\x30\x65\x5a\x00\x6e\x39\xcd\xf6\xf8\x88\x8c\x7a\x15\x55\x5c\xed\xc1\x29\x45\xaf\x8c\x9a\xdb\x1a\x26\x6e\x50\x88\xc2\x6f\xd0\x20\x0a\xcb\x0b\x47\x3c\xf7\xae\x1d\xa9\x33\xaf\x73\xe3\x52\x60\x86\xb9\xba\x94\x29\x28\xa5\xdf\x86\x43\x8f\x89\x3f\xda\xb7\x9c\xc1\x5d\x63\xa5\xd7\x7f\xcc\x68\xa9\x58\x0b\xd9\x09\x6f\xb2\x02\xd2\x96\x1e\xf3\xb5\x4b\xe1\xb0\x9d\xa2\xa9\x14\x66\xfe\x24\x16\xbb\xdf\x29\x45\x27\xe8\x34\x6e\x1c\x81\x70\x27\x18\xf8\x59\x2a\xc6\x94\xa4\xa7\x22\x75\x27\xdf\xb7\x17\x9d\x16\xfa\x22\x7d\x3d\x5e\xd6\x60\x3a\x85\xf4\x08\x4d\x90\x58\x13\xc4\x9a\x51\x6b\x55\x54\x6c\x31\x1c\xc2\xb9\xae\x15\x54\x9f\x67\xcc\xf0\xdd\xce\x4b\x29\xfa\x6b\x8a\xfc\x49\xbf\x5e\x8a\x1a\xf6\x8c\x16\x7d\x1b\x71\x33\xa0\x59\x8d\xa0\x33\xa0\x59\x20\xf7\xf0\xfa\xae\xf8\x54\x87\xec\xeb\x9b\x35\x46\x6f\xa7\x6a\xa3\x2e\x6a\x5e\x61\x76\xd6\x3c\x2b\x43\x0e\xaa\xe8\x45\xfa\x11\x6b\xa2\x4d\x52\xaa\x8b\xb9\xf3\x98\xdf\x44\xc4\x0d\xca\x8e\x24\x5a\x0b\x83\x4a\x3a\xea\xf0\x83\xbf\x65\x71\xea\x21\x64\x7a\x77\xf9\x23\xba\x3c\x93\x43\x57\xbc\x6e\xc5\x9d\xd4\xbf\x57\xd1\x23\xd3\x1a\x47\x7d\xba\xda\xe6\x8d\x70\xb3\xe5\xc6\xbc\xf4\xaa\x5a\x93\xaf\x9d\xa8\xee\x89\x3a\x09\x38\x26\x71\xe5\xe2\x14\xca\x8a\x79\x19\x1f\x20\x1c\x58\x1f\xd2\x5a\x41\x6b\x10\xbb\xe0\x3a\x3a\x6a\x5b\xa9\x2f\x12\xa7\x62\x9e\x6b\x3d\x80\x9e\x69\x0e\xf9\xc3\xda\x53\xfa\x1d\xa6\xbd\xf0\x61\x85\x60\xbb\xdd\x76\x8f\xd9\xb4\x98\x51\x84\xf4\x85\xa7\x9b\xff\x91\x18\x29\x9d\x35\x29\xf5\xcf\x2e\xbb\x6b\x52\xea\x13\x6f\x1d\xc4\xe5\xc7\x8a\xa5\x11\x2b\x22\xb1\x13\x81\x19\xa7\x08\x6c\x39\x77\x16\x4d\x1a\x0e\x3f\xab\xad\x5d\x67\x0c\x97\xa2\x8e\x7c\x9b\x5e\x53\xc8\x56\x21\x8d\xa7\xe9\x0c\x27\x14\xfa\xe4\xac\xa7\x09\x84\x2b\x9c\x16\x67\x2f\x87\x03\x4a\x93\xa6\x5f\xe3\xb9\x17\x9e\x85\x87\x97\xcf\xd0\x27\x07\xb9\xc5\x44\xe2\x82\x40\xff\x27\xfe\x20\xe9\x0e\xc0\x6e\x17\x0e\x87\xa1\x2b\xbc\x3b\x30\x75\x56\xa1\xef\xf8\x62\x38\x4c\xa6\xc5\x6c\x40\x69\x38\x2d\x66\xed\x71\x15\x61\x0a\xe0\x86\xd1\x70\xd2\x3b\x8a\x8e\x9d\x25\xc5\x21\xae\xbe\x63\x24\xe5\x0c\xb9\x67\x24\x71\xe8\xef\x59\x93\x5a\xee\x38\xee\xb4\xcc\x9a\x76\xf7\xe0\x1e\x1e\x5c\xa9\xeb\x45\x95\x1b\x8b\x2a\x6f\x2d\xaa\x47\xaf\xbd\x07\x8e\x69\xbd\x51\x6a\xa5\xc7\x65\xff\xae\x31\x1c\xf6\x46\xe9\xaf\xd7\x6a\xdd\xcf\xe4\xba\xdf\xb4\x00\x87\x7d\x3b\x82\x98\x21\xf2\x1b\x79\x37\x3b\xa0\x31\xce\x75\x62\x1d\x54\x4e\xe4\xef\x5a\x7b\x50\x0d\xcf\xcc\x95\x59\xaf\x88\xf2\x3c\x04\x90\xc7\xc3\xe1\x20\xb7\xb4\x10\x8d\x93\x80\xd8\x37\xb0\xae\x4e\x36\xa0\x94\x1d\x48\x79\xca\xa4\x69\xfb\x80\x96\x67\xf1\x00\x0c\x52\x34\x6d\xd4\xcd\x77\x93\x47\xa9\x3f\x0c\x6d\x75\x48\x5d\xdb\x50\x01\xbf\x1e\x32\x0e\x90\xdf\xd9\x30\x8c\x5e\x73\xe0\x30\x21\x4e\xbb\xfc\x09\xce\x7b\xad\x20\x1d\x89\xdd\xe7\xc8\x3d\x5e\xb6\x6f\xb5\x63\xec\xe2\xdd\xff\xf8\x7d\xf6\xde\xc7\x2b\x69\xa7\xa2\x60\x10\xd4\x71\x00\xcf\xe5\xaf\x8f\xe3\xa0\xb6\x10\xa5\xca\x42\xd4\xb4\x78\xb5\xd8\xe2\x38\xf8\x99\x85\x5f\x78\x1a\x99\x29\xe8\x67\x80\x2b\xef\x48\x1e\xdd\x47\x64\x22\x41\x59\x1d\x4e\x8b\xdd\xc7\x63\xf2\xec\x1e\x4f\x25\x07\x1c\x26\xde\x7b\x5e\x26\x3f\x3e\x3b\xe4\xef\xc3\x38\x2c\x93\xf1\x78\xec\xbe\xe4\x3e\x74\x26\x26\xe3\x67\x3d\x66\xd8\x4e\x50\xda\x7b\x4d\xee\x5f\xdc\x87\xe0\x77\x84\xfb\xc6\x5f\x6b\x7f\x94\x37\x05\xcb\x5d\x32\xd8\x3e\x39\xed\x7d\xde\xbb\x4c\x2b\xd3\xb2\x2d\x94\x85\x0b\x34\x5f\x6a\x0d\xde\x2b\xda\x7c\x03\xb7\x6d\xb5\x60\xf3\xcd\xfb\xeb\xab\x46\xac\xc9\xdc\x62\xcd\x5a\xcc\x68\x48\x32\xf7\x0e\xac\xa0\xf6\x42\xd0\xc1\xa4\x6e\x79\xb3\x14\x6f\xd7\xbc\xe4\x15\x46\xe0\x66\x19\xa9\x59\x7d\xcc\x77\x1f\xc1\x1d\x33\x46\xd2\x2d\x33\x6a\xc9\x3a\xc3\x43\x90\xc9\xae\x61\x22\xcf\x9f\xfe\xa3\xc4\xa0\x82\x98\xee\xc1\x6f\xf8\x5f\x26\x35\xf5\xc9\xbb\xb2\x5a\xb4\xa5\x57\x52\x2b\x9a\x1d\x96\x7c\xc5\x0e\x69\x55\xd9\x15\x4a\xad\xbb\x82\x25\x25\x52\x2b\x8d\xfd\x52\x3a\xcf\xee\xd9\x4c\x09\xfa\xbd\x27\xe6\xf7\x93\xd5\xba\x04\x87\x9c\x25\xaf\x4e\xd6\x65\x9c\x2e\x4e\x7e\x77\xed\x45\xfe\xef\x41\x7d\xe7\xf6\x3b\xfc\x1e\xf8\xd4\x60\x71\xc4\x77\xe0\xf0\xaf\xcb\x2a\xf5\xb0\x35\x00\xb0\x0a\x0e\x6e\xb9\x3f\x59\x7b\x5d\x86\xb2\xf2\xf5\x5e\x9b\x9e\xb1\xa0\x54\xbe\x95\xed\x93\x3a\x6c\xd9\x1a\xb6\xdb\x15\x0f\x1a\x69\x6d\x36\xfc\x8f\xd4\xe8\x50\x61\xc6\xc9\xae\xe9\x1a\xe7\x89\xde\x2a\xaa\x30\x1b\xa7\x04\x15\x29\x54\xdd\x31\x42\xf7\x67\x17\x5a\x1f\x1b\x6b\xf6\x71\x9f\x67\x0e\x66\x46\x66\x78\x0c\x2a\xc5\x31\xf9\xdf\x97\x4f\xb7\x38\x37\x84\x46\xaf\x2b\x8e\xd1\x24\x7d\xc5\x4d\xd8\x2f\xc1\xe0\x07\x39\x13\x0c\xb4\x28\xca\xac\x50\x13\xf3\xf6\x42\x54\x4e\xe9\xe6\xab\x22\x14\xa6\xd5\xa4\x6c\xb3\x32\x79\xc3\xca\x58\xd0\x19\xd8\x35\x01\x50\x37\x0c\xb9\xc8\x12\x75\xc3\x50\x97\x9e\x50\x3b\x04\x39\xe9\x04\x39\x02\x51\x0f\x51\x20\x67\x30\x3a\x6e\xc4\xd1\x31\xa9\xd0\x11\xc3\x89\xee\x4d\x22\x38\xbd\x8e\xbb\xcf\xfb\x58\x30\xc7\x9a\x4d\x9e\xbe\xb8\x97\x19\x3b\xca\x3f\x9a\x43\xf3\xce\x5c\xac\xc9\xf8\xc5\x0b\xb1\x09\xfd\x03\x1c\x52\xff\x0f\x71\x34\x4a\x3d\xe7\x58\x9e\xe6\xad\xd2\xe6\xa9\xb9\x9a\xb7\x6f\xae\x5f\x5f\x5d\xfe\x8f\xf2\x35\xbf\x66\x2c\xc2\x28\xc9\x58\xf4\xaf\xc6\x9b\x3c\x00\x4d\xe7\x5f\x8d\x2c\x56\x8b\xe3\x69\x62\xb5\x30\x09\xe2\xea\xdf\xff\x65\xa8\xe1\x78\x1e\x17\xac\x40\x31\xe2\x52\x1f\xe3\x5f\x8b\x8a\x1e\x80\x00\xa4\xfa\xa9\xc6\x51\xf4\xb4\xbd\xa5\x81\xde\xe5\x59\xaa\xa5\x1d\x5d\x97\xe3\x98\xdd\x5f\xe3\xf4\x0b\x8f\x80\xa7\xd1\x68\xba\xe5\x11\x34\xb9\x76\xd0\x64\x9f\x27\xe4\x2e\x53\x9d\x3b\x71\x71\x22\xf7\x65\xef\xbc\xcb\x6e\x2f\xdb\xae\x7f\x3d\xa5\x84\xe8\xe3\x15\xdd\xee\xf1\x1d\x5d\x1f\x43\xee\xca\x31\x5c\x4d\xf0\xef\x3e\x7c\xba\x69\x48\x3e\xab\x85\x13\xe5\xac\x03\x32\xeb\xb6\x7a\x50\x6a\x28\x12\x74\x10\xfa\x54\xdd\x1f\x6e\x95\x17\x60\xc0\x62\xe2\x11\xe9\xa6\x56\x31\xbb\xdd\x60\xac\x5d\x06\x43\x06\x4a\xbe\xc4\xcf\xd4\x25\xf1\xbe\x57\x85\x26\x82\xab\xb5\x66\x1e\x4e\x78\x2b\x6f\x29\x1d\xe6\x56\xfd\x1a\x24\xc8\x4a\xf2\x5a\xd2\x6d\x90\x34\xa1\xe6\xc1\x5d\x9d\x66\x40\xab\xb3\x4a\xd6\x1b\xec\xde\x02\xb3\x92\x13\x83\x7b\x54\x85\xb5\x10\x3e\x83\xd0\xa8\x83\x38\x27\xa4\x8e\xbc\xd4\xa7\x98\x07\xda\xc1\x9f\x12\xa9\x4a\x27\x75\x32\x08\x2f\xfb\x34\x77\x0e\xaf\x3b\xb2\x93\x00\x01\x47\x4b\xf2\x1a\x2f\xa4\x9e\xef\x4f\x56\x60\x2b\xb3\x8c\xcb\xbd\x1b\x23\xd7\x3d\xe4\x66\x1e\xb8\xaa\xf3\xe7\xfe\x44\x59\xd2\xac\xa6\xd5\x6c\xef\x82\xe5\x3d\x20\x43\x36\x33\x9d\x18\x26\xe1\xba\xc5\xd0\x4d\xc3\x61\xdf\x59\x0b\xa9\x14\x08\x77\xbf\x12\x04\xa6\xaf\xbf\x3b\x03\xae\xa4\xb4\x07\x72\x06\x82\x40\x18\xa1\x53\xb8\x90\x32\x07\xc6\x69\xc1\x05\x45\xbc\x57\xa3\xa9\x4b\x19\x0e\xbd\x8a\x2a\x47\x20\x95\x44\x11\x04\x3f\x15\x25\xcb\xbd\xc2\xc0\x0a\xca\xcc\x56\xa7\x6c\x05\x36\xad\xa0\xa3\x98\x21\x4a\xcd\xc8\x6a\x93\x73\x29\x37\x86\xfb\xce\xc6\xb6\xb5\x3b\x46\x25\x65\x93\xd2\x38\x62\x4c\xfc\x92\x5a\xef\xfa\x63\xb1\x99\xfe\x7d\xcd\x8b\x8d\x74\x3a\x99\x15\xaf\x93\x44\xad\x33\xd3\x14\xd4\x1b\x4e\xff\xdf\x8f\xef\xdf\x05\x52\xb7\x23\x9e\x6f\x3c\xe8\x95\xd3\x3f\xcd\x40\x84\x4f\x55\x45\x67\x7f\xf2\xc1\x65\x60\x44\xd7\x8d\xcb\xc0\xa8\x71\x19\xb8\xac\x1d\x09\x2d\xa5\x98\x7a\x29\xd6\xf8\x15\xa5\x94\xc1\x83\x4c\x75\x57\x53\xd6\xd2\x9f\xcc\xbd\x3b\xd9\x41\x1b\xba\x9a\xde\xcd\x26\x73\x6f\x63\xf4\xdf\xc6\xdf\xd7\x37\xa6\xd5\xde\xe5\x15\xcb\xad\xce\x76\x90\xc7\xee\x6c\x13\xe4\xf9\x93\xa3\x04\xa1\x7f\x44\x31\xae\x8f\xb1\x6f\x5b\xda\x74\xb0\xf6\x5e\x3c\xc0\x44\xe6\xe0\x36\x97\x39\xb6\x39\xe6\xdc\xe6\xe2\x8e\xc6\x10\x6b\x6f\x51\x4a\x39\xdc\x17\x34\x98\x1d\xb1\x3f\xbd\x57\xca\xe4\xf5\x06\xf5\xfe\xc3\xcd\x5b\x4b\xa3\x72\xe6\x42\x27\x37\x01\x88\xfb\x59\xb6\xd8\x60\xd9\x8e\x50\x84\x34\x9d\x39\xfd\x03\x46\xb6\x2d\x48\xbe\xcf\x62\xc7\xe2\x8c\xda\x76\xf2\x0a\x90\x62\xeb\x08\xd4\x58\x5e\x9c\x96\xee\xb5\x4e\xdb\x20\x5a\x8c\x16\xab\xb1\x4d\x3b\x0a\x8a\xa6\x37\xa2\x69\x35\xb3\x1c\x8c\x01\xd4\xc9\x6a\x9d\x54\x71\x9e\x70\xe9\xc5\xcf\xc6\x2b\x83\x2f\xea\x4f\xf8\x57\x09\x59\xe2\xa1\x9b\x25\x3f\xf9\x1d\x9d\x56\xa7\xe8\xf7\x13\x31\x0a\x27\xe5\x3a\xcf\x93\x98\x47\x27\x55\x76\xf2\x4a\x6a\xe6\xff\x54\x0b\xf7\x58\x7a\xc2\x44\x76\x27\xf1\xfc\xe4\x77\x5d\xdc\xef\x27\x71\x79\x52\x15\x6b\x1e\x20\x75\xe3\x1a\xcf\xbd\x7f\x4a\xe9\x27\x65\xc8\x12\xb1\x22\x89\xbe\xec\xd6\x61\xce\x92\x12\x2a\xd1\x76\x64\xa2\x35\x13\x32\x31\x81\xac\x25\x39\x90\x13\xa3\x94\x1d\x28\xc9\xb0\xe9\x46\xb8\x74\x17\x4c\x5d\x41\x47\x38\xa3\x35\x48\x7c\xf1\x2a\x03\x40\x8e\x74\x8a\xd0\x69\x35\x2d\x66\x33\x3a\x18\xc9\xdb\x6a\x48\xc8\xda\x09\x95\xd9\x78\xc7\x5b\x0d\x9b\x16\x33\xc9\xe8\xf8\x13\x78\x96\x4d\xe6\xd1\x80\xd2\x78\x38\xf4\xac\x30\x1a\xfb\x7b\xa9\x2a\x23\xeb\x25\xca\xc6\x3d\x05\xc6\x73\x23\x6f\x6a\xb8\x1d\xb9\xcb\xe2\xa8\x95\xed\x60\xe4\x4f\x74\x06\x50\xe6\xc8\x8e\x94\x9e\x34\xe2\x1e\x56\xbf\xec\xe5\xe5\xd7\x47\x2c\x72\xa1\x63\x91\x4b\x9c\x8b\xdc\x03\xf9\xf6\xa4\xbd\x02\x2a\x23\x13\x93\x81\x3f\xb4\x00\x7e\x54\x36\x29\xf5\x02\xf8\xf1\xf2\xd7\xcb\x73\x83\x45\x8f\x71\xa9\x58\xf4\xf5\xcc\x40\xc9\xdf\x9a\x1c\x2e\xc9\xf0\x9d\xfc\x7d\x00\xeb\x5c\xb3\xad\x87\x18\x51\x93\x3d\xc6\xf3\xfb\xb9\x52\xe7\x12\xed\x5e\xb4\x8e\xe2\x65\xfb\x96\xb4\xb3\x7a\xfd\x22\x1d\xde\xd1\xec\x99\x7a\xa1\xeb\x89\xf7\xef\x61\x5b\xb5\x5e\x62\x4f\x3d\xaa\x33\xd7\x32\x0d\xf8\xc2\x1a\xa8\xcc\x27\x83\x66\xc5\x1c\x50\x53\xd3\x5f\x87\xd6\xba\xed\x3d\x95\x3c\xbb\xa7\x0d\xa4\x1b\xaf\xb3\x3e\x9b\xce\x08\x42\xfe\x51\x7c\x6c\xe9\xe0\x63\xf5\x52\xea\x64\x67\x9d\x4d\x1f\xb5\xb8\x5c\xdc\xe2\xcf\x96\x87\xf8\xb3\xff\x39\x16\xcc\xe4\xb7\xf6\x33\xfc\xf2\x21\x86\xb1\x2d\xaf\x7a\xb0\x0e\x0e\x87\x15\xa5\xb4\xb0\x36\x57\x4d\x4c\x91\x52\xdc\x0f\x6a\xcf\xee\x80\xc8\x26\x17\x8b\x6b\xe8\x7d\x1f\x10\x4a\x2a\xfe\x4d\xef\x05\x38\xa3\x69\x10\xad\xf3\x24\x0e\x41\x2c\x32\xc9\x82\x55\x76\xc7\x6f\x32\xd5\x98\x1b\x05\x0b\x95\x49\x17\xe4\xd1\x87\x2c\x4e\x2b\x0f\x5d\xa6\x11\xa8\x87\x16\xe0\xbd\x78\xa2\xcd\x09\x8c\x8c\xf5\xe9\x1d\x5c\xbb\x13\x86\x79\x1a\x11\x76\x5a\xec\x5b\xa6\x01\xb2\xe6\x5f\xe3\x34\xca\xbe\x0a\x3a\xa9\xbd\xd4\x0f\x87\x8e\x40\x09\x1d\x37\xa8\x76\xbb\x91\x38\xc4\x04\x85\x68\xd4\x39\x00\x3f\xb6\xdd\x95\x8a\x96\xb3\x34\x5c\x66\x85\xd8\x29\x61\xf7\x93\xaf\xef\xe7\xf3\x92\x57\x98\xd1\x2a\x00\x0f\xcc\x10\x1d\xeb\x37\x15\xab\x7c\x20\x40\xa7\xbd\xae\xbc\x91\xd8\x0d\x0a\xcf\xca\xb1\x95\x9f\x99\x9b\x95\x97\xd8\x24\xd6\x67\x23\x52\x06\x55\xa6\x1c\xd7\xfb\xba\xf3\x13\x0d\x58\xa8\x46\x67\x92\xa8\xb1\x13\xd9\xa8\x4b\x8a\x52\x74\x7f\xa2\xba\xdf\x83\x63\x7f\xd1\xd8\x75\x60\x15\xa0\xca\x92\xe8\xab\xb4\xf0\x92\x76\xba\xc4\x4c\x87\x93\x80\xa7\x91\x19\xc9\xd3\x48\x57\x37\xa2\xf9\xd9\x88\x24\x8e\xea\xce\x69\x74\x1a\xe2\x65\x43\x68\x16\x69\x4d\x96\x0a\xaf\xbf\xa8\xa4\x6f\xbc\xa5\xae\x34\xc3\xb1\x86\x22\x5d\x06\x61\x96\x24\x2c\x2f\x79\x64\x53\xc8\xea\x6c\x4e\x22\xa0\x92\xd5\x59\x44\xe6\x5d\xb7\x6a\x35\x13\xe4\xa0\x73\xbb\x22\x16\x3d\xd7\x50\xb9\x95\x68\xe3\x99\x27\xe8\x02\x4a\x14\x33\xc1\x27\xea\xe5\x27\x23\x96\xa7\x11\x78\x42\x83\x08\x9f\x58\x5f\x40\xac\x98\x0d\x3d\x93\x44\x04\xcb\x1e\x40\xe1\x92\x15\x2c\x94\xc6\xb2\x07\xe7\x4f\xa6\x3f\x14\x5d\x65\x7e\x56\x3c\x52\x1f\x8a\x56\x7a\x7e\xc7\xbd\x5b\x3c\xf7\x1c\x73\xa4\x76\xf6\xe8\x9a\x3e\xb8\xa0\x7c\x9a\x78\xfe\xac\x99\xfe\x57\xac\x5a\x06\xab\x38\xf5\xea\x56\x8a\x73\x5a\xab\xdb\x32\x62\x24\x83\x0e\x92\x33\x31\x0d\xf8\xb7\x8a\xa7\xd1\x70\x98\xfd\x54\x43\x4e\xb1\x09\xa3\x19\xce\x68\xac\xcc\x6c\x42\x8f\x8b\x46\xae\xe1\x41\xea\x32\x97\xc3\xe1\x5a\x26\xcf\xfb\xa8\x29\x6f\xa8\xa9\x04\x3b\x25\x5c\x06\x99\x22\xd1\x54\x21\x8b\xbe\x4e\x12\x48\x5e\x7a\x3e\xce\x7e\x62\x67\x5e\x1a\xb0\x28\x92\x39\xe4\x22\x99\xac\x9d\xb7\x96\x19\xac\x75\x06\x3e\xf1\x72\x4d\x9c\xed\x38\x6c\xe5\xe1\xef\x25\xfb\xa8\x98\xc1\xcb\x6f\x3c\x5c\x8b\xae\xb4\x6d\x75\x14\x1b\xa8\xee\x5b\xdf\x64\xc5\xb9\x1e\x45\x39\xa9\x1a\xae\x70\xc1\x2b\xe3\x02\xf2\x75\x18\xf2\xb2\xcc\xa4\x61\xd0\x3a\x08\x59\xfa\xa9\xe4\x17\xef\xaf\x86\x43\x54\xd3\x36\x8a\xd3\x13\xdd\x45\xc3\xe1\xc0\x43\xe6\x88\x8a\x48\x39\xd0\x62\xde\x6e\xc5\x46\x0b\x05\x96\x24\x3f\xcb\x08\xc3\xa5\x19\x10\x93\xd2\xc4\x6a\x88\x94\x48\xdf\xd5\x24\xf2\x1c\x44\x06\xfd\x0d\x22\xe3\xe7\x2f\x70\x7f\x7b\xc8\xf8\xc7\x91\xd8\xee\x1e\x60\x70\xda\x27\x6c\x77\x22\xea\x3b\x2d\xa6\x98\xed\xdc\xc2\xe1\xa7\xbb\xcd\x67\x97\xc7\x18\x43\xad\x2d\x57\x1f\xfb\x49\xec\xad\x0d\x2d\xbc\xef\xc1\x85\x97\x62\x2f\x51\x9e\x38\x04\x1d\x46\x8b\x97\x0a\x8a\x69\xc4\xbf\xd1\xd1\x77\xd8\xf2\x28\x61\xa0\x56\x7f\x6c\x4a\x36\xbc\xf0\x38\xcd\x3d\x32\x82\x5e\x95\x39\x4b\x4f\xd0\x69\xe1\xb0\xf6\xe0\x60\xde\x71\x9a\x9d\xa2\x57\x3f\x88\x64\x3f\xa1\x7b\x0c\x0c\x60\xb9\xe2\xb5\xb5\x46\x0b\x2a\xbd\xa7\xbf\x26\xda\x34\xe4\x94\x4f\xd2\xfa\xdb\xa6\x11\x82\x7d\x6c\xf7\x68\x8a\x99\x4b\xb7\xb1\xab\xf0\xd1\xa7\xab\xee\xef\x0f\x2b\x9d\x66\x0f\x50\x1b\xdd\x5b\x77\xf9\x6b\x39\xe3\xbe\x53\x3d\xf2\x58\xf5\x47\x8b\xf4\xc9\x8b\xc7\xc7\xa8\x36\x8a\xb9\xfa\x00\xcb\xd9\xff\x7f\x5e\xb1\x35\xc7\xf2\xdc\xbd\x5c\x44\xdd\xeb\xb4\x79\x47\x76\xd9\xb9\x5e\xab\x4d\x95\xc0\xab\xc5\x31\xb7\x6b\x37\x0d\x58\x83\x3e\xbe\xdf\x5c\xfe\xe7\xcd\xeb\xeb\xcb\xd7\xff\xe0\x3b\x36\x8d\x2b\x66\x9f\xbc\xf5\x29\x74\x38\xf4\xa2\xda\x7f\x38\xb6\x45\x62\x95\x0f\xb1\x9a\xdd\x7f\x45\xc7\x80\x1d\x3b\x1d\xcd\x7c\xcc\x41\xb6\x23\x15\xdb\x28\x15\xe7\x50\x0e\xf6\x10\xc6\x55\x97\x79\xe6\xb5\xef\xf9\xa4\xe4\x01\xa1\x53\xaf\xb9\xef\xe2\xfe\x81\xcb\xbb\xbc\x47\x02\x51\x57\xbd\xd7\xe0\xda\x75\xa1\x67\x8b\x26\x0e\x4b\x31\x6a\xc1\x45\xf7\x5a\xef\x3e\x01\x40\x47\x25\xcf\xec\x90\xda\xd8\xab\x68\x03\x45\x37\x57\x5b\xee\x6b\xa6\xcc\xbc\x66\x2a\x00\xe6\xf0\xbb\xee\x99\x0e\x9e\xcf\x93\xef\x3f\x88\xff\x8b\x5e\x94\x1c\xbe\x15\x71\x48\xdd\x5f\x3e\xc0\x01\xbb\x5a\x2c\x0b\xae\xe8\x23\xfe\x6f\x7e\x53\xb0\xb4\x64\x8a\x8c\x7b\x3c\xa6\x19\xf7\x25\x46\xf2\xfb\x79\x99\x55\x5e\x6d\xde\x68\x64\x59\xb1\x14\x6e\x9b\x72\x49\x89\xc3\x24\x2b\xad\xf5\x21\x0a\xe2\xf2\x67\x56\x85\xcb\x5a\xd8\x52\xd2\xc1\x78\xbf\xc7\xa1\xf3\xcb\x2c\x98\x27\xeb\x72\x09\x5f\x70\x45\xd7\xa5\x84\x53\xcd\xfc\x3d\x4e\xe8\x34\xc4\xeb\xd9\x24\xf6\x0c\xbf\x69\x98\xa9\x95\x4a\x30\xa8\x46\x63\x7e\x2b\x58\x9e\x5b\x06\xbb\xb5\xb0\x23\xd9\xef\xf5\x61\x36\xe5\x5f\x4f\x0a\xc1\xdd\x76\xea\x49\x06\x63\x7c\x6b\x55\xe4\x00\x96\xb4\xa3\x9d\x13\x67\xdb\x47\x98\x9d\x29\x6c\x5b\x9c\xf9\x24\x0f\x14\xea\xae\xc7\xb1\xb6\xa0\x81\x98\xbd\x83\x99\xee\x27\xd5\x36\x89\x99\x63\x4a\xc6\x4f\x9f\xe0\xce\xd8\x91\xf1\x33\x20\xb5\x87\x38\xe7\xab\xfb\x6f\x69\x6f\x33\x7a\x1f\xe1\x41\x95\x7d\x12\x7d\x7e\xce\x4a\x90\x06\xf5\xdd\x71\x89\x4e\x7f\xaf\x5b\xdc\xfa\x67\x2a\x2c\xed\x2d\x20\x0a\x7f\x7b\x13\x98\xe6\x1b\xca\x20\x45\xce\x3b\x11\x5e\xe3\x44\x5c\xf8\x58\x25\xfd\x90\xac\x17\x71\xfa\xcb\xfa\x56\x25\x36\x02\xc1\xfb\x8f\xb7\xee\x4d\xaa\xf1\x0e\x7f\x81\x25\xce\x7b\xd7\x9b\x50\xba\x88\x79\x7b\x4c\x99\xe5\xcf\xb0\x19\x7b\xdb\x8f\xf1\x2a\x4f\xb8\x11\x43\x5e\xe3\xcb\xb4\xe2\xc5\xaf\x9c\xdd\x59\xe1\x21\x96\x6b\xa7\x19\x16\xe3\xab\xec\x36\x4e\xf8\x47\x36\x67\x45\x0c\xc0\x32\x66\x74\x84\xe5\x11\xce\x0c\xfb\x82\x7f\xe6\xf3\xac\xe0\xa0\x5b\x63\x46\xb0\xbd\xa8\x78\x0b\xac\x51\xd5\xfc\xdf\x45\x6f\xc6\xa1\xed\x98\xc8\xdb\xf4\x7f\x20\x79\x40\x2b\xf5\x87\xfe\xd4\x62\x15\x57\xb3\xd4\x2b\x44\x32\xf8\x22\x30\x5c\x74\x7a\xf3\xfe\xaf\xed\x72\x78\xe9\x6d\x15\x88\xdd\x42\x62\xb1\x5d\x6a\x80\xb4\x5b\x00\x61\x38\x57\x18\x0c\xdf\x34\x26\xd8\x57\x0d\xb1\xf5\xb9\x41\xb2\xba\x92\x30\x6b\x7f\xf3\x24\xd0\x9a\x2f\x91\xd9\xc4\x2b\x07\x6d\x37\xc0\xc1\xfa\x9b\x27\xc1\xf3\x7c\xe8\x39\x63\xd3\x51\x15\x33\x42\xce\xb3\x74\x1e\x2f\xbc\xfc\xd8\x84\x9f\x80\x88\xc4\x44\x6d\xb7\xd6\x0e\xf4\x1a\x38\x34\xf1\x85\x5e\x28\xf5\x84\x50\x38\x98\xe6\x46\xf0\xb1\x9b\x4e\xaf\x4d\x1f\xab\x82\x55\x7c\xb1\xf1\xee\x44\x9a\xeb\x2c\x93\x27\x42\xdd\xcd\x52\x6e\x02\x00\x9b\x3a\xca\x4b\x1a\x69\xc2\x99\xd6\x6c\xb4\x93\x90\x5f\x9d\xc1\x30\xca\xed\xa6\x19\x67\x9c\x95\xea\xa9\x76\x1a\xf3\xb0\xe5\x5d\xcb\x5d\x4d\xed\x5f\x6e\xba\x6e\xb6\xb2\xce\xf4\x69\xb6\xb3\xf3\x24\xe6\x69\x65\xd7\xd0\x00\x67\x91\xdc\x5b\x7b\xc9\x68\xb8\x7d\xe7\x84\x6d\xd8\xfe\x1e\x71\x8e\x62\xff\x05\x8f\xd8\x21\x80\xe6\x18\x70\x68\x82\xb7\xb0\x5a\xfa\xce\x29\x4b\xc7\x39\x65\x75\xb4\xbc\xe3\xce\x94\x77\xc8\x9e\x68\x13\x4c\x83\xe5\xe2\x92\x8a\x2c\xec\xa8\x9f\x35\xda\xd6\xa5\x1d\xfe\x46\x1a\x7c\x9d\xb7\x7c\x87\x82\x76\xec\xf5\x41\x87\xa2\xb7\xad\x58\xad\x67\xfd\xad\x15\xae\x14\x10\xbf\xda\xc1\x4a\x89\xc3\xc7\x9f\xed\xf0\x8f\xfa\x2a\xf4\xca\x0e\xaf\x8f\x4d\x3e\xfe\xd0\x8d\x31\x1b\xfe\xde\x79\x16\xbc\x30\x43\xcd\xdd\x4a\xcc\x60\x6a\xfa\x53\x54\x56\x96\xc8\xc7\xef\xac\x70\x73\x3b\x12\xed\x7f\xeb\x50\xe0\xfc\x48\x1d\x2e\x0f\x6d\x0e\xef\x8b\x4c\xd2\xd9\x22\x90\x8f\x7f\xd5\x51\xc5\x1d\x2f\x3a\xd3\xe2\xb5\x8a\x6d\x6f\x5d\xc8\xc7\x9f\x54\xd4\x7f\xfc\xbb\x8b\xa4\xff\x26\x63\xd5\xc9\x75\x9d\x24\x1f\xd8\xc2\x74\xff\x68\x70\x3a\xca\xb2\x94\x64\x7b\xc9\xf2\xf4\x4c\x6e\xf2\x14\x04\x0f\xdd\xa9\x4d\x9e\x02\x53\xe4\x9c\xd8\xe4\x29\xf0\x46\x7d\xd3\x9a\x3c\x83\x3c\xdd\x93\x9a\x3c\x03\x1e\xea\x90\x38\xd3\x3d\xa1\xc9\x73\xc8\xf5\xe0\x74\x26\xcf\x9f\xfd\xa1\x43\xc7\x03\x64\x37\x6a\x16\x92\x17\xe3\x83\x12\x1d\x6b\x72\x92\x17\x4f\x70\xdf\x2c\x34\xfd\xdc\x36\x73\x90\xbc\xb0\x0a\x15\x93\x99\xbc\x78\x8e\x3b\x93\x92\xbc\xf8\x11\x77\xa7\x24\x79\xf1\x02\x77\x27\x24\x79\xf1\x12\xf7\x4e\x3a\xf2\x72\xdc\x8e\x84\xb9\x4a\x5e\x1a\xcd\xe9\x59\xc4\xc8\xcb\x27\xed\x34\xd2\x40\xe5\xe5\xb3\xc3\x60\xd9\xd6\x24\x26\xe3\xd1\x63\xdc\x9d\xc3\x64\x3c\x7a\xda\x41\xd0\xd6\x53\x98\x8c\x47\xcf\x0f\xa9\xd3\x39\x27\x30\x19\x3f\x86\x14\xce\xb9\x46\xc6\x8f\xa1\xef\xba\x93\x9b\x8c\x1f\xbf\xc4\x7d\x73\x9b\x8c\x9f\xc8\x3c\x3b\x53\x9b\x8c\x9f\x40\xcf\xf6\xcd\x5d\x32\x7e\x36\x16\xc7\x88\xfb\xcc\x73\x9c\xc7\x08\xb8\xf5\x99\x27\x59\x56\x78\xe3\xd1\xe8\xdf\xb8\xff\xc3\x78\x34\x72\x68\x76\x01\x5a\x20\xa8\x49\xed\x76\x23\xff\x34\x35\x77\x7f\x1b\x41\x2d\xee\x6e\x5a\x62\x2c\x5f\xa7\x2c\xd9\x94\x71\x5b\xc0\xa7\x17\xcd\x75\xd7\x94\x54\xed\xf0\xea\x70\x26\x06\xed\x5d\xf6\x55\x5a\x8e\x7e\x66\x49\x72\x25\x4d\xd9\x04\x4d\x94\x64\x3a\xc3\x52\x90\xfe\xb1\x62\xe1\x17\x32\x1d\xcd\xf0\x67\xb9\x8c\xf1\x48\x1c\x22\xe5\x15\xa4\x71\x0a\x4a\x82\x3a\x1e\x30\x33\x34\xb5\x68\xce\x57\x66\xee\x25\xda\x62\xce\xc7\x49\xd0\x2e\x55\x49\xc6\xe8\x08\xaf\x03\x9e\xb2\xdb\x84\xab\x58\x3a\x18\xed\x25\x24\xa8\x51\x62\x27\xcd\x18\x60\xf8\x7f\x65\x65\x65\x35\xc5\x71\x54\xee\x94\xbc\xc7\x79\x11\xa7\xd5\xe5\xb7\x30\x59\x97\xf1\x9d\x2d\xf6\xe1\x94\xef\x76\xdd\x6f\x4c\x45\xf6\xfa\xc3\x8f\x12\x76\x16\x0c\x2e\xb3\xb4\xcc\x12\x1e\x00\xde\xac\x57\x05\x2b\x96\x7b\x5d\xd7\x67\x5b\x54\x13\xde\x49\x28\x56\xc1\x93\x14\x56\x1b\xc3\x95\xa2\x38\x5d\x61\x74\x93\x55\x2c\x39\x89\x53\x55\xd0\x49\x15\xaf\xf8\x89\xb7\x2a\x7d\x44\x0a\x8f\x07\x75\x84\x8f\x51\x5d\x9b\x13\x18\xc2\x76\x52\xfe\xcd\x95\x54\xf9\x6b\x6e\xa5\x95\xa1\x3e\x46\x57\x4d\x4e\x39\x2f\x6a\x57\x68\xae\x6c\x7f\x10\x75\x5f\xa7\x95\x8f\xd1\xb5\x91\x69\xcf\x67\xb2\x84\xe6\x1b\xbd\xa0\x94\x44\x05\xed\xf7\xbe\xaf\xc6\xe7\x6d\xfa\x9d\xe3\x53\x7f\xf8\x1d\xe3\x03\x6e\x06\x4e\x7e\x3a\x09\x9b\x05\xa2\x33\x38\x6f\xfb\x86\x45\xbc\xf6\xb4\x09\xeb\x0a\x24\xd9\xc2\x53\xc3\x2b\x61\x84\x31\xd4\x19\x42\x6e\xe2\x15\xf7\xb8\x1f\x54\xd9\x9b\xf8\x1b\x8f\xbc\xc7\xfe\x29\x3a\x59\x95\xc8\x07\x5a\x37\x9b\xab\x5a\x76\xc5\x72\x97\x83\xbd\x9e\x5e\xc0\x83\x91\xff\x87\x1a\xfe\x1b\x2b\x2b\x1e\x99\xad\x96\x6d\x76\x36\x59\x8d\xa2\xfc\xe6\x98\x21\xc4\xf6\x18\x81\x56\xba\xbb\xcd\x00\x8d\xf9\x07\x3b\x14\x2a\x77\xf1\xfe\xea\xa1\xc4\x25\xf6\xf3\xe3\xc9\x4a\x7e\xb8\xdd\xd7\xb7\x89\x53\x16\xbc\xbd\xf8\xfc\xfa\xe6\xe6\xfa\xed\xcf\x9f\x6e\x2e\x3f\xbf\x7b\x7d\x75\x39\xa3\x3c\x88\x23\x2c\x5d\x99\x50\xae\x3c\x9a\x04\xac\x58\x94\xb4\x65\x07\xc0\x21\xd4\xc7\xd5\x3f\x80\xa4\x3e\x17\x3c\xcc\x8a\xe8\xb7\x22\x76\xf8\xc8\xd2\x92\xf5\x6e\x67\x4c\x7b\x97\xf2\x47\xe3\x59\xf0\x55\xe4\x56\x4e\xb2\x29\x9f\x51\xf1\x6f\xb7\x9b\xce\xb0\x78\x08\xf2\x75\xb9\xf4\xb6\xa2\x6d\xa4\x92\x08\xda\x29\x16\x8d\x21\x85\xa0\x15\xb5\x51\x74\xae\x00\x54\xbf\x19\xcb\x7a\x0d\x40\x48\xa7\x33\xcc\xe8\x08\xc7\x94\x15\x8b\xb5\x59\x91\x09\x7b\x15\x4f\xd8\xe9\xa9\x5f\xc8\x52\xeb\xf8\x29\x9b\x29\x8f\x4a\x38\xc7\x11\xd8\x7c\x28\xd0\xd4\x77\xfc\xab\xe0\x26\x1a\xbe\x40\x3a\xd4\x41\x0e\x69\x2e\x44\xf9\xbd\xbb\x8b\x6a\x68\xbd\x40\x92\xed\x1e\xd7\xeb\x35\x69\x14\xe7\xb7\x7b\x0c\x53\xa5\x14\x4f\xb2\xdb\xc4\x93\x71\xe3\x05\xef\x95\x1e\x45\x32\xda\x8b\xb3\x75\xe8\x89\x03\x78\x1a\xb0\x3c\x4f\x36\xf2\xd2\xa1\x70\x6d\xaf\x87\x87\xa9\xce\x55\xe4\xf7\x28\xc2\xb9\xec\x0b\x79\x6f\xbb\x62\x0b\xfe\x36\xad\xb2\x77\x59\xc4\x75\x3f\x38\x79\x67\x4a\xa9\xd4\x46\xef\xab\xd6\x5a\x65\xdf\x9b\xb3\x24\xb3\xb9\x54\x82\x7c\x7b\xe1\x15\xd3\xf1\xcc\x9f\x24\x81\x49\x9b\xde\x1c\x57\x78\x8d\x8b\xe9\x48\x41\x7e\x1d\x61\x23\x2e\xf2\x06\xb7\x73\xc1\x3c\x2b\x2e\x59\xb8\x74\xcf\x4a\xe5\xa2\x92\x07\xf3\x22\x5b\x01\x27\x39\x1c\x7a\x55\xf3\x66\xc6\x68\x20\x0a\x31\x41\xb3\x26\xad\x7a\x6e\x42\xcd\x74\xcd\x85\xb2\x4c\xdb\xbc\xdb\xb1\xc6\x37\x2b\xd0\x22\x68\xf2\x97\xef\x54\x74\xcc\xd4\x8a\x9d\xc1\xa8\x9b\xfd\xc4\x6b\x10\x03\xac\x16\x91\x35\xae\xfc\xbd\x4f\x5a\xe9\x44\xbf\x40\x97\xca\x2b\xcb\xfa\x1e\x22\x28\x93\x38\xe4\xf2\x36\xab\xc0\xe3\xc6\x9d\x75\xbe\x17\xd4\xd1\x9c\xd4\x6c\x67\x44\xa2\xda\xbb\x5d\x1b\xb1\x69\x40\x69\x35\x1c\x76\x60\x9a\x54\x70\xbf\x87\xa1\x81\x31\xb9\x5a\xe4\xf4\x7d\x7e\x85\xdb\x99\x48\xcb\xa8\x76\x75\x6b\x82\x21\x1d\x95\x87\x15\x3d\x50\x5d\xf1\x1d\xbe\x73\x66\x87\x37\x62\xf5\x6c\xf8\x6a\xbc\x78\xe8\x6a\x2a\x1a\xbc\x3a\xcb\xbc\x85\xdc\x54\x4b\xbc\xc4\x63\x9f\xdc\x0d\x87\x1b\xb9\xc8\x8c\xfa\x17\x04\x3d\xf3\x56\xbe\xf8\x5c\x56\x1f\x2f\xf1\x5a\x42\xaa\x9e\xc4\x73\xef\x4e\xce\x83\x4b\xba\x09\xf2\x2c\xf7\xfc\xc9\x66\xba\x69\x8a\x3e\xa5\x6b\x2c\xbe\xac\x97\x31\xf1\xf1\xa3\x4b\x1f\x02\xeb\xe5\x0c\x72\x94\x46\x21\xdd\x70\x4d\x3d\x0b\x13\xb9\xb7\x9c\x2e\x67\x8d\x7f\x1c\x7d\x6f\xab\x7c\xa2\x02\xbe\x36\x71\x8e\xe8\x67\x88\x3b\x3b\x10\xd7\xe4\x43\xd0\x2b\x31\x7c\x3f\xa1\x3d\xce\xf7\xd6\x35\x54\xd2\xd1\x30\xd1\x98\x5c\xbd\x07\x2e\xf2\xf2\xe0\x09\xd7\x42\x82\x68\x1d\xb6\xc8\xf8\x05\x68\x8e\x38\x4c\xfc\xed\xd3\x64\x8d\x4f\x4f\x47\xd8\x81\x5c\xb2\xad\x4e\x29\x60\x94\xd4\xab\x76\x63\x84\x67\x2b\x3a\x37\x19\x4d\x67\xce\x9c\x60\xe3\xc4\x19\x64\xd7\xe0\x2f\x66\x6a\xdb\xf6\xf5\xc3\xb4\x70\x2f\x9c\x95\xda\xdc\xe2\x88\x14\x18\xb6\xf2\x64\x2a\x97\x9a\xd9\x6e\xa7\xd6\x1c\xd8\xd3\x25\x9f\xb2\xf7\xf7\xbe\xa3\xaa\xcc\xaa\x2a\xd6\x26\x38\x93\xa2\xa9\x6c\x6d\x55\x93\x81\x03\x6f\xcc\xe8\x1a\xfc\x3e\x19\xf4\x98\x19\xa7\xa0\xda\xb2\x32\x16\xcd\x61\x7e\x45\x33\x9b\xe8\xe2\x99\x76\x0d\x85\x53\x71\x16\x4f\xe1\x28\xbe\xb5\xf8\x5b\x52\x19\xfb\xf4\x08\x37\x1b\xf8\x48\x6f\xd9\x23\xb9\x63\x93\x91\xa8\x89\x0c\x9b\xc6\xb3\xe1\xd0\x13\xd9\xa9\x80\x53\x6a\x44\xf9\x66\x8d\x8d\xa4\x75\x98\x48\x6d\x26\xf0\xcd\x66\x19\x1f\xd4\x61\xe2\x03\x33\x81\xf8\x40\x2e\x0e\x46\x6a\x08\x10\x29\xeb\x18\x5f\xe9\x9a\x4e\xe5\xa8\x57\xd2\x3d\xb8\x5d\x97\x9f\x68\x38\x1c\x2a\xf6\x25\x35\x1d\x1a\x94\xd2\x8b\xb1\xad\xae\x56\xab\xc7\xd5\xdf\x3f\x32\x4e\x85\x7b\x1f\x97\x1d\x15\xe5\x1a\x9c\x07\x17\x62\xc8\x33\x3a\x9a\x64\xcd\x90\x67\x7a\xc8\x19\x38\xe7\xce\x66\x38\x91\x83\x1e\x1b\x83\x1e\x9b\x83\x5e\x01\x2a\x68\xe9\xc5\x7e\x43\x00\xb9\x84\x26\x55\x6a\xf0\x6c\x9a\xcf\x64\xa6\x11\x8d\x6d\x8a\xc8\x67\x93\x94\x46\x12\xd2\xff\x14\x9d\xfc\x74\x82\x4e\xa3\x9a\x46\x8a\x69\x3a\xa3\x05\x20\x82\xb6\x68\x24\x95\xac\xab\x41\x09\x46\x95\xa6\xb9\x18\x82\x02\xa6\x6a\xbc\xe2\xa7\xd4\x8e\x93\x0e\x5a\x61\x44\x9a\x84\x6a\xac\x8c\x18\x65\x91\x35\xd7\x83\x05\xb8\xb0\x85\x5f\x67\x0b\xe3\x34\x97\xe3\x24\x02\xeb\x71\x9a\x1f\x1c\x27\xf1\xe9\x23\x79\x5e\xdb\xfb\x78\x6e\xa9\x4b\x37\x2c\x11\xb6\x3d\x58\x73\xbd\x32\xe0\x42\x0e\x86\x31\xc6\x98\xbb\x66\x60\x26\x6b\x6b\x18\x4a\x0f\xc6\x38\xa6\xa3\x49\xdc\x78\xbb\x8e\xa5\x09\xdb\x88\x52\x9a\x8a\xa9\x19\x0b\x7e\xe6\xfd\xdc\xcb\x7c\x7f\xcb\xe8\x60\x34\xb9\x2d\x38\xfb\xb2\x1f\xb0\xe1\x90\xeb\x7e\xc9\x66\x3f\x8d\x04\x43\x34\xcd\xa4\x43\x84\x7a\x59\x31\xd4\x8f\xdb\x3a\x1f\x21\x1d\x07\x8f\x41\xe2\xd5\x65\x3f\x09\x2a\xb9\x98\x06\x1a\xa6\x07\xbf\x7d\xf7\xf1\xf2\xfa\xe6\xf3\xd5\xeb\xeb\x3f\x7f\xfa\xd0\x89\xbd\x7a\xff\x1f\x97\x9f\x2f\xff\xf3\xed\xc7\x9b\xb7\xef\xfe\x9d\xa0\x55\x76\xc7\x11\xbe\xbe\x84\xe0\x77\xef\x2f\x2e\x09\x92\x2a\xd7\x08\xdf\x5c\xfe\xe7\xcd\xe7\xf3\xf7\xef\x6e\x2e\xdf\xdd\xc8\x6c\x0c\x46\x4f\x83\x2f\xb9\xa0\xa1\x4e\x98\x86\x9c\x3d\x04\x0c\x65\xa6\xea\x83\x85\x3a\x01\xd0\xb6\xb2\x07\x13\xaa\xd5\xb2\xe3\xf0\x9d\x94\x8f\x57\x89\xef\xe6\x90\x81\x11\x86\x1d\x32\x07\x12\x63\xeb\xc8\x4c\x32\x6c\x1e\x4c\x49\x61\x6e\xce\x79\x8f\x8e\x88\xd8\x42\xef\xc3\x37\x69\x5b\x5d\x6b\x47\x92\x2d\xfd\x68\xd3\x95\x64\xad\x3e\xd4\xa6\x9a\xae\xbd\xf5\xf6\x0b\xdf\x90\x81\xd8\x06\xe6\xd2\x6f\x4d\x49\xbb\x8a\x34\x98\x69\x04\x1a\x38\xc5\x4b\x35\x90\x2f\x7c\x43\x95\xff\xf9\x82\xcf\x6b\x4f\xe1\xb0\xea\xd4\x3e\x9d\x1b\xbf\xe1\x8d\xea\x08\x65\xfb\x49\xd9\xb0\xe6\x74\xfb\x39\x2e\x4d\x41\x3e\x38\x53\xd0\x17\xd7\x5a\x21\xd8\xa5\x3f\xc7\xf0\x5a\x4c\xeb\x50\x01\x38\x53\x6d\x4f\xac\x74\x18\xfd\x6d\x62\x1a\x33\x14\x7c\x2e\x21\x76\xe1\x11\x87\x66\xdc\x17\xbe\x91\x71\x08\x9d\xc2\x1b\xcc\x79\x26\xfd\x00\x74\x9c\x00\x30\x7f\x38\xec\xa2\x7f\x8b\x50\x6f\x3d\x65\x33\x5a\x89\xb3\xf8\x5e\xaa\x30\xb5\xcf\xef\x8f\x1e\x8b\x1a\x8e\x29\xa5\xb9\xbf\xae\xd5\x2e\x69\x5a\xf3\xae\xf9\x4f\xe3\x66\x85\x89\xa8\x54\xb9\xcc\x7d\x3c\xa7\xa3\xc9\xfc\x55\x3e\x99\x9f\x9e\xfa\xd1\x74\x3e\x6b\x72\x9e\xce\x4f\x1f\xcf\x26\x46\x66\x91\x38\xd3\x70\xc0\x34\x56\x5c\x1f\x68\xec\x28\xe0\x04\x3b\xb4\x69\xe8\xd2\xaf\x3b\x44\xb4\x42\x37\x66\x09\x8d\x31\x74\x83\x4a\x8f\xe3\x10\x27\x62\x73\xd6\x5b\x4a\xfd\xb4\xf6\x9b\x91\x53\x5a\xb0\xd4\x65\xfa\x68\x8d\xad\x54\x21\x93\x4a\x97\x86\x6e\xba\xa6\x35\xc8\x31\xc9\x52\xfe\x3a\x8d\xd4\x2c\x86\x9a\x53\x17\x14\x9f\xaa\xa0\x64\xd7\xb8\x18\x49\xcc\x61\xb8\xb9\xa2\x4c\xf1\xa0\xdd\x1b\x37\x9a\xf0\x69\x5d\xc8\x21\x7a\x2b\xf0\x9a\x32\xb9\x53\x28\x98\xfa\x90\xca\x32\x12\x2a\x4b\xc9\xa9\x2e\xc7\xa2\x43\xd9\xb1\x03\x45\x85\xc3\xa1\x97\xc8\x27\x9c\xd3\xba\x17\x7d\x6c\xa4\xfa\xc2\x37\xc3\xa1\x17\x52\x4d\x8e\x06\xa0\xb8\x83\x1e\x0b\x27\x3d\x16\x92\x1e\x8b\x19\xb8\xaa\x90\xf4\x18\x1d\xa0\xc7\xc8\x4d\x8f\x91\x49\x8f\x73\x45\x8f\x91\x8f\x97\x74\x34\x59\xbe\x8a\x26\xcb\xd3\x53\x7f\x2e\x4e\x3e\x0d\x3d\x2e\x5b\xf4\x38\x6f\x91\x8f\x1c\x1d\x41\x43\xb9\x39\x1c\x92\x78\x6c\x2f\xcf\xb4\x2b\xcf\x1d\x78\x03\xbe\xdb\x0d\x78\xd0\x5a\x36\x7c\x13\xbe\xb8\xbc\xdf\x5f\xef\x71\xee\x78\xdb\xda\x9f\xf7\x61\x64\xb4\x31\x17\x16\xf5\xf8\x2a\x9d\xe5\x3a\xa0\x39\xd4\x81\x09\xbf\x3a\xd3\xa3\x13\xc0\xf3\x39\xa9\x96\xf5\x4d\xc6\x0a\x30\x19\x4f\xb2\xf9\xc9\xef\xe8\x94\x9f\xa2\xdf\x03\xa4\x3a\x14\x21\xa7\x35\x28\x4c\x7d\x97\xd3\xeb\x78\xee\x35\x9e\xb1\x2d\xbf\xd1\x82\x5a\x1b\xa9\x82\xe5\x2a\x3a\x55\xfe\xa1\x25\x79\x5a\x56\x9c\x9d\x36\xd5\x26\xe0\xc3\xa1\xa8\x4f\xfd\x51\x9b\x5d\xe6\xc1\xe7\xb2\xca\x0a\x50\xb8\x96\x62\x07\x0d\x68\x0e\xf3\x69\xb7\xf3\xba\x29\xe8\x60\x84\xd7\xde\x9f\xc4\xc1\xed\x04\x48\x0b\xce\x43\x1a\xd6\x21\x2b\x4e\xe2\x8a\x17\xac\xca\x8a\x13\xe9\x1d\xf8\x64\xc9\xee\xf8\x09\x3b\x59\xa7\xf1\xdf\xd7\xfc\x04\x7d\xe1\x1b\x04\x50\x0d\xc1\x9f\xc0\x53\x46\xdb\xaa\x4e\x0c\xe5\x57\xed\x9e\x6a\x38\x5c\x7b\x08\x24\x6f\x27\xd2\x0f\x57\x69\xe5\x9a\x66\xe9\xa3\x74\xbd\xe2\x45\x1c\x9e\x08\x66\xf2\xa4\xcc\x4e\xb2\x22\xe2\x45\x9c\x2e\x4e\xe2\xf2\x24\x2f\x78\xc9\x8b\x3b\x1e\x05\xa8\xe5\x15\x6b\x6d\x2b\x80\x33\x4f\x6c\xca\x1d\xc9\x4f\x7a\x96\x12\xe7\x30\xe0\x92\x16\xbb\x5d\x8c\xd7\xf4\x16\x24\xd0\x9e\xf8\xa1\xdb\xbd\xb4\xc9\x5b\xb7\xd7\x80\xd2\xf7\xb7\xeb\x69\x09\x20\x0f\x62\xf0\x87\x43\x2d\x52\x68\x9e\x06\x94\x1a\x44\x8a\x4e\xde\x56\x27\x5f\x59\x79\x92\xb3\xb2\xe4\xd1\x09\x53\x7d\x3d\x2f\xb2\xd5\x09\x3a\xcd\x3c\xfd\x99\x7f\x8a\x02\xb4\x37\xc8\x21\xac\x6d\x7d\x5a\x08\x1a\xbe\x7f\x00\xba\x54\xf5\x03\x1c\xda\x57\x6d\x17\xef\x62\x09\x8b\x25\xcc\xad\x5e\x8e\x3a\x69\xb8\xef\x3b\x69\xa5\x5e\xc0\xb8\x3e\x6d\x9f\x37\x4e\xd0\xc4\x7f\x10\x49\xf2\xb4\x2a\x62\x5e\xd6\x35\x14\x2c\x45\x26\xc5\x84\xdc\x9f\x0c\x3c\x46\xd7\x41\x0a\xee\xeb\xfd\x20\xca\x52\x3e\xf1\x3b\x15\x60\x0a\x06\x43\x54\x55\x3d\x9b\x15\xee\xfa\x71\xd3\x6e\x30\xee\x02\xfe\xad\x2a\x58\x58\xbd\x9d\xbf\x29\xd8\x42\xb5\xa6\x3e\x6d\x24\x3d\xee\x23\x12\x7f\x38\x2c\xbd\x04\x87\xd3\x64\x06\xe8\xad\xcd\x10\x24\x8d\x7b\x95\xba\x41\xfd\xbe\x8c\x98\xf2\x65\x14\x83\xbb\xe9\x6b\x0f\xe9\x7c\x0c\x09\xa4\xd8\xfc\x71\x0c\x1c\x8d\x97\x62\x26\x5d\xaa\x84\xac\x0a\x97\x00\x25\x4f\xb9\x60\x35\xe2\xfa\x3a\x34\x9b\x4b\x7c\x94\xe1\x70\xe0\xc5\xc1\x8a\x97\x25\x5b\x70\x51\x83\x6f\xbe\xbf\xfd\x36\xad\x83\x80\x20\xa5\x07\x18\xab\x01\xb9\xe5\xbb\x5f\xee\x13\xc5\x11\xd3\x03\x8c\xbc\xb5\x1c\xcd\x10\x9a\x75\x1c\xf1\x1b\x6b\x9e\xf9\xbd\xf6\x23\xc1\x4f\xd1\x0e\x9d\x16\xf0\x3f\x83\x29\xf5\xd9\xd5\x6b\x9f\x05\x63\x24\x5a\x30\x1c\xa2\x93\x57\xf0\xc1\xc9\x0f\x3f\xa1\x49\x26\xde\x6f\x96\xfc\x84\x4b\xda\x80\x89\x24\x79\x9d\xe8\xe4\x76\x73\x02\x56\x73\x62\xd6\xd4\x0d\x8e\xac\x93\x2c\x17\x34\x79\x56\x09\x16\x80\x08\x3e\x8c\x0f\x87\xc0\x9f\x9e\x8d\x7f\xe0\x94\x8e\x7f\xa8\x08\x17\xaf\xcd\xe7\x40\xdd\x00\x00\x23\x67\x40\xbd\x03\xe8\x19\x91\x15\xf1\x22\x4e\x59\xf2\x41\x39\xbc\xe2\x86\x2b\x9b\xda\xd5\x55\xea\x77\xe0\x5d\x80\x79\x70\x32\x1a\x91\x27\xd8\x09\x9c\x0a\x9e\x62\xb7\xf3\x72\xaf\x00\x57\x3c\x82\xcf\x80\x30\x13\xfe\x67\xa9\xaa\xa7\x97\x76\x90\x5d\xab\x2a\x5e\x02\xec\x9d\xa5\x26\xfc\x26\x2b\x9a\x59\x0d\x00\x06\xd6\x0a\x58\x49\x34\x33\xe9\x1c\x04\x30\x4b\x86\xc3\xc4\x4b\xb1\x11\xa0\x39\x33\x0c\xa2\xff\xdc\xc7\xb0\xcb\x5e\x18\xfc\xae\x14\x40\xac\x9c\x5a\x80\xa6\x56\xa5\x9e\x91\x2d\x35\xca\xae\x97\xfb\xc6\x3f\x9e\x33\x81\xf4\x94\xaf\x3c\xe5\x39\x4e\x6a\xb6\xca\x65\xdb\x2d\x7f\xad\x7a\x29\x0e\xa0\x6a\x7b\x7b\x93\x36\xca\x97\xa6\x3d\xda\x6d\xf7\x6c\xb7\xf7\xf1\x37\x71\x42\xfa\x4a\x7f\xf8\xaf\xbf\x46\xa7\xff\xfb\x07\xfc\x59\xbc\x5e\xd1\x2d\xe0\xda\xbd\x4e\xa3\xdf\x58\x91\xbe\xc9\x8a\xab\x75\x25\x68\x14\x7a\x88\xcc\xb1\xc5\x9e\xf7\x98\x2e\xad\x5a\x4c\xbc\x21\xa3\xaf\x39\xc1\xda\x9e\x89\xd2\x42\x73\x17\x45\x23\x4e\xa1\x8f\x27\xd9\xab\xce\x05\x67\x76\x7a\xea\x87\xc6\xbd\x66\x36\x33\x8e\x05\x4b\xaf\xf0\x71\xb1\xc7\xd6\x11\xc3\x81\xae\x72\xf5\xc0\x23\x86\xc9\xfb\x77\x1a\xdc\x5c\xcb\xae\xac\x43\x82\xbb\xcd\xf8\xf8\x76\x15\x72\x46\xb4\x1a\x67\x0a\x0e\xae\x0c\x04\x31\x17\x7b\xda\xab\x00\x57\xd3\x2f\x19\x8f\x1a\x15\xba\x36\x7d\x91\xf1\xb8\x89\x74\x93\x2e\x19\x8f\x9f\xf7\x26\x81\xe8\x1f\x71\x87\x40\xc9\xf8\x79\x8f\xcf\x8c\x36\x3f\xfd\x00\x0c\x33\xee\x6f\x13\xe9\x33\xb4\xc5\xf5\x2a\xe9\x91\x88\x6c\x49\xe2\xd5\x89\x61\x00\x51\xb0\xd7\xf5\x62\x00\x77\x95\x79\xaf\x58\xde\x28\x9b\x99\x33\x2d\x11\x93\x28\xd7\xea\xb0\xb6\xf2\xbf\xed\x6a\xa5\x83\x2c\x0c\xe6\x8c\x11\x35\xd1\xe6\x26\x91\x71\x4d\xd9\x01\x30\xa2\x1d\xa3\xc7\xb5\x58\xd2\x34\xd6\xe8\x70\x58\x88\xc5\xdf\xb4\x3b\xc6\xce\xfc\x0c\x4c\xce\x7b\xb3\xcc\x0e\x66\x29\x4f\x25\xb4\xab\x8d\x16\x7a\xb1\x8f\x63\xcf\xdf\x4f\xf4\xc5\xb7\x35\x07\xe5\xa1\x71\x0b\x96\x4e\xf5\x4c\xc3\xb5\x7e\x1d\xc9\x71\x5c\xbe\x5b\x27\x49\xdd\x95\x6f\x2f\x08\xdb\x77\xcd\x0b\x7b\x49\xde\x1c\x37\x32\x1e\xb9\x41\x0e\xc7\xa3\xfb\x70\x78\xe4\x4c\xdf\x2e\xd6\xac\x88\x88\x53\xe0\xcc\xad\x29\x5a\xec\xf1\x16\x32\xbe\x0f\xf1\xc0\x26\xe5\x4c\xfb\xd0\x05\x8d\xce\x52\x82\x88\x28\x74\x7e\x08\x52\xae\x76\x4d\x1b\x41\xdb\x82\x09\xc4\x7c\x5b\x69\xe4\x79\xa3\x10\x9d\xdb\xca\x2e\xcc\xdf\x16\x5e\xa6\x19\x4d\x5d\x94\x8a\xb2\xed\xd8\x98\x81\xf3\xdc\x94\x41\xc0\x42\x7c\x3c\x7a\x98\x73\x65\xb9\x08\xe7\x35\xac\x2b\x4e\x25\x12\x67\xa3\xda\x0a\x06\xf4\x92\xbe\xbc\xca\xc7\x05\xcd\x7b\x5d\x17\xa7\xcd\x65\xbd\xc8\xe3\x4d\x5c\x94\x95\xd6\xd9\xf0\x8a\xb6\x3b\x64\x2d\xa9\x34\x20\xae\xb5\xc4\x32\x85\xd5\x0f\x1a\xa8\x25\x97\xa0\xd9\x55\x65\x45\x49\xa7\xed\xb5\xa3\xb9\x70\x74\x14\xbb\xf4\xb8\x99\x9d\xef\xef\x76\x12\x8c\x43\xb0\x2d\x93\x74\xe2\xf3\x26\x6b\x75\xed\x24\x3a\xa1\xf0\x52\xe3\x3a\x81\x8e\x00\xd5\xaf\x49\xa8\x77\x8a\x57\x4c\x5e\x19\x55\x66\xec\x34\x9b\x29\xdf\x9e\xba\x5f\x2b\x7f\xb7\x43\x68\x72\xa7\x6d\x93\x35\x11\x78\xdc\x6a\x3e\xae\x70\x8c\xed\xea\xee\x5b\x4e\x97\xb9\xb7\x52\x80\x32\xbe\x6f\x7a\x48\x6e\xdb\x42\x1c\x85\x85\xf2\x21\xcb\x12\x1e\xb9\x30\xf1\xba\x66\x12\xb9\x43\xe3\x37\x72\x1a\xc4\xce\xdd\x12\xed\x65\xcd\x1f\x49\x14\x72\x56\x2c\x78\xd5\xd8\xd2\x2c\x78\xf5\x29\xbd\xcd\xd6\x69\xc4\xa3\x8f\x61\x91\x25\xc9\x87\xac\x8c\xa5\xb1\xc5\x64\xee\x65\x26\x9c\x47\xc4\xf5\xd1\xa0\x8b\xbc\x6e\x52\x53\x63\x09\x69\x12\x54\x13\xda\x1e\x4f\x3a\xda\xef\x7d\x1c\x06\x2c\x8a\x44\xd7\xc4\xe9\xe2\x26\xf3\x32\x1c\x06\xd5\xd7\xec\xb5\x62\x07\xa0\xcf\x94\x06\xc7\x1d\xdd\x7e\x96\x1a\xc1\xe0\xaa\xb8\x35\xb8\xf2\xa8\xf2\xdb\xdb\x77\x17\xef\x7f\xfb\xfc\xcb\xeb\x77\x17\xbf\x5e\x12\x03\x3f\xe6\x4c\x0e\xa3\x4c\x55\xf2\xea\x97\xbe\xe5\xc1\xdf\x76\xe8\x86\xf2\x3d\x06\x68\x1c\x59\x76\x2b\xad\xaa\x12\x1d\x0c\xf8\x1e\xc7\x65\x27\x55\xbd\x3c\x36\x69\xf7\xb8\x0d\x3e\xdf\xc3\x4c\xa6\x7a\x86\x17\x67\xa5\x72\x0f\x0d\x0e\x67\xee\xe0\x04\x20\x8e\x9b\xf0\xb5\xc5\xc6\x49\x9c\x3e\x59\x84\xf2\xbc\x7f\x7c\x19\xa1\xfc\xe0\xe8\x42\x56\x59\x1a\x57\x59\x21\x49\x48\xe2\x14\x74\x99\xce\xd8\x66\x33\xeb\x96\xa8\x95\x01\x95\xf0\x35\x92\xde\x5f\xcc\x22\xbb\x70\x29\x4d\x1f\xea\xd3\x70\x06\xe7\x59\x98\x5a\x90\x0a\x0e\xed\x51\x60\x1b\x41\x7b\x0c\x84\x4d\xe2\xc4\x97\x6c\xb6\x59\x50\xf0\x84\xb3\x92\x7b\xa9\x38\x65\xef\xbb\x98\xc6\x2d\x33\x89\x67\xcf\xee\xb3\xa3\x71\x0a\x54\xcd\x09\x4f\x9e\x77\x37\xe4\x63\x4d\x2a\xda\x86\xd2\xad\x49\x4d\xc6\xd2\x14\xe7\xc0\x9c\x26\xe3\x1f\xc7\xb0\x5d\x1d\xe7\x63\xcd\x73\xb1\x82\xed\x43\x94\x64\x62\x5c\xba\xc8\x7c\x8f\xd5\xc6\x7a\x38\xb6\x91\xef\xb8\xd3\x59\x20\x0a\x45\x3f\x97\xd3\xe2\x9d\xc7\xa3\xfb\xec\xc3\xdd\x18\x4b\xcd\xcd\xa1\x83\x9f\x70\x58\x20\xda\x8b\xfc\xbd\x7e\x35\x2c\x76\xd8\x0d\xa6\xda\xf2\x8c\x1f\x1e\x3c\x01\x27\xfd\x56\x8c\x79\xd7\x36\xc4\xdc\x3c\x4c\xfb\xb8\xb9\x73\x53\x59\xd2\x6d\xc3\xb9\xb3\xc6\xd8\x03\x43\xcb\x88\xe1\x56\x11\x9b\x45\x93\xc4\x8e\xd0\x3d\x4b\x0a\x23\xbc\x75\x2e\x28\xcd\x28\xab\xdf\x49\xd6\x8e\x52\x5d\x43\x0c\xf3\x13\xdc\xea\x18\x12\x1a\x71\xa2\xed\x24\x37\x02\x1a\x4b\xdf\xc8\x08\xad\x91\x12\x9a\x30\x07\x7f\xed\xd0\x20\xeb\xf2\x84\xc7\x7b\x6e\xec\x37\x88\xb3\x2d\xe1\x9e\xdf\x6f\xf3\xd6\x22\x2d\xf2\xf2\xe5\x91\x07\x5b\x53\x91\xad\x63\x5d\xf5\xf8\x49\x1f\x64\xe7\x78\xf4\x5d\x96\x53\xcc\xab\x71\xed\xf4\x83\x9a\xc8\x98\x77\x21\x3f\x6a\x23\x3a\x69\x00\xaa\x66\x60\x28\x59\x60\x00\x95\x6c\x26\x5d\x8d\x33\xd9\xcc\xb9\x05\xaf\x5e\x87\xc0\x85\x18\x67\xd9\xed\x92\x95\x75\xa6\xe7\x2c\x67\xb7\x71\x12\xb7\xfc\x5e\x37\xeb\xcf\x70\xe8\x29\x2f\x1e\x94\x52\x0e\x98\x78\xe2\xe8\xaf\x5c\xad\xcb\x40\xc1\x21\xed\x76\x0d\x16\x91\x95\x72\xb7\x43\x55\xb1\xe6\x32\x30\x94\xda\x20\x97\x51\x0c\x86\x03\xd2\xbe\xa3\xae\xcc\xdb\x14\xb4\x08\xe1\xc0\xd7\x85\xe6\xf5\x6a\x44\x20\x68\x29\x07\x19\x3b\xe1\xb8\x46\xc4\x03\x6c\x3e\x02\xd7\x1c\xce\xf6\x79\xdc\x3f\x5b\xdb\xc0\x87\x0a\xcf\x17\x50\x84\x40\x26\x5a\x47\xb9\x40\x79\x3d\x1f\x84\xa4\x46\xf1\x62\xad\x0c\xec\x0a\x4c\xaa\x01\xe0\xb1\x16\xe0\x8b\xda\x3b\x50\x1d\x11\xbf\x06\x34\xc3\xba\x3e\x80\x8f\x19\x7b\xa9\xdf\xea\x99\x6e\x6d\xa4\x4e\xb0\x8e\x97\x90\x91\xe0\x7c\xbc\xa2\x0a\x39\xd3\xa8\x18\x44\x03\x88\xa6\x11\x78\x99\x46\xfb\xe6\x22\xb7\x83\x9d\x39\x1c\xba\xc6\x5d\x33\x1c\xf7\x61\x6d\x4e\x52\xa5\x93\xad\xcf\xf7\xbe\x94\x58\x7b\x75\xf5\x1e\xa5\x3d\xa8\x98\x8f\x14\xd2\x92\x62\x90\x7d\xa8\xb7\x4a\xdd\x86\xc2\x6c\xa7\xdd\xab\xab\x95\x4a\x72\x44\x0a\xe3\xd0\x33\xc4\x7a\xbb\x9d\x2a\x7f\x04\xf9\x8e\xf6\xc0\xd5\xba\x3a\xda\xbc\x6b\xb0\x70\x3e\x45\xd7\xd7\xda\x10\xc5\x70\xe8\x15\x34\xf5\xb1\x73\x30\xda\x63\x40\x53\x6c\x8f\x40\x03\xb3\x59\xe0\x56\x5b\xbe\x73\x6c\xc4\xa1\x51\x0e\xc5\x0d\xff\x56\xe9\xe1\x60\x35\xbe\xaa\x37\x18\xf9\x98\xf5\x23\x92\xb2\x7e\xcc\x51\xd6\x60\x8e\x4a\xd5\xe7\xa0\x34\xfa\x58\x3a\x0b\xec\xa0\xda\x75\xd7\x31\xf2\x12\x76\x00\x6b\x15\x23\x63\xb9\x99\x34\x8b\x18\x19\x3f\x7b\x89\x5d\x6b\x18\x19\x3f\x97\x6c\xdc\x7d\x1e\xc4\x9c\xeb\xef\xfc\x94\x37\x08\xb6\x4f\x9e\x77\x05\x04\x86\x7b\x1d\x56\xbc\xae\xbc\x4a\x50\xee\x7c\xb7\xab\xa0\xaf\xe5\xd8\x38\x05\x89\x08\x46\x63\xb7\xab\xbf\x1c\xc1\x97\xa0\xca\x27\x03\x78\xad\x66\xee\x0f\x28\x9d\x77\x2e\xbe\x55\xd1\x52\xeb\x48\xeb\x06\x72\x7f\x38\xcc\xbc\x0a\x37\x34\x6e\x2b\x30\xea\xfa\x9e\xf1\xa0\x5c\xdf\x96\x55\xe1\x8d\x44\x5a\x56\xca\x3d\xec\xfd\xdc\x9b\xfb\x3e\x31\x95\x01\xd6\xf5\x41\x22\xf2\x18\xe4\xcf\xc0\xbb\x67\xe4\xc9\x7a\xf8\x98\x9b\x96\x3e\x0a\x6d\x11\x17\x75\xf3\x4f\x97\x52\x3f\x93\x16\x93\xf4\x55\x55\x43\xec\x0f\x44\x35\x53\x1f\x6e\x6e\x1b\x31\x7a\x5d\x29\xf3\xa2\x3b\x34\xa7\x57\x3d\x05\x74\xfe\xb8\xaa\xe7\x80\xd6\x96\xd4\x0a\x10\xa8\xb9\x9c\x02\x0b\xa8\xd1\x24\x7e\x45\x53\xad\x58\x29\x86\x30\x56\xfd\x15\xfb\x7e\x41\xe3\xe6\xa2\x57\x0f\x42\xec\x83\x12\x4d\xfd\xe6\x83\xce\xe5\x44\xc9\x35\x9a\xea\x16\x06\x60\x1c\xf3\x4a\xdf\x52\xec\x4d\x6c\xf5\x37\x30\x9f\x43\x08\x57\x60\x32\x84\x70\x24\x11\x2d\xe5\x89\x3d\xa4\xb1\x18\x3e\x7f\x12\x79\xe1\x6e\xa7\xba\xb8\xb9\xc8\xa5\x23\x9c\xd3\xf0\xac\x24\x6b\xc1\x86\x4e\x26\x73\x9a\x7b\x73\x91\x44\x6a\x64\xc1\x9d\xf4\x70\x38\x97\xb4\xc5\xe4\x53\xb5\xdb\x79\x4b\x9a\x7a\x73\x1c\xe2\xc2\xf7\xf1\x60\x4c\x29\x5d\xee\x76\x10\xa7\x1a\x14\x79\xc9\xe9\xe9\xab\x95\x52\xaa\xcd\x7b\x38\x5f\x27\x74\x21\x0a\x10\x5e\xd2\xb9\x1e\x8d\x15\x1d\x8f\x46\xf8\x8e\x6e\xdb\xb0\x30\x17\x8e\xf3\x7d\xe1\xe5\x4e\xf8\x18\x4f\x6c\x69\x46\x44\xc7\x5b\xaa\xa6\xb6\xd3\x0a\xb6\x3e\xa7\x30\xd0\x96\x9f\x2b\x35\xb6\xce\x6c\x93\xd5\xfe\x69\xdc\xdc\x77\xea\xb9\x34\xc7\xe3\x86\x32\x7f\x7a\x34\x36\xe7\x4c\xe5\x93\xda\xbc\xa0\x96\x1d\xdc\xf1\xa2\xe4\x0d\xae\xc4\x01\x18\x31\x49\xd1\x13\x36\x80\x6d\x4e\xd0\x07\x83\x04\x83\x31\x86\x05\x57\xda\xff\x24\x1e\x93\x77\xf0\x78\x30\xc2\x83\xb1\xdf\x14\x72\xf3\x35\xfb\xb0\x64\x65\xd7\x10\x50\x6c\x9a\x89\x87\x10\x96\x45\xca\xef\xb0\x28\x00\x21\x19\x02\x25\x18\x59\xbd\xd6\x22\xa6\x4e\x5e\x9d\x7c\xf6\xf8\xb3\x96\x5e\x9e\x67\xab\x55\x96\xea\x6f\xdf\x5e\x90\x10\xe2\xde\xf1\x6f\xd5\x05\x2f\x43\x9e\x46\x0c\xa4\xee\x6b\x1c\x97\x4d\xaa\xf7\x73\x12\xe3\x8f\x97\x1f\x5e\x5f\xbf\xbe\x79\x7f\x4d\xe6\x0e\x31\x42\x0f\x4f\xed\x10\xbe\x1f\xa7\xec\xba\x95\x0a\xc7\xb6\xfd\x6a\xf0\xb9\x90\x42\x85\x8a\x17\x29\x4b\xb4\x70\x41\xa9\x71\x02\x45\x39\xd9\xdb\x9e\xef\xf6\x78\xc9\x9c\xfc\x70\xad\x86\xd7\xff\x65\xc9\xdb\x22\x9b\xde\xda\x55\xee\xbb\x82\xe3\x5c\x2d\x69\x63\xa2\x64\x03\xd2\x92\x38\x5d\xe8\x7c\xa5\x7c\xaf\x8e\x56\x37\x3b\xed\x04\xce\xa2\xef\xbb\x71\x33\x84\x06\x2c\x4a\x78\xf1\xe4\x31\x08\x0c\xb6\xe7\xbf\x5c\x9e\xff\xf9\xe3\xa7\x2b\xb0\xf0\x05\xe3\x5e\x82\x22\x56\xb1\x47\xd0\xf0\x47\x70\xa3\x5c\xae\x57\x08\xb3\x28\x3a\x57\x2f\x37\x99\x54\xb4\x76\xb0\xda\x85\xc1\xb2\xf1\x40\xe9\x60\x7b\xe8\x27\x84\xd1\x09\x3a\xcd\x82\x6e\x71\xa7\x7f\xa2\xe8\x4f\xa7\xd5\xe9\x9f\xd0\x4f\x7f\x12\x2b\x0d\x4b\xaf\xf9\xba\xe4\x9d\x12\xc4\x78\xfc\x2f\xcd\xd6\x09\xde\x42\x6b\x95\x7b\xae\x5c\x1b\x1d\x50\xc1\xd2\xe7\xac\x28\xf9\x5b\x70\x09\x3d\x1e\xf9\x58\x54\x52\xec\x4d\xd6\x20\x66\x92\xe8\x75\xe7\x90\xf1\x53\xb8\x22\x19\x3f\xcc\xc1\x83\xe9\xd0\xf9\xc0\xf6\xa8\xac\x87\x52\xed\x1b\xa7\x5e\x0c\x0b\x6b\x93\x2b\xfc\xe6\x7e\xbd\xee\x54\x25\x7e\xa6\xb5\xfb\x9f\xb3\x47\x63\x92\x3a\x55\x06\x2f\x4c\x06\x7a\x38\xfc\xa5\xbe\x61\x70\x3a\x6d\x88\x95\x26\x15\xe8\x15\xbd\x76\xb8\x11\x57\xdb\xfe\xeb\x69\x35\x03\xf4\x66\xb1\xc2\xbd\xf3\x06\xa0\xad\xe1\xfb\x58\x84\x53\xae\x58\x4c\xf9\x32\xe9\xda\x52\xc5\xf6\x21\x95\x5b\x63\xd9\x7e\xf7\x7e\x85\xcb\x90\x0e\x52\xbe\x02\x9e\x15\x15\x4e\xe5\x02\xad\x6e\x8b\x5f\x4f\xd3\x19\x70\xea\x66\x1e\xb8\xd2\x95\xb3\x78\xa9\xba\x1a\x9d\xb6\x0a\xd6\x2a\xf1\x5e\x4f\xf9\x0c\x73\x7f\xb7\x83\x27\xfa\x4b\x73\x95\x25\x36\x35\x40\x9b\xe6\xd0\x6c\xf3\x82\x3a\x6c\xfa\xf3\x1a\xee\x5f\xb9\x6f\xde\xba\xea\x0e\xb9\x0c\x3a\xd7\xa2\x5e\xe5\x4b\x6d\x75\x57\xdf\xcb\xfa\x54\x33\x5c\xc9\xfa\x54\xee\xfa\xe8\x61\xf0\x5b\x1c\x8f\xdc\x74\xfd\xed\x3b\xc1\x29\xfa\xb4\x66\x71\x52\x33\x97\xd6\x05\x5d\x25\xf5\x3c\x86\xc3\xf7\x5e\x8a\xb9\xa6\xc4\xc1\x48\xed\xb5\x83\xb1\xa5\xe0\x55\xdf\xd7\xdb\xdd\x11\x35\xdd\x21\x22\xb4\xb7\x8f\x41\x02\x9c\x95\xce\x73\x3c\xf9\xb9\xa3\xff\xf4\xb3\xbc\x7b\x39\x0f\x3a\xbb\xa3\xc7\x71\xe4\x2b\x84\x83\x9f\x75\x87\xaa\xe4\x95\xa5\xa6\xd4\xde\xeb\xbf\x06\xb6\xd5\x2b\xa4\x28\xf0\x07\x7f\x02\x7a\xc7\xf5\x8d\xc9\x60\x84\x7f\x09\x1c\x26\x38\x1e\x03\x35\xbc\xa6\x8c\x55\x1b\x7d\xe0\x2a\xe8\x85\x11\x32\x24\xfd\xe0\xb2\x5d\x81\x90\x2e\x25\x06\xa7\x52\xf1\xc3\x85\x8f\x0f\xe5\xa1\x45\xff\x99\x14\x39\xdd\xb9\xc4\xc0\x9b\x7b\x45\xb3\x96\x6e\x53\xcb\xc6\xc4\x21\x3c\xf7\xf1\xa5\x43\xa8\xae\x6c\x8b\xb3\xd6\x47\x2d\x41\xb1\x0d\x33\xd7\xbd\x2a\xbc\xee\x55\xd1\x30\xb1\xe6\xe4\x6e\xa0\xf7\x9f\x16\xe0\x9c\x92\x11\x7f\x75\xe1\xb0\x15\x2d\xb4\x39\x29\x0b\x84\x4b\xf8\x16\xde\x5c\x23\x3e\xfe\x60\x00\xef\xca\x9b\x91\x06\x61\xae\x25\xc1\xbb\xa8\xc5\x75\x35\xb3\xa4\x7a\xe7\x6d\x5a\x4f\xa7\x06\x6d\x4e\x2a\x54\x56\xb1\xe6\xa5\x4d\xa9\xf7\xbb\x2e\x43\xaf\xd0\xe6\x2c\xe7\xec\x35\xde\x9c\x54\x5c\x96\xb5\xee\x64\xf6\xa5\xa3\x35\x76\x1e\xd4\xcc\x9e\x8f\x7f\xa5\x77\x5d\x50\x0f\xfc\x9a\x6e\xf7\xf8\x93\xf8\xf7\x37\xf1\xef\x0d\x9d\xce\xb0\x9a\x56\xbf\xd0\xed\x67\xad\x0d\x5a\xfe\xbc\x31\x4f\x12\x9f\xb0\xbc\x00\xbb\x92\x77\x69\xad\x1d\xbb\xf2\x04\xab\x2a\xad\xba\x2c\xb8\x0a\x07\x7e\x87\x9a\xc9\xbf\x04\x56\x86\x5e\x8a\x8d\xc3\xca\xe7\x5a\xbf\x42\x77\xb3\xe4\xcc\xa0\x34\x5c\x0c\x87\x75\x82\x73\x96\x24\xb7\x2c\xfc\x62\xa4\x28\xfc\xbd\x8f\x39\xe0\x88\x2c\xe2\xb2\x32\x20\xdf\x5a\xb5\x7e\xe7\x55\xc3\x21\x98\x4f\x54\x20\xa4\xb9\x01\x39\xe9\x4b\xeb\xdd\xf7\xf1\x26\xe0\x69\xb9\x2e\xb8\x71\x7f\xa8\x2a\x0d\x5e\x76\xea\x15\xb6\x29\x4e\x51\x84\xd7\xd8\xa8\x7c\x9a\xa6\x33\xca\x71\x0a\xb5\x72\xe1\x7a\xf4\xdc\x7b\xde\x28\x2c\x5f\xc1\xc4\xfd\x12\x74\x5b\x04\xfa\xd5\xba\x90\xab\xf6\x85\xe2\x0a\x0e\xc0\x22\x3b\x5c\x74\x81\xd8\x55\x41\xef\xbc\x85\x43\x2d\x5b\x71\x92\x9f\xa6\x99\x57\xf9\xb0\xa0\x17\x7a\x79\x2d\xda\x86\xee\x22\xf6\xa3\xc7\x9a\x95\xfe\xe4\x97\xc0\x45\x0c\x5e\x21\xd7\x3f\xdf\x69\xdf\xf0\x4b\xd0\xf6\xde\xf0\x1a\x76\x3c\xc1\xc7\x48\xd5\x09\x50\x36\x29\x69\x2c\x58\x9c\xb8\x94\xa8\x4e\x3c\x52\x74\xea\xc5\xe0\x0c\x7e\x38\x1c\x14\x38\x94\x7d\xe5\xea\x67\x68\xf5\xda\x5d\x83\x06\x3d\x5d\x41\xa7\x87\x3e\x0e\xf7\xb8\x56\x3b\x06\x1b\x26\x91\xe9\x7d\xa3\xb6\x68\x29\x4f\x71\x63\x90\x7e\x51\x3a\x58\x5e\x81\xa5\xab\xbc\xde\xcc\xc1\xc0\xd1\x5d\x40\x2d\x72\x5c\x70\x3d\x08\x3f\x6f\xde\x46\x86\xb6\xcd\x3b\xaf\xf0\xf1\x2f\xc1\x81\xec\xe5\xae\xe8\x0b\xba\x68\xd1\xad\x83\xe1\xcf\x6c\x16\xd3\xab\xe8\xf9\x21\x95\x20\x1f\x57\xbb\x1d\x24\xea\xc8\x24\x3c\xdf\xc7\x7f\x03\x2e\x0d\x57\x5d\x87\x1d\x72\xc8\xad\x0a\xbc\xf3\xb8\x9a\xa5\xbc\x35\x4b\xb9\x31\x4b\x27\x4d\x3d\x71\x4a\x3f\x09\xde\x55\xeb\x0f\xa6\xc3\xa1\xd7\x25\x2e\x5d\x5f\xe0\x7a\x94\x5d\xeb\x89\xf8\x4e\x3f\x8b\x4a\x8a\x93\x7b\xb7\x92\xfa\xd3\xd6\x72\x22\x8e\x04\x5f\x3b\xe5\x88\x0a\xd9\x4b\x0a\x74\x5f\xe7\x7a\xc9\x9f\x54\x20\x15\x04\xbb\x95\x89\x5f\x29\x57\x49\xf0\xea\x19\x51\xfe\x1e\xf7\xb0\x72\x8e\x61\x3b\x30\x48\xd0\x4f\x7f\x6b\xfa\xe9\x24\x35\x32\xd6\x9c\xa6\x23\xcb\x7e\x4e\x92\x1b\x34\x2e\xd2\xd4\x5d\x20\xca\x06\x46\x70\x8f\x3b\xd3\xb6\x2d\x32\x1a\x0f\xac\x71\xad\x39\x47\x5d\x78\xed\x6b\x5c\x8f\x2e\x98\xc5\x98\x32\xa6\x2f\x20\x4d\xb0\x34\xbe\xac\x42\x1a\xd5\x30\x3e\x81\x8f\x1b\x47\xd8\xe2\x8c\x31\x81\x6a\xb8\x16\x98\xaa\x5e\xde\xaa\x89\x18\xc0\xe6\x3b\x5b\x2e\xd5\x69\xbb\xf3\xd2\xe2\x8d\xf2\xa1\x3a\x07\x4d\x30\xe9\x83\x3b\x9d\x8e\x66\x34\x0b\xe6\x20\xef\x11\x83\x8d\xb5\x69\x3a\x1d\x8b\x73\xa4\xd6\x31\x33\x2c\x44\x70\x4c\xd3\x69\x71\x7a\x3a\x9b\xc4\x13\x99\x75\x59\xf7\x52\xec\x4f\xca\xb3\x8a\x52\x5a\x9e\x31\x1a\x93\xf3\xc0\x96\x0c\x79\x25\x06\x6f\x20\x75\x19\xa2\x42\xa9\x54\x78\x8b\x8d\x4a\xf8\x3e\x71\x85\xe2\x98\xc6\x60\x5e\xf3\x31\xbe\x4d\xe2\x74\xb1\x8f\xe7\x1e\x6b\xcc\xd0\x6a\x14\x45\xb6\x37\x5e\xde\x79\x52\xaa\xe5\xb0\x7b\x6f\xaf\x74\xf1\xdc\x3b\x72\x83\x4e\x35\x5b\xae\x4f\x33\xb7\x81\x2d\x5f\x00\x47\x66\xaa\x6a\xb5\xd3\x43\xeb\x00\x7a\xeb\x14\x2e\x64\xda\x5f\xd9\x3d\xe9\xe4\xf6\x94\x05\xd9\xba\x92\xfc\xdb\x24\xb3\xcf\xa6\xae\xcf\x30\xf3\x95\x54\xbb\x00\xb1\xf8\x44\x0b\x3b\x05\x57\x51\x3e\x7a\x3c\xc2\xe5\xe9\xe3\x91\x8f\x63\x67\xf0\xe4\x9d\xf7\x72\x60\xf5\xc3\xbe\x13\x82\xdf\xaa\x59\x67\x2f\x02\xd2\xd8\xfd\xed\x85\xf4\x33\xf6\xf6\x82\x94\x58\x39\x0c\x23\x6b\xfd\xf4\x06\xd0\xa5\x94\x34\x2a\xc4\xf9\xba\x58\xf0\xb7\x17\x24\xdf\x4f\xbe\x69\xec\xcc\x2b\xb0\x6c\x2c\xbd\x5f\x30\x32\x74\x82\xf0\xb6\x8f\xc1\xe9\x45\x34\x73\x52\x83\x13\x99\xcb\xf2\xca\xf4\xcb\x61\xcc\x9c\x7b\x75\x1b\x1e\xa2\x90\xdf\x39\x0b\x91\x97\x2f\x8e\xd1\x6c\x38\xa8\x44\xe5\x52\x79\x76\x1d\x83\xc8\x78\xf4\xf2\x90\x3a\x44\x73\x08\x22\xe3\xc7\x63\xec\x3a\x03\x91\xf1\xe3\x7e\x97\x16\xce\x8b\x3e\xf3\x58\x44\xc6\xcf\xb4\xee\xd6\xa1\xf3\x0f\x19\x4b\x2c\xe5\xfe\xe3\x0f\x19\xff\xf8\xd4\x6d\x59\x60\x1d\x7e\xc8\x58\xe2\x14\x1f\x38\xfb\x90\xb1\xc4\x25\x6e\x6b\x55\x8d\x1f\xa2\xc7\x2d\xa3\x97\x0a\x3b\x48\x63\x94\x11\x8e\x9b\x95\x5d\x8a\x6a\x25\xa2\x50\x60\x21\x71\x60\x03\xf2\x8c\xac\x64\x1e\x95\xff\x68\x8c\x0d\x54\x0d\xf9\x75\x8d\xd4\xa6\x32\xcb\xd4\xcb\xbe\x7d\xb9\xf9\xb0\xda\x58\xc8\x1f\x56\x6d\x64\xaa\xfe\x6a\x54\xee\x3a\x28\xaf\xe5\xc7\xd7\xc0\x80\x19\xf9\xde\xf2\xc5\x86\xe9\x77\x2e\x5a\x8f\xaf\x82\x09\x6a\x72\xb8\x0e\x55\xef\x38\xb4\xea\x50\x7a\xa2\x02\xb5\x5f\xf2\x50\xeb\xf5\xb7\xa0\xfc\xbc\x25\x5e\xf9\x78\xed\xf9\x96\x7d\x70\xf3\x29\x1d\xe1\x55\xa3\x43\x2c\x2f\x1a\xef\xd5\xcf\x33\xd5\xe5\xae\xd6\x49\x15\x43\xa1\xb2\x44\xb0\x91\x6b\xe9\xcd\x59\x02\x10\x53\x7b\x0e\xbe\xb3\x62\xe7\x74\x84\x97\xe2\xac\xbf\x12\xff\xee\xe8\x16\xf0\xcf\xc9\x56\x72\xab\xaa\x6d\x7d\xc7\x8d\xc0\x98\xd3\x3a\xad\x4a\x32\x51\xb8\x74\x8a\x59\xd2\xb1\xb4\x50\x2e\x0c\x25\x18\xa6\x0d\x84\x55\xf8\xe2\x3c\xd9\x16\x7f\xc6\xbe\x66\x60\x8a\x69\x3c\xc3\x6b\xda\x46\xbc\x3b\x8d\x71\x48\xf3\xb6\x70\xaf\xc4\x6b\x59\x11\xdb\xeb\x22\xc3\x99\xa4\xa2\xd0\xc7\xec\xf4\x54\xb3\x68\xd9\x1e\x77\x3c\x0a\xda\xec\xe1\xe9\xa9\x62\x36\x07\x23\x50\xd3\x55\x97\x11\xce\x56\x4e\xa2\x9a\xdf\xd7\xbd\x62\xd8\x08\x1c\xb2\xcf\x94\xf9\x99\x1f\x2b\x07\x36\xe9\xb4\x98\xe1\x42\x75\x6b\x69\xb9\xe9\x14\x3c\x7b\x45\x07\xe3\x5a\x47\x78\xfe\xe8\x11\x9e\x8b\x83\xd6\xd9\xda\xf3\x49\xe9\x49\x1f\x88\x12\xd9\xb0\x6f\x44\x75\xfb\x0a\xdd\x3e\x55\x13\xeb\x2b\x95\x18\x17\xae\xd2\x0a\xb3\xb4\xcf\xf7\x14\x27\x8b\x72\xf7\x1e\xce\x68\x14\xb4\x0a\xd6\x22\x02\xb8\xa1\x70\x53\x56\x86\xb3\xdd\xae\x68\x30\xb9\x46\xb8\x54\x04\x06\xf6\xd2\x19\x68\x1a\xf4\xd9\x4b\xaf\x69\x31\x1c\x16\x53\x36\xc3\x21\xcd\xa6\x6c\x36\x59\x53\x4a\x43\xe5\xb7\xbd\x39\x70\xad\x71\x89\x63\xc1\xe2\xca\xdb\x1d\xf6\xcd\x5b\x9b\xd4\x25\xe2\xac\x00\x5a\xfa\xc4\x5b\x0f\x87\xde\xa1\x2f\x7a\xc7\x7c\x8d\x59\xed\x3f\xbd\x1d\xf9\x5a\xdd\xcf\x87\x98\xe1\x12\xba\xc6\xc7\xe5\xe9\xe9\xbe\x6e\x6f\xe1\x0f\x3a\x53\x89\xf9\xbb\x5d\x36\x1c\x3a\x7a\x61\xb7\xeb\xad\x05\xf4\x0a\x33\xdd\x68\x76\x06\xd5\x72\x4b\x78\xcc\x6c\xe0\xba\x59\x9d\x51\xd4\xaa\xf9\xaa\xc7\xbb\xf7\xea\x66\xef\xbd\x4a\x41\x69\xa4\x8d\x80\x69\xa5\x01\xcd\x7c\xe5\x3d\xab\x93\xa3\xbf\x2d\xba\x9f\x57\x76\x06\x20\x0a\x71\x55\xc8\xdf\xb2\x7b\xca\xf6\xe1\x5a\xb9\x6f\x49\x89\x1d\x5f\xd7\x87\xa0\xee\x50\x1f\xd0\x62\xe8\xac\x88\x15\x8e\xbb\x2b\x22\xc7\x0c\x3e\x9a\x58\x75\xd4\x20\x4f\x46\x17\xc1\xb9\x43\xcc\xe1\x0e\x31\xb4\xe5\xbb\x12\x28\xaa\x99\x1f\xdc\xc7\xad\xcc\x41\x4d\xb3\x4f\xbd\xa0\xbd\x1d\x91\x1f\xc7\xc7\xab\x14\xbb\x37\x42\x32\x1e\x3f\xee\xe3\x81\x81\x13\xbc\xcf\xe8\xcd\xb8\x2a\xff\xc2\x37\x57\x71\x51\xc0\x1d\x47\x46\x0b\x6f\x6b\x63\xae\x01\xbb\x60\x03\xad\x41\x90\x09\xb3\x06\x01\x16\xc4\x9a\xe4\x2b\xba\x57\xcf\x4d\x61\x64\xfc\x62\x04\x55\x7d\x80\x57\x42\x29\x25\x71\xa0\x3d\x70\x0b\x5c\x56\xbe\x4d\xb4\x82\x0d\xd8\x48\xa5\x34\x37\xc5\x3d\x60\xd9\x9d\x0e\x87\x5e\x0e\xc0\x93\x34\x04\xb9\x5d\xfb\x86\x59\xa5\x5e\x7b\x89\x8f\x53\xfe\xf5\x24\x69\xf0\x99\x94\x2b\x39\x97\xae\x1d\x80\x05\x09\x2a\xe9\xb9\x10\x36\x31\x27\x22\xd3\x66\xad\x6d\x21\xb6\xee\x5e\x97\x58\x88\x61\x38\xa7\xdb\x3d\x8e\xe4\xf3\x5c\x5b\xf5\x3a\xbd\xab\x59\x53\x12\xcc\xa5\xfa\x3c\xab\x59\x29\xa3\x26\x65\xdb\x2f\x9a\x95\xae\xf4\x72\x29\xe1\x6a\x3b\x60\xb3\x52\x85\x94\xef\xf7\x78\x09\x50\x75\x7d\xf8\x09\xa4\x50\xcb\x98\xbe\xd3\x68\xce\xd0\x59\x1d\x23\xbb\xef\x4d\x56\x88\xea\x13\x86\xe3\xd2\x6a\x07\x89\x0d\xe3\xdc\xb9\xc3\x50\xc0\x69\x0b\xd4\xd5\xf9\x19\x3f\xc0\x4a\xc5\x1c\xa4\x8c\x6e\xd5\x9d\x02\x1c\xb0\x1d\xaa\x3a\x12\x09\xaa\x21\xe4\x41\x43\xc8\xac\xaa\x58\xb8\xbc\xe6\xf3\x9e\xf8\x88\xab\x78\x7f\x0f\xfa\x2a\xb5\xf0\xb8\xbc\xe6\xf3\x9b\xac\x8b\xd5\xee\x65\x81\x59\x1b\x4f\xec\xa1\x69\x53\x8c\x92\x92\xa8\xf5\xcd\xca\xed\x4d\x91\xad\x8e\xcd\xcf\x05\x59\x52\xf0\x79\x29\xa6\x17\xa5\x4e\x50\xa7\xe1\x30\x6d\x5a\xe3\xb5\x14\x74\xd5\x7a\xe1\x18\x94\x87\x58\x36\x58\x70\xf5\xa9\xb2\x60\xd8\x5a\x4e\x4b\xa4\x2b\x95\xac\xe0\x91\x0e\x28\xb0\x2d\xe4\xe9\x74\xc1\xbd\xc0\xf8\xe9\xde\x20\xc0\xad\xe5\x7e\xc5\x22\x86\x2c\xb0\x4a\x16\xd3\xa3\xdd\x07\xd0\xe4\xfb\x94\x89\x95\xce\x95\x4b\x69\x6a\xfc\x00\x90\xc6\xce\x4e\x20\x16\x39\xa5\xaf\x25\x41\xc7\xd4\x8b\xd8\x8e\xce\x8d\x90\x23\x57\xfa\x07\x20\x90\x71\x03\x8d\xb9\xf2\x0c\x6d\x56\xc1\xde\xd2\x6c\xb7\x5b\x28\x47\xcd\x80\xdc\x22\xc1\x80\xe8\x9d\x60\x69\xb5\x94\xfa\x4c\xac\xc2\x00\xe9\xe3\xa1\x6b\xfe\xf7\x75\x5c\xf0\xe8\x04\x9d\xc6\xa7\xe8\xe4\x77\xc0\xbd\xf9\x1d\x30\x6e\xd2\xac\x3a\x29\x73\x1e\xc6\xf3\x98\x03\x2e\xd7\xef\x00\x75\xf3\x7b\x80\x94\xf5\x85\x5e\xb5\x3d\x5d\x85\xbd\x56\xd0\x6a\x4c\x26\x07\x8d\xe6\x66\x0a\xb2\x73\x59\x9c\x9d\x66\xd4\xdd\x5f\xba\x4d\xac\x79\x9d\x69\x0a\xf7\x8e\x91\xc7\xfc\x01\x00\xfa\xeb\x26\x66\x33\x5c\xd2\xb9\xc7\x9a\x12\x9b\x76\xbe\x4d\x01\x47\xaa\x69\x66\x2a\x9a\x99\xcd\x4f\xc4\xea\x21\xde\x4b\xf1\x5e\xae\xf3\x3c\x11\xad\xad\x32\xdd\x15\xf8\x84\x7f\xcb\xc1\x73\x50\x83\xd4\xe6\x5b\x82\xfd\x5a\x83\xb6\xa3\x58\x75\x7f\x23\x06\x36\xac\x56\x8d\xde\xa4\x5b\x13\xfd\xf3\x5a\xa3\x51\xd6\x44\x73\xf4\xc9\x74\x4d\x47\x93\xf5\x2b\xa6\xef\x13\xd6\x1a\xcb\x2b\xa4\xdc\x63\x78\x2d\xb9\xc7\x78\xee\x85\x1d\x70\x28\xcd\x60\x84\xf7\x77\x4d\xdc\xd7\x35\xa2\x3f\x3c\xd1\x33\x46\xe6\xdc\xd7\x5d\x06\x3d\x12\x53\xae\x90\xeb\x16\x07\xbb\x85\x19\xdd\x72\xb8\x1b\x6a\xa7\x3f\x12\x8a\x2f\x3e\x76\x80\xcb\xbe\x56\x34\x40\xc2\xa2\x29\x4a\xd7\x9d\xb7\xa0\x84\x99\x58\xf9\xa7\xf1\xcc\x37\xca\x51\x52\x7f\x68\xe7\xba\xe3\x48\xe5\x30\x19\x94\x36\x19\x80\x41\x8a\x08\x60\xf7\x77\x40\x96\x42\xdb\xd1\xe9\xfa\x14\x19\x2d\xb7\x5b\xbb\xbe\x9f\x9c\x71\x2c\xa9\xd5\x80\x47\x1b\x50\x1a\x6b\xd9\x8d\x68\xd6\x43\x9a\xa0\x29\x39\x3e\x8a\x92\x65\x81\x16\x29\x4b\x64\x75\xd1\xd7\xed\xd3\xee\xda\xff\x27\x50\x75\x78\x3f\x3d\x8c\x26\xac\x21\x04\x26\xe6\x56\x8d\xa4\xe4\x8d\x30\x9f\xb2\x99\x5f\x7f\x66\x12\xc6\xbe\x59\x12\x8e\x5e\x0b\x1c\x3d\xd6\x3b\xb8\xc9\xbf\xf2\xe0\xfe\x2e\x8b\xfb\xbd\x33\xb6\x35\xe4\x1e\x9f\xae\x61\x2d\x0d\x65\x40\x42\x43\x6b\x54\x93\xda\xf5\xcd\xfe\xfe\x51\x04\x55\xc6\xf2\x6b\x5c\x85\x4b\xaf\x81\xf6\x0b\x59\xc9\x51\xba\x5e\xdd\x8a\x73\x24\xbc\x28\xf0\x3a\xf9\xb2\x4e\x23\x3e\x8f\x53\x1e\x21\xa2\xb5\x24\x27\x10\x71\x9b\x65\x09\x67\x69\x1d\xcc\x65\xb0\xea\x40\xe2\x42\x55\xac\xcf\x69\xfc\x8e\x17\x1b\x2f\x37\xd0\xb6\x28\xdf\xed\x96\x0e\x95\x9c\xba\x4c\x4e\x57\x87\xd1\x07\x2b\xd9\x6f\x62\x9d\xcd\xc1\xbb\x9f\xa1\x82\x59\xe7\xa2\x80\x84\x49\xad\xe7\xe9\x54\xe7\xd4\x9d\xa3\x47\xbd\xdd\x90\x33\x04\x9b\x0b\x22\xd6\x99\xee\x9a\x2f\x2e\xbf\xe5\x67\x75\x0f\xb4\xb5\x3e\x65\xde\x91\xd2\x44\x6e\x50\x16\xa9\x52\x61\x35\xf3\xba\x60\x55\x8d\xaf\x2a\x8e\xff\x68\xd2\x4e\x21\x4b\xd3\x69\x0a\xbe\xe0\xdf\x72\x64\x03\xb1\x2f\x9d\xc0\x51\x2b\x37\x66\xdc\xdd\x01\xcc\x38\x0d\x09\xb7\x71\xbb\xed\x5f\x50\xf4\xea\x15\x4b\xb3\x74\xb3\xca\xd6\xe5\x4f\x3f\x21\x7c\x69\x82\x2d\xd5\xbd\xc0\x1b\x7d\x38\x31\x4a\xdd\xe1\x86\x41\x53\xd7\xda\x77\xd3\xe2\xf0\xac\xcb\xe4\xac\xab\x1c\xb3\x2c\x6d\x2d\xa1\x27\x66\x17\xf4\x6e\x80\xdc\xdf\x7b\x3e\x3e\x3f\xa6\xea\xf9\x3f\xbb\xae\xef\xb2\x88\xdf\x53\xd1\x6b\xba\x05\x2a\x24\x99\xa7\xc8\xd1\xc7\x62\x4e\x8a\x77\x3d\x37\x7d\xd0\x2f\x14\x21\xf3\x66\xb8\xe4\x5c\x17\x81\x6a\xd6\xfb\x58\xd2\xa2\x08\xca\xb4\x52\xa8\x5c\x04\x44\x90\x5a\x0e\x7c\xcc\xd2\x8d\xd3\xb8\x6a\x13\x54\x4b\x56\x5d\xc3\x6b\x09\xf3\xd9\x87\x1a\x42\xad\xde\xcf\x09\xc3\x0a\x5d\x92\x5c\x62\x4d\xc1\x60\xa3\x93\x66\x11\x27\xe7\xaa\xf4\xf7\x73\xb2\xc6\x59\x2a\x62\x4a\xf9\x2b\x48\x90\x84\xb8\x5c\xb2\x9c\x13\xcb\x34\xe4\xfa\x1e\x60\x2d\x37\x96\xdc\x61\xb8\x38\x9b\xaa\xc9\xf8\x99\xbc\x5b\x7d\x00\xdc\x9b\x12\x19\x26\x0a\x9d\xa4\xbc\xc9\x3e\xac\x2b\x3a\x9d\x99\x16\xf4\x36\xd4\x10\xbb\x4f\x9d\x79\xe2\x12\x10\x79\x85\x09\x02\xa4\x74\x42\x3f\xac\x6b\x58\x94\xce\xf1\xd4\x51\x2d\x75\xd9\xd8\x48\x55\x09\xc7\xe2\xd8\xf7\x67\xbe\x21\x15\x3c\x49\xcc\x98\x14\x7c\x07\x36\x79\x5b\x4e\x3d\xf5\xd2\xcb\xe9\x68\xc2\x5f\xb9\x4a\x51\xfc\x00\xd7\xbc\x76\x45\x1d\xa9\xa6\x7c\x36\x61\x81\x51\x88\x57\x05\xa6\xc4\x3a\x50\x15\x53\x4f\x50\x31\x5f\x9a\xc7\xf3\xaa\x83\x7c\xe4\xac\x01\x1d\xed\xf1\x01\xb4\x24\xc8\xc9\xf3\xf7\x7b\x1f\x67\x36\xea\x51\x61\x6a\x5f\x14\x07\xc4\x48\x7d\x90\x32\x3d\x2a\x19\x82\xb6\x1e\x3f\xc0\xfe\xa6\xae\x68\x9c\xc6\x55\xcc\x92\xf8\xbf\x2d\x7f\xfc\xbe\x76\x6b\x90\x46\xbc\xb8\xc9\x3e\x56\xac\x8a\x43\xa9\x52\x41\x07\x63\x1d\xa9\x15\x56\xae\x39\x8b\x36\x16\x3e\x8f\x54\xb7\x95\x1e\x0f\x9a\x71\x00\x3d\x0a\x89\xb5\xa7\xb5\xfb\x4d\x5a\xd6\x6a\xc8\x5a\xe5\x9c\xb9\x48\x3c\xbe\x57\x63\xbf\xb4\xd4\xe4\xf3\x75\x65\xa2\x4b\x58\xce\x74\x5b\x35\x6b\x80\x58\x6c\x97\xe4\x89\x5b\xac\x0a\xf8\x87\xba\xf3\x48\x19\xf4\xa0\x3c\xe0\x30\xc9\x4a\x11\xdf\x46\x5f\xd8\xe3\xc8\xca\xa1\x73\x41\x14\x07\x35\xc8\x54\xa3\x58\x1b\x07\x0d\x40\x95\x37\x18\x83\x92\xb6\x2c\xc1\xba\x2d\x31\x53\x01\x71\xcf\xfb\xca\x72\x8d\x65\x4d\xc0\xed\xac\x7b\x92\xa7\x59\x15\xcf\x37\xaf\x93\x44\xd0\x3c\x5e\x1e\x2c\xaa\x4d\x0f\xf7\x95\xd5\x49\x6f\xae\x1e\x50\xde\x8a\x4e\x97\x38\xc7\x11\x9e\xc3\x9d\xfc\x82\x57\xc6\xf8\x29\x01\xb2\xcb\x79\xf0\xaa\x51\xea\x6a\xda\xe2\x48\xe7\x6a\x32\x7c\xda\x26\xa0\xbe\x6f\xdb\x4d\xe8\x5b\x3b\x1a\xb8\x2a\x57\x91\xbe\x7b\xda\x81\x54\x68\x6d\x7f\xd9\x2e\xb0\x6f\x2a\xca\x0b\xa7\x49\x62\xed\x00\x61\x00\x5a\x0d\xf8\xce\xc7\xec\xfe\xc5\xcb\x9e\xb4\xe4\xe9\xb3\x07\x83\x64\xdd\xa7\x64\xd6\x9a\xc3\x64\x3c\x6a\xf4\xb6\x3a\x53\x98\x8c\xc7\xa0\x3f\x65\xfb\x24\x7f\xfa\x04\xd6\xc7\x07\xe8\x35\x89\xc1\xa8\x65\xdb\xa5\x44\xb8\x75\xf9\xa7\xeb\xc2\xd9\x5c\xf3\x39\xac\x5d\x87\xad\x80\xb6\xf6\x75\x63\xfb\xba\x32\x6b\x70\x2e\x5a\xf7\x92\x32\xb6\x11\x13\x76\x29\xd8\xf3\xb5\x5d\x87\x44\xa6\x66\x5d\xe5\xeb\x96\xf4\xb8\x96\x9e\x97\x1e\x07\x7f\x14\x76\x13\x31\xef\x2a\x64\x83\xa8\x3f\xe4\x16\x20\x53\xab\x0d\x4c\x8b\xe7\x3a\x39\x82\x5e\x82\x38\x12\x4b\x9f\x07\xb4\x86\x2e\xd7\x47\xe4\x2c\xb0\xd5\xd6\xe6\xa5\x17\xe3\xca\x9f\x94\xc3\x61\xab\xb6\xb1\x0f\xee\x4d\xec\x9a\x78\xb2\x78\x5c\x0e\x87\x47\x74\xd0\x7e\x8f\x95\x81\x99\x2c\xee\xed\xfc\x1d\x0f\x79\x59\x32\x0b\x57\x59\xda\x38\xf7\x25\x84\x6b\x07\xbf\x8b\x25\x7a\xbf\xe2\xa3\x20\x17\x32\x7e\xfc\x18\x08\xf4\x21\x18\xa3\x2a\xda\x71\x89\x79\xc6\xbd\xca\x75\x51\xe2\x13\x98\xcf\xed\xab\x1e\xaf\xc2\xdc\x02\xae\xc8\xee\xc9\x1c\x36\x77\xc2\x82\xbe\xbb\x1e\x9d\xe1\x5d\xe3\x07\x1f\x9a\xaa\xcd\xe6\x62\xba\xdd\x4f\x62\x63\x7a\x39\x1d\xd9\x80\x7f\x18\xe5\xc4\x55\x42\x0d\x61\x8e\x6b\x42\xd9\xe3\xb8\x43\x23\xad\x6c\x6a\x74\x8e\xda\xcb\x83\x76\x4d\xb3\xdb\x41\xe6\x10\x52\xf0\xb9\xc8\xab\x21\xaa\x63\x2a\x93\xb5\x2b\xd3\x0c\x7c\x6c\x0c\xbc\xd2\x8b\x1d\x8f\x81\xf5\x7f\x7c\x1c\x24\x9f\xba\xe7\x39\x77\xe0\x4b\xb4\xa6\xad\x0b\x82\x02\xae\x46\xb3\x2e\x8c\x45\xa3\xb2\xd7\xdc\x28\x15\xae\x4b\xa2\xc7\xf7\x5d\x56\xda\xb7\x2b\xb9\xc7\xfa\x0c\x9f\x2a\x43\xf3\x2b\x76\xd9\xb0\xd4\x77\x2c\x16\x4b\x28\x78\x9a\xaa\x36\xf9\x6c\x31\x45\x05\x4d\x0c\x63\xae\xa2\xbd\x38\xa6\xb8\xc2\xa1\xe1\xda\xd0\x61\x88\xef\x65\xfe\x5e\x66\x50\xeb\x64\x19\x9b\xa7\x89\x0b\x9b\xfd\x93\xda\x37\xea\x69\x9f\x96\xbc\xe9\x06\xba\x1b\x77\xb8\xf2\xed\x29\xd7\x88\x69\xe2\x83\xa6\xa5\xe5\x21\x03\x52\x93\x67\xfe\xc8\x8b\x3b\x5e\x48\xab\x0e\xc1\x14\x58\x8c\x72\xe8\xb2\x06\x4d\xee\xb7\xe7\xcc\x3b\x77\xdf\x06\x61\x6e\x9b\x43\x08\x48\x10\x0a\xec\x3a\x95\x90\x6c\x7f\x24\x38\xb6\x1b\x8b\xf3\x80\xb6\xf8\x81\x26\x93\xf1\xe3\x67\x7d\x8a\xde\x0f\xd5\xe0\x86\xc9\xf7\x30\xb8\xbd\xef\x3e\xc2\x71\x37\x2b\xc9\x8e\x3c\xc1\xc5\x7d\x27\x38\xa7\x34\xa2\x7d\xac\x8b\x0f\x1f\xc1\x4a\xd7\x11\xac\xd7\x07\xa4\x53\x80\x98\xfc\x91\xb3\x4e\xb8\x6f\x9d\xec\x1e\x7a\x80\x09\xc5\xc1\x6e\x9a\xe3\x64\x26\x0e\x5d\x47\x9f\x46\xa2\x7f\xb5\xd3\x08\xfb\xee\xd3\x48\xfc\x87\x4e\x23\x6b\xeb\x34\x52\xaa\xd3\xc8\xfc\x28\x51\xca\x1f\x3f\x8d\x1c\x7d\xa2\xe8\x97\xf1\x3d\x7e\x18\x68\x1b\x1f\x50\xca\x82\x5e\xa0\x9b\xe1\x30\xd4\xec\xaa\x64\x75\x2c\x8d\x30\x05\xe8\x96\xab\x6b\x8f\xb8\xf6\x63\xa5\x2c\xaa\xd7\x0a\x58\xa3\x3e\x30\x9c\xa5\xd4\x2a\xae\x0b\x9c\x23\x91\x35\x52\x52\xdf\xa6\x99\x1b\xca\xaf\xf1\x9c\x9f\x6f\xc2\xa4\x3d\x91\x5b\xc8\x08\xdf\xe9\x63\xa2\x85\x2e\xd0\x2b\x78\xe9\xa8\x4a\x45\x5d\xd7\x2f\x2d\xdb\xf6\x16\x2b\x9f\x3b\x9d\x3d\xe9\x5e\xcb\xd4\xa5\xca\x20\xdd\xed\x5a\xfd\xd5\x1e\x1e\xeb\x52\x3a\x0d\x3e\xe7\x3c\x8d\xe2\x74\xa1\x8b\x2d\xcf\x1c\x61\xda\xd0\x85\x38\xe2\xe8\xb4\x9a\xe1\xc2\x4b\xfd\x3d\xee\xb1\xce\x3f\xae\x25\xe2\x1c\xd7\xa9\x8b\x23\xac\xae\x8b\x23\x4e\xd5\x85\x37\x75\x79\x93\x15\xa1\x22\x43\xb7\x81\x33\x46\xf3\x26\x09\x92\x6e\x9c\xab\x3a\x67\xe3\x73\x3a\x18\xe1\xc2\xab\xfc\x26\x6f\xe5\xda\x52\x6c\x54\x6d\xd5\xd9\x7a\x54\xb0\xf6\x55\x0b\xa9\x90\x3f\x49\xc1\xf6\x52\xe7\x0f\xa1\x72\x31\x11\x55\x6f\x22\xcc\xbc\x65\xc9\xa9\x51\xf2\x47\x5e\xdd\x53\x6a\xa9\x52\x20\x79\xc5\xe8\x6f\x9d\x85\xee\x76\x3d\x75\x99\xf9\xbe\xee\x67\x39\xb6\x66\xd1\xca\xe7\xd0\x81\xa2\x21\x45\x5d\x74\x2e\x0a\x69\x10\x58\x7c\x65\x8c\xd9\x94\xac\x26\xdc\x6e\x97\xb6\x0f\xde\x38\xa6\x89\xb7\xdd\x63\xa6\x9c\x44\x55\xfe\xa4\xf3\x19\x75\x3b\x1b\xf5\x98\x38\x6b\xdb\x95\x37\xe3\xef\x1d\xb1\x7f\x58\x23\x1e\x52\xe5\x4e\x7f\xb7\xb0\x30\xba\x20\x66\xad\x9c\x2b\x49\xff\xd6\xd9\x3e\xba\xd7\xb5\xe6\x43\xcc\x22\x7b\x2d\x18\x9b\xa5\x96\x8c\x47\x2f\x7a\x2d\x0f\xef\xf5\x30\x34\x7e\x7c\x9f\xee\x9e\x25\xf7\xba\xf3\x0e\x80\xea\x0c\x87\xe7\xd6\xe6\x73\x1c\x0f\x1a\xc5\x85\x61\xdc\x59\xfe\x2a\xaf\x50\x1a\x7f\x11\xa1\xb9\x6b\x4b\x3f\x29\x9a\xbb\xd4\x5c\x46\xb7\x2a\xc7\xe2\x07\xb5\x6c\xf3\x00\x39\x08\x9c\xc2\xf8\xf8\xbc\x8d\xf5\xd1\xc4\xf7\xe1\x96\x6a\x85\xfd\xf7\x45\xc4\x8b\x47\x95\xf9\xe6\x74\xba\xce\xdd\x8d\x9f\xdc\x79\x15\xa5\x74\x53\x83\x9c\x6d\xa4\x7b\xf7\xb8\xd1\x3f\x90\xae\x22\x2b\xd3\x47\xe4\x66\x9a\xce\xe0\xd8\xdb\x59\xa9\x01\x5b\xc4\xb1\x80\x4b\x95\xee\x7e\xb1\x55\x21\xa5\x67\x9d\x0e\xf4\x71\xe6\xdb\xba\x38\x99\xa9\x8b\xc3\xed\x21\xab\xc5\x69\xd9\x94\xcd\xb0\xd3\xef\xa0\x79\xb0\x5e\x2b\x05\x7c\x31\x04\x83\xf3\x20\x2e\x7f\x16\xa3\x10\xa7\x0b\x35\x0c\xbe\x89\x43\xd8\x19\xa3\x35\xe6\xfe\x64\x23\x97\x53\xee\x80\x5b\xf5\x5c\x39\xe2\x45\x5d\x47\x40\xbf\xb9\xa4\x03\x69\x4f\x98\xb8\xcf\x28\xb9\xeb\x3c\x13\x1d\x05\x05\x25\x21\x96\x6c\xbc\x7d\xcb\x88\x70\xe9\x3a\xe0\xac\xdc\xac\xce\x5d\x97\xd5\xd9\x74\x58\x9d\xe9\xcc\xc7\x8b\xd6\xb4\xb9\xa4\x83\x31\x3e\x97\xe3\x7f\x7d\xf0\x38\xe3\x9e\x9c\x9a\x32\xfb\x6e\x65\x9c\x5f\x0d\x1a\x8a\x3e\xf3\x36\x41\x99\x27\x71\xc8\xbd\xd1\x81\x45\xc0\xc7\x5f\x3d\xdf\x27\x1b\xc3\x51\x0c\xbe\x3d\x58\x5d\x9b\xf0\xee\xb9\x3b\xb2\x13\xdb\xb7\x54\xdf\xe8\xf4\x1a\xdf\xce\x26\x2b\xcb\x07\xce\x52\x1d\x37\x8e\x3f\xb7\x7d\x3b\x78\x13\x7c\x60\xe9\x4b\xec\x53\x92\x55\x57\xdf\xb5\x30\x4a\x13\x9a\x23\x10\xcf\x7a\xd7\xcc\x43\xcb\xa9\xb4\x25\x53\x2b\x45\x9f\x46\xba\xea\x1e\xbd\xa0\x48\x84\x9f\xe6\x72\xc4\x95\xb1\x4e\xdb\x9f\x42\x59\x2b\xee\xf7\x3e\xce\x5b\x3e\x82\x24\x5f\xf0\x95\xb6\x94\x04\x26\x9a\x60\x76\xbb\x4b\x89\x35\x52\xaf\xa4\xea\xee\x34\xb3\x20\xe4\x6a\xc1\xbd\x57\x2a\x08\x39\x71\x9a\xd4\xdd\xc5\xfd\x7d\x3c\xf7\x2e\xfd\xad\x98\x34\xca\xdc\x67\x31\x69\xcf\xa8\xca\xa4\x1f\x73\xf0\xfc\xfd\x7e\x3f\xf9\x4a\x23\x8d\xe9\xe0\x21\x6b\x9f\xc6\x68\x9e\xac\xcb\xe5\xcf\xd6\x2a\x86\xf0\x57\xd9\xb4\xcf\x5a\xde\xeb\x1a\x50\x9b\xc5\xf6\xf8\x41\xbc\xbb\xc6\xc4\x46\x2f\x7e\x1f\xab\x82\x55\x7c\xb1\xe9\x66\x73\xe7\x36\x7e\xb2\x57\x5a\x48\xa6\x35\x7f\x8c\x54\x8e\xd5\xf5\x1c\xc4\xce\x57\x74\xdb\x5b\x3b\x29\x7b\xb6\x0b\x20\x0c\x5b\x07\x5b\xb2\xc6\x8e\xae\x22\x5f\x0d\x91\xf5\x67\xcc\x4a\x96\x93\xd0\xe1\x21\xf2\x8f\x1f\xfd\x7b\xd9\xb6\xa3\xf0\x22\x5c\xf2\x81\x23\x78\xb3\xe3\x70\x70\x9d\x1e\x6c\x0c\x5f\x2b\xc1\xd5\xa7\x8f\x37\x9f\x3f\x7d\xbc\x6c\x80\xea\x30\xa3\x5b\x95\x3c\xe6\x25\xd9\x86\x49\x9c\x7f\x60\xd5\x92\x64\x38\xfc\x26\xfe\x6d\x48\x86\x23\xf1\x27\xde\x22\xf1\x36\x8f\x93\x44\xfd\xbc\xcf\x59\x18\x57\x10\x98\xa5\xd5\x1b\xb6\x8a\x13\xfd\xf2\x51\x2c\xcb\x19\x9e\x8b\xcf\xe6\x22\x70\x51\xb0\x28\xe6\xa9\x5c\x2f\x61\xf5\x68\xc2\x3e\xa5\x71\x55\x92\x0c\x60\x05\x78\x71\x99\x46\xf5\xf3\x55\xdc\x3c\x03\x48\x3f\xc9\x70\x06\x38\xfb\xe2\xa1\x2e\x3e\x67\x95\x60\xd5\x95\x49\xa8\xce\x4e\x85\xd6\xaf\x59\x9c\xca\x07\xe5\x76\xfc\x75\x99\x8b\x39\xc5\xaa\x38\x23\x19\x2e\xc4\x9f\xa8\x6e\x21\x72\x2c\xf3\x82\xb3\x48\x1a\xe5\x88\xd7\x2a\xcb\xcf\xb3\x24\x2b\xd4\x73\xd3\xf2\xb2\x2a\xb2\x2f\xbc\x7e\xb8\x60\xe5\x52\x69\xc8\xa9\x90\x5f\xe3\x94\x87\x2c\xaf\xdf\xdb\x9f\xfe\x16\x47\xd0\xdf\x15\xff\x56\xbd\x4e\xc3\x25\x94\x51\x19\xbd\x74\xc7\x8b\x52\x90\x75\x86\xef\x62\xfe\xf5\xe7\x4c\xd4\xf1\xdb\x58\xfc\x7b\x2c\xfe\x91\x0c\x6f\xc4\xdb\x46\xbc\x6d\x48\xb6\xc7\x17\xef\xaf\x6a\x40\x1c\x50\x37\x33\xc6\x15\x89\xa7\x47\x39\xab\x96\xc8\x1a\x42\x24\x5e\x1e\xa9\x1e\x45\xe6\x78\x22\xf1\xfc\x68\x0e\x2f\xa8\x19\x5b\x19\x5c\xc6\xff\xcd\x91\x63\x6c\x51\x27\x08\xb5\x46\x1b\x59\xaf\xc8\x18\x7b\x24\x1f\x1f\xf1\x34\x42\x06\x19\xe8\xe0\x55\x5c\x07\x4b\x8a\xd0\x11\xe0\x9a\x02\x39\x69\x01\x39\x02\x91\x4d\x1f\xc8\x7c\x43\x4e\x1a\x41\x8e\x40\x64\x53\x0a\x32\xdf\x90\x41\x36\x48\x3c\x3e\x0a\xc5\x33\xb2\x28\x48\x46\xd4\x1d\xdf\xa6\x22\x24\x03\x1e\x45\x3a\x04\xb5\xc8\x4a\x27\x48\xe4\x3b\x6a\x51\x99\x8e\x6e\x15\x20\x89\x4e\x47\x7e\x15\x6f\xc8\xa4\x40\xf0\x69\xf3\x88\xc1\x0b\xaa\xe9\x0e\xa9\x07\xe4\xf2\x88\xd9\x82\x07\x82\x75\xeb\x61\x6e\x6b\x7b\x1c\xb9\x0c\x87\xe5\x21\x4f\x36\xea\x20\xf0\x10\x5f\x2f\xf1\x5c\x39\x9b\xb3\xd4\xb1\xf4\x69\xcc\x11\xd5\x78\xdc\x91\x5d\x02\xe8\x28\x55\xd0\xbc\x60\xf9\x28\x5d\x80\xd4\x31\xf2\x15\xd7\xae\x3c\x48\x15\xd4\xcf\x32\xb4\xfe\xc0\x78\xdb\xef\x9d\xae\x4e\x8e\x76\x38\xa3\x6a\x6a\x79\x9d\x21\x1d\x2f\x34\x58\x1a\xd4\x05\xe2\x07\x57\x59\x4e\xd2\x00\x9c\xc5\x01\x4f\x95\xe3\x84\xcf\x2b\x23\xe8\x57\x3e\xaf\xf6\xed\x6b\xcf\x78\xee\x2d\xb4\x72\xc6\x6a\xb7\x5b\x0d\x28\x0d\x3d\xbf\x63\x80\x53\xd1\xc2\x5b\x49\x49\xe9\x66\xb7\x1b\x44\xde\x06\x9c\x3a\x6c\x68\x65\x8a\x9f\x15\x0b\xb5\x54\xcd\xc2\x77\x86\x0b\xea\x54\xba\xa0\x56\xc4\x81\x70\x1a\x54\xe0\xeb\x8e\xae\x70\x1c\xb0\x30\x5c\xaf\xd6\x09\xab\x6a\xcf\x01\x17\xca\x69\x20\x78\x16\xc2\xa9\x75\xe1\x09\x0a\x44\xe7\x99\xbc\x76\x33\x54\x05\xa5\xef\xae\x22\xcb\xd9\x82\x55\x59\xd1\xbe\xee\xec\x53\x11\xfc\xb8\x49\xab\x25\xaf\xe2\x10\xbe\x6f\x64\xd4\x0e\x7f\x53\xfa\x8a\x13\xcc\x87\x21\xbf\x26\x2e\xaf\x6d\x22\xdf\x1b\xde\xd9\xca\x25\x4b\x92\xec\xeb\xe5\xdf\xd7\x2c\x01\x5c\x19\x66\x79\xd8\x2c\xf1\x92\x6e\x65\x97\x90\x6d\x2e\x1a\x1e\x5d\x03\xc0\x64\xd1\x28\x1a\x93\xed\xad\x74\x2b\x49\x72\x6f\x9b\xa5\xb2\x05\xca\x8c\x12\x2b\xef\x8e\x56\x9c\x72\x11\xa9\xb1\x7a\x70\xc4\x73\x9e\x46\x3c\x0d\x05\x7b\x30\x9d\x8b\x0a\xfc\x9c\xac\x0b\x0c\x4f\xca\x2c\xf3\x8a\xa7\x6b\x19\xf0\x46\x50\xb1\x7c\xfc\x33\xdf\x5c\x64\x5f\x53\xf9\x72\x95\xad\x4b\xde\x7a\xfd\x94\xcb\x97\x66\x5e\x2f\x05\x01\xcf\x40\x57\x0f\x18\xc1\x3b\xf9\xa3\xee\x8b\x16\xe2\xb0\x7a\x49\xb7\x1c\x7c\x1d\x8a\xf6\x93\x25\xb6\x3c\xf6\x3a\x20\x70\x95\xe1\x89\xb2\x38\x39\x69\x2a\x49\xbc\x44\x3a\x86\xd5\x2e\xb9\xaa\x8e\x4b\xae\xe1\xd0\x5b\xd1\x4a\xd4\x42\x55\xc1\x9f\x48\x87\x22\x4d\x56\xa2\x2b\x88\xab\xb6\x9d\x94\x75\x0f\x90\x05\x1d\x8c\x3a\xd1\x46\x4f\x92\xd6\x47\x9f\x72\x65\x38\x72\x02\x3d\x90\x79\x85\x6f\x7c\xd8\xea\x3d\xe3\x63\x35\x00\x76\x48\x93\x99\xc8\xc7\xb6\x00\xbe\x34\x9c\x5d\x36\x33\x84\x3c\x7b\x8a\x5d\xf3\x83\x3c\x7b\x79\x9f\xf2\x5d\x6b\x72\x90\xf1\x93\x67\xbd\x7e\x8c\xb0\x7b\x6a\x90\xf1\x8f\x20\xd4\x94\x33\x83\x8c\x5f\x8c\x71\x7b\x62\x90\xf1\x4b\x50\x6c\x7e\x72\x9c\xc7\x6a\x00\x8d\xc9\xb3\xaf\xde\x63\xfc\xec\x89\xdf\xab\x05\xd3\x3d\xc2\xc3\x87\x21\x8f\x13\x0f\x9e\x0a\x96\x46\xd9\xca\xf3\xff\xad\xe8\xda\x92\x43\x75\xee\xd3\x23\x34\x78\xf6\xce\xa2\xd4\x75\x3c\xf9\xa9\x8a\x13\xe3\xba\xdc\xb1\x5c\xc5\xad\x15\xe9\x3c\x89\xf3\xdb\x8c\x15\x91\x5e\x9a\xca\x9e\x25\xab\xbd\x94\xc1\xfc\x68\xad\x67\x75\xe4\x9f\xf9\xc6\xca\x34\x69\xc5\x03\xc9\xea\xc8\xbc\x15\x79\x51\xb0\x85\x8e\x8b\x5a\x71\x37\xd9\x5a\xb9\x79\x6d\xdc\x50\xd6\x91\x9f\xde\xea\x98\x65\x2b\xe6\xb7\x25\xe7\x89\x8e\x5c\xd9\x5e\x8e\xcf\x97\xac\x38\x97\xb8\xe2\x4e\x11\x99\xb5\xe6\x2e\x3a\x12\xb3\xc2\x5e\x6d\x7d\xb1\xf8\xdc\x8a\x09\x7f\xff\x62\xbb\x11\x0b\x2a\x2c\x0e\x83\x91\xb9\xd0\xd6\xe1\x7a\x99\x15\xd1\xfb\x3d\x0e\x93\x38\xfc\x72\x6c\xbe\xe7\x90\xd8\x91\x31\x44\xb4\x73\x36\x16\x96\x63\xf3\x37\x3e\x71\x95\xd2\x44\x77\xca\xca\x37\xc7\x17\x92\x6f\xdc\xb9\xe7\x9b\x76\xb6\xeb\x63\xf6\x37\xf9\xf5\xba\x72\x66\xba\xae\x5a\x79\x46\xd9\xfa\x36\xe1\xe7\x0f\xe9\xf6\x0b\xe3\x13\x47\x19\x46\x74\xbb\xac\x82\x2d\x8e\x2e\x44\xa4\x75\xe5\x5e\xb0\x85\x23\x5b\x71\x5c\x7a\x40\xce\x22\x79\x4f\xe6\x97\x69\xe4\xcc\xbf\xe2\x47\xd3\xfb\x45\xfd\x41\x6f\x19\x15\x6f\x53\x3e\x94\xf2\x2d\x3e\x7a\x84\x2f\x74\xfa\xbe\x32\xbe\xc5\x9d\xb1\x2e\xd8\x42\x3a\xad\x7a\x40\x19\xf2\x83\x9e\x42\x20\xd2\x51\xca\xfb\xbb\x87\xf5\x16\xa4\xef\x29\x43\xc4\x39\x8a\x90\x47\xde\x07\x94\x21\x3f\xe8\x29\x04\x22\x3b\xa5\x64\xf9\xf1\x05\x64\xb9\x3b\xef\x2c\x6f\x65\x0b\x07\x9c\x63\xf3\x95\x2c\x9a\x23\x63\x88\x68\xe5\x1c\x0b\x86\xe1\xd8\x9c\x81\xbb\x70\xe5\x0c\x11\xad\x9c\xbf\x28\x16\xea\xc8\xbc\x35\xc7\xe5\xc8\x5d\x45\x75\xf3\xff\x50\xf0\xf2\xe8\x6e\xf9\xb3\x4e\xef\x2e\x01\xe2\xba\x45\x7c\x3a\x7a\x38\x25\x83\xe8\xce\xfc\x53\x7b\x40\x93\x8c\x1d\xbd\xf8\xfc\x2a\xd2\x3a\xf2\x15\xe1\xad\x6c\x79\x51\x64\x47\x4f\x22\xb0\x79\x75\x65\x0c\x11\xad\x9c\x57\x35\x0b\x7e\x64\xee\x0d\xcf\xee\x28\xa1\x8e\x74\x95\x72\x95\x1d\xbf\xda\x5c\xd5\x1f\xf4\x95\x22\x22\x5d\xa5\xbc\x3f\x9e\xec\xaf\x74\xfa\xbe\x32\xde\x77\x88\x5f\x16\xf1\x80\x15\xed\xaa\xfe\xa0\xb7\x90\xee\x9a\xb6\x52\x47\x9c\x87\x94\xe1\xa6\x51\x15\xd5\xca\x3f\x67\x65\x75\xf4\x50\x7c\x80\xc4\x8e\xbc\x21\xa2\x95\xb3\x34\x04\x3d\x32\xe7\x6b\x48\xec\xc8\x19\x22\x5a\x39\x4b\x77\x2d\xc7\x66\x2d\x9d\xa5\xb8\xf2\x96\x31\xed\xcc\xd7\xb7\xab\xe3\xb7\xdb\x8f\x32\xb5\x2b\x73\x88\x69\x65\x5e\x09\x26\xfe\x9c\xa5\x21\x3f\xba\xfa\x37\xc6\x27\x8e\x62\x8c\x68\x57\x59\x0f\x60\x80\x6e\x74\xfa\xbe\x52\xba\x2c\x10\x14\xf1\x90\xb9\x7c\x53\x7f\xd0\x57\x88\x63\x2e\x43\x29\x0f\xda\xd7\x6f\x9a\x2f\xfa\xca\x71\xed\xec\x5f\xc5\x59\xe9\xd8\x32\xe0\x60\xe5\xca\x1e\x22\xec\x9c\xf7\xf8\x9c\x6e\xb5\x38\xe4\x32\x10\x87\x24\x5c\x65\xb9\xe4\x95\x2f\x03\x38\xdd\xe0\x96\x94\xe3\x32\x30\x8e\x26\x32\x32\xdf\x40\x68\xbe\x81\xd7\x75\x25\xde\xd6\x20\x9c\x34\x79\xef\xcb\xc0\x60\xde\x21\x52\xf0\xcc\x97\x81\xe0\x8e\xf4\xab\x18\x66\x19\x72\x99\x46\x4d\xa0\xe0\x4d\x75\x70\xc5\x8b\x3a\x42\xf0\x93\x2a\xfc\x5b\x5c\xe9\x60\xc9\x02\xca\x70\x78\xd6\x11\xb0\xc6\xc9\x70\xf1\xa8\x83\xe5\x80\xc8\x70\x29\x7b\x86\x88\x2c\x87\xb0\x2c\x17\xaf\x72\xc3\xba\x0c\x60\x97\xc3\xb5\x30\xea\x52\xca\x7f\x45\x80\x64\x50\x2e\x03\xe0\x6a\xb0\x21\xc7\xb9\x0c\x14\x3b\xa2\x02\x25\x27\x00\xa1\xf0\x88\x6b\x09\x0f\x84\x7d\x82\xf2\x60\xe3\xbd\x0c\xc4\x5e\x8d\x2d\x29\xd4\x65\x50\x6f\x87\x75\x04\x10\xae\x8a\x10\xcf\x75\xc4\x7b\xa8\x91\xde\x73\x9a\x60\xd9\x0f\xf5\x46\x81\x0d\x91\x95\x0a\x96\xb5\x90\xeb\xea\x65\x00\x8b\xb1\x08\x90\xcb\xe1\xa5\xd4\xcc\x10\x01\x6a\x11\xbb\x54\xae\xaa\x20\x48\x2e\x3d\x97\x81\x5c\xb1\x44\x90\xb9\x56\x5c\x06\xc6\x62\x53\x47\xca\x81\xd7\x4b\x43\x1d\xac\x5a\x56\xcf\xe7\x3a\x42\x8f\x59\x33\x07\x45\x94\xa4\xfd\xcb\x00\x26\xcc\xbe\x56\xb6\xba\x3e\x89\xd3\x93\x73\xff\x7c\x7a\x3d\x0b\x4c\xb9\x28\x9d\x5e\xcf\x40\x9c\x73\x6b\x49\x27\x2f\x31\xff\xc6\xc3\x75\x55\xcb\xa3\x7b\x20\x9b\xb3\xa0\x95\x4e\xe3\x7d\x83\x33\xe3\x62\x38\xf4\x78\x50\x8a\x5e\x54\xe2\x1e\xa9\x33\xc7\x83\xbc\x80\xc2\x2e\x24\xba\x0c\xb8\x15\xbe\x4f\x1c\x2a\xad\x30\xce\xb5\xe3\xc0\xac\x23\xab\xdf\x4c\x5a\x12\xd3\x45\x50\xd3\x64\xf3\x0e\x54\xd5\xbc\x4a\xa2\x6e\xde\xe5\xe8\x36\xef\x6a\x24\x37\xb4\x34\xe5\x9e\x8b\xc0\xa4\x63\xe5\xde\x7a\x65\xb8\xe8\x84\x4a\x59\x49\x1b\x79\xe6\xa2\x91\x67\x6e\x68\xd8\xc9\x16\x16\xa2\xe6\x55\x4e\xb2\x0d\x5d\x77\x12\xca\x25\x25\x9e\x7b\x8f\x45\x57\x07\xb7\xeb\xaa\xca\xd2\x9e\x0a\x74\x64\xb4\x10\x6a\x2e\x4d\x4d\x68\x33\xd1\x5a\x61\x40\x89\xad\xb0\xf7\x56\xe7\x36\x53\xab\x15\x06\x6d\x4d\x3a\x4d\x80\xe5\xcf\x7e\x15\xb3\xa0\x1d\x52\x59\x19\xd6\xcb\x9e\x1d\x24\x97\x3c\x3b\xac\x55\x95\x66\xa5\x33\xc3\x32\x51\xb7\xbc\x53\x37\x73\xc2\xb6\x42\xed\x3a\x36\xb3\xb4\x15\x26\x8b\xda\xd0\xa8\x93\xb7\x5a\x32\x36\x74\xde\x89\x92\xf3\x77\x43\x97\xdd\xf1\x16\x9b\x8c\xf1\x6a\xf5\xbc\x5c\xa6\x36\x34\xde\xdf\x79\x1b\xa9\x79\x73\x49\x37\xc6\xe5\x54\x06\xb3\x48\xdf\x4a\xb1\xc3\x57\x4f\x97\x3e\xbe\xb4\x24\xc3\xb7\xf7\xcb\xd7\x0d\x51\x2f\x79\xf6\xe2\x90\xdc\xbd\x4f\xcc\x4b\xc6\x4f\x1e\x63\xb7\xcc\x95\x8c\x9f\x3c\x3d\x20\x96\x77\xc9\x7f\xc9\xf8\xc9\x73\xdc\x2f\xfe\x25\xe3\x27\x2f\x70\x8f\xf4\x97\x8c\x9f\xd8\x15\x35\x04\xbc\x64\xfc\x74\x84\x5d\xf2\x5d\x32\x7e\x3a\xc6\x3d\xe2\x5d\x32\x7e\xfa\x18\xbb\xa4\xbb\x64\xfc\xfc\xb1\x5b\x8f\xc6\xbe\x35\x68\x6b\xd5\x3c\x79\xb8\x21\x75\x66\xe8\xb2\x29\x7d\x34\xc3\xb0\xad\x23\x59\x67\x14\x14\x2f\xa0\xc7\x2e\x58\xc5\x1c\xe0\xbc\xc8\x4a\x00\xf7\xdd\x67\x3c\xb0\xbf\x52\x17\xd2\x56\xe0\x7e\x3f\xc9\x02\xb6\x06\xc0\x21\x50\x52\xf2\x0a\xcc\x1c\xb6\x4e\x8e\xc1\x86\xb6\x3f\x04\x08\xfb\x7b\xdb\x1e\x89\xca\x4b\x07\xdb\x7f\xa8\xae\x0f\x31\x36\x7e\x50\x5d\xad\xcb\x0a\x55\x61\xa9\xb0\xc2\x8b\xef\xaa\x78\x8b\xfe\xa1\xf6\x0f\x87\x10\x56\x3a\xa1\x72\x25\x39\xcf\xd2\x79\xbc\xd0\xc6\x98\x3a\xf4\x0a\x54\x5e\x68\x25\x43\x53\x06\xd7\x69\xa2\x5c\x9a\x4e\x0c\x47\x10\xb5\x53\xc2\xac\x08\xc0\x9a\x61\xce\x42\x5e\xf3\x33\x59\xbf\x87\x90\xac\x06\x09\x2d\xa6\xd9\x0c\x5c\x64\x4c\xb3\x19\x65\x67\xcc\x4b\x7d\x92\x4e\xb3\x99\xc2\x12\x57\xd6\xee\x81\xc2\xb8\xfb\x20\x79\x12\x1e\x9d\x75\x83\x08\xf0\x33\x69\x20\x09\x1f\x00\x95\xa4\xef\x8d\xb8\xbc\x68\x25\xa5\xe5\x59\x6c\xe2\x7b\xdd\x14\x6b\x4e\xac\x90\x37\x2c\x29\x55\x9f\xc4\xa5\xc1\x19\x7d\xac\xb2\x3c\xe7\x11\xed\x26\xde\xff\xaf\xfb\x6c\x50\xdb\x7a\xd5\xb1\xdb\x70\xb4\xb4\x6f\x99\x6e\x40\x15\x01\xee\xd1\xb6\xe0\x2b\x47\x9a\x2c\x40\x28\x29\xb5\xf3\x79\x99\xca\x6e\xc3\x3b\x50\x32\x85\x05\x5e\xec\x1d\x4a\xfb\x11\x0e\x61\xa5\x02\x3f\x86\xad\x93\xdd\x26\x3a\xd7\x78\xc5\x3f\x56\x6c\x95\xbb\x5d\xf8\xd7\xd1\xbb\xdd\x05\xab\x78\x90\x66\x5f\x3d\xb8\xc3\x6f\x0d\x84\xb4\xbf\x14\xbd\x5a\xea\xd7\xfd\x84\xd9\x08\x5f\x36\x77\xd9\x55\x59\x6e\x8f\xd8\x60\x34\x31\x3c\x56\x18\x14\x39\x69\x73\xaa\x67\x5d\xd6\x95\x70\x93\x2a\x6a\xf0\x28\x07\x61\x74\xc8\x62\x8f\x5b\xbc\x71\x8f\x0f\x0d\xbb\x46\xad\x6f\xce\x1c\x1c\x36\xe1\x81\xec\xfe\x9f\x61\x44\xe8\x60\x74\x2c\xb9\xc9\x6a\xe5\xbc\x28\xe3\xb2\xdb\x73\x71\xf9\x41\xc6\x88\xd9\xea\xf8\xce\x8c\x77\xd1\xbc\x5b\x8f\xdc\x68\xe9\xe1\x49\xaf\x10\x2b\x61\x46\x57\x33\xa9\xac\xe0\x5a\x70\x1a\xc3\x9b\xd6\x9a\xd3\x44\x58\xcb\x0e\x98\xe5\xfa\xd8\x28\x92\xae\x71\x61\xad\x9e\x6e\xd0\x0c\xb1\x46\x17\x54\xcd\x3d\x79\x17\xef\xa5\x0d\x25\xfa\x82\x30\xa5\x0f\x04\x15\x60\xbe\x50\x2b\xca\x6c\x3a\xe5\x98\x1b\x75\x61\xde\x76\x8f\xd3\x26\x00\x83\xf1\xa3\x55\xbb\xd4\x7a\x6d\x1b\x12\x73\x9c\x05\xd5\xb2\xe0\xfc\x75\xb1\x00\xfd\x2b\x58\x42\x0a\x7f\xdf\xb1\x38\xee\x49\xf8\xfd\x90\x6e\x5d\x03\x62\xdc\x5d\x7f\xc8\xf8\xb9\xdc\x2d\x1f\x62\x57\xfc\xa0\xdd\xb2\xb9\x84\x67\x74\x5b\x70\xc1\xf6\x46\x6a\x59\xfb\x9e\xbd\xd2\xe4\xf9\xa0\xe2\x0f\x30\x40\xfb\x1f\x67\x49\x1e\x82\x2e\xff\xdd\x9d\xdc\xa7\xcc\x10\xdb\x31\x7f\xe6\x9b\xee\xae\x74\x95\x45\xf1\x3c\x06\x15\xd9\x8a\xcb\xcd\xe9\x0b\xdf\x90\x18\x27\x0a\x87\x52\x6d\x30\x55\x91\xfc\x99\x6f\xe4\x4b\xb9\x8c\xe7\x55\xfd\xc6\x92\xe6\x79\xc5\x2b\x56\xbf\x14\x3c\xe7\x4c\xa1\xf3\x8b\xdc\xf4\xe6\xb4\xe0\x76\xa9\x62\xf3\x53\x95\x76\x31\xbe\x5f\xf8\x26\x17\x47\x7f\x04\x2e\x1b\xc4\xf4\x3d\x63\x1e\xf7\xc9\x08\x2e\xad\x0e\x7c\x15\x65\x5f\xd3\xe6\xa3\xdd\x4e\x84\xad\x73\x23\x1b\x1e\xe8\x0c\x46\x7b\xfc\x75\x19\x5b\x92\x97\x7b\xcb\x7f\x70\x11\x0e\x52\x5a\x1f\x4b\xf8\x07\x0f\x34\xe6\x00\x93\xf1\xf3\x27\xb8\x77\x7c\xc9\xf8\xb9\x3c\xd2\x3c\x44\xe1\xf6\x8f\xd1\xe5\x7f\xc4\xfc\xab\x68\xdf\x15\x17\x59\x97\x5d\xb2\x6c\x53\x60\x49\xb7\x65\x58\x70\x9e\xfe\xa7\xa2\x36\x78\xf9\x8b\xa2\xc3\x24\xe6\x69\xf5\x9f\xe6\xcb\x5f\xbe\x9f\x42\x3b\x94\x18\x63\x29\xd9\x71\x98\xa3\x73\x25\xf4\x51\xa7\x7a\x04\xf4\x22\xcf\x61\x15\x79\x4c\x29\xad\xce\x1e\x93\xa7\xf0\x3b\x16\xf4\x24\x53\x97\x7a\x2a\x98\xab\xa0\x93\x27\xb3\x92\xec\x76\x1e\x0f\xe6\x45\xb6\xd2\x96\xc3\x82\xa0\xca\x22\x54\xaf\x67\x3c\xa8\x32\xad\xb1\x6b\x25\xf4\xf7\x38\x67\x0b\xfe\x9f\x2e\x42\x86\x08\x7d\x72\x94\xa9\xe0\x04\x29\x3a\xf4\xb4\x06\x25\x90\xe2\x12\xd0\xe3\x85\xac\xfe\xd2\x97\xd5\x5f\xcc\xac\xfe\x52\x67\xf5\x97\x76\x56\x37\x59\xee\x22\xfd\xf2\x21\xa4\xdf\x26\x22\x32\x7e\xfa\xf4\x7e\x2a\x7f\xfa\x00\x08\xd3\x7f\xd0\xea\xdb\x26\xe6\x98\x6e\x41\x64\xac\x19\x75\xc9\xee\xdf\x98\x41\x21\x28\x64\x46\x56\x58\x2f\xc5\x1e\xa0\xf2\x0e\x31\x33\x47\xaf\xc7\xdf\xb3\xe0\xf4\xf4\xee\xc3\x1d\xbb\x3e\x78\x1f\x76\x1f\xa0\x62\xba\xbd\x8b\xf9\xd7\xb6\xa3\x72\x1e\x88\xd0\x06\xc7\x5d\xbc\x29\xc5\x72\xa6\x20\x38\xe4\x29\x14\x7c\x8c\x4b\x61\x09\x00\x9c\xd7\x3e\xc4\x35\x3c\x1b\x00\xb1\x5d\x28\xfd\x79\x03\xec\x44\x9f\x66\x04\x39\xee\x76\x5a\x55\xfe\x37\xc8\x49\x49\x5f\xc4\x29\xaa\x62\x71\xe2\x9e\xe4\x32\x6e\xb7\x73\x6e\x06\x07\xc7\xa6\xa3\x1a\xeb\xe2\xe9\x9e\xfe\xd3\x24\x55\x1d\x09\x08\x4f\x2a\xe6\x5c\x65\x64\x8c\x5e\x1b\x54\x3a\x04\x37\x24\x17\x46\xd4\x23\x1e\x18\x61\x04\x10\x90\x93\x8a\x39\x57\x1b\x19\x63\x65\xf9\x17\x33\xcb\xbf\x38\xb2\xb4\x12\x38\xe2\xeb\x12\xff\xaf\x9c\x3d\xf0\x7c\xa5\x9d\xd9\xfe\x03\xe4\x39\x4f\x8f\x03\xe8\x73\xf9\xe9\xea\x01\x40\xe8\x9c\x10\xab\xae\x49\xb1\x3c\xd9\xb9\xcd\x8d\x35\xfe\xc1\x57\xf9\xfe\x36\x8d\xab\x0b\x56\xb1\x33\x57\x60\x6d\x42\x4d\x5c\xb1\x74\x3a\x53\xf8\xa5\x71\xf9\x36\x35\xcd\x46\x07\xe3\x3d\x6e\x07\x92\xc1\x18\xf7\x18\x40\x2b\x01\x83\x9d\xbc\xa3\x52\x3d\x18\x38\x0b\xeb\xb3\x2f\xc6\x19\x66\x38\xc6\x25\x5e\xfb\xdb\xc2\x1b\xa8\xc3\xb4\xf5\xa9\xa7\x50\xf7\x42\x9c\x18\x1e\x57\x3b\x8d\x19\xe1\xb0\x39\xce\xd7\x43\xf2\x3a\x49\xbc\x11\x68\x34\xab\xb9\x63\x15\x29\x3e\x69\x3c\xb4\x8a\xcc\xc1\x41\x46\x5d\x0a\xd8\x96\xcb\x2c\xf6\x21\x53\x57\x68\x7b\x9e\x94\xfc\xa4\x13\x5f\xe7\xd2\xd7\xd7\xfb\xda\xc1\x06\xb6\xea\x67\xfb\xcf\xd5\x27\x7a\xda\x47\x35\x38\xa5\x7c\x92\xbe\xaa\x11\xd1\x0d\x94\x08\x70\x97\x54\x57\xbe\x45\x07\xd3\x74\x46\x59\xf0\xfe\xe7\x8f\x97\xd7\xff\x71\x79\xf1\xf9\xf2\xfa\xfa\xfd\xb5\x93\xc6\x44\xc2\xc2\xe8\xc2\x33\xf3\xa5\x59\x81\x94\x77\x2b\xdd\x6c\xed\x70\xd6\x91\x19\xed\x94\xdb\xf4\xb0\x3d\x52\xe9\xe9\xd8\xec\xe8\xfd\x5e\x99\xf7\xb7\x7b\x49\x79\x23\x75\x10\xca\x1f\xe8\xbf\x0c\xc7\xd2\x89\x8b\x9a\x98\xdd\x96\x40\xdf\x66\x82\xca\xca\x41\xb7\x51\xc3\x61\x2c\x09\xa2\x7e\x30\x96\xeb\x52\x2c\x16\x06\xad\xc5\x73\x2f\x73\xd0\x59\xa7\x03\x0e\xce\xf7\xfd\x5e\x2c\xef\xd2\x13\x75\x86\xed\xda\x90\xad\xcb\x9e\xaf\x0b\x3c\xf8\xf4\x38\x17\x85\xdb\x0e\xc7\x49\x46\xb8\xcd\x3a\x92\x11\x2e\xf8\xbc\xe0\xe5\x52\x06\x81\xe0\xcf\xf6\xf3\x58\x74\x59\x57\xca\x83\x6f\xb8\xe8\xf0\xa1\x94\x07\x9b\xbd\xcb\x21\xdd\xd3\x87\x09\xdf\xa5\xc7\x37\xcd\x4d\xf8\xca\xeb\x1b\x6f\x33\x12\x6d\xcf\x2c\xb8\x68\x05\x55\x8d\xe5\xda\x70\x58\x9c\x79\x1c\x80\x48\x02\x96\xe7\xc9\x46\x42\x8b\x70\x9f\xa4\x3a\xdc\x93\xef\xc5\xd9\x94\xcf\x82\x30\x4b\x43\x56\x79\x95\x4f\xa6\x1c\x57\x96\x17\x07\x37\xf2\x65\xd1\x3b\x5a\x0f\x03\x98\x6b\x66\xc3\x18\xa7\x74\x84\x0b\x3a\x9a\x14\x8d\x73\xa5\xe2\xf4\xd4\xaf\xa8\x57\x9d\xf2\x40\x1f\xea\x5f\x57\x5e\xe1\xfb\xff\x27\xc3\x29\xf5\xd2\xd3\xca\xff\x3f\x59\x8d\x65\xba\x4b\x5f\xbd\x1a\x3f\x57\x95\x7f\xfe\xec\xd9\xe3\xb1\x6b\x70\x1c\x02\x1f\xbb\x4e\xc6\x21\x0a\x00\x9b\xbc\x0c\xf7\xa0\xf7\x56\xd9\x27\x41\xf6\xe7\xac\xe4\x9e\xbf\xd7\xbc\xce\x0f\x8f\xbc\xc0\xff\x61\xe1\x2a\xfb\x61\xee\x01\x6b\x9b\xa9\xa6\x2a\x0c\xa3\x55\xf9\x08\xf9\x16\x5f\x15\xb2\x15\x17\x0b\x14\x30\x53\x3f\xfc\xd7\xa3\x55\xf9\xe8\x87\xee\x58\xd5\xa9\xc8\xf8\xe9\x8f\x50\x1b\xc7\xb1\xbd\x4d\x99\xa6\x2f\xcf\x41\xe5\x0f\x87\x1e\x17\x4c\xee\x6e\x37\xc8\x3c\xb0\x55\xcb\xbc\xca\x3f\x83\xc4\x41\xe3\xc2\x1f\xa4\xd8\x59\x5a\xb1\x38\x2d\xcf\x9a\x47\x41\x5f\x83\x81\x78\x5f\x89\xb4\x9a\x25\xfe\x90\x95\x71\x05\x00\x4e\x83\x81\x37\x7e\x3e\xec\x4d\xe0\x55\xbe\x6f\xb7\x5c\xda\x6e\xbd\x03\x01\x95\x83\x3a\x9b\x58\x32\xfe\x11\xf8\xa8\x67\x8e\x43\x9c\xab\xd3\x07\x03\x3e\x1c\x1a\x8e\x8b\x34\xc2\x84\xe9\xb1\xb4\x09\xf5\x87\x43\x24\x29\x56\x99\x0e\x0f\x3c\x54\x72\x89\xe4\x75\xc7\x12\x08\x14\x69\x94\x13\x1a\xc3\xd5\x69\x9a\x45\xe0\xef\x78\x38\xec\xb8\x90\xda\xed\x90\x58\x9d\x39\x87\xcf\x77\x3b\x14\x57\x7c\x25\xb3\x72\xfb\xf0\x15\xd5\x3f\xeb\xf8\x6f\xe2\x41\x09\x50\x37\x3e\x01\x39\xd3\x94\xcf\x4c\xc3\xd4\x2a\x7b\x2d\xfd\xe9\x74\xbd\x5b\xea\x28\x32\x7e\x09\x08\xe0\xcf\x1e\x72\x42\xd3\x72\x0e\xa6\x64\xeb\x6f\x58\x58\x65\x85\xe9\xfe\x4e\x63\x44\x4b\x8e\x78\x5b\xb1\x05\xf8\xa5\xe6\xf6\xa4\xc2\x51\x5c\xe6\x09\x93\x3e\xab\x25\x78\xc9\x9b\x75\x92\x7c\x60\x8b\x06\xdc\x1b\x9d\x72\x1c\xea\x97\xdf\xe2\x24\x51\xb8\x91\x26\xeb\x17\x7b\x83\x31\xe0\xc2\xa7\x11\x2f\x5c\xe8\xa3\x0a\x0e\x54\xba\x3c\xde\x77\xa1\xf3\x5d\x6e\x6c\x3a\x08\xc6\x07\xd7\x4a\x23\x1b\xf2\xe3\x93\x3e\xdc\xb5\xee\x8a\xfa\xcc\x71\x0c\x73\x75\x35\x0f\x56\xb0\x2d\x27\x0d\xb8\xf3\x70\x58\x4d\xc7\xb3\xa0\xca\x7e\xcd\xbe\xd6\xcb\x54\x1b\x9f\x53\xee\x2e\xe1\x64\xed\x0d\x06\xa1\x64\x64\x33\x2a\xf2\xc5\x8c\x66\xc3\x61\xe9\x49\xf7\x6b\xcc\xdf\xa6\x41\x9c\xa6\xbc\xf8\xe5\xe6\xea\x57\xca\xa6\xe3\xd9\x29\x3f\x65\xd3\xc7\xb3\x9a\xa5\x49\x28\x9b\x8e\x66\x93\xe4\xd1\xa3\x89\x9f\xd2\x34\x48\x58\x29\x3d\x83\x4b\x86\xd4\xfc\x5c\xba\xae\xce\x29\xc0\xa1\xa9\x2e\x28\x7f\xde\xdc\x48\x2a\xf0\x50\x19\x16\x71\x2e\xba\x31\x57\x5b\xc1\x70\xe8\xad\xc5\x96\x15\x7b\xb9\x1f\xcc\xb3\xe2\x92\x85\x62\x0b\x6b\xf8\xa9\x88\xc6\x5e\x1a\x80\xdf\x56\x31\xe3\x4b\x7f\x62\x54\x60\xe2\xa7\x96\x7b\x73\x23\xaa\xee\xad\xc8\x32\xd8\x06\xdd\x38\xb0\xdc\x6f\x9c\x96\xd7\xe3\x2c\x29\x17\xa6\xc7\x9b\x22\x5b\x5d\xc5\xdf\x78\x64\x09\xc3\x25\x96\xb1\x60\xe8\xfa\x7c\x5c\xb3\x20\x64\xe9\xa7\x92\x5f\xbc\xbf\x3a\xab\x6d\xeb\x65\xbe\xda\x58\x1e\x45\xf1\x9d\x72\xd1\x8a\x13\xfa\xc3\x7f\xfd\xb5\xfc\xb7\x57\xde\x5f\xbf\x9e\xfa\x3f\x74\x27\xab\xb3\xbe\xe4\x39\xe8\xbb\x38\x6b\x4b\xc6\xcf\x46\xb8\x53\x59\x32\x7e\xde\x47\x85\x0f\x53\xdd\x68\xfc\x04\x4b\x27\x0a\xbb\x5d\x17\xae\x47\x04\x82\x0d\xf4\x19\x42\x24\x2e\xdf\xb1\x77\x60\x1b\x3d\x92\x1b\x4c\xc7\xdb\xa3\x58\x41\xd9\x94\xcf\xce\x10\x3a\xad\x48\xed\xab\xab\xc9\x6e\x38\xf4\x2a\x5a\x05\x55\x11\xaf\x3c\xdf\xc7\xd5\x29\xca\xbf\x21\xdb\x8b\xcf\xc7\x8f\x06\x4a\x0d\xa3\x59\x10\x97\x9f\xd2\xb8\x4a\x78\x59\xbe\x83\xb5\xb9\x3b\x6d\xcd\x6f\x88\x74\xd6\xf1\xcc\xc1\x91\x3a\x77\xee\xee\x3a\xc3\xf7\x36\x44\xe1\x3e\x33\xaf\x5a\xa9\xbc\xc5\xb3\xaf\x5e\x69\x01\xb8\xf3\x59\xfb\xce\x56\x84\x8f\x5a\xe1\xef\x44\x6f\x17\x0a\x20\xdb\xfe\x62\x19\x97\xd4\x8d\xba\xbc\xb7\x53\xea\x0b\x44\xea\x92\x39\x99\xee\x04\xb4\xcd\xf1\xb3\xfb\xd8\xdd\xbb\x7e\xdf\xcd\xcf\x1e\xc6\x2e\x6a\x1d\x38\xb1\x8b\xb9\xf6\x40\x0f\xa1\x53\xee\xd7\xdc\x52\x8c\x0b\xed\xea\x61\x8b\x86\x88\xa0\x21\x5b\xe5\x13\x84\xd1\x4f\xe2\x79\x51\x89\xc7\x57\xe2\x31\x11\x8f\x7f\x42\x7f\x22\x68\xf8\xf7\x75\x06\xe1\x7f\x12\xe1\xff\xcf\xb7\xc7\x3f\x4e\xd0\x1e\xc7\xf4\x87\xe9\xf0\xa7\x57\xe8\x4f\x33\x8b\xaf\xab\x7b\xe0\x21\x97\x88\xad\xa9\xa1\x30\x8d\x4b\xd8\xab\x49\x26\xa8\x5e\x3c\x02\xde\xb9\x58\xc8\xc4\x94\xad\xb1\x0a\xb9\x4f\xbc\x58\xe1\x29\x73\x85\x9f\xde\xe3\x44\x5d\x46\xfa\x18\x90\x0a\x61\xfb\xd3\x53\xe1\x18\xa4\x40\x0b\x02\xd9\xde\xf5\x00\x65\xd8\xb9\xe7\xe9\x05\x30\x2e\x15\x47\x66\x9b\x36\xf7\x6d\x89\x7d\xd0\x56\xbd\xe8\xa3\xb2\x06\x64\x3c\x1e\xb9\x15\xf0\x54\xf9\x64\xfc\xe3\x8f\x2e\x0d\xbc\x67\x0f\xbf\x46\x55\xd2\x35\x71\x42\xee\x28\x2d\xa5\xfe\x24\x1b\x0e\x6b\x59\xb0\x57\x4c\xd3\x19\xad\xda\x3c\x5a\xed\xfd\xb3\x3e\xd7\x71\x25\x4d\xde\xee\x6b\xd5\x4e\x8f\xe3\x42\x9c\xd3\x2a\x8b\x45\x2b\xd8\x1d\x2f\xe0\xf4\x0d\x1b\x56\xc1\xd3\x43\x5d\xab\xb9\x37\xc7\x57\x64\xfc\xf2\x89\xb3\x43\x1e\x06\x98\x53\x15\x9b\x2d\x97\xa6\x03\x9e\x25\x0b\xe8\x4e\xef\xe7\xc7\xa1\x23\xb4\x93\x38\x98\xd8\x7a\xcb\xc7\xa9\x4f\xf8\x70\x58\x49\xd1\x45\x8a\xb9\xef\x5a\x57\x9e\x3b\x98\x55\x0b\x4a\x56\x34\x42\x6f\xfc\x7a\xfb\x65\x26\x3e\xc4\x6e\x57\x87\xdf\x66\xd1\xa6\x69\x67\xfb\x2b\x88\x75\xb5\xfd\x21\xe2\x73\xc5\xc4\xe1\x94\xd6\x77\xbc\xfa\x6a\x50\x1f\x7c\xa5\xd8\x59\xec\x8e\x9e\x60\xf6\x74\xb0\x3f\x1c\x8e\x9f\x50\x4a\x53\xd8\xfe\xc6\x4f\x7c\x52\xd1\x14\x57\x3f\xd1\x27\x8f\x77\x3b\x88\xa9\xce\x2a\x32\x72\x55\xf0\x21\x5b\xba\xba\x13\xf9\xc2\x37\x35\x6b\x3f\x85\xd7\xd9\x6e\x07\xbf\xe0\xe8\xf5\x53\x1a\x47\x3c\xad\xc0\xd3\x3c\x1a\x98\xb7\x21\x7b\x11\xdd\xbd\xfc\x36\xd0\x98\x6b\x46\x4c\x36\xe7\x0c\x81\xf6\x38\x22\xd2\xb7\x06\x5c\x4b\xea\xbb\x6a\x2f\xd5\xee\x42\x8f\xba\x36\x8f\xa7\x75\xa7\xce\x76\x3b\xbb\x92\x04\x21\x93\x43\x70\xe8\x3d\x30\xba\xbd\x2c\x43\x82\x2e\xcb\x90\xe5\x1c\xe1\x8f\x39\x0b\xf9\x2d\x2b\x08\x3a\x41\x18\xe4\x4c\xe8\x75\x51\x64\x5f\xc5\x23\xc2\x9f\x72\xf5\xfa\x29\x47\xf8\x3a\x5e\x2c\x75\x34\x3c\x23\x0c\xda\xf9\x32\x44\x3c\x22\x7c\xc1\x13\x82\x2e\x78\xc2\x2b\x8e\xf0\x6f\x71\x4a\xd0\xfb\x8f\x08\x83\xba\x3f\x32\x74\xff\x11\x7e\x9d\xe7\x65\x2b\x48\x29\xa3\x23\x25\xaa\xca\xc2\x2f\x08\x5f\x65\xff\xfd\xa1\x88\x53\x00\x93\xf9\x33\xdf\x10\xbb\xb9\x62\x2b\xdb\xbe\x20\xe8\x67\x16\x7e\x29\x45\x43\x10\x7e\x49\xd0\x0d\xbb\x45\x78\xfc\x98\xa0\xf3\x84\xb3\x02\xe1\xf1\x13\xa2\x7a\x1f\x8f\x9f\x13\xf4\x71\x19\x8b\xa6\x8d\x7f\x94\xc5\x17\x59\x82\xf0\xf8\x05\x41\xaf\x13\x11\xfa\x92\xa0\x0f\x6c\x5d\x72\x84\x1f\x8f\x08\x3a\x67\x79\x29\x2b\xf2\xf8\xc7\xa6\xcf\x9e\x3c\x86\xde\x7a\xf2\x44\xa4\x5d\x70\xd1\x37\x4f\x9e\xca\x67\xd9\x0b\x4f\x9e\x89\x12\x23\x84\x9f\x3c\x27\xe8\x97\x6c\x25\xbe\xf9\xd1\xea\xd8\x27\x2f\x8c\x8e\x7d\xf2\xd2\xee\xd5\xa7\x23\xab\x4f\x9f\x3e\x23\xe8\x6d\x5a\xf2\x42\x44\x3d\x6f\xba\x77\x2c\xda\xf8\x66\x2c\x1e\x9e\x10\xf4\xe6\xb1\x78\x78\x4a\xd0\x9b\x27\xe2\xe1\x19\xf9\xff\xb8\xfb\xd6\xed\xb6\x71\x34\xc1\xff\xf3\x14\x12\xce\x2c\x8b\x2c\xc1\xb2\xe4\xa4\x73\xa1\x8c\x78\xd2\xa9\x64\xaa\xf6\x54\xaa\x72\x12\xd7\x6e\xef\x2a\xea\x1c\x5a\x82\x6c\x76\x28\x80\x4d\x42\x76\xbc\x96\xe6\x31\xf6\xd7\x3e\xdd\x3e\xc9\x1e\x7c\x1f\x00\x82\x14\x75\xf3\x56\x9d\x9e\x99\x3f\x36\x05\xe2\x4e\xe0\xbb\x5f\xc8\xbb\xa7\xfa\xe1\x59\x4c\xde\xfd\x49\x3f\x3c\x8f\xc9\xbb\x67\xfa\xe1\x45\x4c\xde\x3d\x27\x90\x21\x95\xbc\x7b\x41\x20\x9d\x25\x79\xf7\x92\x40\xde\x36\xf2\x6e\x38\x20\x90\x20\x8b\xbc\x1b\xea\xbe\xcf\x74\xdf\x43\xdd\xf9\xd3\xa7\x31\xf9\x65\xb9\xc0\xfd\x18\xea\x59\xf9\x5f\xea\xec\xec\x69\x4c\xde\x73\x95\x90\x26\x04\xdb\x66\x9e\x01\xb7\xf6\xb8\x24\x48\x95\xa8\x99\x0a\xa6\x6a\xf6\x88\x1a\x25\xf5\x9b\x7a\xde\xc8\xcf\xde\x56\x7b\xa3\x6f\x28\x82\x6b\x4d\x7e\xd9\x3c\xd3\xdd\x22\x08\xba\x5d\x31\x2e\xda\x09\xb2\x4e\x61\xe9\xaf\xd7\x99\x8a\x09\x6a\xa2\x09\x35\xc7\x28\x26\x46\x03\xad\x0f\xbc\x4a\x62\x62\xb4\xd3\x84\xc2\x91\x8b\x89\xd5\x49\x93\xb6\x58\x37\xcf\x8e\xcb\x48\x63\xb9\x64\x65\x6c\x22\x7c\x13\x88\xd5\x0a\xf5\xad\x16\x04\x01\xd8\x74\xc2\x99\x0b\x5f\xb6\x15\xab\x36\x50\x7a\x1c\x19\x6b\xa6\x12\x04\xa1\x0c\x02\x3e\x96\x1a\x86\x8e\x93\x09\x26\xcb\xde\x94\x2f\x79\x50\x14\x41\x55\x4b\x9d\x4f\xf7\x8b\x2b\x99\x05\x01\xfe\xef\xa7\x8a\x17\x89\x92\x05\x4d\x18\xf9\x97\x7f\xb1\xbf\x48\x1b\xa6\x3c\x54\x1e\x9a\x84\xdd\x6e\x1a\xd1\xd9\x26\x5f\xb6\x5a\x85\x9c\x91\xef\x35\x01\xd8\xfa\x32\xf5\x18\x7f\xf2\x3d\x00\xe6\x0b\x72\x9e\xa5\xe2\x6b\xe7\x54\x53\xe2\xe7\xa4\xc7\x7b\xe4\xd5\xf9\x29\xfe\x27\xb4\x1c\xf3\x09\xeb\xa6\xfd\x79\x5a\x58\x2e\x1d\xca\x2e\x66\x63\x3e\xa9\x92\x7f\xc8\x9d\xbc\x7a\xb2\x49\x9f\xa6\x4c\x1e\xc7\x76\x97\xec\x61\x9a\x16\xd3\x8c\xc7\xdd\x01\x75\xd1\x2c\xbb\x03\x3a\xe3\xf3\x52\xff\xe7\x59\x96\xe6\x25\xbc\xbe\xd6\x7f\xb2\x54\x70\xfb\x3f\x29\xfe\xd5\x04\x9b\xd4\x25\xb9\x69\x99\xcb\xec\xfe\x5a\x0a\xfb\x68\x1b\xe8\x9a\x49\xe6\x37\x28\xf8\x14\xfe\x97\x0a\xa2\x5d\x60\xe4\xbc\xee\x60\x4d\x97\x6c\x3c\xa4\xdf\x9d\x63\x0c\xb6\xce\x62\x99\xa9\x34\xcf\x38\xc3\x98\x62\xaf\xbe\xa3\xe4\xfc\x14\xdf\xbd\x22\x13\x3a\xd5\x95\xc9\x39\xa0\x83\x57\x9a\xdd\x39\x35\x8f\x13\x9a\xb1\xf1\x13\xf7\xea\x5c\x69\x3a\xe6\xd5\xb9\x2a\x4c\xad\xe2\xd5\xf9\xa9\x29\xab\x9a\xe4\xd8\x5b\x79\x7b\x8d\xb5\xe0\x61\x42\x67\xec\x81\x7c\x4f\x62\xfd\xee\xe2\x7c\x96\xde\xe2\x4b\x78\x98\xd0\xa4\xe0\x09\xbc\x3a\x5f\x24\x39\xbe\x81\x87\x09\x9d\xca\x2c\x1e\x9f\x6d\x4c\xc1\x0e\x3b\x95\xd9\x75\x21\x97\xa6\x8d\xfb\xe5\xaf\x80\x5f\x73\x31\xc3\xce\xe7\x29\xcf\x66\x25\x57\x58\xbb\xfa\x35\xa1\x79\x52\x24\x0b\xac\x84\xf2\x5c\xac\x62\x9f\x27\x54\x15\x2d\xd3\xc0\x5d\x68\x6e\x80\xcc\x15\xcc\x22\x5e\xea\xc7\x54\x8a\x78\x09\x8e\xca\xfa\x69\x4a\xed\x1c\xe3\x29\x85\x96\xfa\xff\x5c\x4a\xa5\xff\xdf\xf0\x64\xa6\xff\xcf\xe2\x8c\xaa\x9b\x38\xa3\xe6\x60\xe5\xd5\xb9\xca\xf1\x58\xe5\xee\x54\xe5\xf4\x3a\xce\xf1\x4c\xe5\xcd\x23\x95\xe3\x89\xca\xdd\x81\xca\xab\xf3\x94\x37\x8f\x53\x8e\xa7\x29\xc7\xc3\x94\xe3\x59\xca\x5b\xd0\xce\x2e\x39\xd2\xa6\x50\xe8\xd9\x71\xfa\x0c\x08\x8f\xcd\x83\x80\x7b\x17\x7b\x14\x71\x56\xfb\xed\x24\x0d\x75\x74\x82\x6d\x47\x86\x0c\x15\xfc\x9b\xfa\x94\x5e\x65\xa9\xb8\xae\x2c\x74\xbc\xc2\x91\xee\xb4\x82\xd9\xeb\x46\xa2\x85\x4a\xef\x24\xac\xa4\x73\x40\x53\x36\x18\x09\x1c\x00\x08\x50\x07\xfe\xa1\x28\x65\x49\x0f\xc3\x56\x9a\x68\xae\x46\x2e\x49\x93\x73\xcd\xf5\xa5\xaf\x1c\xad\xfb\x00\xa9\xde\x85\x0d\x18\xac\x4e\x92\xf5\x28\x61\xe9\x5a\x0f\x25\x21\xb7\xcb\xba\xae\xf5\x84\x9d\x3c\x8e\x05\xb3\x6b\xbe\xa8\x34\x08\x8c\x31\x79\xc1\xfb\x16\xa8\x79\xf6\x7c\x6e\x6f\x7d\xc8\xf9\xb2\x05\x15\x3c\x3f\x2a\x49\xb7\x21\x00\x92\x20\xf0\x80\x6a\x10\x84\x09\x23\xde\x36\x69\xae\xc5\x01\xda\xc6\xe4\x2e\x6a\x15\x63\x02\x58\xe2\x92\x7f\x03\xe8\x7d\x10\x84\x47\x3f\x82\x43\x0f\x31\xac\xf1\x38\x2d\x86\xdd\x68\xc6\x4c\x80\xd6\x8b\x87\x6f\xd6\x33\x0e\x8c\x1e\x31\x78\xaa\xc7\x2c\x36\xd6\x68\x5c\xcb\x35\x0d\x4b\xef\xfd\x96\xff\xe3\xc0\x96\x97\x32\x5f\xc7\x0f\xdf\x62\x5e\xef\x89\x7b\xaf\x5b\x08\x92\xe7\x7b\x95\x06\x2d\x5a\x4e\x72\xf2\xcf\x43\x12\x35\xd4\x05\x46\xa7\x19\x8e\x5f\x9f\xfc\xcf\x49\xbb\x5a\xf3\xf9\x71\x8c\x64\xa5\xd6\x8c\x7c\xbd\xe6\x09\x28\x36\xfd\xcf\x7e\x73\x9f\xdf\x70\x81\xa6\x8f\x09\x3b\xfd\x6b\xbb\x5e\xb3\xaa\x15\x0f\x9f\x03\x89\xfc\xfc\x38\x12\xd9\x70\x92\x2d\x7a\xbd\x20\x00\xe9\xd9\x00\xb2\xb1\x3a\x7f\x8f\x20\x68\x8d\x50\x5f\xf9\x83\xd4\x93\x63\xee\xad\xde\x4c\x11\xdc\xae\xa1\xa9\x0c\x0e\x35\xe1\xd8\x1d\xea\xff\x40\x78\xa5\x7d\xf0\xd4\x70\x19\x91\x37\x95\x96\xd6\x03\x9f\x8f\x04\x53\x1a\x4e\xf4\xcd\x32\x9a\x22\x74\x7c\x71\x51\x1a\x8a\xc8\x66\x22\xaa\xf2\x7c\xca\x28\x2e\x42\xac\x15\x5d\x08\x7e\x67\x5a\xe8\x72\xfd\x2b\x03\x45\xcf\x46\xb7\x9a\x27\x37\xaa\x4f\x2f\x59\xaf\x60\xd5\x38\x28\xe8\x7b\x27\xe1\xf6\x87\x3c\x8a\xa7\x61\x77\xe8\x05\xe2\x75\x1e\x36\x1a\x58\x0b\x93\xd9\x06\x93\xca\x0e\xaa\xdf\x8b\xe4\xda\x64\xa2\x10\x1b\xc9\xe1\x60\x0d\x65\xaa\xb8\x9f\xdc\xd3\xcf\x12\xf7\x56\x6f\xa2\xff\xd2\x0f\xc4\xfb\x0b\xb0\x4d\xfe\xdb\xdd\x59\x1f\x7d\xa2\x33\xdb\x08\xf1\xe8\x89\xe1\xd7\xd1\x68\x19\x66\x9e\x07\x5c\x62\x93\x7c\x7c\xd9\x9a\xa4\x33\x96\xeb\x88\x6e\x08\xfc\x76\xa4\x7c\xda\x5c\x7a\xfc\xbc\x92\xa6\x36\x16\x1e\xbf\xac\x24\xb0\xcd\x65\xc7\xc3\xe1\x81\xb9\x03\x9e\x1f\xa6\x13\x68\x98\xda\x15\xd6\xf2\x0d\x50\x6e\xd7\x1c\xdc\xa5\x3e\xfa\x78\x11\xc1\xc0\x76\xc9\xf4\x59\x83\xf0\x0f\x21\x79\x9f\x0a\x90\x6c\x74\xf8\xb7\x29\xcf\xf1\xd6\x4c\xc1\x52\x67\x36\xea\x2c\xc1\x0c\x8e\x77\x84\x14\x27\x0b\x5b\x71\xc6\x6f\x3b\xbc\x42\x0c\x9d\xb9\x2c\xa0\xd2\x7c\x99\x65\x1d\x88\x90\xd2\x59\xf0\xb2\x4c\xae\x79\x27\x11\xb3\x4e\x32\x9b\x81\xf1\x41\x92\x75\x6e\x78\x96\xcf\x97\x59\xc7\x2c\xb6\xec\x93\x68\xa4\x0f\x3c\xcc\x72\xca\xc6\xde\x02\x34\x75\x3d\x18\xd5\x66\xfa\x93\xdd\xb4\xce\x7f\x4b\x65\x86\xde\x30\x1d\xd2\x53\x0e\x06\x9e\xfe\x97\xf2\xf4\x9a\x6e\xea\x68\xa6\xe3\xac\xd7\x9b\xac\xa3\x68\xad\x6e\x0a\x79\xd7\x59\xf6\xe7\x45\xb2\xe0\xe5\xa5\xfc\x20\x73\x36\xa4\xcb\x56\x23\xa4\xe7\xc7\x79\x64\xe1\x8e\x7b\x5a\xc9\xd5\x4a\x81\x1d\x43\x32\x43\xb7\x7b\x9b\x79\xd2\x47\xe8\x36\x68\x86\x49\x4d\x22\x18\x91\x82\xf4\x38\x2d\x98\xe8\x78\xd5\x20\xea\x47\x61\x53\xae\xef\x64\xbb\x46\x69\xbf\xe4\xca\xe5\x11\x08\x05\x25\x38\xc4\x88\x44\xb4\x68\x63\x7c\xd3\xb1\x98\x18\x61\x60\xb7\x08\x02\x19\x04\x68\xaa\x0b\x6c\x66\x10\x84\x45\x35\x60\xba\xc8\x71\x30\xd8\x7c\xcd\xaa\xbe\xe3\x89\x82\xb4\x28\x18\xbb\x04\x2d\x7a\x09\x25\x4f\xfa\x03\x12\x45\x14\x85\x17\x92\xee\x54\x0a\x8f\x92\x1a\xf9\x23\xb7\x8d\x17\x04\xfb\x27\x12\x04\x5d\x8d\x6c\x0e\x99\x31\xa1\x44\x4f\xf1\x38\xe2\xe7\x40\x5e\xdf\xd8\xfb\xb4\xc9\x22\x34\x39\x7d\xc1\x3b\xa9\x01\xd9\xa6\x24\xde\x44\x3a\x95\xb9\x0b\x6b\x33\x77\xd9\x44\x12\xf0\xf2\x97\x64\xc1\xf5\x41\xdf\x3c\xce\x8f\x32\x9d\x02\x23\x9e\x9f\x7e\xf9\xf0\xdb\x25\x8a\x83\xed\x10\x41\x20\xc7\x28\x1c\x9e\xac\x56\xe4\xf2\xed\x5f\x2e\x5f\x7f\x7c\xfb\xba\x5e\xc7\x92\x22\x0f\x90\x3e\x01\x98\xfe\x04\xe2\xb4\xc1\x7f\x95\x2e\xe0\x99\xd8\x1f\x27\xe0\x94\x46\x40\x28\xb0\x48\xd2\x4c\x3f\x2c\xa4\x40\xa6\x1f\x77\x02\xc5\x00\x65\x79\x27\x8b\x19\xf2\xfc\xe2\x1a\x3a\x29\x79\x52\x4c\x6f\x90\xc9\xcf\x3c\x5e\x9f\xda\x51\x96\x05\x14\xdf\x71\x0e\x51\x60\xdb\xae\xfb\x1e\x63\xae\x1a\xd9\x15\x04\x4f\xec\x4a\xf5\xd7\xa8\x5b\x54\x6d\xb7\xa6\x72\x5a\x35\x3d\xe0\x8b\xc3\x54\x3b\x2d\x16\xe9\x1b\xde\x50\x54\x80\x12\x2c\xac\x1d\x2b\xc4\x67\x41\xd0\x6d\x2a\x83\xd0\xe4\xc3\x38\x14\xf3\xa6\xc0\x09\x6c\xd4\xc4\x58\x4d\x98\x67\x0e\xd9\x94\x1e\xb6\x32\xb3\x2f\x5a\x38\x83\x26\x96\x32\x13\xf6\x67\x00\xfc\xe8\xc6\x24\x2a\xe3\x4d\x4f\xd9\xdb\xf6\xdd\x5e\x1c\xef\x64\x81\xa8\xb1\x19\x43\x09\x14\xec\x2e\x2f\x1e\xce\xcd\xb8\x63\x70\x9a\x44\xa0\x98\x4c\x26\xac\xd2\x9b\x8d\x93\x09\x4d\xa8\xde\xcf\x9a\xa8\x56\x5a\xa7\xe8\x8a\x40\xad\xaf\xae\x6d\x11\xc7\x31\x00\x4d\xbd\xa7\x6b\x2a\x3c\xdb\xca\x0d\x2d\xeb\x6a\x15\xaa\xb1\x98\x30\xdf\x68\x59\x68\x08\xa8\x11\x40\x0b\xc4\x78\xf1\x18\x2e\xa0\x93\x84\xb2\x25\xa9\x3e\xe5\x1b\x06\x61\x95\xf1\xd7\xa6\xa0\x71\x8b\xa6\x7b\xaf\xa9\xd7\x8b\x83\xa8\x26\xba\x93\x2b\x1e\xd5\xb9\xf1\xc2\x26\x16\x31\xde\x0d\xfa\x76\x59\x69\x77\x7f\x51\x7e\x68\x29\xbd\xe3\x57\x5f\x53\xe5\xbd\xa9\x61\x99\xd5\xea\x61\xbd\x1f\xd3\xbc\x68\xa1\x3e\x3c\x80\xe0\x4d\x86\x44\xa3\x22\x08\x8a\xbe\x90\x77\xab\x55\x58\xb0\x1f\x12\xc5\x9d\x15\x9a\x2e\xed\x5f\xa5\x62\x16\x16\x2d\x3a\x6e\xbf\x97\x78\xf8\x02\xb7\xf0\x31\xa6\x18\xdf\x91\xef\x7a\x1a\x2e\xf6\xbe\x23\xdf\xf9\x1f\x9a\x83\xfa\xea\xb2\x12\x52\xbc\x93\xc5\x9f\x0b\x79\x57\xf2\xa2\xed\x23\xef\xaa\x1e\x0f\xff\xf4\x0c\xe6\x77\x44\x52\xad\x2d\x62\x0f\xc9\x4e\xff\x3a\xee\x7c\x2e\x3e\x8b\xcf\xea\xf3\x7c\x72\xaa\x79\xe3\xf3\xb0\x7b\x72\xb2\xca\x52\xf1\x75\x25\x24\x1a\xcf\xad\x16\x5c\x25\x2b\xf3\x5c\xaa\xfb\x8c\x47\x55\xab\xcf\xa7\xaf\x26\xa7\x34\x6d\xc4\x46\xe0\x9e\xa0\x5e\x41\xc2\x1a\xb2\x14\x33\x3e\x4f\x05\xa8\x73\x0d\xa6\x7e\xff\xe9\x75\x9e\x07\x01\xfc\x83\x20\x72\xbf\x89\x32\x99\xf3\x9f\x35\xfe\xb3\xf1\x02\x82\x20\x6c\x76\xbe\xb3\x7e\xe8\x91\xbd\xf5\x59\x44\x10\xde\xc1\x1d\x69\x3c\x46\xe5\x1e\x2a\xb2\xf4\x35\x0e\x1d\x4d\x2a\x31\xc6\xbc\xc2\x96\xe9\x01\x1c\xaf\x44\x86\x41\xe0\xff\xb2\x34\x3a\x5a\x0f\x72\xcc\xd1\xa7\x78\xa9\x30\x9b\xc7\x39\x98\xb1\x8d\x07\x93\x20\x48\x6c\x71\x7d\x1d\xe4\xf3\x72\xce\xe7\x73\xd2\xb3\xd6\xfc\x35\x99\x27\x46\xa8\x99\x55\x9e\x13\x17\xbc\x6e\xae\x18\xc5\xa2\x3f\x03\x25\xe6\x0f\x89\x4a\xc2\x01\x1d\x46\x68\x53\xd9\xdc\xab\xea\x4c\xa6\x07\x5c\xd2\x7d\x42\xc7\x43\xce\xe2\xfe\x8b\x62\x01\x24\x58\x44\x9b\xc9\x02\xf3\xdd\x3c\x7c\x9e\x34\x50\x1f\xbf\xa2\x06\xc8\x0e\x15\x2a\xae\x56\x1b\x9f\x36\x09\x39\x95\x90\xcf\xbb\x46\x30\xef\xd9\x21\x7a\xc0\x8d\xa6\xcd\x65\xc5\xc3\x17\x2f\xf4\xd6\xbe\x3c\xce\x59\x18\x8f\x9f\xe7\x3e\x6a\xe2\xda\x08\xc0\xe8\x62\x3b\xa5\x21\x34\x62\xef\xb6\x62\x4b\x3e\x16\x93\x2e\x03\x87\x21\x8f\x4f\x73\xfd\x29\xdd\x5f\x4b\xc3\x20\xe8\xb6\x8c\x52\x75\x60\xe7\xd7\x82\x71\x5f\x1e\xe7\xc3\xeb\x8c\xa2\xba\x9a\x51\xb3\xee\x2f\x36\x40\x8b\xe1\x0a\x68\xe1\xb4\xa0\x00\x8f\x1c\xdb\xc0\x84\x2f\x55\x62\x36\x7c\xa2\x57\xa1\xa8\x55\x28\xa0\xb9\x63\x53\x58\xa1\x6f\xb8\x42\xc1\xb9\x32\x02\x31\x30\x13\x81\xdf\xce\xce\x45\x32\xde\xff\x02\x1e\xbc\x50\x8e\x8f\xce\x86\xdd\xba\xcc\x75\x87\xeb\x7d\xb6\x6e\x4d\x09\xc9\xcb\x83\xcd\xba\x8d\x2f\x0c\x38\x09\x6d\x50\xc3\xc7\x78\x29\x44\x54\x86\x1b\x4c\x99\xd2\xa5\xc6\xe6\x56\x9d\x0c\xf1\xa8\xd1\xe6\x11\x88\x3c\x7b\x29\x9c\x42\x45\x1e\x82\x7f\x81\xa1\x34\x7d\x7b\xb0\x4a\xc7\x62\xfd\x93\x8c\x7b\x8f\x02\xbf\x1e\x31\x2e\x26\x8c\x8f\x8b\x49\x45\xa6\x3f\xde\xed\xe8\xe5\xa3\x44\xd0\xb7\x4d\x3b\x52\x3f\x9b\xb6\x3d\x92\x70\x28\x2e\x52\x63\xfc\x14\xab\xbe\x92\x68\x92\x14\x3e\x79\x56\xcf\xe0\xbd\xc5\x0a\xf5\x9e\x16\xf5\x9c\xdd\x4e\xe4\xfc\xcf\xa4\x97\xd4\x12\x45\x97\x4e\x10\x96\x18\xd9\x97\xfb\x7a\x1b\xd8\x98\x2d\x83\xc0\x19\x55\xeb\x9f\x20\x0d\x46\xd3\x5f\x34\x35\x64\xfa\x20\x54\xf7\x61\x59\xbb\x0f\xcb\xd5\x6a\xda\x42\xe9\x3a\x5f\x92\x84\x72\x6a\xcc\xb3\x6f\x34\x71\x44\x07\x51\xac\xb7\x95\xa2\xac\x27\xa7\xb7\xf4\x9e\x5e\xb3\x81\x9e\xd7\x06\x8b\x66\x3f\xfd\x5b\x36\x18\xbd\xad\xdc\xb9\xde\xf6\x7a\x51\xce\xf8\xf8\xed\x84\xde\xb2\x90\x80\x85\xd8\x85\xea\x2d\xe2\x9b\xa8\x27\xc3\x9c\xbe\x8d\xe8\x3d\x13\xbd\x6b\x7a\xdd\x63\x65\x88\x43\xe8\xad\xa8\xa4\x6c\x6f\xd8\xcc\x38\xdf\xbf\xc1\x0d\xfa\x48\xaf\xd8\x1b\x7b\xf8\xa0\x1c\x84\xf5\x5c\xa8\x22\xe5\xa5\x9b\xc8\x37\x36\x18\x75\xc3\x8f\xec\x0a\xb4\x84\x61\x14\xf5\x67\x52\xf0\x51\x94\xb3\x8f\xfd\xdb\x24\x5b\xf2\xf6\x09\x7d\xeb\xf5\x76\x4d\xa9\x03\x5a\xc9\xb6\x7e\x61\x6e\x77\xb6\xf3\xd1\x5d\x10\x84\x39\xbb\x1b\x0f\x5b\x16\x9e\x86\x77\xe3\xc1\x24\xea\x2d\x60\xc4\xc1\x96\xf1\xa2\x35\x22\xfc\x3a\x10\x5b\x46\x0f\xf3\x10\x54\x01\x95\xb6\xd2\xe4\xee\xcd\xfa\x26\x2c\xaf\xde\x17\xbb\x0d\xef\xf5\xf5\xfe\x12\x7d\x69\x02\xf8\xf7\x11\x4c\xf0\xcb\xf8\x7d\xeb\x04\xdf\x1f\x30\x3b\x9b\x2d\xac\x96\x4b\xbd\x96\xa0\xd9\xda\x3b\x0f\x62\x7d\xcc\x09\xa1\x83\x2a\x42\xc0\xb4\x95\xb3\xca\xbc\xd2\x77\x45\x72\x5d\xcf\x5b\x57\x33\x12\xfe\x31\x11\xb3\x8c\x97\x55\x8a\xa7\x6b\xae\x7e\x32\x66\x2f\xef\x44\x95\xdc\xc9\x17\x45\xdc\x6c\x48\xe6\xf3\xfe\xa7\xb7\x1f\x5e\x7f\x7c\x7d\xf9\xeb\xc7\x88\x2e\x18\x89\x09\xbd\x65\x0f\x44\x3f\xb0\x01\xa1\xa4\xaf\x1f\x86\x84\x92\x58\x3f\x9c\x91\x35\xbd\x67\xa7\x63\xd6\x8f\xeb\x76\xe1\xcb\xed\x4c\x5f\x7d\x2d\xf1\x70\xf0\x64\xc3\xde\xd9\x2e\x25\x1e\x0e\x9e\xd1\x8d\x95\xc4\x43\x14\xed\xef\x97\xc1\xbf\x3c\xcc\x71\xb6\x35\xda\xa0\x64\xc5\x26\xbf\xb5\x19\x11\x0c\x86\x69\x61\x5a\xab\xa6\xd0\x7b\x96\x5e\xe1\x12\x49\x84\x3d\x55\x05\xf1\x33\xa4\x97\x5a\xf8\xc5\x9a\xb6\xb9\x61\x0e\x60\xe2\x45\x3f\xac\x1d\x34\xb6\x30\x00\x23\x48\x93\x31\x5e\x92\xce\xbb\x34\xe3\x13\x12\xd7\xca\xfe\x9c\xc9\xab\x66\xd9\x3b\x59\x2c\x34\x6d\x3d\x21\xb1\xa3\xc0\x4c\x7c\x8e\xd8\xe1\xf8\x56\x68\x0f\xca\x61\x94\x99\xd4\x60\x79\x6a\x8c\x66\xbb\x89\x07\x57\xad\xd1\xf7\xb8\xf2\x9a\x32\xd4\x9d\x41\x36\x63\x31\x09\x02\x85\x1e\xba\x5c\x4c\xe5\x8c\xff\xf6\xf1\xa7\x4a\x01\x27\xa2\x1e\x61\xa4\xd7\xf2\x86\x03\x9d\xe7\x5c\xbf\xfa\x7f\x93\xa9\x08\x49\x40\xea\xd8\xc5\xf3\xb8\xd5\x68\x86\x3d\xac\x35\x09\x0f\xe9\xf0\x15\xd4\x36\xa6\x10\xd2\x82\xec\xe4\x3c\x1d\xf5\x7a\x49\x24\x98\x1c\x27\x13\xaa\x98\xb0\x95\x19\x89\x68\x31\x9e\xf1\x8d\x99\x68\x46\x28\x9a\xb0\xd6\x37\xc3\x89\x27\x6e\xf2\x21\x85\x13\x05\xa2\x0e\xc5\xcd\xe9\xf4\x73\x71\xf1\x59\x9c\x42\x98\x96\xf5\x28\xe9\xe7\x32\x0f\x2b\x78\x56\xb2\x01\x5d\x32\xcb\x35\x8d\xca\xf3\xe5\xa8\xd7\x2b\x23\xc1\x92\x71\x89\x93\x4d\xc5\x8c\x7f\xfb\x75\x1e\x92\x18\x14\x08\xc2\x78\x43\x0e\xa8\x6a\x28\xba\xa9\x64\xf7\xa1\x7d\xad\x7a\xc3\x28\xa2\xa9\xa6\x50\x9c\x7b\x71\x5a\xcd\x77\x5a\x53\xa0\x9b\x89\x76\xbe\x1f\x75\xbe\x3f\x8d\xfa\x60\xb3\xe8\xfb\xd9\x65\x5e\xed\x45\xd8\xac\xdf\xf0\x2d\xb6\x41\x63\x5c\x25\x06\x95\x60\xe6\xd8\x31\x95\xd5\xb3\xdb\x4b\x50\x7c\x84\x1c\x26\x1c\x51\xae\x09\x72\x6f\x06\x39\xf6\xad\x34\x8d\xf7\xb0\xb6\xd9\xee\xff\x6e\xc3\xbb\x7e\xbb\x31\x81\x5b\x0b\xfe\x77\xfd\x03\x4b\x35\xbf\xc5\xc8\x8f\x6f\x5f\xff\xa0\x59\x7f\xfb\x7a\x01\x39\x86\x35\xd5\x09\xb4\x81\x69\xde\x2f\x78\x99\x4b\x51\x02\x06\x5a\xad\x80\x57\xdb\xfa\x3e\x5a\xad\x2a\x6d\x5e\x5b\x85\x8b\xcd\x52\xc8\x1a\xeb\x42\x40\x96\x2a\x51\x4b\x70\xee\xad\xcd\xdb\x2b\x37\xf5\xb8\xfa\x04\x45\x55\xb2\xf1\xd0\xf5\x8d\x95\x4d\x14\x93\x1b\x9e\xcc\xb8\xd9\x05\x7c\x2e\xd9\xb2\xaa\x7b\xcd\xd5\xeb\x2c\xfb\x68\x66\xf3\x23\x56\x00\x27\xb3\xaa\xc1\x98\x98\x54\x9e\x27\x9a\x64\x23\x13\xe6\xb7\xae\x37\x0d\xeb\x55\x23\x37\x5b\x7c\xdd\x9c\x2d\xf6\x6f\x6a\x5d\xc9\xd9\xfd\xb6\xcf\x82\x1b\x97\x27\x45\xc9\xff\x2c\x67\xf7\xa1\xfb\x8e\x17\xee\x29\xde\xd8\x5b\x1b\x26\xc3\x1e\x96\x59\x33\x4e\xe6\xe8\xc6\x8b\xa9\x61\x22\xb5\xfc\x7d\xc9\x8b\x7b\xe6\x3d\xaf\x56\x36\x8a\x0b\x4e\xc5\x9e\xad\x65\x91\xd9\x78\xc1\x66\x8f\xed\x01\xfc\xd2\xf8\x2d\x45\x48\x20\xf9\xb6\x27\x0a\xc2\xf8\xa2\xf8\xe1\x8d\xb1\x4f\x71\xff\xa0\x40\xad\x9a\x87\xc2\x72\x1b\x1e\xd5\xee\x6b\x5c\x3f\xe8\x8d\x28\x3a\x69\xd9\x59\x8a\xe4\x2a\xe3\x1d\x25\x3b\xb0\x39\xa0\xef\xb5\xeb\x27\x10\xda\x53\x17\xb3\xee\x80\xf2\xbe\x2c\xd2\xeb\x54\x24\x7a\xda\x02\x16\x7e\x95\x4c\xbf\x6a\xc8\x0e\xf6\xd2\x7c\xa1\x61\x9f\x6b\x8b\x51\x15\x2a\x3b\x05\x57\x9d\x2a\xa0\x46\x95\x39\x66\xaf\xd8\xd9\x60\xa0\x01\x3b\xfe\x3c\x7f\x32\x18\x6c\x6b\x85\x58\xb9\x5a\x86\xf2\x8e\x35\x78\x2f\x94\xcb\xe9\x94\x97\xe5\x7c\x99\x75\x7e\xbc\xbc\xfc\xe0\x2d\x64\x54\x54\xb3\xe7\xb4\xfa\xc4\x4c\x51\x7b\xde\x99\xed\xae\xb6\xb8\xd5\xaa\xa0\x2a\xf2\x41\xc6\xdc\x67\x86\xda\x6c\x92\xc1\xfc\x63\x16\x92\x7f\x7d\x7b\x49\x28\x8f\xfa\x5c\xcc\x42\x15\xc5\x43\xc6\x12\xe3\x40\x58\x5a\x61\x56\xbd\x66\x8c\x3f\x75\xf7\x40\xfa\x41\x6e\x4d\xbd\xad\x0a\x84\x45\x90\x4d\xb3\xe0\xb3\xe5\x14\x33\x68\x7a\x3c\x8f\x1b\xdc\x98\x62\xe9\x63\xb3\x5a\x95\x3c\x9b\x1b\xc3\xaa\xd1\x5c\xdf\xb5\xbf\xfc\xf8\xd1\xf7\x74\xd4\x28\x38\xec\xde\xf6\xff\xf2\xfe\xe7\x1f\x95\xca\x3f\xf2\xbf\x2f\x79\xa9\x56\xab\xdb\xbe\x0d\x4a\x19\x04\x64\x9e\x66\x3c\x26\x8c\x55\x85\xc8\xe0\x4e\x65\x16\x04\xb7\x7d\xcc\x1c\xfb\x17\xc4\xf2\x55\xaa\x08\x7e\xd7\xa9\xf7\x3a\xf2\xd8\x64\xfd\xb6\xd6\x2e\x24\xef\xd3\x69\x21\x4b\x39\x57\x30\x99\xcb\xcb\x0f\xc4\xe7\x97\xf7\xb4\x2d\xbf\x2d\xb2\x33\xdb\xb0\xff\xac\x3f\x78\x7c\xe3\x27\xff\x1f\x8d\x6b\x0d\x1d\x65\x84\x69\x3c\x18\x21\xe0\x7e\x7b\xd1\xe6\x3a\x6a\x1c\x73\xd7\xdb\x02\x16\x1a\x23\x88\xf0\xaf\x9f\xcb\xef\x57\x9f\xcb\xef\xff\x39\x3a\xbd\xa6\x84\x44\xeb\xd1\xbc\x5f\xf2\x02\x63\xf0\xe0\x9c\x58\x4a\xe7\x78\x65\x91\xf6\x63\x90\xfd\xf9\x3e\xe7\x25\x7b\xb8\x51\x8b\x0c\x13\xc9\x9f\xea\x47\x42\xff\x56\x4a\x11\x93\x24\xcf\xb3\x14\xbf\xec\xa9\x2e\x21\xf4\x9b\xae\xe7\x17\x7f\xd3\xb5\x97\x45\x86\xc4\xd5\xac\xf1\xf2\xe4\xee\xee\xee\x64\x2e\x8b\xc5\x49\x55\x85\x50\x08\x18\x75\x48\x45\x02\x25\xb3\x44\x25\xe4\x90\xfa\x6b\xea\x2d\x9a\x3d\x1c\xd0\x22\x4e\xe9\xe6\x22\xe3\xff\xfa\xe9\xd7\x5f\xfa\x28\x02\x48\xe7\xf7\x6b\xbb\x6d\x87\xf5\x58\x6e\xed\x11\x3a\x59\xd3\xdc\x93\x02\x5d\xf3\x56\x8f\x61\x1f\x41\xf2\x3a\xc5\x35\xa9\x77\xd0\x82\xfe\x36\x35\xaf\x6c\x07\xc2\x5d\xad\x08\xc1\xa0\xd2\x20\xd6\x9b\x86\x06\x98\x0a\x96\xe9\x47\x4b\x33\x16\x9a\xde\x16\x18\x8a\xba\x98\x30\x70\x5d\xa9\x4d\xc4\xe1\xcf\x96\xe1\xcd\xfe\x8d\xdd\x30\x13\x2f\xd8\x02\x87\xa4\x39\x08\xf4\x56\xab\x16\x6d\x76\x74\x01\xc6\x6d\x80\x6f\x9b\x6b\x6f\x12\x2a\xb5\xc1\x87\x67\x67\x4f\x8c\x3d\x0b\x67\x67\x83\xa7\x91\x61\x23\xf8\xe9\x70\x30\x58\x0d\x46\x1e\x55\x64\x11\xaf\x41\x1a\x7a\x27\x94\x8d\x39\x36\x97\x6c\xc8\xec\x4f\xf9\x95\x9d\xb9\x1f\x18\x6d\x13\x10\x0e\x7b\xea\x4a\x4b\x5e\xdc\xf2\x02\x4b\xff\xe4\x4a\xc1\x46\x8a\x85\x4f\x41\x64\xa8\x8b\xa3\x20\xc0\xfd\x90\x88\xb1\x0c\x91\x90\x4c\xa7\x3c\x57\x7c\xc6\xce\x06\x67\xcc\x4e\x4b\x48\x2b\xe1\x3f\x1b\x3c\x75\xa5\x57\xc9\xcc\x40\x50\xf6\x74\x30\x70\xc5\x4b\x91\x2c\xd5\x8d\x2c\xd2\xff\xc5\x67\xec\xe9\x60\xe8\xf5\xa2\x5e\x43\xef\x1a\xad\xb3\xa7\x83\x67\xfe\x9b\x77\x72\x29\x74\xf5\xaa\xfb\xb9\x2c\xae\xd2\xd9\x8c\x0b\xf6\x74\xf0\x84\xb1\xc6\xc9\x35\xd3\x66\x1b\x74\x87\xa5\xae\x28\x04\xd7\x00\xb2\x06\x1c\x34\x97\x45\x46\x0b\x46\xa6\x89\x10\x52\x75\x48\x4f\xf5\x48\x87\xf4\x44\x8f\x74\x42\xd2\xf3\x36\xbf\x47\x22\xa2\xa9\x75\x87\xca\x0b\x2f\xfa\x89\x45\xc7\x55\x75\x2a\x2d\xed\xa4\xa8\x04\xc2\x49\x50\xa9\xaf\xac\x25\x1e\x59\x4e\x6f\xc2\x99\x1f\x93\xdc\xfb\xd1\x5f\x96\xbc\xd5\x65\xdf\xa3\xdb\xd6\xb5\x06\x2a\x5d\x70\xb9\xdc\x7e\x6b\xbf\xd8\x0a\xbc\xa5\xf1\x34\xe3\x49\x71\xd9\xec\x61\x4b\x07\x03\xea\x57\x0f\xab\x97\x45\xdb\xbc\x92\x2b\x59\xa8\x26\x06\xc7\x13\xa5\xdf\xf0\x59\xe4\x0f\x62\xca\x5c\x64\x3d\x4d\xda\x42\x99\x3d\x86\xb5\xa1\x4d\x19\x52\x71\x50\x8d\xb4\x4d\xa1\xac\x01\x33\xa3\xaa\x00\x3e\xfe\xa1\xc1\xb6\x5b\xca\x1d\x2c\x2a\x44\xc5\xdd\x42\x9f\xb5\xcd\xd8\x02\x04\xeb\xd4\xf1\x98\xdb\x82\xfa\x84\x96\xa2\x6c\x87\xaf\xa8\x15\xdc\x3d\x04\xf5\x2b\xb9\x71\x5a\x46\xb9\xb6\x20\x78\xfb\x99\xd8\x0a\xca\x6b\x27\x4b\x43\x9d\x6d\x5d\xe8\xcd\x22\x06\x08\x9c\x68\xf8\x44\x2c\xf2\x1e\xf3\xc9\x6a\xc5\x5b\x8f\x04\x5c\xf6\xdd\x5d\x22\x40\x38\xa4\xb3\xa5\xba\x69\x4d\x0a\x70\xa5\x64\x12\xf2\x1e\x89\x49\x4f\xd5\x3e\xa4\x19\xc0\xc0\x22\xc0\x86\x84\x92\x3f\x27\x65\x3a\xd5\x17\xbf\x6d\x10\x64\x90\x36\x27\x6c\xe5\xf1\x5d\xcf\x50\x2e\xe4\x2c\x45\x2b\x13\x03\x48\x91\xa5\x32\x42\xa0\xb6\xde\xc1\xbd\xa9\xb1\x86\xda\x67\x9a\x1b\x71\xd6\x6a\x15\xd6\x0b\x00\x1a\xdd\xf6\xad\xb8\xcb\xf2\x73\xf6\x75\x3f\xc9\x73\x4d\xc9\x43\xb8\xb8\x96\xad\x53\x2a\x99\xde\x6c\xf8\xeb\xff\xde\x43\xd3\xd6\x2d\x2d\xb9\x98\xb5\xa0\xe4\x04\x6c\xc2\x5d\xa8\x52\xcb\x61\xd7\x4e\x18\xf2\x62\x41\x90\x98\x29\x69\x3a\xac\xd2\x52\x14\xde\x55\x86\x57\x4e\x33\xd5\x6e\xce\x7e\x11\x8a\xd5\xca\x51\x00\x21\x90\x76\x64\xff\x1c\x68\x35\x00\x3b\x80\xfc\x62\x4c\x5c\x54\x2d\xbc\xc7\x1e\x09\x48\x8f\xc7\x3c\xf6\x16\xa3\x69\x9f\xa8\xc7\xa3\xd8\x1b\xc3\x46\x10\xe8\xaa\xd5\x4a\x86\x3c\x82\x2e\xe2\xc6\xdc\x81\xa8\xc3\xa9\x45\x0d\x08\x6f\xb8\xc3\xad\xf9\x33\xfa\x5f\x6c\x95\x51\x1b\xa0\xc5\xfa\x8d\x3e\x0b\x59\x96\x3f\xc8\x45\x92\x8a\x2d\x38\xd7\x63\xdf\x7f\x05\x56\x56\xb3\xef\x1a\xcd\x26\x59\x26\xef\xf8\xac\x73\x75\xdf\x79\x0d\xfc\xef\x89\x71\x22\x3e\x79\xad\xdf\x9c\x60\x6d\x12\x8d\x6a\xa3\x38\xb4\xe0\x33\xf2\x6d\x58\x70\x17\x09\x60\xf1\x18\x55\xfe\xf4\x4c\x61\x47\xce\x3b\xe0\xb7\xba\x28\xc1\x06\x9d\xeb\x6f\x17\x8d\x54\xbf\x8e\x3d\xab\x09\x34\xf7\xe4\x2e\x55\x37\x6f\x0a\x0e\x3e\xfa\x49\xb6\x2d\x48\x4f\xff\x4b\xb3\x9e\x59\x59\xbd\xb3\xf6\x2b\x62\xdd\xbf\xad\xb0\xcf\xb2\xc9\x61\x44\x13\x5f\x88\x53\x09\x8d\x69\xda\x58\xba\xa1\x54\xbc\xdb\x5d\x9d\xb4\x51\xfd\x34\x30\x10\x27\x88\xbe\x14\x05\x4f\x66\xf7\x9a\xb8\xe1\x18\x96\xbc\x81\xd4\x9f\x62\x5e\xa6\x64\x76\x8f\xae\xe7\xb8\xe7\xc0\x43\x73\x26\x0c\x55\x54\x89\x78\x38\x1b\xac\x31\x61\x23\x0a\xd6\x71\x8b\x67\x72\x59\xf9\x47\xd7\xbe\x66\x68\x24\x30\x75\xaa\xa1\x92\x90\x37\x0f\x63\x08\xe6\x33\x40\x19\x70\x31\x23\xd1\x1a\xb9\xda\x65\x6d\x43\x35\xe2\x53\x49\xf6\x6a\x00\xb4\x7e\xce\x8b\xa9\xa6\x65\x39\xe4\x3a\xe5\xb3\x53\xf3\xfa\xfb\xe1\x60\x00\xa6\x26\xd0\x5b\x5e\xc8\x6b\x08\x7b\x81\xc1\x4a\x00\x0b\x27\xa5\x35\xa8\x2f\xbd\x0a\x60\xbc\xda\x97\xc2\x16\xb0\x65\x04\xdb\x21\xfa\xcb\x5c\x8f\x60\xf0\xc3\xce\xd6\x58\xb3\xde\x89\xc7\xb2\xa7\xf3\x30\x0d\x82\xae\x47\x83\x05\x81\x4f\x91\xb1\x92\x2b\x7b\x89\xbd\xcf\x55\x6d\x36\x1c\x3c\x4b\x62\xad\x69\x1a\x45\x34\x01\xb7\xbf\x0d\x36\x3d\xb4\x30\x7e\x59\x64\x3d\xf6\x6f\xf6\xb1\x92\xc9\x5f\x90\xe8\x42\x03\xb3\x24\x26\x17\xa4\x97\x44\xfa\xd0\xe4\x5c\x84\x9e\x1c\xd1\x75\x40\xbb\x03\x0b\x41\x1b\x37\x01\x56\xbd\x79\x3b\x22\x0a\x12\x27\x23\x24\xb5\x72\xeb\x9a\xe4\xd4\x15\x36\x91\x72\x19\x04\x5d\x19\x96\x26\x1d\xd9\xd4\x5f\xda\x78\x37\x90\x9f\x8c\xa6\x41\x10\x96\x6c\xaa\x5b\x3b\x13\x88\x0c\x2c\x6e\x3c\x59\xae\xb1\x76\xf1\x08\xb2\x6c\x12\x04\x42\x13\x1a\x86\x11\x32\xdd\x67\xb4\x5e\xa9\x4e\x97\x58\x69\x24\xb4\x20\x08\xc5\xa9\x00\x4c\x19\x3a\x9a\x5f\x33\x10\xc8\x5b\xcd\xe8\xbc\xc1\xa7\xd7\xcc\x9c\x9d\x88\x6e\xb4\x5d\xec\xa7\x37\x9b\x29\x23\x8d\x8d\xa8\x0a\x82\x02\x69\x9d\x50\x45\x54\xe8\x5f\x7a\x6c\x11\xd1\x42\x0f\xac\xa7\xbd\x7d\x34\xf8\x14\xc7\x0f\x57\xa2\xa8\x71\x73\xb4\x19\xcf\x5a\x91\xd5\x3c\x24\x3f\xbc\xfd\xf9\xed\xe5\x5b\x6f\x30\xdd\xb5\xe8\xdb\x9e\x50\x30\xa2\x5a\x48\x1b\x37\xd9\x0f\xaf\x2f\xdf\xfc\xf8\x7b\xce\x36\x97\xe5\x8e\x2f\xf1\xe1\xd7\x4f\x8f\xf9\x14\xdb\x47\x5b\xee\x1a\xec\xb7\xdf\x71\xac\x4a\xf7\x3b\x5f\xd3\x07\x23\xd8\x8d\x87\x2f\x9f\x53\x94\xea\xc6\xc3\x97\xa8\xf2\xdd\xeb\x8c\x92\xce\x43\x27\x5b\x97\xe1\x46\xd8\xd3\x5a\x6e\x31\x2f\x8b\x5c\xc4\xc7\x6a\xc2\xbc\x82\xb1\x9a\x54\x6e\xe5\x9e\x31\x11\xf5\xea\xf4\xa5\xf0\x9b\xf4\x9b\x6e\x4f\xbb\x88\x6d\x8b\xf8\xca\x06\x59\x54\x82\xb6\x2d\x6c\x14\x02\x8b\xb7\x51\xb4\x5a\x8d\x27\x91\x0b\xcc\x8c\x17\xb7\x3e\xbd\x29\x6f\xcc\xc1\xed\x06\x90\x0a\x7d\x39\x9f\x87\x1c\x28\x67\x13\xf2\x19\xb0\xbe\x13\xc6\xa3\xb0\x1d\x55\x5c\xa3\x23\xa6\x2f\xfa\x73\xe1\x44\x46\xc2\x8c\xb0\x39\xbd\xf9\xbc\xb6\x7d\x68\xbd\xea\x36\x6f\xf3\xd5\xeb\x2c\x73\x28\xac\xe5\xf5\xae\xbd\xb7\x81\xdc\xf7\x4c\x7c\xb0\xa9\x89\x88\xb6\xac\xdb\xa8\xa0\x46\x6d\xb4\x6d\x69\xd3\x56\x0b\xbf\xb5\x2e\x69\x51\x75\x44\x6d\x5c\xb9\xdf\x13\x8e\xe3\x18\x0f\x2a\xd9\x60\x24\xcf\x85\x55\x60\xcb\x5e\x2f\x4a\xe7\x61\x58\x30\x31\x96\x93\x08\xad\xf2\x0a\xfd\x05\x18\x53\xd1\x03\xea\xde\xc1\x57\x7b\x18\x61\x96\xe1\x75\x2d\x90\xa3\xbf\x91\xfa\xe6\xd5\x48\x97\x03\x36\xcd\x59\x27\xf8\x46\x7d\x6e\x91\x74\xe8\x98\x9c\x8d\xed\x11\xd1\x83\xa8\xb4\xeb\x9e\xb4\x95\x0d\x40\x61\x6d\x03\x7a\x9f\xcb\x51\xaf\x57\x80\xf1\x9f\x7f\x4c\x55\xb4\x7d\x21\x99\x3b\x27\x5b\xa5\x12\xbb\x4f\x42\xfb\x6d\xab\x0f\xe2\x93\x54\x2d\xe3\x98\xa4\x11\x6e\x2a\x21\x8f\xcc\x92\xd6\xd6\xf8\xb5\xc5\xb0\xdf\x03\x85\x4d\x40\x57\xdb\x1e\xee\x82\x49\xb0\x27\x6d\xfa\xb3\x98\x8f\x8b\x5e\x6f\x02\xbb\x17\x25\xce\x87\x07\x72\xfb\x50\xcd\xa8\xd2\x5e\xaf\xf0\x70\x5b\xe2\x26\xf5\xb8\xb0\x12\x41\xc0\xfb\x5f\xbe\xf0\xf2\xbd\x9c\x2d\x33\x7e\xc1\xe3\x07\x6b\x0a\xc3\xd7\x6b\xe3\x1e\x84\x4a\xb9\xca\x44\x98\x92\xaa\x05\xa1\x0f\x60\xf7\x16\x77\x07\x6b\xeb\xcb\x01\x5a\x3d\x30\x01\xa2\x09\x2b\x42\x69\xbc\xaf\xa1\xec\xa4\x90\x4b\xd4\xfe\x19\x83\x21\x17\xce\xb9\x3c\x15\xc9\x6d\x8a\x59\x2f\xfb\x60\xde\xb5\x64\x85\x26\x6d\x8c\xc1\xd8\x9c\xab\xe9\x0d\xbe\xc8\x58\x11\x4e\xa3\x91\x4b\xab\xc3\x12\xfb\x54\x8f\x34\x5d\x8b\x28\x9d\xe4\x39\xa1\xd7\x5c\xfd\x84\x59\x1e\x30\xd5\xd1\x06\x07\xf6\x80\xd4\x7d\xdc\x1d\x52\x48\xe5\xf7\x00\x79\x1f\xec\x1c\x7f\x48\x67\xef\x9b\xf1\xa6\x2b\xee\x71\x14\x0e\x68\x66\x67\x12\x55\x24\xb5\x75\xe5\x72\xcc\x0b\xd8\x44\x4c\xa5\x28\x65\xc6\x51\xc6\x1e\x92\xd7\xc2\x78\x24\x83\x4f\x33\x9f\x75\xee\x6e\xd2\x8c\x77\x60\xd5\xa9\xb8\xee\xc0\x6c\x08\x55\x9a\xeb\x35\x3a\x04\x1e\xba\xd9\x0e\x70\xb6\xa2\xff\xfe\xcd\x87\x75\xb4\x6e\x8d\x7f\x8d\x13\x6d\x6e\x95\x73\xa7\xb8\x39\x23\x60\x4c\x4a\x49\xe7\x67\x99\xcc\x52\x71\x4d\x3b\x79\xc6\x93\x92\x77\xee\x92\x54\x75\x48\x43\x4e\xa6\x27\x60\x78\x21\x90\x6b\x6d\xeb\x38\xed\x7f\xd4\x9f\x1c\x4d\xdd\x0a\x8a\x19\x12\xbd\x2e\xf4\xef\xb5\xe6\x2c\xb6\x4d\x6c\x96\xde\x9a\x99\x6d\xab\xb2\xb4\xe5\x14\x69\x16\x1e\xad\x6b\x7e\xf3\xee\xa0\x98\xf0\xf8\xdb\x8e\x5c\x7c\x36\x00\xf3\x3a\x77\xd4\xe2\xb3\x81\xa6\x65\x92\xa9\x8a\x87\x2f\xff\x44\xeb\x47\x38\x3e\x7b\xb6\x9e\xd0\xb3\xc1\x31\xf6\xff\x1e\x2a\x57\x0e\xc5\xa1\x7d\x0d\xd8\x1c\x3b\xdb\x31\x2f\x86\xb2\xb3\x59\x0f\x15\xda\x98\xb2\x6e\xf7\xdf\xc6\x18\x03\x8a\x12\x45\x26\x8e\xcb\x32\xef\xeb\x02\xdb\x28\xa2\x9e\x2d\xf0\x46\x5f\x3d\xf3\x10\x51\x3e\x86\x39\x4c\x98\x29\x59\x7b\x1a\x5b\x4d\xcd\x85\xaa\x6e\x6a\x24\x6b\x5a\xdd\x45\x92\x87\x2d\x40\x3b\xdd\xf6\x55\x31\xa6\x12\xa1\x90\x35\x92\x53\x04\x22\x7c\x4d\x49\x87\x50\xae\xff\xea\x53\xfc\x28\x00\x94\xf8\x00\x28\x6d\x55\x94\xec\x84\x7a\x9a\x97\x05\xe0\x54\x2e\x73\x5e\x24\xd7\xe8\x6b\x57\x01\x9b\xe6\x92\xda\x80\xcd\x54\x2e\x16\x89\x98\x9d\x28\x29\xb3\x43\xa0\x8e\xa9\x8f\xf7\x02\x42\xd3\xf7\x4d\x51\x39\x1e\x98\xb8\x56\x65\x3c\x86\xcd\x22\xc4\xec\x16\x21\x14\xf2\x41\x5b\x9e\x76\x3d\xa1\x05\x2f\x97\x99\x2a\xe3\xf1\xc4\x07\x5b\xff\x3d\xcd\xb2\x8f\x18\x7a\x44\x6f\x62\xd9\x92\xa5\xd0\xbb\x90\x66\x60\x8b\xff\xb1\x10\x67\x40\x0b\xbf\xcc\x0c\x36\xf2\x26\xcd\xc5\x2c\x97\xa9\x50\xc6\x32\x1b\x7f\x40\xb8\x52\x5e\x5b\x90\x60\x07\xac\x85\x8d\x27\x51\xcd\xba\x8b\x87\xd5\x46\xd9\x3d\x11\x6e\xcd\x85\x06\x7b\xd3\x1b\x29\x4b\xfe\xc6\xd4\xda\xa1\x45\x68\xf4\x67\x83\x05\x9a\xa3\x1f\xad\x69\x32\x9b\x7d\x80\x70\x62\xed\x92\x42\x7f\x5b\x46\x26\xcf\xca\x9e\x25\x6d\x2c\xc6\x2c\x01\x86\x5b\xe6\xb3\x44\xf1\xc6\x88\x4d\xf3\xac\xa6\x17\x6d\x61\x3d\x57\x44\x7d\x3e\x72\xcc\x27\xc8\x19\xf9\xab\x02\x71\x41\x63\x6c\xb9\x8e\xd6\x1a\x59\x68\x4a\xbc\x39\xb8\x7f\x36\x36\x86\x8e\x1e\xfe\xc9\x19\x30\xfa\x43\x5b\xfa\xef\xd5\x10\x84\x35\x86\x8a\xe5\x9a\xa0\x54\x9b\xc3\x8b\x75\x04\xe3\x2f\xc5\xc6\x27\xf3\x77\x9b\xee\x3a\xa0\xf5\x93\xd7\x23\xa7\xf6\xa0\x9d\xb6\x5a\xcf\x2a\x30\x79\x0e\x37\x3e\x62\xa4\xd1\x77\x09\xbc\x7a\x14\x8a\x08\x79\x5e\x89\xd6\x4e\x47\xa1\x72\x67\xd8\xc5\xeb\xf7\x04\x88\xe3\x2b\x39\xbb\x1f\xa1\x48\x48\x9a\x17\x41\x10\x16\xfd\xa5\x40\x3b\x4f\x5b\x18\xd1\xc2\x6e\xe4\x9f\x34\xd3\x0d\xc6\xb0\xd4\x47\xfd\xde\xb1\x07\x84\x6f\x76\xb4\x9d\x32\xd9\xc4\xdc\x58\xbd\x0e\xb6\x7d\xdf\xdd\x7a\x35\x47\xb4\x8a\xde\x90\x31\x56\xd0\x92\x25\x1a\x88\xda\x4b\x42\x97\xcc\xf2\x73\xf0\x3b\x14\x9a\x6e\x43\xd8\xde\xf7\x8e\xb6\x86\xdd\x5f\x21\x9d\xb0\x01\xf8\xcd\x97\x50\x4c\x22\xbc\x39\x1b\x6f\xd1\x86\x72\x4d\x33\xb4\x10\xb4\x34\xf0\x6a\x15\x66\x1b\x60\xd9\x61\x9a\x32\x4f\x34\x9e\x99\x6a\x30\x6d\xa0\x73\x26\x4b\x4e\xa8\x14\x6f\xb2\x74\xfa\x35\x5e\xae\x29\xf9\xbf\xff\xe7\x7f\x93\x28\xa2\x5b\x3b\x01\x22\x04\xd6\x23\xa8\xd7\x53\x2a\xf2\xa5\x22\xeb\xed\xed\xb0\x02\x7d\x00\x93\xa7\x1b\x99\x69\x9a\x0c\x76\x40\x8f\x0e\x92\xf2\x78\xaa\xb1\x2e\x95\xe2\x9d\x9c\x2e\xcb\xb8\x34\x3b\x03\xb8\x78\xbd\x63\x46\xad\x3d\xe3\xf6\xf9\x7d\xe3\xcd\xdf\xec\xdd\xc0\xb9\xed\xfd\x63\x60\x49\x42\x1f\xbc\xce\x20\x6e\x91\xed\x41\xff\x58\x53\x19\x8e\x2d\x80\xa3\x8e\x68\x71\x14\xc7\x24\x8a\x68\x66\xe8\x51\x3c\xae\x5b\x74\x1e\xb5\x9b\xd2\x20\x26\x3c\x29\xcc\x01\xdf\x47\xed\xf8\x1a\x1a\x18\x18\x5a\x92\x47\x3b\xc9\x64\x0f\xb2\x88\x64\xc1\x57\x2b\x62\x00\x54\x49\x2c\x30\xc2\xab\x11\x3a\x46\xd9\x4c\xbe\x32\xd5\xde\x33\x59\xff\x40\xfa\xe4\xc2\x8e\xf9\x3b\x1a\x9d\xef\x3d\xaa\x5e\xef\xa0\xb4\xdc\xd1\xab\xfb\xd2\x2d\x33\x82\xef\x62\x31\x5a\x0b\x0c\x76\x87\x03\x35\x5f\x3e\xf6\xd5\x67\xa3\x85\x9e\xd9\x7f\xcb\xbc\x69\xe0\x1e\x93\x35\x55\x3b\x5a\x61\xc6\xe4\x7a\xc3\x2b\x25\x3a\x57\x4a\x9c\x14\x4b\x51\x5d\x74\xfc\x4c\x0e\xd7\xac\x29\xf9\xb8\x14\x07\x5c\x7b\xaf\x5f\xf3\x91\xc9\x9a\x42\x78\xc7\x6d\x5c\x46\xc5\x33\x54\x44\x64\x3c\x7c\x89\x0c\xc3\x3e\xdf\xd9\x47\x51\xbd\x85\x4f\xf5\xca\x47\x50\xbd\x85\x4f\xe3\xca\x83\x68\x5c\x21\x38\x0c\x72\x92\x8a\xb9\x24\x87\xdc\xa5\xaa\x0d\x58\x5a\xe9\xab\x05\x76\x56\x7a\x07\x9d\x73\x28\xf8\xfb\x12\xda\x9c\xc3\xae\xeb\x63\x7b\x25\xeb\xed\xcd\x76\x1d\x13\xd3\x03\xd1\xfc\x47\xd5\x5b\x47\x6f\xe5\xe1\x68\x45\xaf\x86\x20\x07\xa3\x80\x83\x39\x62\x09\x98\xe0\xb7\xdc\x35\x7f\x1c\xd0\xb0\xe8\x84\x0a\x18\xe2\xa0\x43\x08\xa7\xee\x11\x39\x0a\x18\x3a\x6f\x8c\x9c\x03\x3e\x42\x8a\x54\x8a\x8b\x50\xb1\x5a\x5a\x04\x33\xd9\x4b\xfe\x4d\x7d\xd4\xf0\x20\xd4\x93\xd2\xe4\xc0\xa5\xcd\x37\x8e\xf1\xfe\x0c\x41\x8a\xc4\xa0\xee\x2c\x8c\x22\x1b\x2b\xf3\x9a\xab\x4f\x76\x00\xe0\x19\x1a\x91\x1f\xaa\x8e\xb1\xe9\x2f\x72\xc6\xbd\x1e\x5b\x7a\x09\x23\x4d\xa1\x60\x3b\x15\x6d\xe1\x5d\xb7\x5e\x7e\x55\xd4\xbe\x11\xef\x7f\xd5\xcf\x3b\x00\xa9\x9a\xd5\x3f\xaa\xc6\xf3\x6b\x8a\xde\xc4\x7b\x5a\x59\x10\x55\xf8\xd4\x05\x62\xf3\x1d\x03\x56\xa2\x11\x60\x9b\x0d\xb2\x37\xe7\xe2\x1f\xc5\x3c\x1f\xc9\x2a\xdb\x93\xbf\x15\x7c\x38\x33\x7d\x74\x78\xe8\x91\xd3\x24\x4f\x4f\x2b\x34\x0c\x80\x25\x4f\xd4\x4d\x9d\x21\xf8\x5b\x29\x85\xe6\x21\x1f\xe0\xab\x69\x54\xa2\x6e\x08\x05\x0e\xed\xcd\x87\x0f\x1f\x4e\x7e\xfa\xb5\xf3\x01\x8a\x0c\x6e\x5b\x53\x5b\x73\xba\x2c\x32\x53\x73\xfa\xdb\xc7\x9f\x1d\x3f\xa7\xcb\x3b\xa4\x17\xf2\x9e\x8a\xbc\xda\x8e\x2e\xc0\xbe\xdd\x4f\x6c\x25\x1c\xe2\x33\x26\x17\xb4\x43\xbc\xd6\x1c\xa2\xd1\x99\xb6\x6f\xcd\x0f\xdb\x12\x5f\xfa\xed\x26\x8f\xa0\x2d\xf2\x3c\x3f\x49\xe5\x49\x05\x61\xb6\x9f\xc4\xe4\x2a\xe3\xde\x81\x2a\x80\x10\x93\x11\x9e\xa8\x43\x01\xcd\xa3\xfc\xf3\xff\xf1\x82\x68\xb3\x3f\xbe\xe8\xf9\x48\x09\xf3\x8c\xdf\xa6\x53\x6e\x90\xe1\x7e\x99\x8f\x19\x30\xee\x0e\xd7\x6b\x5a\xde\xc8\xbb\x1f\x4c\x81\x6f\x8b\x51\x17\x18\xb8\x26\xbe\xfc\x14\xcb\x34\x31\x3b\xdb\xec\xc0\x19\xd4\xd6\x2a\x6f\x84\x14\xe3\xac\x8d\x53\xf6\xaf\x17\xb0\x81\x85\xbc\x92\x1a\x76\x1f\x56\x1b\xf7\x43\xd3\xc7\x0f\x10\xc0\x9c\x40\xf3\x12\x63\xff\x9f\xe2\x5b\xfd\x4b\xa1\xe3\x86\xd7\x01\xbe\xab\xb2\x25\xed\x97\xfb\x1e\x46\xca\x1b\x29\x56\x0d\x72\xe0\x58\x26\x65\xc6\x02\xa2\x90\x78\x64\xca\xbe\x29\xb4\x61\x72\xdd\x1f\x59\x6f\x95\x56\xa7\xfd\x9f\x53\xf1\xb5\x95\x0c\x31\x6d\xa9\x92\xae\x1f\xea\x84\x44\xd4\x16\xed\x90\x95\x6f\x21\x4a\xea\x14\xb0\x77\xd6\x34\x19\xbb\x47\xf2\xde\x4e\xa5\xec\x99\x01\x80\x90\xc2\x7a\x4d\x9a\x66\xe1\x2e\x18\x52\xbf\x81\xf1\xd9\xe0\x6c\xaf\xe0\x7d\x9f\xd3\xfb\x7f\x10\x3a\x1a\xa0\xfc\xc1\x92\x62\x01\x6d\x08\x75\xfa\xc9\xf8\x61\x4d\x11\x51\xa0\xd4\x17\x45\x26\xd0\xf5\x86\x4a\xb8\x82\x24\xc2\x64\x60\x6d\x08\x3d\xb1\xd7\x43\x84\x70\x86\x74\xf7\x75\x41\x76\x46\x56\x4a\xbc\x21\x98\xc3\x69\xea\x1b\x0f\x21\x4e\x30\x6d\x94\x95\x60\xf2\xbb\x0e\xe0\xbf\x4f\x72\x59\x4c\xb9\xde\x46\xd9\x97\xc2\xc4\xe7\xad\xbe\xc3\x86\x84\x0a\x3b\x1d\x55\x22\x34\x5c\x9b\xb2\x1a\x31\xd4\x2f\xed\x15\xa7\x99\x2d\x04\x21\x32\x04\x95\x94\x4d\x69\xed\xe6\xce\x0b\x4f\x78\x6a\x55\xca\x87\xcb\x4f\xeb\xe2\x53\xd7\xeb\x48\x40\x9a\xee\x4c\x62\x52\x5c\x34\x2f\x10\x60\x50\xe0\x2b\xfe\x1a\x93\xa8\x7e\x6f\xfb\x76\xe6\x36\x7c\xe5\xf7\x65\xd8\xf6\xd5\xa2\x86\x2c\xb0\x0a\x23\xba\x93\x3e\x06\x91\x8b\x4f\xb4\xda\x0e\x77\xb1\x32\x9a\xe4\x45\x57\xdf\x1d\x3c\x52\x93\x9a\xc6\x7d\xae\x60\x59\xd3\xf4\x04\xcc\x6d\x6d\xad\x28\x5a\x7b\x1e\x38\x87\xc2\x37\xb7\x19\x27\x26\x91\xf5\x9e\x65\x20\xbd\xd4\xda\xc3\xce\x76\x37\x3c\xb1\x3b\xb0\xa3\x92\xee\x59\x66\x9f\xf2\x44\xc4\xe4\x4c\x33\x96\xce\x6c\x81\x44\xbb\xf6\x4d\xf3\x63\x6e\x7f\xa3\xc8\x81\x87\x5d\x8a\x0c\x43\x6a\x6e\x15\xbc\x1d\x79\x08\xa0\xbb\x83\x4e\x00\x42\x92\x3d\xc7\xc0\xd4\x44\x5b\xfe\x03\x3e\x6c\xcb\x87\x31\x84\xf6\x1f\xf0\x55\x0c\xd5\x7e\xe8\x27\xe1\xd1\x51\x62\x47\xcb\x13\x18\xe0\x5b\x99\xa5\x38\xb9\x23\xae\x2c\x7c\xc4\x71\xf7\x30\xcf\x8e\x7d\xf1\x85\x8e\x87\xf7\x0d\xe2\xe9\x0e\x8e\x70\x08\x48\x68\x15\x67\xe3\x31\xda\x94\x3e\x02\xf2\xa9\x8b\x1e\x2b\xb4\xb7\xde\x31\x4d\x27\x03\xaa\x11\x44\x38\xbf\x35\x25\x1d\xbc\x61\x1d\x08\xb7\xad\x89\xca\x03\x59\x9e\x7d\xc1\x5c\xff\x51\x94\x08\x4d\x36\xf9\x9d\x23\xa9\x93\xca\x42\xa2\x8d\x43\xdf\x77\xe4\x44\x72\xbb\xef\x46\xb5\x49\xf3\xf6\x82\xde\xc4\xd0\xd0\x9a\x50\x3e\x25\x35\xf4\x23\xaf\xe5\xce\x73\xb6\xb8\x26\xf4\xa1\x2c\xa6\x31\x39\x4d\x17\xc9\x35\x2f\x4f\x75\x93\x93\x42\x5e\xf1\x64\xf9\xad\x9f\x8b\x6b\x42\x93\x4c\xc5\xe4\x23\x96\x90\x75\x74\x98\x94\x6d\x0b\x95\xfa\xa8\xb4\xc7\xff\x19\xd8\x61\xe0\xf6\xfe\x83\x72\xc3\x1e\x1c\x86\x65\x50\xb5\xc9\xc3\xb6\x04\x66\x32\xb8\x0c\xd8\xd9\x63\xd8\x57\x75\x18\x4a\xb0\x53\xf1\x04\xe7\x15\xa7\xaa\xc9\x6e\x6e\xb8\xd9\x92\x4a\x46\x4e\x77\x4d\xb5\xf2\x7a\xdc\xce\xc9\x19\x91\x7a\x9d\x08\x93\x77\x28\xac\x52\x3b\x78\xc0\x4d\xad\x49\x75\x14\xf6\xf3\xc5\x4a\xc6\x92\xb6\xa9\x72\x74\x27\xf0\x74\x95\x5e\x83\x9c\x1d\x4b\x7e\x5f\x7e\x58\xfd\x21\xfc\x70\x8d\xd9\x5f\x66\x19\x57\x27\xde\x97\xdb\xd9\x5e\x15\x52\x83\x24\x14\xca\xbd\xf1\x1a\x45\xa8\x06\xb0\xf6\xc8\x8f\x98\x82\x39\x2c\x87\x0f\xff\x83\x69\x10\x19\xf1\xa0\x19\xfa\x0f\xe6\xf3\x8f\x89\xf3\xad\x49\xd6\xf6\xfc\x4e\xa1\x62\x9c\x72\x06\xd2\x63\x12\xd1\x70\x40\x65\xff\x9a\xab\x28\xe4\x7e\x5c\x2e\x51\xf7\x45\x50\x55\x2a\xd4\x2a\x1a\x46\x88\xd9\xe1\xa2\x91\x0a\x8d\x9c\xe3\x11\xa6\x6a\xb4\x02\xa6\x45\x05\x9f\x6b\x26\x67\xed\x1b\xd8\xa2\x50\x7c\x6c\xc2\x8c\x7f\x1c\x8a\x29\xc2\xd4\x25\x56\x4a\xf2\x1c\xb1\xcc\x94\x15\xe1\xd2\x85\x82\xbc\x4d\xf9\x5d\x69\x60\x18\xbe\xcf\x59\x11\x66\x2e\xea\xa3\xf7\x1e\x5f\xcf\x59\x11\xce\x22\x7a\xe3\xbf\xc6\x13\x8e\xef\x17\xac\x08\x6f\x22\x7a\xeb\xbf\x17\x52\x9d\xcc\xe5\x52\xcc\xb0\xca\x3d\x2b\xc2\xdb\x88\x5e\xb3\xb0\x74\x17\xa2\x66\xbd\xda\x28\x8e\xe8\x5b\xe6\x15\xf1\x59\x5a\xf0\xa9\xa2\x6f\xbc\xc2\x5f\x4c\x94\x0a\xa8\xbf\x03\x83\xda\x1b\x77\x4d\x8d\xa0\x01\xec\x95\x11\xe7\x9c\x12\x7a\x83\x13\x88\xa7\xd5\x49\xd8\xdb\x03\xee\x5d\xd5\x36\x77\x6d\xb7\x03\x8b\x7a\x63\x3b\x01\x83\x49\x62\x53\x68\x3b\x9c\x1f\x31\x99\x4a\x9c\xa9\x3b\xb4\xc2\xdf\xd8\x16\xdb\x2e\x17\xd5\x1c\xb7\x4f\xf2\x2d\x7d\x98\x17\x72\x01\x1b\xa3\x29\x40\xb3\xd0\x1d\xcb\x7a\x43\x1f\xec\x08\xf7\xfe\x08\x5b\x61\x94\x39\x94\xf1\x10\x73\x64\x35\x4f\x53\x7c\x36\x1c\xd0\xf6\x53\x14\x9f\x0d\x87\x74\xf3\x7c\xc6\x67\xc3\x33\xda\x72\xac\xe3\xb3\xe1\x93\xbd\x10\xf0\x0f\xb0\xed\x7f\xfc\x7d\x85\xe2\xd2\xbf\xb2\xa3\xea\xb8\x17\x4b\x11\xba\x33\x4a\x7d\x9e\xa5\xfa\x34\x48\xe9\x84\xdb\xbe\x15\x37\x56\xdc\x4e\xfb\x7b\xcd\x6d\x68\xd5\x3f\xdf\xff\x34\x0b\x89\x21\xd5\x09\x5a\xf0\x3c\xd4\xa6\x14\x9f\x0d\x5e\xec\xdb\xce\xe1\x71\x16\xdb\x7f\x24\xbc\xf4\xa8\x3d\x37\x28\xf7\xcd\x3e\xc7\x13\x5a\xb0\xee\x80\x4a\xd6\x1d\xd2\xc4\x2a\xe4\x55\x71\xef\xfc\x4a\x52\x4d\xb1\x8f\x1b\xc9\xa0\x27\x61\x34\xea\x86\x05\x0b\x53\x56\xd6\xe2\x15\xa3\xe3\x30\x58\xab\xa6\xd6\xf0\xbb\xab\x56\x2b\x4b\x46\x80\x48\x76\xa4\x87\x8c\x46\x95\x2b\xb1\xd4\x53\x48\x18\x5f\xcf\x53\x91\x64\xd9\xfd\x83\x9e\x40\xb7\x08\x82\xb2\x8f\xbb\x53\x3d\x85\x91\xab\x94\xce\x43\x19\x61\x22\xb3\xc4\x45\x0d\x16\xeb\xa6\x24\xd4\xda\x54\xd6\x43\x4b\xfb\x89\x75\xd2\x79\xd8\x58\x5f\x27\x15\x26\xd0\x92\x57\x91\x43\x57\x23\x1c\x51\xf0\xbb\xce\xe5\x7d\xce\xbd\x94\x6c\x59\x3a\xeb\x24\x4a\xf1\x45\xae\x3a\x4a\x76\x66\x1c\x13\x0d\x2e\x0b\x4c\x1b\x07\x7d\x5f\x65\x55\x30\x27\x12\xad\xd7\xa1\xcf\x43\x83\x4a\xbc\x70\xf6\xe1\x8d\x5b\x62\xae\x47\x03\xa5\xd4\x90\x5a\xcd\xf7\xc0\x37\xfa\x6a\x41\x70\xb5\xba\x95\xa4\xc6\xc7\x75\x47\x6b\xda\x11\xd6\x2e\xd2\x6f\xa9\x28\xe3\x71\xd9\x07\x46\x6a\x42\xe7\xa9\x98\x21\x69\xb7\xcd\x32\x1c\xf9\x0f\xcd\x7d\x08\x73\x06\x41\x4f\x66\xc0\x78\x7f\x9e\x66\x8a\x17\x6d\xc2\x63\x54\xaa\x31\xc6\xf8\x3a\x1a\x0f\xc0\x7f\xac\x88\x1e\x04\x92\x61\xbb\x39\x14\x64\xa6\x6a\x9a\xc2\x96\x6a\x05\x56\x33\xa7\x6a\x5c\x50\x31\xd9\xc3\x4b\x5d\x73\xf5\xc1\x98\xee\x59\xe5\x9f\x59\x65\xb5\x0f\x18\x68\x44\x86\x8a\x9e\x41\x44\xd6\xf1\x60\x42\x13\x26\xc6\xc3\x09\x2d\xed\x25\xb4\x01\x59\x2f\xc2\x92\x15\x95\x96\xdf\x78\x72\x6d\x53\xb2\x3b\x24\x6c\x11\x23\x0e\xd8\xa9\xec\x06\x6c\x4f\x71\xd5\x29\xb5\x4a\x94\x38\x59\x47\x31\x21\xbb\x6c\xf9\xb6\x30\x6d\xfb\xac\x48\x36\x55\x98\x27\xce\xb2\x61\x4d\xcb\xad\xad\xe7\x5b\xd6\x63\xe5\x96\xfe\xcc\xa3\x28\x8a\xb7\xf5\x53\x21\x0d\x80\xfe\xbb\x18\x88\x9d\xb7\x28\x3e\x1b\x68\xcc\xbc\xe3\xf6\xc4\x67\x83\xa7\xb4\x79\x51\x01\x6b\xef\xc3\x1b\xff\x49\x0c\xf7\xdc\xc2\x1f\x23\xd1\xc3\xc3\x92\xce\xfc\x6e\x76\x09\x8f\x87\xce\x9e\xe4\x17\xa9\x3a\x40\x0a\xf7\x8f\xb0\x26\x19\x1e\x67\xb6\xf6\xef\x81\xb7\x69\xc3\x02\x35\x57\xc6\xda\xd9\xac\x44\x23\xbe\x6f\xa3\x09\x7c\x5f\xab\xe9\x99\x97\xf4\x4d\xf8\xfb\x22\xcc\x6d\xb8\xfb\xc6\xa5\xa8\x99\x66\x62\xf5\x1b\x56\x84\x73\x13\x75\x75\x1f\x26\xba\x65\x45\xb8\x78\x94\xc0\xaf\x42\x2f\xa9\x8f\x5e\x3e\xea\x77\x07\x00\x64\x2b\xe2\xf2\x0d\x34\x12\x95\x38\xa7\xfe\xb6\x58\xe3\x90\xb5\xcc\x50\xd4\x07\x63\xa2\xb5\x85\xb3\x97\x52\x66\x2d\x68\x6f\x87\x78\x6f\x03\x7b\x01\x85\xc2\x9b\x28\x20\x7a\xb4\x80\x6d\x3b\x3b\x75\x5b\x41\x5b\x87\x26\x78\x0b\x9a\x00\xbf\x1a\x6a\x10\x67\x7b\x18\x56\x8b\xbb\x9b\x5a\x5f\xa4\x3b\x1f\x60\x71\xf1\x8e\x5d\xc0\xf6\x6d\x35\x0c\xe6\xde\x2b\xff\x9c\x55\x8b\x01\x89\x22\x4a\x35\x4d\xbf\x95\x83\x17\xfa\xb3\x7a\xe2\xb2\xf6\xf5\x78\x15\xb6\x39\x23\x6e\x9b\xc8\x4d\x7d\x22\x46\xbc\x5a\x75\x08\x1e\x5a\xfb\x44\xb4\xee\x94\x57\x9a\x38\x7e\x71\xa4\x88\x74\xc7\x97\xcf\xaa\x39\x9a\x4f\x63\xfd\xc9\xbc\x73\xac\xaf\xc2\xa1\x7e\xb8\xb6\x8f\xdf\xf3\x78\xb6\x7a\x36\x18\x28\x73\x54\xb3\x4a\x32\x69\x04\x8b\xf0\x13\x22\xe7\x1d\x33\xb6\x2f\x61\x35\x7b\xe5\x8a\x74\x67\x9a\x20\x39\xd0\xa9\xf8\x77\x25\x48\x5a\xe0\x73\x7c\x36\x18\x36\xab\x35\x20\x7e\x7c\x06\x29\x44\x76\xa0\x8f\xf8\x0c\xf3\x88\x1c\x4f\xda\xfc\xbb\x37\xda\xdc\x8d\x35\x51\x42\xf1\x18\x7c\x55\x12\x8a\xff\x37\x89\xa0\xb0\x81\x84\x4c\x48\xae\xaa\xc0\x20\x1d\x0c\xe8\x72\x24\xcc\x29\x5b\x61\x8e\xbb\xda\xed\xe0\xe6\x68\x63\x44\x9c\x20\x28\xe0\xc1\x05\xd5\x24\x84\x80\xd2\x3d\x62\xfa\x7d\xc7\xcc\x23\xd3\xd6\xf4\x61\x4d\xc7\x67\x83\x97\x93\x68\xf4\x4f\xff\x2f\x00\x00\xff\xff\x64\xa9\xce\x6d\xa0\x27\x03\x00") func jsScriptJsBytes() ([]byte, error) { return bindataRead( _jsScriptJs, "js/script.js", ) } func jsScriptJs() (*asset, error) { bytes, err := jsScriptJsBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "js/script.js", size: 206752, mode: os.FileMode(436), modTime: time.Unix(1492020681, 0)} a := &asset{bytes: bytes, info: info} return a, nil } // Asset loads and returns the asset for the given name. // It returns an error if the asset could not be found or // could not be loaded. func Asset(name string) ([]byte, error) { cannonicalName := strings.Replace(name, "\\", "/", -1) if f, ok := _bindata[cannonicalName]; ok { a, err := f() if err != nil { return nil, fmt.Errorf("asset %s can't read by error: %v", name, err) } return a.bytes, nil } return nil, fmt.Errorf("asset %s not found", name) } // MustAsset is like Asset but panics when Asset would return an error. // It simplifies safe initialization of global variables. func MustAsset(name string) []byte { a, err := Asset(name) if err != nil { panic("asset: Asset(" + name + "): " + err.Error()) } return a } // AssetInfo loads and returns the asset info for the given name. // It returns an error if the asset could not be found or // could not be loaded. func AssetInfo(name string) (os.FileInfo, error) { cannonicalName := strings.Replace(name, "\\", "/", -1) if f, ok := _bindata[cannonicalName]; ok { a, err := f() if err != nil { return nil, fmt.Errorf("assetInfo %s can't read by error: %v", name, err) } return a.info, nil } return nil, fmt.Errorf("assetInfo %s not found", name) } // AssetNames returns the names of the assets. func AssetNames() []string { names := make([]string, 0, len(_bindata)) for name := range _bindata { names = append(names, name) } return names } // _bindata is a table, holding each asset generator, mapped to its name. var _bindata = map[string]func() (*asset, error){ "css/.keep": cssKeep, "css/application.css": cssApplicationCss, "css/application.css.map": cssApplicationCssMap, "css/fonts.css": cssFontsCss, "fonts/inconsolata-bold-webfont.eot": fontsInconsolataBoldWebfontEot, "fonts/inconsolata-bold-webfont.svg": fontsInconsolataBoldWebfontSvg, "fonts/inconsolata-bold-webfont.ttf": fontsInconsolataBoldWebfontTtf, "fonts/inconsolata-bold-webfont.woff": fontsInconsolataBoldWebfontWoff, "fonts/inconsolata-regular-webfont.eot": fontsInconsolataRegularWebfontEot, "fonts/inconsolata-regular-webfont.svg": fontsInconsolataRegularWebfontSvg, "fonts/inconsolata-regular-webfont.ttf": fontsInconsolataRegularWebfontTtf, "fonts/inconsolata-regular-webfont.woff": fontsInconsolataRegularWebfontWoff, "fonts/roboto-bold-webfont.eot": fontsRobotoBoldWebfontEot, "fonts/roboto-bold-webfont.svg": fontsRobotoBoldWebfontSvg, "fonts/roboto-bold-webfont.ttf": fontsRobotoBoldWebfontTtf, "fonts/roboto-bold-webfont.woff": fontsRobotoBoldWebfontWoff, "fonts/roboto-regular-webfont.eot": fontsRobotoRegularWebfontEot, "fonts/roboto-regular-webfont.svg": fontsRobotoRegularWebfontSvg, "fonts/roboto-regular-webfont.ttf": fontsRobotoRegularWebfontTtf, "fonts/roboto-regular-webfont.woff": fontsRobotoRegularWebfontWoff, "fonts/robotoslab-bold-webfont.eot": fontsRobotoslabBoldWebfontEot, "fonts/robotoslab-bold-webfont.svg": fontsRobotoslabBoldWebfontSvg, "fonts/robotoslab-bold-webfont.ttf": fontsRobotoslabBoldWebfontTtf, "fonts/robotoslab-bold-webfont.woff": fontsRobotoslabBoldWebfontWoff, "images/bullet-connections-2.png": imagesBulletConnections2Png, "images/bullet-connections.png": imagesBulletConnectionsPng, "images/bullet-devices-2.png": imagesBulletDevices2Png, "images/bullet-devices.png": imagesBulletDevicesPng, "images/delete.png": imagesDeletePng, "images/devices-image-2.png": imagesDevicesImage2Png, "images/devices-image.png": imagesDevicesImagePng, "images/logo-robeaux.png": imagesLogoRobeauxPng, "images/robots-icon_03.png": imagesRobotsIcon_03Png, "index.html": indexHtml, "js/.keep": jsKeep, "js/script.js": jsScriptJs, } // AssetDir returns the file names below a certain // directory embedded in the file by go-bindata. // For example if you run go-bindata on data/... and data contains the // following hierarchy: // // data/ // foo.txt // img/ // a.png // b.png // // then AssetDir("data") would return []string{"foo.txt", "img"} // AssetDir("data/img") would return []string{"a.png", "b.png"} // AssetDir("foo.txt") and AssetDir("notexist") would return an error // AssetDir("") will return []string{"data"}. func AssetDir(name string) ([]string, error) { node := _bintree if len(name) != 0 { cannonicalName := strings.Replace(name, "\\", "/", -1) pathList := strings.Split(cannonicalName, "/") for _, p := range pathList { node = node.Children[p] if node == nil { return nil, fmt.Errorf("asset %s not found", name) } } } if node.Func != nil { return nil, fmt.Errorf("asset %s not found", name) } rv := make([]string, 0, len(node.Children)) for childName := range node.Children { rv = append(rv, childName) } return rv, nil } type bintree struct { Func func() (*asset, error) Children map[string]*bintree } var _bintree = &bintree{nil, map[string]*bintree{ "css": {nil, map[string]*bintree{ ".keep": {cssKeep, map[string]*bintree{}}, "application.css": {cssApplicationCss, map[string]*bintree{}}, "application.css.map": {cssApplicationCssMap, map[string]*bintree{}}, "fonts.css": {cssFontsCss, map[string]*bintree{}}, }}, "fonts": {nil, map[string]*bintree{ "inconsolata-bold-webfont.eot": {fontsInconsolataBoldWebfontEot, map[string]*bintree{}}, "inconsolata-bold-webfont.svg": {fontsInconsolataBoldWebfontSvg, map[string]*bintree{}}, "inconsolata-bold-webfont.ttf": {fontsInconsolataBoldWebfontTtf, map[string]*bintree{}}, "inconsolata-bold-webfont.woff": {fontsInconsolataBoldWebfontWoff, map[string]*bintree{}}, "inconsolata-regular-webfont.eot": {fontsInconsolataRegularWebfontEot, map[string]*bintree{}}, "inconsolata-regular-webfont.svg": {fontsInconsolataRegularWebfontSvg, map[string]*bintree{}}, "inconsolata-regular-webfont.ttf": {fontsInconsolataRegularWebfontTtf, map[string]*bintree{}}, "inconsolata-regular-webfont.woff": {fontsInconsolataRegularWebfontWoff, map[string]*bintree{}}, "roboto-bold-webfont.eot": {fontsRobotoBoldWebfontEot, map[string]*bintree{}}, "roboto-bold-webfont.svg": {fontsRobotoBoldWebfontSvg, map[string]*bintree{}}, "roboto-bold-webfont.ttf": {fontsRobotoBoldWebfontTtf, map[string]*bintree{}}, "roboto-bold-webfont.woff": {fontsRobotoBoldWebfontWoff, map[string]*bintree{}}, "roboto-regular-webfont.eot": {fontsRobotoRegularWebfontEot, map[string]*bintree{}}, "roboto-regular-webfont.svg": {fontsRobotoRegularWebfontSvg, map[string]*bintree{}}, "roboto-regular-webfont.ttf": {fontsRobotoRegularWebfontTtf, map[string]*bintree{}}, "roboto-regular-webfont.woff": {fontsRobotoRegularWebfontWoff, map[string]*bintree{}}, "robotoslab-bold-webfont.eot": {fontsRobotoslabBoldWebfontEot, map[string]*bintree{}}, "robotoslab-bold-webfont.svg": {fontsRobotoslabBoldWebfontSvg, map[string]*bintree{}}, "robotoslab-bold-webfont.ttf": {fontsRobotoslabBoldWebfontTtf, map[string]*bintree{}}, "robotoslab-bold-webfont.woff": {fontsRobotoslabBoldWebfontWoff, map[string]*bintree{}}, }}, "images": {nil, map[string]*bintree{ "bullet-connections-2.png": {imagesBulletConnections2Png, map[string]*bintree{}}, "bullet-connections.png": {imagesBulletConnectionsPng, map[string]*bintree{}}, "bullet-devices-2.png": {imagesBulletDevices2Png, map[string]*bintree{}}, "bullet-devices.png": {imagesBulletDevicesPng, map[string]*bintree{}}, "delete.png": {imagesDeletePng, map[string]*bintree{}}, "devices-image-2.png": {imagesDevicesImage2Png, map[string]*bintree{}}, "devices-image.png": {imagesDevicesImagePng, map[string]*bintree{}}, "logo-robeaux.png": {imagesLogoRobeauxPng, map[string]*bintree{}}, "robots-icon_03.png": {imagesRobotsIcon_03Png, map[string]*bintree{}}, }}, "index.html": {indexHtml, map[string]*bintree{}}, "js": {nil, map[string]*bintree{ ".keep": {jsKeep, map[string]*bintree{}}, "script.js": {jsScriptJs, map[string]*bintree{}}, }}, }} // RestoreAsset restores an asset under the given directory func RestoreAsset(dir, name string) error { data, err := Asset(name) if err != nil { return err } info, err := AssetInfo(name) if err != nil { return err } err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0o755)) if err != nil { return err } err = os.WriteFile(_filePath(dir, name), data, info.Mode()) if err != nil { return err } err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime()) if err != nil { return err } return nil } // RestoreAssets restores an asset under the given directory recursively func RestoreAssets(dir, name string) error { children, err := AssetDir(name) // File if err != nil { return RestoreAsset(dir, name) } // Dir for _, child := range children { err = RestoreAssets(dir, filepath.Join(name, child)) if err != nil { return err } } return nil } func _filePath(dir, name string) string { cannonicalName := strings.Replace(name, "\\", "/", -1) return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) } ================================================ FILE: appveyor.yml ================================================ version: "{build}" image: Visual Studio 2019 clone_folder: c:\gopath\src\gobot.io\x\gobot environment: PATH: C:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin;%PATH% GOPATH: c:\gopath before_test: - go version - go env build_script: - go test -v -cpu=2 . - go test -v -cpu=2 ./drivers/aio/... - go test -v -cpu=2 ./drivers/ble/. - go test -v -cpu=2 ./drivers/ble/parrot/. - go test -v -cpu=2 ./drivers/ble/sphero/. - go test -v -cpu=2 ./drivers/serial/... - go test -v -cpu=2 ./platforms/bleclient/... - go test -v -cpu=2 ./platforms/dji/... - go test -v -cpu=2 ./platforms/firmata/... - go test -v -cpu=2 ./platforms/joystick/... - go test -v -cpu=2 ./platforms/parrot/... - go test -v -cpu=2 ./platforms/serialport/... - cd .. ================================================ FILE: commander.go ================================================ package gobot type commander struct { commands map[string]func(map[string]interface{}) interface{} } // Commander is the interface which describes the behaviour for a Driver or Adaptor // which exposes API commands. type Commander interface { // Command returns a command given a name. Returns nil if the command is not found. Command(name string) (command func(map[string]interface{}) interface{}) // Commands returns a map of commands. Commands() (commands map[string]func(map[string]interface{}) interface{}) // AddCommand adds a command given a name. AddCommand(name string, command func(map[string]interface{}) interface{}) } // NewCommander returns a new Commander. func NewCommander() Commander { return &commander{ commands: make(map[string]func(map[string]interface{}) interface{}), } } // Command returns the command interface when passed a valid command name func (c *commander) Command(name string) func(map[string]interface{}) interface{} { return c.commands[name] } // Commands returns the entire map of valid commands func (c *commander) Commands() map[string]func(map[string]interface{}) interface{} { return c.commands } // AddCommand adds a new command, when passed a command name and the command interface. func (c *commander) AddCommand(name string, command func(map[string]interface{}) interface{}) { c.commands[name] = command } ================================================ FILE: commander_test.go ================================================ package gobot import ( "testing" "github.com/stretchr/testify/assert" ) func TestCommander(t *testing.T) { // arrange c := NewCommander() c.AddCommand("test", func(map[string]interface{}) interface{} { return "hi" }) // act && assert assert.Len(t, c.Commands(), 1) assert.NotNil(t, c.Command("test")) assert.Nil(t, c.Command("booyeah")) } ================================================ FILE: connection.go ================================================ package gobot import ( "fmt" "log" "reflect" multierror "github.com/hashicorp/go-multierror" ) // JSONConnection is a JSON representation of a Connection. type JSONConnection struct { Name string `json:"name"` Adaptor string `json:"adaptor"` } // NewJSONConnection returns a JSONConnection given a Connection. func NewJSONConnection(connection Connection) *JSONConnection { return &JSONConnection{ Name: connection.Name(), Adaptor: reflect.TypeOf(connection).String(), } } // A Connection is an instance of an Adaptor type Connection Adaptor // Connections represents a collection of Connection type Connections []Connection // Len returns connections length func (c *Connections) Len() int { return len(*c) } // Each enumerates through the Connections and calls specified callback function. func (c *Connections) Each(f func(Connection)) { for _, connection := range *c { f(connection) } } // Start calls Connect on each Connection in c func (c *Connections) Start() error { log.Printf("Starting %d connections...", len(*c)) var err error for _, connection := range *c { info := "Starting connection " + connection.Name() if porter, ok := connection.(Porter); ok { info = info + " on port " + porter.Port() } log.Println(info + "...") if cerr := connection.Connect(); cerr != nil { err = multierror.Append(err, fmt.Errorf("'%s' connect error: %w", connection.Name(), cerr)) } } return err } // Finalize calls Finalize on each Connection in c func (c *Connections) Finalize() error { log.Printf("Finalize %d connections...", len(*c)) var err error for _, connection := range *c { if cerr := connection.Finalize(); cerr != nil { err = multierror.Append(err, fmt.Errorf("'%s' finalize error: %w", connection.Name(), cerr)) } } return err } ================================================ FILE: debug.go ================================================ package gobot import "fmt" func Debuglnf(isDebug bool, format string, a ...interface{}) { if isDebug { msg := fmt.Sprintf(format, a...) fmt.Printf(": %s\n", msg) } } ================================================ FILE: device.go ================================================ package gobot import ( "fmt" "log" "reflect" multierror "github.com/hashicorp/go-multierror" ) // JSONDevice is a JSON representation of a Device. type JSONDevice struct { Name string `json:"name"` Driver string `json:"driver"` Connection string `json:"connection"` Commands []string `json:"commands"` } // NewJSONDevice returns a JSONDevice given a Device. func NewJSONDevice(device Device) *JSONDevice { jsonDevice := &JSONDevice{ Name: device.Name(), Driver: reflect.TypeOf(device).String(), Commands: []string{}, Connection: "", } if device.Connection() != nil { jsonDevice.Connection = device.Connection().Name() } if commander, ok := device.(Commander); ok { for command := range commander.Commands() { jsonDevice.Commands = append(jsonDevice.Commands, command) } } return jsonDevice } // A Device is an instnace of a Driver type Device Driver // Devices represents a collection of Device type Devices []Device // Len returns devices length func (d *Devices) Len() int { return len(*d) } // Each enumerates through the Devices and calls specified callback function. func (d *Devices) Each(f func(Device)) { for _, device := range *d { f(device) } } // Start calls Start on each Device in d func (d *Devices) Start() error { log.Printf("Starting %d devices...", d.Len()) var err error for _, device := range *d { info := "Starting device " + device.Name() if pinner, ok := device.(Pinner); ok { info = info + " on pin " + pinner.Pin() } log.Println(info + "...") if derr := device.Start(); derr != nil { err = multierror.Append(err, fmt.Errorf("'%s' start error: %w", device.Name(), derr)) } } return err } // Halt calls Halt on each Device in d func (d *Devices) Halt() error { log.Printf("Halt %d devices...", d.Len()) var err error for _, device := range *d { if derr := device.Halt(); derr != nil { err = multierror.Append(err, fmt.Errorf("'%s' halt error: %w", device.Name(), derr)) } } return err } ================================================ FILE: doc.go ================================================ // Copyright 2014-2018 The Hybrid Group. All rights reserved. /* Package gobot is the primary entrypoint for Gobot (http://gobot.io), a framework for robotics, physical computing, and the Internet of Things written using the Go programming language . It provides a simple, yet powerful way to create solutions that incorporate multiple, different hardware devices at the same time. # Classic Gobot Here is a "Classic Gobot" program that blinks an LED using an Arduino: package main import ( "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/firmata" ) func main() { firmataAdaptor := firmata.NewAdaptor("/dev/ttyACM0") led := gpio.NewLedDriver(firmataAdaptor, "13") work := func() { gobot.Every(1*time.Second, func() { if err := led.Toggle(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("bot", []gobot.Connection{firmataAdaptor}, []gobot.Device{led}, work, ) if err := robot.Start(); err != nil { panic(err) } } # Metal Gobot You can also use Metal Gobot and pick and choose from the various Gobot packages to control hardware with nothing but pure idiomatic Golang code. For example: package main import ( "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/intel-iot/edison" "time" ) func main() { e := edison.NewAdaptor() if err := e.Connect(); err != nil { fmt.Println(err) } led := gpio.NewLedDriver(e, "13") if err := led.Start(); err != nil { fmt.Println(err) } for { if err := led.Toggle(); err != nil { fmt.Println(err) } time.Sleep(1000 * time.Millisecond) } } # Manager Gobot Finally, you can use Manager Gobot to add the complete Gobot API or control swarms of Robots: package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/api" "gobot.io/x/gobot/v2/drivers/common/spherocommon" "gobot.io/x/gobot/v2/drivers/serial" "gobot.io/x/gobot/v2/platforms/serialport" ) func NewSwarmBot(port string) *gobot.Robot { spheroAdaptor := serialport.NewAdaptor(port) spheroDriver := sphero.NewSpheroDriver(spheroAdaptor, serial.WithName("Sphero" + port)) work := func() { spheroDriver.Stop() _ = spheroDriver.On(sphero.CollisionEvent, func(data interface{}) { fmt.Println("Collision Detected!") }) gobot.Every(1*time.Second, func() { spheroDriver.Roll(100, uint16(gobot.Rand(360))) }) gobot.Every(3*time.Second, func() { spheroDriver.SetRGB(uint8(gobot.Rand(255)), uint8(gobot.Rand(255)), uint8(gobot.Rand(255)), ) }) } robot := gobot.NewRobot("sphero", []gobot.Connection{spheroAdaptor}, []gobot.Device{spheroDriver}, work, ) return robot } func main() { manager := gobot.NewManager() api.NewAPI(manager).Start() spheros := []string{ "/dev/rfcomm0", "/dev/rfcomm1", "/dev/rfcomm2", "/dev/rfcomm3", } for _, port := range spheros { manager.AddRobot(NewSwarmBot(port)) } if err := manager.Start(); err != nil { panic(err) } } Copyright (c) 2013-2018 The Hybrid Group. Licensed under the Apache 2.0 license. */ package gobot // import "gobot.io/x/gobot/v2" ================================================ FILE: driver.go ================================================ package gobot // Driver is the interface that describes a driver in gobot type Driver interface { // Name returns the label for the Driver Name() string // SetName sets the label for the Driver (deprecated, use WithName() instead). // Please use options [aio.WithName, ble.WithName, gpio.WithName, onewire.WithName or serial.WithName] instead. SetName(s string) // Start initiates the Driver Start() error // Halt terminates the Driver Halt() error // Connection returns the Connection associated with the Driver Connection() Connection } // Pinner is the interface that describes a driver's pin type Pinner interface { Pin() string } ================================================ FILE: drivers/aio/LICENSE ================================================ Copyright (c) 2013-2018 The Hybrid Group Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: drivers/aio/README.md ================================================ # AIO This package provides drivers for [Analog Input/Output (AIO)](https://en.wikipedia.org/wiki/Analog-to-digital_converter) devices. It is normally used by connecting an adaptor such as [BeagleBone](https://gobot.io/documentation/platforms/beagleboard/beaglebone/) that supports the needed interfaces for analog devices. ## Getting Started Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) ## Hardware Support Gobot has a extensible system for connecting to hardware devices. The following AIO devices are currently supported: - Analog Actuator - Analog Sensor - Grove Light Sensor - Grove Piezo Vibration Sensor - Grove Rotary Dial - Grove Sound Sensor - Grove Temperature Sensor - Temperature Sensor (supports linear and NTC thermistor in normal and inverse mode) - Thermal Zone Temperature Sensor ================================================ FILE: drivers/aio/aio_driver.go ================================================ package aio import ( "log" "sync" "gobot.io/x/gobot/v2" ) const ( // Error event Error = "error" // Data event Data = "data" // Value event Value = "value" // Vibration event Vibration = "vibration" ) // AnalogReader interface represents an Adaptor which has AnalogRead capabilities type AnalogReader interface { // gobot.Adaptor AnalogRead(pin string) (val int, err error) } // AnalogWriter interface represents an Adaptor which has AnalogWrite capabilities type AnalogWriter interface { // gobot.Adaptor AnalogWrite(pin string, val int) error } // optionApplier needs to be implemented by each configurable option type type optionApplier interface { apply(cfg *configuration) } // configuration contains all changeable attributes of the driver. type configuration struct { name string } // nameOption is the type for applying another name to the configuration type nameOption string // Driver implements the interface gobot.Driver. type driver struct { gobot.Commander driverCfg *configuration connection interface{} afterStart func() error beforeHalt func() error mutex *sync.Mutex // e.g. used to prevent data race between cyclic and single shot write/read to values and scaler } // newDriver creates a new basic analog gobot driver. func newDriver(a interface{}, name string) *driver { d := driver{ driverCfg: &configuration{name: gobot.DefaultName(name)}, connection: a, afterStart: func() error { return nil }, beforeHalt: func() error { return nil }, Commander: gobot.NewCommander(), mutex: &sync.Mutex{}, } return &d } // WithName is used to replace the default name of the driver. func WithName(name string) optionApplier { return nameOption(name) } // Name returns the name of the driver. func (d *driver) Name() string { return d.driverCfg.name } // SetName sets the name of the driver. // Deprecated: Please use option [aio.WithName] instead. func (d *driver) SetName(name string) { WithName(name).apply(d.driverCfg) } // Connection returns the gobot connection of the driver. func (d *driver) Connection() gobot.Connection { if d.connection == nil { log.Printf("%s has no connection\n", d.driverCfg.name) return nil } if conn, ok := d.connection.(gobot.Connection); ok { return conn } log.Printf("%s has no gobot connection\n", d.driverCfg.name) return nil } // Start initializes the driver. func (d *driver) Start() error { d.mutex.Lock() defer d.mutex.Unlock() // currently there is nothing to do here for the driver return d.afterStart() } // Halt halts the driver. func (d *driver) Halt() error { d.mutex.Lock() defer d.mutex.Unlock() // currently there is nothing to do after halt for the driver return d.beforeHalt() } // apply change the name in the configuration. func (o nameOption) apply(c *configuration) { c.name = string(o) } ================================================ FILE: drivers/aio/aio_driver_test.go ================================================ package aio import ( "fmt" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) var _ gobot.Driver = (*driver)(nil) func initTestDriver() *driver { a := newAioTestAdaptor() d := newDriver(a, "AIO_BASIC") return d } func Test_newDriver(t *testing.T) { // arrange const name = "mybot" a := newAioTestAdaptor() // act d := newDriver(a, name) // assert assert.IsType(t, &driver{}, d) assert.NotNil(t, d.driverCfg) assert.True(t, strings.HasPrefix(d.Name(), name)) assert.Equal(t, a, d.Connection()) require.NoError(t, d.afterStart()) require.NoError(t, d.beforeHalt()) assert.NotNil(t, d.Commander) assert.NotNil(t, d.mutex) } func Test_applyWithName(t *testing.T) { // arrange const name = "mybot" cfg := configuration{name: "oldname"} // act WithName(name).apply(&cfg) // assert assert.Equal(t, name, cfg.name) } func TestStart(t *testing.T) { // arrange d := initTestDriver() // act, assert require.NoError(t, d.Start()) // arrange after start function d.afterStart = func() error { return fmt.Errorf("after start error") } // act, assert require.EqualError(t, d.Start(), "after start error") } func TestHalt(t *testing.T) { // arrange d := initTestDriver() // act, assert require.NoError(t, d.Halt()) // arrange after start function d.beforeHalt = func() error { return fmt.Errorf("before halt error") } // act, assert require.EqualError(t, d.Halt(), "before halt error") } ================================================ FILE: drivers/aio/analog_actuator_driver.go ================================================ package aio import ( "fmt" "strconv" ) // actuatorOptionApplier needs to be implemented by each configurable option type type actuatorOptionApplier interface { apply(cfg *actuatorConfiguration) } // actuatorConfiguration contains all changeable attributes of the driver. type actuatorConfiguration struct { scale func(input float64) (value int) } // actuatorScaleOption is the type for applying another scaler to the configuration type actuatorScaleOption struct { scaler func(input float64) (value int) } // AnalogActuatorDriver represents an analog actuator type AnalogActuatorDriver struct { *driver pin string actuatorCfg *actuatorConfiguration lastValue float64 lastRawValue int } // NewAnalogActuatorDriver returns a new driver for analog actuator, given by an AnalogWriter and pin. // The driver supports customizable scaling from given float64 value to written int. // The default scaling is 1:1. An adjustable linear scaler is provided by the driver. // // Supported options: // // "WithName" // "WithActuatorScaler" // // Adds the following API Commands: // // "Write" - See AnalogActuator.Write // "WriteRaw" - See AnalogActuator.WriteRaw func NewAnalogActuatorDriver(a AnalogWriter, pin string, opts ...interface{}) *AnalogActuatorDriver { d := &AnalogActuatorDriver{ driver: newDriver(a, "AnalogActuator"), pin: pin, actuatorCfg: &actuatorConfiguration{scale: func(input float64) int { return int(input) }}, } for _, opt := range opts { switch o := opt.(type) { case optionApplier: o.apply(d.driverCfg) case actuatorOptionApplier: o.apply(d.actuatorCfg) default: panic(fmt.Sprintf("'%s' can not be applied on '%s'", opt, d.driverCfg.name)) } } //nolint:forcetypeassert // ok here d.AddCommand("Write", func(params map[string]interface{}) interface{} { val, err := strconv.ParseFloat(params["val"].(string), 64) if err != nil { return err } return d.Write(val) }) //nolint:forcetypeassert // ok here d.AddCommand("WriteRaw", func(params map[string]interface{}) interface{} { val, _ := strconv.Atoi(params["val"].(string)) return d.WriteRaw(val) }) return d } // WithActuatorScaler substitute the default 1:1 return value function by a new scaling function func WithActuatorScaler(scaler func(input float64) (value int)) actuatorOptionApplier { return actuatorScaleOption{scaler: scaler} } // SetScaler substitute the default 1:1 return value function by a new scaling function // If the scaler is not changed after initialization, prefer to use [aio.WithActuatorScaler] instead. func (a *AnalogActuatorDriver) SetScaler(scaler func(float64) int) { a.mutex.Lock() defer a.mutex.Unlock() WithActuatorScaler(scaler).apply(a.actuatorCfg) } // Pin returns the drivers pin func (a *AnalogActuatorDriver) Pin() string { return a.pin } // Write writes the given value to the actuator func (a *AnalogActuatorDriver) Write(val float64) error { a.mutex.Lock() defer a.mutex.Unlock() rawValue := a.actuatorCfg.scale(val) if err := a.WriteRaw(rawValue); err != nil { return err } a.lastValue = val return nil } // RawWrite write the given raw value to the actuator // Deprecated: Please use [aio.WriteRaw] instead. func (a *AnalogActuatorDriver) RawWrite(val int) error { return a.WriteRaw(val) } // WriteRaw write the given raw value to the actuator func (a *AnalogActuatorDriver) WriteRaw(val int) error { writer, ok := a.connection.(AnalogWriter) if !ok { return fmt.Errorf("'AnalogWrite' is not supported by the platform '%s'", a.Connection().Name()) } if err := writer.AnalogWrite(a.Pin(), val); err != nil { return err } a.lastRawValue = val return nil } // Value returns the last written value func (a *AnalogActuatorDriver) Value() float64 { return a.lastValue } // RawValue returns the last written raw value func (a *AnalogActuatorDriver) RawValue() int { return a.lastRawValue } func (o actuatorScaleOption) String() string { return "scaler option for analog actuators" } func (o actuatorScaleOption) apply(cfg *actuatorConfiguration) { cfg.scale = o.scaler } // AnalogActuatorLinearScaler creates a linear scaler function from the given values. func AnalogActuatorLinearScaler(fromMin, fromMax float64, toMin, toMax int) func(input float64) (value int) { m := float64(toMax-toMin) / (fromMax - fromMin) n := float64(toMin) - m*fromMin return func(input float64) int { if input <= fromMin { return toMin } if input >= fromMax { return toMax } return int(input*m + n) } } ================================================ FILE: drivers/aio/analog_actuator_driver_test.go ================================================ //nolint:forcetypeassert // ok here package aio import ( "strings" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestNewAnalogActuatorDriver(t *testing.T) { // arrange const pin = "47" a := newAioTestAdaptor() // act d := NewAnalogActuatorDriver(a, pin) // assert: driver attributes assert.IsType(t, &AnalogActuatorDriver{}, d) assert.NotNil(t, d.driverCfg) assert.True(t, strings.HasPrefix(d.Name(), "AnalogActuator")) assert.Equal(t, a, d.Connection()) require.NoError(t, d.afterStart()) require.NoError(t, d.beforeHalt()) assert.NotNil(t, d.Commander) assert.NotNil(t, d.mutex) // assert: actuator attributes assert.Equal(t, pin, d.Pin()) assert.InDelta(t, 0.0, d.lastValue, 0, 0) assert.Equal(t, 0, d.lastRawValue) require.NotNil(t, d.actuatorCfg) assert.NotNil(t, d.actuatorCfg.scale) } func TestNewAnalogActuatorDriver_options(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithName() option, least one // option of this driver and one of another driver (which should lead to panic). Further tests for options can also // be done by call of "WithOption(val).apply(cfg)". // arrange myName := "relay 1" myScaler := func(input float64) int { return int(2 * input) } panicFunc := func() { NewAnalogActuatorDriver(newAioTestAdaptor(), "1", WithName("crazy"), WithSensorCyclicRead(10*time.Millisecond)) } // act d := NewAnalogActuatorDriver(newAioTestAdaptor(), "1", WithName(myName), WithActuatorScaler(myScaler)) // assert assert.Equal(t, myName, d.Name()) assert.Equal(t, 3, d.actuatorCfg.scale(1.5)) assert.PanicsWithValue(t, "'read interval option for analog sensors' can not be applied on 'crazy'", panicFunc) } func TestAnalogActuatorWriteRaw(t *testing.T) { tests := map[string]struct { inputVal int simulateWriteErr bool wantWritten int wantErr string }{ "write_raw": {inputVal: 100, wantWritten: 100}, "error_write": {inputVal: 12345, wantWritten: 12345, simulateWriteErr: true, wantErr: "write error"}, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange const pin = "47" a := newAioTestAdaptor() d := NewAnalogActuatorDriver(a, pin) a.simulateWriteError = tc.simulateWriteErr a.written = nil // reset previous writes // act err := d.WriteRaw(tc.inputVal) // assert if tc.wantErr != "" { require.EqualError(t, err, tc.wantErr) assert.Empty(t, a.written) } else { require.NoError(t, err) assert.Len(t, a.written, 1) assert.Equal(t, pin, a.written[0].pin) assert.Equal(t, tc.wantWritten, a.written[0].val) } }) } } func TestAnalogActuatorWriteRaw_AnalogWriteNotSupported(t *testing.T) { // arrange d := NewAnalogActuatorDriver(newAioTestAdaptor(), "1") d.connection = &aioTestBareAdaptor{} // act & assert require.EqualError(t, d.WriteRaw(3), "'AnalogWrite' is not supported by the platform 'bare'") } func TestAnalogActuatorWrite_SetScaler(t *testing.T) { tests := map[string]struct { fromMin float64 fromMax float64 input float64 wantWritten int }{ "byte_range_min": {fromMin: 0, fromMax: 255, input: 0, wantWritten: 0}, "byte_range_max": {fromMin: 0, fromMax: 255, input: 255, wantWritten: 255}, "signed_percent_range_min": {fromMin: -100, fromMax: 100, input: -100, wantWritten: 0}, "signed_percent_range_mid": {fromMin: -100, fromMax: 100, input: 0, wantWritten: 127}, "signed_percent_range_max": {fromMin: -100, fromMax: 100, input: 100, wantWritten: 255}, "voltage_range_min": {fromMin: 0, fromMax: 5.1, input: 0, wantWritten: 0}, "voltage_range_nearmin": {fromMin: 0, fromMax: 5.1, input: 0.02, wantWritten: 1}, "voltage_range_mid": {fromMin: 0, fromMax: 5.1, input: 2.55, wantWritten: 127}, "voltage_range_nearmax": {fromMin: 0, fromMax: 5.1, input: 5.08, wantWritten: 254}, "voltage_range_max": {fromMin: 0, fromMax: 5.1, input: 5.1, wantWritten: 255}, "upscale": {fromMin: 0, fromMax: 24, input: 12, wantWritten: 127}, "below_min": {fromMin: -10, fromMax: 10, input: -11, wantWritten: 0}, "exceed_max": {fromMin: 0, fromMax: 20, input: 21, wantWritten: 255}, } const pin = "7" a := newAioTestAdaptor() d := NewAnalogActuatorDriver(a, pin) for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d.SetScaler(AnalogActuatorLinearScaler(tc.fromMin, tc.fromMax, 0, 255)) a.written = nil // reset previous writes // act err := d.Write(tc.input) // assert require.NoError(t, err) assert.Len(t, a.written, 1) assert.Equal(t, pin, a.written[0].pin) assert.Equal(t, tc.wantWritten, a.written[0].val) }) } } func TestAnalogActuatorCommands_WithActuatorScaler(t *testing.T) { // arrange const pin = "8" a := newAioTestAdaptor() d := NewAnalogActuatorDriver(a, pin, WithActuatorScaler(func(input float64) int { return int((input + 3) / 2.5) })) a.written = nil // reset previous writes // act & assert: WriteRaw err := d.Command("WriteRaw")(map[string]interface{}{"val": "100"}) assert.Nil(t, err) assert.Len(t, a.written, 1) assert.Equal(t, pin, a.written[0].pin) assert.Equal(t, 100, a.written[0].val) assert.Equal(t, 100, d.RawValue()) assert.InDelta(t, 0.0, d.Value(), 0.0) // act & assert: Write err = d.Command("Write")(map[string]interface{}{"val": "247.0"}) assert.Nil(t, err) assert.Len(t, a.written, 2) assert.Equal(t, pin, a.written[1].pin) assert.Equal(t, 100, a.written[1].val) assert.Equal(t, 100, d.RawValue()) assert.InDelta(t, 247.0, d.Value(), 0.0) // arrange & act & assert: Write with error a.simulateWriteError = true err = d.Command("Write")(map[string]interface{}{"val": "247.0"}) require.EqualError(t, err.(error), "write error") } ================================================ FILE: drivers/aio/analog_sensor_driver.go ================================================ package aio import ( "fmt" "time" "gobot.io/x/gobot/v2" ) // sensorOptionApplier needs to be implemented by each configurable option type type sensorOptionApplier interface { apply(cfg *sensorConfiguration) } // sensorConfiguration contains all changeable attributes of the driver. type sensorConfiguration struct { readInterval time.Duration scale func(input int) (value float64) } // sensorReadIntervalOption is the type for applying another read interval to the configuration type sensorReadIntervalOption time.Duration // sensorScaleOption is the type for applying another scaler to the configuration type sensorScaleOption struct { scaler func(input int) (value float64) } // AnalogSensorDriver represents an analog sensor type AnalogSensorDriver struct { *driver gobot.Eventer sensorCfg *sensorConfiguration pin string halt chan struct{} lastRawValue int lastValue float64 analogRead func() (int, float64, error) } // NewAnalogSensorDriver returns a new driver for analog sensors, given an AnalogReader and pin. // The driver supports cyclic reading and customizable scaling from read int value to returned float64. // The default scaling is 1:1. An adjustable linear scaler is provided by the driver. // // Supported options: // // "WithName" // "WithSensorCyclicRead" // "WithSensorScaler" // // Adds the following API Commands: // // "Read" - See AnalogDriverSensor.Read // "ReadRaw" - See AnalogDriverSensor.ReadRaw func NewAnalogSensorDriver(a AnalogReader, pin string, opts ...interface{}) *AnalogSensorDriver { d := &AnalogSensorDriver{ driver: newDriver(a, "AnalogSensor"), sensorCfg: &sensorConfiguration{scale: func(input int) float64 { return float64(input) }}, pin: pin, Eventer: gobot.NewEventer(), // needed early due to grove vibration sensor driver } d.afterStart = d.initialize d.beforeHalt = d.shutdown d.analogRead = d.analogSensorRead for _, opt := range opts { switch o := opt.(type) { case optionApplier: o.apply(d.driverCfg) case sensorOptionApplier: o.apply(d.sensorCfg) case time.Duration: // TODO this is only for backward compatibility and will be removed after version 2.x d.sensorCfg.readInterval = o default: panic(fmt.Sprintf("'%s' can not be applied on '%s'", opt, d.driverCfg.name)) } } d.AddCommand("Read", func(_ map[string]interface{}) interface{} { val, err := d.Read() return map[string]interface{}{"val": val, "err": err} }) d.AddCommand("ReadRaw", func(_ map[string]interface{}) interface{} { val, err := d.ReadRaw() return map[string]interface{}{"val": val, "err": err} }) return d } // WithSensorCyclicRead add a asynchronous cyclic reading functionality to the sensor with the given read interval. func WithSensorCyclicRead(interval time.Duration) sensorOptionApplier { return sensorReadIntervalOption(interval) } // WithSensorScaler substitute the default 1:1 return value function by a new scaling function func WithSensorScaler(scaler func(input int) (value float64)) sensorOptionApplier { return sensorScaleOption{scaler: scaler} } // SetScaler substitute the default 1:1 return value function by a new scaling function // If the scaler is not changed after initialization, prefer to use [aio.WithSensorScaler] instead. func (a *AnalogSensorDriver) SetScaler(scaler func(int) float64) { a.mutex.Lock() defer a.mutex.Unlock() WithSensorScaler(scaler).apply(a.sensorCfg) } // Pin returns the AnalogSensorDrivers pin func (a *AnalogSensorDriver) Pin() string { return a.pin } // Read returns the current reading from the sensor, scaled by the current scaler func (a *AnalogSensorDriver) Read() (float64, error) { _, value, err := a.analogRead() return value, err } // ReadRaw returns the current reading from the sensor without scaling func (a *AnalogSensorDriver) ReadRaw() (int, error) { rawValue, _, err := a.analogRead() return rawValue, err } // Value returns the last read value from the sensor func (a *AnalogSensorDriver) Value() float64 { a.mutex.Lock() defer a.mutex.Unlock() return a.lastValue } // RawValue returns the last read raw value from the sensor func (a *AnalogSensorDriver) RawValue() int { a.mutex.Lock() defer a.mutex.Unlock() return a.lastRawValue } // initialize the AnalogSensorDriver and if the cyclic reading is active, reads the sensor at the given interval. // Emits the Events: // // Data int - Event is emitted on change and represents the current raw reading from the sensor. // Value float64 - Event is emitted on change and represents the current reading from the sensor. // Error error - Event is emitted on error reading from the sensor. func (a *AnalogSensorDriver) initialize() error { if a.sensorCfg.readInterval == 0 { // cyclic reading deactivated return nil } a.AddEvent(Data) a.AddEvent(Value) a.AddEvent(Error) // A small buffer is needed to prevent mutex-channel-deadlock between Halt() and analogRead(). // This can happen, if the shutdown is in progress (mutex passed) and the go routine is calling // the analogRead() in between, before the halt can be evaluated by the select statement. // In this case the mutex of analogRead() blocks the reading of the halt channel and, without a small buffer, // the writing to halt is blocked because there is no immediate read from channel. // Please note, that this is special behavior caused by the first read is done immediately before the select // statement. a.halt = make(chan struct{}, 1) oldRawValue := 0 oldValue := 0.0 go func() { timer := time.NewTimer(a.sensorCfg.readInterval) timer.Stop() for { // please note, that this ensures the first read is done immediately, but has drawbacks, see notes above rawValue, value, err := a.analogRead() if err != nil { a.Publish(a.Event(Error), err) } else { if rawValue != oldRawValue && rawValue != -1 { a.Publish(a.Event(Data), rawValue) oldRawValue = rawValue } if value != oldValue && value != -1 { a.Publish(a.Event(Value), value) oldValue = value } } timer.Reset(a.sensorCfg.readInterval) // ensure that after each read is a wait, independent of duration of read select { case <-timer.C: case <-a.halt: timer.Stop() return } } }() return nil } // shutdown stops polling the analog sensor for new information func (a *AnalogSensorDriver) shutdown() error { if a.sensorCfg.readInterval == 0 || a.halt == nil { // cyclic reading deactivated return nil } close(a.halt) // broadcast halt, also to the test return nil } // analogSensorRead performs an reading from the sensor, sets the internal attributes and returns // the raw and scaled value func (a *AnalogSensorDriver) analogSensorRead() (int, float64, error) { a.mutex.Lock() defer a.mutex.Unlock() reader, ok := a.connection.(AnalogReader) if !ok { return 0, 0, fmt.Errorf("'AnalogRead' is not supported by the platform '%s'", a.Connection().Name()) } rawValue, err := reader.AnalogRead(a.Pin()) if err != nil { return 0, 0, err } a.lastRawValue = rawValue a.lastValue = a.sensorCfg.scale(a.lastRawValue) return a.lastRawValue, a.lastValue, nil } func (o sensorReadIntervalOption) String() string { return "read interval option for analog sensors" } func (o sensorScaleOption) String() string { return "scaler option for analog sensors" } func (o sensorReadIntervalOption) apply(cfg *sensorConfiguration) { cfg.readInterval = time.Duration(o) } func (o sensorScaleOption) apply(cfg *sensorConfiguration) { cfg.scale = o.scaler } // AnalogSensorLinearScaler creates a linear scaler function from the given values. func AnalogSensorLinearScaler(fromMin, fromMax int, toMin, toMax float64) func(int) float64 { m := (toMax - toMin) / float64(fromMax-fromMin) n := toMin - m*float64(fromMin) return func(input int) float64 { if input <= fromMin { return toMin } if input >= fromMax { return toMax } return float64(input)*m + n } } ================================================ FILE: drivers/aio/analog_sensor_driver_test.go ================================================ //nolint:forcetypeassert // ok here package aio import ( "fmt" "strings" "sync" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) var _ gobot.Driver = (*AnalogSensorDriver)(nil) func TestNewAnalogSensorDriver(t *testing.T) { // arrange const pin = "5" a := newAioTestAdaptor() // act d := NewAnalogSensorDriver(a, pin) // assert: driver attributes assert.IsType(t, &AnalogSensorDriver{}, d) assert.NotNil(t, d.driverCfg) assert.True(t, strings.HasPrefix(d.Name(), "AnalogSensor")) assert.Equal(t, a, d.Connection()) require.NoError(t, d.afterStart()) require.NoError(t, d.beforeHalt()) assert.NotNil(t, d.Commander) assert.NotNil(t, d.mutex) // assert: sensor attributes assert.Equal(t, pin, d.Pin()) assert.InDelta(t, 0.0, d.lastValue, 0, 0) assert.Equal(t, 0, d.lastRawValue) assert.Nil(t, d.halt) // will be created on initialize, if cyclic reading is on assert.NotNil(t, d.Eventer) require.NotNil(t, d.sensorCfg) assert.Equal(t, time.Duration(0), d.sensorCfg.readInterval) assert.NotNil(t, d.sensorCfg.scale) } func TestNewAnalogSensorDriver_options(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithName() option, least one // option of this driver and one of another driver (which should lead to panic). Further tests for options can also // be done by call of "WithOption(val).apply(cfg)". // arrange const ( myName = "voltage 1" cycReadDur = 10 * time.Millisecond ) panicFunc := func() { NewAnalogSensorDriver(newAioTestAdaptor(), "1", WithName("crazy"), WithActuatorScaler(func(float64) int { return 0 })) } // act d := NewAnalogSensorDriver(newAioTestAdaptor(), "1", WithName(myName), WithSensorCyclicRead(cycReadDur)) // assert assert.Equal(t, cycReadDur, d.sensorCfg.readInterval) assert.Equal(t, myName, d.Name()) assert.PanicsWithValue(t, "'scaler option for analog actuators' can not be applied on 'crazy'", panicFunc) } func TestAnalogSensor_WithSensorScaler(t *testing.T) { // arrange myScaler := func(input int) float64 { return float64(input) / 2 } cfg := sensorConfiguration{} // act WithSensorScaler(myScaler).apply(&cfg) // assert assert.InDelta(t, 1.5, cfg.scale(3), 0.0) } func TestAnalogSensorDriverReadRaw(t *testing.T) { tests := map[string]struct { simulateReadErr bool wantVal int wantErr string }{ "read_raw": {wantVal: analogReadReturnValue}, "error_read": {wantVal: 0, simulateReadErr: true, wantErr: "read error"}, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange const pin = "47" a := newAioTestAdaptor() d := NewAnalogSensorDriver(a, pin) a.simulateReadError = tc.simulateReadErr a.written = nil // reset previous writes // act got, err := d.ReadRaw() // assert if tc.wantErr != "" { require.EqualError(t, err, tc.wantErr) assert.Empty(t, a.written) } else { require.NoError(t, err) } assert.Equal(t, tc.wantVal, got) }) } } func TestAnalogSensorDriverReadRaw_AnalogWriteNotSupported(t *testing.T) { // arrange d := NewAnalogSensorDriver(newAioTestAdaptor(), "1") d.connection = &aioTestBareAdaptor{} // act & assert got, err := d.ReadRaw() require.EqualError(t, err, "'AnalogRead' is not supported by the platform 'bare'") assert.Equal(t, 0, got) } func TestAnalogSensorRead_SetScaler(t *testing.T) { // the input scales per default from 0...255 tests := map[string]struct { toMin float64 toMax float64 input int want float64 }{ "single_byte_range_min": {toMin: 0, toMax: 255, input: 0, want: 0}, "single_byte_range_max": {toMin: 0, toMax: 255, input: 255, want: 255}, "single_below_min": {toMin: 3, toMax: 121, input: -1, want: 3}, "single_is_max": {toMin: 5, toMax: 6, input: 255, want: 6}, "single_upscale": {toMin: 337, toMax: 5337, input: 127, want: 2827.196078431373}, "grd_int_range_min": {toMin: -180, toMax: 180, input: 0, want: -180}, "grd_int_range_minus_one": {toMin: -180, toMax: 180, input: 127, want: -0.7058823529411598}, "grd_int_range_max": {toMin: -180, toMax: 180, input: 255, want: 180}, "upscale": {toMin: -10, toMax: 1234, input: 255, want: 1234}, } a := newAioTestAdaptor() d := NewAnalogSensorDriver(a, "7") for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d.SetScaler(AnalogSensorLinearScaler(0, 255, tc.toMin, tc.toMax)) a.analogReadFunc = func() (int, error) { return tc.input, nil } // act got, err := d.Read() // assert require.NoError(t, err) assert.InDelta(t, tc.want, got, 1.0e-14) }) } } func TestAnalogSensor_WithSensorCyclicRead(t *testing.T) { // arrange a := newAioTestAdaptor() d := NewAnalogSensorDriver(a, "1", WithSensorCyclicRead(10*time.Millisecond)) d.SetScaler(func(input int) float64 { return float64(input * input) }) semData := make(chan bool) semDone := make(chan bool) nextVal := make(chan int) readTimeout := time.Second a.analogReadFunc = func() (int, error) { val := 100 var err error select { case val = <-nextVal: if val < 0 { err = fmt.Errorf("analog read error") } return val, err default: return val, nil } } // arrange: expect raw value to be received _ = d.Once(Data, func(data interface{}) { // we can't use d.Event(Data) here, because not registered yet assert.Equal(t, 100, data.(int)) semData <- true }) // arrange: expect scaled value to be received _ = d.Once(Value, func(value interface{}) { // we can't use d.Event(Value) here, because not registered yet assert.InDelta(t, 10000.0, value.(float64), 0.0) <-semData // wait for data is finished semDone <- true nextVal <- -1 // arrange: error in read function }) // wait some time to ensure the cyclic go routine is working time.Sleep(15 * time.Millisecond) // act (start cyclic reading) require.NoError(t, d.Start()) // assert: both events within timeout select { case <-semDone: case <-time.After(readTimeout): require.Fail(t, "AnalogSensor Event \"Data\" was not published") } // arrange: for error to be received _ = d.Once(d.Event(Error), func(err interface{}) { assert.Equal(t, "analog read error", err.(error).Error()) semDone <- true }) // assert: error select { case <-semDone: case <-time.After(readTimeout): require.Fail(t, "AnalogSensor Event \"Error\" was not published") } // arrange: for halt message _ = d.Once(d.Event(Data), func(data interface{}) { semData <- true }) _ = d.Once(d.Event(Value), func(value interface{}) { semDone <- true }) // act: send the halt message require.NoError(t, d.Halt()) // assert: no event select { case <-semData: require.Fail(t, "AnalogSensor Event for data should not published") case <-semDone: require.Fail(t, "AnalogSensor Event for value should not published") case <-time.After(100 * time.Millisecond): } } func TestAnalogSensorHalt_WithSensorCyclicRead(t *testing.T) { // arrange d := NewAnalogSensorDriver(newAioTestAdaptor(), "1", WithSensorCyclicRead(10*time.Millisecond)) require.NoError(t, d.Start()) timeout := 2 * d.sensorCfg.readInterval wg := sync.WaitGroup{} wg.Add(1) go func() { defer wg.Done() select { case <-d.halt: // wait until halt is broadcasted by close the channel case <-time.After(timeout): // otherwise run into the timeout assert.Fail(t, fmt.Sprintf("halt was not received within %s", timeout)) } }() // act & assert require.NoError(t, d.Halt()) wg.Wait() // wait until the go function was really finished } func TestAnalogSensorCommands_WithSensorScaler(t *testing.T) { // arrange a := newAioTestAdaptor() d := NewAnalogSensorDriver(a, "42", WithSensorScaler(func(input int) float64 { return 2.5*float64(input) - 3 })) var readReturn int a.analogReadFunc = func() (int, error) { readReturn += 100 return readReturn, nil } // act & assert: ReadRaw ret := d.Command("ReadRaw")(nil).(map[string]interface{}) assert.Equal(t, 100, ret["val"].(int)) assert.Nil(t, ret["err"]) assert.Equal(t, 100, d.RawValue()) assert.InDelta(t, 247.0, d.Value(), 0.0) // act & assert: Read ret = d.Command("Read")(nil).(map[string]interface{}) assert.InDelta(t, 497.0, ret["val"].(float64), 0.0) assert.Nil(t, ret["err"]) assert.Equal(t, 200, d.RawValue()) assert.InDelta(t, 497.0, d.Value(), 0.0) } ================================================ FILE: drivers/aio/doc.go ================================================ /* Package aio provides Gobot drivers for Analog Input/Output devices. Installing: Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) For further information refer to aio README: https://github.com/hybridgroup/gobot/blob/release/platforms/aio/README.md */ package aio // import "gobot.io/x/gobot/v2/drivers/aio" ================================================ FILE: drivers/aio/grove_drivers.go ================================================ package aio import "gobot.io/x/gobot/v2" // GroveRotaryDriver represents an analog rotary dial with a Grove connector type GroveRotaryDriver struct { *AnalogSensorDriver } // NewGroveRotaryDriver returns a new driver for grove rotary dial, given an AnalogReader and pin. // // Supported options: see [aio.NewAnalogSensorDriver] // Adds the following API Commands: see [aio.NewAnalogSensorDriver] func NewGroveRotaryDriver(a AnalogReader, pin string, opts ...interface{}) *GroveRotaryDriver { d := GroveRotaryDriver{ AnalogSensorDriver: NewAnalogSensorDriver(a, pin, opts...), } d.driverCfg.name = gobot.DefaultName("GroveRotary") return &d } // GroveLightSensorDriver represents an analog light sensor // with a Grove connector type GroveLightSensorDriver struct { *AnalogSensorDriver } // NewGroveLightSensorDriver returns a new driver for grove light sensor, given an AnalogReader and pin. // // Supported options: see [aio.NewAnalogSensorDriver] // Adds the following API Commands: see [aio.NewAnalogSensorDriver] func NewGroveLightSensorDriver(a AnalogReader, pin string, opts ...interface{}) *GroveLightSensorDriver { d := GroveLightSensorDriver{ AnalogSensorDriver: NewAnalogSensorDriver(a, pin, opts...), } d.driverCfg.name = gobot.DefaultName("GroveLightSensor") return &d } // GrovePiezoVibrationSensorDriver represents an analog vibration sensor with a Grove connector type GrovePiezoVibrationSensorDriver struct { *AnalogSensorDriver } // NewGrovePiezoVibrationSensorDriver returns a new driver for grove piezo vibration sensor, given an AnalogReader // and pin. // // Supported options: see [aio.NewAnalogSensorDriver] // Adds the following API Commands: see [aio.NewAnalogSensorDriver] func NewGrovePiezoVibrationSensorDriver( a AnalogReader, pin string, opts ...interface{}, ) *GrovePiezoVibrationSensorDriver { d := &GrovePiezoVibrationSensorDriver{ AnalogSensorDriver: NewAnalogSensorDriver(a, pin, opts...), } d.driverCfg.name = gobot.DefaultName("GrovePiezoVibrationSensor") d.AddEvent(Vibration) if err := d.On(d.Event(Data), func(data interface{}) { if data.(int) > 1000 { //nolint:forcetypeassert // no error return value, so there is no better way d.Publish(d.Event(Vibration), data) } }); err != nil { panic(err) } return d } // GroveSoundSensorDriver represents a analog sound sensor with a Grove connector type GroveSoundSensorDriver struct { *AnalogSensorDriver } // NewGroveSoundSensorDriver returns a new driver for grove sound sensor, given an AnalogReader and pin. // // Supported options: see [aio.NewAnalogSensorDriver] // Adds the following API Commands: see [aio.NewAnalogSensorDriver] func NewGroveSoundSensorDriver(a AnalogReader, pin string, opts ...interface{}) *GroveSoundSensorDriver { d := GroveSoundSensorDriver{ AnalogSensorDriver: NewAnalogSensorDriver(a, pin, opts...), } d.driverCfg.name = gobot.DefaultName("GroveSoundSensor") return &d } ================================================ FILE: drivers/aio/grove_drivers_test.go ================================================ //nolint:forcetypeassert // ok here package aio import ( "errors" "reflect" "strings" "sync/atomic" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) type groveDriverTestDriverAndEventer interface { gobot.Driver gobot.Eventer } func TestNewGroveRotaryDriver(t *testing.T) { // arrange a := newAioTestAdaptor() pin := "456" // act d := NewGroveRotaryDriver(a, pin) // assert: driver attributes assert.IsType(t, &GroveRotaryDriver{}, d) assert.NotNil(t, d.driverCfg) assert.True(t, strings.HasPrefix(d.Name(), "GroveRotary")) assert.Equal(t, a, d.Connection()) require.NoError(t, d.afterStart()) require.NoError(t, d.beforeHalt()) assert.NotNil(t, d.Commander) assert.NotNil(t, d.mutex) // assert: sensor attributes assert.Equal(t, pin, d.Pin()) assert.InDelta(t, 0.0, d.lastValue, 0, 0) assert.Equal(t, 0, d.lastRawValue) assert.Nil(t, d.halt) // will be created on initialize, if cyclic reading is on assert.NotNil(t, d.Eventer) require.NotNil(t, d.sensorCfg) assert.Equal(t, time.Duration(0), d.sensorCfg.readInterval) assert.NotNil(t, d.sensorCfg.scale) } func TestNewGroveLightSensorDriver(t *testing.T) { // arrange a := newAioTestAdaptor() pin := "456" // act d := NewGroveLightSensorDriver(a, pin) // assert: driver attributes assert.IsType(t, &GroveLightSensorDriver{}, d) assert.NotNil(t, d.driverCfg) assert.True(t, strings.HasPrefix(d.Name(), "GroveLightSensor")) assert.Equal(t, a, d.Connection()) require.NoError(t, d.afterStart()) require.NoError(t, d.beforeHalt()) assert.NotNil(t, d.Commander) assert.NotNil(t, d.mutex) // assert: sensor attributes assert.Equal(t, pin, d.Pin()) assert.InDelta(t, 0.0, d.lastValue, 0, 0) assert.Equal(t, 0, d.lastRawValue) assert.Nil(t, d.halt) // will be created on initialize, if cyclic reading is on assert.NotNil(t, d.Eventer) require.NotNil(t, d.sensorCfg) assert.Equal(t, time.Duration(0), d.sensorCfg.readInterval) assert.NotNil(t, d.sensorCfg.scale) } func TestNewGrovePiezoVibrationSensorDriver(t *testing.T) { // arrange a := newAioTestAdaptor() pin := "456" // act d := NewGrovePiezoVibrationSensorDriver(a, pin) // assert: driver attributes assert.IsType(t, &GrovePiezoVibrationSensorDriver{}, d) assert.NotNil(t, d.driverCfg) assert.True(t, strings.HasPrefix(d.Name(), "GrovePiezoVibrationSensor")) assert.Equal(t, a, d.Connection()) require.NoError(t, d.afterStart()) require.NoError(t, d.beforeHalt()) assert.NotNil(t, d.Commander) assert.NotNil(t, d.mutex) // assert: sensor attributes assert.Equal(t, pin, d.Pin()) assert.InDelta(t, 0.0, d.lastValue, 0, 0) assert.Equal(t, 0, d.lastRawValue) assert.Nil(t, d.halt) // will be created on initialize, if cyclic reading is on assert.NotNil(t, d.Eventer) require.NotNil(t, d.sensorCfg) assert.Equal(t, time.Duration(0), d.sensorCfg.readInterval) assert.NotNil(t, d.sensorCfg.scale) } func TestNewGroveSoundSensorDriver(t *testing.T) { // arrange a := newAioTestAdaptor() pin := "456" // act d := NewGroveSoundSensorDriver(a, pin) // assert: driver attributes assert.IsType(t, &GroveSoundSensorDriver{}, d) assert.NotNil(t, d.driverCfg) assert.True(t, strings.HasPrefix(d.Name(), "GroveSoundSensor")) assert.Equal(t, a, d.Connection()) require.NoError(t, d.afterStart()) require.NoError(t, d.beforeHalt()) assert.NotNil(t, d.Commander) assert.NotNil(t, d.mutex) // assert: sensor attributes assert.Equal(t, pin, d.Pin()) assert.InDelta(t, 0.0, d.lastValue, 0, 0) assert.Equal(t, 0, d.lastRawValue) assert.Nil(t, d.halt) // will be created on initialize, if cyclic reading is on assert.NotNil(t, d.Eventer) require.NotNil(t, d.sensorCfg) assert.Equal(t, time.Duration(0), d.sensorCfg.readInterval) assert.NotNil(t, d.sensorCfg.scale) } func TestGroveDriverHalt_WithSensorCyclicRead(t *testing.T) { // arrange testAdaptor := newAioTestAdaptor() pin := "456" drivers := []groveDriverTestDriverAndEventer{ NewGroveSoundSensorDriver(testAdaptor, pin, WithSensorCyclicRead(10*time.Millisecond)), NewGroveLightSensorDriver(testAdaptor, pin, WithSensorCyclicRead(10*time.Millisecond)), NewGrovePiezoVibrationSensorDriver(testAdaptor, pin, WithSensorCyclicRead(10*time.Millisecond)), NewGroveRotaryDriver(testAdaptor, pin, WithSensorCyclicRead(10*time.Millisecond)), } for _, driver := range drivers { var callCount int32 testAdaptor.analogReadFunc = func() (int, error) { atomic.AddInt32(&callCount, 1) return 42, nil } // Start the driver and allow for multiple digital reads _ = driver.Start() time.Sleep(20 * time.Millisecond) _ = driver.Halt() lastCallCount := atomic.LoadInt32(&callCount) // If driver was not halted, digital reads would still continue time.Sleep(20 * time.Millisecond) // note: if a reading is already in progress, it will be finished before halt have an impact if atomic.LoadInt32(&callCount) > lastCallCount+1 { require.Fail(t, "AnalogRead was called more than once after driver was halted") } } } func TestGroveDriverWithSensorCyclicReadPublishesError(t *testing.T) { // arrange testAdaptor := newAioTestAdaptor() pin := "456" drivers := []groveDriverTestDriverAndEventer{ NewGroveSoundSensorDriver(testAdaptor, pin, WithSensorCyclicRead(10*time.Millisecond)), NewGroveLightSensorDriver(testAdaptor, pin, WithSensorCyclicRead(10*time.Millisecond)), NewGrovePiezoVibrationSensorDriver(testAdaptor, pin, WithSensorCyclicRead(10*time.Millisecond)), NewGroveRotaryDriver(testAdaptor, pin, WithSensorCyclicRead(10*time.Millisecond)), } for _, driver := range drivers { sem := make(chan struct{}, 1) // send error testAdaptor.analogReadFunc = func() (int, error) { return 0, errors.New("read error") } require.NoError(t, driver.Start()) // expect error _ = driver.Once(driver.Event(Error), func(data interface{}) { assert.Equal(t, "read error", data.(error).Error()) close(sem) }) select { case <-sem: case <-time.After(time.Second): require.Fail(t, groveGetType(driver)+" Event \"Error\" was not published") } // Cleanup _ = driver.Halt() } } func groveGetType(driver interface{}) string { d := reflect.TypeOf(driver) if d.Kind() == reflect.Ptr { return d.Elem().Name() } return d.Name() } ================================================ FILE: drivers/aio/grove_temperature_sensor_driver.go ================================================ package aio import ( "fmt" "time" "gobot.io/x/gobot/v2" ) // GroveTemperatureSensorDriver represents a temperature sensor // The temperature is reported in degree Celsius type GroveTemperatureSensorDriver struct { *TemperatureSensorDriver } // NewGroveTemperatureSensorDriver returns a new driver for grove temperature sensor, given an AnalogReader and pin. // // Supported options: see [aio.NewAnalogSensorDriver] // Adds the following API Commands: see [aio.NewAnalogSensorDriver] func NewGroveTemperatureSensorDriver(a AnalogReader, pin string, opts ...interface{}) *GroveTemperatureSensorDriver { t := NewTemperatureSensorDriver(a, pin, opts...) ntc := TemperatureSensorNtcConf{TC0: 25, R0: 10000.0, B: 3975} // Ohm, R25=10k t.SetNtcScaler(1023, 10000, false, ntc) // Ohm, reference value: 1023, series R: 10k d := &GroveTemperatureSensorDriver{ TemperatureSensorDriver: t, } d.driverCfg.name = gobot.DefaultName("GroveTemperatureSensor") for _, opt := range opts { switch o := opt.(type) { case optionApplier: o.apply(d.driverCfg) case sensorOptionApplier: o.apply(d.sensorCfg) case time.Duration: // TODO this is only for backward compatibility and will be removed after version 2.x d.sensorCfg.readInterval = o default: panic(fmt.Sprintf("'%s' can not be applied on '%s'", opt, d.driverCfg.name)) } } return d } // Temperature returns the last read temperature from the sensor. func (t *TemperatureSensorDriver) Temperature() float64 { return t.Value() } ================================================ FILE: drivers/aio/grove_temperature_sensor_driver_test.go ================================================ //nolint:forcetypeassert // ok here package aio import ( "strings" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) var _ gobot.Driver = (*GroveTemperatureSensorDriver)(nil) func TestNewGroveTemperatureSensorDriver(t *testing.T) { // arrange const pin = "123" a := newAioTestAdaptor() // act d := NewGroveTemperatureSensorDriver(a, pin) // assert: driver attributes assert.IsType(t, &GroveTemperatureSensorDriver{}, d) assert.NotNil(t, d.driverCfg) assert.True(t, strings.HasPrefix(d.Name(), "GroveTemperatureSensor")) assert.Equal(t, a, d.Connection()) require.NoError(t, d.afterStart()) require.NoError(t, d.beforeHalt()) assert.NotNil(t, d.Commander) assert.NotNil(t, d.mutex) // assert: sensor attributes assert.Equal(t, pin, d.Pin()) assert.InDelta(t, 0.0, d.lastValue, 0, 0) assert.Equal(t, 0, d.lastRawValue) assert.Nil(t, d.halt) // will be created on initialize, if cyclic reading is on assert.NotNil(t, d.Eventer) require.NotNil(t, d.sensorCfg) assert.Equal(t, time.Duration(0), d.sensorCfg.readInterval) assert.NotNil(t, d.sensorCfg.scale) } func TestNewGroveTemperatureSensorDriver_options(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithName() option, least one // option of this driver and one of another driver (which should lead to panic). Further tests for options can also // be done by call of "WithOption(val).apply(cfg)". // arrange const ( myName = "inlet temperature" cycReadDur = 10 * time.Millisecond ) panicFunc := func() { NewGroveTemperatureSensorDriver(newAioTestAdaptor(), "1", WithName("crazy"), WithActuatorScaler(func(float64) int { return 0 })) } // act d := NewGroveTemperatureSensorDriver(newAioTestAdaptor(), "1", WithName(myName), WithSensorCyclicRead(cycReadDur)) // assert assert.Equal(t, cycReadDur, d.sensorCfg.readInterval) assert.Equal(t, myName, d.Name()) assert.PanicsWithValue(t, "'scaler option for analog actuators' can not be applied on 'crazy'", panicFunc) } func TestGroveTemperatureSensorRead_scaler(t *testing.T) { tests := map[string]struct { input int want float64 }{ "min": {input: 0, want: -273.15}, "nearMin": {input: 1, want: -76.96736464322436}, "T-25C": {input: 65, want: -25.064097201780044}, "T0C": {input: 233, want: -0.014379114122164083}, "T25C": {input: 511, want: 24.956285721537938}, "585": {input: 585, want: 31.61532462352477}, "nearMax": {input: 1022, want: 347.6819764792606}, "max": {input: 1023, want: 347.77682140097613}, "biggerThanMax": {input: 5000, want: 347.77682140097613}, } a := newAioTestAdaptor() d := NewGroveTemperatureSensorDriver(a, "54") for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange a.analogReadFunc = func() (int, error) { return tc.input, nil } // act got, err := d.Read() // assert require.NoError(t, err) assert.InDelta(t, tc.want, got, 0.0) }) } } func TestGroveTemperatureSensor_publishesTemperatureInCelsius(t *testing.T) { // arrange sem := make(chan bool) a := newAioTestAdaptor() d := NewGroveTemperatureSensorDriver(a, "1", WithSensorCyclicRead(10*time.Millisecond)) // 584: 31.52208881030674, 585: 31.61532462352477 lastRawValue := 584 a.analogReadFunc = func() (int, error) { // ensure a changed value on each read, otherwise no event will be published lastRawValue++ if lastRawValue > 585 { lastRawValue = 584 } return lastRawValue, nil } // act: start cyclic reading require.NoError(t, d.Start()) // wait some time to ensure the cyclic go routine is working time.Sleep(15 * time.Millisecond) var eventValue float64 _ = d.Once(d.Event(Value), func(data interface{}) { eventValue = data.(float64) sem <- true }) // assert: value was published and is in expected delta select { case <-sem: require.NoError(t, d.Halt()) case <-time.After(100 * time.Millisecond): require.Fail(t, "Grove Temperature Sensor Event \"Value\" was not published") } assert.InDelta(t, eventValue, d.Temperature(), 0.0) assert.InDelta(t, 31.61532462352477, d.Temperature(), 31.61532462352477-31.52208881030674) } ================================================ FILE: drivers/aio/helpers_test.go ================================================ package aio import ( "fmt" "sync" ) const analogReadReturnValue = 99 type aioTestBareAdaptor struct{} func (t *aioTestBareAdaptor) Connect() error { return nil } func (t *aioTestBareAdaptor) Finalize() error { return nil } func (t *aioTestBareAdaptor) Name() string { return "bare" } func (t *aioTestBareAdaptor) SetName(n string) {} type aioTestWritten struct { pin string val int } type aioTestAdaptor struct { name string written []aioTestWritten simulateWriteError bool simulateReadError bool port string mtx sync.Mutex analogReadFunc func() (val int, err error) analogWriteFunc func(val int) error } func newAioTestAdaptor() *aioTestAdaptor { t := aioTestAdaptor{ name: "aio_test_adaptor", port: "/dev/null", analogReadFunc: func() (int, error) { return analogReadReturnValue, nil }, analogWriteFunc: func(val int) error { return nil }, } return &t } // AnalogRead capabilities (interface AnalogReader) func (t *aioTestAdaptor) AnalogRead(pin string) (int, error) { t.mtx.Lock() defer t.mtx.Unlock() if t.simulateReadError { return 0, fmt.Errorf("read error") } return t.analogReadFunc() } // AnalogWrite capabilities (interface AnalogWriter) func (t *aioTestAdaptor) AnalogWrite(pin string, val int) error { t.mtx.Lock() defer t.mtx.Unlock() if t.simulateWriteError { return fmt.Errorf("write error") } w := aioTestWritten{pin: pin, val: val} t.written = append(t.written, w) return t.analogWriteFunc(val) } func (t *aioTestAdaptor) Connect() error { return nil } func (t *aioTestAdaptor) Finalize() error { return nil } func (t *aioTestAdaptor) Name() string { return t.name } func (t *aioTestAdaptor) SetName(n string) { t.name = n } func (t *aioTestAdaptor) Port() string { return t.port } ================================================ FILE: drivers/aio/temperature_sensor_driver.go ================================================ package aio import ( "fmt" "math" "time" "gobot.io/x/gobot/v2" ) const kelvinOffset = 273.15 // TemperatureSensorNtcConf contains all attributes to calculate key parameters of a NTC thermistor. type TemperatureSensorNtcConf struct { TC0 int // °C R0 float64 // same unit as resistance of NTC (Ohm is recommended) B float64 // 2000..5000K TC1 int // used if B is not given, °C R1 float64 // used if B is not given, same unit as R0 needed t0 float64 r float64 } // TemperatureSensorDriver represents an Analog Sensor type TemperatureSensorDriver struct { *AnalogSensorDriver } // NewTemperatureSensorDriver is a driver for analog temperature sensors, given an AnalogReader and pin. // Linear scaling and NTC scaling is supported. // // Supported options: see [aio.NewAnalogSensorDriver] // Adds the following API Commands: see [aio.NewAnalogSensorDriver] func NewTemperatureSensorDriver(a AnalogReader, pin string, opts ...interface{}) *TemperatureSensorDriver { d := &TemperatureSensorDriver{AnalogSensorDriver: NewAnalogSensorDriver(a, pin)} d.driverCfg.name = gobot.DefaultName("TemperatureSensor") for _, opt := range opts { switch o := opt.(type) { case optionApplier: o.apply(d.driverCfg) case sensorOptionApplier: o.apply(d.sensorCfg) case time.Duration: // TODO this is only for backward compatibility and will be removed after version 2.x d.sensorCfg.readInterval = o default: panic(fmt.Sprintf("'%s' can not be applied on '%s'", opt, d.driverCfg.name)) } } return d } // SetNtcScaler sets a function for typical NTC scaling the read value. // The read value is related to the voltage over the thermistor in an series connection to a resistor. // If the thermistor is connected to ground, the reverse flag must be set to true. // This means the voltage decreases when temperature gets higher. // Currently no negative values for voltage are supported. // If the scaler is not changed after initialization, prefer to use [aio.WithSensorScaler] instead. func (t *TemperatureSensorDriver) SetNtcScaler(vRef uint, rOhm uint, reverse bool, ntc TemperatureSensorNtcConf) { t.SetScaler(TemperatureSensorNtcScaler(vRef, rOhm, reverse, ntc)) } // SetLinearScaler sets a function for linear scaling the read value. // This can be applied for some silicon based PTC sensors or e.g. PT100, // and in a small temperature range also for NTC. // If the scaler is not changed after initialization, prefer to use [aio.WithSensorScaler] instead. func (t *TemperatureSensorDriver) SetLinearScaler(fromMin, fromMax int, toMin, toMax float64) { t.SetScaler(AnalogSensorLinearScaler(fromMin, fromMax, toMin, toMax)) } // TemperatureSensorNtcScaler creates a function for typical NTC scaling the read value. // The read value is related to the voltage over the thermistor in an series connection to a resistor. // If the thermistor is connected to ground, the reverse flag must be set to true. // This means the voltage decreases when temperature gets higher. // Currently no negative values for voltage are supported. func TemperatureSensorNtcScaler( vRef uint, rOhm uint, reverse bool, ntc TemperatureSensorNtcConf, ) func(input int) (value float64) { ntc.initialize() return (func(input int) float64 { if input < 0 { input = 0 } rTherm := temperaturSensorGetResistance(uint(input), vRef, rOhm, reverse) //nolint:gosec // checked before temp := ntc.getTemp(rTherm) return temp }) } // getResistance calculates the value of the series thermistor by given value // and reference value (e.g. the voltage value over the complete series circuit) // The unit of the returned thermistor value equals the given series resistor unit. func temperaturSensorGetResistance(value uint, vRef uint, rSeries uint, reverse bool) float64 { if value > vRef { value = vRef } valDiff := vRef - value if reverse { // rSeries thermistor // vRef o--|==|--o--|=/=|----| GND // |-> value <-| if value == 0 { // prevent jump to -273.15 value = 1 } return float64(rSeries*value) / float64(valDiff) } // thermistor rSeries // vRef o--|=/=|--o--|==|-----| GND // |-> value <-| if valDiff == 0 { // prevent jump to -273.15 valDiff = 1 } return float64(rSeries*valDiff) / float64(value) } // getTemp calculates the temperature from the given resistance of the NTC resistor func (n *TemperatureSensorNtcConf) getTemp(rntc float64) float64 { // 1/T = 1/T0 + 1/B * ln(R/R0) // // B/T = B/T0 + ln(R/R0) = k, B/T0 = r // T = B/k, Tc = T - 273 k := n.r + math.Log(rntc/n.R0) return n.B/k - kelvinOffset } // initialize is used to calculate some constants for the NTC algorithm. // If B is unknown (given as 0), the function needs a second pair to calculate // B from the both pairs (R1, TC1), (R0, TC0) func (n *TemperatureSensorNtcConf) initialize() { n.t0 = float64(n.TC0) + kelvinOffset if n.B <= 0 { // B=[ln(R0)-ln(R1)]/(1/T0-1/T1) T1 := float64(n.TC1) + kelvinOffset n.B = (1/n.t0 - 1/T1) n.B = (math.Log(n.R0) - math.Log(n.R1)) / n.B // 2000K...5000K } n.r = n.B / n.t0 } ================================================ FILE: drivers/aio/temperature_sensor_driver_test.go ================================================ //nolint:forcetypeassert // ok here package aio import ( "errors" "strings" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestNewTemperatureSensorDriver(t *testing.T) { // arrange const pin = "123" a := newAioTestAdaptor() // act d := NewTemperatureSensorDriver(a, pin) // assert: driver attributes assert.IsType(t, &TemperatureSensorDriver{}, d) assert.NotNil(t, d.driverCfg) assert.True(t, strings.HasPrefix(d.Name(), "TemperatureSensor")) assert.Equal(t, a, d.Connection()) require.NoError(t, d.afterStart()) require.NoError(t, d.beforeHalt()) assert.NotNil(t, d.Commander) assert.NotNil(t, d.mutex) // assert: sensor attributes assert.Equal(t, pin, d.Pin()) assert.InDelta(t, 0.0, d.lastValue, 0, 0) assert.Equal(t, 0, d.lastRawValue) assert.Nil(t, d.halt) // will be created on initialize, if cyclic reading is on assert.NotNil(t, d.Eventer) require.NotNil(t, d.sensorCfg) assert.Equal(t, time.Duration(0), d.sensorCfg.readInterval) assert.NotNil(t, d.sensorCfg.scale) } func TestNewTemperatureSensorDriver_options(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithName() option, least one // option of this driver and one of another driver (which should lead to panic). Further tests for options can also // be done by call of "WithOption(val).apply(cfg)". // arrange const ( myName = "outlet temperature" cycReadDur = 10 * time.Millisecond ) panicFunc := func() { NewTemperatureSensorDriver(newAioTestAdaptor(), "1", WithName("crazy"), WithActuatorScaler(func(float64) int { return 0 })) } // act d := NewTemperatureSensorDriver(newAioTestAdaptor(), "1", WithName(myName), WithSensorCyclicRead(cycReadDur)) // assert assert.Equal(t, cycReadDur, d.sensorCfg.readInterval) assert.Equal(t, myName, d.Name()) assert.PanicsWithValue(t, "'scaler option for analog actuators' can not be applied on 'crazy'", panicFunc) } func TestTemperatureSensorRead_NtcScaler(t *testing.T) { tests := map[string]struct { input int want float64 }{ "smaller_than_min": {input: -1, want: 457.720219684306}, "min": {input: 0, want: 457.720219684306}, "near_min": {input: 1, want: 457.18923673420545}, "mid_range": {input: 127, want: 87.9784401845593}, "T25C": {input: 232, want: 24.805280460718336}, "T0C": {input: 248, want: -0.9858175109026774}, "T-25C": {input: 253, want: -22.92863536929451}, "near_max": {input: 254, want: -33.51081663999781}, "max": {input: 255, want: -273.15}, "bigger_than_max": {input: 256, want: -273.15}, } a := newAioTestAdaptor() d := NewTemperatureSensorDriver(a, "4") ntc1 := TemperatureSensorNtcConf{TC0: 25, R0: 10000.0, B: 3950} // Ohm, R25=10k, B=3950 d.SetNtcScaler(255, 1000, true, ntc1) // Ohm, reference value: 3300, series R: 1k for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange a.analogReadFunc = func() (int, error) { return tc.input, nil } // act got, err := d.Read() // assert require.NoError(t, err) assert.InDelta(t, tc.want, got, 0.0) }) } } func TestTemperatureSensorDriver_LinearScaler(t *testing.T) { tests := map[string]struct { input int want float64 }{ "smaller_than_min": {input: -129, want: -40}, "min": {input: -128, want: -40}, "near_min": {input: -127, want: -39.450980392156865}, "T-25C": {input: -101, want: -25.17647058823529}, "T0C": {input: -55, want: 0.07843137254902288}, "T25C": {input: -10, want: 24.7843137254902}, "mid_range": {input: 0, want: 30.274509803921575}, "near_max": {input: 126, want: 99.45098039215688}, "max": {input: 127, want: 100}, "bigger_than_max": {input: 128, want: 100}, } a := newAioTestAdaptor() d := NewTemperatureSensorDriver(a, "4") d.SetLinearScaler(-128, 127, -40, 100) for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange a.analogReadFunc = func() (int, error) { return tc.input, nil } // act got, err := d.Read() // assert require.NoError(t, err) assert.InDelta(t, tc.want, got, 1.0e-14) }) } } func TestTemperatureSensorWithSensorCyclicRead_PublishesTemperatureInCelsius(t *testing.T) { // arrange sem := make(chan bool) a := newAioTestAdaptor() d := NewTemperatureSensorDriver(a, "1", WithSensorCyclicRead(10*time.Millisecond)) ntc := TemperatureSensorNtcConf{TC0: 25, R0: 10000.0, B: 3975} // Ohm, R25=10k d.SetNtcScaler(1023, 10000, false, ntc) // Ohm, reference value: 1023, series R: 10k // 584: 31.52208881030674, 585: 31.61532462352477 lastRawValue := 585 a.analogReadFunc = func() (int, error) { // ensure a changed value on each read, otherwise no event will be published lastRawValue++ if lastRawValue > 585 { lastRawValue = 584 } return lastRawValue, nil } // act: start cyclic reading require.NoError(t, d.Start()) // wait some time to ensure the cyclic go routine is working time.Sleep(15 * time.Millisecond) var eventValue float64 _ = d.Once(d.Event(Value), func(data interface{}) { eventValue = data.(float64) sem <- true }) // assert: value was published and is in expected delta select { case <-sem: require.NoError(t, d.Halt()) case <-time.After(100 * time.Millisecond): require.Fail(t, "Grove Temperature Sensor Event \"Value\" was not published") } assert.InDelta(t, eventValue, d.Temperature(), 0.0) assert.InDelta(t, 31.61532462352477, d.Value(), 31.61532462352477-31.52208881030674) } func TestTemperatureSensorWithSensorCyclicRead_PublishesError(t *testing.T) { // arrange sem := make(chan bool) a := newAioTestAdaptor() d := NewTemperatureSensorDriver(a, "1", WithSensorCyclicRead(10*time.Millisecond)) // send error a.analogReadFunc = func() (int, error) { return 0, errors.New("read error") } require.NoError(t, d.Start()) // expect error _ = d.Once(d.Event(Error), func(data interface{}) { assert.Equal(t, "read error", data.(error).Error()) sem <- true }) select { case <-sem: case <-time.After(1 * time.Second): require.Fail(t, " Temperature Sensor Event \"Error\" was not published") } } func TestTemperatureSensorHalt_WithSensorCyclicRead(t *testing.T) { // arrange d := NewTemperatureSensorDriver(newAioTestAdaptor(), "1", WithSensorCyclicRead(10*time.Millisecond)) require.NoError(t, d.Start()) errChan := make(chan error, 1) // act & assert go func() { errChan <- d.Halt() }() // test that the halt is not blocked by any deadlock with mutex and/or channel select { case err := <-errChan: require.NoError(t, err) case <-time.After(100 * time.Millisecond): require.Fail(t, "Temperature Sensor was not halted") } } func TestTempDriver_initialize(t *testing.T) { tests := map[string]struct { input TemperatureSensorNtcConf want TemperatureSensorNtcConf }{ "B_low_tc0": { input: TemperatureSensorNtcConf{TC0: -13, B: 2601.5}, want: TemperatureSensorNtcConf{TC0: -13, B: 2601.5, t0: 260.15, r: 10}, }, "B_low_tc0_B": { input: TemperatureSensorNtcConf{TC0: -13, B: 5203}, want: TemperatureSensorNtcConf{TC0: -13, B: 5203, t0: 260.15, r: 20}, }, "B_mid_tc0": { input: TemperatureSensorNtcConf{TC0: 25, B: 3950}, want: TemperatureSensorNtcConf{TC0: 25, B: 3950, t0: 298.15, r: 13.248364916988095}, }, "B_mid_tc0_r0_no_change": { input: TemperatureSensorNtcConf{TC0: 25, R0: 1234.5, B: 3950}, want: TemperatureSensorNtcConf{TC0: 25, R0: 1234.5, B: 3950, t0: 298.15, r: 13.248364916988095}, }, "B_high_tc0": { input: TemperatureSensorNtcConf{TC0: 100, B: 3731.5}, want: TemperatureSensorNtcConf{TC0: 100, B: 3731.5, t0: 373.15, r: 10}, }, "T1_low": { input: TemperatureSensorNtcConf{TC0: 25, R0: 2500.0, TC1: -13, R1: 10000}, want: TemperatureSensorNtcConf{ TC0: 25, R0: 2500.0, TC1: -13, R1: 10000, B: 2829.6355560320544, t0: 298.15, r: 9.490644159087891, }, }, "T1_high": { input: TemperatureSensorNtcConf{TC0: 25, R0: 2500.0, TC1: 100, R1: 371}, want: TemperatureSensorNtcConf{ TC0: 25, R0: 2500.0, TC1: 100, R1: 371, B: 2830.087381913779, t0: 298.15, r: 9.49215959052081, }, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange ntc := tc.input // act ntc.initialize() // assert assert.Equal(t, tc.want, ntc) }) } } ================================================ FILE: drivers/aio/thermalzone_driver.go ================================================ package aio import ( "fmt" "gobot.io/x/gobot/v2" ) // thermalZoneOptionApplier needs to be implemented by each configurable option type type thermalZoneOptionApplier interface { apply(cfg *thermalZoneConfiguration) } // thermalZoneConfiguration contains all changeable attributes of the driver. type thermalZoneConfiguration struct { scaleUnit func(float64) float64 } // thermalZoneUnitscalerOption is the type for applying another unit scaler to the configuration type thermalZoneUnitscalerOption struct { unitscaler func(float64) float64 } // ThermalZoneDriver represents an driver for reading the system thermal zone temperature type ThermalZoneDriver struct { *AnalogSensorDriver thermalZoneCfg *thermalZoneConfiguration } // NewThermalZoneDriver is a driver for reading the system thermal zone temperature, given an AnalogReader and zone id. // // Supported options: see also [aio.NewAnalogSensorDriver] // // "WithFahrenheit()" // // Adds the following API Commands: see [aio.NewAnalogSensorDriver] func NewThermalZoneDriver(a AnalogReader, zoneID string, opts ...interface{}) *ThermalZoneDriver { degreeScaler := func(input int) float64 { return float64(input) / 1000 } d := ThermalZoneDriver{ AnalogSensorDriver: NewAnalogSensorDriver(a, zoneID, WithSensorScaler(degreeScaler)), thermalZoneCfg: &thermalZoneConfiguration{ scaleUnit: func(input float64) float64 { return input }, // 1:1 in °C }, } d.driverCfg.name = gobot.DefaultName("ThermalZone") d.analogRead = d.thermalZoneRead for _, opt := range opts { switch o := opt.(type) { case optionApplier: o.apply(d.driverCfg) case sensorOptionApplier: o.apply(d.sensorCfg) case thermalZoneOptionApplier: o.apply(d.thermalZoneCfg) default: panic(fmt.Sprintf("'%s' can not be applied on '%s'", opt, d.driverCfg.name)) } } return &d } // WithFahrenheit substitute the default 1:1 °C scaler by a scaler for °F func WithFahrenheit() thermalZoneOptionApplier { // (1°C × 9/5) + 32 = 33,8°F unitscaler := func(input float64) float64 { return input*9.0/5.0 + 32.0 } return thermalZoneUnitscalerOption{unitscaler: unitscaler} } // thermalZoneRead overrides and extends the analogSensorRead() function to add the unit scaler func (d *ThermalZoneDriver) thermalZoneRead() (int, float64, error) { if _, _, err := d.analogSensorRead(); err != nil { return 0, 0, err } // apply unit scaler on value d.lastValue = d.thermalZoneCfg.scaleUnit(d.lastValue) return d.lastRawValue, d.lastValue, nil } func (o thermalZoneUnitscalerOption) apply(cfg *thermalZoneConfiguration) { cfg.scaleUnit = o.unitscaler } ================================================ FILE: drivers/aio/thermalzone_driver_test.go ================================================ package aio import ( "strings" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestNewThermalZoneDriver(t *testing.T) { // arrange const pin = "thermal_zone0" a := newAioTestAdaptor() // act d := NewThermalZoneDriver(a, pin) // assert: driver attributes assert.IsType(t, &ThermalZoneDriver{}, d) assert.NotNil(t, d.driverCfg) assert.True(t, strings.HasPrefix(d.Name(), "ThermalZone")) assert.Equal(t, a, d.Connection()) require.NoError(t, d.afterStart()) require.NoError(t, d.beforeHalt()) assert.NotNil(t, d.Commander) assert.NotNil(t, d.mutex) // assert: sensor attributes assert.Equal(t, pin, d.Pin()) assert.InDelta(t, 0.0, d.lastValue, 0, 0) assert.Equal(t, 0, d.lastRawValue) assert.Nil(t, d.halt) // will be created on initialize, if cyclic reading is on assert.NotNil(t, d.Eventer) require.NotNil(t, d.sensorCfg) assert.Equal(t, time.Duration(0), d.sensorCfg.readInterval) assert.NotNil(t, d.sensorCfg.scale) // assert: thermal zone attributes require.NotNil(t, d.thermalZoneCfg) require.NotNil(t, d.thermalZoneCfg.scaleUnit) assert.InDelta(t, 1.0, d.thermalZoneCfg.scaleUnit(1), 0.0) } func TestNewThermalZoneDriver_options(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithName() option, least one // option of this driver and one of another driver (which should lead to panic). Further tests for options can also // be done by call of "WithOption(val).apply(cfg)". // arrange const ( myName = "outlet temperature" cycReadDur = 10 * time.Millisecond ) panicFunc := func() { NewThermalZoneDriver(newAioTestAdaptor(), "1", WithName("crazy"), WithActuatorScaler(func(float64) int { return 0 })) } // act d := NewThermalZoneDriver(newAioTestAdaptor(), "1", WithName(myName), WithSensorCyclicRead(cycReadDur), WithFahrenheit()) // assert assert.Equal(t, cycReadDur, d.sensorCfg.readInterval) assert.InDelta(t, 33.8, d.thermalZoneCfg.scaleUnit(1), 0.0) // (1°C × 9/5) + 32 = 33,8°F assert.Equal(t, myName, d.Name()) assert.PanicsWithValue(t, "'scaler option for analog actuators' can not be applied on 'crazy'", panicFunc) } func TestThermalZoneWithSensorCyclicRead_PublishesTemperatureInFahrenheit(t *testing.T) { // arrange sem := make(chan bool) a := newAioTestAdaptor() d := NewThermalZoneDriver(a, "1", WithSensorCyclicRead(10*time.Millisecond), WithFahrenheit()) a.analogReadFunc = func() (int, error) { return -100000, nil // -100.000 °C } // act: start cyclic reading require.NoError(t, d.Start()) // assert _ = d.Once(d.Event(Value), func(data interface{}) { //nolint:forcetypeassert // ok here assert.InDelta(t, -148.0, data.(float64), 0.0) sem <- true }) select { case <-sem: case <-time.After(1 * time.Second): require.Fail(t, " Temperature Sensor Event \"Data\" was not published") } assert.InDelta(t, -148.0, d.Value(), 0.0) } ================================================ FILE: drivers/ble/LICENSE ================================================ Copyright (c) 2014-2018 The Hybrid Group Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: drivers/ble/README.md ================================================ # BLE This package provides drivers for [Bluetooth LE (BLE)](http://en.wikipedia.org/wiki/Bluetooth_low_energy) devices. It is normally used by connecting an [BLE client adaptor](https://github.com/hybridgroup/gobot/tree/release/platforms/bleclient) that supports the needed interfaces for BLE devices. ## Getting Started Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) and the README files in the subfolders. ## Hardware Support Gobot has a extensible system for connecting to hardware devices. The following BLE devices are currently supported: - Battery Service - Device Information Service - Generic Access Service - Microbit: Accelerometer - Microbit: Button - Microbit: IO Pin - Microbit: LED - Microbit: Magnetometer - Microbit: Temperature - Serial Port over BLE - Sphero: BB8 - Sphero: Ollie - Sphero: SPRK+ ================================================ FILE: drivers/ble/battery_driver.go ================================================ package ble import ( "bytes" "gobot.io/x/gobot/v2" ) const batteryCharaShort = "2a19" // BatteryDriver represents the battery service for a BLE peripheral type BatteryDriver struct { *Driver gobot.Eventer } // NewBatteryDriver creates a new driver func NewBatteryDriver(a gobot.BLEConnector, opts ...OptionApplier) *BatteryDriver { d := &BatteryDriver{ Driver: NewDriver(a, "Battery", nil, nil, opts...), Eventer: gobot.NewEventer(), } return d } // GetBatteryLevel reads and returns the current battery level func (d *BatteryDriver) GetBatteryLevel() (uint8, error) { c, err := d.Adaptor().ReadCharacteristic(batteryCharaShort) if err != nil { return 0, err } buf := bytes.NewBuffer(c) val, _ := buf.ReadByte() level := val return level, nil } ================================================ FILE: drivers/ble/battery_driver_test.go ================================================ package ble import ( "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble/testutil" ) var _ gobot.Driver = (*BatteryDriver)(nil) func TestNewBatteryDriver(t *testing.T) { // arrange d := NewBatteryDriver(testutil.NewBleTestAdaptor()) // act & assert assert.True(t, strings.HasPrefix(d.Name(), "Battery")) assert.NotNil(t, d.Eventer) } func TestNewBatteryDriverWithName(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithName() option. Further // tests for options can also be done by call of "WithOption(val).apply(cfg)". // arrange const newName = "new name" a := testutil.NewBleTestAdaptor() // act d := NewBatteryDriver(a, WithName(newName)) // assert assert.Equal(t, newName, d.Name()) } func TestBatteryDriverRead(t *testing.T) { // arrange a := testutil.NewBleTestAdaptor() d := NewBatteryDriver(a) a.SetReadCharacteristicTestFunc(func(cUUID string) ([]byte, error) { if cUUID == "2a19" { return []byte{20}, nil } return nil, nil }) // act level, err := d.GetBatteryLevel() // assert require.NoError(t, err) assert.Equal(t, uint8(20), level) } ================================================ FILE: drivers/ble/ble_driver.go ================================================ package ble import ( "log" "sync" "gobot.io/x/gobot/v2" ) // OptionApplier needs to be implemented by each configurable option type type OptionApplier interface { apply(cfg *configuration) } // configuration contains all changeable attributes of the driver. type configuration struct { name string } // nameOption is the type for applying another name to the configuration type nameOption string // Driver implements the interface gobot.Driver. type Driver struct { gobot.Commander connection interface{} driverCfg *configuration afterStart func() error beforeHalt func() error mutex *sync.Mutex } // NewDriver creates a new basic BLE gobot driver. func NewDriver( a interface{}, name string, afterStart func() error, beforeHalt func() error, opts ...OptionApplier, ) *Driver { if afterStart == nil { afterStart = func() error { return nil } } if beforeHalt == nil { beforeHalt = func() error { return nil } } d := Driver{ driverCfg: &configuration{name: gobot.DefaultName(name)}, connection: a, afterStart: afterStart, beforeHalt: beforeHalt, Commander: gobot.NewCommander(), mutex: &sync.Mutex{}, } for _, o := range opts { o.apply(d.driverCfg) } return &d } // WithName is used to replace the default name of the driver. func WithName(name string) OptionApplier { return nameOption(name) } // Name returns the name of the driver. func (d *Driver) Name() string { return d.driverCfg.name } // SetName sets the name of the driver. // Deprecated: Please use option [ble.WithName] instead. func (d *Driver) SetName(name string) { WithName(name).apply(d.driverCfg) } // Connection returns the gobot connection of the driver. func (d *Driver) Connection() gobot.Connection { if d.connection == nil { log.Printf("%s has no connection\n", d.driverCfg.name) return nil } if conn, ok := d.connection.(gobot.Connection); ok { return conn } log.Printf("%s has no gobot connection\n", d.driverCfg.name) return nil } // Start initializes the driver. func (d *Driver) Start() error { d.mutex.Lock() defer d.mutex.Unlock() // currently there is nothing to do here for the driver return d.afterStart() } // Halt halts the driver. func (d *Driver) Halt() error { d.mutex.Lock() defer d.mutex.Unlock() // currently there is nothing to do after halt for the driver return d.beforeHalt() } // Adaptor returns the BLE adaptor func (d *Driver) Adaptor() gobot.BLEConnector { if d.connection == nil { log.Printf("%s has no connection\n", d.driverCfg.name) return nil } if a, ok := d.connection.(gobot.BLEConnector); ok { return a } log.Printf("%s has no BLE connector\n", d.driverCfg.name) return nil } func (d *Driver) Mutex() *sync.Mutex { return d.mutex } // apply change the name in the configuration. func (o nameOption) apply(c *configuration) { c.name = string(o) } ================================================ FILE: drivers/ble/ble_driver_test.go ================================================ package ble import ( "fmt" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble/testutil" ) var _ gobot.Driver = (*Driver)(nil) func initTestDriver() *Driver { a := testutil.NewBleTestAdaptor() d := NewDriver(a, "BLE_BASIC", nil, nil) return d } func TestNewDriver(t *testing.T) { // arrange const name = "mybot" a := testutil.NewBleTestAdaptor() // act d := NewDriver(a, name, nil, nil) // assert assert.IsType(t, &Driver{}, d) assert.NotNil(t, d.driverCfg) assert.True(t, strings.HasPrefix(d.Name(), name)) assert.Equal(t, a, d.Connection()) require.NoError(t, d.afterStart()) require.NoError(t, d.beforeHalt()) assert.NotNil(t, d.Commander) assert.NotNil(t, d.mutex) } func TestNewDriverWithName(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithName() option. Further // tests for options can also be done by call of "WithOption(val).apply(cfg)". // arrange const ( name = "mybot" newName = "overwrite mybot" ) a := testutil.NewBleTestAdaptor() // act d := NewDriver(a, name, nil, nil, WithName(newName)) // assert assert.Equal(t, newName, d.Name()) } func Test_applyWithName(t *testing.T) { // arrange const name = "mybot" cfg := configuration{name: "oldname"} // act WithName(name).apply(&cfg) // assert assert.Equal(t, name, cfg.name) } func TestStart(t *testing.T) { // arrange d := initTestDriver() // act, assert require.NoError(t, d.Start()) // arrange after start function d.afterStart = func() error { return fmt.Errorf("after start error") } // act, assert require.EqualError(t, d.Start(), "after start error") } func TestHalt(t *testing.T) { // arrange d := initTestDriver() // act, assert require.NoError(t, d.Halt()) // arrange after start function d.beforeHalt = func() error { return fmt.Errorf("before halt error") } // act, assert require.EqualError(t, d.Halt(), "before halt error") } func TestAdaptor(t *testing.T) { wrongConnectorType := struct { a uint32 }{} // arrange a := testutil.NewBleTestAdaptor() d := NewDriver(a, "BLE_BASIC", nil, nil) // act, assert assert.Equal(t, a, d.Adaptor()) // arrange wrong connector type d.connection = wrongConnectorType // act, assert assert.Nil(t, d.Adaptor()) } ================================================ FILE: drivers/ble/device_information_driver.go ================================================ package ble import ( "bytes" "gobot.io/x/gobot/v2" ) const ( deviceInformationModelNumberCharaShort = "2a24" deviceInformationFirmwareRevisionCharaShort = "2a26" deviceInformationHardwareRevisionCharaShort = "2a27" deviceInformationManufacturerNameCharaShort = "2a29" deviceInformationPnPIdCharaShort = "2a50" ) // DeviceInformationDriver represents the device information service for a BLE peripheral type DeviceInformationDriver struct { *Driver gobot.Eventer } // NewDeviceInformationDriver creates a new driver func NewDeviceInformationDriver(a gobot.BLEConnector, opts ...OptionApplier) *DeviceInformationDriver { n := &DeviceInformationDriver{ Driver: NewDriver(a, "DeviceInformation", nil, nil, opts...), Eventer: gobot.NewEventer(), } return n } // GetModelNumber returns the model number for the BLE Peripheral func (d *DeviceInformationDriver) GetModelNumber() (string, error) { c, err := d.Adaptor().ReadCharacteristic(deviceInformationModelNumberCharaShort) if err != nil { return "", err } buf := bytes.NewBuffer(c) model := buf.String() return model, nil } // GetFirmwareRevision returns the firmware revision for the BLE Peripheral func (d *DeviceInformationDriver) GetFirmwareRevision() (string, error) { c, err := d.Adaptor().ReadCharacteristic(deviceInformationFirmwareRevisionCharaShort) if err != nil { return "", err } buf := bytes.NewBuffer(c) val := buf.String() return val, nil } // GetHardwareRevision returns the hardware revision for the BLE Peripheral func (d *DeviceInformationDriver) GetHardwareRevision() (string, error) { c, err := d.Adaptor().ReadCharacteristic(deviceInformationHardwareRevisionCharaShort) if err != nil { return "", err } buf := bytes.NewBuffer(c) val := buf.String() return val, nil } // GetManufacturerName returns the manufacturer name for the BLE Peripheral func (d *DeviceInformationDriver) GetManufacturerName() (string, error) { c, err := d.Adaptor().ReadCharacteristic(deviceInformationManufacturerNameCharaShort) if err != nil { return "", err } buf := bytes.NewBuffer(c) val := buf.String() return val, nil } // GetPnPId returns the PnP ID for the BLE Peripheral func (d *DeviceInformationDriver) GetPnPId() (string, error) { c, err := d.Adaptor().ReadCharacteristic(deviceInformationPnPIdCharaShort) if err != nil { return "", err } buf := bytes.NewBuffer(c) val := buf.String() return val, nil } ================================================ FILE: drivers/ble/device_information_driver_test.go ================================================ package ble import ( "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble/testutil" ) var _ gobot.Driver = (*DeviceInformationDriver)(nil) func TestNewDeviceInformationDriver(t *testing.T) { // arrange d := NewDeviceInformationDriver(testutil.NewBleTestAdaptor()) // act & assert assert.True(t, strings.HasPrefix(d.Name(), "DeviceInformation")) assert.NotNil(t, d.Eventer) } func TestNewDeviceInformationDriverWithName(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithName() option. Further // tests for options can also be done by call of "WithOption(val).apply(cfg)". // arrange const newName = "new name" a := testutil.NewBleTestAdaptor() // act d := NewDeviceInformationDriver(a, WithName(newName)) // assert assert.Equal(t, newName, d.Name()) } func TestDeviceInformationGetModelNumber(t *testing.T) { // arrange d := NewDeviceInformationDriver(testutil.NewBleTestAdaptor()) // act modelNo, err := d.GetModelNumber() // assert require.NoError(t, err) assert.Equal(t, "2a24", modelNo) } func TestDeviceInformationGetFirmwareRevision(t *testing.T) { // arrange d := NewDeviceInformationDriver(testutil.NewBleTestAdaptor()) // act fwRev, err := d.GetFirmwareRevision() // assert require.NoError(t, err) assert.Equal(t, "2a26", fwRev) } func TestDeviceInformationGetHardwareRevision(t *testing.T) { // arrange d := NewDeviceInformationDriver(testutil.NewBleTestAdaptor()) // act hwRev, err := d.GetHardwareRevision() // assert require.NoError(t, err) assert.Equal(t, "2a27", hwRev) } func TestDeviceInformationGetManufacturerName(t *testing.T) { // arrange d := NewDeviceInformationDriver(testutil.NewBleTestAdaptor()) // act manuName, err := d.GetManufacturerName() // assert require.NoError(t, err) assert.Equal(t, "2a29", manuName) } func TestDeviceInformationGetPnPId(t *testing.T) { // arrange d := NewDeviceInformationDriver(testutil.NewBleTestAdaptor()) // act pid, err := d.GetPnPId() // assert require.NoError(t, err) assert.Equal(t, "2a50", pid) } ================================================ FILE: drivers/ble/doc.go ================================================ /* Package ble provides the Gobot drivers for several Bluetooth LE Services. For more information refer to the README: https://github.com/hybridgroup/gobot/blob/release/drivers/ble/README.md */ package ble // import "gobot.io/x/gobot/v2/drivers/ble" ================================================ FILE: drivers/ble/generic_access_driver.go ================================================ package ble import ( "bytes" "encoding/binary" "gobot.io/x/gobot/v2" ) const ( genericAccessDeviceNameCharaShort = "2a00" genericAccessAppearanceCharaShort = "2a01" ) // GenericAccessDriver represents the Generic Access Service for a BLE Peripheral type GenericAccessDriver struct { *Driver gobot.Eventer } // NewGenericAccessDriver creates a GenericAccessDriver func NewGenericAccessDriver(a gobot.BLEConnector, opts ...OptionApplier) *GenericAccessDriver { d := &GenericAccessDriver{ Driver: NewDriver(a, "GenericAccess", nil, nil, opts...), Eventer: gobot.NewEventer(), } return d } // GetDeviceName returns the device name for the BLE Peripheral func (d *GenericAccessDriver) GetDeviceName() (string, error) { c, err := d.Adaptor().ReadCharacteristic(genericAccessDeviceNameCharaShort) if err != nil { return "", err } buf := bytes.NewBuffer(c) val := buf.String() return val, nil } // GetAppearance returns the appearance string for the BLE Peripheral func (d *GenericAccessDriver) GetAppearance() (string, error) { c, err := d.Adaptor().ReadCharacteristic(genericAccessAppearanceCharaShort) if err != nil { return "", err } buf := bytes.NewBuffer(c) var val uint16 if err := binary.Read(buf, binary.LittleEndian, &val); err != nil { return "", err } return appearances[val], nil } var appearances = map[uint16]string{ 0: "Unknown", 1024: "Generic Glucose Meter", 1088: "Generic: Running Walking Sensor", 1089: "Running Walking Sensor: In-Shoe", 1090: "Running Walking Sensor: On-Shoe", 1091: "Running Walking Sensor: On-Hip", 1152: "Generic: Cycling", 1153: "Cycling: Cycling Computer", 1154: "Cycling: Speed Sensor", 1155: "Cycling: Cadence Sensor", 1156: "Cycling: Power Sensor", 1157: "Cycling: Speed and Cadence Sensor", 128: "Generic Computer", 192: "Generic Watch", 193: "Watch: Sports Watch", 256: "Generic Clock", 3136: "Generic: Pulse Oximeter", 3137: "Fingertip Pulse", 3138: "Wrist Worn", 320: "Generic Display", 3200: "Generic: Weight Scale", 384: "Generic Remote Control", 448: "Generic Eye-glasses", 512: "Generic Tag", 5184: "Generic: Outdoor Sports Activity", 5185: "Location Display Device", 5186: "Location and Navigation Display Device", 5187: "Location Pod", 5188: "Location and Navigation Pod", 576: "Generic Keyring", 64: "Generic Phone", 640: "Generic Media Player", 704: "Generic Barcode Scanner", 768: "Generic Thermometer", 769: "Thermometer: Ear", 832: "Generic Heart rate Sensor", 833: "Heart Rate Sensor: Heart Rate Belt", 896: "Generic Blood Pressure", 897: "Blood Pressure: Arm Blood", 898: "Blood Pressure: Wrist Blood", 960: "Human Interface Device (HID)", 961: "Keyboard", 962: "Mouse", 963: "Joystick", 964: "Gamepad", 965: "Digitizer Tablet", 966: "Card Reader", 967: "Digital Pen", 968: "Barcode Scanner", } ================================================ FILE: drivers/ble/generic_access_driver_test.go ================================================ package ble import ( "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble/testutil" ) var _ gobot.Driver = (*GenericAccessDriver)(nil) func TestNewGenericAccessDriver(t *testing.T) { // arrange d := NewGenericAccessDriver(testutil.NewBleTestAdaptor()) // act assert.True(t, strings.HasPrefix(d.Name(), "GenericAccess")) assert.NotNil(t, d.Eventer) } func TestNewGenericAccessDriverWithName(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithName() option. Further // tests for options can also be done by call of "WithOption(val).apply(cfg)". // arrange const newName = "new name" a := testutil.NewBleTestAdaptor() // act d := NewGenericAccessDriver(a, WithName(newName)) // assert assert.Equal(t, newName, d.Name()) } func TestGenericAccessDriverGetDeviceName(t *testing.T) { // arrange d := NewGenericAccessDriver(testutil.NewBleTestAdaptor()) // act devName, err := d.GetDeviceName() // assert require.NoError(t, err) assert.Equal(t, "2a00", devName) } func TestGenericAccessDriverGetAppearance(t *testing.T) { // arrange a := testutil.NewBleTestAdaptor() d := NewGenericAccessDriver(a) a.SetReadCharacteristicTestFunc(func(cUUID string) ([]byte, error) { if cUUID == "2a01" { return []byte{128, 0}, nil } return nil, nil }) // act app, err := d.GetAppearance() // assert require.NoError(t, err) assert.Equal(t, "Generic Computer", app) } ================================================ FILE: drivers/ble/microbit/LICENSE ================================================ Copyright (c) 2014-2018 The Hybrid Group Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: drivers/ble/microbit/accelerometer_driver.go ================================================ package microbit import ( "bytes" "encoding/binary" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble" ) const ( // accelerometerService = "e95d0753251d470aa062fa1922dfa9a8" accelerometerChara = "e95dca4b251d470aa062fa1922dfa9a8" AccelerometerEvent = "accelerometer" ) // AccelerometerDriver is the Gobot driver for the Microbit's built-in accelerometer type AccelerometerDriver struct { *ble.Driver gobot.Eventer } type AccelerometerData struct { X float32 Y float32 Z float32 } // NewAccelerometerDriver creates a AccelerometerDriver func NewAccelerometerDriver(a gobot.BLEConnector, opts ...ble.OptionApplier) *AccelerometerDriver { d := &AccelerometerDriver{ Eventer: gobot.NewEventer(), } d.Driver = ble.NewDriver(a, "Microbit Accelerometer", d.initialize, nil, opts...) d.AddEvent(AccelerometerEvent) return d } // initialize tells driver to get ready to do work func (d *AccelerometerDriver) initialize() error { // subscribe to accelerometer notifications return d.Adaptor().Subscribe(accelerometerChara, func(data []byte) { a := struct{ x, y, z int16 }{x: 0, y: 0, z: 0} buf := bytes.NewBuffer(data) if err := binary.Read(buf, binary.LittleEndian, &a.x); err != nil { panic(err) } if err := binary.Read(buf, binary.LittleEndian, &a.y); err != nil { panic(err) } if err := binary.Read(buf, binary.LittleEndian, &a.z); err != nil { panic(err) } result := &AccelerometerData{ X: float32(a.x) / 1000.0, Y: float32(a.y) / 1000.0, Z: float32(a.z) / 1000.0, } d.Publish(d.Event(AccelerometerEvent), result) }) } ================================================ FILE: drivers/ble/microbit/accelerometer_driver_test.go ================================================ //nolint:forcetypeassert,dupl // ok here package microbit import ( "strings" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble" "gobot.io/x/gobot/v2/drivers/ble/testutil" ) var _ gobot.Driver = (*AccelerometerDriver)(nil) func TestNewAccelerometerDriver(t *testing.T) { d := NewAccelerometerDriver(testutil.NewBleTestAdaptor()) assert.IsType(t, &AccelerometerDriver{}, d) assert.True(t, strings.HasPrefix(d.Name(), "Microbit Accelerometer")) assert.NotNil(t, d.Eventer) } func TestNewAccelerometerDriverWithName(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithName() option. Further // tests for options can also be done by call of "WithOption(val).apply(cfg)". // arrange const newName = "new name" a := testutil.NewBleTestAdaptor() // act d := NewAccelerometerDriver(a, ble.WithName(newName)) // assert assert.Equal(t, newName, d.Name()) } func TestAccelerometerStartAndHalt(t *testing.T) { d := NewAccelerometerDriver(testutil.NewBleTestAdaptor()) require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestAccelerometerReadData(t *testing.T) { sem := make(chan bool) a := testutil.NewBleTestAdaptor() d := NewAccelerometerDriver(a) require.NoError(t, d.Start()) err := d.On("accelerometer", func(data interface{}) { assert.InDelta(t, float32(8.738), data.(*AccelerometerData).X, 0.0) assert.InDelta(t, float32(8.995), data.(*AccelerometerData).Y, 0.0) assert.InDelta(t, float32(9.252), data.(*AccelerometerData).Z, 0.0) sem <- true }) require.NoError(t, err) a.SendTestDataToSubscriber([]byte{0x22, 0x22, 0x23, 0x23, 0x24, 0x24}) select { case <-sem: case <-time.After(100 * time.Millisecond): require.Fail(t, "Microbit Event \"Accelerometer\" was not published") } } ================================================ FILE: drivers/ble/microbit/button_driver.go ================================================ package microbit import ( "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble" ) const ( // buttonService = "e95d9882251d470aa062fa1922dfa9a8" buttonAChara = "e95dda90251d470aa062fa1922dfa9a8" buttonBChara = "e95dda91251d470aa062fa1922dfa9a8" ButtonAEvent = "buttonA" ButtonBEvent = "buttonB" ) // ButtonDriver is the Gobot driver for the Microbit's built-in buttons type ButtonDriver struct { *ble.Driver gobot.Eventer } // NewButtonDriver creates a new driver func NewButtonDriver(a gobot.BLEConnector, opts ...ble.OptionApplier) *ButtonDriver { d := &ButtonDriver{ Eventer: gobot.NewEventer(), } d.Driver = ble.NewDriver(a, "Microbit Button", d.initialize, nil, opts...) d.AddEvent(ButtonAEvent) d.AddEvent(ButtonBEvent) return d } // initialize tells driver to get ready to do work func (d *ButtonDriver) initialize() error { // subscribe to button A notifications if err := d.Adaptor().Subscribe(buttonAChara, func(data []byte) { d.Publish(d.Event(ButtonAEvent), data) }); err != nil { return err } // subscribe to button B notifications return d.Adaptor().Subscribe(buttonBChara, func(data []byte) { d.Publish(d.Event(ButtonBEvent), data) }) } ================================================ FILE: drivers/ble/microbit/button_driver_test.go ================================================ package microbit import ( "strings" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble" "gobot.io/x/gobot/v2/drivers/ble/testutil" ) var _ gobot.Driver = (*ButtonDriver)(nil) func TestNewButtonDriver(t *testing.T) { d := NewButtonDriver(testutil.NewBleTestAdaptor()) assert.IsType(t, &ButtonDriver{}, d) assert.True(t, strings.HasPrefix(d.Name(), "Microbit Button")) assert.NotNil(t, d.Eventer) } func TestNewButtonDriverWithName(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithName() option. Further // tests for options can also be done by call of "WithOption(val).apply(cfg)". // arrange const newName = "new name" a := testutil.NewBleTestAdaptor() // act d := NewButtonDriver(a, ble.WithName(newName)) // assert assert.Equal(t, newName, d.Name()) } func TestButtonStartAndHalt(t *testing.T) { d := NewButtonDriver(testutil.NewBleTestAdaptor()) require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestButtonReadData(t *testing.T) { sem := make(chan bool) a := testutil.NewBleTestAdaptor() d := NewButtonDriver(a) require.NoError(t, d.Start()) err := d.On("buttonB", func(data interface{}) { sem <- true }) require.NoError(t, err) a.SendTestDataToSubscriber([]byte{1}) select { case <-sem: case <-time.After(100 * time.Millisecond): require.Fail(t, "Microbit Event \"ButtonB\" was not published") } } ================================================ FILE: drivers/ble/microbit/doc.go ================================================ /* Package microbit contains the Gobot drivers for the Microbit platform. For more information refer to the microbit README: https://github.com/hybridgroup/gobot/blob/release/platforms/microbit/README.md */ package microbit // import "gobot.io/x/gobot/v2/drivers/ble/microbit" ================================================ FILE: drivers/ble/microbit/io_pin_driver.go ================================================ package microbit import ( "bytes" "encoding/binary" "errors" "strconv" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble" "gobot.io/x/gobot/v2/drivers/common/bit" ) const ( // ioPinService = "e95d127b251d470aa062fa1922dfa9a8" pinDataChara = "e95d8d00251d470aa062fa1922dfa9a8" pinADConfigChara = "e95d5899251d470aa062fa1922dfa9a8" pinIOConfigChara = "e95db9fe251d470aa062fa1922dfa9a8" ) // IOPinDriver is the Gobot driver for the Microbit's built-in digital and analog I/O type IOPinDriver struct { *ble.Driver gobot.Eventer adMask int ioMask int } // pinData has the read data for a specific digital pin type pinData struct { pin uint8 value uint8 } // NewIOPinDriver creates a new driver func NewIOPinDriver(a gobot.BLEConnector, opts ...ble.OptionApplier) *IOPinDriver { d := &IOPinDriver{ Eventer: gobot.NewEventer(), } d.Driver = ble.NewDriver(a, "Microbit IO Pins", d.initialize, nil, opts...) return d } // initialize tells driver to get ready to do work func (d *IOPinDriver) initialize() error { if _, err := d.ReadPinADConfig(); err != nil { return err } _, err := d.ReadPinIOConfig() return err } // WritePinData writes the pin data for a single pin func (d *IOPinDriver) WritePinData(pin string, data byte) error { i, err := strconv.Atoi(pin) if err != nil { return err } buf := []byte{byte(i), data} err = d.Adaptor().WriteCharacteristic(pinDataChara, buf) return err } // ReadPinADConfig reads and returns the pin A/D config mask for all pins func (d *IOPinDriver) ReadPinADConfig() (int, error) { c, err := d.Adaptor().ReadCharacteristic(pinADConfigChara) if err != nil { return 0, err } var result byte for i := 0; i < 4; i++ { result |= c[i] << uint(i) //nolint:gosec // ok here } d.adMask = int(result) return int(result), nil } // WritePinADConfig writes the pin A/D config mask for all pins func (d *IOPinDriver) WritePinADConfig(config int) error { d.adMask = config data := &bytes.Buffer{} //nolint:gosec // TODO: fix later if err := binary.Write(data, binary.LittleEndian, uint32(config)); err != nil { return err } return d.Adaptor().WriteCharacteristic(pinADConfigChara, data.Bytes()) } // ReadPinIOConfig reads and returns the pin IO config mask for all pins func (d *IOPinDriver) ReadPinIOConfig() (int, error) { c, err := d.Adaptor().ReadCharacteristic(pinIOConfigChara) if err != nil { return 0, err } var result byte for i := 0; i < 4; i++ { result |= c[i] << uint(i) //nolint:gosec // ok here } d.ioMask = int(result) return int(result), nil } // WritePinIOConfig writes the pin I/O config mask for all pins func (d *IOPinDriver) WritePinIOConfig(config int) error { d.ioMask = config data := &bytes.Buffer{} //nolint:gosec // TODO: fix later if err := binary.Write(data, binary.LittleEndian, uint32(config)); err != nil { return err } return d.Adaptor().WriteCharacteristic(pinIOConfigChara, data.Bytes()) } // DigitalRead reads from a pin func (d *IOPinDriver) DigitalRead(pin string) (int, error) { p, err := validatedPin(pin) if err != nil { return 0, err } if err := d.ensureDigital(p); err != nil { return 0, err } if err := d.ensureInput(p); err != nil { return 0, err } pins, err := d.readAllPinData() if err != nil { return 0, err } return int(pins[p].value), nil } // DigitalWrite writes to a pin func (d *IOPinDriver) DigitalWrite(pin string, level byte) error { p, err := validatedPin(pin) if err != nil { return err } if err := d.ensureDigital(p); err != nil { return err } if err := d.ensureOutput(p); err != nil { return err } return d.WritePinData(pin, level) } // AnalogRead reads from a pin func (d *IOPinDriver) AnalogRead(pin string) (int, error) { p, err := validatedPin(pin) if err != nil { return 0, err } if err := d.ensureAnalog(p); err != nil { return 0, err } if err := d.ensureInput(p); err != nil { return 0, err } pins, err := d.readAllPinData() if err != nil { return 0, err } return int(pins[p].value), nil } func (d *IOPinDriver) ensureDigital(pin int) error { //nolint:gosec // TODO: fix later if bit.IsSet(d.adMask, uint8(pin)) { return d.WritePinADConfig(bit.Clear(d.adMask, uint8(pin))) } return nil } func (d *IOPinDriver) ensureAnalog(pin int) error { //nolint:gosec // TODO: fix later if !bit.IsSet(d.adMask, uint8(pin)) { return d.WritePinADConfig(bit.Set(d.adMask, uint8(pin))) } return nil } func (d *IOPinDriver) ensureInput(pin int) error { //nolint:gosec // TODO: fix later if !bit.IsSet(d.ioMask, uint8(pin)) { return d.WritePinIOConfig(bit.Set(d.ioMask, uint8(pin))) } return nil } func (d *IOPinDriver) ensureOutput(pin int) error { //nolint:gosec // TODO: fix later if bit.IsSet(d.ioMask, uint8(pin)) { return d.WritePinIOConfig(bit.Clear(d.ioMask, uint8(pin))) //nolint:gosec // TODO: fix later } return nil } func (d *IOPinDriver) readAllPinData() ([]pinData, error) { c, _ := d.Adaptor().ReadCharacteristic(pinDataChara) buf := bytes.NewBuffer(c) pinsData := make([]pinData, buf.Len()/2) for i := 0; i < buf.Len()/2; i++ { pin, err := buf.ReadByte() if err != nil { return nil, err } value, err := buf.ReadByte() if err != nil { return nil, err } pinData := pinData{ pin: pin, value: value, } pinsData[i] = pinData } return pinsData, nil } func validatedPin(pin string) (int, error) { i, err := strconv.Atoi(pin) if err != nil { return 0, err } if i < 0 || i > 2 { return 0, errors.New("invalid pin") } return i, nil } ================================================ FILE: drivers/ble/microbit/io_pin_driver_test.go ================================================ package microbit import ( "errors" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" "gobot.io/x/gobot/v2/drivers/ble" "gobot.io/x/gobot/v2/drivers/ble/testutil" "gobot.io/x/gobot/v2/drivers/gpio" ) // the MicrobitIOPinDriver is a Driver var _ gobot.Driver = (*IOPinDriver)(nil) // that supports the DigitalReader, DigitalWriter, & AnalogReader interfaces var ( _ gpio.DigitalReader = (*IOPinDriver)(nil) _ gpio.DigitalWriter = (*IOPinDriver)(nil) _ aio.AnalogReader = (*IOPinDriver)(nil) ) func TestNewIOPinDriver(t *testing.T) { d := NewIOPinDriver(testutil.NewBleTestAdaptor()) assert.IsType(t, &IOPinDriver{}, d) assert.True(t, strings.HasPrefix(d.Name(), "Microbit IO Pin")) assert.NotNil(t, d.Eventer) } func TestNewIOPinDriverWithName(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithName() option. Further // tests for options can also be done by call of "WithOption(val).apply(cfg)". // arrange const newName = "new name" a := testutil.NewBleTestAdaptor() // act d := NewIOPinDriver(a, ble.WithName(newName)) // assert assert.Equal(t, newName, d.Name()) } func TestIOPinStartAndHalt(t *testing.T) { a := testutil.NewBleTestAdaptor() d := NewIOPinDriver(a) a.SetReadCharacteristicTestFunc(func(cUUID string) ([]byte, error) { return []byte{0, 1, 1, 0}, nil }) require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestIOPinStartError(t *testing.T) { a := testutil.NewBleTestAdaptor() d := NewIOPinDriver(a) a.SetReadCharacteristicTestFunc(func(cUUID string) ([]byte, error) { return nil, errors.New("read error") }) require.ErrorContains(t, d.Start(), "read error") } func TestIOPinDigitalRead(t *testing.T) { a := testutil.NewBleTestAdaptor() d := NewIOPinDriver(a) a.SetReadCharacteristicTestFunc(func(cUUID string) ([]byte, error) { return []byte{0, 1, 1, 0, 2, 1}, nil }) val, err := d.DigitalRead("0") require.NoError(t, err) assert.Equal(t, 1, val) val, err = d.DigitalRead("1") require.NoError(t, err) assert.Equal(t, 0, val) } func TestIOPinDigitalReadInvalidPin(t *testing.T) { a := testutil.NewBleTestAdaptor() d := NewIOPinDriver(a) _, err := d.DigitalRead("A3") require.Error(t, err) _, err = d.DigitalRead("6") require.ErrorContains(t, err, "invalid pin") } func TestIOPinDigitalWrite(t *testing.T) { a := testutil.NewBleTestAdaptor() d := NewIOPinDriver(a) // TODO: a better test require.NoError(t, d.DigitalWrite("0", 1)) } func TestIOPinDigitalWriteInvalidPin(t *testing.T) { a := testutil.NewBleTestAdaptor() d := NewIOPinDriver(a) require.Error(t, d.DigitalWrite("A3", 1)) require.ErrorContains(t, d.DigitalWrite("6", 1), "invalid pin") } func TestIOPinAnalogRead(t *testing.T) { a := testutil.NewBleTestAdaptor() d := NewIOPinDriver(a) a.SetReadCharacteristicTestFunc(func(cUUID string) ([]byte, error) { return []byte{0, 0, 1, 128, 2, 1}, nil }) val, err := d.AnalogRead("0") require.NoError(t, err) assert.Equal(t, 0, val) val, err = d.AnalogRead("1") require.NoError(t, err) assert.Equal(t, 128, val) } func TestIOPinAnalogReadInvalidPin(t *testing.T) { a := testutil.NewBleTestAdaptor() d := NewIOPinDriver(a) _, err := d.AnalogRead("A3") require.Error(t, err) _, err = d.AnalogRead("6") require.ErrorContains(t, err, "invalid pin") } func TestIOPinDigitalAnalogRead(t *testing.T) { a := testutil.NewBleTestAdaptor() d := NewIOPinDriver(a) a.SetReadCharacteristicTestFunc(func(cUUID string) ([]byte, error) { return []byte{0, 0, 1, 128, 2, 1}, nil }) val, err := d.DigitalRead("0") require.NoError(t, err) assert.Equal(t, 0, val) val, err = d.AnalogRead("0") require.NoError(t, err) assert.Equal(t, 0, val) } func TestIOPinDigitalWriteAnalogRead(t *testing.T) { a := testutil.NewBleTestAdaptor() d := NewIOPinDriver(a) a.SetReadCharacteristicTestFunc(func(cUUID string) ([]byte, error) { return []byte{0, 0, 1, 128, 2, 1}, nil }) require.NoError(t, d.DigitalWrite("1", 0)) val, err := d.AnalogRead("1") require.NoError(t, err) assert.Equal(t, 128, val) } func TestIOPinAnalogReadDigitalWrite(t *testing.T) { a := testutil.NewBleTestAdaptor() d := NewIOPinDriver(a) a.SetReadCharacteristicTestFunc(func(cUUID string) ([]byte, error) { return []byte{0, 0, 1, 128, 2, 1}, nil }) val, err := d.AnalogRead("1") require.NoError(t, err) assert.Equal(t, 128, val) require.NoError(t, d.DigitalWrite("1", 0)) } ================================================ FILE: drivers/ble/microbit/led_driver.go ================================================ package microbit import ( "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble" ) const ( // ledService = "e95dd91d251d470aa062fa1922dfa9a8" ledMatrixStateChara = "e95d7b77251d470aa062fa1922dfa9a8" ledTextChara = "e95d93ee251d470aa062fa1922dfa9a8" ledScrollingDelayChara = "e95d0d2d251d470aa062fa1922dfa9a8" ) // LEDDriver is the Gobot driver for the Microbit's LED array type LEDDriver struct { *ble.Driver gobot.Eventer } // NewLEDDriver creates a Microbit LEDDriver func NewLEDDriver(a gobot.BLEConnector, opts ...ble.OptionApplier) *LEDDriver { d := &LEDDriver{ Eventer: gobot.NewEventer(), } d.Driver = ble.NewDriver(a, "Microbit LED", nil, nil, opts...) return d } // ReadMatrix read the current LED matrix state func (b *LEDDriver) ReadMatrix() ([]byte, error) { return b.Adaptor().ReadCharacteristic(ledMatrixStateChara) } // WriteMatrix writes an array of 5 bytes to set the LED matrix func (b *LEDDriver) WriteMatrix(data []byte) error { return b.Adaptor().WriteCharacteristic(ledMatrixStateChara, data) } // WriteText writes a text message to the Microbit LED matrix func (b *LEDDriver) WriteText(msg string) error { return b.Adaptor().WriteCharacteristic(ledTextChara, []byte(msg)) } func (b *LEDDriver) ReadScrollingDelay() (uint16, error) { return 0, nil } func (b *LEDDriver) WriteScrollingDelay(delay uint16) error { buf := []byte{byte(delay)} return b.Adaptor().WriteCharacteristic(ledScrollingDelayChara, buf) } // Blank clears the LEDs on the Microbit func (b *LEDDriver) Blank() error { buf := []byte{0x00, 0x00, 0x00, 0x00, 0x00} return b.WriteMatrix(buf) } // Solid turns on all of the Microbit LEDs func (b *LEDDriver) Solid() error { buf := []byte{0x1F, 0x1F, 0x1F, 0x1F, 0x1F} return b.WriteMatrix(buf) } // UpRightArrow displays an arrow pointing upwards and to the right on the Microbit LEDs func (b *LEDDriver) UpRightArrow() error { buf := []byte{0x0F, 0x03, 0x05, 0x09, 0x10} return b.WriteMatrix(buf) } // UpLeftArrow displays an arrow pointing upwards and to the left on the Microbit LEDs func (b *LEDDriver) UpLeftArrow() error { buf := []byte{0x1E, 0x18, 0x14, 0x12, 0x01} return b.WriteMatrix(buf) } // DownRightArrow displays an arrow pointing down and to the right on the Microbit LEDs func (b *LEDDriver) DownRightArrow() error { buf := []byte{0x10, 0x09, 0x05, 0x03, 0x0F} return b.WriteMatrix(buf) } // DownLeftArrow displays an arrow pointing down and to the left on the Microbit LEDs func (b *LEDDriver) DownLeftArrow() error { buf := []byte{0x01, 0x12, 0x14, 0x18, 0x1E} return b.WriteMatrix(buf) } // Dimond displays a dimond on the Microbit LEDs func (b *LEDDriver) Dimond() error { buf := []byte{0x04, 0x0A, 0x11, 0x0A, 0x04} return b.WriteMatrix(buf) } // Smile displays a smile on the Microbit LEDs func (b *LEDDriver) Smile() error { buf := []byte{0x0A, 0x0A, 0x00, 0x11, 0x0E} return b.WriteMatrix(buf) } // Wink displays a wink on the Microbit LEDs func (b *LEDDriver) Wink() error { buf := []byte{0x08, 0x0B, 0x00, 0x11, 0x0E} return b.WriteMatrix(buf) } ================================================ FILE: drivers/ble/microbit/led_driver_test.go ================================================ package microbit import ( "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble" "gobot.io/x/gobot/v2/drivers/ble/testutil" ) var _ gobot.Driver = (*LEDDriver)(nil) func initTestLEDDriver() *LEDDriver { d := NewLEDDriver(testutil.NewBleTestAdaptor()) return d } func TestNewLEDDriver(t *testing.T) { d := NewLEDDriver(testutil.NewBleTestAdaptor()) assert.IsType(t, &LEDDriver{}, d) assert.True(t, strings.HasPrefix(d.Name(), "Microbit LED")) assert.NotNil(t, d.Eventer) } func TestNewLEDDriverWithName(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithName() option. Further // tests for options can also be done by call of "WithOption(val).apply(cfg)". // arrange const newName = "new name" a := testutil.NewBleTestAdaptor() // act d := NewLEDDriver(a, ble.WithName(newName)) // assert assert.Equal(t, newName, d.Name()) } func TestLEDWriteMatrix(t *testing.T) { d := initTestLEDDriver() require.NoError(t, d.WriteMatrix([]byte{0x01, 0x02})) } func TestLEDWriteText(t *testing.T) { d := initTestLEDDriver() require.NoError(t, d.WriteText("Hello")) } func TestLEDCommands(t *testing.T) { d := initTestLEDDriver() require.NoError(t, d.Blank()) require.NoError(t, d.Solid()) require.NoError(t, d.UpRightArrow()) require.NoError(t, d.UpLeftArrow()) require.NoError(t, d.DownRightArrow()) require.NoError(t, d.DownLeftArrow()) require.NoError(t, d.Dimond()) require.NoError(t, d.Smile()) require.NoError(t, d.Wink()) } ================================================ FILE: drivers/ble/microbit/magnetometer_driver.go ================================================ package microbit import ( "bytes" "encoding/binary" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble" ) const ( // magnetometerService = "e95df2d8251d470aa062fa1922dfa9a8" magnetometerChara = "e95dfb11251d470aa062fa1922dfa9a8" MagnetometerEvent = "magnetometer" ) // MagnetometerDriver is the Gobot driver for the Microbit's built-in magnetometer type MagnetometerDriver struct { *ble.Driver gobot.Eventer } type MagnetometerData struct { X float32 Y float32 Z float32 } // NewMagnetometerDriver creates a Microbit MagnetometerDriver func NewMagnetometerDriver(a gobot.BLEConnector, opts ...ble.OptionApplier) *MagnetometerDriver { d := &MagnetometerDriver{ Eventer: gobot.NewEventer(), } d.Driver = ble.NewDriver(a, "Microbit Magnetometer", d.initialize, nil, opts...) d.AddEvent(MagnetometerEvent) return d } // initialize tells driver to get ready to do work func (d *MagnetometerDriver) initialize() error { // subscribe to magnetometer notifications return d.Adaptor().Subscribe(magnetometerChara, func(data []byte) { a := struct{ x, y, z int16 }{x: 0, y: 0, z: 0} buf := bytes.NewBuffer(data) if err := binary.Read(buf, binary.LittleEndian, &a.x); err != nil { panic(err) } if err := binary.Read(buf, binary.LittleEndian, &a.y); err != nil { panic(err) } if err := binary.Read(buf, binary.LittleEndian, &a.z); err != nil { panic(err) } result := &MagnetometerData{ X: float32(a.x) / 1000.0, Y: float32(a.y) / 1000.0, Z: float32(a.z) / 1000.0, } d.Publish(d.Event(MagnetometerEvent), result) }) } ================================================ FILE: drivers/ble/microbit/magnetometer_driver_test.go ================================================ //nolint:forcetypeassert,dupl // ok here package microbit import ( "strings" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble" "gobot.io/x/gobot/v2/drivers/ble/testutil" ) var _ gobot.Driver = (*MagnetometerDriver)(nil) func initTestMagnetometerDriver() *MagnetometerDriver { d := NewMagnetometerDriver(testutil.NewBleTestAdaptor()) return d } func TestMagnetometerDriver(t *testing.T) { d := NewMagnetometerDriver(testutil.NewBleTestAdaptor()) assert.IsType(t, &MagnetometerDriver{}, d) assert.True(t, strings.HasPrefix(d.Name(), "Microbit Magnetometer")) assert.NotNil(t, d.Eventer) } func TestNewMagnetometerDriverWithName(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithName() option. Further // tests for options can also be done by call of "WithOption(val).apply(cfg)". // arrange const newName = "new name" a := testutil.NewBleTestAdaptor() // act d := NewMagnetometerDriver(a, ble.WithName(newName)) // assert assert.Equal(t, newName, d.Name()) } func TestMagnetometerStartAndHalt(t *testing.T) { d := initTestMagnetometerDriver() require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestMagnetometerReadData(t *testing.T) { sem := make(chan bool) a := testutil.NewBleTestAdaptor() d := NewMagnetometerDriver(a) require.NoError(t, d.Start()) err := d.On("magnetometer", func(data interface{}) { assert.InDelta(t, float32(8.738), data.(*MagnetometerData).X, 0.0) assert.InDelta(t, float32(8.995), data.(*MagnetometerData).Y, 0.0) assert.InDelta(t, float32(9.252), data.(*MagnetometerData).Z, 0.0) sem <- true }) require.NoError(t, err) a.SendTestDataToSubscriber([]byte{0x22, 0x22, 0x23, 0x23, 0x24, 0x24}) select { case <-sem: case <-time.After(100 * time.Millisecond): require.Fail(t, "Microbit Event \"Magnetometer\" was not published") } } ================================================ FILE: drivers/ble/microbit/temperature_driver.go ================================================ package microbit import ( "bytes" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble" ) const ( // temperatureService = "e95d6100251d470aa062fa1922dfa9a8" temperatureChara = "e95d9250251d470aa062fa1922dfa9a8" TemperatureEvent = "temperature" ) // TemperatureDriver is the Gobot driver for the Microbit's built-in thermometer type TemperatureDriver struct { *ble.Driver gobot.Eventer } // NewTemperatureDriver creates a Microbit TemperatureDriver func NewTemperatureDriver(a gobot.BLEConnector, opts ...ble.OptionApplier) *TemperatureDriver { d := &TemperatureDriver{ Eventer: gobot.NewEventer(), } d.Driver = ble.NewDriver(a, "Microbit Temperature", d.initialize, nil, opts...) d.AddEvent(TemperatureEvent) return d } // initialize tells driver to get ready to do work func (d *TemperatureDriver) initialize() error { // subscribe to temperature notifications return d.Adaptor().Subscribe(temperatureChara, func(data []byte) { var l int8 buf := bytes.NewBuffer(data) val, _ := buf.ReadByte() l = int8(val) d.Publish(d.Event(TemperatureEvent), l) }) } ================================================ FILE: drivers/ble/microbit/temperature_driver_test.go ================================================ package microbit import ( "strings" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble" "gobot.io/x/gobot/v2/drivers/ble/testutil" ) var _ gobot.Driver = (*TemperatureDriver)(nil) func initTestTemperatureDriver() *TemperatureDriver { d := NewTemperatureDriver(testutil.NewBleTestAdaptor()) return d } func TestNewTemperatureDriver(t *testing.T) { d := NewTemperatureDriver(testutil.NewBleTestAdaptor()) assert.IsType(t, &TemperatureDriver{}, d) assert.True(t, strings.HasPrefix(d.Name(), "Microbit Temperature")) assert.NotNil(t, d.Eventer) } func TestNewTemperatureDriverWithName(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithName() option. Further // tests for options can also be done by call of "WithOption(val).apply(cfg)". // arrange const newName = "new name" a := testutil.NewBleTestAdaptor() // act d := NewTemperatureDriver(a, ble.WithName(newName)) // assert assert.Equal(t, newName, d.Name()) } func TestTemperatureStartAndHalt(t *testing.T) { d := initTestTemperatureDriver() require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestTemperatureReadData(t *testing.T) { sem := make(chan bool) a := testutil.NewBleTestAdaptor() d := NewTemperatureDriver(a) require.NoError(t, d.Start()) err := d.On("temperature", func(data interface{}) { assert.Equal(t, int8(0x22), data) sem <- true }) require.NoError(t, err) a.SendTestDataToSubscriber([]byte{0x22}) select { case <-sem: case <-time.After(100 * time.Millisecond): require.Fail(t, "Microbit Event \"Temperature\" was not published") } } ================================================ FILE: drivers/ble/parrot/LICENSE ================================================ Copyright (c) 2014-2018 The Hybrid Group Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: drivers/ble/parrot/doc.go ================================================ /* Package parrot contains the Gobot driver for the Parrot Minidrone platform. For more information refer to the minidrone README: https://github.com/hybridgroup/gobot/blob/release/platforms/parrot/minidrone/README.md */ package parrot // import "gobot.io/x/gobot/v2/drivers/ble/parrot" ================================================ FILE: drivers/ble/parrot/minidrone_driver.go ================================================ package parrot import ( "bytes" "encoding/binary" "fmt" "math" "sync" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble" ) const ( // droneCommandService = "9a66fa000800919111e4012d1540cb8e" // droneNotificationService = "9a66fb000800919111e4012d1540cb8e" // send characteristics pcmdChara = "9a66fa0a0800919111e4012d1540cb8e" commandChara = "9a66fa0b0800919111e4012d1540cb8e" priorityChara = "9a66fa0c0800919111e4012d1540cb8e" // receive characteristics flightStatusChara = "9a66fb0e0800919111e4012d1540cb8e" batteryChara = "9a66fb0f0800919111e4012d1540cb8e" // piloting states flatTrimChanged = 0 flyingStateChanged = 1 // flying states flyingStateLanded = 0 flyingStateTakeoff = 1 flyingStateHovering = 2 flyingStateFlying = 3 flyingStateLanding = 4 flyingStateEmergency = 5 flyingStateRolling = 6 BatteryEvent = "battery" FlightStatusEvent = "flightstatus" TakeoffEvent = "takeoff" HoveringEvent = "hovering" FlyingEvent = "flying" LandingEvent = "landing" LandedEvent = "landed" EmergencyEvent = "emergency" RollingEvent = "rolling" FlatTrimChangeEvent = "flattrimchange" // modes for LightControl LightFixed = 0 LightBlinked = 1 LightOscillated = 3 // modes for ClawControl ClawOpen = 0 ClawClosed = 1 ) // MinidroneDriver is the Gobot interface to the Parrot Minidrone type MinidroneDriver struct { *ble.Driver gobot.Eventer stepsfa0a uint16 stepsfa0b uint16 pcmdMutex sync.Mutex flying bool Pcmd Pcmd } // Pcmd is the Parrot Command structure for flight control type Pcmd struct { Flag int Roll int Pitch int Yaw int Gaz int Psi float32 } // NewMinidroneDriver creates a Parrot Minidrone Driver func NewMinidroneDriver(a gobot.BLEConnector, opts ...ble.OptionApplier) *MinidroneDriver { d := &MinidroneDriver{ Pcmd: Pcmd{ Flag: 0, Roll: 0, Pitch: 0, Yaw: 0, Gaz: 0, Psi: 0, }, Eventer: gobot.NewEventer(), } d.Driver = ble.NewDriver(a, "Minidrone", d.initialize, d.shutdown, opts...) d.AddEvent(BatteryEvent) d.AddEvent(FlightStatusEvent) d.AddEvent(TakeoffEvent) d.AddEvent(FlyingEvent) d.AddEvent(HoveringEvent) d.AddEvent(LandingEvent) d.AddEvent(LandedEvent) d.AddEvent(EmergencyEvent) d.AddEvent(RollingEvent) return d } // GenerateAllStates sets up all the default states aka settings on the drone func (d *MinidroneDriver) GenerateAllStates() error { d.stepsfa0b++ buf := []byte{ 0x04, byte(d.stepsfa0b), 0x00, 0x04, 0x01, 0x00, 0x32, 0x30, 0x31, 0x34, 0x2D, 0x31, 0x30, 0x2D, 0x32, 0x38, 0x00, } return d.Adaptor().WriteCharacteristic(commandChara, buf) } // TakeOff tells the Minidrone to takeoff func (d *MinidroneDriver) TakeOff() error { d.stepsfa0b++ buf := []byte{0x02, byte(d.stepsfa0b) & 0xff, 0x02, 0x00, 0x01, 0x00} return d.Adaptor().WriteCharacteristic(commandChara, buf) } // Land tells the Minidrone to land func (d *MinidroneDriver) Land() error { d.stepsfa0b++ buf := []byte{0x02, byte(d.stepsfa0b) & 0xff, 0x02, 0x00, 0x03, 0x00} return d.Adaptor().WriteCharacteristic(commandChara, buf) } // FlatTrim calibrates the Minidrone to use its current position as being level func (d *MinidroneDriver) FlatTrim() error { d.stepsfa0b++ buf := []byte{0x02, byte(d.stepsfa0b) & 0xff, 0x02, 0x00, 0x00, 0x00} return d.Adaptor().WriteCharacteristic(commandChara, buf) } // Emergency sets the Minidrone into emergency mode func (d *MinidroneDriver) Emergency() error { d.stepsfa0b++ buf := []byte{0x02, byte(d.stepsfa0b) & 0xff, 0x02, 0x00, 0x04, 0x00} return d.Adaptor().WriteCharacteristic(priorityChara, buf) } // TakePicture tells the Minidrone to take a picture func (d *MinidroneDriver) TakePicture() error { d.stepsfa0b++ buf := []byte{0x02, byte(d.stepsfa0b) & 0xff, 0x02, 0x06, 0x01, 0x00} return d.Adaptor().WriteCharacteristic(commandChara, buf) } // StartPcmd starts the continuous Pcmd communication with the Minidrone func (d *MinidroneDriver) StartPcmd() { go func() { // wait a little bit so that there is enough time to get some ACKs time.Sleep(500 * time.Millisecond) for { err := d.Adaptor().WriteCharacteristic(pcmdChara, d.generatePcmd().Bytes()) if err != nil { fmt.Println("pcmd write error:", err) } time.Sleep(50 * time.Millisecond) } }() } // Up tells the drone to ascend. Pass in an int from 0-100. func (d *MinidroneDriver) Up(val int) error { d.pcmdMutex.Lock() defer d.pcmdMutex.Unlock() d.Pcmd.Flag = 1 d.Pcmd.Gaz = validatePitch(val) return nil } // Down tells the drone to descend. Pass in an int from 0-100. func (d *MinidroneDriver) Down(val int) error { d.pcmdMutex.Lock() defer d.pcmdMutex.Unlock() d.Pcmd.Flag = 1 d.Pcmd.Gaz = validatePitch(val) * -1 return nil } // Forward tells the drone to go forward. Pass in an int from 0-100. func (d *MinidroneDriver) Forward(val int) error { d.pcmdMutex.Lock() defer d.pcmdMutex.Unlock() d.Pcmd.Flag = 1 d.Pcmd.Pitch = validatePitch(val) return nil } // Backward tells drone to go in reverse. Pass in an int from 0-100. func (d *MinidroneDriver) Backward(val int) error { d.pcmdMutex.Lock() defer d.pcmdMutex.Unlock() d.Pcmd.Flag = 1 d.Pcmd.Pitch = validatePitch(val) * -1 return nil } // Right tells drone to go right. Pass in an int from 0-100. func (d *MinidroneDriver) Right(val int) error { d.pcmdMutex.Lock() defer d.pcmdMutex.Unlock() d.Pcmd.Flag = 1 d.Pcmd.Roll = validatePitch(val) return nil } // Left tells drone to go left. Pass in an int from 0-100. func (d *MinidroneDriver) Left(val int) error { d.pcmdMutex.Lock() defer d.pcmdMutex.Unlock() d.Pcmd.Flag = 1 d.Pcmd.Roll = validatePitch(val) * -1 return nil } // Clockwise tells drone to rotate in a clockwise directiod. Pass in an int from 0-100. func (d *MinidroneDriver) Clockwise(val int) error { d.pcmdMutex.Lock() defer d.pcmdMutex.Unlock() d.Pcmd.Flag = 1 d.Pcmd.Yaw = validatePitch(val) return nil } // CounterClockwise tells drone to rotate in a counter-clockwise directiod. // Pass in an int from 0-100. func (d *MinidroneDriver) CounterClockwise(val int) error { d.pcmdMutex.Lock() defer d.pcmdMutex.Unlock() d.Pcmd.Flag = 1 d.Pcmd.Yaw = validatePitch(val) * -1 return nil } // Stop tells the drone to stop moving in any direction and simply hover in place func (d *MinidroneDriver) Stop() error { d.pcmdMutex.Lock() defer d.pcmdMutex.Unlock() d.Pcmd = Pcmd{ Flag: 0, Roll: 0, Pitch: 0, Yaw: 0, Gaz: 0, Psi: 0, } return nil } // StartRecording is not supported by the Parrot Minidrone func (d *MinidroneDriver) StartRecording() error { return nil } // StopRecording is not supported by the Parrot Minidrone func (d *MinidroneDriver) StopRecording() error { return nil } // HullProtection is not supported by the Parrot Minidrone func (d *MinidroneDriver) HullProtection(protect bool) error { return nil } // Outdoor mode is not supported by the Parrot Minidrone func (d *MinidroneDriver) Outdoor(outdoor bool) error { return nil } // FrontFlip tells the drone to perform a front flip func (d *MinidroneDriver) FrontFlip() error { return d.Adaptor().WriteCharacteristic(commandChara, d.generateAnimation(0).Bytes()) } // BackFlip tells the drone to perform a backflip func (d *MinidroneDriver) BackFlip() error { return d.Adaptor().WriteCharacteristic(commandChara, d.generateAnimation(1).Bytes()) } // RightFlip tells the drone to perform a flip to the right func (d *MinidroneDriver) RightFlip() error { return d.Adaptor().WriteCharacteristic(commandChara, d.generateAnimation(2).Bytes()) } // LeftFlip tells the drone to perform a flip to the left func (d *MinidroneDriver) LeftFlip() error { return d.Adaptor().WriteCharacteristic(commandChara, d.generateAnimation(3).Bytes()) } // LightControl controls lights on those Minidrone models which // have the correct hardware, such as the Maclane, Blaze, & Swat. // Params: // // id - always 0 // mode - either LightFixed, LightBlinked, or LightOscillated // intensity - Light intensity from 0 (OFF) to 100 (Max intensity). // Only used in LightFixed mode. func (d *MinidroneDriver) LightControl(id uint8, mode uint8, intensity uint8) error { d.stepsfa0b++ buf := []byte{0x02, byte(d.stepsfa0b) & 0xff, 0x02, 0x10, 0x00, id, mode, intensity, 0x00} return d.Adaptor().WriteCharacteristic(commandChara, buf) } // ClawControl controls the claw on the Parrot Mambo // Params: // // id - always 0 // mode - either ClawOpen or ClawClosed func (d *MinidroneDriver) ClawControl(id uint8, mode uint8) error { d.stepsfa0b++ buf := []byte{0x02, byte(d.stepsfa0b) & 0xff, 0x02, 0x10, 0x01, id, mode, 0x00} return d.Adaptor().WriteCharacteristic(commandChara, buf) } // GunControl fires the gun on the Parrot Mambo // Params: // // id - always 0 func (d *MinidroneDriver) GunControl(id uint8) error { d.stepsfa0b++ buf := []byte{0x02, byte(d.stepsfa0b) & 0xff, 0x02, 0x10, 0x02, id, 0x00} return d.Adaptor().WriteCharacteristic(commandChara, buf) } // initialize tells driver to get ready to do work func (d *MinidroneDriver) initialize() error { d.Adaptor().WithoutResponses(true) if err := d.GenerateAllStates(); err != nil { return err } // subscribe to battery notifications if err := d.Adaptor().Subscribe(batteryChara, func(data []byte) { d.Publish(d.Event(BatteryEvent), data[len(data)-1]) }); err != nil { return err } // subscribe to flying status notifications if err := d.Adaptor().Subscribe(flightStatusChara, func(data []byte) { d.processFlightStatus(data) }); err != nil { return err } if err := d.FlatTrim(); err != nil { return err } d.StartPcmd() return d.FlatTrim() } // shutdown stops minidrone driver (void) func (d *MinidroneDriver) shutdown() error { err := d.Land() time.Sleep(500 * time.Millisecond) return err } func (d *MinidroneDriver) generateAnimation(direction int8) *bytes.Buffer { d.stepsfa0b++ buf := []byte{0x02, byte(d.stepsfa0b) & 0xff, 0x02, 0x04, 0x00, 0x00, byte(direction), 0x00, 0x00, 0x00} return bytes.NewBuffer(buf) } func (d *MinidroneDriver) generatePcmd() *bytes.Buffer { d.pcmdMutex.Lock() defer d.pcmdMutex.Unlock() d.stepsfa0a++ pcmd := d.Pcmd cmd := &bytes.Buffer{} if err := binary.Write(cmd, binary.LittleEndian, int8(2)); err != nil { panic(err) } //nolint:gosec // TODO: fix later if err := binary.Write(cmd, binary.LittleEndian, int8(d.stepsfa0a)); err != nil { panic(err) } if err := binary.Write(cmd, binary.LittleEndian, int8(2)); err != nil { panic(err) } if err := binary.Write(cmd, binary.LittleEndian, int8(0)); err != nil { panic(err) } if err := binary.Write(cmd, binary.LittleEndian, int8(2)); err != nil { panic(err) } if err := binary.Write(cmd, binary.LittleEndian, int8(0)); err != nil { panic(err) } //nolint:gosec // TODO: fix later if err := binary.Write(cmd, binary.LittleEndian, int8(pcmd.Flag)); err != nil { panic(err) } //nolint:gosec // TODO: fix later if err := binary.Write(cmd, binary.LittleEndian, int8(pcmd.Roll)); err != nil { panic(err) } //nolint:gosec // TODO: fix later if err := binary.Write(cmd, binary.LittleEndian, int8(pcmd.Pitch)); err != nil { panic(err) } //nolint:gosec // TODO: fix later if err := binary.Write(cmd, binary.LittleEndian, int8(pcmd.Yaw)); err != nil { panic(err) } //nolint:gosec // TODO: fix later if err := binary.Write(cmd, binary.LittleEndian, int8(pcmd.Gaz)); err != nil { panic(err) } if err := binary.Write(cmd, binary.LittleEndian, pcmd.Psi); err != nil { panic(err) } if err := binary.Write(cmd, binary.LittleEndian, int16(0)); err != nil { panic(err) } if err := binary.Write(cmd, binary.LittleEndian, int16(0)); err != nil { panic(err) } return cmd } func (d *MinidroneDriver) processFlightStatus(data []byte) { if len(data) < 5 { // ignore, just a sync return } d.Publish(FlightStatusEvent, data[4]) switch data[4] { case flatTrimChanged: d.Publish(FlatTrimChangeEvent, true) case flyingStateChanged: switch data[6] { case flyingStateLanded: if d.flying { d.flying = false d.Publish(LandedEvent, true) } case flyingStateTakeoff: d.Publish(TakeoffEvent, true) case flyingStateHovering: if !d.flying { d.flying = true d.Publish(HoveringEvent, true) } case flyingStateFlying: if !d.flying { d.flying = true d.Publish(FlyingEvent, true) } case flyingStateLanding: d.Publish(LandingEvent, true) case flyingStateEmergency: d.Publish(EmergencyEvent, true) case flyingStateRolling: d.Publish(RollingEvent, true) } } } // ValidatePitch helps validate pitch values such as those created by // a joystick to values between 0-100 that are required as // params to Parrot Minidrone PCMDs func ValidatePitch(data float64, offset float64) int { value := math.Abs(data) / offset if value >= 0.1 { if value <= 1.0 { return int((float64(int(value*100)) / 100) * 100) } return 100 } return 0 } func validatePitch(val int) int { if val > 100 { return 100 } else if val < 0 { return 0 } return val } ================================================ FILE: drivers/ble/parrot/minidrone_driver_test.go ================================================ package parrot import ( "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble" "gobot.io/x/gobot/v2/drivers/ble/testutil" ) var _ gobot.Driver = (*MinidroneDriver)(nil) func initTestMinidroneDriver() *MinidroneDriver { d := NewMinidroneDriver(testutil.NewBleTestAdaptor()) if err := d.Start(); err != nil { panic(err) } return d } func TestNewMinidroneDriver(t *testing.T) { d := NewMinidroneDriver(testutil.NewBleTestAdaptor()) assert.True(t, strings.HasPrefix(d.Name(), "Minidrone")) assert.NotNil(t, d.Eventer) } func TestNewMinidroneDriverWithName(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithName() option. Further // tests for options can also be done by call of "WithOption(val).apply(cfg)". // arrange const newName = "new name" a := testutil.NewBleTestAdaptor() // act d := NewMinidroneDriver(a, ble.WithName(newName)) // assert assert.Equal(t, newName, d.Name()) } func TestMinidroneHalt(t *testing.T) { d := initTestMinidroneDriver() require.NoError(t, d.Halt()) } func TestMinidroneTakeoff(t *testing.T) { d := initTestMinidroneDriver() require.NoError(t, d.TakeOff()) } func TestMinidroneEmergency(t *testing.T) { d := initTestMinidroneDriver() require.NoError(t, d.Emergency()) } func TestMinidroneTakePicture(t *testing.T) { d := initTestMinidroneDriver() require.NoError(t, d.TakePicture()) } func TestMinidroneUp(t *testing.T) { d := initTestMinidroneDriver() require.NoError(t, d.Up(25)) } func TestMinidroneUpTooFar(t *testing.T) { d := initTestMinidroneDriver() require.NoError(t, d.Up(125)) require.NoError(t, d.Up(-50)) } func TestMinidroneDown(t *testing.T) { d := initTestMinidroneDriver() require.NoError(t, d.Down(25)) } func TestMinidroneForward(t *testing.T) { d := initTestMinidroneDriver() require.NoError(t, d.Forward(25)) } func TestMinidroneBackward(t *testing.T) { d := initTestMinidroneDriver() require.NoError(t, d.Backward(25)) } func TestMinidroneRight(t *testing.T) { d := initTestMinidroneDriver() require.NoError(t, d.Right(25)) } func TestMinidroneLeft(t *testing.T) { d := initTestMinidroneDriver() require.NoError(t, d.Left(25)) } func TestMinidroneClockwise(t *testing.T) { d := initTestMinidroneDriver() require.NoError(t, d.Clockwise(25)) } func TestMinidroneCounterClockwise(t *testing.T) { d := initTestMinidroneDriver() require.NoError(t, d.CounterClockwise(25)) } func TestMinidroneStop(t *testing.T) { d := initTestMinidroneDriver() require.NoError(t, d.Stop()) } func TestMinidroneStartStopRecording(t *testing.T) { d := initTestMinidroneDriver() require.NoError(t, d.StartRecording()) require.NoError(t, d.StopRecording()) } func TestMinidroneHullProtectionOutdoor(t *testing.T) { d := initTestMinidroneDriver() require.NoError(t, d.HullProtection(true)) require.NoError(t, d.Outdoor(true)) } func TestMinidroneHullFlips(t *testing.T) { d := initTestMinidroneDriver() require.NoError(t, d.FrontFlip()) require.NoError(t, d.BackFlip()) require.NoError(t, d.RightFlip()) require.NoError(t, d.LeftFlip()) } func TestMinidroneLightControl(t *testing.T) { d := initTestMinidroneDriver() require.NoError(t, d.LightControl(0, LightBlinked, 25)) } func TestMinidroneClawControl(t *testing.T) { d := initTestMinidroneDriver() require.NoError(t, d.ClawControl(0, ClawOpen)) } func TestMinidroneGunControl(t *testing.T) { d := initTestMinidroneDriver() require.NoError(t, d.GunControl(0)) } func TestMinidroneProcessFlightData(t *testing.T) { d := initTestMinidroneDriver() d.processFlightStatus([]byte{0x00, 0x00, 0x00}) d.processFlightStatus([]byte{0x00, 0x00, 0x00, 0x00, 0x00}) d.processFlightStatus([]byte{0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00}) assert.False(t, d.flying) d.processFlightStatus([]byte{0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01}) assert.False(t, d.flying) d.processFlightStatus([]byte{0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02}) assert.True(t, d.flying) d.processFlightStatus([]byte{0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03}) assert.True(t, d.flying) d.processFlightStatus([]byte{0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04}) d.processFlightStatus([]byte{0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x05}) d.processFlightStatus([]byte{0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x06}) require.NoError(t, d.Stop()) } func TestMinidroneValidatePitchWhenEqualOffset(t *testing.T) { assert.Equal(t, 100, ValidatePitch(32767.0, 32767.0)) } func TestMinidroneValidatePitchWhenTiny(t *testing.T) { assert.Equal(t, 0, ValidatePitch(1.1, 32767.0)) } func TestMinidroneValidatePitchWhenCentered(t *testing.T) { assert.Equal(t, 50, ValidatePitch(16383.5, 32767.0)) } ================================================ FILE: drivers/ble/serial_port.go ================================================ package ble import ( "sync" "gobot.io/x/gobot/v2" ) // SerialPortDriver is a implementation of serial over Bluetooth LE // Inspired by https://github.com/monteslu/ble-serial by @monteslu type SerialPortDriver struct { *Driver rid string tid string // buffer of responseData and mutex to protect it responseData []byte responseMutex sync.Mutex } // NewSerialPortDriver returns a new serial over Bluetooth LE connection func NewSerialPortDriver(a gobot.BLEConnector, rid string, tid string, opts ...OptionApplier) *SerialPortDriver { d := &SerialPortDriver{ Driver: NewDriver(a, "BleSerial", nil, nil, opts...), rid: rid, tid: tid, } return d } // Open opens a connection to a BLE serial device func (p *SerialPortDriver) Open() error { if err := p.Adaptor().Connect(); err != nil { return err } // subscribe to response notifications return p.Adaptor().Subscribe(p.rid, func(data []byte) { p.responseMutex.Lock() defer p.responseMutex.Unlock() p.responseData = append(p.responseData, data...) }) } // Read reads bytes from BLE serial port connection func (p *SerialPortDriver) Read(b []byte) (int, error) { p.responseMutex.Lock() defer p.responseMutex.Unlock() if len(p.responseData) == 0 { return 0, nil } n := len(b) if len(p.responseData) < n { n = len(p.responseData) } copy(b, p.responseData[:n]) if len(p.responseData) > n { p.responseData = p.responseData[n:] } else { p.responseData = nil } return n, nil } // Write writes to the BLE serial port connection func (p *SerialPortDriver) Write(b []byte) (int, error) { err := p.Adaptor().WriteCharacteristic(p.tid, b) n := len(b) return n, err } // Close closes the BLE serial port connection func (p *SerialPortDriver) Close() error { return p.Adaptor().Disconnect() } // Address returns the BLE address func (p *SerialPortDriver) Address() string { return p.Adaptor().Address() } ================================================ FILE: drivers/ble/serial_port_test.go ================================================ package ble import ( "fmt" "io" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble/testutil" ) var _ gobot.Driver = (*SerialPortDriver)(nil) var _ io.ReadWriteCloser = (*SerialPortDriver)(nil) func TestNewSerialPortDriver(t *testing.T) { d := NewSerialPortDriver(testutil.NewBleTestAdaptor(), "123", "456") assert.Equal(t, "01:02:03:0A:0B:0C", d.Address()) } func TestNewSerialPortDriverWithName(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithName() option. Further // tests for options can also be done by call of "WithOption(val).apply(cfg)". // arrange const newName = "new name" a := testutil.NewBleTestAdaptor() // act d := NewSerialPortDriver(a, "123", "456", WithName(newName)) // assert assert.Equal(t, newName, d.Name()) } func TestSerialPortOpen(t *testing.T) { const receiveCharacteristicUUID = "123" tests := map[string]struct { simConnectErr bool simSubscribeErr bool wantErr string }{ "open_ok": {}, "error_connect": { simConnectErr: true, wantErr: "connect error", }, "error_subscribe": { simSubscribeErr: true, wantErr: "subscribe error", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange a := testutil.NewBleTestAdaptor() a.SetSimulateConnectError(tc.simConnectErr) a.SetSimulateSubscribeError(tc.simSubscribeErr) d := NewSerialPortDriver(a, receiveCharacteristicUUID, "456") // act err := d.Open() // assert if tc.wantErr == "" { require.NoError(t, err) a.SendTestDataToSubscriber([]byte{3, 5, 7}) assert.Equal(t, []byte{3, 5, 7}, d.responseData) assert.Equal(t, receiveCharacteristicUUID, a.SubscribeCharaUUID()) } else { require.EqualError(t, err, tc.wantErr) } }) } } func TestSerialPortRead(t *testing.T) { tests := map[string]struct { availableData []byte readDataBuffer []byte wantCount int wantData []byte wantRemaining []byte }{ "no_data": { availableData: []byte{}, readDataBuffer: []byte{0, 0, 0}, wantCount: 0, wantData: []byte{0, 0, 0}, wantRemaining: nil, }, "read_all": { availableData: []byte{1, 2, 3}, readDataBuffer: []byte{0, 0, 0}, wantCount: 3, wantData: []byte{1, 2, 3}, wantRemaining: nil, }, "read_smaller": { availableData: []byte{4, 6, 7}, readDataBuffer: []byte{0, 0}, wantCount: 2, wantData: []byte{4, 6}, wantRemaining: []byte{7}, }, "read_bigger": { availableData: []byte{7, 8}, readDataBuffer: []byte{0, 0, 0}, wantCount: 2, wantData: []byte{7, 8, 0}, wantRemaining: nil, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d := NewSerialPortDriver(testutil.NewBleTestAdaptor(), "123", "456") d.responseData = append(d.responseData, tc.availableData...) // act gotCount, err := d.Read(tc.readDataBuffer) // assert require.NoError(t, err) assert.Equal(t, tc.wantCount, gotCount) assert.Equal(t, tc.wantData, tc.readDataBuffer) assert.Equal(t, tc.wantRemaining, d.responseData) }) } } func TestSerialPortWrite(t *testing.T) { const transmitCharacteristicUUID = "456" tests := map[string]struct { writeData []byte simError bool wantCount int wantData []byte wantErr string }{ "write_ok": { writeData: []byte{1, 2, 3}, wantCount: 3, wantData: []byte{1, 2, 3}, }, "error_write": { writeData: []byte{1, 2, 3}, simError: true, wantCount: 3, wantData: []byte{1, 2, 3}, wantErr: "write error", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange a := testutil.NewBleTestAdaptor() var gotUUID string var gotData []byte a.SetWriteCharacteristicTestFunc(func(cUUID string, data []byte) error { gotUUID = cUUID gotData = append(gotData, data...) if tc.simError { return fmt.Errorf("write error") } return nil }) d := NewSerialPortDriver(a, "123", transmitCharacteristicUUID) // act gotCount, err := d.Write(tc.writeData) // assert if tc.wantErr == "" { require.NoError(t, err) } else { require.EqualError(t, err, tc.wantErr) } assert.Equal(t, tc.wantCount, gotCount) assert.Equal(t, transmitCharacteristicUUID, gotUUID) assert.Equal(t, tc.wantData, gotData) }) } } func TestSerialPortClose(t *testing.T) { tests := map[string]struct { simDisconnectErr bool wantErr string }{ "close_ok": {}, "error_close": { simDisconnectErr: true, wantErr: "disconnect error", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange a := testutil.NewBleTestAdaptor() a.SetSimulateDisconnectError(tc.simDisconnectErr) d := NewSerialPortDriver(a, "123", "456") // act err := d.Close() // assert if tc.wantErr == "" { require.NoError(t, err) } else { require.EqualError(t, err, tc.wantErr) } }) } } ================================================ FILE: drivers/ble/sphero/LICENSE ================================================ Copyright (c) 2013-2018 The Hybrid Group Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: drivers/ble/sphero/doc.go ================================================ /* Package sphero provides the Gobot drivers for the Sphero BLE based platforms. For further information refer to sphero readme files: https://github.com/hybridgroup/gobot/blob/release/platforms/sphero/bb8/README.md https://github.com/hybridgroup/gobot/blob/release/platforms/sphero/ollie/README.md https://github.com/hybridgroup/gobot/blob/release/platforms/sphero/sprkplus/README.md */ package sphero // import "gobot.io/x/gobot/v2/drivers/ble/sphero" ================================================ FILE: drivers/ble/sphero/sphero_bb8_driver.go ================================================ package sphero import ( "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble" "gobot.io/x/gobot/v2/drivers/common/spherocommon" ) // BB8Driver represents a Sphero BB-8 type BB8Driver struct { *OllieDriver } // NewBB8Driver creates a driver for a Sphero BB-8 func NewBB8Driver(a gobot.BLEConnector, opts ...ble.OptionApplier) *BB8Driver { return &BB8Driver{OllieDriver: newOllieBaseDriver(a, "BB8", bb8DefaultCollisionConfig(), opts...)} } // bb8DefaultCollisionConfig returns a CollisionConfig with sensible collision defaults func bb8DefaultCollisionConfig() spherocommon.CollisionConfig { return spherocommon.CollisionConfig{ Method: 0x01, Xt: 0x20, Yt: 0x20, Xs: 0x20, Ys: 0x20, Dead: 0x01, } } ================================================ FILE: drivers/ble/sphero/sphero_bb8_driver_test.go ================================================ package sphero import ( "strings" "testing" "github.com/stretchr/testify/assert" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble" "gobot.io/x/gobot/v2/drivers/ble/testutil" ) var _ gobot.Driver = (*BB8Driver)(nil) func TestNewBB8Driver(t *testing.T) { d := NewBB8Driver(testutil.NewBleTestAdaptor()) assert.NotNil(t, d.OllieDriver) assert.True(t, strings.HasPrefix(d.Name(), "BB8")) assert.NotNil(t, d.OllieDriver) assert.Equal(t, d.defaultCollisionConfig, bb8DefaultCollisionConfig()) } func TestNewBB8DriverWithName(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithName() option. Further // tests for options can also be done by call of "WithOption(val).apply(cfg)". // arrange const newName = "new name" a := testutil.NewBleTestAdaptor() // act d := NewBB8Driver(a, ble.WithName(newName)) // assert assert.Equal(t, newName, d.Name()) } ================================================ FILE: drivers/ble/sphero/sphero_ollie_driver.go ================================================ package sphero import ( "bytes" "encoding/binary" "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble" "gobot.io/x/gobot/v2/drivers/common/spherocommon" ) // MotorModes is used to configure the motor type MotorModes uint8 // MotorModes required for SetRawMotorValues command const ( Off MotorModes = iota Forward Reverse Brake Ignore ) const ( // spheroBLEService = "22bb746f2bb075542d6f726568705327" // robotControlService = "22bb746f2ba075542d6f726568705327" wakeChara = "22bb746f2bbf75542d6f726568705327" txPowerChara = "22bb746f2bb275542d6f726568705327" antiDosChara = "22bb746f2bbd75542d6f726568705327" commandsChara = "22bb746f2ba175542d6f726568705327" responseChara = "22bb746f2ba675542d6f726568705327" // packet header size packetHeaderSize = 5 // Response packet max size responsePacketMaxSize = 20 // Collision packet data size: The number of bytes following the DLEN field through the end of the packet collisionDataSize = 17 // Full size of the collision response collisionResponseSize = packetHeaderSize + collisionDataSize ) // packet describes head, body and checksum for a data package to be sent type packet struct { header []uint8 body []uint8 checksum uint8 } // Point2D represents a coordinate in 2-Dimensional space, exposed because used in a callback type Point2D struct { X int16 Y int16 } // OllieDriver is the Gobot driver for the Sphero Ollie robot type OllieDriver struct { *ble.Driver gobot.Eventer defaultCollisionConfig spherocommon.CollisionConfig seq uint8 collisionResponse []uint8 packetChannel chan *packet asyncBuffer []byte asyncMessage []byte locatorCallback func(p Point2D) powerstateCallback func(p spherocommon.PowerStatePacket) } // NewOllieDriver creates a driver for a Sphero Ollie func NewOllieDriver(a gobot.BLEConnector, opts ...ble.OptionApplier) *OllieDriver { return newOllieBaseDriver(a, "Ollie", ollieDefaultCollisionConfig(), opts...) } func newOllieBaseDriver( a gobot.BLEConnector, name string, dcc spherocommon.CollisionConfig, opts ...ble.OptionApplier, ) *OllieDriver { d := &OllieDriver{ defaultCollisionConfig: dcc, Eventer: gobot.NewEventer(), packetChannel: make(chan *packet, 1024), } d.Driver = ble.NewDriver(a, name, d.initialize, d.shutdown, opts...) d.AddEvent(spherocommon.ErrorEvent) d.AddEvent(spherocommon.CollisionEvent) return d } // SetTXPower sets transmit level func (d *OllieDriver) SetTXPower(level int) error { buf := []byte{byte(level)} if err := d.Adaptor().WriteCharacteristic(txPowerChara, buf); err != nil { return err } return nil } // Wake wakes Ollie up so we can play func (d *OllieDriver) Wake() error { buf := []byte{0x01} if err := d.Adaptor().WriteCharacteristic(wakeChara, buf); err != nil { return err } return nil } // ConfigureCollisionDetection configures the sensitivity of the detection. func (d *OllieDriver) ConfigureCollisionDetection(cc spherocommon.CollisionConfig) { d.sendCraftPacket([]uint8{cc.Method, cc.Xt, cc.Yt, cc.Xs, cc.Ys, cc.Dead}, 0x02, 0x12) } // GetLocatorData calls the passed function with the data from the locator func (d *OllieDriver) GetLocatorData(f func(p Point2D)) { // CID 0x15 is the code for the locator request d.sendCraftPacket([]uint8{}, 0x02, 0x15) d.locatorCallback = f } // GetPowerState calls the passed function with the Power State information from the sphero func (d *OllieDriver) GetPowerState(f func(p spherocommon.PowerStatePacket)) { // CID 0x20 is the code for the power state d.sendCraftPacket([]uint8{}, 0x00, 0x20) d.powerstateCallback = f } // SetRGB sets the Ollie to the given r, g, and b values func (d *OllieDriver) SetRGB(r uint8, g uint8, b uint8) { d.sendCraftPacket([]uint8{r, g, b, 0x01}, 0x02, 0x20) } // Roll tells the Ollie to roll func (d *OllieDriver) Roll(speed uint8, heading uint16) { //nolint:gosec // TODO: fix later d.sendCraftPacket([]uint8{speed, uint8(heading >> 8), uint8(heading & 0xFF), 0x01}, 0x02, 0x30) } // Boost executes the boost macro from within the SSB which takes a 1 byte parameter which is // either 01h to begin boosting or 00h to stop. func (d *OllieDriver) Boost(state bool) { s := uint8(0x01) if !state { s = 0x00 } d.sendCraftPacket([]uint8{s}, 0x02, 0x31) } // SetStabilization enables or disables the built-in auto stabilizing features of the Ollie func (d *OllieDriver) SetStabilization(state bool) { s := uint8(0x01) if !state { s = 0x00 } d.sendCraftPacket([]uint8{s}, 0x02, 0x02) } // SetRotationRate allows you to control the rotation rate that Sphero will use to meet new heading commands. A value // of 255 jumps to the maximum (currently 400 degrees/sec). A value of zero doesn't make much sense so it's interpreted // as 1, the minimum. func (d *OllieDriver) SetRotationRate(speed uint8) { d.sendCraftPacket([]uint8{speed}, 0x02, 0x03) } // SetRawMotorValues allows you to take over one or both of the motor output values, instead of having the stabilization // system control them. Each motor (left and right) requires a mode and a power value from 0-255. func (d *OllieDriver) SetRawMotorValues(lmode MotorModes, lpower uint8, rmode MotorModes, rpower uint8) { d.sendCraftPacket([]uint8{uint8(lmode), lpower, uint8(rmode), rpower}, 0x02, 0x33) } // SetBackLEDBrightness allows you to control the brightness of the back(tail) LED. func (d *OllieDriver) SetBackLEDBrightness(value uint8) { d.sendCraftPacket([]uint8{value}, 0x02, 0x21) } // Stop tells the Ollie to stop func (d *OllieDriver) Stop() { d.Roll(0, 0) } // Sleep says Go to sleep func (d *OllieDriver) Sleep() { d.sendCraftPacket([]uint8{0x00, 0x00, 0x00, 0x00, 0x00}, 0x00, 0x22) } // SetDataStreamingConfig passes the config to the sphero to stream sensor data func (d *OllieDriver) SetDataStreamingConfig(dsc spherocommon.DataStreamingConfig) error { buf := new(bytes.Buffer) if err := binary.Write(buf, binary.BigEndian, dsc); err != nil { return err } d.sendCraftPacket(buf.Bytes(), 0x02, 0x11) return nil } // initialize tells driver to get ready to do work func (d *OllieDriver) initialize() error { if err := d.antiDOSOff(); err != nil { return err } if err := d.SetTXPower(7); err != nil { return err } if err := d.Wake(); err != nil { return err } // subscribe to Sphero response notifications if err := d.Adaptor().Subscribe(responseChara, d.handleResponses); err != nil { return err } go func() { for { packet := <-d.packetChannel err := d.writeCommand(packet) if err != nil { d.Publish(d.Event(spherocommon.ErrorEvent), err) } } }() d.ConfigureCollisionDetection(d.defaultCollisionConfig) d.enableStopOnDisconnect() return nil } // antiDOSOff turns off Anti-DOS code so we can control Ollie func (d *OllieDriver) antiDOSOff() error { str := "011i3" buf := &bytes.Buffer{} buf.WriteString(str) if err := d.Adaptor().WriteCharacteristic(antiDosChara, buf.Bytes()); err != nil { return err } return nil } func (d *OllieDriver) writeCommand(packet *packet) error { d.Mutex().Lock() defer d.Mutex().Unlock() buf := append(packet.header, packet.body...) buf = append(buf, packet.checksum) if err := d.Adaptor().WriteCharacteristic(commandsChara, buf); err != nil { fmt.Println("async send command error:", err) return err } d.seq++ return nil } // enableStopOnDisconnect auto-sends a Stop command after losing the connection func (d *OllieDriver) enableStopOnDisconnect() { d.sendCraftPacket([]uint8{0x00, 0x00, 0x00, 0x01}, 0x02, 0x37) } // shutdown stops Ollie driver (void) func (d *OllieDriver) shutdown() error { d.Sleep() time.Sleep(750 * time.Microsecond) return nil } // handleResponses handles responses returned from Ollie func (d *OllieDriver) handleResponses(data []byte) { // since packets can only be 20 bytes long, we have to puzzle them together newMessage := false // append message parts to existing if len(data) > 0 && data[0] != 0xFF { d.asyncBuffer = append(d.asyncBuffer, data...) } // clear message when new one begins (first byte is always 0xFF) if len(data) > 0 && data[0] == 0xFF { d.asyncMessage = d.asyncBuffer d.asyncBuffer = data newMessage = true } parts := d.asyncMessage // 3 is the id of data streaming, located at index 2 byte if newMessage && len(parts) > 2 && parts[2] == 3 { d.handleDataStreaming(parts) } // index 1 is the type of the message, 0xFF being a direct response, 0xFE an asynchronous message if len(data) > 4 && data[1] == 0xFF && data[0] == 0xFF { // locator request if data[4] == 0x0B && len(data) == 16 { d.handleLocatorDetected(data) } if data[4] == 0x09 { d.handlePowerStateDetected(data) } } d.handleCollisionDetected(data) } func (d *OllieDriver) handleDataStreaming(data []byte) { // ensure data is the right length: if len(data) != 88 { return } // data packet is the same as for the normal sphero, since the same communication api is used // only difference in communication is that the "newer" spheros use BLE for communications var dataPacket spherocommon.DataStreamingPacket buffer := bytes.NewBuffer(data[5:]) // skip header if err := binary.Read(buffer, binary.BigEndian, &dataPacket); err != nil { panic(err) } d.Publish(spherocommon.SensorDataEvent, dataPacket) } func (d *OllieDriver) handleLocatorDetected(data []uint8) { if d.locatorCallback == nil { return } // read the unsigned raw values ux := binary.BigEndian.Uint16(data[5:7]) uy := binary.BigEndian.Uint16(data[7:9]) // convert to signed values var x, y int16 if ux > 32255 { x = int16(ux - 65535) //nolint:gosec // ok here } else { x = int16(ux) } if uy > 32255 { y = int16(uy - 65535) //nolint:gosec // ok here } else { y = int16(uy) } d.locatorCallback(Point2D{X: x, Y: y}) } func (d *OllieDriver) handlePowerStateDetected(data []uint8) { var dataPacket spherocommon.PowerStatePacket buffer := bytes.NewBuffer(data[5:]) // skip header if err := binary.Read(buffer, binary.BigEndian, &dataPacket); err != nil { panic(err) } d.powerstateCallback(dataPacket) } func (d *OllieDriver) handleCollisionDetected(data []uint8) { switch len(data) { case responsePacketMaxSize: // Check if this is the header of collision response. (i.e. first part of data) // Collision response is 22 bytes long. (individual packet size is maxed at 20) if data[1] == 0xFE && data[2] == 0x07 && len(d.collisionResponse) == 0 { // response code 7 is for a detected collision d.collisionResponse = append(d.collisionResponse, data...) } case collisionResponseSize - responsePacketMaxSize: // if this is the remaining part of the collision response, // then make sure the header and first part of data is already received if len(d.collisionResponse) == responsePacketMaxSize { d.collisionResponse = append(d.collisionResponse, data...) } default: return // not collision event } // check expected sizes if len(d.collisionResponse) != collisionResponseSize || d.collisionResponse[4] != collisionDataSize { return } // confirm checksum size := len(d.collisionResponse) chk := d.collisionResponse[size-1] // last byte is checksum if chk != spherocommon.CalculateChecksum(d.collisionResponse[2:size-1]) { return } var collision spherocommon.CollisionPacket buffer := bytes.NewBuffer(d.collisionResponse[5:]) // skip header if err := binary.Read(buffer, binary.BigEndian, &collision); err != nil { panic(err) } d.collisionResponse = nil // clear the current response d.Publish(spherocommon.CollisionEvent, collision) } func (d *OllieDriver) sendCraftPacket(body []uint8, did byte, cid byte) { d.packetChannel <- d.craftPacket(body, did, cid) } func (d *OllieDriver) craftPacket(body []uint8, did byte, cid byte) *packet { dlen := len(body) + 1 hdr := []uint8{0xFF, 0xFF, did, cid, d.seq, uint8(dlen)} //nolint:gosec // TODO: fix later buf := append(hdr, body...) packet := &packet{ body: body, header: hdr, checksum: spherocommon.CalculateChecksum(buf[2:]), } return packet } // ollieDefaultCollisionConfig returns a CollisionConfig with sensible collision defaults func ollieDefaultCollisionConfig() spherocommon.CollisionConfig { return spherocommon.CollisionConfig{ Method: 0x01, Xt: 0x20, Yt: 0x20, Xs: 0x20, Ys: 0x20, Dead: 0x60, } } ================================================ FILE: drivers/ble/sphero/sphero_ollie_driver_test.go ================================================ //nolint:forcetypeassert // ok here package sphero import ( "strconv" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble" "gobot.io/x/gobot/v2/drivers/ble/testutil" "gobot.io/x/gobot/v2/drivers/common/spherocommon" ) var _ gobot.Driver = (*OllieDriver)(nil) func initTestOllieDriver() *OllieDriver { d := NewOllieDriver(testutil.NewBleTestAdaptor()) return d } func TestNewOllieDriver(t *testing.T) { d := NewOllieDriver(testutil.NewBleTestAdaptor()) assert.NotNil(t, d.Driver) assert.NotNil(t, d.Eventer) assert.Equal(t, d.defaultCollisionConfig, ollieDefaultCollisionConfig()) assert.NotNil(t, d.packetChannel) } func TestNewOllieDriverWithName(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithName() option. Further // tests for options can also be done by call of "WithOption(val).apply(cfg)". // arrange const newName = "new name" a := testutil.NewBleTestAdaptor() // act d := NewOllieDriver(a, ble.WithName(newName)) // assert assert.Equal(t, newName, d.Name()) } func TestOllieStartAndHalt(t *testing.T) { d := initTestOllieDriver() require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestLocatorData(t *testing.T) { d := initTestOllieDriver() tables := []struct { x1 byte x2 byte y1 byte y2 byte x int16 y int16 }{ {0x00, 0x05, 0x00, 0x05, 5, 5}, {0x00, 0x00, 0x00, 0x00, 0, 0}, {0x00, 0x0A, 0x00, 0xF0, 10, 240}, {0x01, 0x00, 0x01, 0x00, 256, 256}, {0xFF, 0xFE, 0xFF, 0xFE, -1, -1}, } for _, point := range tables { // 0x0B is the locator ID packet := []byte{ 0xFF, 0xFF, 0x00, 0x00, 0x0B, point.x1, point.x2, point.y1, point.y2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, } d.GetLocatorData(func(p Point2D) { assert.Equal(t, point.y, p.Y) }) d.handleResponses(packet) } } func TestDataStreaming(t *testing.T) { d := initTestOllieDriver() err := d.SetDataStreamingConfig(spherocommon.DefaultDataStreamingConfig()) require.NoError(t, err) responseChan := make(chan bool) err = d.On("sensordata", func(data interface{}) { cont := data.(spherocommon.DataStreamingPacket) // fmt.Printf("got streaming packet: %+v \n", cont) assert.Equal(t, int16(10), cont.RawAccX) responseChan <- true }) require.NoError(t, err) // example data packet p1 := []string{ "FFFE030053000A003900FAFFFE0007FFFF000000", "000000000000000000FFECFFFB00010000004B01", "BD1034FFFF000300000000000000000000000000", "0000002701FDE500560000000000000065000000", "0000000000000071", } for _, elem := range p1 { var bytes []byte for i := 0; i < len([]rune(elem)); i += 2 { a := []rune(elem)[i : i+2] b, err := strconv.ParseUint(string(a), 16, 16) require.NoError(t, err) c := uint16(b) bytes = append(bytes, byte(c)) } d.handleResponses(bytes) } // send empty packet to indicate start of next message d.handleResponses([]byte{0xFF}) select { case <-responseChan: case <-time.After(10 * time.Millisecond): t.Error("no response received") } } ================================================ FILE: drivers/ble/sphero/sphero_sprkplus_driver.go ================================================ package sphero import ( "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble" "gobot.io/x/gobot/v2/drivers/common/spherocommon" ) // SPRKPlusDriver represents a Sphero SPRK+ type SPRKPlusDriver struct { *OllieDriver } // NewSPRKPlusDriver creates a driver for a Sphero SPRK+ func NewSPRKPlusDriver(a gobot.BLEConnector, opts ...ble.OptionApplier) *SPRKPlusDriver { return &SPRKPlusDriver{OllieDriver: newOllieBaseDriver(a, "SPRKPlus", sprkplusDefaultCollisionConfig(), opts...)} } // sprkplusDefaultCollisionConfig returns a CollisionConfig with sensible collision defaults func sprkplusDefaultCollisionConfig() spherocommon.CollisionConfig { return spherocommon.CollisionConfig{ Method: 0x01, Xt: 0x20, Yt: 0x20, Xs: 0x20, Ys: 0x20, Dead: 0x01, } } ================================================ FILE: drivers/ble/sphero/sphero_sprkplus_driver_test.go ================================================ package sphero import ( "strings" "testing" "github.com/stretchr/testify/assert" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble" "gobot.io/x/gobot/v2/drivers/ble/testutil" ) var _ gobot.Driver = (*SPRKPlusDriver)(nil) func TestNewSPRKPlusDriver(t *testing.T) { d := NewSPRKPlusDriver(testutil.NewBleTestAdaptor()) assert.NotNil(t, d.OllieDriver) assert.True(t, strings.HasPrefix(d.Name(), "SPRK")) assert.NotNil(t, d.OllieDriver) assert.Equal(t, d.defaultCollisionConfig, sprkplusDefaultCollisionConfig()) } func TestNewSPRKPlusDriverWithName(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithName() option. Further // tests for options can also be done by call of "WithOption(val).apply(cfg)". // arrange const newName = "new name" a := testutil.NewBleTestAdaptor() // act d := NewSPRKPlusDriver(a, ble.WithName(newName)) // assert assert.Equal(t, newName, d.Name()) } ================================================ FILE: drivers/ble/testutil/testutil.go ================================================ package testutil import ( "fmt" "sync" "gobot.io/x/gobot/v2" ) var _ gobot.BLEConnector = (*bleTestClientAdaptor)(nil) type bleTestClientAdaptor struct { name string address string mtx sync.Mutex withoutResponses bool simulateConnectErr bool simulateSubscribeErr bool simulateDisconnectErr bool readCharacteristicFunc func(string) ([]byte, error) writeCharacteristicFunc func(string, []byte) error subscribeFunc func([]byte) subscribeCharaUUID string } func NewBleTestAdaptor() *bleTestClientAdaptor { return &bleTestClientAdaptor{ address: "01:02:03:0A:0B:0C", readCharacteristicFunc: func(cUUID string) ([]byte, error) { return []byte(cUUID), nil }, writeCharacteristicFunc: func(cUUID string, data []byte) error { return nil }, } } func (t *bleTestClientAdaptor) SubscribeCharaUUID() string { return t.subscribeCharaUUID } func (t *bleTestClientAdaptor) SetReadCharacteristicTestFunc(f func(cUUID string) (data []byte, err error)) { t.mtx.Lock() defer t.mtx.Unlock() t.readCharacteristicFunc = f } func (t *bleTestClientAdaptor) SetWriteCharacteristicTestFunc(f func(cUUID string, data []byte) error) { t.mtx.Lock() defer t.mtx.Unlock() t.writeCharacteristicFunc = f } func (t *bleTestClientAdaptor) SetSimulateConnectError(val bool) { t.simulateConnectErr = val } func (t *bleTestClientAdaptor) SetSimulateSubscribeError(val bool) { t.simulateSubscribeErr = val } func (t *bleTestClientAdaptor) SetSimulateDisconnectError(val bool) { t.simulateDisconnectErr = val } func (t *bleTestClientAdaptor) SendTestDataToSubscriber(data []byte) { t.mtx.Lock() defer t.mtx.Unlock() t.subscribeFunc(data) } func (t *bleTestClientAdaptor) Connect() error { if t.simulateConnectErr { return fmt.Errorf("connect error") } return nil } func (t *bleTestClientAdaptor) Reconnect() error { return nil } func (t *bleTestClientAdaptor) Disconnect() error { if t.simulateDisconnectErr { return fmt.Errorf("disconnect error") } return nil } func (t *bleTestClientAdaptor) Finalize() error { return nil } func (t *bleTestClientAdaptor) Name() string { return t.name } func (t *bleTestClientAdaptor) SetName(n string) { t.name = n } func (t *bleTestClientAdaptor) Address() string { return t.address } func (t *bleTestClientAdaptor) WithoutResponses(use bool) { t.withoutResponses = use } func (t *bleTestClientAdaptor) ReadCharacteristic(cUUID string) ([]byte, error) { t.mtx.Lock() defer t.mtx.Unlock() return t.readCharacteristicFunc(cUUID) } func (t *bleTestClientAdaptor) WriteCharacteristic(cUUID string, data []byte) error { t.mtx.Lock() defer t.mtx.Unlock() return t.writeCharacteristicFunc(cUUID, data) } func (t *bleTestClientAdaptor) Subscribe(cUUID string, f func(data []byte)) error { if t.simulateSubscribeErr { return fmt.Errorf("subscribe error") } t.subscribeCharaUUID = cUUID t.subscribeFunc = f return nil } ================================================ FILE: drivers/common/bit/bit.go ================================================ package bit // Set is used to set a bit in the given integer at a given position to 1. func Set(n int, pos uint8) int { n |= (1 << pos) return n } // Clear is used to set a bit in the given integer at a given position to 0. func Clear(n int, pos uint8) int { mask := ^int(1 << pos) n &= mask return n } // IsSet tests if the bit at the given position is set in the given integer. func IsSet(n int, pos uint8) bool { val := n & (1 << uint(pos)) return (val > 0) } ================================================ FILE: drivers/common/bit/bit_test.go ================================================ package bit import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestSet(t *testing.T) { const ( oldVal = 1 bitPos = 7 want = 129 ) require.False(t, IsSet(oldVal, bitPos)) got := Set(1, 7) assert.Equal(t, want, got) assert.True(t, IsSet(got, bitPos)) } func TestClear(t *testing.T) { const ( oldVal = 128 bitPos = 7 want int = 0 ) require.True(t, IsSet(oldVal, bitPos)) got := Clear(128, 7) assert.Equal(t, want, got) assert.False(t, IsSet(got, bitPos)) } ================================================ FILE: drivers/common/mfrc522/mfrc522_connectionwrapper.go ================================================ package mfrc522 import "fmt" func (d *MFRC522Common) readByteData(reg uint8) (uint8, error) { if d.connection == nil { return 0, fmt.Errorf("not connected") } return d.connection.ReadByteData(reg) } func (d *MFRC522Common) writeByteData(reg uint8, data uint8) error { if d.connection == nil { return fmt.Errorf("not connected") } return d.connection.WriteByteData(reg, data) } func (d *MFRC522Common) setRegisterBitMask(reg uint8, mask uint8) error { val, err := d.readByteData(reg) if err != nil { return err } if err := d.writeByteData(reg, val|mask); err != nil { return err } return nil } func (d *MFRC522Common) clearRegisterBitMask(reg uint8, mask uint8) error { val, err := d.readByteData(reg) if err != nil { return err } if err := d.writeByteData(reg, val&^mask); err != nil { return err } return nil } ================================================ FILE: drivers/common/mfrc522/mfrc522_pcd.go ================================================ package mfrc522 import ( "fmt" "time" ) // PCD: proximity coupling device (reader unit) // PICC: proximity integrated circuit card (the card or chip) const ( pcdDebug = false initTime = 50 * time.Millisecond // at least 5 ms are needed after switch on, see AN10834 antennaOnTime = 10 * time.Millisecond ) type busConnection interface { ReadByteData(reg byte) (byte, error) WriteByteData(reg byte, data byte) error } var versions = map[uint8]string{ 0x12: "Counterfeit", 0x88: "FM17522", 0x89: "FM17522E", 0x90: "MFRC522 0.0", 0x91: "MFRC522 1.0", 0x92: "MFRC522 2.0", 0xB2: "FM17522 1", } // MFRC522Common is the Gobot Driver for MFRC522 RFID. // datasheet: // https://www.nxp.com/docs/en/data-sheet/MFRC522.pdf // // reference implementations: // * https://github.com/OSSLibraries/ArduinoRegMFRC522v2 // * https://github.com/jdevelop/golang-rpi-extras // * https://github.com/pimylifeup/MFRC522-python // * https://periph.io/device/mf-rc522/ type MFRC522Common struct { connection busConnection firstCardAccess bool } // NewMFRC522Common creates a new Gobot Driver for MFRC522 RFID with specified bus connection // The device supports SPI, I2C and UART (not implemented yet at gobot system level). // // Params: // // c BusConnection - the bus connection to use with this driver func NewMFRC522Common() *MFRC522Common { d := &MFRC522Common{} return d } // Initialize sets the connection and initializes the driver. func (d *MFRC522Common) Initialize(c busConnection) error { d.connection = c if err := d.softReset(); err != nil { return err } initSequence := [][]byte{ {regTxMode, rxtxModeRegReset}, {regRxMode, rxtxModeRegReset}, {regModWidth, modWidthRegReset}, {regTMode, tModeRegTAutoBit | 0x0F}, // timer starts automatically at the end of the transmission {regTPrescaler, 0xFF}, {regTReloadL, tReloadRegValue25ms & 0xFF}, {regTReloadH, tReloadRegValue25ms >> 8}, {regTxASK, txASKRegForce100ASKBit}, {regMode, modeRegTxWaitRFBit | modeRegPolMFinBit | modeRegCRCPreset6363}, } for _, init := range initSequence { if err := d.writeByteData(init[0], init[1]); err != nil { return err } } if err := d.switchAntenna(true); err != nil { return err } if err := d.setAntennaGain(rfcCfgRegRxGain38dB); err != nil { return err } return nil } // PrintReaderVersion gets and prints the reader (pcd) version. func (d *MFRC522Common) PrintReaderVersion() error { version, err := d.getVersion() if err != nil { return err } fmt.Printf("PCD version: '%s' (0x%X)\n", versions[version], version) return nil } func (d *MFRC522Common) getVersion() (uint8, error) { return d.readByteData(regVersion) } func (d *MFRC522Common) switchAntenna(targetState bool) error { val, err := d.readByteData(regTxControl) if err != nil { return err } maskForOn := uint8(txControlRegTx2RFEn1outputBit | txControlRegTx1RFEn1outputBit) currentState := val&maskForOn == maskForOn if targetState == currentState { return nil } if targetState { val = val | maskForOn } else { val = val & ^maskForOn } if err := d.writeByteData(regTxControl, val); err != nil { return err } if targetState { time.Sleep(antennaOnTime) } return nil } func (d *MFRC522Common) setAntennaGain(val uint8) error { return d.writeByteData(regRFCfg, val) } func (d *MFRC522Common) softReset() error { if err := d.writeByteData(regCommand, commandRegSoftReset); err != nil { return err } // The datasheet does not mention how long the SoftReset command takes to complete. According to section 8.8.2 of the // datasheet the oscillator start-up time is the start up time of the crystal + 37.74 us. // TODO: this can be done better by wait until the power down bit is cleared time.Sleep(initTime) val, err := d.readByteData(regCommand) if err != nil { return err } if val&commandRegPowerDownBit > 1 { return fmt.Errorf("initialization takes longer than %s", initTime) } return nil } func (d *MFRC522Common) stopCrypto1() error { return d.clearRegisterBitMask(regStatus2, status2RegMFCrypto1OnBit) } func (d *MFRC522Common) communicateWithPICC(command uint8, sendData []byte, backData []byte, txLastBits uint8, checkCRC bool, ) error { irqEn := 0x00 waitIRq := uint8(0x00) switch command { case commandRegMFAuthent: irqEn = comIEnRegIdleIEnBit | comIEnRegErrIEnBit waitIRq = comIrqRegIdleIRqBit case commandRegTransceive: irqEn = comIEnRegTimerIEnBit | comIEnRegErrIEnBit | comIEnRegLoAlertIEnBit irqEn = irqEn | comIEnRegIdleIEnBit | comIEnRegRxIEnBit | comIEnRegTxIEnBit waitIRq = uint8(comIrqRegIdleIRqBit | comIrqRegRxIRqBit) } // TODO: this is not used at the moment (propagation of IRQ pin) //nolint:gosec // TODO: fix later if err := d.writeByteData(regComIEn, uint8(irqEn|comIEnRegIRqInv)); err != nil { return err } if err := d.writeByteData(regComIrq, comIrqRegClearAll); err != nil { return err } if err := d.writeByteData(regFIFOLevel, fifoLevelRegFlushBufferBit); err != nil { return err } // stop any active command if err := d.writeByteData(regCommand, commandRegIdle); err != nil { return err } // prepare and start communication if err := d.writeFifo(sendData); err != nil { return err } if err := d.writeByteData(regBitFraming, txLastBits); err != nil { return err } if err := d.writeByteData(regCommand, command); err != nil { return err } if command == commandRegTransceive { if err := d.setRegisterBitMask(regBitFraming, bitFramingRegStartSendBit); err != nil { return err } } // Wait for the command to complete. On initialization the TAuto flag in TMode register is set. This means the timer // automatically starts when the PCD stops transmitting. const maxTries = 5 i := 0 for ; i < maxTries; i++ { irqs, err := d.readByteData(regComIrq) if err != nil { return err } if irqs&waitIRq > 0 { // One of the interrupts that signal success has been set. break } if irqs&comIrqRegTimerIRqBit == comIrqRegTimerIRqBit { return fmt.Errorf("the timer interrupt occurred") } time.Sleep(time.Millisecond) } if err := d.clearRegisterBitMask(regBitFraming, bitFramingRegStartSendBit); err != nil { return err } if i >= maxTries { return fmt.Errorf("no data available after %d tries", maxTries) } errorRegValue, err := d.readByteData(regError) if err != nil { return err } // stop if any errors except collisions were detected. if err := d.getFirstError(errorRegValue &^ errorRegCollErrBit); err != nil { return err } backLen := len(backData) var rxLastBits uint8 if backLen > 0 { rxLastBits, err = d.readFifo(backData) if err != nil { return err } if pcdDebug { fmt.Printf("rxLastBits: 0x%02x\n", rxLastBits) } } if err := d.getFirstError(errorRegValue & errorRegCollErrBit); err != nil { return err } if backLen > 2 && checkCRC { // the last 2 bytes of data contains the CRC if backLen == 3 && rxLastBits == 0x04 { return fmt.Errorf("CRC: MIFARE Classic NAK is not OK") } if backLen < 4 || backLen == 4 && rxLastBits != 0 { return fmt.Errorf("CRC: at least the 2 byte CRCRegA value and all 8 bits of the last byte must be received") } crcResult := []byte{0x00, 0x00} crcData := backData[:backLen-2] dataCrc := backData[backLen-2:] err := d.calculateCRC(crcData, crcResult) if err != nil { return err } if dataCrc[0] != crcResult[0] || dataCrc[1] != crcResult[1] { return fmt.Errorf("CRC: values not match %v - %v", crcResult, dataCrc) } } return nil } // 16 bit CRC will be calculated for the given data func (d *MFRC522Common) calculateCRC(data []byte, result []byte) error { // Stop any active command. if err := d.writeByteData(regCommand, commandRegIdle); err != nil { return err } if err := d.writeByteData(regDivIrq, divIrqRegCRCIRqBit); err != nil { return err } if err := d.writeByteData(regFIFOLevel, fifoLevelRegFlushBufferBit); err != nil { return err } if err := d.writeFifo(data); err != nil { return err } if err := d.writeByteData(regCommand, commandRegCalcCRC); err != nil { return err } const maxTries = 3 for i := 0; i < maxTries; i++ { irqs, err := d.readByteData(regDivIrq) if err != nil { return err } if irqs&divIrqRegCRCIRqBit == divIrqRegCRCIRqBit { if err := d.writeByteData(regCommand, commandRegIdle); err != nil { return err } result[0], err = d.readByteData(regCRCResultL) if err != nil { return err } result[1], err = d.readByteData(regCRCResultH) if err != nil { return err } return nil } time.Sleep(time.Millisecond) } return fmt.Errorf("no CRC available after %d tries", maxTries) } func (d *MFRC522Common) writeFifo(fifoData []byte) error { // the register command is always the same, the pointer in FIFO is incremented automatically after each write for _, b := range fifoData { if err := d.writeByteData(regFIFOData, b); err != nil { return err } } return nil } func (d *MFRC522Common) readFifo(backData []byte) (uint8, error) { n, err := d.readByteData(regFIFOLevel) // Number of bytes in the FIFO if err != nil { return 0, err } //nolint:gosec // TODO: fix later if n > uint8(len(backData)) { return 0, fmt.Errorf("more data in FIFO (%d) than expected (%d)", n, len(backData)) } //nolint:gosec // TODO: fix later if n < uint8(len(backData)) { return 0, fmt.Errorf("less data in FIFO (%d) than expected (%d)", n, len(backData)) } // the register command is always the same, the pointer in FIFO is incremented automatically after each read for i := 0; i < int(n); i++ { byteVal, err := d.readByteData(regFIFOData) if err != nil { return 0, err } backData[i] = byteVal } rxLastBits, err := d.readByteData(regControl) if err != nil { return 0, err } return rxLastBits & controlRegRxLastBits, nil } func (d *MFRC522Common) getFirstError(errorRegValue uint8) error { if errorRegValue == 0 { return nil } if errorRegValue&errorRegProtocolErrBit == errorRegProtocolErrBit { return fmt.Errorf("a protocol error occurred") } if errorRegValue&errorRegParityErrBit == errorRegParityErrBit { return fmt.Errorf("a parity error occurred") } if errorRegValue&errorRegCRCErrBit == errorRegCRCErrBit { return fmt.Errorf("a CRC error occurred") } if errorRegValue&errorRegCollErrBit == errorRegCollErrBit { return fmt.Errorf("a collision error occurred") } if errorRegValue&errorRegBufferOvflBit == errorRegBufferOvflBit { return fmt.Errorf("a buffer overflow error occurred") } if errorRegValue&errorRegTempErrBit == errorRegTempErrBit { return fmt.Errorf("a temperature error occurred") } if errorRegValue&errorRegWrErrBit == errorRegWrErrBit { return fmt.Errorf("a temperature error occurred") } return fmt.Errorf("an unknown error occurred") } ================================================ FILE: drivers/common/mfrc522/mfrc522_pcd_register.go ================================================ //nolint:lll // ok here package mfrc522 // Page 0: Command and status const ( // 0x00 // reserved for future use regCommand = 0x01 // starts and stops command execution // ------------ values -------------------- // commands, see chapter 10.3, table 149 of the datasheet (only 4 lower bits are used for writing) commandRegIdle = 0x00 // no action, cancels current command execution commandRegMem = 0x01 // stores 25 bytes into the internal buffer commandRegGenerateRandomID = 0x02 // generates a 10-byte random ID number commandRegCalcCRC = 0x03 // activates the CRC coprocessor or performs a self-test commandRegTransmit = 0x04 // transmits data from the FIFO buffer // 0x05, 0x06 not used // commandRegNoCmdChange = 0x07 // no command change, can be used to modify the Command register bits without // commandRegReceive = 0x08 // activates the receiver circuits // 0x09..0x0B not used commandRegTransceive = 0x0C // transmits data from FIFO buffer to antenna and automatically activates the receiver after transmission // 0x0D reserved commandRegMFAuthent = 0x0E // performs the MIFARE standard authentication as a reader commandRegSoftReset = 0x0F // resets the MFRC522 // starts the wake up procedure during which this bit is read as a logic 1; it is read as a logic 0 when the // is ready; Remark: The PowerDown bit cannot be set when the SoftReset command is activated commandRegPowerDownBit = 0x10 // Soft power-down mode entered, if 1 commandRegRcvOffBit = 0x20 // analog part of the receiver is switched off, if 1 // commandRegReserved67 = 0xC0 ) const ( regComIEn = 0x02 // enable and disable the passing of interrupt requests to IRQ pin // ------------ values -------------------- comIEnRegReset = 0x80 // see table 25 of data sheet comIEnRegTimerIEnBit = 0x01 // bit 0: allows the timer interrupt request (TimerIRq bit) to be propagated comIEnRegErrIEnBit = 0x02 // bit 1: allows the error interrupt request (ErrIRq bit) to be propagated comIEnRegLoAlertIEnBit = 0x04 // bit 2: allows the low alert interrupt request (LoAlertIRq bit) to be propagated comIEnRegHiAlertIEnBit = 0x08 // bit 3: allows the high alert interrupt request (HiAlertIRq bit) to be propagated comIEnRegIdleIEnBit = 0x10 // bit 4: allows the idle interrupt request (IdleIRq bit) to be propagated comIEnRegRxIEnBit = 0x20 // bit 5: allows the receiver interrupt request (RxIRq bit) to be propagated comIEnRegTxIEnBit = 0x40 // bit 6: allows the transmitter interrupt request (TxIRq bit) to be propagated // 1: signal on pin IRQ is inverted with respect to the Status1 register’s IRq bit // 0: signal on pin IRQ is equal to the IRq bit; in combination with the DivIEn register’s IRqPushPull bit, the // default value of logic 1 ensures that the output level on pin IRQ is 3-state comIEnRegIRqInv = 0x80 // bit 7: see above ) const ( // ------------ unused commands -------------------- // regDivIEn = 0x03 // enable and disable the passing of interrupt requests to IRQ pin ) const ( regComIrq = 0x04 // interrupt request bits for communication // ------------ values -------------------- comIrqRegReset = 0x14 // see table 29 of data sheet comIrqRegClearAll = 0x7F // all bits are set to clear, except the Set1Bit (0 indicates the reset) comIrqRegTimerIRqBit = 0x01 // bit 0: the timer decrements the timer value in register TCounterVal to zero, if 1 comIrqRegErrIRq1anyBit = 0x02 // bit 1: error bit in the Error register is set, if 1 // Status1 register’s LoAlert bit is set in opposition to the LoAlert bit, the LoAlertIRq bit stores this event and // can only be reset as indicated by the Set1 bit in this register // comIrqRegLoAlertIRqBit = 0x04 // bit 2: if 1, see above // the Status1 register’s HiAlert bit is set in opposition to the HiAlert bit, the HiAlertIRq bit stores this event // and can only be reset as indicated by the Set1 bit in this register // comIrqRegHiAlertIRqBit = 0x08 // bit 3: if 1, see above // If a command terminates, for example, when the Command register changes its value from any command to Idle command. // If an unknown command is started, the Command register Command[3:0] value changes to the idle state and the // IdleIRq bit is set. The microcontroller starting the Idle command does not set the IdleIRq bit. comIrqRegIdleIRqBit = 0x10 // bit 4: if 1, see above // receiver has detected the end of a valid data stream, if the RxMode register’s RxNoErr bit is set to logic 1, // the RxIRq bit is only set to logic 1 when data bytes are available in the FIFO comIrqRegRxIRqBit = 0x20 // bit 5: if 1, see above comIrqRegTxIRqBit = 0x40 // bit 6: set to 1, immediately after the last bit of the transmitted data was sent out // 1: indicates that the marked bits in the register are set // 0: indicates that the marked bits in the register are cleared // comIrqRegSet1Bit = 0x80 // bit 7: see above ) const ( regDivIrq = 0x05 // diverse interrupt request bits // ------------ values -------------------- // divIrqRegReset = 0x00 // see table 31 of data sheet // divIrqRegReserved01 = 0x03 divIrqRegCRCIRqBit = 0x04 // bit 2: the CalcCRC command is active and all data is processed // divIrqRegReservedBit3 = 0x08 // this interrupt is set when either a rising or falling signal edge is detected // divIrqRegMfinActIRqBit = 0x10 // bit 4: MFIN is active; see above // divIrqRegReserved56 = 0x60 // 1: indicates that the marked bits in the register are set // 0: indicates that the marked bits in the register are cleared // divIrqRegSet2Bit = 0x80 // bit 7: see above ) const ( regError = 0x06 // error bits showing the error status of the last command executed // ------------ values -------------------- // errorRegReset = 0x00 // see table 33 of data sheet // set to logic 1 if the SOF is incorrect automatically cleared during receiver start-up phase bit is only valid for // 106 kBd; during the MFAuthent command, the ProtocolErr bit is set to logic 1 if the number of bytes received in one // data stream is incorrect errorRegProtocolErrBit = 0x01 // bit 0: see above // automatically cleared during receiver start-up phase; only valid for ISO/IEC 14443 A/MIFARE communication at 106 kBd errorRegParityErrBit = 0x02 // bit 1: parity check failed, see above // the RxMode register’s RxCRCEn bit is set and the CRC calculation fails automatically; cleared to logic 0 during // receiver start-up phase errorRegCRCErrBit = 0x04 // bit 2: see above // cleared automatically at receiver start-up phase; only valid during the bitwise anticollision at 106 kBd; always // set to logic 0 during communication protocols at 212 kBd, 424 kBd and 848 kBd errorRegCollErrBit = 0x08 // bit 3: a bit-collision is detected, see above // the host or a MFRC522’s internal state machine (e.g. receiver) tries to write data to the FIFO buffer even though // it is already full errorRegBufferOvflBit = 0x10 // bit 4: FIFO is full, see above // errorRegReservedBit5 = 0x20 // the antenna drivers are automatically switched off errorRegTempErrBit = 0x40 // bit 6: internal temperature sensor detects overheating, see above // data is written into the FIFO buffer by the host during the MFAuthent command or if data is written into the FIFO // buffer by the host during the time between sending the last bit on the RF interface and receiving the last bit on // the RF interface errorRegWrErrBit = 0x80 // bit 7: see above ) const ( // ------------ unused commands -------------------- // regStatus1 = 0x07 // communication status bits ) const ( regStatus2 = 0x08 // receiver and transmitter status bits // ------------ values -------------------- // status2RegReset = 0x00 // see table 37 of data sheet // bit 0..2 shows the state of the transmitter and receiver state machines // status2RegModemStateIdle = 0x00 // idle // status2RegModemStateWait = 0x01 // wait for the BitFraming register’s StartSend bit // the minimum time for TxWait is defined by the TxWait register // status2RegModemStateTxWait = 0x02 // wait until RF field is present if the TMode register’s TxWaitRF bit is set to logic 1 // status2RegModemStateTransmitting = 0x03 // the minimum time for RxWait is defined by the RxWait register // status2RegModemStateRxWait = 0x04 // wait until RF field is present if the TMode register’s TxWaitRF bit is set to logic 1 // status2RegModemStateWaitForData = 0x05 // status2RegModemStateReceiving = 0x06 // all data communication with the card is encrypted; can only be set to logic 1 by a successful execution of the // MFAuthent command; only valid in Read/Write mode for MIFARE standard cards; this bit is cleared by software status2RegMFCrypto1OnBit = 0x08 // bit 3: indicates that the MIFARE Crypto1 unit is switched on and, see above // status2RegReserved45 = 0x30 // 1: the I2C-bus input filter is set to the High-speed mode independent of the I2C-bus protocol // 0: the I2C-bus input filter is set to the I2C-bus protocol used // status2RegI2cForceHSBit = 0x40 // I2C-bus input filter settings, see above // status2RegTempSensClear1Bit = 0x80 // clears the temperature error if the temperature is below the alarm limit of 125C ) const ( regFIFOData = 0x09 // input and output of 64 byte FIFO buffer ) const ( regFIFOLevel = 0x0A // number of bytes stored in the FIFO buffer // ------------ values -------------------- // fifoLevelRegReset = 0x00 // see table 41 of data sheet // indicates the number of bytes stored in the FIFO buffer writing to the FIFOData register increments and reading // decrements the FIFOLevel value // fifoLevelRegValue = 0x7F // bit 0..6: see above // immediately clears the internal FIFO buffer’s read and write pointer and Error register’s BufferOvfl bit reading // this bit always returns 0 fifoLevelRegFlushBufferBit = 0x80 // bit 7: see above ) const ( // ------------ unused commands -------------------- // regWaterLevel = 0x0B // level for FIFO underflow and overflow warning ) const ( regControl = 0x0C // miscellaneous control registers // ------------ values -------------------- // controlRegReset = 0x10 // see table 45 of data sheet // indicates the number of valid bits in the last received byte // if this value is 000b, the whole byte is valid controlRegRxLastBits = 0x07 // bit 0..2: see above // controlRegReserved3to5 = 0x38 // controlRegTStartNowBit = 0x40 // bit 6: timer starts immediately, if 1; reading always returns logic 0 // controlRegTStopNow = 0x80 // bit 7: timer stops immediately, if 1; reading always returns logic 0 ) const ( regBitFraming = 0x0D // adjustments for bit-oriented frames // ------------ values -------------------- bitFramingRegReset = 0x00 // see table 47 of data sheet // used for transmission of bit oriented frames: defines the number of bits of the last byte that will be transmitted // 000b indicates that all bits of the last byte will be transmitted bitFramingRegTxLastBits = 0x07 // bit 0..2: see above // bitFramingRegReservedBit3 = 0x08 // used for reception of bit-oriented frames: defines the bit position for the first bit received to be stored in the // FIFO buffer, example: // 0: LSB of the received bit is stored at bit position 0, the second received bit is stored at bit position 1 // 1: LSB of the received bit is stored at bit position 1, the second received bit is stored at bit position 2 // 7: LSB of the received bit is stored at bit position 7, the second received bit is stored in the next byte that // follows at bit position 0 // These bits are only to be used for bitwise anticollision at 106 kBd, for all other modes they are set to 0 // bitFramingRegRxAlign = 0x70 // bit 4..6: see above // starts the transmission of data, only valid in combination with the Transceive command bitFramingRegStartSendBit = 0x80 // bit 7: see above ) const ( regColl = 0x0E // bit position of the first bit-collision detected on the RF interface // 4 to 0 CollPos[4:0]- // shows the bit position of the first detected collision in a received frame only data bits are interpreted example: // 00: indicates a bit-collision in the 32nd bit // 01: indicates a bit-collision in the 1st bit // 08: indicates a bit-collision in the 8th bit // These bits will only be interpreted if the CollPosNotValid bit is set to logic 0 // collRegCollPos = 0x1F // bit 0..4: read-only, see above // no collision detected or the position of the collision is out of the range of CollPos[4:0], if set to 1 // collRegCollPosNotValidBit = 0x20 // bit 5: read-only, see above // collRegReservedBit6 = 0x40 // all received bits will be cleared after a collision only used during bitwise anticollision at 106 kBd, otherwise it // is set to logic 1 collRegValuesAfterCollBit = 0x80 // bit 7: see above ) // 0x0F // reserved for future use // Page 1: Command // 0x10 // reserved for future use const ( regMode = 0x11 // defines general modes for transmitting and receiving // ------------ values -------------------- // modeRegReset = 0x3F // see table 55 of data sheet // bit 0..1: defines the preset value for the CRC coprocessor for the CalcCRC command; Remark: during any // communication, the preset values are selected automatically according to the definition of bits in the rxModeReg // and TxMode registers modeRegCRCPreset0000 = 0x00 // 0x0000 modeRegCRCPreset6363 = 0x01 // 0x6363 modeRegCRCPresetA671 = 0x10 // 0xA671 modeRegCRCPresetFFFF = 0x11 // 0xFFFF // modeRegReservedBit2 = 0x04 // defines the polarity of pin MFIN; Remark: the internal envelope signal is encoded active LOW, changing this bit // generates a MFinActIRq event modeRegPolMFinBit = 0x08 // bit 3: polarity of pin MFIN is active HIGH, is set to 1 // modeRegReservedBit4 = 0x10 modeRegTxWaitRFBit = 0x20 // bit 5: transmitter can only be started if an RF field is generated, if set to 1 // modeRegReservedBit6 = 0x40 // CRC coprocessor calculates the CRC with MSB first 0 in the CRCResult register the values for the CRCResultMSB[7:0] // bits and the CRCResultLSB[7:0] bits are bit reversed; Remark: during RF communication this bit is ignored // modeRegMSBFirstBit = 0x80 // bit 7: see above, if set to 1 ) const ( regTxMode = 0x12 // defines transmission data rate and framing regRxMode = 0x13 // defines reception data rate and framing // ------------ values -------------------- rxtxModeRegReset = 0x00 // txModeRegReserved = 0x07 // bit 0..2 reserved for TX // rxModeRegReserved = 0x03 // bit 0,1 reserved for RX // 0: receiver is deactivated after receiving a data frame // 1: able to receive more than one data frame; only valid for data rates above 106 kBd in order to handle the // polling command; after setting this bit the Receive and Transceive commands will not terminate automatically. // Multiple reception can only be deactivated by writing any command (except the Receive command) to the commandReg // register, or by the host clearing the bit if set to logic 1, an error byte is added to the FIFO buffer at the // end of a received data stream which is a copy of the Error register value. For the version 2.0 the // CRC status is reflected in the signal CRCOk, which indicates the actual status of the CRC coprocessor. For the // version 1.0 the CRC status is reflected in the signal CRCErr. // rxModeRegRxMultipleBit = 0x04 // an invalid received data stream (less than 4 bits received) will be ignored and the receiver remains active // rxModeRegRxNoErrBit = 0x08 // bit 3 // txModeRegInvModBit = 0x08 // bit 3: modulation of transmitted data is inverted, if 1 // bit 4..6: defines the bit rate during data transmission; the handles transfer speeds up to 848 kBd // rxtxModeRegSpeed106kBd = 0x00 //106 kBd // rxtxModeRegSpeed212kBd = 0x10 //212 kBd // rxtxModeRegSpeed424kBd = 0x20 //424 kBd // rxtxModeRegSpeed848kBd = 0x30 //848 kBd // rxtxModeRegSpeedRes1 = 0x40 //reserved // rxtxModeRegSpeedRes2 = 0x50 //reserved // rxtxModeRegSpeedRes3 = 0x60 //reserved // rxtxModeRegSpeedRes4 = 0x70 //reserved // RX: enables the CRC calculation during reception // TX: enables CRC generation during data transmission // rxtxModeRegTxCRCEnBit = 0x80 // bit 7: can only be set to logic 0 at 106 kBd ) const ( regTxControl = 0x14 // controls the logical behavior of the antenna driver pins TX1 and TX2 // ------------ values -------------------- // regtxControlRegReset = 0x80 // see table 61 of data sheet // signal on pin TX1 delivers the 13.56 MHz energy carrier modulated by the transmission data txControlRegTx1RFEn1outputBit = 0x01 // bit 0: see above // signal on pin TX2 delivers the 13.56 MHz energy carrier modulated by the transmission data txControlRegTx2RFEn1outputBit = 0x02 // bit 1: see above // txControlRegReservedBit2 = 0x04 // signal on pin TX2 continuously delivers the unmodulated 13.56 MHz energy carrier0Tx2CW bit is enabled to modulate // the 13.56 MHz energy carrier // txControlRegTx2CW1outputBit = 0x08 // bit 3: see above // txControlRegInvTx1RFOffBit = 0x10 // bit 4: output signal on pin TX1 inverted if driver TX1 is disabled, if 1 // txControlRegInvTx2RFOffBit = 0x20 // bit 5: output signal on pin TX2 inverted if driver TX2 is disabled, if 1 // txControlRegInvTx1RFOnBit = 0x40 // bit 6: output signal on pin TX1 inverted if driver TX1 is enabled, if 1 // txControlRegInvTx2RFOnBit = 0x80 // bit 7: output signal on pin TX2 inverted if driver TX2 is enabled, if 1 ) const ( regTxASK = 0x15 // controls the setting of the transmission modulation // ------------ values -------------------- // txASKRegReset = 0x00 // see table 63 of data sheet // txASKRegReserved = 0x3F // bit 0..5 txASKRegForce100ASKBit = 0x40 // bit 6: forces a 100 % ASK modulation independent of the ModGsP register // txASKRegReservedBit7 = 0x80 ) const ( // regTxSel = 0x16 // selects the internal sources for the antenna driver // regRxSel = 0x17 // selects internal receiver settings // regRxThreshold = 0x18 // selects thresholds for the bit decoder // regDemod = 0x19 // defines demodulator settings // 0x1A // reserved for future use // 0x1B // reserved for future use // regMfTx = 0x1C // controls some MIFARE communication transmit parameters // regMfRx = 0x1D // controls some MIFARE communication receive parameters // 0x1E // reserved for future use // regSerialSpeed = 0x1F // selects the speed of the serial UART interface // Page 2: Configuration // 0x20 // reserved for future use regCRCResultH = 0x21 // shows the MSB and LSB values of the CRC calculation regCRCResultL = 0x22 // 0x23 // reserved for future use ) const ( regModWidth = 0x24 // ------------ values -------------------- modWidthRegReset = 0x26 // see table 93 of data sheet ) // 0x25 // reserved for future use const ( regRFCfg = 0x26 // configures the receiver gain // ------------ values -------------------- // rfcCfgRegReset = 0x48 // see table 97 of data sheet // rfcCfgRegReserved03 = 0x07 // bit 4..6: defines the receiver’s signal voltage gain factor rfcCfgRegRxGain18dB = 0x00 rfcCfgRegRxGain23dB = 0x10 rfcCfgRegRxGain018dB = 0x20 rfcCfgRegRxGain023dB = 0x30 rfcCfgRegRxGain33dB = 0x40 rfcCfgRegRxGain38dB = 0x50 rfcCfgRegRxGain43dB = 0x60 rfcCfgRegRxGain48dB = 0x70 // rfcCfgRegReserved7 = 0x80 ) const ( // ------------ unused commands -------------------- // regGsN = 0x27 // selects the conductance of the antenna driver pins TX1 and TX2 for modulation // regCWGsP = 0x28 // defines the conductance of the p-driver output during periods of no modulation // regModGsP = 0x29 // defines the conductance of the p-driver output during periods of modulation ) const ( regTMode = 0x2A // defines settings for the internal timer regTPrescaler = 0x2B // the lower 8 bits of the TPrescaler value. The 4 high bits are in tModeReg. // ------------ values -------------------- // tModeRegReset = 0x00 // see table 105 of data sheet // tPrescalerRegReset = 0x00 // see table 107 of data sheet // timer starts automatically at the end of the transmission in all communication modes at all speeds; if the // RxMode register’s RxMultiple bit is not set, the timer stops immediately after receiving the 5th bit (1 start // bit, 4 data bits); if the RxMultiple bit is set to logic 1 the timer never stops, in which case the timer can be // stopped by setting the Control register’s TStopNow bit to logic 1 tModeRegTAutoBit = 0x80 // bit 7: see above // bit 6,5: indicates that the timer is not influenced by the protocol; internal timer is running in // gated mode; Remark: in gated mode, the Status1 register’s TRunning bit is logic 1 when the timer is enabled by // the TMode register’s TGated bits; this bit does not influence the gating signal // tModeRegTGatedNon = 0x00 // non-gated mode // tModeRegTGatedMFIN = 0x20 // gated by pin MFIN // tModeRegTGatedAUX1 = 0x40 // gated by pin AUX1 // 1: timer automatically restarts its count-down from the 16-bit timer reload value instead of counting down to zero // 0: timer decrements to 0 and the ComIrq register’s TimerIRq bit is set to logic 1 // tModeRegTAutoRestartBit = 0x10 // bit 4, see above // defines the higher 4 bits of the TPrescaler value; The following formula is used to calculate the timer // frequency if the Demod register’s TPrescalEven bit in Demot register’s set to logic 0: // ftimer = 13.56 MHz / (2*TPreScaler+1); TPreScaler = [tPrescalerRegHi:tPrescalerRegLo] // TPrescaler value on 12 bits) (Default TPrescalEven bit is logic 0) // The following formula is used to calculate the timer frequency if the Demod register’s TPrescalEven bit is set // to logic 1: ftimer = 13.56 MHz / (2*TPreScaler+2). // tModeRegtPrescalerRegValue25us = 0x0A9 // 169 => fRegtimer=40kHz, timer period of 25μs. // tModeRegtPrescalerRegValue38us = 0x0FF // 255 => fRegtimer=26kHz, timer period of 38μs. // tModeRegtPrescalerRegValue500us = 0xD3E // 3390 => fRegtimer= 2kHz, timer period of 500us. // tModeRegtPrescalerRegValue604us = 0xFFF // 4095 => fRegtimer=1.65kHz, timer period of 604us. ) const ( // defines the 16-bit timer reload value; on a start event, the timer loads the timer reload value changing this // register affects the timer only at the next start event regTReloadH = 0x2C regTReloadL = 0x2D // ------------ values -------------------- tReloadRegReset = 0x0000 // see table 109, 111 tReloadRegValue25ms = 0x03E8 // 1000, 25ms before timeout tReloadRegValue833ms = 0x001E // 30, 833ms before timeout ) const ( // ------------ unused commands -------------------- // regTCounterValueH = 0x2E // shows the 16-bit timer value // regTCounterValueL = 0x2F // Page 3: Test Registers // 0x30 // reserved for future use regTestSel1 = 0x31 // general test signal configuration regTestSel2 = 0x32 // general test signal configuration regTestPinEn = 0x33 // enables pin output driver on pins D1 to D7 regTestPinValue = 0x34 // defines the values for D1 to D7 when it is used as an I/O bus regTestBus = 0x35 // shows the status of the internal test bus regAutoTest = 0x36 // controls the digital self-test regVersion = 0x37 // shows the software version regAnalogTest = 0x38 // controls the pins AUX1 and AUX2 regTestDAC1 = 0x39 // defines the test value for TestDAC1 regTestDAC2 = 0x3A // defines the test value for TestDAC2 regTestADC = 0x3B // shows the value of ADC I and Q channels // 0x3C // reserved for production tests // 0x3D // reserved for production tests // 0x3E // reserved for production tests // 0x3F // reserved for production tests ) ================================================ FILE: drivers/common/mfrc522/mfrc522_pcd_test.go ================================================ package mfrc522 import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) type busConnMock struct { written []byte readIdx int simRead []byte fifoIdx int simFifo []byte } func (c *busConnMock) ReadByteData(reg uint8) (uint8, error) { c.written = append(c.written, reg) switch reg { case regFIFOLevel: return uint8(len(c.simFifo)), nil //nolint:gosec // ok for test case regFIFOData: c.fifoIdx++ return c.simFifo[c.fifoIdx-1], nil default: if len(c.simRead) > 0 { c.readIdx++ return c.simRead[c.readIdx-1], nil } return 0, nil } } func (c *busConnMock) WriteByteData(reg uint8, data byte) error { c.written = append(c.written, reg) c.written = append(c.written, data) return nil } func initTestMFRC522CommonWithStubbedConnector() (*MFRC522Common, *busConnMock) { c := &busConnMock{} d := NewMFRC522Common() d.connection = c return d, c } func TestNewMFRC522Common(t *testing.T) { // act d := NewMFRC522Common() // assert assert.NotNil(t, d) } func TestInitialize(t *testing.T) { // arrange wantSoftReset := []byte{0x01, 0x0F, 0x01} wantInit := []byte{ 0x12, 0x00, 0x13, 0x00, 0x24, 0x26, 0x2A, 0x8F, 0x2B, 0xFF, 0x2D, 0xE8, 0x2C, 0x03, 0x15, 0x40, 0x11, 0x29, } wantAntennaOn := []byte{0x14, 0x14, 0x03} wantGain := []byte{0x26, 0x50} c := &busConnMock{} d := NewMFRC522Common() // act err := d.Initialize(c) // assert require.NoError(t, err) assert.Equal(t, c, d.connection) assert.Equal(t, wantSoftReset, c.written[:3]) assert.Equal(t, wantInit, c.written[3:21]) assert.Equal(t, wantAntennaOn, c.written[21:24]) assert.Equal(t, wantGain, c.written[24:]) } func Test_getVersion(t *testing.T) { // arrange d, c := initTestMFRC522CommonWithStubbedConnector() wantWritten := []byte{0x37} const want = uint8(5) c.simRead = []byte{want} // act got, err := d.getVersion() // assert require.NoError(t, err) assert.Equal(t, want, got) assert.Equal(t, wantWritten, c.written) } func Test_switchAntenna(t *testing.T) { tests := map[string]struct { target bool simRead byte wantWritten []byte }{ "switch_on": { target: true, simRead: 0xFD, wantWritten: []byte{0x14, 0x14, 0xFF}, }, "is_already_on": { target: true, simRead: 0x03, wantWritten: []byte{0x14}, }, "switch_off": { target: false, simRead: 0x03, wantWritten: []byte{0x14, 0x14, 0x00}, }, "is_already_off": { target: false, simRead: 0xFD, wantWritten: []byte{0x14}, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, c := initTestMFRC522CommonWithStubbedConnector() c.simRead = []byte{tc.simRead} // act err := d.switchAntenna(tc.target) // assert require.NoError(t, err) assert.Equal(t, tc.wantWritten, c.written) }) } } func Test_stopCrypto1(t *testing.T) { // arrange d, c := initTestMFRC522CommonWithStubbedConnector() c.simRead = []byte{0xFF} wantWritten := []byte{0x08, 0x08, 0xF7} // act err := d.stopCrypto1() // assert require.NoError(t, err) assert.Equal(t, wantWritten, c.written) } func Test_communicateWithPICC(t *testing.T) { // arrange d, c := initTestMFRC522CommonWithStubbedConnector() dataToFifo := []byte{0xF1, 0xF2} writtenPrepare := []byte{0x02, 0xF7, 0x04, 0x7F, 0x0A, 0x80, 0x01, 0x00} writtenWriteFifo := []byte{0x09, 0xF1, 0x09, 0xF2} writtenTransceive := []byte{0x0D, 0x00, 0x01, 0x0C} writtenBitFramingStart := []byte{0x0D, 0x0D, 0x80} writtenWaitAndFinish := []byte{0x04, 0x0D, 0x0D, 0x7F, 0x06} writtenReadFifo := []byte{0x0A, 0x09, 0x09, 0x0C} // read: bit framing register set, simulate calculation done, bit framing register clear, simulate no error, // simulate control register 0x00 c.simRead = []byte{0x00, 0x30, 0xFF, 0x00, 0x00} c.simFifo = []byte{0x11, 0x22} backData := []byte{0x00, 0x00} // act // transceive, all 8 bits, no CRC err := d.communicateWithPICC(0x0C, dataToFifo, backData, 0x00, false) // assert require.NoError(t, err) assert.Equal(t, writtenPrepare, c.written[:8]) assert.Equal(t, writtenWriteFifo, c.written[8:12]) assert.Equal(t, writtenTransceive, c.written[12:16]) assert.Equal(t, writtenBitFramingStart, c.written[16:19]) assert.Equal(t, writtenWaitAndFinish, c.written[19:24]) assert.Equal(t, writtenReadFifo, c.written[24:]) assert.Equal(t, []byte{0x11, 0x22}, backData) } func Test_calculateCRC(t *testing.T) { // arrange d, c := initTestMFRC522CommonWithStubbedConnector() dataToFifo := []byte{0x02, 0x03} writtenPrepare := []byte{0x01, 0x00, 0x05, 0x04, 0x0A, 0x80} writtenFifo := []byte{0x09, 0x02, 0x09, 0x03} writtenCalc := []byte{0x01, 0x03, 0x05, 0x01, 0x00} writtenGetResult := []byte{0x22, 0x21} c.simRead = []byte{0x04, 0x11, 0x22} // calculation done, crcL, crcH gotCrcBack := []byte{0x00, 0x00} // act err := d.calculateCRC(dataToFifo, gotCrcBack) // assert require.NoError(t, err) assert.Equal(t, writtenPrepare, c.written[:6]) assert.Equal(t, writtenFifo, c.written[6:10]) assert.Equal(t, writtenCalc, c.written[10:15]) assert.Equal(t, writtenGetResult, c.written[15:]) assert.Equal(t, []byte{0x11, 0x22}, gotCrcBack) } func Test_writeFifo(t *testing.T) { // arrange d, c := initTestMFRC522CommonWithStubbedConnector() dataToFifo := []byte{0x11, 0x22, 0x33} wantWritten := []byte{0x09, 0x11, 0x09, 0x22, 0x09, 0x33} // act err := d.writeFifo(dataToFifo) // assert require.NoError(t, err) assert.Equal(t, wantWritten, c.written) } func Test_readFifo(t *testing.T) { // arrange d, c := initTestMFRC522CommonWithStubbedConnector() c.simFifo = []byte{0x30, 0x20, 0x10} wantWritten := []byte{0x0A, 0x09, 0x09, 0x09, 0x0C} backData := []byte{0x00, 0x00, 0x00} // act _, err := d.readFifo(backData) // assert require.NoError(t, err) assert.Equal(t, wantWritten, c.written) assert.Equal(t, c.simFifo, backData) } ================================================ FILE: drivers/common/mfrc522/mfrc522_picc.go ================================================ //nolint:lll // ok here package mfrc522 import ( "fmt" ) const piccDebug = false // Commands sent to the PICC, used by the PCD to for communication with several PICCs (ISO 14443-3, Type A, section 6.4) const ( // Activation piccCommandRequestA = 0x26 // REQuest command type A, 7 bit frame, invites PICCs in state IDLE to go to READY piccCommandWakeUpA = 0x52 // Wake-UP command type A, 7 bit frame, invites PICCs in state IDLE and HALT to go to READY // Anticollision and SAK piccCommandCascadeLevel1 = 0x93 // Select cascade level 1 piccCommandCascadeLevel2 = 0x95 // Select cascade Level 2 piccCommandCascadeLevel3 = 0x97 // Select cascade Level 3 piccCascadeTag = 0x88 // Cascade tag is used during anti collision piccUIDNotComplete = 0x04 // used on SAK call // Halt piccCommandHLTA = 0x50 // Halt command, Type A. Instructs an active PICC to go to state HALT. piccCommandRATS = 0xE0 // Request command for Answer To Reset. // The commands used for MIFARE Classic (from http://www.mouser.com/ds/2/302/MF1S503x-89574.pdf, Section 9) // Use MFAuthent to authenticate access to a sector, then use these commands to read/write/modify the blocks on // the sector. The read/write commands can also be used for MIFARE Ultralight. piccCommandMFRegAUTHRegKEYRegA = 0x60 // Perform authentication with Key A piccCommandMFRegAUTHRegKEYRegB = 0x61 // Perform authentication with Key B // Reads one 16 byte block from the authenticated sector of the PICC. Also used for MIFARE Ultralight. piccCommandMFRegREAD = 0x30 // Writes one 16 byte block to the authenticated sector of the PICC. Called "COMPATIBILITY WRITE" for MIFARE Ultralight. piccCommandMFRegWRITE = 0xA0 piccWriteAck = 0x0A // MIFARE Classic: 4 bit ACK, we use any other value as NAK (data sheet: 0h to 9h, Bh to Fh) piccCommandMFRegDECREMENT = 0xC0 // Decrements the contents of a block and stores the result in the internal data register. piccCommandMFRegINCREMENT = 0xC1 // Increments the contents of a block and stores the result in the internal data register. piccCommandMFRegRESTORE = 0xC2 // Reads the contents of a block into the internal data register. piccCommandMFRegTRANSFER = 0xB0 // Writes the contents of the internal data register to a block. // The commands used for MIFARE Ultralight (from http://www.nxp.com/documents/dataRegsheet/MF0ICU1.pdf, Section 8.6) // The piccCommandMFRegREAD and piccCommandMFRegWRITE can also be used for MIFARE Ultralight. // piccCommandULRegWRITE = 0xA2 // Writes one 4 byte page to the PICC. ) const piccReadWriteAuthBlock = uint8(11) var ( piccKey = []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} piccUserBlockAddresses = []byte{8, 9, 10} ) var piccCardFromSak = map[uint8]string{ 0x08: "Classic 1K, Plus 2K-SE-1K(SL1)", 0x18: "Classic 4K, Plus 4K(SL1)", 0x10: "Plus 2K(SL2)", 0x11: "Plus 4K(SL2)", 0x20: "Plus 2K-SE-1K(SL3), Plus 4K(SL3)", } // IsCardPresent is used to poll for a card in range. After an successful request, the card is halted. func (d *MFRC522Common) IsCardPresent() error { d.firstCardAccess = true if err := d.writeByteData(regTxMode, rxtxModeRegReset); err != nil { return err } if err := d.writeByteData(regRxMode, rxtxModeRegReset); err != nil { return err } if err := d.writeByteData(regModWidth, modWidthRegReset); err != nil { return err } answer := []byte{0x00, 0x00} // also called ATQA if err := d.piccRequest(piccCommandWakeUpA, answer); err != nil { return err } if piccDebug { fmt.Printf("Card found: %v\n\n", answer) } if err := d.piccHalt(); err != nil { return err } return nil } // ReadText reads a card with the dedicated workflow: REQA, Activate, Perform Transaction, Halt/Deselect. // see "Card Polling" in https://www.nxp.com/docs/en/application-note/AN10834.pdf. // and return the result as text string. // TODO: make this more usable, e.g. by given length of text func (d *MFRC522Common) ReadText() (string, error) { answer := []byte{0x00, 0x00} if err := d.piccRequest(piccCommandWakeUpA, answer); err != nil { return "", err } uid, err := d.piccActivate() if err != nil { return "", err } if piccDebug { fmt.Printf("uid: %v\n", uid) } if err := d.piccAuthenticate(piccReadWriteAuthBlock, piccKey, uid); err != nil { if piccDebug { fmt.Println("authenticate failed for address", piccReadWriteAuthBlock) } return "", err } var content []byte for _, block := range piccUserBlockAddresses { blockData, err := d.piccRead(block) if err != nil { if piccDebug { fmt.Println("read failed at block", block) } return "", err } content = append(content, blockData...) } if piccDebug { fmt.Println("content:", string(content), len(content)) } if err := d.piccHalt(); err != nil { return "", err } return string(content), d.stopCrypto1() } // WriteText writes the given string to the card. All old values will be overwritten. func (d *MFRC522Common) WriteText(text string) error { answer := []byte{0x00, 0x00} if err := d.piccRequest(piccCommandWakeUpA, answer); err != nil { return err } uid, err := d.piccActivate() if err != nil { return err } if piccDebug { fmt.Printf("uid: %v\n", uid) } if err := d.piccAuthenticate(piccReadWriteAuthBlock, piccKey, uid); err != nil { if piccDebug { fmt.Println("authenticate failed for address", piccReadWriteAuthBlock) } return err } // prepare data with text and trailing zero's textData := append([]byte(text), make([]byte, len(piccUserBlockAddresses)*16)...) for i, blockNum := range piccUserBlockAddresses { blockData := textData[i*16 : (i+1)*16] err := d.piccWrite(blockNum, blockData) if err != nil { if piccDebug { fmt.Println("write failed at block", blockNum) } return err } } if err := d.piccHalt(); err != nil { return err } return d.stopCrypto1() } func (d *MFRC522Common) piccHalt() error { if piccDebug { fmt.Println("-halt-") } haltCommand := []byte{piccCommandHLTA, 0x00} crcResult := []byte{0x00, 0x00} if err := d.calculateCRC(haltCommand, crcResult); err != nil { return err } haltCommand = append(haltCommand, crcResult...) txLastBits := uint8(0x00) // we use all 8 bits if err := d.communicateWithPICC(commandRegTransceive, haltCommand, []byte{}, txLastBits, false); err != nil { // an error is the sign for successful halt if piccDebug { fmt.Println("this is not treated as error:", err) } return nil } return fmt.Errorf("something went wrong with halt") } func (d *MFRC522Common) piccWrite(block uint8, blockData []byte) error { if piccDebug { fmt.Println("-write-") fmt.Println("blockData:", string(blockData), len(blockData)) } if len(blockData) != 16 { return fmt.Errorf("the block to write needs to be exactly 16 bytes long, but has %d bytes", len(blockData)) } // MIFARE Classic protocol requires two steps to perform a write. // Step 1: Tell the PICC we want to write to block blockAddr. writeDataCommand := []byte{piccCommandMFRegWRITE, block} crcResult := []byte{0x00, 0x00} if err := d.calculateCRC(writeDataCommand, crcResult); err != nil { return err } writeDataCommand = append(writeDataCommand, crcResult...) txLastBits := uint8(0x00) // we use all 8 bits backData := make([]byte, 1) if err := d.communicateWithPICC(commandRegTransceive, writeDataCommand, backData, txLastBits, false); err != nil { return err } if backData[0]&piccWriteAck != piccWriteAck { return fmt.Errorf("preparation of write on MIFARE classic failed (%v)", backData) } if piccDebug { fmt.Println("backData", string(backData)) } // Step 2: Transfer the data if err := d.calculateCRC(blockData, crcResult); err != nil { return err } var writeData []byte writeData = append(writeData, blockData...) writeData = append(writeData, crcResult...) if err := d.communicateWithPICC(commandRegTransceive, writeData, []byte{}, txLastBits, false); err != nil { return err } return nil } func (d *MFRC522Common) piccRead(block uint8) ([]byte, error) { if piccDebug { fmt.Println("-read-") } readDataCommand := []byte{piccCommandMFRegREAD, block} crcResult := []byte{0x00, 0x00} if err := d.calculateCRC(readDataCommand, crcResult); err != nil { return nil, err } readDataCommand = append(readDataCommand, crcResult...) txLastBits := uint8(0x00) // we use all 8 bits backData := make([]byte, 18) // 16 data byte and 2 byte CRC if err := d.communicateWithPICC(commandRegTransceive, readDataCommand, backData, txLastBits, true); err != nil { return nil, err } return backData[:16], nil } func (d *MFRC522Common) piccAuthenticate(address uint8, key []byte, uid []byte) error { if piccDebug { fmt.Println("-authenticate-") } buf := []byte{piccCommandMFRegAUTHRegKEYRegA, address} buf = append(buf, key...) buf = append(buf, uid...) if err := d.communicateWithPICC(commandRegMFAuthent, buf, []byte{}, 0, false); err != nil { return err } return nil } // activate a card with the dedicated workflow: Anticollision and optional Request for "Answer To Select" (RATS) and // "Protocol Parameter Selection" (PPS). // see "Card Activation" in https://www.nxp.com/docs/en/application-note/AN10834.pdf. // note: the card needs to be in ready state, e.g. by a request or wake up is done before func (d *MFRC522Common) piccActivate() ([]byte, error) { if err := d.clearRegisterBitMask(regColl, collRegValuesAfterCollBit); err != nil { return nil, err } if err := d.writeByteData(regBitFraming, bitFramingRegReset); err != nil { return nil, err } // start cascade level 1 (0x93) for return: // * one size UID (4 byte): UID0..3 and one byte BCC or // * cascade tag (0x88) and UID0..2 and BCC // in the latter case the UID is incomplete and the next cascade level needs to be started. // cascade level 2 (0x95) return: // * double size UID (7 byte): UID3..6 and one byte BCC or // * cascade tag (0x88) and UID3..5 and BCC // cascade level 3 (0x97) return: // * triple size UID (10 byte): UID6..9 // after each anticollision check (request of next UID) the SAK needs to be done (same level command) // BCC: Block Check Character // SAK: Select Acknowledge var uid []byte var sak uint8 for cascadeLevel := 1; cascadeLevel < 3; cascadeLevel++ { var piccCommand uint8 switch cascadeLevel { case 1: piccCommand = piccCommandCascadeLevel1 case 2: piccCommand = piccCommandCascadeLevel2 case 3: piccCommand = piccCommandCascadeLevel3 default: return nil, fmt.Errorf("unknown cascade level %d", cascadeLevel) } if piccDebug { fmt.Println("-anti collision-") } txLastBits := uint8(0x00) // we use all 8 bits numValidBits := uint8(4 * 8) sendForAnticol := []byte{piccCommand, numValidBits} backData := []byte{0x00, 0x00, 0x00, 0x00, 0x00} // 4 bytes CT/UID and BCC if err := d.communicateWithPICC(commandRegTransceive, sendForAnticol, backData, txLastBits, false); err != nil { return nil, err } // TODO: no real anticollision check yet // check BCC bcc := byte(0) for _, v := range backData[:4] { bcc = bcc ^ v } if bcc != backData[4] { return nil, fmt.Errorf("BCC mismatch, expected %02x actual %02x", bcc, backData[4]) } if backData[0] == piccCascadeTag { uid = append(uid, backData[1:3]...) if piccDebug { fmt.Printf("next cascade is needed after SAK, uid: %v", uid) } } else { uid = append(uid, backData[:4]...) if piccDebug { fmt.Printf("backData: %v, uid: %v\n", backData, uid) } } if piccDebug { fmt.Println("-select acknowledge-") } sendCommand := []byte{piccCommand} sendCommand = append(sendCommand, 0x70) // 7 bytes sendCommand = append(sendCommand, backData...) // uid including BCC crcResult := []byte{0x00, 0x00} if err := d.calculateCRC(sendCommand, crcResult); err != nil { return uid, err } sendCommand = append(sendCommand, crcResult...) sakData := []byte{0x00, 0x00, 0x00} if err := d.communicateWithPICC(commandRegTransceive, sendCommand, sakData, txLastBits, false); err != nil { return nil, err } bcc = byte(0) for _, v := range sakData[:2] { bcc = bcc ^ v } if piccDebug { fmt.Printf("sak data: %v\n", sakData) } if sakData[0] != piccUIDNotComplete { sak = sakData[0] break } if piccDebug { fmt.Printf("next cascade called, SAK: %v\n", sakData[0]) } } if piccDebug || d.firstCardAccess { d.firstCardAccess = false fmt.Printf("card '%s' selected\n", piccCardFromSak[sak]) } return uid, nil } func (d *MFRC522Common) piccRequest(reqMode uint8, answer []byte) error { if len(answer) < 2 { return fmt.Errorf("at least 2 bytes room needed for the answer") } if err := d.clearRegisterBitMask(regColl, collRegValuesAfterCollBit); err != nil { return err } // for request A and wake up the short frame format is used - transmit only 7 bits of the last (and only) byte. txLastBits := uint8(0x07 & bitFramingRegTxLastBits) if err := d.communicateWithPICC(commandRegTransceive, []byte{reqMode}, answer, txLastBits, false); err != nil { return err } return nil } ================================================ FILE: drivers/common/spherocommon/spherocommon.go ================================================ package spherocommon const ( // ErrorEvent event when error encountered ErrorEvent = "error" // SensorDataEvent event when sensor data is received SensorDataEvent = "sensordata" // CollisionEvent event when collision is detected CollisionEvent = "collision" ) // DefaultDataStreamingConfig returns a config with a sampling rate of 40hz, 1 sample frame per package, // unlimited streaming, and will stream all available sensor information func DefaultDataStreamingConfig() DataStreamingConfig { return DataStreamingConfig{ N: 10, M: 1, Mask: 4294967295, Pcnt: 0, Mask2: 4294967295, } } // CalculateChecksum calculates the checksum for Sphero packets func CalculateChecksum(buf []byte) byte { var calculatedChecksum uint16 for i := range buf { calculatedChecksum += uint16(buf[i]) } return uint8(^(calculatedChecksum % 256)) //nolint:gosec // TODO: fix later } ================================================ FILE: drivers/common/spherocommon/spherocommon_packets.go ================================================ package spherocommon // LocatorConfig provides configuration for the Location api. // For more information refer to the api specification of "Orbotix Communication API" // see also: http://wiki.mark-toma.com/view/Sphero_API_Tutorial // The current (X,Y) coordinates of Sphero on the ground plane in centimeters. type LocatorConfig struct { // Determines whether calibrate commands automatically correct the yaw tare value Flags uint8 // Controls how the X-plane is aligned with Sphero’s heading coordinate system. X int16 // Controls how the Y-plane is aligned with Sphero’s heading coordinate system. Y int16 // Controls how the X,Y-plane is aligned with Sphero’s heading coordinate system. YawTare int16 } // CollisionConfig provides configuration for the collision detection alogorithm. // For more information refer to the api specification of "Orbotix Communication API" // see also: http://wiki.mark-toma.com/view/Sphero_API_Tutorial type CollisionConfig struct { // Detection method type to use. Methods 01h and 02h are supported as // of FW ver 1.42. Use 00h to completely disable this service. Method uint8 // An 8-bit settable threshold for the X (left/right) axes of Sphero. // A value of 00h disables the contribution of that axis. Xt uint8 // An 8-bit settable threshold for the Y (front/back) axes of Sphero. // A value of 00h disables the contribution of that axis. Yt uint8 // An 8-bit settable speed value for the X axes. This setting is ranged // by the speed, then added to Xt to generate the final threshold value. Xs uint8 // An 8-bit settable speed value for the Y axes. This setting is ranged // by the speed, then added to Yt to generate the final threshold value. Ys uint8 // An 8-bit post-collision dead time to prevent retriggering; specified // in 10ms increments. Dead uint8 } // DataStreamingConfig provides configuration for Sensor Data Streaming. // For more information refer to the api specification of "Orbotix Communication API" // see also: http://wiki.mark-toma.com/view/Sphero_API_Tutorial type DataStreamingConfig struct { // Divisor of the maximum sensor sampling rate N uint16 // Number of sample frames emitted per packet M uint16 // Bitwise selector of data sources to stream Mask uint32 // Packet count 1-255 (or 0 for unlimited streaming) Pcnt uint8 // Bitwise selector of more data sources to stream (optional) Mask2 uint32 } // PowerStatePacket contains all data relevant to the power state of the sphero type PowerStatePacket struct { // record Version Code RecVer uint8 // High-Level State of the Battery; 1=charging, 2=battery ok, 3=battery low, 4=battery critical PowerState uint8 // Battery Voltage, scaled in 100th of a Volt, 0x02EF would be 7.51 volts BattVoltage uint16 // Number of charges in the total lifetime of the sphero NumCharges uint16 // Seconds awake since last charge TimeSinceChg uint16 } // CollisionPacket represents the response from a Collision event type CollisionPacket struct { // Normalized impact components (direction of the collision event): X, Y, Z int16 // Thresholds exceeded by X (1h) and/or Y (2h) axis (bitmask): Axis byte // Power that cross threshold Xt + Xs: XMagnitude, YMagnitude int16 // Sphero's speed when impact detected: Speed uint8 // Millisecond timer Timestamp uint32 } // DataStreamingPacket represents the response from a Data Streaming event type DataStreamingPacket struct { // 8000 0000h accelerometer axis X, raw -2048 to 2047 4mG RawAccX int16 // 4000 0000h accelerometer axis Y, raw -2048 to 2047 4mG RawAccY int16 // 2000 0000h accelerometer axis Z, raw -2048 to 2047 4mG RawAccZ int16 // 1000 0000h gyro axis X, raw -32768 to 32767 0.068 degrees RawGyroX int16 // 0800 0000h gyro axis Y, raw -32768 to 32767 0.068 degrees RawGyroY int16 // 0400 0000h gyro axis Z, raw -32768 to 32767 0.068 degrees RawGyroZ int16 // 0200 0000h Reserved Rsrv1 int16 // 0100 0000h Reserved Rsrv2 int16 // 0080 0000h Reserved Rsrv3 int16 // 0040 0000h right motor back EMF, raw -32768 to 32767 22.5 cm RawRMotorBack int16 // 0020 0000h left motor back EMF, raw -32768 to 32767 22.5 cm RawLMotorBack int16 // 0010 0000h left motor, PWM, raw -2048 to 2047 duty cycle RawLMotor int16 // 0008 0000h right motor, PWM raw -2048 to 2047 duty cycle RawRMotor int16 // 0004 0000h IMU pitch angle, filtered -179 to 180 degrees FiltPitch int16 // 0002 0000h IMU roll angle, filtered -179 to 180 degrees FiltRoll int16 // 0001 0000h IMU yaw angle, filtered -179 to 180 degrees FiltYaw int16 // 0000 8000h accelerometer axis X, filtered -32768 to 32767 1/4096 G FiltAccX int16 // 0000 4000h accelerometer axis Y, filtered -32768 to 32767 1/4096 G FiltAccY int16 // 0000 2000h accelerometer axis Z, filtered -32768 to 32767 1/4096 G FiltAccZ int16 // 0000 1000h gyro axis X, filtered -20000 to 20000 0.1 dps FiltGyroX int16 // 0000 0800h gyro axis Y, filtered -20000 to 20000 0.1 dps FiltGyroY int16 // 0000 0400h gyro axis Z, filtered -20000 to 20000 0.1 dps FiltGyroZ int16 // 0000 0200h Reserved Rsrv4 int16 // 0000 0100h Reserved Rsrv5 int16 // 0000 0080h Reserved Rsrv6 int16 // 0000 0040h right motor back EMF, filtered -32768 to 32767 22.5 cm FiltRMotorBack int16 // 0000 0020h left motor back EMF, filtered -32768 to 32767 22.5 cm FiltLMotorBack int16 // 0000 0010h Reserved 1 Rsrv7 int16 // 0000 0008h Reserved 2 Rsrv8 int16 // 0000 0004h Reserved 3 Rsrv9 int16 // 0000 0002h Reserved 4 Rsrv10 int16 // 0000 0001h Reserved 5 Rsrv11 int16 // 8000 0000h Quaternion Q0 -10000 to 10000 1/10000 Q Quat0 int16 // 4000 0000h Quaternion Q1 -10000 to 10000 1/10000 Q Quat1 int16 // 2000 0000h Quaternion Q2 -10000 to 10000 1/10000 Q Quat2 int16 // 1000 0000h Quaternion Q3 -10000 to 10000 1/10000 Q Quat3 int16 // 0800 0000h Odometer X -32768 to 32767 cm OdomX int16 // 0400 0000h Odometer Y -32768 to 32767 cm OdomY int16 // 0200 0000h AccelOne 0 to 8000 1 mG AccelOne int16 // 0100 0000h Velocity X -32768 to 32767 mm/s VeloX int16 // 0080 0000h Velocity Y -32768 to 32767 mm/s VeloY int16 } ================================================ FILE: drivers/common/spherocommon/spherocommon_test.go ================================================ package spherocommon import ( "fmt" "testing" "github.com/stretchr/testify/require" ) func TestCalculateChecksum(t *testing.T) { tests := []struct { data []byte checksum byte }{ {[]byte{0x00}, 0xff}, {[]byte{0xf0, 0x0f}, 0x00}, } for _, tt := range tests { actual := CalculateChecksum(tt.data) if actual != tt.checksum { require.Fail(t, fmt.Sprintf("Expected %x, got %x for data %x.", tt.checksum, actual, tt.data)) } } } ================================================ FILE: drivers/gpio/LICENSE ================================================ Copyright (c) 2013-2018 The Hybrid Group Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: drivers/gpio/README.md ================================================ # GPIO This package provides drivers for [General Purpose Input/Output (GPIO)](https://en.wikipedia.org/wiki/General_Purpose_Input/Output) devices. It is normally used by connecting an adaptor such as [Raspberry Pi](https://gobot.io/documentation/platforms/raspi/) that supports the needed interfaces for GPIO devices. ## Getting Started Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) ## Hardware Support Gobot has a extensible system for connecting to hardware devices. The following GPIO devices are currently supported: - AIP1640 LED Dot Matrix/7 Segment Controller - Button - Buzzer - Direct Pin - EasyDriver - Grove Button (by using driver for Button) - Grove Buzzer (by using driver for Buzzer) - Grove LED (by using driver for LED) - Grove Magnetic Switch (by using driver for Button) - Grove Relay (by using driver for Relay) - Grove Touch Sensor (by using driver for Button) - HC-SR04 Ultrasonic Ranging Module - HD44780 LCD controller - LED - Makey Button (by using driver for Button) - MAX7219 LED Dot Matrix - Motor - Proximity Infra Red (PIR) Motion Sensor - Relay - RGB LED - Servo - Stepper Motor - TM1638 LED Controller ================================================ FILE: drivers/gpio/aip1640_driver.go ================================================ package gpio import ( "time" "gobot.io/x/gobot/v2" ) // Commands of the driver const ( AIP1640DataCmd = 0x40 AIP1640DispCtrl = 0x88 AIP1640AddrCmd = 0xC0 AIP1640FixedAddr = 0x04 ) // AIP1640Driver is the gobot driver for the AIP1640 LED driver used in the WEMOS D1 mini Matrix LED Shield. // It has some similarities with the TM16xx LED drivers // // Datasheet CN: https://datasheet.lcsc.com/szlcsc/AiP1640_C82650.pdf // // Library ported from: https://github.com/wemos/WEMOS_Matrix_LED_Shield_Arduino_Library type AIP1640Driver struct { *driver pinClock *DirectPinDriver pinData *DirectPinDriver intensity byte buffer [8]byte } // NewAIP1640Driver return a new driver for AIP1640 LED driver given a gobot.Connection and the clock, // data and strobe pins. // // Supported options: // // "WithName" func NewAIP1640Driver(a gobot.Connection, clockPin string, dataPin string, opts ...interface{}) *AIP1640Driver { d := &AIP1640Driver{ driver: newDriver(a, "AIP1640", opts...), pinClock: NewDirectPinDriver(a, clockPin), pinData: NewDirectPinDriver(a, dataPin), intensity: 7, } d.afterStart = d.initialize /* TODO : Add commands */ return d } // SetIntensity changes the intensity (from 1 to 7) of the display func (d *AIP1640Driver) SetIntensity(level byte) { if level >= 7 { level = 7 } d.intensity = level } // Display sends the buffer to the display (ie. turns on/off the corresponding LEDs) func (d *AIP1640Driver) Display() error { for i := 0; i < 8; i++ { if err := d.sendData(byte(i), d.buffer[i]); err != nil { return err } if err := d.pinData.Off(); err != nil { return err } if err := d.pinClock.Off(); err != nil { return err } time.Sleep(1 * time.Millisecond) if err := d.pinClock.On(); err != nil { return err } if err := d.pinData.On(); err != nil { return err } } return d.sendCommand(AIP1640DispCtrl | d.intensity) } // Clear empties the buffer (turns off all the LEDs) func (d *AIP1640Driver) Clear() { for i := 0; i < 8; i++ { d.buffer[i] = 0x00 } } // DrawPixel turns on or off a specific in the buffer func (d *AIP1640Driver) DrawPixel(x, y byte, enabled bool) { if x >= 8 || y >= 8 { return } y = 7 - y if enabled { d.buffer[y] |= 1 << x } else { d.buffer[y] &^= 1 << x } } // DrawRow sets any given row of LEDs in the buffer func (d *AIP1640Driver) DrawRow(row, data byte) { if row >= 8 { return } d.buffer[7-row] = data } // DrawMatrix sets the whole buffer func (d *AIP1640Driver) DrawMatrix(data [8]byte) { for i := 0; i < 8; i++ { d.buffer[7-i] = data[i] } } // initialize initializes the tm1638, it uses a SPI-like communication protocol func (d *AIP1640Driver) initialize() error { if err := d.pinData.On(); err != nil { return err } return d.pinClock.On() } // sendCommand is an auxiliary function to send commands to the AIP1640Driver module func (d *AIP1640Driver) sendCommand(cmd byte) error { if err := d.pinData.Off(); err != nil { return err } if err := d.send(cmd); err != nil { return err } return d.pinData.On() } // sendData is an auxiliary function to send data to the AIP1640Driver module func (d *AIP1640Driver) sendData(address byte, data byte) error { if err := d.sendCommand(AIP1640DataCmd | AIP1640FixedAddr); err != nil { return err } if err := d.pinData.Off(); err != nil { return err } if err := d.send(AIP1640AddrCmd | address); err != nil { return err } if err := d.send(data); err != nil { return err } return d.pinData.On() } // send writes data on the module func (d *AIP1640Driver) send(data byte) error { for i := 0; i < 8; i++ { if err := d.pinClock.Off(); err != nil { return err } if (data & 1) > 0 { if err := d.pinData.On(); err != nil { return err } } else { if err := d.pinData.Off(); err != nil { return err } } data >>= 1 if err := d.pinClock.On(); err != nil { return err } } return nil } ================================================ FILE: drivers/gpio/aip1640_driver_test.go ================================================ package gpio import ( "strings" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" ) var _ gobot.Driver = (*AIP1640Driver)(nil) func initTestAIP1640Driver() *AIP1640Driver { d, _ := initTestAIP1640DriverWithStubbedAdaptor() return d } func initTestAIP1640DriverWithStubbedAdaptor() (*AIP1640Driver, *gpioTestAdaptor) { a := newGpioTestAdaptor() return NewAIP1640Driver(a, "1", "2"), a } func TestNewAIP1640Driver(t *testing.T) { // arrange a := newGpioTestAdaptor() // act d := NewAIP1640Driver(a, "1", "2") // assert assert.IsType(t, &AIP1640Driver{}, d) // assert: gpio.driver attributes require.NotNil(t, d.driver) assert.True(t, strings.HasPrefix(d.driverCfg.name, "AIP1640")) assert.Equal(t, a, d.connection) assert.NotNil(t, d.afterStart) assert.NotNil(t, d.beforeHalt) assert.NotNil(t, d.Commander) assert.NotNil(t, d.mutex) // assert: driver specific attributes assert.NotNil(t, d.pinClock) assert.NotNil(t, d.pinData) assert.Equal(t, uint8(7), d.intensity) } func TestNewAIP1640Driver_options(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithName() option, least one // option of this driver and one of another driver (which should lead to panic). Further tests for options can also // be done by call of "WithOption(val).apply(cfg)". // arrange const ( myName = "count up" cycReadDur = 30 * time.Millisecond ) panicFunc := func() { NewAIP1640Driver(newGpioTestAdaptor(), "1", "2", WithName("crazy"), aio.WithActuatorScaler(func(float64) int { return 0 })) } // act d := NewAIP1640Driver(newGpioTestAdaptor(), "1", "2", WithName(myName)) // assert assert.Equal(t, myName, d.Name()) assert.PanicsWithValue(t, "'scaler option for analog actuators' can not be applied on 'crazy'", panicFunc) } func TestAIP1640Start(t *testing.T) { d := initTestAIP1640Driver() require.NoError(t, d.Start()) } func TestAIP1640DrawPixel(t *testing.T) { d := initTestAIP1640Driver() d.DrawPixel(2, 3, true) d.DrawPixel(0, 3, true) assert.Equal(t, uint8(5), d.buffer[7-3]) } func TestAIP1640DrawRow(t *testing.T) { d := initTestAIP1640Driver() d.DrawRow(4, 0x3C) assert.Equal(t, uint8(0x3C), d.buffer[7-4]) } func TestAIP1640DrawMatrix(t *testing.T) { d := initTestAIP1640Driver() drawing := [8]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF} d.DrawMatrix(drawing) assert.Equal(t, [8]byte{0xEF, 0xCD, 0xAB, 0x89, 0x67, 0x45, 0x23, 0x01}, d.buffer) } func TestAIP1640Clear(t *testing.T) { d := initTestAIP1640Driver() drawing := [8]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF} d.DrawMatrix(drawing) assert.Equal(t, [8]byte{0xEF, 0xCD, 0xAB, 0x89, 0x67, 0x45, 0x23, 0x01}, d.buffer) d.Clear() assert.Equal(t, [8]byte{}, d.buffer) } func TestAIP1640SetIntensity(t *testing.T) { d := initTestAIP1640Driver() d.SetIntensity(3) assert.Equal(t, uint8(3), d.intensity) } func TestAIP1640SetIntensityHigherThan7(t *testing.T) { d := initTestAIP1640Driver() d.SetIntensity(19) assert.Equal(t, uint8(7), d.intensity) } ================================================ FILE: drivers/gpio/button_driver.go ================================================ package gpio import ( "fmt" "time" "gobot.io/x/gobot/v2" ) // buttonOptionApplier needs to be implemented by each configurable option type type buttonOptionApplier interface { apply(cfg *buttonConfiguration) } // buttonConfiguration contains all changeable attributes of the driver. type buttonConfiguration struct { readInterval time.Duration defaultState int } // buttonReadIntervalOption is the type for applying another read interval to the configuration type buttonReadIntervalOption time.Duration // buttonDefaultStateOption is the type for applying another default state to the configuration type buttonDefaultStateOption int // ButtonDriver Represents a digital Button type ButtonDriver struct { *driver gobot.Eventer buttonCfg *buttonConfiguration active bool halt chan struct{} } // NewButtonDriver returns a driver for a button with a polling interval for changed state of 10 milliseconds, // given a DigitalReader and pin. // // Supported options: // // "WithName" // "WithButtonPollInterval" func NewButtonDriver(a DigitalReader, pin string, opts ...interface{}) *ButtonDriver { //nolint:forcetypeassert // no error return value, so there is no better way d := &ButtonDriver{ driver: newDriver(a.(gobot.Connection), "Button", withPin(pin)), buttonCfg: &buttonConfiguration{readInterval: 10 * time.Millisecond, defaultState: 0}, } d.afterStart = d.initialize d.beforeHalt = d.shutdown for _, opt := range opts { switch o := opt.(type) { case optionApplier: o.apply(d.driverCfg) case buttonOptionApplier: o.apply(d.buttonCfg) case time.Duration: // TODO this is only for backward compatibility and will be removed after version 2.x d.buttonCfg.readInterval = o default: panic(fmt.Sprintf("'%s' can not be applied on '%s'", opt, d.driverCfg.name)) } } return d } // WithButtonPollInterval change the asynchronous cyclic reading interval from default 10ms to the given value. func WithButtonPollInterval(interval time.Duration) buttonOptionApplier { return buttonReadIntervalOption(interval) } // WithButtonDefaultState change the default state from default 0 to the given value. func WithButtonDefaultState(s int) buttonOptionApplier { return buttonDefaultStateOption(s) } // Active gets the current state func (d *ButtonDriver) Active() bool { // ensure that read and write can not interfere d.mutex.Lock() defer d.mutex.Unlock() return d.active } // SetDefaultState for the next start. // Deprecated: Please use option [gpio.WithButtonDefaultState] instead. func (d *ButtonDriver) SetDefaultState(s int) { // ensure that read and write can not interfere d.mutex.Lock() defer d.mutex.Unlock() WithButtonDefaultState(s).apply(d.buttonCfg) } // initialize the ButtonDriver and polls the state of the button at the given interval. // // Emits the Events: // // Push int - On button push // Release int - On button release // Error error - On button error func (d *ButtonDriver) initialize() error { if d.buttonCfg.readInterval == 0 { return fmt.Errorf("the read interval for button needs to be greater than zero") } d.Eventer = gobot.NewEventer() d.AddEvent(ButtonPush) d.AddEvent(ButtonRelease) d.AddEvent(Error) d.halt = make(chan struct{}) state := d.buttonCfg.defaultState go func() { for { select { case <-time.After(d.buttonCfg.readInterval): newValue, err := d.digitalRead(d.driverCfg.pin) if err != nil { d.Publish(Error, err) } else if newValue != state && newValue != -1 { state = newValue d.update(newValue) } case <-d.halt: return } } }() return nil } func (d *ButtonDriver) shutdown() error { if d.buttonCfg.readInterval == 0 || d.halt == nil { // cyclic reading deactivated return nil } close(d.halt) // broadcast halt, also to the test return nil } func (d *ButtonDriver) update(newValue int) { // ensure that read and write can not interfere d.mutex.Lock() defer d.mutex.Unlock() if newValue != d.buttonCfg.defaultState { d.active = true d.Publish(ButtonPush, newValue) } else { d.active = false d.Publish(ButtonRelease, newValue) } } func (o buttonReadIntervalOption) String() string { return "read interval option for buttons" } func (o buttonDefaultStateOption) String() string { return "default state option for buttons" } func (o buttonReadIntervalOption) apply(cfg *buttonConfiguration) { cfg.readInterval = time.Duration(o) } func (o buttonDefaultStateOption) apply(cfg *buttonConfiguration) { cfg.defaultState = int(o) } ================================================ FILE: drivers/gpio/button_driver_test.go ================================================ package gpio import ( "fmt" "strings" "sync" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" ) var _ gobot.Driver = (*ButtonDriver)(nil) const buttonTestDelay = 250 func initTestButtonDriverWithStubbedAdaptor() (*ButtonDriver, *gpioTestAdaptor) { a := newGpioTestAdaptor() d := NewButtonDriver(a, "1") return d, a } func TestNewButtonDriver(t *testing.T) { // arrange a := newGpioTestAdaptor() // act d := NewButtonDriver(a, "1") // assert assert.IsType(t, &ButtonDriver{}, d) // assert: gpio.driver attributes require.NotNil(t, d.driver) assert.True(t, strings.HasPrefix(d.driverCfg.name, "Button")) assert.Equal(t, "1", d.driverCfg.pin) assert.Equal(t, a, d.connection) assert.NotNil(t, d.afterStart) assert.NotNil(t, d.beforeHalt) assert.NotNil(t, d.Commander) assert.NotNil(t, d.mutex) // assert: driver specific attributes assert.False(t, d.active) assert.Nil(t, d.Eventer) // will be created on initialize assert.Nil(t, d.halt) // will be created on initialize require.NotNil(t, d.buttonCfg) assert.Equal(t, 0, d.buttonCfg.defaultState) assert.Equal(t, 10*time.Millisecond, d.buttonCfg.readInterval) } func TestNewButtonDriver_options(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithName() option, least one // option of this driver and one of another driver (which should lead to panic). Further tests for options can also // be done by call of "WithOption(val).apply(cfg)". // arrange const ( myName = "count up" cycReadDur = 30 * time.Millisecond ) panicFunc := func() { NewButtonDriver(newGpioTestAdaptor(), "1", WithName("crazy"), aio.WithActuatorScaler(func(float64) int { return 0 })) } // act d := NewButtonDriver(newGpioTestAdaptor(), "1", WithName(myName), WithButtonPollInterval(cycReadDur)) // assert assert.Equal(t, cycReadDur, d.buttonCfg.readInterval) assert.Equal(t, myName, d.Name()) assert.PanicsWithValue(t, "'scaler option for analog actuators' can not be applied on 'crazy'", panicFunc) } func TestButton_WithButtonDefaultState(t *testing.T) { // arrange const myDefaultState = 5 // only for test, usually it would be 0 or 1 cfg := buttonConfiguration{} // act WithButtonDefaultState(myDefaultState).apply(&cfg) // assert assert.Equal(t, myDefaultState, cfg.defaultState) } func TestButtonStart(t *testing.T) { // arrange sem := make(chan bool) nextVal := make(chan int, 1) d, a := initTestButtonDriverWithStubbedAdaptor() a.digitalReadFunc = func(string) (int, error) { val := 1 var err error select { case val = <-nextVal: if val < 0 { err = fmt.Errorf("digital read error") } return val, err default: return val, err } } // act: start cyclic reading err := d.Start() _ = d.Once(ButtonPush, func(data interface{}) { assert.True(t, d.Active()) nextVal <- 0 sem <- true }) // assert & rearrange require.NoError(t, err) select { case <-sem: case <-time.After(buttonTestDelay * time.Millisecond): assert.Fail(t, "Button Event \"Push\" was not published") } _ = d.Once(ButtonRelease, func(data interface{}) { assert.False(t, d.Active()) nextVal <- -1 sem <- true }) select { case <-sem: case <-time.After(buttonTestDelay * time.Millisecond): assert.Fail(t, "Button Event \"Release\" was not published") } _ = d.Once(Error, func(data interface{}) { sem <- true }) select { case <-sem: case <-time.After(buttonTestDelay * time.Millisecond): assert.Fail(t, "Button Event \"Error\" was not published") } _ = d.Once(ButtonPush, func(data interface{}) { sem <- true }) require.NoError(t, d.Halt()) nextVal <- 1 select { case <-sem: assert.Fail(t, "Button Event \"Press\" should not published") case <-time.After(buttonTestDelay * time.Millisecond): } } func TestButtonStart_WithDefaultState(t *testing.T) { // arrange sem := make(chan bool) nextVal := make(chan int, 1) a := newGpioTestAdaptor() d := NewButtonDriver(a, "1", WithButtonDefaultState(1)) a.digitalReadFunc = func(string) (int, error) { val := 0 select { case val = <-nextVal: return val, nil default: return val, nil } } // act: start cyclic reading require.NoError(t, d.Start()) _ = d.Once(ButtonPush, func(data interface{}) { assert.True(t, d.Active()) nextVal <- 1 sem <- true }) select { case <-sem: case <-time.After(buttonTestDelay * time.Millisecond): assert.Fail(t, "Button Event \"Push\" was not published") } _ = d.Once(ButtonRelease, func(data interface{}) { assert.False(t, d.Active()) sem <- true }) select { case <-sem: case <-time.After(buttonTestDelay * time.Millisecond): assert.Fail(t, "Button Event \"Release\" was not published") } } func TestButtonHalt(t *testing.T) { // arrange d, _ := initTestButtonDriverWithStubbedAdaptor() require.NoError(t, d.Start()) timeout := 2 * d.buttonCfg.readInterval wg := sync.WaitGroup{} wg.Add(1) go func() { defer wg.Done() select { case <-d.halt: // wait until halt is broadcasted by close the channel case <-time.After(timeout): // otherwise run into the timeout assert.Fail(t, fmt.Sprintf("halt was not received within %s", timeout)) } }() // act & assert require.NoError(t, d.Halt()) wg.Wait() // wait until the go function was really finished } func TestButtonActive(t *testing.T) { tests := map[string]struct { want bool }{ "active_true": {want: true}, "active_false": {want: false}, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d := ButtonDriver{driver: newDriver(nil, "Button")} // just for mutex d.active = tc.want // act & assert assert.Equal(t, tc.want, d.Active()) }) } } ================================================ FILE: drivers/gpio/buzzer_driver.go ================================================ package gpio import ( "fmt" "time" "gobot.io/x/gobot/v2" ) // Some useful divider const ( Whole = 4 Half = 2 Quarter = 1 Eighth = 0.500 ) // Some items of the musical scale const ( Rest = 0 C0 = 16.35 Db0 = 17.32 D0 = 18.35 Eb0 = 19.45 E0 = 20.60 F0 = 21.83 Gb0 = 23.12 G0 = 24.50 Ab0 = 25.96 A0 = 27.50 Bb0 = 29.14 B0 = 30.87 C1 = 32.70 Db1 = 34.65 D1 = 36.71 Eb1 = 38.89 E1 = 41.20 F1 = 43.65 Gb1 = 46.25 G1 = 49.00 Ab1 = 51.91 A1 = 55.00 Bb1 = 58.27 B1 = 61.74 C2 = 65.41 Db2 = 69.30 D2 = 73.42 Eb2 = 77.78 E2 = 82.41 F2 = 87.31 Gb2 = 92.50 G2 = 98.00 Ab2 = 103.83 A2 = 110.00 Bb2 = 116.54 B2 = 123.47 C3 = 130.81 Db3 = 138.59 D3 = 146.83 Eb3 = 155.56 E3 = 164.81 F3 = 174.61 Gb3 = 185.00 G3 = 196.00 Ab3 = 207.65 A3 = 220.00 Bb3 = 233.08 B3 = 246.94 C4 = 261.63 Db4 = 277.18 D4 = 293.66 Eb4 = 311.13 E4 = 329.63 F4 = 349.23 Gb4 = 369.99 G4 = 392.00 Ab4 = 415.30 A4 = 440.00 Bb4 = 466.16 B4 = 493.88 C5 = 523.25 Db5 = 554.37 D5 = 587.33 Eb5 = 622.25 E5 = 659.25 F5 = 698.46 Gb5 = 739.99 G5 = 783.99 Ab5 = 830.61 A5 = 880.00 Bb5 = 932.33 B5 = 987.77 C6 = 1046.50 Db6 = 1108.73 D6 = 1174.66 Eb6 = 1244.51 E6 = 1318.51 F6 = 1396.91 Gb6 = 1479.98 G6 = 1567.98 Ab6 = 1661.22 A6 = 1760.00 Bb6 = 1864.66 B6 = 1975.53 C7 = 2093.00 Db7 = 2217.46 D7 = 2349.32 Eb7 = 2489.02 E7 = 2637.02 F7 = 2793.83 Gb7 = 2959.96 G7 = 3135.96 Ab7 = 3322.44 A7 = 3520.00 Bb7 = 3729.31 B7 = 3951.07 C8 = 4186.01 Db8 = 4434.92 D8 = 4698.63 Eb8 = 4978.03 E8 = 5274.04 F8 = 5587.65 Gb8 = 5919.91 G8 = 6271.93 Ab8 = 6644.88 A8 = 7040.00 Bb8 = 7458.62 B8 = 7902.13 ) // BuzzerDriver represents a digital buzzer type BuzzerDriver struct { *driver high bool bpm float64 } // NewBuzzerDriver return a new BuzzerDriver given a DigitalWriter and pin. // // Supported options: // // "WithName" func NewBuzzerDriver(a DigitalWriter, pin string, opts ...interface{}) *BuzzerDriver { //nolint:forcetypeassert // no error return value, so there is no better way d := &BuzzerDriver{ driver: newDriver(a.(gobot.Connection), "Buzzer", withPin(pin)), bpm: 96.0, } for _, opt := range opts { switch o := opt.(type) { case optionApplier: o.apply(d.driverCfg) default: panic(fmt.Sprintf("'%s' can not be applied on '%s'", opt, d.driverCfg.name)) } } return d } // SetBPM change the bpm value. func (d *BuzzerDriver) SetBPM(val float64) { d.bpm = val } // BPM gets the current bpm value. func (d *BuzzerDriver) BPM() float64 { return d.bpm } // State return true if the buzzer is on and false if the buzzer is off func (d *BuzzerDriver) State() bool { return d.high } // On sets the buzzer to a high state. func (d *BuzzerDriver) On() error { if err := d.digitalWrite(d.driverCfg.pin, 1); err != nil { return err } d.high = true return nil } // Off sets the buzzer to a low state. func (d *BuzzerDriver) Off() error { if err := d.digitalWrite(d.driverCfg.pin, 0); err != nil { return err } d.high = false return nil } // Toggle sets the buzzer to the opposite of it's current state func (d *BuzzerDriver) Toggle() error { if d.State() { return d.Off() } return d.On() } // Tone is to make a sound with the given frequency func (d *BuzzerDriver) Tone(hz, duration float64) error { // calculation based off https://www.arduino.cc/en/Tutorial/Melody tone := (1.0 / (2.0 * hz)) * 1000000.0 tempo := ((60 / d.bpm) * (duration * 1000)) for i := 0.0; i < tempo*1000; i += tone * 2.0 { if err := d.On(); err != nil { return err } time.Sleep(time.Duration(tone) * time.Microsecond) if err := d.Off(); err != nil { return err } time.Sleep(time.Duration(tone) * time.Microsecond) } return nil } ================================================ FILE: drivers/gpio/buzzer_driver_test.go ================================================ package gpio import ( "errors" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" ) var _ gobot.Driver = (*BuzzerDriver)(nil) func initTestBuzzerDriver(conn DigitalWriter) *BuzzerDriver { return NewBuzzerDriver(conn, "1") } func TestNewBuzzerDriver(t *testing.T) { // arrange a := newGpioTestAdaptor() // act d := NewBuzzerDriver(a, "10") // assert assert.IsType(t, &BuzzerDriver{}, d) // assert: gpio.driver attributes require.NotNil(t, d.driver) assert.True(t, strings.HasPrefix(d.driverCfg.name, "Buzzer")) assert.Equal(t, "10", d.driverCfg.pin) assert.Equal(t, a, d.connection) assert.NotNil(t, d.afterStart) assert.NotNil(t, d.beforeHalt) assert.NotNil(t, d.Commander) assert.NotNil(t, d.mutex) // assert: driver specific attributes assert.False(t, d.high) assert.InDelta(t, 96, d.bpm, 0.0) } func TestNewBuzzerDriver_options(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithName() option, least one // option of this driver and one of another driver (which should lead to panic). Further tests for options can also // be done by call of "WithOption(val).apply(cfg)". // arrange const ( myName = "song player" ) panicFunc := func() { NewBuzzerDriver(newGpioTestAdaptor(), "1", WithName("crazy"), aio.WithActuatorScaler(func(float64) int { return 0 })) } // act d := NewBuzzerDriver(newGpioTestAdaptor(), "1", WithName(myName)) // assert assert.Equal(t, myName, d.Name()) assert.PanicsWithValue(t, "'scaler option for analog actuators' can not be applied on 'crazy'", panicFunc) } func TestBuzzerToggle(t *testing.T) { d := initTestBuzzerDriver(newGpioTestAdaptor()) require.NoError(t, d.Off()) require.NoError(t, d.Toggle()) assert.True(t, d.State()) require.NoError(t, d.Toggle()) assert.False(t, d.State()) } func TestBuzzerTone(t *testing.T) { d := initTestBuzzerDriver(newGpioTestAdaptor()) require.NoError(t, d.Tone(100, 0.01)) } func TestBuzzerOnError(t *testing.T) { a := newGpioTestAdaptor() d := initTestBuzzerDriver(a) a.digitalWriteFunc = func(string, byte) error { return errors.New("write error") } require.EqualError(t, d.On(), "write error") } func TestBuzzerOffError(t *testing.T) { a := newGpioTestAdaptor() d := initTestBuzzerDriver(a) a.digitalWriteFunc = func(string, byte) error { return errors.New("write error") } require.EqualError(t, d.Off(), "write error") } func TestBuzzerToneError(t *testing.T) { a := newGpioTestAdaptor() d := initTestBuzzerDriver(a) a.digitalWriteFunc = func(string, byte) error { return errors.New("write error") } require.EqualError(t, d.Tone(100, 0.01), "write error") } ================================================ FILE: drivers/gpio/direct_pin_driver.go ================================================ package gpio import ( "strconv" "gobot.io/x/gobot/v2" ) // DirectPinDriver represents a GPIO pin type DirectPinDriver struct { *driver } // NewDirectPinDriver return a new DirectPinDriver given a Connection and pin. // // Supported options: // // "WithName" // // Adds the following API Commands: // // "DigitalRead" - See DirectPinDriver.DigitalRead // "DigitalWrite" - See DirectPinDriver.DigitalWrite // "PwmWrite" - See DirectPinDriver.PwmWrite // "ServoWrite" - See DirectPinDriver.ServoWrite func NewDirectPinDriver(a gobot.Connection, pin string, opts ...interface{}) *DirectPinDriver { d := &DirectPinDriver{ driver: newDriver(a, "DirectPin", append(opts, withPin(pin))...), } d.AddCommand("DigitalRead", func(_ map[string]interface{}) interface{} { val, err := d.DigitalRead() return map[string]interface{}{"val": val, "err": err} }) //nolint:forcetypeassert // ok here d.AddCommand("DigitalWrite", func(params map[string]interface{}) interface{} { level, _ := strconv.Atoi(params["level"].(string)) return d.DigitalWrite(byte(level)) }) //nolint:forcetypeassert // ok here d.AddCommand("PwmWrite", func(params map[string]interface{}) interface{} { level, _ := strconv.Atoi(params["level"].(string)) return d.PwmWrite(byte(level)) }) //nolint:forcetypeassert // ok here d.AddCommand("ServoWrite", func(params map[string]interface{}) interface{} { level, _ := strconv.Atoi(params["level"].(string)) return d.ServoWrite(byte(level)) }) return d } // Off turn off pin func (d *DirectPinDriver) Off() error { return d.digitalWrite(d.driverCfg.pin, byte(0)) } // On turn on pin func (d *DirectPinDriver) On() error { return d.digitalWrite(d.driverCfg.pin, byte(1)) } // DigitalRead returns the current digital state of the pin func (d *DirectPinDriver) DigitalRead() (int, error) { return d.digitalRead(d.driverCfg.pin) } // DigitalWrite writes to the pin. Acceptable values are 1 or 0 func (d *DirectPinDriver) DigitalWrite(level byte) error { return d.digitalWrite(d.driverCfg.pin, level) } // PwmWrite writes the 0-254 value to the specified pin func (d *DirectPinDriver) PwmWrite(level byte) error { return d.pwmWrite(d.driverCfg.pin, level) } // ServoWrite writes value to the specified pin func (d *DirectPinDriver) ServoWrite(level byte) error { return d.servoWrite(d.driverCfg.pin, level) } ================================================ FILE: drivers/gpio/direct_pin_driver_test.go ================================================ //nolint:forcetypeassert // ok here package gpio import ( "errors" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" ) var _ gobot.Driver = (*DirectPinDriver)(nil) func initTestDirectPinDriver() *DirectPinDriver { a := newGpioTestAdaptor() a.digitalReadFunc = func(string) (int, error) { return 1, nil } a.digitalWriteFunc = func(string, byte) error { return errors.New("write error") } a.pwmWriteFunc = func(string, byte) error { return errors.New("write error") } a.servoWriteFunc = func(string, byte) error { return errors.New("write error") } return NewDirectPinDriver(a, "1") } func TestNewDirectPinDriver(t *testing.T) { // arrange a := newGpioTestAdaptor() // act d := NewDirectPinDriver(a, "10") // assert assert.IsType(t, &DirectPinDriver{}, d) // assert: gpio.driver attributes require.NotNil(t, d.driver) assert.True(t, strings.HasPrefix(d.driverCfg.name, "DirectPin")) assert.Equal(t, "10", d.driverCfg.pin) assert.Equal(t, a, d.connection) assert.NotNil(t, d.afterStart) assert.NotNil(t, d.beforeHalt) assert.NotNil(t, d.Commander) assert.NotNil(t, d.mutex) } func TestNewDirectPinDriver_options(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithName() option, least one // option of this driver and one of another driver (which should lead to panic). Further tests for options can also // be done by call of "WithOption(val).apply(cfg)". // arrange const ( myName = "count up" ) panicFunc := func() { NewDirectPinDriver(newGpioTestAdaptor(), "1", WithName("crazy"), aio.WithActuatorScaler(func(float64) int { return 0 })) } // act d := NewDirectPinDriver(newGpioTestAdaptor(), "1", WithName(myName)) // assert assert.Equal(t, myName, d.Name()) assert.PanicsWithValue(t, "'scaler option for analog actuators' can not be applied on 'crazy'", panicFunc) } func TestDirectPin_Commands(t *testing.T) { var ret map[string]interface{} var err interface{} d := initTestDirectPinDriver() ret = d.Command("DigitalRead")(nil).(map[string]interface{}) assert.Equal(t, 1, ret["val"].(int)) assert.Nil(t, ret["err"]) err = d.Command("DigitalWrite")(map[string]interface{}{"level": "1"}) require.EqualError(t, err.(error), "write error") err = d.Command("PwmWrite")(map[string]interface{}{"level": "1"}) require.EqualError(t, err.(error), "write error") err = d.Command("ServoWrite")(map[string]interface{}{"level": "1"}) require.EqualError(t, err.(error), "write error") } func TestDirectPinOff(t *testing.T) { d := initTestDirectPinDriver() require.Error(t, d.Off()) a := newGpioTestAdaptor() d = NewDirectPinDriver(a, "1") require.NoError(t, d.Off()) } func TestDirectPinOffNotSupported(t *testing.T) { a := &gpioTestBareAdaptor{} d := NewDirectPinDriver(a, "1") require.EqualError(t, d.Off(), "DigitalWrite is not supported by this platform") } func TestDirectPinOn(t *testing.T) { a := newGpioTestAdaptor() d := NewDirectPinDriver(a, "1") require.NoError(t, d.On()) } func TestDirectPinOnError(t *testing.T) { d := initTestDirectPinDriver() require.Error(t, d.On()) } func TestDirectPinOnNotSupported(t *testing.T) { a := &gpioTestBareAdaptor{} d := NewDirectPinDriver(a, "1") require.EqualError(t, d.On(), "DigitalWrite is not supported by this platform") } func TestDirectPinDigitalWrite(t *testing.T) { adaptor := newGpioTestAdaptor() d := NewDirectPinDriver(adaptor, "1") require.NoError(t, d.DigitalWrite(1)) } func TestDirectPinDigitalWriteNotSupported(t *testing.T) { a := &gpioTestBareAdaptor{} d := NewDirectPinDriver(a, "1") require.EqualError(t, d.DigitalWrite(1), "DigitalWrite is not supported by this platform") } func TestDirectPinDigitalWriteError(t *testing.T) { d := initTestDirectPinDriver() require.Error(t, d.DigitalWrite(1)) } func TestDirectPinDigitalRead(t *testing.T) { d := initTestDirectPinDriver() ret, err := d.DigitalRead() assert.Equal(t, 1, ret) require.NoError(t, err) } func TestDirectPinDigitalReadNotSupported(t *testing.T) { a := &gpioTestBareAdaptor{} d := NewDirectPinDriver(a, "1") _, e := d.DigitalRead() require.EqualError(t, e, "DigitalRead is not supported by this platform") } func TestDirectPinPwmWrite(t *testing.T) { a := newGpioTestAdaptor() d := NewDirectPinDriver(a, "1") require.NoError(t, d.PwmWrite(1)) } func TestDirectPinPwmWriteNotSupported(t *testing.T) { a := &gpioTestBareAdaptor{} d := NewDirectPinDriver(a, "1") require.EqualError(t, d.PwmWrite(1), "PwmWrite is not supported by this platform") } func TestDirectPinPwmWriteError(t *testing.T) { d := initTestDirectPinDriver() require.Error(t, d.PwmWrite(1)) } func TestDirectPinServoWrite(t *testing.T) { a := newGpioTestAdaptor() d := NewDirectPinDriver(a, "1") require.NoError(t, d.ServoWrite(1)) } func TestDirectPinServoWriteNotSupported(t *testing.T) { a := &gpioTestBareAdaptor{} d := NewDirectPinDriver(a, "1") require.EqualError(t, d.ServoWrite(1), "ServoWrite is not supported by this platform") } func TestDirectPinServoWriteError(t *testing.T) { d := initTestDirectPinDriver() require.Error(t, d.ServoWrite(1)) } ================================================ FILE: drivers/gpio/doc.go ================================================ /* Package gpio provides Gobot drivers for General Purpose Input/Output devices. Installing: Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) For further information refer to gpio README: https://github.com/hybridgroup/gobot/blob/release/platforms/gpio/README.md */ package gpio // import "gobot.io/x/gobot/v2/drivers/gpio" ================================================ FILE: drivers/gpio/easy_driver.go ================================================ package gpio import ( "fmt" "strings" "time" "gobot.io/x/gobot/v2" ) const easyDriverDebug = false // easyOptionApplier needs to be implemented by each configurable option type type easyOptionApplier interface { apply(cfg *easyConfiguration) } // easyConfiguration contains all changeable attributes of the driver. type easyConfiguration struct { dirPin string enPin string sleepPin string } // easyDirPinOption is the type for applying a pin for change direction type easyDirPinOption string // easyEnPinOption is the type for applying a pin for device disabling/enabling type easyEnPinOption string // easySleepPinOption is the type for applying a pin for setting device to sleep/wake type easySleepPinOption string // EasyDriver is an driver for stepper hardware board from SparkFun (https://www.sparkfun.com/products/12779) // This should also work for the BigEasyDriver (untested). It is basically a wrapper for the common StepperDriver{} // with the specific additions for the board, e.g. direction, enable and sleep outputs. type EasyDriver struct { *StepperDriver easyCfg *easyConfiguration stepPin string anglePerStep float32 sleeping bool } // NewEasyDriver returns a new driver // TODO: Support selecting phase input instead of hard-wiring MS1 and MS2 to board truth table // A - DigitalWriter // anglePerStep - Step angle of motor // stepPin - Pin corresponding to step input on EasyDriver // // Supported options: // // "WithName" // "WithEasyDirectionPin" // "WithEasyEnablePin" // "WithEasySleepPin" func NewEasyDriver(a DigitalWriter, anglePerStep float32, stepPin string, opts ...interface{}) *EasyDriver { if anglePerStep <= 0 { panic("angle per step needs to be greater than zero") } if stepPin == "" { panic("step pin is mandatory for easy driver") } stepper := NewStepperDriver(a, [4]string{}, nil, 1) stepper.driverCfg.name = gobot.DefaultName("EasyDriver") stepper.stepperDebug = easyDriverDebug stepper.haltIfRunning = false stepper.stepsPerRev = 360.0 / anglePerStep d := &EasyDriver{ StepperDriver: stepper, easyCfg: &easyConfiguration{}, stepPin: stepPin, anglePerStep: anglePerStep, } d.stepFunc = d.onePinStepping d.sleepFunc = d.sleepWithSleepPin d.beforeHalt = d.shutdown // 1/4 of max speed. Not too fast, not too slow d.speedRpm = d.MaxSpeed() / 4 for _, opt := range opts { switch o := opt.(type) { case optionApplier: o.apply(d.driverCfg) case easyOptionApplier: o.apply(d.easyCfg) default: oNames := []string{"WithEasyDirectionPin", "WithEasyEnablePin", "WithEasySleepPin"} msg := fmt.Sprintf("'%s' can not be applied on '%s', consider to use one of the options instead: %s", opt, d.driverCfg.name, strings.Join(oNames, ", ")) panic(msg) } } return d } // WithEasyDirectionPin configure a pin for change the moving direction. func WithEasyDirectionPin(pin string) easyOptionApplier { return easyDirPinOption(pin) } // WithEasyEnablePin configure a pin for disabling/enabling the driver. func WithEasyEnablePin(pin string) easyOptionApplier { return easyEnPinOption(pin) } // WithEasySleepPin configure a pin for sleep/wake the driver. func WithEasySleepPin(pin string) easyOptionApplier { return easySleepPinOption(pin) } // SetDirection sets the direction to be moving. func (d *EasyDriver) SetDirection(direction string) error { if d.easyCfg.dirPin == "" { return fmt.Errorf("dirPin is not set for '%s'", d.driverCfg.name) } direction = strings.ToLower(direction) if direction != StepperDriverForward && direction != StepperDriverBackward { return fmt.Errorf("invalid direction '%s'. Value should be '%s' or '%s'", direction, StepperDriverForward, StepperDriverBackward) } writeVal := byte(0) // low is forward if direction == StepperDriverBackward { writeVal = 1 // high is backward } if err := d.digitalWrite(d.easyCfg.dirPin, writeVal); err != nil { return err } // ensure that write of variable can not interfere with read in step() d.valueMutex.Lock() defer d.valueMutex.Unlock() d.direction = direction return nil } // Enable enables all motor output func (d *EasyDriver) Enable() error { if d.easyCfg.enPin == "" { d.disabled = false return fmt.Errorf("enPin is not set - board '%s' is enabled by default", d.driverCfg.name) } // enPin is active low if err := d.digitalWrite(d.easyCfg.enPin, 0); err != nil { return err } d.disabled = false return nil } // Disable disables all motor output func (d *EasyDriver) Disable() error { if d.easyCfg.enPin == "" { return fmt.Errorf("enPin is not set for '%s'", d.driverCfg.name) } _ = d.stopIfRunning() // drop step errors // enPin is active low if err := d.digitalWrite(d.easyCfg.enPin, 1); err != nil { return err } d.disabled = true return nil } // IsEnabled returns a bool stating whether motor is enabled func (d *EasyDriver) IsEnabled() bool { return !d.disabled } // Wake wakes up the driver func (d *EasyDriver) Wake() error { if d.easyCfg.sleepPin == "" { return fmt.Errorf("sleepPin is not set for '%s'", d.driverCfg.name) } // sleepPin is active low if err := d.digitalWrite(d.easyCfg.sleepPin, 1); err != nil { return err } d.sleeping = false // we need to wait 1ms after sleeping before doing a step to charge the step pump (according to data sheet) time.Sleep(1 * time.Millisecond) return nil } // IsSleeping returns a bool stating whether motor is sleeping func (d *EasyDriver) IsSleeping() bool { return d.sleeping } func (d *EasyDriver) onePinStepping() error { // ensure that read and write of variables (direction, stepNum) can not interfere d.valueMutex.Lock() defer d.valueMutex.Unlock() // a valid steps occurs for a low to high transition if err := d.digitalWrite(d.stepPin, 0); err != nil { return err } time.Sleep(d.getDelayPerStep()) if err := d.digitalWrite(d.stepPin, 1); err != nil { return err } if d.direction == StepperDriverForward { d.stepNum++ } else { d.stepNum-- } return nil } // sleepWithSleepPin puts the driver to sleep and disables all motor output. Low power mode. func (d *EasyDriver) sleepWithSleepPin() error { if d.easyCfg.sleepPin == "" { return fmt.Errorf("sleepPin is not set for '%s'", d.driverCfg.name) } _ = d.stopIfRunning() // drop step errors // sleepPin is active low if err := d.digitalWrite(d.easyCfg.sleepPin, 0); err != nil { return err } d.sleeping = true return nil } func (o easyDirPinOption) String() string { return "direction pin option easy driver" } func (o easyEnPinOption) String() string { return "enable pin option easy driver" } func (o easySleepPinOption) String() string { return "sleep pin option easy driver" } func (o easyDirPinOption) apply(cfg *easyConfiguration) { cfg.dirPin = string(o) } func (o easyEnPinOption) apply(cfg *easyConfiguration) { cfg.enPin = string(o) } func (o easySleepPinOption) apply(cfg *easyConfiguration) { cfg.sleepPin = string(o) } ================================================ FILE: drivers/gpio/easy_driver_test.go ================================================ package gpio import ( "fmt" "strings" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2/drivers/aio" ) func initTestEasyDriverWithStubbedAdaptor() (*EasyDriver, *gpioTestAdaptor) { const anglePerStep = 0.5 // use non int step angle to check int math a := newGpioTestAdaptor() d := NewEasyDriver(a, anglePerStep, "1") return d, a } func TestNewEasyDriver(t *testing.T) { // arrange const anglePerStep = 0.5 // use non int step angle to check int math a := newGpioTestAdaptor() // act d := NewEasyDriver(a, anglePerStep, "1") // assert assert.IsType(t, &EasyDriver{}, d) // assert: gpio.driver attributes require.NotNil(t, d.driver) assert.True(t, strings.HasPrefix(d.driverCfg.name, "EasyDriver")) assert.Equal(t, a, d.connection) require.NoError(t, d.afterStart()) require.NoError(t, d.beforeHalt()) assert.NotNil(t, d.Commander) assert.NotNil(t, d.mutex) // assert: driver specific attributes assert.Equal(t, "1", d.stepPin) assert.InDelta(t, float32(anglePerStep), d.anglePerStep, 0.0) assert.Equal(t, uint(14), d.speedRpm) assert.Equal(t, "forward", d.direction) assert.Equal(t, 0, d.stepNum) assert.False(t, d.disabled) assert.False(t, d.sleeping) assert.Nil(t, d.stopAsynchRunFunc) require.NotNil(t, d.easyCfg) assert.Empty(t, d.easyCfg.dirPin) assert.Empty(t, d.easyCfg.enPin) assert.Empty(t, d.easyCfg.sleepPin) } func TestNewEasyDriver_options(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithName() option, least one // option of this driver and one of another driver (which should lead to panic). Further tests for options can also // be done by call of "WithOption(val).apply(cfg)". // arrange const ( myName = "front wheel" dirPin = "2" ) panicFunc := func() { NewEasyDriver(newGpioTestAdaptor(), 0.1, "1", WithName("crazy"), aio.WithActuatorScaler(func(float64) int { return 0 })) } // act d := NewEasyDriver(newGpioTestAdaptor(), 0.2, "1", WithName(myName), WithEasyDirectionPin(dirPin)) // assert assert.Equal(t, dirPin, d.easyCfg.dirPin) assert.Equal(t, myName, d.Name()) assert.PanicsWithValue(t, "'scaler option for analog actuators' can not be applied on 'crazy', "+ "consider to use one of the options instead: WithEasyDirectionPin, WithEasyEnablePin, WithEasySleepPin", panicFunc) } func TestEasy_WithEasyEnablePin(t *testing.T) { // arrange const myEnablePin = "3" cfg := easyConfiguration{} // act WithEasyEnablePin(myEnablePin).apply(&cfg) // assert assert.Equal(t, myEnablePin, cfg.enPin) } func TestEasy_WithEasySleepPin(t *testing.T) { // arrange const mySleepPin = "4" cfg := easyConfiguration{} // act WithEasySleepPin(mySleepPin).apply(&cfg) // assert assert.Equal(t, mySleepPin, cfg.sleepPin) } func TestEasyMoveDeg_IsMoving(t *testing.T) { tests := map[string]struct { inputDeg int simulateDisabled bool simulateAlreadyRunning bool simulateWriteErr bool wantWrites int wantSteps int wantMoving bool wantErr string }{ "move_one": { inputDeg: 1, wantWrites: 4, wantSteps: 2, wantMoving: false, }, "move_more": { inputDeg: 20, wantWrites: 80, wantSteps: 40, wantMoving: false, }, "error_disabled": { simulateDisabled: true, wantMoving: false, wantErr: "is disabled", }, "error_already_running": { simulateAlreadyRunning: true, wantMoving: true, wantErr: "already running or moving", }, "error_write": { inputDeg: 1, simulateWriteErr: true, wantWrites: 0, wantMoving: false, wantErr: "write error", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, a := initTestEasyDriverWithStubbedAdaptor() defer func() { // for cleanup dangling channels if d.stopAsynchRunFunc != nil { err := d.stopAsynchRunFunc(true) require.NoError(t, err) } }() // arrange: different behavior d.disabled = tc.simulateDisabled if tc.simulateAlreadyRunning { d.stopAsynchRunFunc = func(bool) error { return nil } } // arrange: writes a.written = nil // reset writes of Start() a.simulateWriteError = tc.simulateWriteErr // act err := d.MoveDeg(tc.inputDeg) // assert if tc.wantErr != "" { require.ErrorContains(t, err, tc.wantErr) } else { require.NoError(t, err) } assert.Equal(t, tc.wantSteps, d.stepNum) assert.Len(t, a.written, tc.wantWrites) assert.Equal(t, tc.wantMoving, d.IsMoving()) }) } } func TestEasyRun_IsMoving(t *testing.T) { tests := map[string]struct { simulateDisabled bool simulateAlreadyRunning bool simulateWriteErr bool wantMoving bool wantErr string }{ "run": { wantMoving: true, }, "error_disabled": { simulateDisabled: true, wantMoving: false, wantErr: "is disabled", }, "write_error_skipped": { simulateWriteErr: true, wantMoving: true, }, "error_already_running": { simulateAlreadyRunning: true, wantMoving: true, wantErr: "already running or moving", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, a := initTestEasyDriverWithStubbedAdaptor() d.skipStepErrors = true d.disabled = tc.simulateDisabled if tc.simulateAlreadyRunning { d.stopAsynchRunFunc = func(bool) error { return nil } } simWriteErr := tc.simulateWriteErr // to prevent data race in write function (go-called) a.digitalWriteFunc = func(string, byte) error { if simWriteErr { simWriteErr = false // to prevent to much output return fmt.Errorf("write error") } return nil } // act err := d.Run() // assert if tc.wantErr != "" { require.ErrorContains(t, err, tc.wantErr) } else { require.NoError(t, err) } assert.Equal(t, tc.wantMoving, d.IsMoving()) }) } } func TestEasyStop_IsMoving(t *testing.T) { // arrange d, _ := initTestEasyDriverWithStubbedAdaptor() require.NoError(t, d.Run()) require.True(t, d.IsMoving()) // act err := d.Stop() // assert require.NoError(t, err) assert.False(t, d.IsMoving()) } func TestEasyDriverHalt_IsMoving(t *testing.T) { // arrange d, _ := initTestEasyDriverWithStubbedAdaptor() require.NoError(t, d.Run()) require.True(t, d.IsMoving()) // act err := d.Halt() // assert require.NoError(t, err) assert.False(t, d.IsMoving()) } func TestEasySetDirection(t *testing.T) { const anglePerStep = 0.5 // use non int step angle to check int math tests := map[string]struct { input string dirPin string simulateWriteErr bool wantVal string wantWritten byte wantErr string }{ "forward": { input: "forward", dirPin: "10", wantWritten: 0, wantVal: "forward", }, "backward": { input: "backward", dirPin: "11", wantWritten: 1, wantVal: "backward", }, "unknown": { input: "unknown", dirPin: "12", wantWritten: 0xFF, wantVal: "forward", wantErr: "invalid direction 'unknown'", }, "error_no_pin": { input: "forward", dirPin: "", wantWritten: 0xFF, wantVal: "forward", wantErr: "dirPin is not set", }, "error_write": { input: "backward", dirPin: "13", simulateWriteErr: true, wantWritten: 0xFF, wantVal: "forward", wantErr: "write error", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange a := newGpioTestAdaptor() d := NewEasyDriver(a, anglePerStep, "1", WithEasyDirectionPin(tc.dirPin)) a.written = nil // reset writes of Start() a.simulateWriteError = tc.simulateWriteErr require.Equal(t, "forward", d.direction) // act err := d.SetDirection(tc.input) // assert if tc.wantErr != "" { require.ErrorContains(t, err, tc.wantErr) } else { require.NoError(t, err) assert.Equal(t, tc.dirPin, a.written[0].pin) assert.Equal(t, tc.wantWritten, a.written[0].val) } assert.Equal(t, tc.wantVal, d.direction) }) } } func TestEasyMaxSpeed(t *testing.T) { const delayForMaxSpeed = 1428 * time.Microsecond // 1/700Hz tests := map[string]struct { anglePerStep float32 want uint }{ "maxspeed_for_20spr": { anglePerStep: 360.0 / 20.0, want: 2100, }, "maxspeed_for_36spr": { anglePerStep: 360.0 / 36.0, want: 1166, }, "maxspeed_for_50spr": { anglePerStep: 360.0 / 50.0, want: 840, }, "maxspeed_for_100spr": { anglePerStep: 360.0 / 100.0, want: 420, }, "maxspeed_for_400spr": { anglePerStep: 360.0 / 400.0, want: 105, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, _ := initTestEasyDriverWithStubbedAdaptor() d.anglePerStep = tc.anglePerStep d.stepsPerRev = 360.0 / tc.anglePerStep // act got := d.MaxSpeed() d.speedRpm = got got2 := d.getDelayPerStep() // assert assert.Equal(t, tc.want, got) assert.Equal(t, delayForMaxSpeed.Microseconds()/10, got2.Microseconds()/10) }) } } func TestEasySetSpeed(t *testing.T) { const ( anglePerStep = 10 maxRpm = 1166 ) tests := map[string]struct { input uint want uint wantErr string }{ "below_minimum": { input: 0, want: 0, wantErr: "RPM (0) cannot be a zero or negative value", }, "minimum": { input: 1, want: 1, }, "maximum": { input: maxRpm, want: maxRpm, }, "above_maximum": { input: maxRpm + 1, want: maxRpm, wantErr: "cannot be greater then maximal value 1166", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, _ := initTestEasyDriverWithStubbedAdaptor() d.speedRpm = 0 d.anglePerStep = anglePerStep d.stepsPerRev = 360.0 / anglePerStep // act err := d.SetSpeed(tc.input) // assert if tc.wantErr != "" { require.ErrorContains(t, err, tc.wantErr) } else { require.NoError(t, err) } assert.Equal(t, tc.want, d.speedRpm) }) } } func TestEasy_onePinStepping(t *testing.T) { tests := map[string]struct { countCallsForth int countCallsBack int simulateWriteErr bool wantSteps int wantWritten []gpioTestWritten wantErr string }{ "single": { countCallsForth: 1, wantSteps: 1, wantWritten: []gpioTestWritten{ {pin: "1", val: 0x00}, {pin: "1", val: 0x01}, }, }, "many": { countCallsForth: 4, wantSteps: 4, wantWritten: []gpioTestWritten{ {pin: "1", val: 0x0}, {pin: "1", val: 0x1}, {pin: "1", val: 0x0}, {pin: "1", val: 0x1}, {pin: "1", val: 0x0}, {pin: "1", val: 0x1}, {pin: "1", val: 0x0}, {pin: "1", val: 0x1}, }, }, "forth_and_back": { countCallsForth: 5, countCallsBack: 3, wantSteps: 2, wantWritten: []gpioTestWritten{ {pin: "1", val: 0x0}, {pin: "1", val: 0x1}, {pin: "1", val: 0x0}, {pin: "1", val: 0x1}, {pin: "1", val: 0x0}, {pin: "1", val: 0x1}, {pin: "1", val: 0x0}, {pin: "1", val: 0x1}, {pin: "1", val: 0x0}, {pin: "1", val: 0x1}, {pin: "1", val: 0x0}, {pin: "1", val: 0x1}, {pin: "1", val: 0x0}, {pin: "1", val: 0x1}, {pin: "1", val: 0x0}, {pin: "1", val: 0x1}, }, }, "reverse": { countCallsBack: 3, wantSteps: -3, wantWritten: []gpioTestWritten{ {pin: "1", val: 0x0}, {pin: "1", val: 0x1}, {pin: "1", val: 0x0}, {pin: "1", val: 0x1}, {pin: "1", val: 0x0}, {pin: "1", val: 0x1}, }, }, "error_write": { simulateWriteErr: true, countCallsBack: 2, wantErr: "write error", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, a := initTestEasyDriverWithStubbedAdaptor() a.written = nil // reset writes of Start() a.simulateWriteError = tc.simulateWriteErr var errs []string // act for i := 0; i < tc.countCallsForth; i++ { if err := d.onePinStepping(); err != nil { errs = append(errs, err.Error()) } } d.direction = "backward" for i := 0; i < tc.countCallsBack; i++ { if err := d.onePinStepping(); err != nil { errs = append(errs, err.Error()) } } // assert if tc.wantErr != "" { assert.Contains(t, strings.Join(errs, ","), tc.wantErr) } else { assert.Nil(t, errs) } assert.Equal(t, tc.wantSteps, d.stepNum) assert.Equal(t, tc.wantSteps, d.CurrentStep()) assert.Equal(t, tc.wantWritten, a.written) }) } } func TestEasyEnable_IsEnabled(t *testing.T) { const anglePerStep = 0.5 // use non int step angle to check int math tests := map[string]struct { enPin string simulateWriteErr bool wantWrites int wantEnabled bool wantErr string }{ "basic": { enPin: "10", wantWrites: 1, wantEnabled: true, }, "with_run": { enPin: "11", wantWrites: 1, wantEnabled: true, }, "error_no_pin": { enPin: "", wantWrites: 0, wantEnabled: true, // is enabled by default wantErr: "enPin is not set", }, "error_write": { enPin: "12", simulateWriteErr: true, wantWrites: 0, wantEnabled: false, wantErr: "write error", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange a := newGpioTestAdaptor() d := NewEasyDriver(a, anglePerStep, "1", WithEasyEnablePin(tc.enPin)) a.written = nil // reset writes of Start() a.simulateWriteError = tc.simulateWriteErr d.disabled = true require.False(t, d.IsEnabled()) // act err := d.Enable() // assert assert.Len(t, a.written, tc.wantWrites) if tc.wantErr != "" { require.ErrorContains(t, err, tc.wantErr) } else { require.NoError(t, err) assert.Equal(t, tc.enPin, a.written[0].pin) assert.Equal(t, byte(0), a.written[0].val) // enable pin is active low } assert.Equal(t, tc.wantEnabled, d.IsEnabled()) }) } } func TestEasyDisable_IsEnabled(t *testing.T) { const anglePerStep = 0.5 // use non int step angle to check int math tests := map[string]struct { enPin string runBefore bool simulateWriteErr bool wantWrites int wantEnabled bool wantErr string }{ "basic": { enPin: "10", wantWrites: 1, wantEnabled: false, }, "with_run": { enPin: "10", runBefore: true, wantWrites: 1, wantEnabled: false, }, "error_no_pin": { enPin: "", wantWrites: 0, wantEnabled: true, // is enabled by default wantErr: "enPin is not set", }, "error_write": { enPin: "12", simulateWriteErr: true, wantWrites: 1, wantEnabled: true, wantErr: "write error", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange a := newGpioTestAdaptor() d := NewEasyDriver(a, anglePerStep, "1", WithEasyEnablePin(tc.enPin)) var numCallsWrite int var writtenPin string writtenValue := byte(0xFF) a.digitalWriteFunc = func(pin string, val byte) error { if pin == d.stepPin { // we do not consider call of step() return nil } numCallsWrite++ writtenPin = pin writtenValue = val if tc.simulateWriteErr { return fmt.Errorf("write error") } return nil } if tc.runBefore { require.NoError(t, d.Run()) require.True(t, d.IsMoving()) time.Sleep(time.Millisecond) } d.disabled = false require.True(t, d.IsEnabled()) // act err := d.Disable() // assert if tc.wantErr != "" { require.ErrorContains(t, err, tc.wantErr) } else { require.NoError(t, err) assert.Equal(t, byte(1), writtenValue) // enable pin is active low } assert.Equal(t, tc.wantEnabled, d.IsEnabled()) assert.False(t, d.IsMoving()) assert.Equal(t, tc.wantWrites, numCallsWrite) assert.Equal(t, tc.enPin, writtenPin) }) } } func TestEasySleep_IsSleeping(t *testing.T) { const anglePerStep = 0.5 // use non int step angle to check int math tests := map[string]struct { sleepPin string runBefore bool simulateWriteErr bool wantWrites int wantSleep bool wantErr string }{ "basic": { sleepPin: "10", wantWrites: 1, wantSleep: true, }, "with_run": { sleepPin: "11", runBefore: true, wantWrites: 1, wantSleep: true, }, "error_no_pin": { sleepPin: "", wantSleep: false, wantWrites: 0, wantErr: "sleepPin is not set", }, "error_write": { sleepPin: "12", simulateWriteErr: true, wantWrites: 1, wantSleep: false, wantErr: "write error", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange a := newGpioTestAdaptor() d := NewEasyDriver(a, anglePerStep, "1", WithEasySleepPin(tc.sleepPin)) d.sleeping = false require.False(t, d.IsSleeping()) // arrange: writes var numCallsWrite int var writtenPin string writtenValue := byte(0xFF) a.digitalWriteFunc = func(pin string, val byte) error { if pin == d.stepPin { // we do not consider call of step() return nil } numCallsWrite++ writtenPin = pin writtenValue = val if tc.simulateWriteErr { return fmt.Errorf("write error") } return nil } if tc.runBefore { require.NoError(t, d.Run()) } // act err := d.Sleep() // assert if tc.wantErr != "" { require.ErrorContains(t, err, tc.wantErr) } else { require.NoError(t, err) assert.Equal(t, byte(0), writtenValue) // sleep pin is active low } assert.Equal(t, tc.wantSleep, d.IsSleeping()) assert.Equal(t, tc.wantWrites, numCallsWrite) assert.Equal(t, tc.sleepPin, writtenPin) }) } } func TestEasyWake_IsSleeping(t *testing.T) { const anglePerStep = 0.5 // use non int step angle to check int math tests := map[string]struct { sleepPin string simulateWriteErr bool wantWrites int wantSleep bool wantErr string }{ "basic": { sleepPin: "10", wantWrites: 1, wantSleep: false, }, "error_no_pin": { sleepPin: "", wantWrites: 0, wantSleep: true, wantErr: "sleepPin is not set", }, "error_write": { sleepPin: "12", simulateWriteErr: true, wantWrites: 1, wantSleep: true, wantErr: "write error", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange a := newGpioTestAdaptor() d := NewEasyDriver(a, anglePerStep, "1", WithEasySleepPin(tc.sleepPin)) d.sleeping = true require.True(t, d.IsSleeping()) // arrange: writes var numCallsWrite int var writtenPin string writtenValue := byte(0xFF) a.digitalWriteFunc = func(pin string, val byte) error { if pin == d.stepPin { // we do not consider call of step() return nil } numCallsWrite++ writtenPin = pin writtenValue = val if tc.simulateWriteErr { return fmt.Errorf("write error") } return nil } // act err := d.Wake() // assert if tc.wantErr != "" { require.ErrorContains(t, err, tc.wantErr) } else { require.NoError(t, err) assert.Equal(t, byte(1), writtenValue) // sleep pin is active low } assert.Equal(t, tc.wantSleep, d.IsSleeping()) assert.Equal(t, tc.wantWrites, numCallsWrite) assert.Equal(t, tc.sleepPin, writtenPin) }) } } ================================================ FILE: drivers/gpio/gpio_driver.go ================================================ package gpio import ( "errors" "fmt" "log" "sync" "gobot.io/x/gobot/v2" ) var ( // ErrServoWriteUnsupported is the error resulting when a driver attempts to use // hardware capabilities which a connection does not support ErrServoWriteUnsupported = errors.New("ServoWrite is not supported by this platform") // ErrPwmWriteUnsupported is the error resulting when a driver attempts to use // hardware capabilities which a connection does not support ErrPwmWriteUnsupported = errors.New("PwmWrite is not supported by this platform") // ErrDigitalWriteUnsupported is the error resulting when a driver attempts to use // hardware capabilities which a connection does not support ErrDigitalWriteUnsupported = errors.New("DigitalWrite is not supported by this platform") // ErrDigitalReadUnsupported is the error resulting when a driver attempts to use // hardware capabilities which a connection does not support ErrDigitalReadUnsupported = errors.New("DigitalRead is not supported by this platform") ) const ( // Error event Error = "error" // ButtonRelease event ButtonRelease = "release" // ButtonPush event ButtonPush = "push" // MotionDetected event MotionDetected = "motion-detected" // MotionStopped event MotionStopped = "motion-stopped" ) // PwmWriter interface represents an Adaptor which has Pwm capabilities type PwmWriter interface { PwmWrite(pin string, val byte) error } // ServoWriter interface represents an Adaptor which has Servo capabilities type ServoWriter interface { ServoWrite(pin string, val byte) error } // DigitalWriter interface represents an Adaptor which has DigitalWrite capabilities type DigitalWriter interface { DigitalWrite(pin string, val byte) error } // DigitalReader interface represents an Adaptor which has DigitalRead capabilities type DigitalReader interface { DigitalRead(pin string) (val int, err error) } // optionApplier needs to be implemented by each configurable option type type optionApplier interface { apply(cfg *configuration) } // configuration contains all changeable attributes of the driver. type configuration struct { name string pin string } // nameOption is the type for applying another name to the configuration type nameOption string // pinOption is the type for applying a pin to the configuration type pinOption string // Driver implements the interface gobot.Driver. type driver struct { gobot.Commander driverCfg *configuration connection gobot.Adaptor afterStart func() error beforeHalt func() error mutex *sync.Mutex // mutex often needed to ensure that write-read sequences are not interrupted } // newDriver creates a new generic and basic gpio gobot driver. // // Supported options: // // "WithName" // "withPin" func newDriver(a gobot.Adaptor, name string, opts ...interface{}) *driver { d := &driver{ driverCfg: &configuration{name: gobot.DefaultName(name)}, connection: a, afterStart: func() error { return nil }, beforeHalt: func() error { return nil }, Commander: gobot.NewCommander(), mutex: &sync.Mutex{}, } for _, opt := range opts { switch o := opt.(type) { case optionApplier: o.apply(d.driverCfg) default: panic(fmt.Sprintf("'%s' can not be applied on '%s'", opt, d.driverCfg.name)) } } return d } // WithName is used to replace the default name of the driver. func WithName(name string) optionApplier { return nameOption(name) } // withPin is used to add a pin to the driver. Only one pin can be linked. // This option is not available outside gpio package. func withPin(pin string) optionApplier { return pinOption(pin) } // Name returns the name of the gpio device. func (d *driver) Name() string { return d.driverCfg.name } // SetName sets the name of the gpio device. // Deprecated: Please use option [gpio.WithName] instead. func (d *driver) SetName(name string) { WithName(name).apply(d.driverCfg) } // Pin returns the pin associated with the driver. func (d *driver) Pin() string { return d.driverCfg.pin } // Connection returns the gobot connection of the gpio device. func (d *driver) Connection() gobot.Connection { if d.connection == nil { log.Printf("%s has no connection\n", d.driverCfg.name) return nil } if conn, ok := d.connection.(gobot.Connection); ok { return conn } log.Printf("%s has no gobot connection\n", d.driverCfg.name) return nil } // Start initializes the gpio device. func (d *driver) Start() error { d.mutex.Lock() defer d.mutex.Unlock() // currently there is nothing to do here for the driver return d.afterStart() } // Halt halts the gpio device. func (d *driver) Halt() error { d.mutex.Lock() defer d.mutex.Unlock() // currently there is nothing to do after halt for the driver return d.beforeHalt() } // digitalRead is a helper function with check that the connection implements DigitalReader func (d *driver) digitalRead(pin string) (int, error) { if d.connection == nil { return 0, fmt.Errorf("%s has no connection", d.driverCfg.name) } if reader, ok := d.connection.(DigitalReader); ok { return reader.DigitalRead(pin) } return 0, ErrDigitalReadUnsupported } // digitalWrite is a helper function with check that the connection implements DigitalWriter func (d *driver) digitalWrite(pin string, val byte) error { if d.connection == nil { return fmt.Errorf("%s has no connection", d.driverCfg.name) } if writer, ok := d.connection.(DigitalWriter); ok { return writer.DigitalWrite(pin, val) } return ErrDigitalWriteUnsupported } // pwmWrite is a helper function with check that the connection implements PwmWriter func (d *driver) pwmWrite(pin string, level byte) error { if d.connection == nil { return fmt.Errorf("%s has no connection", d.driverCfg.name) } if writer, ok := d.connection.(PwmWriter); ok { return writer.PwmWrite(pin, level) } return ErrPwmWriteUnsupported } // servoWrite is a helper function with check that the connection implements ServoWriter func (d *driver) servoWrite(pin string, level byte) error { if d.connection == nil { return fmt.Errorf("%s has no connection", d.driverCfg.name) } if writer, ok := d.connection.(ServoWriter); ok { return writer.ServoWrite(pin, level) } return ErrServoWriteUnsupported } func (o nameOption) String() string { return "name option for digital drivers" } func (o pinOption) String() string { return "pin option for digital drivers" } // apply change the name in the configuration. func (o nameOption) apply(c *configuration) { c.name = string(o) } // apply change the pins list of the configuration. func (o pinOption) apply(c *configuration) { c.pin = string(o) } ================================================ FILE: drivers/gpio/gpio_driver_test.go ================================================ package gpio import ( "fmt" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) var _ gobot.Driver = (*driver)(nil) func initTestDriverWithStubbedAdaptor() (*driver, *gpioTestAdaptor) { a := newGpioTestAdaptor() d := newDriver(a, "GPIO_BASIC") return d, a } func initTestDriver() *driver { d, _ := initTestDriverWithStubbedAdaptor() return d } func TestNewDriver(t *testing.T) { // arrange a := newGpioTestAdaptor() // act d := newDriver(a, "GPIO_BASIC") // assert assert.IsType(t, &driver{}, d) assert.Contains(t, d.driverCfg.name, "GPIO_BASIC") assert.Equal(t, a, d.connection) require.NoError(t, d.afterStart()) require.NoError(t, d.beforeHalt()) assert.NotNil(t, d.Commander) assert.NotNil(t, d.mutex) } func Test_applyWithName(t *testing.T) { // arrange const name = "mybot" cfg := configuration{name: "oldname"} // act WithName(name).apply(&cfg) // assert assert.Equal(t, name, cfg.name) } func Test_applywithPin(t *testing.T) { // arrange const pin = "36" cfg := configuration{pin: "oldpin"} // act withPin(pin).apply(&cfg) // assert assert.Equal(t, pin, cfg.pin) } func TestConnection(t *testing.T) { // arrange d, a := initTestDriverWithStubbedAdaptor() // act, assert assert.Equal(t, a, d.Connection()) } func TestStart(t *testing.T) { // arrange d := initTestDriver() // act, assert require.NoError(t, d.Start()) // arrange after start function d.afterStart = func() error { return fmt.Errorf("after start error") } // act, assert require.EqualError(t, d.Start(), "after start error") } func TestHalt(t *testing.T) { // arrange d := initTestDriver() // act, assert require.NoError(t, d.Halt()) // arrange after start function d.beforeHalt = func() error { return fmt.Errorf("before halt error") } // act, assert require.EqualError(t, d.Halt(), "before halt error") } ================================================ FILE: drivers/gpio/grove_drivers.go ================================================ package gpio // GroveRelayDriver represents a Relay with a Grove connector type GroveRelayDriver struct { *RelayDriver } // NewGroveRelayDriver return a new GroveRelayDriver given a DigitalWriter and pin. // // Supported options: // // "WithName" // // Adds the following API Commands: // // "Toggle" - See RelayDriver.Toggle // "On" - See RelayDriver.On // "Off" - See RelayDriver.Off // // Deprecated: Please use [gpio.NewRelayDriver] instead. Development will be discontinued. func NewGroveRelayDriver(a DigitalWriter, pin string) *GroveRelayDriver { return &GroveRelayDriver{ RelayDriver: NewRelayDriver(a, pin), } } // GroveLedDriver represents an LED with a Grove connector type GroveLedDriver struct { *LedDriver } // NewGroveLedDriver return a new driver for Grove Led given a DigitalWriter and pin. // // Supported options: // // "WithName" // // Adds the following API Commands: // // "Brightness" - See LedDriver.Brightness // "Toggle" - See LedDriver.Toggle // "On" - See LedDriver.On // "Off" - See LedDriver.Off // // Deprecated: Please use [gpio.NewLedDriver] instead. Development will be discontinued. func NewGroveLedDriver(a DigitalWriter, pin string) *GroveLedDriver { return &GroveLedDriver{ LedDriver: NewLedDriver(a, pin), } } // GroveBuzzerDriver represents a buzzer with a Grove connector type GroveBuzzerDriver struct { *BuzzerDriver } // NewGroveBuzzerDriver return a new driver for Grove buzzer given a DigitalWriter and pin. // // Supported options: // // "WithName" // // Deprecated: Please use [gpio.NewBuzzerDriver] instead. Development will be discontinued. func NewGroveBuzzerDriver(a DigitalWriter, pin string, opts ...interface{}) *GroveBuzzerDriver { return &GroveBuzzerDriver{ BuzzerDriver: NewBuzzerDriver(a, pin, opts...), } } // GroveButtonDriver represents a button sensor with a Grove connector type GroveButtonDriver struct { *ButtonDriver } // NewGroveButtonDriver returns a new driver for Grove button with a polling interval of 10 milliseconds given // a DigitalReader and pin. // // Supported options: // // "WithName" // "WithButtonPollInterval" // // Deprecated: Please use [gpio.NewButtonDriver] instead. Development will be discontinued. func NewGroveButtonDriver(a DigitalReader, pin string, opts ...interface{}) *GroveButtonDriver { return &GroveButtonDriver{ ButtonDriver: NewButtonDriver(a, pin, opts...), } } // GroveTouchDriver represents a touch button sensor // with a Grove connector type GroveTouchDriver struct { *ButtonDriver } // NewGroveTouchDriver returns a new driver for Grove touch sensor with a polling interval of 10 milliseconds given // a DigitalReader and pin. // // Supported options: // // "WithName" // "WithButtonPollInterval" // // Deprecated: Please use [gpio.NewButtonDriver] instead. Development will be discontinued. func NewGroveTouchDriver(a DigitalReader, pin string, opts ...interface{}) *GroveTouchDriver { return &GroveTouchDriver{ ButtonDriver: NewButtonDriver(a, pin, opts...), } } // GroveMagneticSwitchDriver represent a magnetic switch sensor with a Grove connector type GroveMagneticSwitchDriver struct { *ButtonDriver } // NewGroveMagneticSwitchDriver returns a new driver for Grove magnetic switch sensor with a polling interval of // 10 milliseconds given a DigitalReader, name and pin. // // Supported options: // // "WithName" // "WithButtonPollInterval" // // Deprecated: Please use [gpio.NewButtonDriver] instead. Development will be discontinued. func NewGroveMagneticSwitchDriver(a DigitalReader, pin string, opts ...interface{}) *GroveMagneticSwitchDriver { return &GroveMagneticSwitchDriver{ ButtonDriver: NewButtonDriver(a, pin, opts...), } } ================================================ FILE: drivers/gpio/grove_drivers_test.go ================================================ //nolint:forcetypeassert // ok here package gpio import ( "errors" "reflect" "sync/atomic" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) type DriverAndPinner interface { gobot.Driver gobot.Pinner } type DriverAndEventer interface { gobot.Driver gobot.Eventer } func TestDriverDefaults(t *testing.T) { a := newGpioTestAdaptor() pin := "456" drivers := []DriverAndPinner{ NewGroveTouchDriver(a, pin), NewGroveButtonDriver(a, pin), NewGroveBuzzerDriver(a, pin), NewGroveLedDriver(a, pin), NewGroveRelayDriver(a, pin), NewGroveMagneticSwitchDriver(a, pin), } for _, driver := range drivers { assert.Equal(t, a, driver.Connection()) assert.Equal(t, pin, driver.Pin()) } } func TestDigitalDriverHalt(t *testing.T) { a := newGpioTestAdaptor() pin := "456" drivers := []DriverAndEventer{ NewGroveTouchDriver(a, pin), NewGroveButtonDriver(a, pin), NewGroveMagneticSwitchDriver(a, pin), } for _, driver := range drivers { var callCount int32 a.digitalReadFunc = func(string) (int, error) { atomic.AddInt32(&callCount, 1) return 42, nil } // Start the driver and allow for multiple digital reads _ = driver.Start() time.Sleep(20 * time.Millisecond) _ = driver.Halt() lastCallCount := atomic.LoadInt32(&callCount) // If driver was not halted, digital reads would still continue time.Sleep(20 * time.Millisecond) // note: if a reading is already in progress, it will be finished before halt have an impact if atomic.LoadInt32(&callCount) > lastCallCount+1 { require.Fail(t, "DigitalRead was called more than once after driver was halted") } } } func TestDriverPublishesError(t *testing.T) { a := newGpioTestAdaptor() pin := "456" drivers := []DriverAndEventer{ NewGroveTouchDriver(a, pin), NewGroveButtonDriver(a, pin), NewGroveMagneticSwitchDriver(a, pin), } for _, driver := range drivers { sem := make(chan struct{}, 1) // send error returnErr := func(string) (int, error) { return 0, errors.New("read error") } a.digitalReadFunc = returnErr require.NoError(t, driver.Start()) // expect error _ = driver.Once(driver.Event(Error), func(data interface{}) { assert.Equal(t, "read error", data.(error).Error()) close(sem) }) select { case <-sem: case <-time.After(time.Second): require.Fail(t, getType(driver)+" Event \"Error\" was not published") } // Cleanup _ = driver.Halt() } } func getType(driver interface{}) string { d := reflect.TypeOf(driver) if d.Kind() == reflect.Ptr { return d.Elem().Name() } return d.Name() } ================================================ FILE: drivers/gpio/hcsr04_driver.go ================================================ package gpio import ( "fmt" "sync" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/system" ) const ( hcsr04SoundSpeed = 343 // in [m/s] // the device can measure 2 cm .. 4 m, this means sweep distances between 4 cm and 8 m // this cause pulse duration between 0.12 ms and 24 ms (at 34.3 cm/ms, ~0.03 ms/cm, ~3 ms/m) // so we use 60 ms as a limit for timeout and 100 ms for duration between 2 consecutive measurements hcsr04StartTransmitTimeout time.Duration = 100 * time.Millisecond // unfortunately takes sometimes longer than 60 ms hcsr04ReceiveTimeout time.Duration = 60 * time.Millisecond hcsr04EmitTriggerDuration time.Duration = 10 * time.Microsecond // according to specification hcsr04MonitorUpdate time.Duration = 200 * time.Millisecond // the resolution of the device is ~3 mm, which relates to 10 us (343 mm/ms = 0.343 mm/us) // the poll interval increases the reading interval to this value and adds around 3 mm inaccuracy // it takes only an effect for fast systems, because reading inputs is typically much slower, e.g. 30-50 us on raspi // so, using the internal edge detection with "cdev" is more precise hcsr04PollInputIntervall time.Duration = 10 * time.Microsecond ) // hcsr04OptionApplier needs to be implemented by each configurable option type type hcsr04OptionApplier interface { apply(cfg *hcsr04Configuration) } // hcsr04Configuration contains all changeable attributes of the driver. type hcsr04Configuration struct { useEdgePolling bool } // hcsr04UseEdgePollingOption is the type for applying to use discrete edge polling instead pin edge detection // by "cdev" from the go-gpiocdev package. type hcsr04UseEdgePollingOption bool // HCSR04Driver is a driver for ultrasonic range measurement. type HCSR04Driver struct { *driver hcsr04Cfg *hcsr04Configuration triggerPinID string echoPinID string measureMutex *sync.Mutex // to ensure that only one measurement is done at a time triggerPin gobot.DigitalPinner echoPin gobot.DigitalPinner lastMeasureMicroSec int64 // ~120 .. 24000 us distanceMonitorStopChan chan struct{} distanceMonitorStopWaitGroup *sync.WaitGroup delayMicroSecChan chan int64 // channel for event handler return value pollQuitChan chan struct{} // channel for quit the continuous polling } // NewHCSR04Driver creates a new instance of the driver for HC-SR04 (same as SEN-US01). // // Datasheet: https://www.makershop.de/download/HCSR04-datasheet-version-1.pdf // // Supported options: // // "WithName" func NewHCSR04Driver(a gobot.Adaptor, triggerPinID, echoPinID string, opts ...interface{}) *HCSR04Driver { d := HCSR04Driver{ driver: newDriver(a, "HCSR04"), hcsr04Cfg: &hcsr04Configuration{}, triggerPinID: triggerPinID, echoPinID: echoPinID, measureMutex: &sync.Mutex{}, } for _, opt := range opts { switch o := opt.(type) { case optionApplier: o.apply(d.driverCfg) case hcsr04OptionApplier: o.apply(d.hcsr04Cfg) default: panic(fmt.Sprintf("'%s' can not be applied on '%s'", opt, d.driverCfg.name)) } } d.afterStart = func() error { tpin, err := a.(gobot.DigitalPinnerProvider).DigitalPin(triggerPinID) //nolint:forcetypeassert // ok here if err != nil { return fmt.Errorf("error on get trigger pin: %v", err) } if err := tpin.ApplyOptions(system.WithPinDirectionOutput(0)); err != nil { return fmt.Errorf("error on apply output for trigger pin: %v", err) } d.triggerPin = tpin // pins are inputs by default epin, err := a.(gobot.DigitalPinnerProvider).DigitalPin(echoPinID) //nolint:forcetypeassert // ok here if err != nil { return fmt.Errorf("error on get echo pin: %v", err) } epinOptions := []func(gobot.DigitalPinOptioner) bool{system.WithPinEventOnBothEdges(d.createEventHandler())} if d.hcsr04Cfg.useEdgePolling { d.pollQuitChan = make(chan struct{}) epinOptions = append(epinOptions, system.WithPinPollForEdgeDetection(hcsr04PollInputIntervall, d.pollQuitChan)) } if err := epin.ApplyOptions(epinOptions...); err != nil { return fmt.Errorf("error on apply options for echo pin: %v", err) } d.echoPin = epin d.delayMicroSecChan = make(chan int64) return nil } d.beforeHalt = func() error { if d.hcsr04Cfg.useEdgePolling { close(d.pollQuitChan) } if err := d.stopDistanceMonitor(); err != nil { fmt.Printf("no need to stop distance monitoring: %v\n", err) } // note: Unexport() of all pins will be done on adaptor.Finalize() close(d.delayMicroSecChan) return nil } return &d } // WithHCSR04UseEdgePolling use discrete edge polling instead pin edge detection by "cdev" from the go-gpiocdev package. func WithHCSR04UseEdgePolling() hcsr04OptionApplier { return hcsr04UseEdgePollingOption(true) } // MeasureDistance retrieves the distance in front of sensor in meters and returns the measure. It is not designed // to work in a fast loop! For this specific usage, use StartDistanceMonitor() associated with Distance() instead. func (d *HCSR04Driver) MeasureDistance() (float64, error) { err := d.measureDistance() if err != nil { return 0, err } return d.Distance(), nil } // Distance returns the last distance measured in meter, it does not trigger a distance measurement func (d *HCSR04Driver) Distance() float64 { distMm := d.lastMeasureMicroSec * hcsr04SoundSpeed / 1000 / 2 return float64(distMm) / 1000.0 } // StartDistanceMonitor starts continuous measurement. The current value can be read by Distance() func (d *HCSR04Driver) StartDistanceMonitor() error { // ensure that start and stop can not interfere d.mutex.Lock() defer d.mutex.Unlock() if d.distanceMonitorStopChan != nil { return fmt.Errorf("distance monitor already started for '%s'", d.driverCfg.name) } d.distanceMonitorStopChan = make(chan struct{}) d.distanceMonitorStopWaitGroup = &sync.WaitGroup{} d.distanceMonitorStopWaitGroup.Add(1) go func(name string) { defer d.distanceMonitorStopWaitGroup.Done() for { select { case <-d.distanceMonitorStopChan: d.distanceMonitorStopChan = nil return default: if err := d.measureDistance(); err != nil { fmt.Printf("continuous measure distance skipped for '%s': %v\n", name, err) } time.Sleep(hcsr04MonitorUpdate) } } }(d.driverCfg.name) return nil } // StopDistanceMonitor stop the monitor process func (d *HCSR04Driver) StopDistanceMonitor() error { // ensure that start and stop can not interfere d.mutex.Lock() defer d.mutex.Unlock() return d.stopDistanceMonitor() } func (d *HCSR04Driver) createEventHandler() func(int, time.Duration, string, uint32, uint32) { var startTimestamp time.Duration return func(offset int, t time.Duration, et string, sn uint32, lsn uint32) { switch et { case system.DigitalPinEventRisingEdge: startTimestamp = t case system.DigitalPinEventFallingEdge: // unfortunately there is an additional falling edge at each start trigger, so we need to filter this // we use the start duration value for filtering if startTimestamp == 0 { return } d.delayMicroSecChan <- (t - startTimestamp).Microseconds() startTimestamp = 0 } } } func (d *HCSR04Driver) stopDistanceMonitor() error { if d.distanceMonitorStopChan == nil { return fmt.Errorf("distance monitor is not yet started for '%s'", d.driverCfg.name) } d.distanceMonitorStopChan <- struct{}{} d.distanceMonitorStopWaitGroup.Wait() return nil } func (d *HCSR04Driver) measureDistance() error { d.measureMutex.Lock() defer d.measureMutex.Unlock() if err := d.emitTrigger(); err != nil { return err } // stop the loop if the measure is done or the timeout is elapsed timeout := hcsr04StartTransmitTimeout + hcsr04ReceiveTimeout select { case <-time.After(timeout): return fmt.Errorf("timeout %s reached while waiting for value with echo pin %s", timeout, d.echoPinID) case d.lastMeasureMicroSec = <-d.delayMicroSecChan: } return nil } func (d *HCSR04Driver) emitTrigger() error { if err := d.triggerPin.Write(1); err != nil { return err } time.Sleep(hcsr04EmitTriggerDuration) return d.triggerPin.Write(0) } func (o hcsr04UseEdgePollingOption) String() string { return "hcsr04 use edge polling option" } func (o hcsr04UseEdgePollingOption) apply(cfg *hcsr04Configuration) { cfg.useEdgePolling = bool(o) } ================================================ FILE: drivers/gpio/hcsr04_driver_test.go ================================================ package gpio import ( "errors" "fmt" "strings" "sync" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2/drivers/aio" "gobot.io/x/gobot/v2/system" ) func initTestHCSR04DriverWithStubbedAdaptor(triggerPinID string, echoPinID string) (*HCSR04Driver, *digitalPinMock) { a := newGpioTestAdaptor() tpin := a.addDigitalPin(triggerPinID) _ = a.addDigitalPin(echoPinID) d := NewHCSR04Driver(a, triggerPinID, echoPinID) if err := d.Start(); err != nil { panic(err) } return d, tpin } func TestNewHCSR04Driver(t *testing.T) { // arrange const ( triggerPinID = "3" echoPinID = "4" ) a := newGpioTestAdaptor() tpin := a.addDigitalPin(triggerPinID) epin := a.addDigitalPin(echoPinID) // act d := NewHCSR04Driver(a, triggerPinID, echoPinID) // assert assert.IsType(t, &HCSR04Driver{}, d) // assert: gpio.driver attributes assert.NotNil(t, d.driver) assert.True(t, strings.HasPrefix(d.driverCfg.name, "HCSR04")) assert.Equal(t, a, d.connection) require.NoError(t, d.afterStart()) require.NoError(t, d.beforeHalt()) assert.NotNil(t, d.Commander) assert.NotNil(t, d.mutex) // assert: driver specific attributes assert.False(t, d.hcsr04Cfg.useEdgePolling) assert.Equal(t, triggerPinID, d.triggerPinID) assert.Equal(t, echoPinID, d.echoPinID) assert.NotNil(t, d.measureMutex) assert.Equal(t, tpin, d.triggerPin) assert.Equal(t, epin, d.echoPin) } func TestNewHCSR04Driver_options(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithName() option, least one // option of this driver and one of another driver (which should lead to panic). Further tests for options can also // be done by call of "WithOption(val).apply(cfg)". // arrange const ( myName = "count up" cycReadDur = 30 * time.Millisecond ) panicFunc := func() { NewHCSR04Driver(newGpioTestAdaptor(), "1", "2", WithName("crazy"), aio.WithActuatorScaler(func(float64) int { return 0 })) } // act d := NewHCSR04Driver(newGpioTestAdaptor(), "1", "2", WithName(myName), WithHCSR04UseEdgePolling()) // assert assert.True(t, d.hcsr04Cfg.useEdgePolling) assert.Equal(t, myName, d.Name()) assert.PanicsWithValue(t, "'scaler option for analog actuators' can not be applied on 'crazy'", panicFunc) } func TestHCSR04MeasureDistance(t *testing.T) { tests := map[string]struct { measureMicroSec int64 simulateWriteErr string wantCallsWrite int wantVal float64 wantErr string }{ "measure_ok": { measureMicroSec: 5831, wantCallsWrite: 2, wantVal: 1.0, }, "error_timeout": { measureMicroSec: 170000, // > 160 ms wantCallsWrite: 2, wantErr: "timeout 160ms reached", }, "error_write": { measureMicroSec: 5831, simulateWriteErr: "write error", wantCallsWrite: 1, wantErr: "write error", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, tpin := initTestHCSR04DriverWithStubbedAdaptor("3", "4") // arrange sensor and event handler simulation waitForTriggerChan := make(chan struct{}) loopWg := sync.WaitGroup{} defer func() { close(waitForTriggerChan) loopWg.Wait() }() loopWg.Add(1) go func() { <-waitForTriggerChan m := tc.measureMicroSec // to prevent data race together with wait group loopWg.Done() time.Sleep(time.Duration(m) * time.Microsecond) d.delayMicroSecChan <- m }() // arrange writes numCallsWrite := 0 var oldVal int tpin.writeFunc = func(val int) error { numCallsWrite++ if val == 0 && oldVal == 1 { // falling edge detected waitForTriggerChan <- struct{}{} } oldVal = val var err error if tc.simulateWriteErr != "" { err = errors.New(tc.simulateWriteErr) } return err } // act got, err := d.MeasureDistance() // assert assert.Equal(t, tc.wantCallsWrite, numCallsWrite) if tc.wantErr != "" { require.ErrorContains(t, err, tc.wantErr) } else { require.NoError(t, err) } assert.InDelta(t, tc.wantVal, got, 0.0) }) } } func TestHCSR04Distance(t *testing.T) { tests := map[string]struct { measureMicroSec int64 simulateWriteErr string wantVal float64 wantErr string }{ "distance_0mm": { measureMicroSec: 0, // no validity test yet wantVal: 0.0, }, "distance_2cm": { measureMicroSec: 117, // 117us ~ 0.12ms => ~2cm wantVal: 0.02, }, "distance_4m": { measureMicroSec: 23324, // 23324us ~ 24ms => ~4m wantVal: 4.0, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d := HCSR04Driver{lastMeasureMicroSec: tc.measureMicroSec} // act got := d.Distance() // assert assert.InDelta(t, tc.wantVal, got, 0.0) }) } } func TestHCSR04StartDistanceMonitor(t *testing.T) { tests := map[string]struct { simulateIsStarted bool simulateWriteErr bool wantErr string }{ "start_ok": {}, "start_ok_measure_error": { simulateWriteErr: true, }, "error_already_started": { simulateIsStarted: true, wantErr: "already started for 'HCSR04-", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, tpin := initTestHCSR04DriverWithStubbedAdaptor("3", "4") defer func() { if d.distanceMonitorStopChan != nil { close(d.distanceMonitorStopChan) } if d.distanceMonitorStopWaitGroup != nil { d.distanceMonitorStopWaitGroup.Wait() } }() if tc.simulateIsStarted { d.distanceMonitorStopChan = make(chan struct{}) } tpin.writeFunc = func(val int) error { if tc.simulateWriteErr { return fmt.Errorf("write error") } return nil } // act err := d.StartDistanceMonitor() time.Sleep(1 * time.Millisecond) // < 160 ms // assert if tc.wantErr != "" { require.ErrorContains(t, err, tc.wantErr) } else { require.NoError(t, err) assert.NotNil(t, d.distanceMonitorStopChan) assert.NotNil(t, d.distanceMonitorStopWaitGroup) } }) } } func TestHCSR04StopDistanceMonitor(t *testing.T) { tests := map[string]struct { start bool wantErr string }{ "stop_ok": { start: true, }, "error_not_started": { wantErr: "not yet started for 'HCSR04-", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, _ := initTestHCSR04DriverWithStubbedAdaptor("3", "4") defer func() { if d.distanceMonitorStopChan != nil { close(d.distanceMonitorStopChan) } if d.distanceMonitorStopWaitGroup != nil { d.distanceMonitorStopWaitGroup.Wait() } }() if tc.start { err := d.StartDistanceMonitor() require.NoError(t, err) } // act err := d.StopDistanceMonitor() time.Sleep(1 * time.Millisecond) // < 160 ms // assert if tc.wantErr != "" { require.ErrorContains(t, err, tc.wantErr) } else { require.NoError(t, err) assert.Nil(t, d.distanceMonitorStopChan) } }) } } func TestHCSR04_createEventHandler(t *testing.T) { type eventCall struct { timeStamp time.Duration eventType string } tests := map[string]struct { calls []eventCall wants []int64 }{ "only_rising": { calls: []eventCall{ {timeStamp: 1 * time.Microsecond, eventType: system.DigitalPinEventRisingEdge}, {timeStamp: 2 * time.Microsecond, eventType: system.DigitalPinEventRisingEdge}, }, }, "only_falling": { calls: []eventCall{ {timeStamp: 2 * time.Microsecond, eventType: system.DigitalPinEventFallingEdge}, {timeStamp: 3 * time.Microsecond, eventType: system.DigitalPinEventFallingEdge}, }, }, "event_normal": { calls: []eventCall{ {timeStamp: 1 * time.Microsecond, eventType: system.DigitalPinEventRisingEdge}, {timeStamp: 10 * time.Microsecond, eventType: system.DigitalPinEventFallingEdge}, }, wants: []int64{9}, }, "event_falling_before": { calls: []eventCall{ {timeStamp: 1 * time.Microsecond, eventType: system.DigitalPinEventFallingEdge}, {timeStamp: 2 * time.Microsecond, eventType: system.DigitalPinEventRisingEdge}, {timeStamp: 10 * time.Microsecond, eventType: system.DigitalPinEventFallingEdge}, }, wants: []int64{8}, }, "event_falling_after": { calls: []eventCall{ {timeStamp: 1 * time.Microsecond, eventType: system.DigitalPinEventRisingEdge}, {timeStamp: 10 * time.Microsecond, eventType: system.DigitalPinEventFallingEdge}, {timeStamp: 12 * time.Microsecond, eventType: system.DigitalPinEventFallingEdge}, }, wants: []int64{9}, }, "event_rising_before": { calls: []eventCall{ {timeStamp: 1 * time.Microsecond, eventType: system.DigitalPinEventRisingEdge}, {timeStamp: 5 * time.Microsecond, eventType: system.DigitalPinEventRisingEdge}, {timeStamp: 10 * time.Microsecond, eventType: system.DigitalPinEventFallingEdge}, }, wants: []int64{5}, }, "event_rising_after": { calls: []eventCall{ {timeStamp: 1 * time.Microsecond, eventType: system.DigitalPinEventRisingEdge}, {timeStamp: 10 * time.Microsecond, eventType: system.DigitalPinEventFallingEdge}, {timeStamp: 12 * time.Microsecond, eventType: system.DigitalPinEventRisingEdge}, }, wants: []int64{9}, }, "event_multiple": { calls: []eventCall{ {timeStamp: 1 * time.Microsecond, eventType: system.DigitalPinEventRisingEdge}, {timeStamp: 10 * time.Microsecond, eventType: system.DigitalPinEventFallingEdge}, {timeStamp: 11 * time.Microsecond, eventType: system.DigitalPinEventRisingEdge}, {timeStamp: 13 * time.Microsecond, eventType: system.DigitalPinEventFallingEdge}, }, wants: []int64{9, 2}, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d := HCSR04Driver{delayMicroSecChan: make(chan int64, len(tc.wants))} // act eh := d.createEventHandler() for _, call := range tc.calls { eh(0, call.timeStamp, call.eventType, 0, 0) } // assert for _, want := range tc.wants { got := <-d.delayMicroSecChan assert.Equal(t, want, got) } }) } } ================================================ FILE: drivers/gpio/hd44780_driver.go ================================================ package gpio import ( "errors" "fmt" "time" "gobot.io/x/gobot/v2" ) // Commands for the driver const ( HD44780_CLEARDISPLAY = 0x01 HD44780_RETURNHOME = 0x02 HD44780_ENTRYMODESET = 0x04 HD44780_DISPLAYCONTROL = 0x08 HD44780_CURSORSHIFT = 0x10 HD44780_FUNCTIONSET = 0x20 HD44780_SETCGRAMADDR = 0x40 HD44780_SETDDRAMADDR = 0x80 HD44780_ENTRYRIGHT = 0x00 HD44780_ENTRYLEFT = 0x02 HD44780_ENTRYSHIFTINCREMENT = 0x01 HD44780_ENTRYSHIFTDECREMENT = 0x00 HD44780_DISPLAYON = 0x04 HD44780_DISPLAYOFF = 0x00 HD44780_CURSORON = 0x02 HD44780_CURSOROFF = 0x00 HD44780_BLINKON = 0x01 HD44780_BLINKOFF = 0x00 HD44780_DISPLAYMOVE = 0x08 HD44780_CURSORMOVE = 0x00 HD44780_MOVERIGHT = 0x04 HD44780_MOVELEFT = 0x00 HD44780_1LINE = 0x00 HD44780_2LINE = 0x08 HD44780_5x8DOTS = 0x00 HD44780_5x10DOTS = 0x04 HD44780_4BITBUS = 0x00 HD44780_8BITBUS = 0x10 ) // Some useful constants for the driver const ( HD44780_2NDLINEOFFSET = 0x40 ) // HD44780BusMode is the data bus mode type HD44780BusMode int // Bus modes of the driver const ( HD44780_4BITMODE HD44780BusMode = iota + 1 HD44780_8BITMODE ) // HD44780DataPin are the data bit pins type HD44780DataPin struct { D0 string // not used if 4Bit mode D1 string // not used if 4Bit mode D2 string // not used if 4Bit mode D3 string // not used if 4Bit mode D4 string D5 string D6 string D7 string } // hd44780OptionApplier needs to be implemented by each configurable option type type hd44780OptionApplier interface { apply(cfg *hd44780Configuration) } // hd44780Configuration contains all changeable attributes of the driver type hd44780Configuration struct { pinRW string } // hd44780PinRWOption is the type for applying a R/W pin to the configuration type hd44780PinRWOption string // HD44780Driver is the gobot driver for the HD44780 LCD controller // Datasheet: https://www.sparkfun.com/datasheets/LCD/HD44780.pdf type HD44780Driver struct { *driver hd44780Cfg *hd44780Configuration cols int rows int rowOffsets [4]int busMode HD44780BusMode pinRS *DirectPinDriver pinEN *DirectPinDriver pinRW *DirectPinDriver pinDataBits []*DirectPinDriver displayCtrl int displayFunc int displayMode int } // NewHD44780Driver return a new HD44780Driver // a: gobot.Connection // cols: lcd columns // rows: lcd rows // busMode: 4Bit or 8Bit // pinRS: register select pin // pinEN: clock enable pin // pinDataBits: databit pins // // Supported options: // // "WithName" func NewHD44780Driver( a gobot.Connection, cols int, rows int, busMode HD44780BusMode, pinRS string, pinEN string, pinDataBits HD44780DataPin, opts ...interface{}, ) *HD44780Driver { d := &HD44780Driver{ driver: newDriver(a, "HD44780"), hd44780Cfg: &hd44780Configuration{}, cols: cols, rows: rows, busMode: busMode, pinRS: NewDirectPinDriver(a, pinRS), pinEN: NewDirectPinDriver(a, pinEN), } d.afterStart = d.initialize for _, opt := range opts { switch o := opt.(type) { case optionApplier: o.apply(d.driverCfg) case hd44780OptionApplier: o.apply(d.hd44780Cfg) default: panic(fmt.Sprintf("'%s' can not be applied on '%s'", opt, d.driverCfg.name)) } } if d.busMode == HD44780_4BITMODE { d.pinDataBits = make([]*DirectPinDriver, 4) d.pinDataBits[0] = NewDirectPinDriver(a, pinDataBits.D4) d.pinDataBits[1] = NewDirectPinDriver(a, pinDataBits.D5) d.pinDataBits[2] = NewDirectPinDriver(a, pinDataBits.D6) d.pinDataBits[3] = NewDirectPinDriver(a, pinDataBits.D7) } else { d.pinDataBits = make([]*DirectPinDriver, 8) d.pinDataBits[0] = NewDirectPinDriver(a, pinDataBits.D0) d.pinDataBits[1] = NewDirectPinDriver(a, pinDataBits.D1) d.pinDataBits[2] = NewDirectPinDriver(a, pinDataBits.D2) d.pinDataBits[3] = NewDirectPinDriver(a, pinDataBits.D3) d.pinDataBits[4] = NewDirectPinDriver(a, pinDataBits.D4) d.pinDataBits[5] = NewDirectPinDriver(a, pinDataBits.D5) d.pinDataBits[6] = NewDirectPinDriver(a, pinDataBits.D6) d.pinDataBits[7] = NewDirectPinDriver(a, pinDataBits.D7) } if d.hd44780Cfg.pinRW != "" { d.pinRW = NewDirectPinDriver(d.connection, d.hd44780Cfg.pinRW) } d.rowOffsets[0] = 0x00 d.rowOffsets[1] = HD44780_2NDLINEOFFSET d.rowOffsets[2] = 0x00 + cols d.rowOffsets[3] = HD44780_2NDLINEOFFSET + cols /* TODO : Add commands */ return d } // WithHD44780RWPin sets the RW pin for next initializing. func WithHD44780RWPin(pin string) hd44780OptionApplier { return hd44780PinRWOption(pin) } // initialize initializes the HD44780 LCD controller // refer to page 45/46 of Hitachi HD44780 datasheet func (d *HD44780Driver) initialize() error { for _, bitPin := range d.pinDataBits { if bitPin.Pin() == "" { return errors.New("initialization error") } } time.Sleep(50 * time.Millisecond) if err := d.activateWriteMode(); err != nil { return err } // for initialization refer to documentation, page 45 and 46 if d.busMode == HD44780_4BITMODE { if err := d.writeDataPins(0x03); err != nil { return err } time.Sleep(5 * time.Millisecond) if err := d.writeDataPins(0x03); err != nil { return err } time.Sleep(100 * time.Microsecond) if err := d.writeDataPins(0x03); err != nil { return err } // no additional delay is necessary now if err := d.writeDataPins(0x02); err != nil { return err } } else { if err := d.sendCommand(0x30); err != nil { return err } time.Sleep(5 * time.Millisecond) if err := d.sendCommand(0x30); err != nil { return err } time.Sleep(100 * time.Microsecond) if err := d.sendCommand(0x30); err != nil { return err } // no additional delay is necessary now } if d.busMode == HD44780_4BITMODE { d.displayFunc |= HD44780_4BITBUS } else { d.displayFunc |= HD44780_8BITBUS } if d.rows > 1 { d.displayFunc |= HD44780_2LINE } else { d.displayFunc |= HD44780_1LINE } d.displayFunc |= HD44780_5x8DOTS d.displayCtrl = HD44780_DISPLAYON | HD44780_BLINKOFF | HD44780_CURSOROFF d.displayMode = HD44780_ENTRYLEFT | HD44780_ENTRYSHIFTDECREMENT if err := d.sendCommand(HD44780_FUNCTIONSET | d.displayFunc); err != nil { return err } if err := d.sendCommand(HD44780_DISPLAYCONTROL | d.displayCtrl); err != nil { return err } if err := d.clear(); err != nil { return err } if err := d.sendCommand(HD44780_ENTRYMODESET | d.displayMode); err != nil { return err } // see documentation, page 45, 46: the busy flag can't be checked before return nil } // Write output text to the display func (d *HD44780Driver) Write(message string) error { d.mutex.Lock() defer d.mutex.Unlock() col := 0 if (d.displayMode & HD44780_ENTRYLEFT) == 0 { col = d.cols - 1 } row := 0 for _, c := range message { if c == '\n' { row++ if err := d.setCursor(col, row); err != nil { return err } continue } if err := d.writeChar(int(c)); err != nil { return err } } return nil } // Clear clear the display func (d *HD44780Driver) Clear() error { d.mutex.Lock() defer d.mutex.Unlock() return d.clear() } // Home return cursor to home func (d *HD44780Driver) Home() error { d.mutex.Lock() defer d.mutex.Unlock() if err := d.sendCommand(HD44780_RETURNHOME); err != nil { return err } time.Sleep(2 * time.Millisecond) return nil } // SetCursor move the cursor to the specified position func (d *HD44780Driver) SetCursor(col int, row int) error { d.mutex.Lock() defer d.mutex.Unlock() return d.setCursor(col, row) } // Display turn the display on and off func (d *HD44780Driver) Display(on bool) error { d.mutex.Lock() defer d.mutex.Unlock() if on { d.displayCtrl |= HD44780_DISPLAYON } else { d.displayCtrl &= ^HD44780_DISPLAYON } return d.sendCommand(HD44780_DISPLAYCONTROL | d.displayCtrl) } // Cursor turn the cursor on and off func (d *HD44780Driver) Cursor(on bool) error { d.mutex.Lock() defer d.mutex.Unlock() if on { d.displayCtrl |= HD44780_CURSORON } else { d.displayCtrl &= ^HD44780_CURSORON } return d.sendCommand(HD44780_DISPLAYCONTROL | d.displayCtrl) } // Blink turn the blink on and off func (d *HD44780Driver) Blink(on bool) error { d.mutex.Lock() defer d.mutex.Unlock() if on { d.displayCtrl |= HD44780_BLINKON } else { d.displayCtrl &= ^HD44780_BLINKON } return d.sendCommand(HD44780_DISPLAYCONTROL | d.displayCtrl) } // ScrollLeft scroll text left func (d *HD44780Driver) ScrollLeft() error { d.mutex.Lock() defer d.mutex.Unlock() return d.sendCommand(HD44780_CURSORSHIFT | HD44780_DISPLAYMOVE | HD44780_MOVELEFT) } // ScrollRight scroll text right func (d *HD44780Driver) ScrollRight() error { d.mutex.Lock() defer d.mutex.Unlock() return d.sendCommand(HD44780_CURSORSHIFT | HD44780_DISPLAYMOVE | HD44780_MOVERIGHT) } // LeftToRight display text from left to right func (d *HD44780Driver) LeftToRight() error { d.mutex.Lock() defer d.mutex.Unlock() d.displayMode |= HD44780_ENTRYLEFT return d.sendCommand(HD44780_ENTRYMODESET | d.displayMode) } // RightToLeft display text from right to left func (d *HD44780Driver) RightToLeft() error { d.mutex.Lock() defer d.mutex.Unlock() d.displayMode &= ^HD44780_ENTRYLEFT return d.sendCommand(HD44780_ENTRYMODESET | d.displayMode) } // SendCommand send control command func (d *HD44780Driver) SendCommand(data int) error { d.mutex.Lock() defer d.mutex.Unlock() return d.sendCommand(data) } // WriteChar output a character to the display func (d *HD44780Driver) WriteChar(data int) error { d.mutex.Lock() defer d.mutex.Unlock() return d.writeChar(data) } // CreateChar create custom character func (d *HD44780Driver) CreateChar(pos int, charMap [8]byte) error { d.mutex.Lock() defer d.mutex.Unlock() if pos > 7 { return errors.New("can't set a custom character at a position greater than 7") } if err := d.sendCommand(HD44780_SETCGRAMADDR | (pos << 3)); err != nil { return err } for i := range charMap { if err := d.writeChar(int(charMap[i])); err != nil { return err } } return nil } func (d *HD44780Driver) sendCommand(data int) error { if err := d.activateWriteMode(); err != nil { return err } if err := d.pinRS.Off(); err != nil { return err } if d.busMode == HD44780_4BITMODE { if err := d.writeDataPins(data >> 4); err != nil { return err } } return d.writeDataPins(data) } func (d *HD44780Driver) writeChar(data int) error { if err := d.activateWriteMode(); err != nil { return err } if err := d.pinRS.On(); err != nil { return err } if d.busMode == HD44780_4BITMODE { if err := d.writeDataPins(data >> 4); err != nil { return err } } return d.writeDataPins(data) } func (d *HD44780Driver) clear() error { if err := d.sendCommand(HD44780_CLEARDISPLAY); err != nil { return err } // clear is time consuming, see documentation for JHD1313 // for lower clock speed it takes more time time.Sleep(4 * time.Millisecond) return nil } func (d *HD44780Driver) setCursor(col int, row int) error { if col < 0 || row < 0 || col >= d.cols || row >= d.rows { return fmt.Errorf("invalid position value (%d, %d), range (%d, %d)", col, row, d.cols-1, d.rows-1) } return d.sendCommand(HD44780_SETDDRAMADDR | col + d.rowOffsets[row]) } func (d *HD44780Driver) writeDataPins(data int) error { for i, pin := range d.pinDataBits { if ((data >> i) & 0x01) == 0x01 { if err := pin.On(); err != nil { return err } } else { if err := pin.Off(); err != nil { return err } } } return d.fallingEdge() } // fallingEdge creates falling edge to trigger data transmission func (d *HD44780Driver) fallingEdge() error { if err := d.pinEN.On(); err != nil { return err } time.Sleep(1 * time.Microsecond) if err := d.pinEN.Off(); err != nil { return err } // fastest write operation at 190kHz mode takes 53 us time.Sleep(60 * time.Microsecond) return nil } func (d *HD44780Driver) activateWriteMode() error { if d.pinRW == nil { return nil } return d.pinRW.Off() } func (o hd44780PinRWOption) String() string { return "hd44780 RW pin option" } func (o hd44780PinRWOption) apply(cfg *hd44780Configuration) { cfg.pinRW = string(o) } ================================================ FILE: drivers/gpio/hd44780_driver_test.go ================================================ package gpio import ( "errors" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" ) var _ gobot.Driver = (*HD44780Driver)(nil) func initTestHD44780Driver() *HD44780Driver { d, _ := initTestHD44780Driver4BitModeWithStubbedAdaptor() if err := d.Start(); err != nil { panic(err) } return d } func initTestHD44780Driver4BitModeWithStubbedAdaptor() (*HD44780Driver, *gpioTestAdaptor) { a := newGpioTestAdaptor() dataPins := HD44780DataPin{ D4: "22", D5: "18", D6: "16", D7: "12", } return NewHD44780Driver(a, 2, 16, HD44780_4BITMODE, "13", "15", dataPins), a } func initTestHD44780Driver8BitModeWithStubbedAdaptor() (*HD44780Driver, *gpioTestAdaptor) { a := newGpioTestAdaptor() dataPins := HD44780DataPin{ D0: "31", D1: "33", D2: "35", D3: "37", D4: "22", D5: "18", D6: "16", D7: "12", } return NewHD44780Driver(a, 2, 16, HD44780_8BITMODE, "13", "15", dataPins), a } func TestNewHD44780Driver(t *testing.T) { // arrange a := newGpioTestAdaptor() dataPins := HD44780DataPin{ D4: "22", D5: "18", D6: "16", D7: "12", } // act d := NewHD44780Driver(a, 16, 2, HD44780_4BITMODE, "13", "15", dataPins) // assert assert.IsType(t, &HD44780Driver{}, d) // assert: gpio.driver attributes require.NotNil(t, d.driver) assert.True(t, strings.HasPrefix(d.driverCfg.name, "HD44780")) assert.Equal(t, a, d.connection) assert.NotNil(t, d.afterStart) assert.NotNil(t, d.beforeHalt) assert.NotNil(t, d.Commander) assert.NotNil(t, d.mutex) // assert: driver specific attributes assert.Empty(t, d.hd44780Cfg.pinRW) assert.Equal(t, 16, d.cols) assert.Equal(t, 2, d.rows) assert.Equal(t, HD44780_4BITMODE, d.busMode) assert.NotNil(t, d.pinRS) assert.NotNil(t, d.pinEN) assert.Nil(t, d.pinRW) // will be set optionally assert.NotNil(t, d.pinRS) assert.Equal(t, [4]int{0, 64, 16, 80}, d.rowOffsets) assert.Len(t, d.pinDataBits, 4) for _, b := range d.pinDataBits { assert.NotNil(t, b) } assert.Equal(t, 0, d.displayCtrl) assert.Equal(t, 0, d.displayFunc) assert.Equal(t, 0, d.displayMode) } func TestNewHD44780Driver_options(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithName() option, least one // option of this driver and one of another driver (which should lead to panic). Further tests for options can also // be done by call of "WithOption(val).apply(cfg)". // arrange const ( myName = "LCD output" pinRW = "3" ) dataPins := HD44780DataPin{ D4: "22", D5: "18", D6: "16", D7: "12", } panicFunc := func() { NewHD44780Driver(newGpioTestAdaptor(), 16, 2, HD44780_4BITMODE, "1", "2", dataPins, WithName("crazy"), aio.WithActuatorScaler(func(float64) int { return 0 })) } // act d := NewHD44780Driver(newGpioTestAdaptor(), 16, 2, HD44780_4BITMODE, "1", "2", dataPins, WithName(myName), WithHD44780RWPin(pinRW)) // assert assert.Equal(t, pinRW, d.hd44780Cfg.pinRW) assert.Equal(t, myName, d.Name()) assert.PanicsWithValue(t, "'scaler option for analog actuators' can not be applied on 'crazy'", panicFunc) } func TestHD44780Start(t *testing.T) { // arrange d, _ := initTestHD44780Driver4BitModeWithStubbedAdaptor() // act & assert: tests also initialize() require.NoError(t, d.Start()) } func TestHD44780StartError(t *testing.T) { a := newGpioTestAdaptor() var pins HD44780DataPin var d *HD44780Driver pins = HD44780DataPin{ D4: "22", D5: "18", D6: "16", D7: "", } d = NewHD44780Driver(a, 2, 16, HD44780_4BITMODE, "13", "15", pins) require.EqualError(t, d.Start(), "initialization error") pins = HD44780DataPin{ D0: "31", D1: "33", D2: "35", D3: "37", D4: "22", D5: "18", D6: "16", D7: "", } d = NewHD44780Driver(a, 2, 16, HD44780_8BITMODE, "13", "15", pins) require.EqualError(t, d.Start(), "initialization error") } func TestHD44780Write(t *testing.T) { var d *HD44780Driver d, _ = initTestHD44780Driver4BitModeWithStubbedAdaptor() _ = d.Start() require.NoError(t, d.Write("hello gobot")) d, _ = initTestHD44780Driver8BitModeWithStubbedAdaptor() _ = d.Start() require.NoError(t, d.Write("hello gobot")) } func TestHD44780WriteError(t *testing.T) { var d *HD44780Driver var a *gpioTestAdaptor d, a = initTestHD44780Driver4BitModeWithStubbedAdaptor() a.digitalWriteFunc = func(string, byte) error { return errors.New("write error") } _ = d.Start() require.EqualError(t, d.Write("hello gobot"), "write error") d, a = initTestHD44780Driver8BitModeWithStubbedAdaptor() a.digitalWriteFunc = func(string, byte) error { return errors.New("write error") } _ = d.Start() require.EqualError(t, d.Write("hello gobot"), "write error") } func TestHD44780Clear(t *testing.T) { d := initTestHD44780Driver() require.NoError(t, d.Clear()) } func TestHD44780Home(t *testing.T) { d := initTestHD44780Driver() require.NoError(t, d.Home()) } func TestHD44780SetCursor(t *testing.T) { d := initTestHD44780Driver() require.NoError(t, d.SetCursor(0, 3)) } func TestHD44780SetCursorInvalid(t *testing.T) { d := initTestHD44780Driver() require.EqualError(t, d.SetCursor(-1, 3), "invalid position value (-1, 3), range (1, 15)") require.EqualError(t, d.SetCursor(2, 3), "invalid position value (2, 3), range (1, 15)") require.EqualError(t, d.SetCursor(0, -1), "invalid position value (0, -1), range (1, 15)") require.EqualError(t, d.SetCursor(0, 16), "invalid position value (0, 16), range (1, 15)") } func TestHD44780DisplayOn(t *testing.T) { d := initTestHD44780Driver() require.NoError(t, d.Display(true)) } func TestHD44780DisplayOff(t *testing.T) { d := initTestHD44780Driver() require.NoError(t, d.Display(false)) } func TestHD44780CursorOn(t *testing.T) { d := initTestHD44780Driver() require.NoError(t, d.Cursor(true)) } func TestHD44780CursorOff(t *testing.T) { d := initTestHD44780Driver() require.NoError(t, d.Cursor(false)) } func TestHD44780BlinkOn(t *testing.T) { d := initTestHD44780Driver() require.NoError(t, d.Blink(true)) } func TestHD44780BlinkOff(t *testing.T) { d := initTestHD44780Driver() require.NoError(t, d.Blink(false)) } func TestHD44780ScrollLeft(t *testing.T) { d := initTestHD44780Driver() require.NoError(t, d.ScrollLeft()) } func TestHD44780ScrollRight(t *testing.T) { d := initTestHD44780Driver() require.NoError(t, d.ScrollRight()) } func TestHD44780LeftToRight(t *testing.T) { d := initTestHD44780Driver() require.NoError(t, d.LeftToRight()) } func TestHD44780RightToLeft(t *testing.T) { d := initTestHD44780Driver() require.NoError(t, d.RightToLeft()) } func TestHD44780SendCommand(t *testing.T) { d := initTestHD44780Driver() require.NoError(t, d.SendCommand(0x33)) } func TestHD44780WriteChar(t *testing.T) { d := initTestHD44780Driver() require.NoError(t, d.WriteChar(0x41)) } func TestHD44780CreateChar(t *testing.T) { d := initTestHD44780Driver() charMap := [8]byte{1, 2, 3, 4, 5, 6, 7, 8} require.NoError(t, d.CreateChar(0, charMap)) } func TestHD44780CreateCharError(t *testing.T) { d := initTestHD44780Driver() charMap := [8]byte{1, 2, 3, 4, 5, 6, 7, 8} require.EqualError(t, d.CreateChar(8, charMap), "can't set a custom character at a position greater than 7") } ================================================ FILE: drivers/gpio/helpers_test.go ================================================ package gpio import ( "fmt" "sync" "gobot.io/x/gobot/v2" ) type gpioTestBareAdaptor struct{} func (t *gpioTestBareAdaptor) Connect() error { return nil } func (t *gpioTestBareAdaptor) Finalize() error { return nil } func (t *gpioTestBareAdaptor) Name() string { return "" } func (t *gpioTestBareAdaptor) SetName(n string) {} type digitalPinMock struct { writeFunc func(val int) error } type gpioTestWritten struct { pin string val byte } type gpioTestAdaptor struct { name string pinMap map[string]gobot.DigitalPinner port string written []gpioTestWritten simulateWriteError bool mtx sync.Mutex digitalReadFunc func(ping string) (val int, err error) digitalWriteFunc func(pin string, val byte) error pwmWriteFunc func(pin string, val byte) error servoWriteFunc func(pin string, val byte) error } func newGpioTestAdaptor() *gpioTestAdaptor { t := gpioTestAdaptor{ name: "gpio_test_adaptor", pinMap: make(map[string]gobot.DigitalPinner), port: "/dev/null", digitalWriteFunc: func(pin string, val byte) error { return nil }, servoWriteFunc: func(pin string, val byte) error { return nil }, pwmWriteFunc: func(pin string, val byte) error { return nil }, digitalReadFunc: func(pin string) (int, error) { return 1, nil }, } return &t } // DigitalRead capabilities (interface DigitalReader) func (t *gpioTestAdaptor) DigitalRead(pin string) (int, error) { t.mtx.Lock() defer t.mtx.Unlock() return t.digitalReadFunc(pin) } // DigitalWrite capabilities (interface DigitalWriter) func (t *gpioTestAdaptor) DigitalWrite(pin string, val byte) error { t.mtx.Lock() defer t.mtx.Unlock() if t.simulateWriteError { return fmt.Errorf("write error") } w := gpioTestWritten{pin: pin, val: val} t.written = append(t.written, w) return t.digitalWriteFunc(pin, val) } // PwmWrite capabilities (interface PwmWriter) func (t *gpioTestAdaptor) PwmWrite(pin string, val byte) error { t.mtx.Lock() defer t.mtx.Unlock() return t.pwmWriteFunc(pin, val) } // ServoWrite capabilities (interface ServoWriter) func (t *gpioTestAdaptor) ServoWrite(pin string, val byte) error { t.mtx.Lock() defer t.mtx.Unlock() return t.servoWriteFunc(pin, val) } func (t *gpioTestAdaptor) Connect() error { return nil } func (t *gpioTestAdaptor) Finalize() error { return nil } func (t *gpioTestAdaptor) Name() string { return t.name } func (t *gpioTestAdaptor) SetName(n string) { t.name = n } func (t *gpioTestAdaptor) Port() string { return t.port } // DigitalPin (interface DigitalPinnerProvider) return a pin object func (t *gpioTestAdaptor) DigitalPin(id string) (gobot.DigitalPinner, error) { if pin, ok := t.pinMap[id]; ok { return pin, nil } return nil, fmt.Errorf("pin '%s' not found in '%s'", id, t.name) } // ApplyOptions (interface DigitalPinOptionApplier by DigitalPinner) apply all given options to the pin immediately func (d *digitalPinMock) ApplyOptions(options ...func(gobot.DigitalPinOptioner) bool) error { return nil } // Export (interface DigitalPinner) exports the pin for use by the adaptor func (d *digitalPinMock) Export() error { return nil } // Unexport (interface DigitalPinner) releases the pin from the adaptor, so it is free for the operating system func (d *digitalPinMock) Unexport() error { return nil } // Read (interface DigitalPinner) reads the current value of the pin func (d *digitalPinMock) Read() (int, error) { return 0, nil } // Write (interface DigitalPinner) writes to the pin func (d *digitalPinMock) Write(b int) error { return d.writeFunc(b) } func (t *gpioTestAdaptor) addDigitalPin(id string) *digitalPinMock { dpm := &digitalPinMock{ writeFunc: func(val int) error { return nil }, } t.pinMap[id] = dpm return dpm } ================================================ FILE: drivers/gpio/led_driver.go ================================================ package gpio import ( "gobot.io/x/gobot/v2" ) // LedDriver represents a digital Led type LedDriver struct { *driver high bool } // NewLedDriver return a new LedDriver given a DigitalWriter and pin. // // Supported options: // // "WithName" // // Adds the following API Commands: // // "Brightness" - See LedDriver.Brightness // "Toggle" - See LedDriver.Toggle // "On" - See LedDriver.On // "Off" - See LedDriver.Off func NewLedDriver(a DigitalWriter, pin string, opts ...interface{}) *LedDriver { //nolint:forcetypeassert // no error return value, so there is no better way d := &LedDriver{ driver: newDriver(a.(gobot.Connection), "LED", append(opts, withPin(pin))...), } //nolint:forcetypeassert // ok here d.AddCommand("Brightness", func(params map[string]interface{}) interface{} { level := byte(params["level"].(float64)) return d.Brightness(level) }) d.AddCommand("Toggle", func(_ map[string]interface{}) interface{} { return d.Toggle() }) d.AddCommand("On", func(_ map[string]interface{}) interface{} { return d.On() }) d.AddCommand("Off", func(_ map[string]interface{}) interface{} { return d.Off() }) return d } // State return true if the led is On and false if the led is Off func (d *LedDriver) State() bool { return d.high } // On sets the led to a high state. func (d *LedDriver) On() error { if err := d.digitalWrite(d.driverCfg.pin, 1); err != nil { return err } d.high = true return nil } // Off sets the led to a low state. func (d *LedDriver) Off() error { if err := d.digitalWrite(d.driverCfg.pin, 0); err != nil { return err } d.high = false return nil } // Toggle sets the led to the opposite of it's current state func (d *LedDriver) Toggle() error { if d.State() { return d.Off() } return d.On() } // Brightness sets the led to the specified level of brightness func (d *LedDriver) Brightness(level byte) error { return d.pwmWrite(d.driverCfg.pin, level) } ================================================ FILE: drivers/gpio/led_driver_test.go ================================================ //nolint:forcetypeassert // ok here package gpio import ( "errors" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" ) var _ gobot.Driver = (*LedDriver)(nil) func initTestLedDriver() *LedDriver { a := newGpioTestAdaptor() a.digitalWriteFunc = func(string, byte) error { return nil } a.pwmWriteFunc = func(string, byte) error { return nil } return NewLedDriver(a, "1") } func TestNewLedDriver(t *testing.T) { // arrange a := newGpioTestAdaptor() // act d := NewLedDriver(a, "10") // assert assert.IsType(t, &LedDriver{}, d) // assert: gpio.driver attributes require.NotNil(t, d.driver) assert.True(t, strings.HasPrefix(d.driverCfg.name, "LED")) assert.Equal(t, "10", d.driverCfg.pin) assert.Equal(t, a, d.connection) assert.NotNil(t, d.afterStart) assert.NotNil(t, d.beforeHalt) assert.NotNil(t, d.Commander) assert.NotNil(t, d.mutex) // assert: driver specific attributes assert.False(t, d.high) } func TestNewLedDriver_options(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithName() option, least one // option of this driver and one of another driver (which should lead to panic). Further tests for options can also // be done by call of "WithOption(val).apply(cfg)". // arrange const ( myName = "back light" ) panicFunc := func() { NewLedDriver(newGpioTestAdaptor(), "1", WithName("crazy"), aio.WithActuatorScaler(func(float64) int { return 0 })) } // act d := NewLedDriver(newGpioTestAdaptor(), "1", WithName(myName)) // assert assert.Equal(t, myName, d.Name()) assert.PanicsWithValue(t, "'scaler option for analog actuators' can not be applied on 'crazy'", panicFunc) } func TestLed_Commands(t *testing.T) { var err interface{} a := newGpioTestAdaptor() d := NewLedDriver(a, "1") a.digitalWriteFunc = func(string, byte) error { return errors.New("write error") } a.pwmWriteFunc = func(string, byte) error { return errors.New("pwm error") } err = d.Command("Toggle")(nil) require.EqualError(t, err.(error), "write error") err = d.Command("On")(nil) require.EqualError(t, err.(error), "write error") err = d.Command("Off")(nil) require.EqualError(t, err.(error), "write error") err = d.Command("Brightness")(map[string]interface{}{"level": 100.0}) require.EqualError(t, err.(error), "pwm error") } func TestLedToggle(t *testing.T) { d := initTestLedDriver() require.NoError(t, d.Off()) require.NoError(t, d.Toggle()) assert.True(t, d.State()) require.NoError(t, d.Toggle()) assert.False(t, d.State()) } func TestLedBrightness(t *testing.T) { a := newGpioTestAdaptor() d := NewLedDriver(a, "1") a.pwmWriteFunc = func(string, byte) error { return errors.New("pwm error") } require.EqualError(t, d.Brightness(150), "pwm error") } ================================================ FILE: drivers/gpio/max7219_driver.go ================================================ package gpio import ( "github.com/hashicorp/go-multierror" "gobot.io/x/gobot/v2" ) // Access and command constants for the driver const ( MAX7219Digit0 = 0x01 MAX7219Digit1 = 0x02 MAX7219Digit2 = 0x03 MAX7219Digit3 = 0x04 MAX7219Digit4 = 0x05 MAX7219Digit5 = 0x06 MAX7219Digit6 = 0x07 MAX7219Digit7 = 0x08 MAX7219DecodeMode = 0x09 MAX7219Intensity = 0x0a MAX7219ScanLimit = 0x0b MAX7219Shutdown = 0x0c MAX7219DisplayTest = 0x0f ) // MAX7219Driver is the gobot driver for the MAX7219 LED driver // // Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX7219-MAX7221.pdf type MAX7219Driver struct { *driver pinClock *DirectPinDriver pinData *DirectPinDriver pinCS *DirectPinDriver count uint } // NewMAX7219Driver return a new MAX7219Driver given a gobot.Connection, pins and how many chips are chained // // Supported options: // // "WithName" func NewMAX7219Driver( a gobot.Connection, clockPin, dataPin, csPin string, count uint, opts ...interface{}, ) *MAX7219Driver { d := &MAX7219Driver{ driver: newDriver(a, "MAX7219", opts...), pinClock: NewDirectPinDriver(a, clockPin), pinData: NewDirectPinDriver(a, dataPin), pinCS: NewDirectPinDriver(a, csPin), count: count, } d.afterStart = d.initialize /* TODO : Add commands */ return d } // SetIntensity changes the intensity (from 1 to 7) of the display func (d *MAX7219Driver) SetIntensity(level byte) error { if level > 15 { level = 15 } return d.All(MAX7219Intensity, level) } // ClearAll turns off all LEDs of all modules func (d *MAX7219Driver) ClearAll() error { var err error for i := 1; i <= 8; i++ { if e := d.All(byte(i), 0); e != nil { err = multierror.Append(err, e) } } return err } // ClearOne turns off all LEDs of the given module func (d *MAX7219Driver) ClearOne(which uint) error { var err error for i := 1; i <= 8; i++ { if e := d.One(which, byte(i), 0); e != nil { err = multierror.Append(err, e) } } return err } // All sends the same data to all the modules func (d *MAX7219Driver) All(address byte, data byte) error { if err := d.pinCS.Off(); err != nil { return err } var c uint for c = 0; c < d.count; c++ { if err := d.send(address); err != nil { return err } if err := d.send(data); err != nil { return err } } return d.pinCS.On() } // One sends data to a specific module func (d *MAX7219Driver) One(which uint, address byte, data byte) error { if err := d.pinCS.Off(); err != nil { return err } var c uint for c = 0; c < d.count; c++ { if c == which { if err := d.send(address); err != nil { return err } if err := d.send(data); err != nil { return err } } else { if err := d.send(0); err != nil { return err } if err := d.send(0); err != nil { return err } } } return d.pinCS.On() } // initialize initializes the max7219, it uses a SPI-like communication protocol func (d *MAX7219Driver) initialize() error { if err := d.pinData.On(); err != nil { return err } if err := d.pinClock.On(); err != nil { return err } if err := d.pinCS.On(); err != nil { return err } if err := d.All(MAX7219ScanLimit, 0x07); err != nil { return err } if err := d.All(MAX7219DecodeMode, 0x00); err != nil { return err } if err := d.All(MAX7219Shutdown, 0x01); err != nil { return err } if err := d.All(MAX7219DisplayTest, 0x00); err != nil { return err } if err := d.ClearAll(); err != nil { return err } return d.All(MAX7219Intensity, 0x0f) } // send writes data on the module func (d *MAX7219Driver) send(data byte) error { var i byte for i = 8; i > 0; i-- { mask := byte(0x01 << (i - 1)) if err := d.pinClock.Off(); err != nil { return err } if data&mask > 0 { if err := d.pinData.On(); err != nil { return err } } else { if err := d.pinData.Off(); err != nil { return err } } if err := d.pinClock.On(); err != nil { return err } } return nil } ================================================ FILE: drivers/gpio/max7219_driver_test.go ================================================ package gpio import ( "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" ) var _ gobot.Driver = (*MAX7219Driver)(nil) func initTestMAX7219Driver() *MAX7219Driver { d, _ := initTestMAX7219DriverWithStubbedAdaptor() return d } func initTestMAX7219DriverWithStubbedAdaptor() (*MAX7219Driver, *gpioTestAdaptor) { a := newGpioTestAdaptor() return NewMAX7219Driver(a, "1", "2", "3", 1), a } func TestNewMAX7219Driver(t *testing.T) { // arrange a := newGpioTestAdaptor() // act d := NewMAX7219Driver(a, "1", "2", "3", 4) // assert assert.IsType(t, &MAX7219Driver{}, d) // assert: gpio.driver attributes require.NotNil(t, d.driver) assert.True(t, strings.HasPrefix(d.driverCfg.name, "MAX7219")) assert.Equal(t, a, d.connection) assert.NotNil(t, d.afterStart) assert.NotNil(t, d.beforeHalt) assert.NotNil(t, d.Commander) assert.NotNil(t, d.mutex) // assert: driver specific attributes assert.NotNil(t, d.pinClock) assert.NotNil(t, d.pinData) assert.NotNil(t, d.pinCS) assert.Equal(t, uint(4), d.count) } func TestNewMAX7219Driver_options(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithName() option, least one // option of this driver and one of another driver (which should lead to panic). Further tests for options can also // be done by call of "WithOption(val).apply(cfg)". // arrange const ( myName = "light chain 5" ) panicFunc := func() { NewMAX7219Driver(newGpioTestAdaptor(), "1", "2", "3", 4, WithName("crazy"), aio.WithActuatorScaler(func(float64) int { return 0 })) } // act d := NewMAX7219Driver(newGpioTestAdaptor(), "1", "2", "3", 4, WithName(myName)) // assert assert.Equal(t, myName, d.Name()) assert.PanicsWithValue(t, "'scaler option for analog actuators' can not be applied on 'crazy'", panicFunc) } func TestMAX7219Start(t *testing.T) { // arrange d := initTestMAX7219Driver() // act & assert: tests also initialize() require.NoError(t, d.Start()) } ================================================ FILE: drivers/gpio/motor_driver.go ================================================ package gpio import ( "fmt" "gobot.io/x/gobot/v2" ) // motorOptionApplier needs to be implemented by each configurable option type type motorOptionApplier interface { apply(cfg *motorConfiguration) } // motorConfiguration contains all changeable attributes of the driver. type motorConfiguration struct { modeIsAnalog bool directionPin string forwardPin string backwardPin string } // motorModeIsAnalogOption is the type for applying analog mode to the configuration type motorModeIsAnalogOption bool // motorDirectionPinOption is the type for applying a direction pin to the configuration type motorDirectionPinOption string // motorForwardPinOption is the type for applying a forward pin to the configuration type motorForwardPinOption string // motorBackwardPinOption is the type for applying a backward pin to the configuration type motorBackwardPinOption string // MotorDriver Represents a Motor type MotorDriver struct { *driver motorCfg *motorConfiguration currentState byte currentSpeed byte currentDirection string } // NewMotorDriver return a new MotorDriver given a DigitalWriter and pin. This defaults to digital mode and just switch // on and off in forward direction. Optional pins can be given, depending on your hardware. So the direction can be // changed with one pin or by using separated forward and backward pins. // // If the given pin supports the PwmWriter the motor can be used/switched to analog mode by writing once to SetSpeed() // or by calling SetAnalogMode(). The optional pins can be used for direction control. // // Supported options: // // "WithName" // "WithMotorAnalog" // "WithMotorDirectionPin" // "WithMotorForwardPin" // "WithMotorBackwardPin" func NewMotorDriver(a DigitalWriter, speedPin string, opts ...interface{}) *MotorDriver { //nolint:forcetypeassert // no error return value, so there is no better way d := &MotorDriver{ driver: newDriver(a.(gobot.Connection), "Motor", withPin(speedPin)), motorCfg: &motorConfiguration{}, currentDirection: "forward", } for _, opt := range opts { switch o := opt.(type) { case optionApplier: o.apply(d.driverCfg) case motorOptionApplier: o.apply(d.motorCfg) default: panic(fmt.Sprintf("'%s' can not be applied on '%s'", opt, d.driverCfg.name)) } } return d } // WithMotorAnalog change the default mode "digital" to analog for the motor. func WithMotorAnalog() motorOptionApplier { return motorModeIsAnalogOption(true) } // WithMotorDirectionPin introduces a pin for change the direction of the motor. func WithMotorDirectionPin(pin string) motorOptionApplier { return motorDirectionPinOption(pin) } // WithMotorForwardPin introduces a pin for setting the direction to forward. func WithMotorForwardPin(pin string) motorOptionApplier { return motorForwardPinOption(pin) } // WithMotorBackwardPin introduces a pin for setting the direction to backward. func WithMotorBackwardPin(pin string) motorOptionApplier { return motorBackwardPinOption(pin) } // Off turns the motor off or sets the motor to a 0 speed. func (d *MotorDriver) Off() error { if d.IsDigital() { return d.changeState(0) } return d.SetSpeed(0) } // On turns the motor on or sets the motor to a maximum speed. func (d *MotorDriver) On() error { if d.IsDigital() { return d.changeState(1) } if d.currentSpeed == 0 { d.currentSpeed = 255 } return d.SetSpeed(d.currentSpeed) } // RunMin sets the motor to the minimum speed. func (d *MotorDriver) RunMin() error { return d.Off() } // RunMax sets the motor to the maximum speed. func (d *MotorDriver) RunMax() error { return d.SetSpeed(255) } // Toggle sets the motor to the opposite of it's current state. func (d *MotorDriver) Toggle() error { if d.IsOn() { return d.Off() } return d.On() } // SetSpeed change the speed of the motor, without change the direction. func (d *MotorDriver) SetSpeed(value byte) error { if writer, ok := d.connection.(PwmWriter); ok { WithMotorAnalog().apply(d.motorCfg) d.currentSpeed = value return writer.PwmWrite(d.driverCfg.pin, value) } return ErrPwmWriteUnsupported } // Forward runs the motor forward with the specified speed. func (d *MotorDriver) Forward(speed byte) error { if err := d.SetDirection("forward"); err != nil { return err } if err := d.SetSpeed(speed); err != nil { return err } return nil } // Backward runs the motor backward with the specified speed. func (d *MotorDriver) Backward(speed byte) error { if err := d.SetDirection("backward"); err != nil { return err } if err := d.SetSpeed(speed); err != nil { return err } return nil } // Direction sets the direction pin to the specified direction. func (d *MotorDriver) SetDirection(direction string) error { d.currentDirection = direction if d.motorCfg.directionPin != "" { var level byte if direction == "forward" { level = 1 } else { level = 0 } return d.digitalWrite(d.motorCfg.directionPin, level) } var forwardLevel, backwardLevel byte switch direction { case "forward": forwardLevel = 1 backwardLevel = 0 case "backward": forwardLevel = 0 backwardLevel = 1 case "none": forwardLevel = 0 backwardLevel = 0 } if d.motorCfg.forwardPin != "" { if err := d.digitalWrite(d.motorCfg.forwardPin, forwardLevel); err != nil { return err } } if d.motorCfg.backwardPin != "" { return d.digitalWrite(d.motorCfg.backwardPin, backwardLevel) } return nil } // IsAnalog returns true if the motor is in analog mode. func (d *MotorDriver) IsAnalog() bool { return d.motorCfg.modeIsAnalog } // IsDigital returns true if the motor is in digital mode. func (d *MotorDriver) IsDigital() bool { return !d.motorCfg.modeIsAnalog } // IsOn returns true if the motor is on. func (d *MotorDriver) IsOn() bool { if d.IsDigital() { return d.currentState == 1 } return d.currentSpeed > 0 } // IsOff returns true if the motor is off. func (d *MotorDriver) IsOff() bool { return !d.IsOn() } // Direction returns the current direction ("forward" or "backward") of the motor. func (d *MotorDriver) Direction() string { return d.currentDirection } // Speed returns the current speed of the motor. func (d *MotorDriver) Speed() byte { return d.currentSpeed } func (d *MotorDriver) changeState(state byte) error { d.currentState = state if state == 1 { d.currentSpeed = 255 } else { d.currentSpeed = 0 } if d.motorCfg.forwardPin == "" { return d.digitalWrite(d.driverCfg.pin, state) } if state != 1 { return d.SetDirection("none") } if err := d.SetDirection(d.currentDirection); err != nil { return err } if d.driverCfg.pin != "" { if err := d.SetSpeed(d.currentSpeed); err != nil { return err } } return nil } func (o motorModeIsAnalogOption) String() string { return "motor mode (analog, digital) option" } func (o motorDirectionPinOption) String() string { return "direction pin option for motors" } func (o motorForwardPinOption) String() string { return "forward pin option for motors" } func (o motorBackwardPinOption) String() string { return "backward pin option for motors" } func (o motorModeIsAnalogOption) apply(cfg *motorConfiguration) { cfg.modeIsAnalog = bool(o) } func (o motorDirectionPinOption) apply(cfg *motorConfiguration) { cfg.directionPin = string(o) } func (o motorForwardPinOption) apply(cfg *motorConfiguration) { cfg.forwardPin = string(o) } func (o motorBackwardPinOption) apply(cfg *motorConfiguration) { cfg.backwardPin = string(o) } ================================================ FILE: drivers/gpio/motor_driver_test.go ================================================ package gpio import ( "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" ) var _ gobot.Driver = (*MotorDriver)(nil) func initTestMotorDriver() *MotorDriver { return NewMotorDriver(newGpioTestAdaptor(), "1") } func TestMotorDriver(t *testing.T) { d := NewMotorDriver(newGpioTestAdaptor(), "1") assert.NotNil(t, d.Connection()) } func TestNewMotorDriver(t *testing.T) { // arrange a := newGpioTestAdaptor() // act d := NewMotorDriver(a, "10") // assert assert.IsType(t, &MotorDriver{}, d) // assert: gpio.driver attributes require.NotNil(t, d.driver) assert.True(t, strings.HasPrefix(d.driverCfg.name, "Motor")) assert.Equal(t, "10", d.driverCfg.pin) assert.Equal(t, a, d.connection) assert.NotNil(t, d.afterStart) assert.NotNil(t, d.beforeHalt) assert.NotNil(t, d.Commander) assert.NotNil(t, d.mutex) // assert: driver specific attributes assert.Empty(t, d.motorCfg.directionPin) assert.Empty(t, d.motorCfg.forwardPin) assert.Empty(t, d.motorCfg.backwardPin) assert.False(t, d.motorCfg.modeIsAnalog) assert.Equal(t, uint8(0), d.currentState) assert.Equal(t, uint8(0), d.currentSpeed) assert.Equal(t, "forward", d.currentDirection) } func TestNewMotorDriver_options(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithName() option, least one // option of this driver and one of another driver (which should lead to panic). Further tests for options can also // be done by call of "WithOption(val).apply(cfg)". // arrange const ( myName = "move analog" ) panicFunc := func() { NewMotorDriver(newGpioTestAdaptor(), "1", WithName("crazy"), aio.WithActuatorScaler(func(float64) int { return 0 })) } // act d := NewMotorDriver(newGpioTestAdaptor(), "1", WithName(myName), WithMotorAnalog()) // assert assert.True(t, d.motorCfg.modeIsAnalog) assert.Equal(t, myName, d.Name()) assert.PanicsWithValue(t, "'scaler option for analog actuators' can not be applied on 'crazy'", panicFunc) } func TestMotor_WithMotorDirectionPin(t *testing.T) { // arrange const myPin = "8" cfg := motorConfiguration{directionPin: "old_pin"} // act WithMotorDirectionPin(myPin).apply(&cfg) // assert assert.Equal(t, myPin, cfg.directionPin) } func TestMotor_WithMotorForwardPin(t *testing.T) { // arrange const myPin = "3" cfg := motorConfiguration{directionPin: "old_pin"} // act WithMotorForwardPin(myPin).apply(&cfg) // assert assert.Equal(t, myPin, cfg.forwardPin) } func TestMotor_WithMotorBackwardPin(t *testing.T) { // arrange const myPin = "6" cfg := motorConfiguration{directionPin: "old_pin"} // act WithMotorBackwardPin(myPin).apply(&cfg) // assert assert.Equal(t, myPin, cfg.backwardPin) } func TestMotorIsOn(t *testing.T) { d := initTestMotorDriver() d.motorCfg.modeIsAnalog = false d.currentState = 1 assert.True(t, d.IsDigital()) assert.True(t, d.IsOn()) d.motorCfg.modeIsAnalog = true d.currentSpeed = 100 assert.False(t, d.IsDigital()) assert.True(t, d.IsOn()) } func TestMotorIsOff(t *testing.T) { d := initTestMotorDriver() require.NoError(t, d.Off()) assert.True(t, d.IsOff()) } func TestMotorOn(t *testing.T) { d := initTestMotorDriver() d.motorCfg.modeIsAnalog = false assert.True(t, d.IsDigital()) require.NoError(t, d.On()) assert.Equal(t, uint8(1), d.currentState) d.motorCfg.modeIsAnalog = true d.currentSpeed = 0 assert.False(t, d.IsDigital()) require.NoError(t, d.On()) assert.Equal(t, uint8(255), d.currentSpeed) } func TestMotorOff(t *testing.T) { d := initTestMotorDriver() d.motorCfg.modeIsAnalog = false assert.True(t, d.IsDigital()) require.NoError(t, d.Off()) assert.Equal(t, uint8(0), d.currentState) d.motorCfg.modeIsAnalog = true d.currentSpeed = 100 assert.False(t, d.IsDigital()) require.NoError(t, d.Off()) assert.Equal(t, uint8(0), d.currentSpeed) } func TestMotorToggle(t *testing.T) { d := initTestMotorDriver() require.NoError(t, d.Off()) require.NoError(t, d.Toggle()) assert.True(t, d.IsOn()) require.NoError(t, d.Toggle()) assert.False(t, d.IsOn()) } func TestMotorRunMin(t *testing.T) { d := initTestMotorDriver() require.NoError(t, d.RunMin()) } func TestMotorRunMax(t *testing.T) { d := initTestMotorDriver() require.NoError(t, d.RunMax()) } func TestMotorSetSpeed(t *testing.T) { d := initTestMotorDriver() require.NoError(t, d.SetSpeed(100)) } func TestMotorForward(t *testing.T) { d := initTestMotorDriver() require.NoError(t, d.Forward(100)) assert.Equal(t, uint8(100), d.currentSpeed) assert.Equal(t, "forward", d.currentDirection) } func TestMotorBackward(t *testing.T) { d := initTestMotorDriver() require.NoError(t, d.Backward(100)) assert.Equal(t, uint8(100), d.currentSpeed) assert.Equal(t, "backward", d.currentDirection) } func TestMotorSetDirection(t *testing.T) { d := initTestMotorDriver() require.NoError(t, d.SetDirection("none")) d.motorCfg.directionPin = "2" require.NoError(t, d.SetDirection("forward")) require.NoError(t, d.SetDirection("backward")) } func TestMotorDigital(t *testing.T) { d := initTestMotorDriver() d.driverCfg.pin = "" // Disable speed d.motorCfg.modeIsAnalog = false d.motorCfg.forwardPin = "2" d.motorCfg.backwardPin = "3" require.NoError(t, d.On()) assert.Equal(t, uint8(1), d.currentState) require.NoError(t, d.Off()) assert.Equal(t, uint8(0), d.currentState) } ================================================ FILE: drivers/gpio/pir_motion_driver.go ================================================ package gpio import ( "fmt" "time" "gobot.io/x/gobot/v2" ) // pirMotionOptionApplier needs to be implemented by each configurable option type type pirMotionOptionApplier interface { apply(cfg *pirMotionConfiguration) } // pirMotionConfiguration contains all changeable attributes of the driver. type pirMotionConfiguration struct { readInterval time.Duration } // pirMotionReadIntervalOption is the type for applying another read interval to the configuration type pirMotionReadIntervalOption time.Duration // PIRMotionDriver represents a digital Proximity Infra Red (PIR) motion detecter // // Supported options: // // "WithName" type PIRMotionDriver struct { *driver gobot.Eventer pirMotionCfg *pirMotionConfiguration active bool halt chan struct{} } // NewPIRMotionDriver returns a new driver for PIR motion sensor with a polling interval of 10 Milliseconds, // given a DigitalReader and pin. // // Supported options: // // "WithName" // "WithButtonPollInterval" func NewPIRMotionDriver(a DigitalReader, pin string, opts ...interface{}) *PIRMotionDriver { //nolint:forcetypeassert // no error return value, so there is no better way d := &PIRMotionDriver{ driver: newDriver(a.(gobot.Connection), "PIRMotion", withPin(pin)), pirMotionCfg: &pirMotionConfiguration{readInterval: 10 * time.Millisecond}, } d.afterStart = d.initialize d.beforeHalt = d.shutdown for _, opt := range opts { switch o := opt.(type) { case optionApplier: o.apply(d.driverCfg) case pirMotionOptionApplier: o.apply(d.pirMotionCfg) case time.Duration: // TODO this is only for backward compatibility and will be removed after version 2.x d.pirMotionCfg.readInterval = o default: panic(fmt.Sprintf("'%s' can not be applied on '%s'", opt, d.driverCfg.name)) } } return d } // WithPIRMotionPollInterval change the asynchronous cyclic reading interval from default 10ms to the given value. func WithPIRMotionPollInterval(interval time.Duration) pirMotionOptionApplier { return pirMotionReadIntervalOption(interval) } // Active gets the current state func (d *PIRMotionDriver) Active() bool { // ensure that read and write can not interfere d.mutex.Lock() defer d.mutex.Unlock() return d.active } // initialize the PIRMotionDriver and polls the state of the sensor at the given interval. // // Emits the Events: // // MotionDetected - On motion detected // MotionStopped int - On motion stopped // Error error - On pirMotion error // // The PIRMotionDriver will send the MotionDetected event over and over, // just as long as motion is still being detected. // It will only send the MotionStopped event once, however, until // motion starts being detected again func (d *PIRMotionDriver) initialize() error { if d.pirMotionCfg.readInterval == 0 { return fmt.Errorf("the read interval for pirMotion needs to be greater than zero") } d.Eventer = gobot.NewEventer() d.AddEvent(MotionDetected) d.AddEvent(MotionStopped) d.AddEvent(Error) d.halt = make(chan struct{}) go func() { for { select { case <-time.After(d.pirMotionCfg.readInterval): newValue, err := d.digitalRead(d.driverCfg.pin) if err != nil { d.Publish(Error, err) } d.update(newValue) case <-d.halt: return } } }() return nil } // shutdown stops polling func (d *PIRMotionDriver) shutdown() error { if d.pirMotionCfg.readInterval == 0 || d.halt == nil { // cyclic reading deactivated return nil } close(d.halt) // broadcast halt, also to the test return nil } func (d *PIRMotionDriver) update(newValue int) { // ensure that read and write can not interfere d.mutex.Lock() defer d.mutex.Unlock() switch newValue { case 1: if !d.active { d.active = true d.Publish(MotionDetected, newValue) } case 0: if d.active { d.active = false d.Publish(MotionStopped, newValue) } } } func (o pirMotionReadIntervalOption) String() string { return "read interval option for PIR motion sensor" } func (o pirMotionReadIntervalOption) apply(cfg *pirMotionConfiguration) { cfg.readInterval = time.Duration(o) } ================================================ FILE: drivers/gpio/pir_motion_driver_test.go ================================================ package gpio import ( "fmt" "strings" "sync" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" ) var _ gobot.Driver = (*PIRMotionDriver)(nil) const motionTestDelay = 150 func initTestPIRMotionDriverWithStubbedAdaptor() (*PIRMotionDriver, *gpioTestAdaptor) { a := newGpioTestAdaptor() d := NewPIRMotionDriver(a, "1") return d, a } func TestNewPIRMotionDriver(t *testing.T) { // arrange a := newGpioTestAdaptor() // act d := NewPIRMotionDriver(a, "1") // assert assert.IsType(t, &PIRMotionDriver{}, d) // assert: gpio.driver attributes require.NotNil(t, d.driver) assert.True(t, strings.HasPrefix(d.driverCfg.name, "PIRMotion")) assert.Equal(t, "1", d.driverCfg.pin) assert.Equal(t, a, d.connection) assert.NotNil(t, d.afterStart) assert.NotNil(t, d.beforeHalt) assert.NotNil(t, d.Commander) assert.NotNil(t, d.mutex) // assert: driver specific attributes assert.False(t, d.active) assert.Equal(t, 10*time.Millisecond, d.pirMotionCfg.readInterval) assert.Nil(t, d.Eventer) // will be created on initialize assert.Nil(t, d.halt) // will be created on initialize } func TestNewPIRMotionDriver_options(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithName() option, least one // option of this driver and one of another driver (which should lead to panic). Further tests for options can also // be done by call of "WithOption(val).apply(cfg)". // arrange const ( myName = "voltage 1" cycReadDur = 30 * time.Millisecond ) panicFunc := func() { NewPIRMotionDriver(newGpioTestAdaptor(), "1", WithName("crazy"), aio.WithActuatorScaler(func(float64) int { return 0 })) } // act d := NewPIRMotionDriver(newGpioTestAdaptor(), "1", WithName(myName), WithPIRMotionPollInterval(cycReadDur)) // assert assert.Equal(t, cycReadDur, d.pirMotionCfg.readInterval) assert.Equal(t, myName, d.Name()) assert.PanicsWithValue(t, "'scaler option for analog actuators' can not be applied on 'crazy'", panicFunc) } func TestPIRMotionStart(t *testing.T) { // arrange sem := make(chan bool) nextVal := make(chan int, 1) a := newGpioTestAdaptor() d := NewPIRMotionDriver(a, "1") a.digitalReadFunc = func(string) (int, error) { val := 1 var err error select { case val = <-nextVal: if val < 0 { err = fmt.Errorf("digital read error") } return val, err default: return val, err } } // act: start cyclic reading err := d.Start() _ = d.Once(MotionDetected, func(data interface{}) { assert.True(t, d.active) nextVal <- 0 sem <- true }) // assert & rearrange require.NoError(t, err) select { case <-sem: case <-time.After(motionTestDelay * time.Millisecond): require.Fail(t, "PIRMotionDriver Event \"MotionDetected\" was not published") } _ = d.Once(MotionStopped, func(data interface{}) { assert.False(t, d.active) nextVal <- -1 sem <- true }) select { case <-sem: case <-time.After(motionTestDelay * time.Millisecond): require.Fail(t, "PIRMotionDriver Event \"MotionStopped\" was not published") } _ = d.Once(Error, func(data interface{}) { sem <- true }) select { case <-sem: case <-time.After(motionTestDelay * time.Millisecond): require.Fail(t, "PIRMotionDriver Event \"Error\" was not published") } _ = d.Once(MotionDetected, func(data interface{}) { sem <- true }) require.NoError(t, d.Halt()) nextVal <- 1 select { case <-sem: require.Fail(t, "PIRMotion Event \"MotionDetected\" should not published") case <-time.After(motionTestDelay * time.Millisecond): } } func TestPIRMotionHalt(t *testing.T) { // arrange d, _ := initTestPIRMotionDriverWithStubbedAdaptor() require.NoError(t, d.Start()) timeout := 2 * d.pirMotionCfg.readInterval wg := sync.WaitGroup{} wg.Add(1) go func() { defer wg.Done() select { case <-d.halt: // wait until halt is broadcasted by close the channel case <-time.After(timeout): // otherwise run into the timeout assert.Fail(t, fmt.Sprintf("halt was not received within %s", timeout)) } }() // act & assert require.NoError(t, d.Halt()) wg.Wait() // wait until the go function was really finished } func TestPIRMotionActive(t *testing.T) { tests := map[string]struct { want bool }{ "active_true": {want: true}, "active_false": {want: false}, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d := PIRMotionDriver{driver: newDriver(nil, "PIRMotion")} // just for mutex d.active = tc.want // act & assert assert.Equal(t, tc.want, d.Active()) }) } } ================================================ FILE: drivers/gpio/relay_driver.go ================================================ package gpio import ( "fmt" "gobot.io/x/gobot/v2" ) // relayOptionApplier needs to be implemented by each configurable option type type relayOptionApplier interface { apply(cfg *relayConfiguration) } // relayConfiguration contains all changeable attributes of the driver. type relayConfiguration struct { inverted bool } // relayInvertedOption is the type for applying inverted behavior to the configuration type relayInvertedOption bool // RelayDriver represents a digital relay type RelayDriver struct { *driver relayCfg *relayConfiguration high bool } // NewRelayDriver return a new RelayDriver given a DigitalWriter and pin. // // Supported options: // // "WithName" // "WithRelayInverted" // // Adds the following API Commands: // // "Toggle" - See RelayDriver.Toggle // "On" - See RelayDriver.On // "Off" - See RelayDriver.Off func NewRelayDriver(a DigitalWriter, pin string, opts ...interface{}) *RelayDriver { //nolint:forcetypeassert // no error return value, so there is no better way d := &RelayDriver{ driver: newDriver(a.(gobot.Connection), "Relay", withPin(pin)), relayCfg: &relayConfiguration{}, } for _, opt := range opts { switch o := opt.(type) { case optionApplier: o.apply(d.driverCfg) case relayOptionApplier: o.apply(d.relayCfg) default: panic(fmt.Sprintf("'%s' can not be applied on '%s'", opt, d.driverCfg.name)) } } d.AddCommand("Toggle", func(_ map[string]interface{}) interface{} { return d.Toggle() }) d.AddCommand("On", func(_ map[string]interface{}) interface{} { return d.On() }) d.AddCommand("Off", func(_ map[string]interface{}) interface{} { return d.Off() }) return d } // WithRelayInverted change the relay action to inverted. func WithRelayInverted() relayOptionApplier { return relayInvertedOption(true) } // State return true if the relay is On and false if the relay is Off func (d *RelayDriver) State() bool { if d.relayCfg.inverted { return !d.high } return d.high } // On sets the relay to a high state. func (d *RelayDriver) On() error { newValue := byte(1) if d.relayCfg.inverted { newValue = 0 } if err := d.digitalWrite(d.driverCfg.pin, newValue); err != nil { return err } d.high = !d.relayCfg.inverted return nil } // Off sets the relay to a low state. func (d *RelayDriver) Off() error { newValue := byte(0) if d.relayCfg.inverted { newValue = 1 } if err := d.digitalWrite(d.driverCfg.pin, newValue); err != nil { return err } d.high = d.relayCfg.inverted return nil } // Toggle sets the relay to the opposite of it's current state func (d *RelayDriver) Toggle() error { if d.State() { return d.Off() } return d.On() } // IsInverted returns true if the relay acts inverted func (d *RelayDriver) IsInverted() bool { return d.relayCfg.inverted } func (o relayInvertedOption) String() string { return "relay acts inverted option" } func (o relayInvertedOption) apply(cfg *relayConfiguration) { cfg.inverted = bool(o) } ================================================ FILE: drivers/gpio/relay_driver_test.go ================================================ package gpio import ( "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" ) var _ gobot.Driver = (*RelayDriver)(nil) // Helper to return low/high value for testing func (l *RelayDriver) High() bool { return l.high } func initTestRelayDriver() (*RelayDriver, *gpioTestAdaptor) { a := newGpioTestAdaptor() a.digitalWriteFunc = func(string, byte) error { return nil } a.pwmWriteFunc = func(string, byte) error { return nil } return NewRelayDriver(a, "1"), a } func TestNewRelayDriver(t *testing.T) { // arrange a := newGpioTestAdaptor() // act d := NewRelayDriver(a, "10") // assert assert.IsType(t, &RelayDriver{}, d) // assert: gpio.driver attributes require.NotNil(t, d.driver) assert.True(t, strings.HasPrefix(d.driverCfg.name, "Relay")) assert.Equal(t, "10", d.driverCfg.pin) assert.Equal(t, a, d.connection) assert.NotNil(t, d.afterStart) assert.NotNil(t, d.beforeHalt) assert.NotNil(t, d.Commander) assert.NotNil(t, d.mutex) // assert: driver specific attributes assert.False(t, d.relayCfg.inverted) assert.False(t, d.high) } func TestNewRelayDriver_options(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithName() option, least one // option of this driver and one of another driver (which should lead to panic). Further tests for options can also // be done by call of "WithOption(val).apply(cfg)". // arrange const ( myName = "switch alarm relay" ) panicFunc := func() { NewRelayDriver(newGpioTestAdaptor(), "1", WithName("crazy"), aio.WithActuatorScaler(func(float64) int { return 0 })) } // act d := NewRelayDriver(newGpioTestAdaptor(), "1", WithName(myName), WithRelayInverted()) // assert assert.True(t, d.relayCfg.inverted) assert.Equal(t, myName, d.Name()) assert.PanicsWithValue(t, "'scaler option for analog actuators' can not be applied on 'crazy'", panicFunc) } func TestRelayToggle(t *testing.T) { d, a := initTestRelayDriver() var lastVal byte a.digitalWriteFunc = func(pin string, val byte) error { lastVal = val return nil } _ = d.Off() assert.False(t, d.State()) assert.Equal(t, byte(0), lastVal) _ = d.Toggle() assert.True(t, d.State()) assert.Equal(t, byte(1), lastVal) _ = d.Toggle() assert.False(t, d.State()) assert.Equal(t, byte(0), lastVal) } func TestRelayToggleInverted(t *testing.T) { d, a := initTestRelayDriver() var lastVal byte a.digitalWriteFunc = func(pin string, val byte) error { lastVal = val return nil } WithRelayInverted().apply(d.relayCfg) _ = d.Off() assert.False(t, d.State()) assert.Equal(t, byte(1), lastVal) _ = d.Toggle() assert.True(t, d.State()) assert.Equal(t, byte(0), lastVal) _ = d.Toggle() assert.False(t, d.State()) assert.Equal(t, byte(1), lastVal) } func TestRelay_Commands(t *testing.T) { d, a := initTestRelayDriver() var lastVal byte a.digitalWriteFunc = func(pin string, val byte) error { lastVal = val return nil } assert.Nil(t, d.Command("Off")(nil)) assert.False(t, d.State()) assert.Equal(t, byte(0), lastVal) assert.Nil(t, d.Command("On")(nil)) assert.True(t, d.State()) assert.Equal(t, byte(1), lastVal) assert.Nil(t, d.Command("Toggle")(nil)) assert.False(t, d.State()) assert.Equal(t, byte(0), lastVal) } func TestRelay_CommandsInverted(t *testing.T) { d, a := initTestRelayDriver() var lastVal byte a.digitalWriteFunc = func(pin string, val byte) error { lastVal = val return nil } WithRelayInverted().apply(d.relayCfg) assert.Nil(t, d.Command("Off")(nil)) assert.True(t, d.High()) assert.False(t, d.State()) assert.Equal(t, byte(1), lastVal) assert.Nil(t, d.Command("On")(nil)) assert.False(t, d.High()) assert.True(t, d.State()) assert.Equal(t, byte(0), lastVal) assert.Nil(t, d.Command("Toggle")(nil)) assert.True(t, d.High()) assert.False(t, d.State()) assert.Equal(t, byte(1), lastVal) } ================================================ FILE: drivers/gpio/rgb_led_driver.go ================================================ package gpio import ( "gobot.io/x/gobot/v2" ) // RgbLedDriver represents a digital RGB Led type RgbLedDriver struct { *driver pinRed string redColor byte pinGreen string greenColor byte pinBlue string blueColor byte high bool } // NewRgbLedDriver return a new RgbLedDriver given a PwmWriter and 3 pins: redPin, greenPin, and bluePin // // Supported options: // // "WithName" // // Adds the following API Commands: // // "SetRGB" - See RgbLedDriver.SetRGB // "Toggle" - See RgbLedDriver.Toggle // "On" - See RgbLedDriver.On // "Off" - See RgbLedDriver.Off func NewRgbLedDriver(a PwmWriter, redPin string, greenPin string, bluePin string, opts ...interface{}) *RgbLedDriver { //nolint:forcetypeassert // no error return value, so there is no better way d := &RgbLedDriver{ driver: newDriver(a.(gobot.Connection), "RGBLED", opts...), pinRed: redPin, pinGreen: greenPin, pinBlue: bluePin, } //nolint:forcetypeassert // ok here d.AddCommand("SetRGB", func(params map[string]interface{}) interface{} { r := byte(params["r"].(int)) g := byte(params["g"].(int)) b := byte(params["b"].(int)) return d.SetRGB(r, g, b) }) d.AddCommand("Toggle", func(_ map[string]interface{}) interface{} { return d.Toggle() }) d.AddCommand("On", func(_ map[string]interface{}) interface{} { return d.On() }) d.AddCommand("Off", func(_ map[string]interface{}) interface{} { return d.Off() }) return d } // Pin returns the RgbLedDrivers pins func (d *RgbLedDriver) Pin() string { return "r=" + d.pinRed + ", g=" + d.pinGreen + ", b=" + d.pinBlue } // RedPin returns the RgbLedDrivers redPin func (d *RgbLedDriver) RedPin() string { return d.pinRed } // GreenPin returns the RgbLedDrivers redPin func (d *RgbLedDriver) GreenPin() string { return d.pinGreen } // BluePin returns the RgbLedDrivers bluePin func (d *RgbLedDriver) BluePin() string { return d.pinBlue } // State return true if the led is On and false if the led is Off func (d *RgbLedDriver) State() bool { return d.high } // On sets the led's pins to their various states func (d *RgbLedDriver) On() error { if err := d.SetLevel(d.pinRed, d.redColor); err != nil { return err } if err := d.SetLevel(d.pinGreen, d.greenColor); err != nil { return err } if err := d.SetLevel(d.pinBlue, d.blueColor); err != nil { return err } d.high = true return nil } // Off sets the led to black. func (d *RgbLedDriver) Off() error { if err := d.SetLevel(d.pinRed, 0); err != nil { return err } if err := d.SetLevel(d.pinGreen, 0); err != nil { return err } if err := d.SetLevel(d.pinBlue, 0); err != nil { return err } d.high = false return nil } // Toggle sets the led to the opposite of it's current state func (d *RgbLedDriver) Toggle() error { if d.State() { return d.Off() } return d.On() } // SetLevel sets the led to the specified color level func (d *RgbLedDriver) SetLevel(pin string, level byte) error { return d.pwmWrite(pin, level) } // SetRGB sets the Red Green Blue value of the LED. func (d *RgbLedDriver) SetRGB(r, g, b byte) error { d.redColor = r d.greenColor = g d.blueColor = b return d.On() } ================================================ FILE: drivers/gpio/rgb_led_driver_test.go ================================================ //nolint:forcetypeassert // ok here package gpio import ( "errors" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" ) var _ gobot.Driver = (*RgbLedDriver)(nil) func initTestRgbLedDriver() *RgbLedDriver { a := newGpioTestAdaptor() a.digitalWriteFunc = func(string, byte) error { return nil } a.pwmWriteFunc = func(string, byte) error { return nil } return NewRgbLedDriver(a, "1", "2", "3") } func TestNewRgbLedDriver(t *testing.T) { // arrange a := newGpioTestAdaptor() // act d := NewRgbLedDriver(a, "10", "20", "30") // assert assert.IsType(t, &RgbLedDriver{}, d) // assert: gpio.driver attributes require.NotNil(t, d.driver) assert.True(t, strings.HasPrefix(d.driverCfg.name, "RGBLED")) assert.Equal(t, a, d.connection) assert.NotNil(t, d.afterStart) assert.NotNil(t, d.beforeHalt) assert.NotNil(t, d.Commander) assert.NotNil(t, d.mutex) // assert: driver specific attributes assert.Equal(t, "10", d.RedPin()) assert.Equal(t, "20", d.GreenPin()) assert.Equal(t, "30", d.BluePin()) assert.Equal(t, "r=10, g=20, b=30", d.Pin()) assert.Equal(t, uint8(0), d.redColor) assert.Equal(t, uint8(0), d.greenColor) assert.Equal(t, uint8(0), d.blueColor) assert.False(t, d.high) } func TestNewRgbLedDriver_options(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithName() option, least one // option of this driver and one of another driver (which should lead to panic). Further tests for options can also // be done by call of "WithOption(val).apply(cfg)". // arrange const ( myName = "colored light" ) panicFunc := func() { NewRgbLedDriver(newGpioTestAdaptor(), "1", "2", "3", WithName("crazy"), aio.WithActuatorScaler(func(float64) int { return 0 })) } // act d := NewRgbLedDriver(newGpioTestAdaptor(), "1", "2", "3", WithName(myName)) // assert assert.Equal(t, myName, d.Name()) assert.PanicsWithValue(t, "'scaler option for analog actuators' can not be applied on 'crazy'", panicFunc) } func TestRgbLed_Commands(t *testing.T) { var err interface{} a := newGpioTestAdaptor() d := NewRgbLedDriver(a, "1", "2", "3") a.digitalWriteFunc = func(string, byte) error { return errors.New("write error") } a.pwmWriteFunc = func(string, byte) error { return errors.New("pwm error") } err = d.Command("Toggle")(nil) require.EqualError(t, err.(error), "pwm error") err = d.Command("On")(nil) require.EqualError(t, err.(error), "pwm error") err = d.Command("Off")(nil) require.EqualError(t, err.(error), "pwm error") err = d.Command("SetRGB")(map[string]interface{}{"r": 0xff, "g": 0xff, "b": 0xff}) require.EqualError(t, err.(error), "pwm error") } func TestRgbLedDriverToggle(t *testing.T) { d := initTestRgbLedDriver() _ = d.Off() _ = d.Toggle() assert.True(t, d.State()) _ = d.Toggle() assert.False(t, d.State()) } func TestRgbLedSetLevel(t *testing.T) { a := newGpioTestAdaptor() d := NewRgbLedDriver(a, "1", "2", "3") require.NoError(t, d.SetLevel("1", 150)) d = NewRgbLedDriver(a, "1", "2", "3") a.pwmWriteFunc = func(string, byte) error { return errors.New("pwm error") } require.EqualError(t, d.SetLevel("1", 150), "pwm error") } ================================================ FILE: drivers/gpio/servo_driver.go ================================================ package gpio import ( "fmt" "gobot.io/x/gobot/v2" ) // ServoDriver Represents a Servo type ServoDriver struct { *driver currentAngle byte } // NewServoDriver returns a new ServoDriver given a ServoWriter and pin. // // Supported options: // // "WithName" // // Adds the following API Commands: // // "Move" - See ServoDriver.Move // "Min" - See ServoDriver.ToMin // "Center" - See ServoDriver.ToCenter // "Max" - See ServoDriver.ToMax func NewServoDriver(a ServoWriter, pin string, opts ...interface{}) *ServoDriver { //nolint:forcetypeassert // no error return value, so there is no better way d := &ServoDriver{ driver: newDriver(a.(gobot.Connection), "Servo", append(opts, withPin(pin))...), } //nolint:forcetypeassert // ok here d.AddCommand("Move", func(params map[string]interface{}) interface{} { angle := byte(params["angle"].(float64)) return d.Move(angle) }) d.AddCommand("ToMin", func(_ map[string]interface{}) interface{} { return d.ToMin() }) d.AddCommand("ToCenter", func(_ map[string]interface{}) interface{} { return d.ToCenter() }) d.AddCommand("ToMax", func(_ map[string]interface{}) interface{} { return d.ToMax() }) return d } // Move sets the servo to the specified angle. Acceptable angles are 0-180 func (d *ServoDriver) Move(angle uint8) error { if angle > 180 { return fmt.Errorf("servo angle (%d) must be between 0-180", angle) } d.currentAngle = angle return d.servoWrite(d.driverCfg.pin, angle) } // Min sets the servo to it's minimum position func (d *ServoDriver) ToMin() error { return d.Move(0) } // Center sets the servo to it's center position func (d *ServoDriver) ToCenter() error { return d.Move(90) } // Max sets the servo to its maximum position func (d *ServoDriver) ToMax() error { return d.Move(180) } // Angle returns the current angle func (d *ServoDriver) Angle() uint8 { return d.currentAngle } ================================================ FILE: drivers/gpio/servo_driver_test.go ================================================ //nolint:forcetypeassert // ok here package gpio import ( "errors" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" ) var _ gobot.Driver = (*ServoDriver)(nil) func initTestServoDriver() *ServoDriver { return NewServoDriver(newGpioTestAdaptor(), "1") } func TestNewServoDriver(t *testing.T) { // arrange a := newGpioTestAdaptor() // act d := NewServoDriver(a, "10") // assert assert.IsType(t, &ServoDriver{}, d) // assert: gpio.driver attributes require.NotNil(t, d.driver) assert.True(t, strings.HasPrefix(d.driverCfg.name, "Servo")) assert.Equal(t, "10", d.driverCfg.pin) assert.Equal(t, a, d.connection) assert.NotNil(t, d.afterStart) assert.NotNil(t, d.beforeHalt) assert.NotNil(t, d.Commander) assert.NotNil(t, d.mutex) // assert: driver specific attributes assert.Equal(t, uint8(0), d.currentAngle) } func TestNewServoDriver_options(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithName() option, least one // option of this driver and one of another driver (which should lead to panic). Further tests for options can also // be done by call of "WithOption(val).apply(cfg)". // arrange const ( myName = "left wheel" ) panicFunc := func() { NewServoDriver(newGpioTestAdaptor(), "1", WithName("crazy"), aio.WithActuatorScaler(func(float64) int { return 0 })) } // act d := NewServoDriver(newGpioTestAdaptor(), "1", WithName(myName)) // assert assert.Equal(t, myName, d.Name()) assert.PanicsWithValue(t, "'scaler option for analog actuators' can not be applied on 'crazy'", panicFunc) } func TestServo_Commands(t *testing.T) { var err interface{} a := newGpioTestAdaptor() d := NewServoDriver(a, "1") a.servoWriteFunc = func(string, byte) error { return errors.New("pwm error") } err = d.Command("ToMin")(nil) require.EqualError(t, err.(error), "pwm error") err = d.Command("ToCenter")(nil) require.EqualError(t, err.(error), "pwm error") err = d.Command("ToMax")(nil) require.EqualError(t, err.(error), "pwm error") err = d.Command("Move")(map[string]interface{}{"angle": 100.0}) require.EqualError(t, err.(error), "pwm error") } func TestServoMove(t *testing.T) { d := initTestServoDriver() _ = d.Move(100) assert.Equal(t, uint8(100), d.currentAngle) err := d.Move(200) require.EqualError(t, err, "servo angle (200) must be between 0-180") } func TestServoMin(t *testing.T) { d := initTestServoDriver() _ = d.ToMin() assert.Equal(t, uint8(0), d.currentAngle) assert.Equal(t, d.currentAngle, d.Angle()) } func TestServoMax(t *testing.T) { d := initTestServoDriver() _ = d.ToMax() assert.Equal(t, uint8(180), d.currentAngle) } func TestServoCenter(t *testing.T) { d := initTestServoDriver() _ = d.ToCenter() assert.Equal(t, uint8(90), d.currentAngle) } ================================================ FILE: drivers/gpio/stepper_driver.go ================================================ package gpio import ( "fmt" "log" "math" "os" "os/signal" "strconv" "strings" "sync" "time" "gobot.io/x/gobot/v2" ) const ( stepperDriverDebug = false // StepperDriverForward is to set the stepper to run in forward direction (e.g. turn clock wise) StepperDriverForward = "forward" // StepperDriverBackward is to set the stepper to run in backward direction (e.g. turn counter clock wise) StepperDriverBackward = "backward" ) type phase [][4]byte // StepperModes to decide on Phase and Stepping var StepperModes = struct { SinglePhaseStepping phase DualPhaseStepping phase HalfStepping phase }{ // 1 cycle = 4 steps with lesser torque SinglePhaseStepping: phase{ {1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}, }, // 1 cycle = 4 steps with higher torque and current DualPhaseStepping: phase{ {1, 0, 0, 1}, {1, 1, 0, 0}, {0, 1, 1, 0}, {0, 0, 1, 1}, }, // 1 cycle = 8 steps with lesser torque than full stepping HalfStepping: phase{ {1, 0, 0, 1}, {1, 0, 0, 0}, {1, 1, 0, 0}, {0, 1, 0, 0}, {0, 1, 1, 0}, {0, 0, 1, 0}, {0, 0, 1, 1}, {0, 0, 0, 1}, }, } // StepperDriver is a common driver for stepper motors. It supports 3 different stepping modes. type StepperDriver struct { *driver pins [4]string phase phase stepsPerRev float32 stepperDebug bool speedRpm uint direction string skipStepErrors bool haltIfRunning bool // stop automatically if run is called disabled bool valueMutex *sync.Mutex // to ensure that read and write of values do not interfere stepFunc func() error sleepFunc func() error stepNum int stopAsynchRunFunc func(bool) error } // NewStepperDriver returns a new StepperDriver given a DigitalWriter // Pins - To which the stepper is connected // Phase - Defined by StepperModes {SinglePhaseStepping, DualPhaseStepping, HalfStepping} // Steps - No of steps per revolution of Stepper motor // // Supported options: // // "WithName" func NewStepperDriver( a DigitalWriter, pins [4]string, phase phase, stepsPerRev uint, opts ...interface{}, ) *StepperDriver { if stepsPerRev <= 0 { panic("steps per revolution needs to be greater than zero") } //nolint:forcetypeassert // no error return value, so there is no better way d := &StepperDriver{ driver: newDriver(a.(gobot.Connection), "Stepper", opts...), pins: pins, phase: phase, stepsPerRev: float32(stepsPerRev), stepperDebug: stepperDriverDebug, skipStepErrors: false, haltIfRunning: true, direction: StepperDriverForward, stepNum: 0, speedRpm: 1, valueMutex: &sync.Mutex{}, } d.speedRpm = d.MaxSpeed() d.stepFunc = d.phasedStepping d.sleepFunc = d.sleepOuputs d.beforeHalt = d.shutdown //nolint:forcetypeassert // ok here d.AddCommand("MoveDeg", func(params map[string]interface{}) interface{} { degs, _ := strconv.Atoi(params["degs"].(string)) return d.MoveDeg(degs) }) //nolint:forcetypeassert // ok here d.AddCommand("Move", func(params map[string]interface{}) interface{} { steps, _ := strconv.Atoi(params["steps"].(string)) return d.Move(steps) }) d.AddCommand("Step", func(_ map[string]interface{}) interface{} { return d.Move(1) }) d.AddCommand("Run", func(_ map[string]interface{}) interface{} { return d.Run() }) d.AddCommand("Sleep", func(_ map[string]interface{}) interface{} { return d.Sleep() }) d.AddCommand("Stop", func(_ map[string]interface{}) interface{} { return d.Stop() }) d.AddCommand("Halt", func(_ map[string]interface{}) interface{} { return d.Halt() }) return d } // Move moves the motor for given number of steps. func (d *StepperDriver) Move(stepsToMove int) error { d.mutex.Lock() defer d.mutex.Unlock() if err := d.stepAsynch(float64(stepsToMove)); err != nil { // something went wrong with preparation return err } err := d.stopAsynchRunFunc(false) // wait to finish with err or nil d.stopAsynchRunFunc = nil return err } // MoveDeg moves the motor given number of degrees at current speed. Negative values cause to move backward. func (d *StepperDriver) MoveDeg(degs int) error { d.mutex.Lock() defer d.mutex.Unlock() stepsToMove := float64(degs) * float64(d.stepsPerRev) / 360 if err := d.stepAsynch(stepsToMove); err != nil { // something went wrong with preparation return err } err := d.stopAsynchRunFunc(false) // wait to finish with err or nil d.stopAsynchRunFunc = nil return err } // Run runs the stepper continuously. Stop needs to be done with call Stop(). func (d *StepperDriver) Run() error { d.mutex.Lock() defer d.mutex.Unlock() return d.stepAsynch(float64(math.MaxInt) + 1) } // IsMoving returns a bool stating whether motor is currently in motion func (d *StepperDriver) IsMoving() bool { return d.stopAsynchRunFunc != nil } // Stop running the stepper func (d *StepperDriver) Stop() error { if d.stopAsynchRunFunc == nil { return fmt.Errorf("'%s' is not yet started", d.driverCfg.name) } err := d.stopAsynchRunFunc(true) d.stopAsynchRunFunc = nil return err } // Sleep release all pins to the same output level, so no current is consumed anymore. func (d *StepperDriver) Sleep() error { return d.sleepFunc() } // SetDirection sets the direction in which motor should be moving, default is forward. // Changing the direction affects the next step, also for asynchronous running. func (d *StepperDriver) SetDirection(direction string) error { direction = strings.ToLower(direction) if direction != StepperDriverForward && direction != StepperDriverBackward { return fmt.Errorf("invalid direction '%s'. Value should be '%s' or '%s'", direction, StepperDriverForward, StepperDriverBackward) } // ensure that write of variable can not interfere with read in step() d.valueMutex.Lock() defer d.valueMutex.Unlock() d.direction = direction return nil } // MaxSpeed gives the max RPM of motor // max. speed is limited by: // * motor friction, inertia and inductance, load inertia // * full step rate is normally below 1000 per second (1kHz), typically not more than ~400 per second // * mostly not more than 1000-2000rpm (20-40 revolutions per second) are possible // * higher values can be achieved only by ramp-up the velocity // * duration of GPIO write (PI1 can reach up to 70kHz, typically 20kHz, so this is most likely not the limiting factor) // * the hardware driver, to force the high current transitions for the max. speed // * there are CNC steppers with 1000..20.000 steps per revolution, which works with faster step rates (e.g. 200kHz) func (d *StepperDriver) MaxSpeed() uint { const maxStepsPerSecond = 700 // a typical value for a normal, lightly loaded motor return uint(float32(60*maxStepsPerSecond) / d.stepsPerRev) } // SetSpeed sets the rpm for the next move or run. A valid value is between 1 and MaxSpeed(). // The run needs to be stopped and called again after set this value. func (d *StepperDriver) SetSpeed(rpm uint) error { var err error if rpm <= 0 { rpm = 0 err = fmt.Errorf("RPM (%d) cannot be a zero or negative value", rpm) } maxRpm := d.MaxSpeed() if rpm > maxRpm { rpm = maxRpm err = fmt.Errorf("RPM (%d) cannot be greater then maximal value %d", rpm, maxRpm) } d.valueMutex.Lock() defer d.valueMutex.Unlock() d.speedRpm = rpm return err } // CurrentStep gives the current step of motor func (d *StepperDriver) CurrentStep() int { // ensure that read can not interfere with write in step() d.valueMutex.Lock() defer d.valueMutex.Unlock() return d.stepNum } // SetHaltIfRunning with the given value. Normally a call of Run() returns an error if already running. If set this // to true, the next call of Run() cause a automatic stop before. func (d *StepperDriver) SetHaltIfRunning(val bool) { d.haltIfRunning = val } // shutdown the driver func (d *StepperDriver) shutdown() error { // stops the continuous motion of the stepper, if running return d.stopIfRunning() } func (d *StepperDriver) stepAsynch(stepsToMove float64) error { if d.disabled { return fmt.Errorf("'%s' is disabled and can not be running or moving", d.driverCfg.name) } // if running, return error or stop automatically if d.stopAsynchRunFunc != nil { if !d.haltIfRunning { return fmt.Errorf("'%s' already running or moving", d.driverCfg.name) } d.debug("stop former run forcefully") if err := d.stopAsynchRunFunc(true); err != nil { d.stopAsynchRunFunc = nil return err } } // prepare stepping behavior stepsLeft := uint64(math.Abs(stepsToMove)) if stepsLeft == 0 { return fmt.Errorf("no steps to do for '%s'", d.driverCfg.name) } // t [min] = steps [st] / (steps_per_revolution [st/u] * speed [u/min]) or // t [min] = steps [st] * delay_per_step [min/st], use safety factor 2 and a small offset of 100 ms // prepare this timeout outside of stop function to prevent data race with stepsLeft //nolint:gosec // TODO: fix later stopTimeout := time.Duration(2*stepsLeft)*d.getDelayPerStep() + 100*time.Millisecond endlessMovement := false if stepsLeft > math.MaxInt { stopTimeout = 100 * time.Millisecond endlessMovement = true } else { d.direction = "forward" if stepsToMove < 0 { d.direction = "backward" } } // prepare new asynchronous stepping onceDoneChan := make(chan struct{}) runStopChan := make(chan struct{}) runErrChan := make(chan error) sigChan := make(chan os.Signal, 1) signal.Notify(sigChan, os.Interrupt) d.stopAsynchRunFunc = func(forceStop bool) error { defer func() { d.debug("RUN: cleanup stop channel") if runStopChan != nil { close(runStopChan) } runStopChan = nil d.debug("STOP: cleanup err channel") if runErrChan != nil { close(runErrChan) } runErrChan = nil d.debug("STOP: cleanup done") }() d.debug("STOP: wait for once done") <-onceDoneChan // wait for the first step was called // send stop for endless movement or a forceful stop happen if endlessMovement || forceStop { d.debug("STOP: send stop channel") runStopChan <- struct{}{} } if !endlessMovement && forceStop { // do not wait if an normal movement was stopped forcefully log.Printf("'%s' was forcefully stopped\n", d.driverCfg.name) return nil } // wait for go routine is finished and cleanup d.debug(fmt.Sprintf("STOP: wait %s for err channel", stopTimeout)) select { case err := <-runErrChan: return err case <-time.After(stopTimeout): return fmt.Errorf("'%s' was not finished in %s", d.driverCfg.name, stopTimeout) } } d.debug(fmt.Sprintf("going to start go routine - endless=%t, steps=%d", endlessMovement, stepsLeft)) go func(name string) { var err error var onceDone bool defer func() { // some cases here: // * stop by stop channel: error should be send as nil // * count of steps reached: error should be send as nil // * write error occurred // * for Run(): caller needs to send stop channel and read the error // * for Move(): caller waits for the error, but don't send stop channel // d.debug(fmt.Sprintf("RUN: write '%v' to err channel", err)) runErrChan <- err }() for stepsLeft > 0 { select { case <-sigChan: d.debug("RUN: OS signal received") err = fmt.Errorf("OS signal received") return case <-runStopChan: d.debug("RUN: stop channel received") return default: if err == nil { err = d.stepFunc() if err != nil { if d.skipStepErrors { fmt.Printf("step skipped for '%s': %v\n", name, err) err = nil } else { d.debug("RUN: write error occurred") } } if !onceDone { close(onceDoneChan) // to inform that we are ready for stop now onceDone = true d.debug("RUN: once done") } if !endlessMovement { if err != nil { return } stepsLeft-- } } } } }(d.driverCfg.name) return nil } // getDelayPerStep gives the delay per step // formula: delay_per_step [min] = 1/(steps_per_revolution * speed [rpm]) func (d *StepperDriver) getDelayPerStep() time.Duration { // considering a max. speed of 1000 rpm and max. 1000 steps per revolution, a microsecond resolution is needed // if the motor or application needs bigger values, switch to nanosecond is needed return time.Duration(60*1000*1000/(d.stepsPerRev*float32(d.speedRpm))) * time.Microsecond } // phasedStepping moves the motor one step with the configured speed and direction. The speed can be adjusted // by SetSpeed() and the direction can be changed by SetDirection() asynchronously. func (d *StepperDriver) phasedStepping() error { // ensure that read and write of variables (direction, stepNum) can not interfere d.valueMutex.Lock() defer d.valueMutex.Unlock() oldStepNum := d.stepNum if d.direction == StepperDriverForward { d.stepNum++ } else { d.stepNum-- } if d.stepNum >= int(d.stepsPerRev) { d.stepNum = 0 } else if d.stepNum < 0 { d.stepNum = int(d.stepsPerRev) - 1 } r := int(math.Abs(float64(d.stepNum))) % len(d.phase) for i, v := range d.phase[r] { if err := d.digitalWrite(d.pins[i], v); err != nil { d.stepNum = oldStepNum return err } } delay := d.getDelayPerStep() time.Sleep(delay) return nil } func (d *StepperDriver) sleepOuputs() error { for _, pin := range d.pins { if err := d.digitalWrite(pin, 0); err != nil { return err } } return nil } // stopIfRunning stop the stepper if moving or running func (d *StepperDriver) stopIfRunning() error { // stops the continuous motion of the stepper, if running if d.stopAsynchRunFunc == nil { return nil } err := d.stopAsynchRunFunc(true) d.stopAsynchRunFunc = nil return err } func (d *StepperDriver) debug(text string) { if d.stepperDebug { fmt.Println(text) } } ================================================ FILE: drivers/gpio/stepper_driver_test.go ================================================ package gpio import ( "fmt" "log" "strings" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2/drivers/aio" ) func initTestStepperDriverWithStubbedAdaptor() (*StepperDriver, *gpioTestAdaptor) { const stepsPerRev = 32 a := newGpioTestAdaptor() d := NewStepperDriver(a, [4]string{"7", "11", "13", "15"}, StepperModes.DualPhaseStepping, stepsPerRev) return d, a } func TestNewStepperDriver(t *testing.T) { // arrange const stepsPerRev = 32 a := newGpioTestAdaptor() // act d := NewStepperDriver(a, [4]string{"7", "11", "13", "15"}, StepperModes.DualPhaseStepping, stepsPerRev) // assert assert.IsType(t, &StepperDriver{}, d) // assert: gpio.driver attributes require.NotNil(t, d.driver) assert.True(t, strings.HasPrefix(d.driverCfg.name, "Stepper")) assert.Equal(t, a, d.connection) require.NoError(t, d.afterStart()) require.NoError(t, d.beforeHalt()) assert.NotNil(t, d.Commander) assert.NotNil(t, d.mutex) // assert: driver specific attributes assert.Equal(t, "forward", d.direction) assert.Equal(t, StepperModes.DualPhaseStepping, d.phase) assert.InDelta(t, float32(stepsPerRev), d.stepsPerRev, 0.0) assert.Equal(t, 0, d.stepNum) assert.Nil(t, d.stopAsynchRunFunc) } func TestNewStepperDriver_options(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithName() option, least one // option of this driver and one of another driver (which should lead to panic). Further tests for options can also // be done by call of "WithOption(val).apply(cfg)". // arrange const ( myName = "left wheel" ) panicFunc := func() { NewStepperDriver(newGpioTestAdaptor(), [4]string{"7", "11", "13", "15"}, StepperModes.DualPhaseStepping, 32, WithName("crazy"), aio.WithActuatorScaler(func(float64) int { return 0 })) } // act d := NewStepperDriver(newGpioTestAdaptor(), [4]string{"7", "11", "13", "15"}, StepperModes.DualPhaseStepping, 32, WithName(myName)) // assert assert.Equal(t, myName, d.Name()) assert.PanicsWithValue(t, "'scaler option for analog actuators' can not be applied on 'crazy'", panicFunc) } func TestStepperMove_IsMoving(t *testing.T) { const stepsPerRev = 32 tests := map[string]struct { inputSteps int noAutoStopIfRunning bool simulateAlreadyRunning bool simulateWriteErr bool wantWrites int wantSteps int wantMoving bool wantErr string }{ "move_forward": { inputSteps: 2, wantWrites: 8, wantSteps: 2, wantMoving: false, }, "move_more_forward": { inputSteps: 10, wantWrites: 40, wantSteps: 10, wantMoving: false, }, "move_forward_full_revolution": { inputSteps: stepsPerRev, wantWrites: 128, wantSteps: 0, // will be reset after each revision wantMoving: false, }, "move_backward": { inputSteps: -2, wantWrites: 8, wantSteps: stepsPerRev - 2, wantMoving: false, }, "move_more_backward": { inputSteps: -10, wantWrites: 40, wantSteps: stepsPerRev - 10, wantMoving: false, }, "move_backward_full_revolution": { inputSteps: -stepsPerRev, wantWrites: 128, wantSteps: 0, // will be reset after each revision wantMoving: false, }, "already_running_autostop": { inputSteps: 3, simulateAlreadyRunning: true, wantWrites: 12, wantSteps: 3, wantMoving: false, }, "error_already_running": { noAutoStopIfRunning: true, simulateAlreadyRunning: true, wantMoving: true, wantErr: "already running or moving", }, "error_no_steps": { inputSteps: 0, wantWrites: 0, wantSteps: 0, wantMoving: false, wantErr: "no steps to do", }, "error_write": { inputSteps: 1, simulateWriteErr: true, wantWrites: 0, wantMoving: false, wantErr: "write error", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, a := initTestStepperDriverWithStubbedAdaptor() defer func() { // for cleanup dangling channels if d.stopAsynchRunFunc != nil { err := d.stopAsynchRunFunc(true) require.NoError(t, err) } }() // arrange: different behavior d.haltIfRunning = !tc.noAutoStopIfRunning if tc.simulateAlreadyRunning { d.stopAsynchRunFunc = func(bool) error { log.Println("former run stopped"); return nil } } // arrange: writes a.written = nil // reset writes of Start() a.simulateWriteError = tc.simulateWriteErr // act err := d.Move(tc.inputSteps) // assert if tc.wantErr != "" { require.ErrorContains(t, err, tc.wantErr) } else { require.NoError(t, err) } assert.Equal(t, tc.wantSteps, d.stepNum) assert.Len(t, a.written, tc.wantWrites) assert.Equal(t, tc.wantMoving, d.IsMoving()) }) } } func TestStepperRun_IsMoving(t *testing.T) { tests := map[string]struct { noAutoStopIfRunning bool simulateAlreadyRunning bool simulateWriteErr bool wantMoving bool wantErr string }{ "run": { wantMoving: true, }, "error_write": { simulateWriteErr: true, wantMoving: true, }, "error_already_running": { noAutoStopIfRunning: true, simulateAlreadyRunning: true, wantMoving: true, wantErr: "already running or moving", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, a := initTestStepperDriverWithStubbedAdaptor() defer func() { // for cleanup dangling channels if d.stopAsynchRunFunc != nil { err := d.stopAsynchRunFunc(true) require.NoError(t, err) } }() // arrange: different behavior writeChan := make(chan struct{}) if tc.noAutoStopIfRunning { // in this case no write should be called close(writeChan) writeChan = nil d.haltIfRunning = false } else { d.haltIfRunning = true } if tc.simulateAlreadyRunning { d.stopAsynchRunFunc = func(bool) error { return nil } } // arrange: writes simWriteErr := tc.simulateWriteErr // to prevent data race in write function (go-called) var firstWriteDone bool a.digitalWriteFunc = func(string, byte) error { if firstWriteDone { return nil // to prevent to much output and write to channel } writeChan <- struct{}{} firstWriteDone = true if simWriteErr { return fmt.Errorf("write error") } return nil } // act err := d.Run() // assert if tc.wantErr != "" { require.ErrorContains(t, err, tc.wantErr) } else { require.NoError(t, err) } assert.Equal(t, tc.wantMoving, d.IsMoving()) if writeChan != nil { // wait until the first write was called and a little bit longer <-writeChan time.Sleep(10 * time.Millisecond) var asynchErr error if d.stopAsynchRunFunc != nil { asynchErr = d.stopAsynchRunFunc(false) d.stopAsynchRunFunc = nil } if tc.simulateWriteErr { require.Error(t, asynchErr) } else { require.NoError(t, asynchErr) } } }) } } func TestStepperStop_IsMoving(t *testing.T) { tests := map[string]struct { running bool wantErr string }{ "stop_running": { running: true, }, "errro_not_started": { running: false, wantErr: "is not yet started", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, _ := initTestStepperDriverWithStubbedAdaptor() if tc.running { require.NoError(t, d.Run()) require.True(t, d.IsMoving()) } // act err := d.Stop() // assert if tc.wantErr != "" { require.ErrorContains(t, err, tc.wantErr) } else { require.NoError(t, err) } assert.False(t, d.IsMoving()) }) } } func TestStepperHalt_IsMoving(t *testing.T) { tests := map[string]struct { running bool }{ "halt_running": { running: true, }, "halt_not_started": { running: false, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, _ := initTestStepperDriverWithStubbedAdaptor() if tc.running { require.NoError(t, d.Run()) require.True(t, d.IsMoving()) } // act err := d.Halt() // assert require.NoError(t, err) assert.False(t, d.IsMoving()) }) } } func TestStepperSetDirection(t *testing.T) { tests := map[string]struct { input string wantVal string wantErr string }{ "direction_forward": { input: "forward", wantVal: "forward", }, "direction_backward": { input: "backward", wantVal: "backward", }, "error_invalid_direction": { input: "reverse", wantVal: "forward", wantErr: "invalid direction 'reverse'", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, _ := initTestStepperDriverWithStubbedAdaptor() require.Equal(t, "forward", d.direction) // act err := d.SetDirection(tc.input) // assert if tc.wantErr != "" { require.ErrorContains(t, err, tc.wantErr) } else { require.NoError(t, err) } assert.Equal(t, tc.wantVal, d.direction) }) } } func TestStepperMaxSpeed(t *testing.T) { const delayForMaxSpeed = 1428 * time.Microsecond // 1/700Hz tests := map[string]struct { stepsPerRev float32 want uint }{ "maxspeed_for_20spr": { stepsPerRev: 20, want: 2100, }, "maxspeed_for_50spr": { stepsPerRev: 50, want: 840, }, "maxspeed_for_100spr": { stepsPerRev: 100, want: 420, }, "maxspeed_for_400spr": { stepsPerRev: 400, want: 105, }, "maxspeed_for_1000spr": { stepsPerRev: 1000, want: 42, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d := StepperDriver{stepsPerRev: tc.stepsPerRev} // act got := d.MaxSpeed() d.speedRpm = got got2 := d.getDelayPerStep() // assert assert.Equal(t, tc.want, got) assert.Equal(t, delayForMaxSpeed, got2) }) } } func TestStepperSetSpeed(t *testing.T) { const maxRpm = 1166 tests := map[string]struct { input uint want uint wantErr string }{ "below_minimum": { input: 0, want: 0, wantErr: "RPM (0) cannot be a zero or negative value", }, "minimum": { input: 1, want: 1, }, "maximum": { input: maxRpm, want: maxRpm, }, "above_maximum": { input: maxRpm + 1, want: maxRpm, wantErr: "cannot be greater then maximal value 1166", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, _ := initTestStepperDriverWithStubbedAdaptor() d.stepsPerRev = 36 // act err := d.SetSpeed(tc.input) // assert if tc.wantErr != "" { require.ErrorContains(t, err, tc.wantErr) } else { require.NoError(t, err) } assert.Equal(t, tc.want, d.speedRpm) }) } } ================================================ FILE: drivers/gpio/tm1638_driver.go ================================================ package gpio import ( "math" "strings" "gobot.io/x/gobot/v2" ) // Colors of the display const ( TM1638None = iota TM1638Red TM1638Green ) // Commands of the driver const ( TM1638DataCmd = 0x40 TM1638DispCtrl = 0x80 TM1638AddrCmd = 0xC0 TM1638WriteDisp = 0x00 TM1638ReadKeys = 0x02 TM1638FixedAddr = 0x04 ) // TM1638Driver is the driver for modules based on the TM1638, which has 8 7-segment displays, 8 LEDs and 8 buttons. // Buttons are not supported yet by this driver. // // Datasheet EN: https://retrocip.cz/files/tm1638.pdf // Datasheet CN: http://www.datasheetspdf.com/pdf/775356/TitanMicro/TM1638/1 // // Ported from the Arduino driver https://github.com/rjbatista/tm1638-library type TM1638Driver struct { *driver pinClock *DirectPinDriver pinData *DirectPinDriver pinStrobe *DirectPinDriver fonts map[string]byte } // NewTM1638Driver return a new TM1638Driver given a gobot.Connection and the clock, data and strobe pins // // Supported options: // // "WithName" func NewTM1638Driver(a gobot.Connection, clockPin, dataPin, strobePin string, opts ...interface{}) *TM1638Driver { d := &TM1638Driver{ driver: newDriver(a, "TM1638", opts...), pinClock: NewDirectPinDriver(a, clockPin), pinData: NewDirectPinDriver(a, dataPin), pinStrobe: NewDirectPinDriver(a, strobePin), fonts: NewTM1638Fonts(), } d.afterStart = d.initialize /* TODO : Add commands */ return d } // SetLED changes the color (TM1638None, TM1638Red, TM1638Green) of the specific LED func (d *TM1638Driver) SetLED(color byte, pos byte) error { if pos > 7 { return nil } return d.sendData((pos<<1)+1, color) } // SetDisplay cuts and sends a byte array to the display (without dots) func (d *TM1638Driver) SetDisplay(data []byte) error { minLength := int(math.Min(8, float64(len(data)))) for i := 0; i < minLength; i++ { if err := d.SendChar(byte(i), data[i], false); err != nil { return err } } return nil } // SetDisplayText cuts and sends a string to the display (without dots) func (d *TM1638Driver) SetDisplayText(text string) error { data := d.fromStringToByteArray(text) minLength := int(math.Min(8, float64(len(data)))) for i := 0; i < minLength; i++ { if err := d.SendChar(byte(i), data[i], false); err != nil { return err } } return nil } // SendChar sends one byte to the specific position in the display func (d *TM1638Driver) SendChar(pos byte, data byte, dot bool) error { if pos > 7 { return nil } var dotData byte if dot { dotData = TM1638DispCtrl } return d.sendData(pos<<1, data|(dotData)) } // AddFonts adds new custom fonts or modify the representation of existing ones func (d *TM1638Driver) AddFonts(fonts map[string]byte) { for k, v := range fonts { d.fonts[k] = v } } // ClearFonts removes all the fonts from the driver func (d *TM1638Driver) ClearFonts() { d.fonts = make(map[string]byte) } // initialize initializes the tm1638, it uses a SPI-like communication protocol func (d *TM1638Driver) initialize() error { if err := d.pinStrobe.On(); err != nil { return err } if err := d.pinClock.On(); err != nil { return err } if err := d.sendCommand(TM1638DataCmd); err != nil { return err } if err := d.sendCommand(TM1638DispCtrl | 8 | 7); err != nil { return err } if err := d.pinStrobe.Off(); err != nil { return err } if err := d.send(TM1638AddrCmd); err != nil { return err } for i := 0; i < 16; i++ { if err := d.send(TM1638WriteDisp); err != nil { return err } } return d.pinStrobe.On() } // fromStringToByteArray translates a string to a byte array with the corresponding representation // for the 7-segment LCD, return and empty character if the font is not available func (d *TM1638Driver) fromStringToByteArray(str string) []byte { chars := strings.Split(str, "") data := make([]byte, len(chars)) for index, char := range chars { if val, ok := d.fonts[char]; ok { data[index] = val } } return data } // sendData is an auxiliary function to send data to the TM1638 module func (d *TM1638Driver) sendData(address byte, data byte) error { if err := d.sendCommand(TM1638DataCmd | TM1638FixedAddr); err != nil { return err } if err := d.pinStrobe.Off(); err != nil { return err } if err := d.send(TM1638AddrCmd | address); err != nil { return err } if err := d.send(data); err != nil { return err } return d.pinStrobe.On() } // sendCommand is an auxiliary function to send commands to the TM1638 module func (d *TM1638Driver) sendCommand(cmd byte) error { if err := d.pinStrobe.Off(); err != nil { return err } if err := d.send(cmd); err != nil { return err } return d.pinStrobe.On() } // send writes data on the module func (d *TM1638Driver) send(data byte) error { for i := 0; i < 8; i++ { if err := d.pinClock.Off(); err != nil { return err } if (data & 1) > 0 { if err := d.pinData.On(); err != nil { return err } } else { if err := d.pinData.Off(); err != nil { return err } } data >>= 1 if err := d.pinClock.On(); err != nil { return err } } return nil } // NewTM1638Fonts returns a map with fonts and their corresponding byte for proper representation on the 7-segment LCD func NewTM1638Fonts() map[string]byte { return map[string]byte{ " ": 0x00, "!": 0x86, "'": 0x22, "#": 0x7E, "$": 0x6D, "%": 0x00, "&": 0x00, "\"": 0x02, "(": 0x30, ")": 0x06, "*": 0x63, "+": 0x00, ",": 0x04, "-": 0x40, ".": 0x80, "/": 0x52, "0": 0x3F, "1": 0x06, "2": 0x5B, "3": 0x4F, "4": 0x66, "5": 0x6D, "6": 0x7D, "7": 0x27, "8": 0x7F, "9": 0x6F, ":": 0x00, ";": 0x00, "<": 0x00, "=": 0x48, ">": 0x00, "?": 0x53, "@": 0x5F, "A": 0x77, "B": 0x7F, "C": 0x39, "D": 0x3F, "E": 0x79, "F": 0x71, "G": 0x3D, "H": 0x76, "I": 0x06, "J": 0x1F, "K": 0x69, "L": 0x38, "M": 0x15, "N": 0x37, "O": 0x3F, "P": 0x73, "Q": 0x67, "R": 0x31, "S": 0x6D, "T": 0x78, "U": 0x3E, "V": 0x2A, "W": 0x1D, "X": 0x76, "Y": 0x6E, "Z": 0x5B, "[": 0x39, "\\": 0x64, // (this can't be the last char on a line, even in comment or it'll concat) "]": 0x0F, "^": 0x00, "_": 0x08, "`": 0x20, "a": 0x5F, "b": 0x7C, "c": 0x58, "d": 0x5E, "e": 0x7B, "f": 0x31, "g": 0x6F, "h": 0x74, "i": 0x04, "j": 0x0E, "k": 0x75, "l": 0x30, "m": 0x55, "n": 0x54, "o": 0x5C, "p": 0x73, "q": 0x67, "r": 0x50, "s": 0x6D, "t": 0x78, "u": 0x1C, "v": 0x2A, "w": 0x1D, "x": 0x76, "y": 0x6E, "z": 0x47, "{": 0x46, "|": 0x06, "}": 0x70, "~": 0x01, } } ================================================ FILE: drivers/gpio/tm1638_driver_test.go ================================================ package gpio import ( "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" ) var _ gobot.Driver = (*TM1638Driver)(nil) func initTestTM1638Driver() *TM1638Driver { d, _ := initTestTM1638DriverWithStubbedAdaptor() return d } func initTestTM1638DriverWithStubbedAdaptor() (*TM1638Driver, *gpioTestAdaptor) { a := newGpioTestAdaptor() return NewTM1638Driver(a, "1", "2", "3"), a } func TestNewTM1638Driver(t *testing.T) { // arrange a := newGpioTestAdaptor() // act d := NewTM1638Driver(a, "10", "20", "30") // assert assert.IsType(t, &TM1638Driver{}, d) // assert: gpio.driver attributes require.NotNil(t, d.driver) assert.True(t, strings.HasPrefix(d.driverCfg.name, "TM1638")) assert.Equal(t, a, d.connection) assert.NotNil(t, d.afterStart) assert.NotNil(t, d.beforeHalt) assert.NotNil(t, d.Commander) assert.NotNil(t, d.mutex) // assert: driver specific attributes assert.NotNil(t, d.pinClock) assert.NotNil(t, d.pinData) assert.NotNil(t, d.pinStrobe) assert.NotNil(t, d.fonts) } func TestNewTM1638Driver_options(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithName() option, least one // option of this driver and one of another driver (which should lead to panic). Further tests for options can also // be done by call of "WithOption(val).apply(cfg)". // arrange const ( myName = "show rotation count" ) panicFunc := func() { NewTM1638Driver(newGpioTestAdaptor(), "1", "2", "3", WithName("crazy"), aio.WithActuatorScaler(func(float64) int { return 0 })) } // act d := NewTM1638Driver(newGpioTestAdaptor(), "1", "2", "3", WithName(myName)) // assert assert.Equal(t, myName, d.Name()) assert.PanicsWithValue(t, "'scaler option for analog actuators' can not be applied on 'crazy'", panicFunc) } func TestTM1638Start(t *testing.T) { // arrange d := initTestTM1638Driver() // act & assert: tests also initialize() require.NoError(t, d.Start()) } func TestTM1638FromStringToByteArray(t *testing.T) { d := initTestTM1638Driver() data := d.fromStringToByteArray("Hello World") assert.Equal(t, []byte{0x76, 0x7B, 0x30, 0x30, 0x5C, 0x00, 0x1D, 0x5C, 0x50, 0x30, 0x5E}, data) } func TestTM1638AddFonts(t *testing.T) { d := initTestTM1638Driver() d.AddFonts(map[string]byte{"µ": 0x1C, "ß": 0x7F}) data := d.fromStringToByteArray("µß") assert.Equal(t, []byte{0x1C, 0x7F}, data) } func TestTM1638ClearFonts(t *testing.T) { d := initTestTM1638Driver() d.ClearFonts() data := d.fromStringToByteArray("Hello World") assert.Equal(t, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, data) } ================================================ FILE: drivers/i2c/LICENSE ================================================ Copyright (c) 2013-2018 The Hybrid Group Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: drivers/i2c/README.md ================================================ # I2C This package provides drivers for [i2c](https://en.wikipedia.org/wiki/I%C2%B2C)devices. It must be used along with an adaptor such as [Tinker Board](https://gobot.io/documentation/platforms/asus/tinkerboard/) that supports the needed interfaces for i2c devices. ## Getting Started Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) ## Hardware Support Gobot has a extensible system for connecting to hardware devices. The following i2c devices are currently supported: - Adafruit 1109 2x16 RGB-LCD with 5 keys - Adafruit 2327 16-Channel PWM/Servo HAT Hat - Adafruit 2348 DC and Stepper Motor Hat - ADS1015 Analog to Digital Converter - ADS1115 Analog to Digital Converter - ADXL345 Digital Accelerometer - BH1750 Digital Luminosity/Lux/Light Sensor - BlinkM LED - BME280 Barometric Pressure/Temperature/Altitude/Humidity Sensor - BMP180 Barometric Pressure/Temperature/Altitude Sensor - BMP280 Barometric Pressure/Temperature/Altitude Sensor - BMP388 Barometric Pressure/Temperature/Altitude Sensor - DRV2605L Haptic Controller - Generic driver for read and write values to/from register address - Grove Digital Accelerometer - GrovePi Expansion Board - Grove RGB LCD - HMC6352 Compass - HMC5883L 3-Axis Digital Compass - INA3221 Voltage Monitor - JHD1313M1 LCD Display w/RGB Backlight - L3GD20H 3-Axis Gyroscope - LIDAR-Lite - MCP23017 Port Expander - MMA7660 3-Axis Accelerometer - MPL115A2 Barometric Pressure/Temperature - MPU6050 Accelerometer/Gyroscope - PCA9501 8-bit I/O port with interrupt, 2-kbit EEPROM - PCA953x LED Dimmer for PCA9530 (2-bit), PCA9533 (4-bit), PCA9531 (8-bit), PCA9532 (16-bit) - PCA9685 16-channel 12-bit PWM/Servo Driver - PCF8583 clock and calendar or event counter, 240 x 8-bit RAM - PCF8591 8-bit 4xA/D & 1xD/A converter - SHT2x Temperature/Humidity - SHT3x-D Temperature/Humidity - SSD1306 OLED Display Controller - TSL2561 Digital Luminosity/Lux/Light Sensor - Wii Nunchuck Controller - YL-40 Brightness/Temperature sensor, Potentiometer, analog input, analog output Driver More drivers are coming soon... ## Using A Different Bus or Address You can set a different I2C address or I2C bus than the default when initializing your I2C drivers by using optional parameters. Here is an example: ```go blinkm := i2c.NewBlinkMDriver(e, i2c.WithBus(0), i2c.WithAddress(0x09)) ``` ================================================ FILE: drivers/i2c/adafruit1109_driver.go ================================================ package i2c import ( "fmt" "strconv" "strings" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" ) const adafruit1109Debug = false type adafruit1109PortPin struct { port string pin uint8 } // Adafruit1109Driver is a driver for the 2x16 LCD display with RGB backlit and 5 keys from adafruit, designed for Pi. // The display is driven by the HD44780, and all is connected by i2c port expander MCP23017. // https://www.adafruit.com/product/1109 // // Have to implement DigitalWriter, DigitalReader interface type Adafruit1109Driver struct { *MCP23017Driver *gpio.HD44780Driver name string redPin adafruit1109PortPin greenPin adafruit1109PortPin bluePin adafruit1109PortPin selectPin adafruit1109PortPin upPin adafruit1109PortPin downPin adafruit1109PortPin leftPin adafruit1109PortPin rightPin adafruit1109PortPin rwPin adafruit1109PortPin rsPin adafruit1109PortPin enPin adafruit1109PortPin dataPinD4 adafruit1109PortPin dataPinD5 adafruit1109PortPin dataPinD6 adafruit1109PortPin dataPinD7 adafruit1109PortPin mcpStarted bool } // NewAdafruit1109Driver creates is a new driver for the 2x16 LCD display with RGB backlit and 5 keys. // // Because HD44780 and MCP23017 are already implemented in gobot, this is a wrapper for using existing implementation. // So, for the documentation of the parameters, have a look at this drivers. // // Tests are done with a Tinkerboard. func NewAdafruit1109Driver(a Connector, options ...func(Config)) *Adafruit1109Driver { options = append(options, WithMCP23017AutoIODirOff(1)) mcp := NewMCP23017Driver(a, options...) d := &Adafruit1109Driver{ name: gobot.DefaultName("Adafruit1109"), MCP23017Driver: mcp, redPin: adafruit1109PortPin{"A", 6}, greenPin: adafruit1109PortPin{"A", 7}, bluePin: adafruit1109PortPin{"B", 0}, selectPin: adafruit1109PortPin{"A", 0}, upPin: adafruit1109PortPin{"A", 3}, downPin: adafruit1109PortPin{"A", 2}, leftPin: adafruit1109PortPin{"A", 4}, rightPin: adafruit1109PortPin{"A", 1}, rwPin: adafruit1109PortPin{"B", 6}, rsPin: adafruit1109PortPin{"B", 7}, enPin: adafruit1109PortPin{"B", 5}, dataPinD4: adafruit1109PortPin{"B", 4}, dataPinD5: adafruit1109PortPin{"B", 3}, dataPinD6: adafruit1109PortPin{"B", 2}, dataPinD7: adafruit1109PortPin{"B", 1}, } // mapping for HD44780 to MCP23017 port and IO, 4-Bit data dataPins := gpio.HD44780DataPin{ D4: d.dataPinD4.String(), D5: d.dataPinD5.String(), D6: d.dataPinD6.String(), D7: d.dataPinD7.String(), } // rwPin := "B_6" not mapped in HD44780 driver // at test initialization, there seems rows and columns be switched // but inside the driver the row is used as row and col as column rows := 2 columns := 16 lcd := gpio.NewHD44780Driver(d, columns, rows, gpio.HD44780_4BITMODE, d.rsPin.String(), d.enPin.String(), dataPins, gpio.WithHD44780RWPin(d.rwPin.String())) d.HD44780Driver = lcd return d } // Connect implements the adaptor.Connector interface. // Haven't found any adaptor which implements this with more content. func (d *Adafruit1109Driver) Connect() error { return nil } // Finalize implements the adaptor.Connector interface. // Haven't found any adaptor which implements this with more content. func (d *Adafruit1109Driver) Finalize() error { return nil } // Name implements the gobot.Device interface func (d *Adafruit1109Driver) Name() string { return fmt.Sprintf("%s_%s_%s", d.name, d.MCP23017Driver.Name(), d.HD44780Driver.Name()) } // SetName implements the gobot.Device interface. func (d *Adafruit1109Driver) SetName(n string) { d.name = n } // Connection implements the gobot.Device interface. func (d *Adafruit1109Driver) Connection() gobot.Connection { return d.MCP23017Driver.Connection() } // Start implements the gobot.Device interface. func (d *Adafruit1109Driver) Start() error { d.debuglnf("## MCP.Start ##") if err := d.MCP23017Driver.Start(); err != nil { return err } d.mcpStarted = true // set all to output (inputs will be set by initButton) for pin := uint8(0); pin <= 7; pin++ { if err := d.SetPinMode(pin, "A", 0); err != nil { return err } if err := d.SetPinMode(pin, "B", 0); err != nil { return err } } // button pins are inputs, has inverse logic and needs pull up if err := d.adafruit1109InitButton(d.selectPin); err != nil { return err } if err := d.adafruit1109InitButton(d.upPin); err != nil { return err } if err := d.adafruit1109InitButton(d.downPin); err != nil { return err } if err := d.adafruit1109InitButton(d.leftPin); err != nil { return err } if err := d.adafruit1109InitButton(d.rightPin); err != nil { return err } // lets start with neutral background if err := d.SetRGB(true, true, true); err != nil { return err } // set rw pin to write if err := d.writePin(d.rwPin, 0x00); err != nil { return err } d.debuglnf("## HD.Start ##") return d.HD44780Driver.Start() } // Halt implements the gobot.Device interface. func (d *Adafruit1109Driver) Halt() error { // we try halt on each device, not stopping on the first error var errors []string d.debuglnf("## HD.Halt ##") if err := d.HD44780Driver.Halt(); err != nil { errors = append(errors, err.Error()) } d.debuglnf("## HD.Halt done ##: %v", errors) if d.mcpStarted { d.debuglnf("## MCP.Halt ##") // switch off the background light if err := d.SetRGB(false, false, false); err != nil { errors = append(errors, err.Error()) } // must be after HD44780Driver if err := d.MCP23017Driver.Halt(); err != nil { errors = append(errors, err.Error()) } } d.mcpStarted = false if len(errors) > 0 { return fmt.Errorf("'Halt' the driver %s", strings.Join(errors, ", ")) } d.debuglnf("## AD.Halt done without errors ##") return nil } // DigitalWrite implements the DigitalWriter interface // This is called by HD44780 driver to set one gpio output. We redirect the call to the i2c driver MCP23017. // The given id is the same as defined in dataPins and has the syntax "_". func (d *Adafruit1109Driver) DigitalWrite(id string, val byte) error { portio := adafruit1109ParseID(id) return d.writePin(portio, val) } // DigitalRead implements the DigitalReader interface // This is called by HD44780 driver to read one gpio input. We redirect the call to the i2c driver MCP23017. // The given id is the same as defined in dataPins and has the syntax "_". func (d *Adafruit1109Driver) DigitalRead(id string) (int, error) { portio := adafruit1109ParseID(id) uval, err := d.readPin(portio) if err != nil { return 0, err } return int(uval), err } // SetRGB sets the Red Green Blue value of backlit. // The MCP23017 variant don't support PWM and have inverted logic func (d *Adafruit1109Driver) SetRGB(r, g, b bool) error { d.debuglnf("## SetRGB %t, %t, %t ##", r, g, b) rio := d.redPin gio := d.greenPin bio := d.bluePin rval := uint8(0x1) gval := uint8(0x1) bval := uint8(0x1) if r { rval = 0x00 } if g { gval = 0x00 } if b { bval = 0x00 } if err := d.writePin(rio, rval); err != nil { return err } if err := d.writePin(gio, gval); err != nil { return err } if err := d.writePin(bio, bval); err != nil { return err } return nil } // SelectButton reads the state of the "select" button (1=pressed). func (d *Adafruit1109Driver) SelectButton() (uint8, error) { return d.readPin(d.selectPin) } // UpButton reads the state of the "up" button (1=pressed). func (d *Adafruit1109Driver) UpButton() (uint8, error) { return d.readPin(d.upPin) } // DownButton reads the state of the "down" button (1=pressed). func (d *Adafruit1109Driver) DownButton() (uint8, error) { return d.readPin(d.downPin) } // LeftButton reads the state of the "left" button (1=pressed). func (d *Adafruit1109Driver) LeftButton() (uint8, error) { return d.readPin(d.leftPin) } // RightButton reads the state of the "right" button (1=pressed). func (d *Adafruit1109Driver) RightButton() (uint8, error) { return d.readPin(d.rightPin) } func (d *Adafruit1109Driver) writePin(ap adafruit1109PortPin, val uint8) error { return d.WriteGPIO(ap.pin, ap.port, val) } func (d *Adafruit1109Driver) readPin(ap adafruit1109PortPin) (uint8, error) { return d.ReadGPIO(ap.pin, ap.port) } func (ap *adafruit1109PortPin) String() string { return fmt.Sprintf("%s_%d", ap.port, ap.pin) } func adafruit1109ParseID(id string) adafruit1109PortPin { items := strings.Split(id, "_") io := uint8(0) if io64, err := strconv.ParseUint(items[1], 10, 32); err == nil { io = uint8(io64) //nolint:gosec // TODO: fix later } return adafruit1109PortPin{port: items[0], pin: io} } func (d *Adafruit1109Driver) adafruit1109InitButton(p adafruit1109PortPin) error { // make an input if err := d.SetPinMode(p.pin, p.port, 1); err != nil { return err } // add pull up resistors if err := d.SetPullUp(p.pin, p.port, 1); err != nil { return err } // invert polarity if err := d.SetGPIOPolarity(p.pin, p.port, 1); err != nil { return err } return nil } func (d *Adafruit1109Driver) debuglnf(format string, p ...interface{}) { gobot.Debuglnf(adafruit1109Debug, format, p...) } ================================================ FILE: drivers/i2c/adafruit1109_driver_test.go ================================================ package i2c import ( "errors" "fmt" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) var _ gobot.Driver = (*Adafruit1109Driver)(nil) func initTestAdafruit1109WithStubbedAdaptor() (*Adafruit1109Driver, *i2cTestAdaptor) { adaptor := newI2cTestAdaptor() return NewAdafruit1109Driver(adaptor), adaptor } func TestNewAdafruit1109Driver(t *testing.T) { var di interface{} = NewAdafruit1109Driver(newI2cTestAdaptor()) d, ok := di.(*Adafruit1109Driver) if !ok { require.Fail(t, "NewAdafruit1109Driver() should have returned a *Adafruit1109Driver") } assert.NotNil(t, d.Driver) assert.NotNil(t, d.Connection()) assert.True(t, strings.HasPrefix(d.Name(), "Adafruit1109")) assert.Contains(t, d.Name(), "MCP23017") assert.Contains(t, d.Name(), "HD44780") assert.NotNil(t, d.MCP23017Driver) assert.NotNil(t, d.HD44780Driver) assert.NotNil(t, d.redPin) assert.NotNil(t, d.greenPin) assert.NotNil(t, d.bluePin) assert.NotNil(t, d.selectPin) assert.NotNil(t, d.upPin) assert.NotNil(t, d.downPin) assert.NotNil(t, d.leftPin) assert.NotNil(t, d.rightPin) assert.NotNil(t, d.rwPin) assert.NotNil(t, d.rsPin) assert.NotNil(t, d.enPin) assert.NotNil(t, d.dataPinD4) assert.NotNil(t, d.dataPinD5) assert.NotNil(t, d.dataPinD6) assert.NotNil(t, d.dataPinD7) } func TestAdafruit1109Connect(t *testing.T) { d, _ := initTestAdafruit1109WithStubbedAdaptor() require.NoError(t, d.Connect()) } func TestAdafruit1109Finalize(t *testing.T) { d, _ := initTestAdafruit1109WithStubbedAdaptor() require.NoError(t, d.Finalize()) } func TestAdafruit1109SetName(t *testing.T) { d, _ := initTestAdafruit1109WithStubbedAdaptor() d.SetName("foo") assert.Equal(t, "foo", d.name) } func TestAdafruit1109Start(t *testing.T) { d, _ := initTestAdafruit1109WithStubbedAdaptor() require.NoError(t, d.Start()) } func TestAdafruit1109StartWriteErr(t *testing.T) { d, adaptor := initTestAdafruit1109WithStubbedAdaptor() adaptor.i2cWriteImpl = func([]byte) (int, error) { return 0, errors.New("write error") } require.ErrorContains(t, d.Start(), "write error") } func TestAdafruit1109StartReadErr(t *testing.T) { d, adaptor := initTestAdafruit1109WithStubbedAdaptor() adaptor.i2cReadImpl = func([]byte) (int, error) { return 0, errors.New("read error") } require.ErrorContains(t, d.Start(), "MCP write-read: MCP write-ReadByteData(reg=0): read error") } func TestAdafruit1109Halt(t *testing.T) { d, _ := initTestAdafruit1109WithStubbedAdaptor() require.NoError(t, d.Halt()) // must be idempotent require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestAdafruit1109DigitalRead(t *testing.T) { tests := map[string]struct { read uint8 wantReg uint8 }{ "A_0": {read: 0x01, wantReg: 0x12}, "A_1": {read: 0x02, wantReg: 0x12}, "A_2": {read: 0x04, wantReg: 0x12}, "A_3": {read: 0x08, wantReg: 0x12}, "A_4": {read: 0x10, wantReg: 0x12}, "A_5": {read: 0x20, wantReg: 0x12}, "A_6": {read: 0x40, wantReg: 0x12}, "A_7": {read: 0x80, wantReg: 0x12}, "B_0": {read: 0x01, wantReg: 0x13}, "B_1": {read: 0x02, wantReg: 0x13}, "B_2": {read: 0x04, wantReg: 0x13}, "B_3": {read: 0x08, wantReg: 0x13}, "B_4": {read: 0x10, wantReg: 0x13}, "B_5": {read: 0x20, wantReg: 0x13}, "B_6": {read: 0x40, wantReg: 0x13}, "B_7": {read: 0x80, wantReg: 0x13}, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, a := initTestAdafruit1109WithStubbedAdaptor() _ = d.Start() a.written = []byte{} // reset writes of Start() and former test // arrange reads numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ b[0] = tc.read return len(b), nil } // act got, err := d.DigitalRead(name) // assert require.NoError(t, err) assert.Equal(t, 1, numCallsRead) assert.Len(t, a.written, 1) assert.Equal(t, tc.wantReg, a.written[0]) assert.Equal(t, 1, got) }) } } func TestAdafruit1109SelectButton(t *testing.T) { tests := map[string]struct { read uint8 want uint8 }{ "A0_not_pressed": {read: 0xFE, want: 0}, "A0_pressed": {read: 0x01, want: 1}, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, a := initTestAdafruit1109WithStubbedAdaptor() _ = d.Start() // arrange reads numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ b[0] = tc.read return len(b), nil } // act got, err := d.SelectButton() // assert require.NoError(t, err) assert.Equal(t, 1, numCallsRead) assert.Equal(t, tc.want, got) }) } } func TestAdafruit1109UpButton(t *testing.T) { tests := map[string]struct { read uint8 want uint8 }{ "A3_not_pressed": {read: 0xF7, want: 0}, "A3_pressed": {read: 0x08, want: 1}, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, a := initTestAdafruit1109WithStubbedAdaptor() _ = d.Start() // arrange reads numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ b[0] = tc.read return len(b), nil } // act got, err := d.UpButton() // assert require.NoError(t, err) assert.Equal(t, 1, numCallsRead) assert.Equal(t, tc.want, got) }) } } func TestAdafruit1109DownButton(t *testing.T) { tests := map[string]struct { read uint8 want uint8 }{ "A2_not_pressed": {read: 0xFB, want: 0}, "A2_pressed": {read: 0x04, want: 1}, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, a := initTestAdafruit1109WithStubbedAdaptor() _ = d.Start() // arrange reads numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ b[0] = tc.read return len(b), nil } // act got, err := d.DownButton() // assert require.NoError(t, err) assert.Equal(t, 1, numCallsRead) assert.Equal(t, tc.want, got) }) } } func TestAdafruit1109LeftButton(t *testing.T) { tests := map[string]struct { read uint8 want uint8 }{ "A4_not_pressed": {read: 0xEF, want: 0}, "A4_pressed": {read: 0x10, want: 1}, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, a := initTestAdafruit1109WithStubbedAdaptor() _ = d.Start() // arrange reads numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ b[0] = tc.read return len(b), nil } // act got, err := d.LeftButton() // assert require.NoError(t, err) assert.Equal(t, 1, numCallsRead) assert.Equal(t, tc.want, got) }) } } func TestAdafruit1109RightButton(t *testing.T) { tests := map[string]struct { read uint8 want uint8 }{ "A1_not_pressed": {read: 0xFD, want: 0}, "A1_pressed": {read: 0x02, want: 1}, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, a := initTestAdafruit1109WithStubbedAdaptor() _ = d.Start() // arrange reads numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ b[0] = tc.read return len(b), nil } // act got, err := d.RightButton() // assert require.NoError(t, err) assert.Equal(t, 1, numCallsRead) assert.Equal(t, tc.want, got) }) } } func TestAdafruit1109_parseID(t *testing.T) { // arrange ports := []string{"A", "B"} for _, port := range ports { for pin := uint8(0); pin <= 7; pin++ { id := fmt.Sprintf("%s_%d", port, pin) t.Run(id, func(t *testing.T) { // act got := adafruit1109ParseID(id) // assert assert.Equal(t, adafruit1109PortPin{port, pin}, got) }) } } } ================================================ FILE: drivers/i2c/adafruit2327_driver.go ================================================ package i2c import ( "gobot.io/x/gobot/v2" ) // Adafruit2327Driver is a driver for Adafruit 16-Channel PWM/Servo HAT & Bonnet - a Raspberry Pi add-on, based on // PCA9685. This driver just wraps the PCA9685Driver. // Stacking 62 of them is possible (addresses 0x40..0x7E), for controlling up to 992 servos. // datasheet: // https://cdn-learn.adafruit.com/downloads/pdf/adafruit-16-channel-pwm-servo-hat-for-raspberry-pi.pdf type Adafruit2327Driver struct { *PCA9685Driver } // NewAdafruit2327Driver initializes a new driver for PWM servos. // Params: // // c Connector - the Adaptor to use with this Driver // // Optional params: // // i2c.WithBus(int): bus to use with this driver // i2c.WithAddress(int): address to use with this driver func NewAdafruit2327Driver(c Connector, options ...func(Config)) *Adafruit2327Driver { pca := NewPCA9685Driver(c, options...) // the default address of the driver is already 0x40 pca.SetName(gobot.DefaultName("Adafruit2327ServoHat")) d := &Adafruit2327Driver{ PCA9685Driver: pca, } // TODO: add API funcs return d } // SetServoMotorFreq sets the frequency for the currently addressed PWM Servo HAT. func (d *Adafruit2327Driver) SetServoMotorFreq(freq float64) error { return d.SetPWMFreq(float32(freq)) } // SetServoMotorPulse is a convenience function to specify the 'tick' value, // between 0-4095, when the signal will turn on, and when it will turn off. func (d *Adafruit2327Driver) SetServoMotorPulse(channel byte, on, off int32) error { return d.SetPWM(int(channel), uint16(on), uint16(off)) //nolint:gosec // TODO: fix later } ================================================ FILE: drivers/i2c/adafruit2327_driver_test.go ================================================ package i2c import ( "errors" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) // this ensures that the implementation implements the gobot.Driver interface var _ gobot.Driver = (*Adafruit2327Driver)(nil) func initTestAdafruit2327WithStubbedAdaptor() (*Adafruit2327Driver, *i2cTestAdaptor) { a := newI2cTestAdaptor() d := NewAdafruit2327Driver(a) if err := d.Start(); err != nil { panic(err) } return d, a } func TestNewAdafruit2327Driver(t *testing.T) { // arrange & act d := NewAdafruit2327Driver(newI2cTestAdaptor()) // assert assert.IsType(t, &Adafruit2327Driver{}, d) assert.True(t, strings.HasPrefix(d.Name(), "Adafruit2327ServoHat")) assert.Equal(t, 0x40, d.defaultAddress) } func TestAdafruit2327Halt(t *testing.T) { // arrange d := NewAdafruit2327Driver(newI2cTestAdaptor()) // act, assert require.NoError(t, d.Halt()) // must be idempotent require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestAdafruit2327Options(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithBus() option and // least one of this driver. Further tests for options can also be done by call of "WithOption(val)(d)". // arrange & act d := NewAdafruit2327Driver(newI2cTestAdaptor(), WithBus(2)) // assert assert.Equal(t, 2, d.GetBusOrDefault(1)) } func TestAdafruit2327SetServoMotorFreq(t *testing.T) { // arrange d, a := initTestAdafruit2327WithStubbedAdaptor() a.written = []byte{} // reset writes of former test const freq = 60.0 // act err := d.SetServoMotorFreq(freq) // assert require.NoError(t, err) assert.Len(t, a.written, 9) // detailed test, see "TestPCA9685SetPWMFreq" } func TestAdafruit2327SetServoMotorFreqError(t *testing.T) { // arrange d, a := initTestAdafruit2327WithStubbedAdaptor() a.i2cWriteImpl = func([]byte) (int, error) { return 0, errors.New("write error") } const freq = 60.0 // act & assert require.ErrorContains(t, d.SetServoMotorFreq(freq), "write error") } func TestAdafruit2327SetServoMotorPulse(t *testing.T) { // arrange d, a := initTestAdafruit2327WithStubbedAdaptor() a.written = []byte{} // reset writes of former test const ( channel byte = 7 on int32 = 1234 off int32 = 4321 ) // act err := d.SetServoMotorPulse(channel, on, off) // assert require.NoError(t, err) assert.Len(t, a.written, 8) // detailed test, see "TestPCA9685SetPWM" } func TestAdafruit2327SetServoMotorPulseError(t *testing.T) { // arrange d, a := initTestAdafruit2327WithStubbedAdaptor() a.i2cWriteImpl = func([]byte) (int, error) { return 0, errors.New("write error") } const ( channel byte = 7 on int32 = 1234 off int32 = 4321 ) // act & assert require.ErrorContains(t, d.SetServoMotorPulse(channel, on, off), "write error") } ================================================ FILE: drivers/i2c/adafruit2348_driver.go ================================================ package i2c import ( "errors" "log" "sync" "time" "gobot.io/x/gobot/v2" ) const adafruit2348Debug = false // Set this to true to see debug output const ( adafruit2348MotorHatDefaultAddress = 0x60 adafruit2348StepperMicrosteps = 8 ) // Adafruit2348Direction declares a type for specification of the motor direction type Adafruit2348Direction int // Adafruit2348StepStyle declares a type for specification of the stepper motor rotation type Adafruit2348StepStyle int // constants for running the motor in different direction or release const ( Adafruit2348Forward Adafruit2348Direction = iota // 0 Adafruit2348Backward // 1 Adafruit2348Release // 2 ) // constants for running the stepper motor in different modes const ( Adafruit2348Single Adafruit2348StepStyle = iota // 0 Adafruit2348Double // 1 Adafruit2348Interleave // 2 Adafruit2348Microstep // 3 ) type adafruit2348DCMotor struct { pwmPin, in1Pin, in2Pin byte } type adafruit2348StepperMotor struct { pwmPinA, pwmPinB byte ain1, ain2 byte bin1, bin2 byte secPerStep float64 currentStep, revSteps int } // Adafruit2348Driver is a driver for Adafruit DC and Stepper Motor HAT - a Raspberry Pi add-on, based on PCA9685. // The HAT can drive up to 4 DC or 2 stepper motors with full PWM speed and direction control over I2C. // This driver wraps the PCA9685Driver. // Stacking 32 of them is possible (addresses 0x60..0x80), for controlling up to 64 stepper motors or 128 DC motors. // datasheet: // https://cdn-learn.adafruit.com/downloads/pdf/adafruit2348-dc-and-stepper-motor-hat-for-raspberry-pi.pdf type Adafruit2348Driver struct { *PCA9685Driver dcMotors []adafruit2348DCMotor stepperMotors []adafruit2348StepperMotor stepperMicrostepCurve []int step2coils map[int][]int32 stepperSpeedMutex *sync.Mutex } // NewAdafruit2348Driver initializes a new driver for DC and stepper motors. // Params: // // c Connector - the Adaptor to use with this Driver // // Optional params: // // i2c.WithBus(int): bus to use with this driver // i2c.WithAddress(int): address to use with this driver func NewAdafruit2348Driver(c Connector, options ...func(Config)) *Adafruit2348Driver { var dc []adafruit2348DCMotor var st []adafruit2348StepperMotor for i := 0; i < 4; i++ { switch i { case 0: dc = append(dc, adafruit2348DCMotor{pwmPin: 8, in1Pin: 10, in2Pin: 9}) st = append(st, adafruit2348StepperMotor{ pwmPinA: 8, pwmPinB: 13, ain1: 10, ain2: 9, bin1: 11, bin2: 12, revSteps: 200, secPerStep: 0.1, }) case 1: dc = append(dc, adafruit2348DCMotor{pwmPin: 13, in1Pin: 11, in2Pin: 12}) st = append(st, adafruit2348StepperMotor{ pwmPinA: 2, pwmPinB: 7, ain1: 4, ain2: 3, bin1: 5, bin2: 6, revSteps: 200, secPerStep: 0.1, }) case 2: dc = append(dc, adafruit2348DCMotor{pwmPin: 2, in1Pin: 4, in2Pin: 3}) case 3: dc = append(dc, adafruit2348DCMotor{pwmPin: 7, in1Pin: 5, in2Pin: 6}) } } // external given address must be able to override the default one o := append([]func(Config){WithAddress(adafruit2348MotorHatDefaultAddress)}, options...) pca := NewPCA9685Driver(c, o...) pca.SetName(gobot.DefaultName("Adafruit2348MotorHat")) d := &Adafruit2348Driver{ PCA9685Driver: pca, dcMotors: dc, stepperMotors: st, stepperMicrostepCurve: []int{0, 50, 98, 142, 180, 212, 236, 250, 255}, step2coils: map[int][]int32{ 0: {1, 0, 0, 0}, 1: {1, 1, 0, 0}, 2: {0, 1, 0, 0}, 3: {0, 1, 1, 0}, 4: {0, 0, 1, 0}, 5: {0, 0, 1, 1}, 6: {0, 0, 0, 1}, 7: {1, 0, 0, 1}, }, stepperSpeedMutex: &sync.Mutex{}, } // TODO: add API funcs return d } // SetDCMotorSpeed will set the appropriate pins to run the specified DC motor for the given speed. func (d *Adafruit2348Driver) SetDCMotorSpeed(dcMotor int, speed int32) error { return d.SetPWM(int(d.dcMotors[dcMotor].pwmPin), 0, uint16(speed*16)) //nolint:gosec // TODO: fix later } // RunDCMotor will set the appropriate pins to run the specified DC motor for the given direction. func (d *Adafruit2348Driver) RunDCMotor(dcMotor int, dir Adafruit2348Direction) error { switch dir { case Adafruit2348Forward: if err := d.setPin(d.dcMotors[dcMotor].in2Pin, 0); err != nil { return err } if err := d.setPin(d.dcMotors[dcMotor].in1Pin, 1); err != nil { return err } case Adafruit2348Backward: if err := d.setPin(d.dcMotors[dcMotor].in1Pin, 0); err != nil { return err } if err := d.setPin(d.dcMotors[dcMotor].in2Pin, 1); err != nil { return err } case Adafruit2348Release: if err := d.setPin(d.dcMotors[dcMotor].in1Pin, 0); err != nil { return err } if err := d.setPin(d.dcMotors[dcMotor].in2Pin, 0); err != nil { return err } } return nil } // SetStepperMotorSpeed sets the seconds-per-step for the given stepper motor. It is applied in the next cycle. func (d *Adafruit2348Driver) SetStepperMotorSpeed(stepperMotor int, rpm int) error { d.stepperSpeedMutex.Lock() defer d.stepperSpeedMutex.Unlock() revSteps := d.stepperMotors[stepperMotor].revSteps d.stepperMotors[stepperMotor].secPerStep = 60.0 / float64(revSteps*rpm) return nil } // Step will rotate the stepper motor the given number of steps, in the given direction and step style. func (d *Adafruit2348Driver) Step(motor, steps int, dir Adafruit2348Direction, style Adafruit2348StepStyle) error { d.stepperSpeedMutex.Lock() defer d.stepperSpeedMutex.Unlock() secPerStep := d.stepperMotors[motor].secPerStep var latestStep int var err error if style == Adafruit2348Interleave { secPerStep = secPerStep / 2.0 } if style == Adafruit2348Microstep { secPerStep /= float64(adafruit2348StepperMicrosteps) steps *= adafruit2348StepperMicrosteps } if adafruit2348Debug { log.Printf("[adafruit2348_driver] %f seconds per step", secPerStep) } for i := 0; i < steps; i++ { if latestStep, err = d.oneStep(motor, dir, style); err != nil { return err } time.Sleep(time.Duration(secPerStep) * time.Second) } // As documented in the Adafruit python driver: // This is an edge case, if we are in between full steps, keep going to end on a full step if style == Adafruit2348Microstep { for latestStep != 0 && latestStep != adafruit2348StepperMicrosteps { if latestStep, err = d.oneStep(motor, dir, style); err != nil { return err } time.Sleep(time.Duration(secPerStep) * time.Second) } } return nil } func (d *Adafruit2348Driver) oneStep(motor int, dir Adafruit2348Direction, style Adafruit2348StepStyle) (int, error) { pwmA := 255 pwmB := 255 // Determine the stepping procedure switch style { case Adafruit2348Single: if (d.stepperMotors[motor].currentStep / (adafruit2348StepperMicrosteps / 2) % 2) != 0 { // we're at an odd step if dir == Adafruit2348Forward { d.stepperMotors[motor].currentStep += adafruit2348StepperMicrosteps / 2 } else { d.stepperMotors[motor].currentStep -= adafruit2348StepperMicrosteps / 2 } } else { // go to next even step if dir == Adafruit2348Forward { d.stepperMotors[motor].currentStep += adafruit2348StepperMicrosteps } else { d.stepperMotors[motor].currentStep -= adafruit2348StepperMicrosteps } } case Adafruit2348Double: if (d.stepperMotors[motor].currentStep / (adafruit2348StepperMicrosteps / 2) % 2) == 0 { // we're at an even step, weird if dir == Adafruit2348Forward { d.stepperMotors[motor].currentStep += adafruit2348StepperMicrosteps / 2 } else { d.stepperMotors[motor].currentStep -= adafruit2348StepperMicrosteps / 2 } } else { // go to next odd step if dir == Adafruit2348Forward { d.stepperMotors[motor].currentStep += adafruit2348StepperMicrosteps } else { d.stepperMotors[motor].currentStep -= adafruit2348StepperMicrosteps } } case Adafruit2348Interleave: if dir == Adafruit2348Forward { d.stepperMotors[motor].currentStep += adafruit2348StepperMicrosteps / 2 } else { d.stepperMotors[motor].currentStep -= adafruit2348StepperMicrosteps / 2 } case Adafruit2348Microstep: if dir == Adafruit2348Forward { d.stepperMotors[motor].currentStep++ } else { d.stepperMotors[motor].currentStep-- } // go to next step and wrap around d.stepperMotors[motor].currentStep += adafruit2348StepperMicrosteps * 4 d.stepperMotors[motor].currentStep %= adafruit2348StepperMicrosteps * 4 pwmA = 0 pwmB = 0 currStep := d.stepperMotors[motor].currentStep switch { case currStep >= 0 && currStep < adafruit2348StepperMicrosteps: pwmA = d.stepperMicrostepCurve[adafruit2348StepperMicrosteps-currStep] pwmB = d.stepperMicrostepCurve[currStep] case currStep >= adafruit2348StepperMicrosteps && currStep < adafruit2348StepperMicrosteps*2: pwmA = d.stepperMicrostepCurve[currStep-adafruit2348StepperMicrosteps] pwmB = d.stepperMicrostepCurve[adafruit2348StepperMicrosteps*2-currStep] case currStep >= adafruit2348StepperMicrosteps*2 && currStep < adafruit2348StepperMicrosteps*3: pwmA = d.stepperMicrostepCurve[adafruit2348StepperMicrosteps*3-currStep] pwmB = d.stepperMicrostepCurve[currStep-adafruit2348StepperMicrosteps*2] case currStep >= adafruit2348StepperMicrosteps*3 && currStep < adafruit2348StepperMicrosteps*4: pwmA = d.stepperMicrostepCurve[currStep-adafruit2348StepperMicrosteps*3] pwmB = d.stepperMicrostepCurve[adafruit2348StepperMicrosteps*4-currStep] } } // switch // go to next 'step' and wrap around d.stepperMotors[motor].currentStep += adafruit2348StepperMicrosteps * 4 d.stepperMotors[motor].currentStep %= adafruit2348StepperMicrosteps * 4 // only really used for microstepping, otherwise always on! //nolint:gosec // TODO: fix later if err := d.SetPWM(int(d.stepperMotors[motor].pwmPinA), 0, uint16(pwmA*16)); err != nil { return 0, err } //nolint:gosec // TODO: fix later if err := d.SetPWM(int(d.stepperMotors[motor].pwmPinB), 0, uint16(pwmB*16)); err != nil { return 0, err } var coils []int32 currStep := d.stepperMotors[motor].currentStep if style == Adafruit2348Microstep { switch { case currStep >= 0 && currStep < adafruit2348StepperMicrosteps: coils = []int32{1, 1, 0, 0} case currStep >= adafruit2348StepperMicrosteps && currStep < adafruit2348StepperMicrosteps*2: coils = []int32{0, 1, 1, 0} case currStep >= adafruit2348StepperMicrosteps*2 && currStep < adafruit2348StepperMicrosteps*3: coils = []int32{0, 0, 1, 1} case currStep >= adafruit2348StepperMicrosteps*3 && currStep < adafruit2348StepperMicrosteps*4: coils = []int32{1, 0, 0, 1} } } else { // step-2-coils is initialized in init() coils = d.step2coils[(currStep / (adafruit2348StepperMicrosteps / 2))] } if adafruit2348Debug { log.Printf("[adafruit2348_driver] currStep: %d, index into step2coils: %d\n", currStep, (currStep / (adafruit2348StepperMicrosteps / 2))) log.Printf("[adafruit2348_driver] coils state = %v", coils) } if err := d.setPin(d.stepperMotors[motor].ain2, coils[0]); err != nil { return 0, err } if err := d.setPin(d.stepperMotors[motor].bin1, coils[1]); err != nil { return 0, err } if err := d.setPin(d.stepperMotors[motor].ain1, coils[2]); err != nil { return 0, err } if err := d.setPin(d.stepperMotors[motor].bin2, coils[3]); err != nil { return 0, err } return d.stepperMotors[motor].currentStep, nil } func (d *Adafruit2348Driver) setPin(pin byte, value int32) error { if value == 0 { return d.SetPWM(int(pin), 0, 4096) } if value == 1 { return d.SetPWM(int(pin), 4096, 0) } return errors.New("invalid pin") } ================================================ FILE: drivers/i2c/adafruit2348_driver_test.go ================================================ package i2c import ( "errors" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) // this ensures that the implementation implements the gobot.Driver interface var _ gobot.Driver = (*Adafruit2348Driver)(nil) func initTestAdafruit2348WithStubbedAdaptor() (*Adafruit2348Driver, *i2cTestAdaptor) { a := newI2cTestAdaptor() d := NewAdafruit2348Driver(a) if err := d.Start(); err != nil { panic(err) } return d, a } func TestNewAdafruit2348Driver(t *testing.T) { // arrange & act d := NewAdafruit2348Driver(newI2cTestAdaptor()) // assert assert.IsType(t, &Adafruit2348Driver{}, d) assert.True(t, strings.HasPrefix(d.Name(), "Adafruit2348MotorHat")) assert.Equal(t, 0x40, d.defaultAddress) // the default address of PCA9685 driver assert.Equal(t, 0x60, d.GetAddressOrDefault(d.defaultAddress)) // the really used address } func TestAdafruit2348Halt(t *testing.T) { // arrange d := NewAdafruit2348Driver(newI2cTestAdaptor()) // act, assert require.NoError(t, d.Halt()) // must be idempotent require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestAdafruit2348Options(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithBus() option and // least one of this driver. Further tests for options can also be done by call of "WithOption(val)(d)". // arrange & act d := NewAdafruit2348Driver(newI2cTestAdaptor(), WithBus(2), WithAddress(0x45)) // assert assert.Equal(t, 2, d.GetBusOrDefault(1)) assert.Equal(t, 0x45, d.GetAddressOrDefault(2)) } func TestAdafruit2348SetDCMotorSpeed(t *testing.T) { // arrange d, a := initTestAdafruit2348WithStubbedAdaptor() a.written = []byte{} // reset writes of former test const ( dcMotor = 1 speed = 255 ) // act err := d.SetDCMotorSpeed(dcMotor, speed) // assert require.NoError(t, err) assert.Len(t, a.written, 8) // detailed test, see "TestPCA9685SetPWM" } func TestAdafruit2348SetDCMotorSpeedError(t *testing.T) { // arrange d, a := initTestAdafruit2348WithStubbedAdaptor() a.i2cWriteImpl = func([]byte) (int, error) { return 0, errors.New("write error") } // act & assert require.ErrorContains(t, d.SetDCMotorSpeed(1, 255), "write error") } func TestAdafruit2348RunDCMotor(t *testing.T) { // arrange d, _ := initTestAdafruit2348WithStubbedAdaptor() const dcMotor = 1 // act & assert require.NoError(t, d.RunDCMotor(dcMotor, Adafruit2348Forward)) require.NoError(t, d.RunDCMotor(dcMotor, Adafruit2348Backward)) require.NoError(t, d.RunDCMotor(dcMotor, Adafruit2348Release)) } func TestAdafruit2348RunDCMotorError(t *testing.T) { // arrange d, a := initTestAdafruit2348WithStubbedAdaptor() a.i2cWriteImpl = func([]byte) (int, error) { return 0, errors.New("write error") } const dcMotor = 1 // act & assert require.ErrorContains(t, d.RunDCMotor(dcMotor, Adafruit2348Forward), "write error") require.ErrorContains(t, d.RunDCMotor(dcMotor, Adafruit2348Backward), "write error") require.ErrorContains(t, d.RunDCMotor(dcMotor, Adafruit2348Release), "write error") } func TestAdafruit2348SetStepperMotorSpeed(t *testing.T) { // arrange d, _ := initTestAdafruit2348WithStubbedAdaptor() const ( stepperMotor = 1 rpm = 30 ) // act & assert require.NoError(t, d.SetStepperMotorSpeed(stepperMotor, rpm)) assert.InDelta(t, 0.01, d.stepperMotors[stepperMotor].secPerStep, 0.0) // 60/(revSteps*rpm), revSteps=200 } func TestAdafruit2348StepperSingleStep(t *testing.T) { // arrange d, _ := initTestAdafruit2348WithStubbedAdaptor() const ( stepperMotor = 0 steps = 50 back = 1 single = 0 ) // act err := d.Step(stepperMotor, steps, back, single) // assert require.NoError(t, err) } func TestAdafruit2348StepperDoubleStep(t *testing.T) { // arrange d, _ := initTestAdafruit2348WithStubbedAdaptor() const ( stepperMotor = 0 steps = 50 back = 1 double = 1 ) // act err := d.Step(stepperMotor, steps, back, double) // assert require.NoError(t, err) } func TestAdafruit2348StepperInterleaveStep(t *testing.T) { // arrange d, _ := initTestAdafruit2348WithStubbedAdaptor() const ( stepperMotor = 0 steps = 50 back = 1 interleave = 2 ) // act err := d.Step(stepperMotor, steps, back, interleave) // assert require.NoError(t, err) } func TestAdafruit2348StepperMicroStep(t *testing.T) { // arrange d, _ := initTestAdafruit2348WithStubbedAdaptor() const ( stepperMotor = 0 steps = 50 back = 1 micro = 3 ) // act err := d.Step(stepperMotor, steps, back, micro) // assert require.NoError(t, err) } ================================================ FILE: drivers/i2c/ads1x15_driver.go ================================================ package i2c import ( "fmt" "log" "math" "sort" "strconv" "time" ) const ads1x15DefaultAddress = 0x48 const ( ads1x15Debug = false ads1x15WaitMaxCount = 200 ads1x15FullScaleValue = 0x7FFF // same as 32768, 1<<15 or 64 ) const ( // Address pointer registers ads1x15PointerConversion = 0x00 ads1x15PointerConfig = 0x01 ads1x15PointerLowThreshold = 0x02 ads1x15PointerHighThreshold = 0x03 // Values for config register ads1x15ConfigCompQueDisable = 0x0003 ads1x15ConfigCompLatching = 0x0004 ads1x15ConfigCompActiveHigh = 0x0008 ads1x15ConfigCompWindow = 0x0010 ads1x15ConfigModeContinuous = 0x0000 ads1x15ConfigModeSingle = 0x0100 // single shot mode ads1x15ConfigOsSingle = 0x8000 // write: set to start a single-conversion, read: wait for finished ads1x15ConfigMuxOffset = 12 ads1x15ConfigPgaOffset = 9 ) type ads1x15ChanCfg struct { gain int dataRate int } // ADS1x15Driver is the Gobot driver for the ADS1015/ADS1115 ADC // datasheet: // https://www.ti.com/lit/gpn/ads1115 // // reference implementations: // * https://github.com/adafruit/Adafruit_Python_ADS1x15 // * https://github.com/Wh1teRabbitHU/ADS1115-Driver type ADS1x15Driver struct { *Driver dataRates map[int]uint16 channelCfgs map[int]*ads1x15ChanCfg waitOnlyOneCycle bool } var ads1x15FullScaleRange = map[int]float64{ 0: 6.144, 1: 4.096, 2: 2.048, 3: 1.024, 4: 0.512, 5: 0.256, 6: 0.256, 7: 0.256, } // NewADS1015Driver creates a new driver for the ADS1015 (12-bit ADC) func NewADS1015Driver(a Connector, options ...func(Config)) *ADS1x15Driver { dataRates := map[int]uint16{ 128: 0x0000, 250: 0x0020, 490: 0x0040, 920: 0x0060, 1600: 0x0080, 2400: 0x00A0, 3300: 0x00C0, } defaultDataRate := 1600 return newADS1x15Driver(a, "ADS1015", dataRates, defaultDataRate, options...) } // NewADS1115Driver creates a new driver for the ADS1115 (16-bit ADC) func NewADS1115Driver(a Connector, options ...func(Config)) *ADS1x15Driver { dataRates := map[int]uint16{ 8: 0x0000, 16: 0x0020, 32: 0x0040, 64: 0x0060, 128: 0x0080, 250: 0x00A0, 475: 0x00C0, 860: 0x00E0, } defaultDataRate := 128 return newADS1x15Driver(a, "ADS1115", dataRates, defaultDataRate, options...) } func newADS1x15Driver(c Connector, name string, drs map[int]uint16, ddr int, options ...func(Config)) *ADS1x15Driver { ccs := map[int]*ads1x15ChanCfg{0: {1, ddr}, 1: {1, ddr}, 2: {1, ddr}, 3: {1, ddr}} d := &ADS1x15Driver{ Driver: NewDriver(c, name, ads1x15DefaultAddress), dataRates: drs, channelCfgs: ccs, } for _, option := range options { option(d) } //nolint:forcetypeassert // ok here d.AddCommand("ReadDifferenceWithDefaults", func(params map[string]interface{}) interface{} { channel := params["channel"].(int) val, err := d.ReadDifferenceWithDefaults(channel) return map[string]interface{}{"val": val, "err": err} }) //nolint:forcetypeassert // ok here d.AddCommand("ReadDifference", func(params map[string]interface{}) interface{} { channel := params["channel"].(int) gain := params["gain"].(int) dataRate := params["dataRate"].(int) val, err := d.ReadDifference(channel, gain, dataRate) return map[string]interface{}{"val": val, "err": err} }) //nolint:forcetypeassert // ok here d.AddCommand("ReadWithDefaults", func(params map[string]interface{}) interface{} { channel := params["channel"].(int) val, err := d.ReadWithDefaults(channel) return map[string]interface{}{"val": val, "err": err} }) //nolint:forcetypeassert // ok here d.AddCommand("Read", func(params map[string]interface{}) interface{} { channel := params["channel"].(int) gain := params["gain"].(int) dataRate := params["dataRate"].(int) val, err := d.Read(channel, gain, dataRate) return map[string]interface{}{"val": val, "err": err} }) //nolint:forcetypeassert // ok here d.AddCommand("AnalogRead", func(params map[string]interface{}) interface{} { pin := params["pin"].(string) val, err := d.AnalogRead(pin) return map[string]interface{}{"val": val, "err": err} }) return d } // WithADS1x15BestGainForVoltage option sets the ADS1x15Driver best gain for all channels. func WithADS1x15BestGainForVoltage(voltage float64) func(Config) { return func(c Config) { d, ok := c.(*ADS1x15Driver) if ok { // validate the given value bestGain, err := ads1x15BestGainForVoltage(voltage) if err != nil { panic(err) } WithADS1x15Gain(bestGain)(d) } else if ads1x15Debug { log.Printf("Trying to set best gain for voltage for non-ADS1x15Driver %v", c) } } } // WithADS1x15ChannelBestGainForVoltage option sets the ADS1x15Driver best gain for one channel. func WithADS1x15ChannelBestGainForVoltage(channel int, voltage float64) func(Config) { return func(c Config) { d, ok := c.(*ADS1x15Driver) if ok { // validate the given value bestGain, err := ads1x15BestGainForVoltage(voltage) if err != nil { panic(err) } WithADS1x15ChannelGain(channel, bestGain)(d) } else if ads1x15Debug { log.Printf("Trying to set channel best gain for voltage for non-ADS1x15Driver %v", c) } } } // WithADS1x15Gain option sets the ADS1x15Driver gain for all channels. // Valid gain settings are any of the PGA values (0..7). func WithADS1x15Gain(val int) func(Config) { return func(c Config) { d, ok := c.(*ADS1x15Driver) if ok { // validate the given value if _, err := ads1x15GetFullScaleRange(val); err != nil { panic(err) } d.setChannelGains(val) } else if ads1x15Debug { log.Printf("Trying to set gain for non-ADS1x15Driver %v", c) } } } // WithADS1x15ChannelGain option sets the ADS1x15Driver gain for one channel. // Valid gain settings are any of the PGA values (0..7). func WithADS1x15ChannelGain(channel int, val int) func(Config) { return func(c Config) { d, ok := c.(*ADS1x15Driver) if ok { // validate the given value if _, err := ads1x15GetFullScaleRange(val); err != nil { panic(err) } if err := d.checkChannel(channel); err != nil { panic(err) } d.channelCfgs[channel].gain = val } else if ads1x15Debug { log.Printf("Trying to set channel gain for non-ADS1x15Driver %v", c) } } } // WithADS1x15DataRate option sets the ADS1x15Driver data rate for all channels. // Valid gain settings are any of the DR values in SPS. func WithADS1x15DataRate(val int) func(Config) { return func(c Config) { d, ok := c.(*ADS1x15Driver) if ok { // validate the given value if _, err := ads1x15GetDataRateBits(d.dataRates, val); err != nil { panic(err) } d.setChannelDataRates(val) } else if ads1x15Debug { log.Printf("Trying to set data rate for non-ADS1x15Driver %v", c) } } } // WithADS1x15ChannelDataRate option sets the ADS1x15Driver data rate for one channel. // Valid gain settings are any of the DR values in SPS. func WithADS1x15ChannelDataRate(channel int, val int) func(Config) { return func(c Config) { d, ok := c.(*ADS1x15Driver) if ok { // validate the given values if _, err := ads1x15GetDataRateBits(d.dataRates, val); err != nil { panic(err) } if err := d.checkChannel(channel); err != nil { panic(err) } d.channelCfgs[channel].dataRate = val } else if ads1x15Debug { log.Printf("Trying to set channel data rate for non-ADS1x15Driver %v", c) } } } // WithADS1x15WaitSingleCycle option sets the ADS1x15Driver to wait only a single cycle for conversion. According to the // specification, chapter "Output Data Rate and Conversion Time", the device normally finishes the conversion within one // cycle (after wake up). The cycle time depends on configured data rate and will be calculated. For unknown reasons // some devices do not work with this setting. So the default behavior for single shot mode is to wait for a conversion // is finished by reading the configuration register bit 15. Activating this option will switch off this behavior and // will possibly create faster response. But, if multiple inputs are used and some inputs calculates the same result, // most likely the device is not working with this option. func WithADS1x15WaitSingleCycle() func(Config) { return func(c Config) { d, ok := c.(*ADS1x15Driver) if ok { d.waitOnlyOneCycle = true } else if ads1x15Debug { log.Printf("Trying to set wait single cycle for non-ADS1x15Driver %v", c) } } } // ReadDifferenceWithDefaults reads the difference in V between 2 inputs. It uses the default gain and data rate // diff can be: // * 0: Channel 0 - channel 1 // * 1: Channel 0 - channel 3 // * 2: Channel 1 - channel 3 // * 3: Channel 2 - channel 3 func (d *ADS1x15Driver) ReadDifferenceWithDefaults(diff int) (float64, error) { d.mutex.Lock() defer d.mutex.Unlock() if err := d.checkChannel(diff); err != nil { return 0, err } return d.readVoltage(diff, 0, d.channelCfgs[diff].gain, d.channelCfgs[diff].dataRate) } // ReadDifference reads the difference in V between 2 inputs. // diff can be: // * 0: Channel 0 - channel 1 // * 1: Channel 0 - channel 3 // * 2: Channel 1 - channel 3 // * 3: Channel 2 - channel 3 func (d *ADS1x15Driver) ReadDifference(diff int, gain int, dataRate int) (float64, error) { d.mutex.Lock() defer d.mutex.Unlock() if err := d.checkChannel(diff); err != nil { return 0, err } return d.readVoltage(diff, 0, gain, dataRate) } // ReadWithDefaults reads the voltage at the specified channel (between 0 and 3). // Default values are used for the gain and data rate. The result is in V. func (d *ADS1x15Driver) ReadWithDefaults(channel int) (float64, error) { d.mutex.Lock() defer d.mutex.Unlock() if err := d.checkChannel(channel); err != nil { return 0, err } return d.readVoltage(channel, 0x04, d.channelCfgs[channel].gain, d.channelCfgs[channel].dataRate) } // Read reads the voltage at the specified channel (between 0 and 3). The result is in V. func (d *ADS1x15Driver) Read(channel int, gain int, dataRate int) (float64, error) { d.mutex.Lock() defer d.mutex.Unlock() if err := d.checkChannel(channel); err != nil { return 0, err } return d.readVoltage(channel, 0x04, gain, dataRate) } // AnalogRead returns value from analog reading of specified pin using the default values. func (d *ADS1x15Driver) AnalogRead(pin string) (int, error) { d.mutex.Lock() defer d.mutex.Unlock() var channel int var channelOffset int // Check for the ADC is used in difference mode switch pin { case "0-1": channel = 0 case "0-3": channel = 1 case "1-3": channel = 2 case "2-3": channel = 3 default: // read the voltage at a specific pin, compared to the ground var err error channel, err = strconv.Atoi(pin) if err != nil { return 0, err } channelOffset = 0x04 } if err := d.checkChannel(channel); err != nil { return 0, err } return d.rawRead(channel, channelOffset, d.channelCfgs[channel].gain, d.channelCfgs[channel].dataRate) } func (d *ADS1x15Driver) readVoltage(channel int, channelOffset int, gain int, dataRate int) (float64, error) { fsr, err := ads1x15GetFullScaleRange(gain) if err != nil { return 0, err } rawValue, err := d.rawRead(channel, channelOffset, gain, dataRate) // Calculate return value in V value := float64(rawValue) / float64(1<<15) * fsr return value, err } func (d *ADS1x15Driver) rawRead(channel int, channelOffset int, gain int, dataRate int) (int, error) { // Validate the passed in data rate (differs between ADS1015 and ADS1115). dataRateBits, err := ads1x15GetDataRateBits(d.dataRates, dataRate) if err != nil { return 0, err } var config uint16 // Go out of power-down mode for conversion. config = ads1x15ConfigOsSingle // Specify mux value. mux := channel + channelOffset config |= uint16((mux & 0x07) << ads1x15ConfigMuxOffset) //nolint:gosec // TODO: fix later // Set the programmable gain amplifier bits. config |= uint16(gain) << ads1x15ConfigPgaOffset //nolint:gosec // TODO: fix later // Set the mode (continuous or single shot). config |= ads1x15ConfigModeSingle // Set the data rate. config |= dataRateBits // Disable comparator mode. config |= ads1x15ConfigCompQueDisable // Send the config value to start the ADC conversion. if err := d.writeWordBigEndian(ads1x15PointerConfig, config); err != nil { return 0, err } // Wait for the ADC sample to finish based on the sample rate plus a // small offset to be sure (0.1 millisecond). delay := time.Duration(1000000/dataRate+100) * time.Microsecond if err := d.waitForConversionFinished(delay); err != nil { return 0, err } // Retrieve the result. udata, err := d.readWordBigEndian(ads1x15PointerConversion) if err != nil { return 0, err } // Handle negative values as two's complement return int(twosComplement16Bit(udata)), nil } func (d *ADS1x15Driver) checkChannel(channel int) error { if channel < 0 || channel > 3 { return fmt.Errorf("invalid channel (%d), must be between 0 and 3", channel) } return nil } func (d *ADS1x15Driver) waitForConversionFinished(delay time.Duration) error { start := time.Now() for i := 0; i < ads1x15WaitMaxCount; i++ { if i == ads1x15WaitMaxCount-1 { // most likely the last try will also not finish, so we stop with an error return fmt.Errorf("the conversion is not finished within %s", time.Since(start)) } data, err := d.readWordBigEndian(ads1x15PointerConfig) if err != nil { return err } if ads1x15Debug { log.Printf("ADS1x15Driver: config register state: 0x%X\n", data) } // the highest bit 15: 0-device perform a conversion, 1-no conversion in progress if data&ads1x15ConfigOsSingle > 0 { break } time.Sleep(delay) if d.waitOnlyOneCycle { break } } if ads1x15Debug { elapsed := time.Since(start) log.Printf("conversion takes %s", elapsed) } return nil } func (d *ADS1x15Driver) writeWordBigEndian(reg uint8, val uint16) error { return d.writeWordData(reg, swapBytes(val)) } func (d *ADS1x15Driver) readWordBigEndian(reg uint8) (uint16, error) { data, err := d.readWordData(reg) if err != nil { return 0, err } return swapBytes(data), err } func (d *ADS1x15Driver) setChannelDataRates(ddr int) { for i := 0; i <= 3; i++ { d.channelCfgs[i].dataRate = ddr } } func (d *ADS1x15Driver) setChannelGains(gain int) { for i := 0; i <= 3; i++ { d.channelCfgs[i].gain = gain } } func ads1x15GetFullScaleRange(gain int) (float64, error) { if fsr, ok := ads1x15FullScaleRange[gain]; ok { return fsr, nil } keys := []int{} for k := range ads1x15FullScaleRange { keys = append(keys, k) } sort.Ints(keys) return 0, fmt.Errorf("gain (%d) must be one of: %d", gain, keys) } func ads1x15GetDataRateBits(dataRates map[int]uint16, dataRate int) (uint16, error) { if bits, ok := dataRates[dataRate]; ok { return bits, nil } keys := []int{} for k := range dataRates { keys = append(keys, k) } sort.Ints(keys) return 0, fmt.Errorf("invalid data rate (%d). Accepted values: %d", dataRate, keys) } // ads1x15BestGainForVoltage returns the gain the most adapted to read up to the specified difference of potential. func ads1x15BestGainForVoltage(voltage float64) (int, error) { var maximum float64 difference := math.MaxFloat64 currentBestGain := -1 for key, fsr := range ads1x15FullScaleRange { maximum = math.Max(maximum, fsr) newDiff := fsr - voltage if newDiff >= 0 && newDiff < difference { difference = newDiff currentBestGain = key } } if currentBestGain < 0 { return 0, fmt.Errorf("the maximum voltage which can be read is %f", maximum) } return currentBestGain, nil } ================================================ FILE: drivers/i2c/ads1x15_driver_1015_test.go ================================================ package i2c import ( "errors" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func initTestADS1015DriverWithStubbedAdaptor() (*ADS1x15Driver, *i2cTestAdaptor) { a := newI2cTestAdaptor() d := NewADS1015Driver(a) if err := d.Start(); err != nil { panic(err) } return d, a } func TestNewADS1015Driver(t *testing.T) { var di interface{} = NewADS1015Driver(newI2cTestAdaptor()) d, ok := di.(*ADS1x15Driver) if !ok { require.Fail(t, "NewADS1015Driver() should have returned a *ADS1x15Driver") } assert.NotNil(t, d.Driver) assert.True(t, strings.HasPrefix(d.Name(), "ADS1015")) for i := 0; i <= 3; i++ { assert.Equal(t, 1, d.channelCfgs[i].gain) assert.Equal(t, 1600, d.channelCfgs[i].dataRate) } } func TestADS1015Halt(t *testing.T) { // arrange d := NewADS1015Driver(newI2cTestAdaptor()) // act, assert require.NoError(t, d.Halt()) // must be idempotent require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestADS1015Options(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithBus() option and // least one of this driver. Further tests for options can also be done by call of "WithOption(val)(d)". d := NewADS1015Driver(newI2cTestAdaptor(), WithBus(2), WithADS1x15Gain(2), WithADS1x15DataRate(920)) assert.Equal(t, 2, d.GetBusOrDefault(1)) for i := 0; i <= 3; i++ { assert.Equal(t, 2, d.channelCfgs[i].gain) assert.Equal(t, 920, d.channelCfgs[i].dataRate) } } func TestADS1015WithADS1x15BestGainForVoltage(t *testing.T) { d, _ := initTestADS1015DriverWithStubbedAdaptor() WithADS1x15BestGainForVoltage(1.01)(d) for i := 0; i <= 3; i++ { assert.Equal(t, 3, d.channelCfgs[i].gain) } } func TestADS1015WithADS1x15ChannelBestGainForVoltage(t *testing.T) { d, _ := initTestADS1015DriverWithStubbedAdaptor() WithADS1x15ChannelBestGainForVoltage(0, 1.0)(d) WithADS1x15ChannelBestGainForVoltage(1, 2.5)(d) WithADS1x15ChannelBestGainForVoltage(2, 3.3)(d) WithADS1x15ChannelBestGainForVoltage(3, 5.0)(d) assert.Equal(t, 3, d.channelCfgs[0].gain) assert.Equal(t, 1, d.channelCfgs[1].gain) assert.Equal(t, 1, d.channelCfgs[2].gain) assert.Equal(t, 0, d.channelCfgs[3].gain) } func TestADS1015AnalogRead(t *testing.T) { d, a := initTestADS1015DriverWithStubbedAdaptor() WithADS1x15WaitSingleCycle()(d) a.i2cReadImpl = func(b []byte) (int, error) { copy(b, []byte{0x7F, 0xFF}) return 2, nil } val, err := d.AnalogRead("0") assert.Equal(t, 32767, val) require.NoError(t, err) val, err = d.AnalogRead("1") assert.Equal(t, 32767, val) require.NoError(t, err) val, err = d.AnalogRead("2") assert.Equal(t, 32767, val) require.NoError(t, err) val, err = d.AnalogRead("3") assert.Equal(t, 32767, val) require.NoError(t, err) val, err = d.AnalogRead("0-1") assert.Equal(t, 32767, val) require.NoError(t, err) val, err = d.AnalogRead("0-3") assert.Equal(t, 32767, val) require.NoError(t, err) val, err = d.AnalogRead("1-3") assert.Equal(t, 32767, val) require.NoError(t, err) val, err = d.AnalogRead("2-3") assert.Equal(t, 32767, val) require.NoError(t, err) _, err = d.AnalogRead("3-2") require.Error(t, err) } func TestADS1x15AnalogReadError(t *testing.T) { d, a := initTestADS1015DriverWithStubbedAdaptor() a.i2cReadImpl = func(b []byte) (int, error) { return 0, errors.New("read error") } _, err := d.AnalogRead("0") require.ErrorContains(t, err, "read error") } func TestADS1x15AnalogReadInvalidPin(t *testing.T) { d, _ := initTestADS1015DriverWithStubbedAdaptor() _, err := d.AnalogRead("99") require.ErrorContains(t, err, "invalid channel (99), must be between 0 and 3") } func TestADS1x15AnalogReadWriteError(t *testing.T) { d, a := initTestADS1015DriverWithStubbedAdaptor() a.i2cWriteImpl = func([]byte) (int, error) { return 0, errors.New("write error") } _, err := d.AnalogRead("0") require.ErrorContains(t, err, "write error") _, err = d.AnalogRead("0-1") require.ErrorContains(t, err, "write error") _, err = d.AnalogRead("2-3") require.ErrorContains(t, err, "write error") } func TestADS1x15ReadInvalidChannel(t *testing.T) { d, _ := initTestADS1015DriverWithStubbedAdaptor() _, err := d.Read(9, 1, 1600) require.ErrorContains(t, err, "invalid channel (9), must be between 0 and 3") } func TestADS1x15ReadInvalidGain(t *testing.T) { d, _ := initTestADS1015DriverWithStubbedAdaptor() _, err := d.Read(0, 8, 1600) require.ErrorContains(t, err, "gain (8) must be one of: [0 1 2 3 4 5 6 7]") } func TestADS1x15ReadInvalidDataRate(t *testing.T) { d, _ := initTestADS1015DriverWithStubbedAdaptor() _, err := d.Read(0, 1, 321) require.ErrorContains(t, err, "invalid data rate (321). Accepted values: [128 250 490 920 1600 2400 3300]") } func TestADS1x15ReadDifferenceInvalidChannel(t *testing.T) { d, _ := initTestADS1015DriverWithStubbedAdaptor() _, err := d.ReadDifference(9, 1, 1600) require.ErrorContains(t, err, "invalid channel (9), must be between 0 and 3") } func TestADS1015_rawRead(t *testing.T) { // sequence to read: // * prepare config register content (mode, input, gain, data rate, comparator) // * write config register (16 bit, MSByte first) // * read config register (16 bit, MSByte first) and wait for bit 15 is set // * read conversion register (16 bit, MSByte first) for the value // * apply two's complement converter, relates to one digit resolution (1/2^15), voltage multiplier tests := map[string]struct { input []uint8 gain int dataRate int want int wantConfig []uint8 }{ "+FS": { input: []uint8{0x7F, 0xFF}, gain: 0, dataRate: 128, want: (1<<15 - 1), wantConfig: []uint8{0x91, 0x03}, }, "+1": { input: []uint8{0x00, 0x01}, gain: 0, dataRate: 250, want: 1, wantConfig: []uint8{0x91, 0x23}, }, "+-0": { input: []uint8{0x00, 0x00}, gain: 0, dataRate: 490, want: 0, wantConfig: []uint8{0x91, 0x43}, }, "-1": { input: []uint8{0xFF, 0xFF}, gain: 0, dataRate: 920, want: -1, wantConfig: []uint8{0x91, 0x63}, }, "-FS": { input: []uint8{0x80, 0x00}, gain: 0, dataRate: 1600, want: -(1 << 15), wantConfig: []uint8{0x91, 0x83}, }, "+FS gain 1": { input: []uint8{0x7F, 0xFF}, gain: 1, dataRate: 2400, want: (1<<15 - 1), wantConfig: []uint8{0x93, 0xA3}, }, "+FS gain 3": { input: []uint8{0x7F, 0xFF}, gain: 3, dataRate: 3300, want: (1<<15 - 1), wantConfig: []uint8{0x97, 0xC3}, }, "+FS gain 5": { input: []uint8{0x7F, 0xFF}, gain: 5, dataRate: 2400, want: (1<<15 - 1), wantConfig: []uint8{0x9B, 0xA3}, }, "+FS gain 7": { input: []uint8{0x7F, 0xFF}, gain: 7, dataRate: 1600, want: (1<<15 - 1), wantConfig: []uint8{0x9F, 0x83}, }, } d, a := initTestADS1015DriverWithStubbedAdaptor() // arrange channel := 0 channelOffset := 1 for name, tc := range tests { t.Run(name, func(t *testing.T) { a.written = []byte{} // reset writes of Start() and former test // arrange reads conversion := []uint8{0x00, 0x00} // a conversion is in progress noConversion := []uint8{0x80, 0x00} // no conversion in progress returnRead := [3][]uint8{conversion, noConversion, tc.input} numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ retRead := returnRead[numCallsRead-1] copy(b, retRead) return len(b), nil } // act got, err := d.rawRead(channel, channelOffset, tc.gain, tc.dataRate) // assert require.NoError(t, err) assert.Equal(t, tc.want, got) assert.Equal(t, 3, numCallsRead) assert.Len(t, a.written, 6) assert.Equal(t, uint8(ads1x15PointerConfig), a.written[0]) assert.Equal(t, tc.wantConfig[0], a.written[1]) // MSByte: OS, MUX, PGA, MODE assert.Equal(t, tc.wantConfig[1], a.written[2]) // LSByte: DR, COMP_* assert.Equal(t, uint8(ads1x15PointerConfig), a.written[3]) // first check for no conversion assert.Equal(t, uint8(ads1x15PointerConfig), a.written[4]) // second check for no conversion assert.Equal(t, uint8(ads1x15PointerConversion), a.written[5]) }) } } ================================================ FILE: drivers/i2c/ads1x15_driver_1115_test.go ================================================ package i2c import ( "errors" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func initTestADS1115DriverWithStubbedAdaptor() (*ADS1x15Driver, *i2cTestAdaptor) { a := newI2cTestAdaptor() d := NewADS1115Driver(a) if err := d.Start(); err != nil { panic(err) } return d, a } func TestNewADS1115Driver(t *testing.T) { var di interface{} = NewADS1115Driver(newI2cTestAdaptor()) d, ok := di.(*ADS1x15Driver) if !ok { require.Fail(t, "NewADS1115Driver() should have returned a *ADS1x15Driver") } assert.NotNil(t, d.Driver) assert.True(t, strings.HasPrefix(d.Name(), "ADS1115")) for i := 0; i <= 3; i++ { assert.Equal(t, 1, d.channelCfgs[i].gain) assert.Equal(t, 128, d.channelCfgs[i].dataRate) } } func TestADS1115Halt(t *testing.T) { // arrange d := NewADS1115Driver(newI2cTestAdaptor()) // act, assert require.NoError(t, d.Halt()) // must be idempotent require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestADS1115Options(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithBus() option and // least one of this driver. Further tests for options can also be done by call of "WithOption(val)(d)". d := NewADS1115Driver(newI2cTestAdaptor(), WithBus(2), WithADS1x15Gain(2), WithADS1x15DataRate(860)) assert.Equal(t, 2, d.GetBusOrDefault(1)) for i := 0; i <= 3; i++ { assert.Equal(t, 2, d.channelCfgs[i].gain) assert.Equal(t, 860, d.channelCfgs[i].dataRate) } } func TestADS1115WithADS1x15BestGainForVoltage(t *testing.T) { d, _ := initTestADS1115DriverWithStubbedAdaptor() WithADS1x15BestGainForVoltage(1.01)(d) for i := 0; i <= 3; i++ { assert.Equal(t, 3, d.channelCfgs[i].gain) } } func TestADS1115WithADS1x15ChannelBestGainForVoltage(t *testing.T) { d, _ := initTestADS1115DriverWithStubbedAdaptor() WithADS1x15ChannelBestGainForVoltage(0, 1.0)(d) WithADS1x15ChannelBestGainForVoltage(1, 2.5)(d) WithADS1x15ChannelBestGainForVoltage(2, 3.3)(d) WithADS1x15ChannelBestGainForVoltage(3, 5.0)(d) assert.Equal(t, 3, d.channelCfgs[0].gain) assert.Equal(t, 1, d.channelCfgs[1].gain) assert.Equal(t, 1, d.channelCfgs[2].gain) assert.Equal(t, 0, d.channelCfgs[3].gain) } func TestADS1115AnalogRead(t *testing.T) { d, a := initTestADS1115DriverWithStubbedAdaptor() WithADS1x15WaitSingleCycle()(d) a.i2cReadImpl = func(b []byte) (int, error) { copy(b, []byte{0x7F, 0xFF}) return 2, nil } val, err := d.AnalogRead("0") assert.Equal(t, 32767, val) require.NoError(t, err) val, err = d.AnalogRead("1") assert.Equal(t, 32767, val) require.NoError(t, err) val, err = d.AnalogRead("2") assert.Equal(t, 32767, val) require.NoError(t, err) val, err = d.AnalogRead("3") assert.Equal(t, 32767, val) require.NoError(t, err) val, err = d.AnalogRead("0-1") assert.Equal(t, 32767, val) require.NoError(t, err) val, err = d.AnalogRead("0-3") assert.Equal(t, 32767, val) require.NoError(t, err) val, err = d.AnalogRead("1-3") assert.Equal(t, 32767, val) require.NoError(t, err) val, err = d.AnalogRead("2-3") assert.Equal(t, 32767, val) require.NoError(t, err) _, err = d.AnalogRead("3-2") require.Error(t, err) } func TestADS1115AnalogReadError(t *testing.T) { d, a := initTestADS1115DriverWithStubbedAdaptor() a.i2cReadImpl = func(b []byte) (int, error) { return 0, errors.New("read error") } _, err := d.AnalogRead("0") require.ErrorContains(t, err, "read error") } func TestADS1115AnalogReadInvalidPin(t *testing.T) { d, _ := initTestADS1115DriverWithStubbedAdaptor() _, err := d.AnalogRead("98") require.ErrorContains(t, err, "invalid channel (98), must be between 0 and 3") } func TestADS1115AnalogReadWriteError(t *testing.T) { d, a := initTestADS1115DriverWithStubbedAdaptor() a.i2cWriteImpl = func([]byte) (int, error) { return 0, errors.New("write error") } _, err := d.AnalogRead("0") require.ErrorContains(t, err, "write error") _, err = d.AnalogRead("0-1") require.ErrorContains(t, err, "write error") _, err = d.AnalogRead("2-3") require.ErrorContains(t, err, "write error") } func TestADS1115ReadInvalidChannel(t *testing.T) { d, _ := initTestADS1115DriverWithStubbedAdaptor() _, err := d.Read(7, 1, 1600) require.ErrorContains(t, err, "invalid channel (7), must be between 0 and 3") } func TestADS1115ReadInvalidGain(t *testing.T) { d, _ := initTestADS1115DriverWithStubbedAdaptor() _, err := d.Read(0, 21, 1600) require.ErrorContains(t, err, "gain (21) must be one of: [0 1 2 3 4 5 6 7]") } func TestADS1115ReadInvalidDataRate(t *testing.T) { d, _ := initTestADS1115DriverWithStubbedAdaptor() _, err := d.Read(0, 1, 678) require.ErrorContains(t, err, "invalid data rate (678). Accepted values: [8 16 32 64 128 250 475 860]") } func TestADS1115ReadDifferenceInvalidChannel(t *testing.T) { d, _ := initTestADS1115DriverWithStubbedAdaptor() _, err := d.ReadDifference(5, 1, 1600) require.ErrorContains(t, err, "invalid channel (5), must be between 0 and 3") } func TestADS1115_rawRead(t *testing.T) { // sequence to read: // * prepare config register content (mode, input, gain, data rate, comparator) // * write config register (16 bit, MSByte first) // * read config register (16 bit, MSByte first) and wait for bit 15 is set // * read conversion register (16 bit, MSByte first) for the value // * apply two's complement converter, relates to one digit resolution (1/2^15), voltage multiplier tests := map[string]struct { input []uint8 gain int dataRate int want int wantConfig []uint8 }{ "+FS": { input: []uint8{0x7F, 0xFF}, gain: 0, dataRate: 8, want: (1<<15 - 1), wantConfig: []uint8{0x91, 0x03}, }, "+1": { input: []uint8{0x00, 0x01}, gain: 0, dataRate: 16, want: 1, wantConfig: []uint8{0x91, 0x23}, }, "+-0": { input: []uint8{0x00, 0x00}, gain: 0, dataRate: 32, want: 0, wantConfig: []uint8{0x91, 0x43}, }, "-1": { input: []uint8{0xFF, 0xFF}, gain: 0, dataRate: 64, want: -1, wantConfig: []uint8{0x91, 0x63}, }, "-FS": { input: []uint8{0x80, 0x00}, gain: 0, dataRate: 128, want: -(1 << 15), wantConfig: []uint8{0x91, 0x83}, }, "+FS gain 1": { input: []uint8{0x7F, 0xFF}, gain: 1, dataRate: 250, want: (1<<15 - 1), wantConfig: []uint8{0x93, 0xA3}, }, "+FS gain 3": { input: []uint8{0x7F, 0xFF}, gain: 3, dataRate: 475, want: (1<<15 - 1), wantConfig: []uint8{0x97, 0xC3}, }, "+FS gain 5": { input: []uint8{0x7F, 0xFF}, gain: 5, dataRate: 860, want: (1<<15 - 1), wantConfig: []uint8{0x9B, 0xE3}, }, "+FS gain 7": { input: []uint8{0x7F, 0xFF}, gain: 7, dataRate: 128, want: (1<<15 - 1), wantConfig: []uint8{0x9F, 0x83}, }, } d, a := initTestADS1115DriverWithStubbedAdaptor() // arrange channel := 0 channelOffset := 1 for name, tc := range tests { t.Run(name, func(t *testing.T) { a.written = []byte{} // reset writes of Start() and former test // arrange reads conversion := []uint8{0x00, 0x00} // a conversion is in progress noConversion := []uint8{0x80, 0x00} // no conversion in progress returnRead := [3][]uint8{conversion, noConversion, tc.input} numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ retRead := returnRead[numCallsRead-1] copy(b, retRead) return len(b), nil } // act got, err := d.rawRead(channel, channelOffset, tc.gain, tc.dataRate) // assert require.NoError(t, err) assert.Equal(t, tc.want, got) assert.Equal(t, 3, numCallsRead) assert.Len(t, a.written, 6) assert.Equal(t, uint8(ads1x15PointerConfig), a.written[0]) assert.Equal(t, tc.wantConfig[0], a.written[1]) // MSByte: OS, MUX, PGA, MODE assert.Equal(t, tc.wantConfig[1], a.written[2]) // LSByte: DR, COMP_* assert.Equal(t, uint8(ads1x15PointerConfig), a.written[3]) // first check for no conversion assert.Equal(t, uint8(ads1x15PointerConfig), a.written[4]) // second check for no conversion assert.Equal(t, uint8(ads1x15PointerConversion), a.written[5]) }) } } ================================================ FILE: drivers/i2c/ads1x15_driver_test.go ================================================ //nolint:forcetypeassert // ok here package i2c import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" ) // this ensures that the implementation is based on i2c.Driver, which implements the gobot.Driver // and tests all implementations, so no further tests needed here for gobot.Driver interface var _ gobot.Driver = (*ADS1x15Driver)(nil) // that supports the AnalogReader interface var _ aio.AnalogReader = (*ADS1x15Driver)(nil) func initTestADS1x15DriverWithStubbedAdaptor() (*ADS1x15Driver, *i2cTestAdaptor) { //nolint:unparam // keep for tests a := newI2cTestAdaptor() const defaultDataRate = 3 dataRates := map[int]uint16{defaultDataRate: 0x0003} d := newADS1x15Driver(a, "ADS1x15", dataRates, defaultDataRate) noConversion := []uint8{0x80, 0x00} // no conversion in progress a.i2cReadImpl = func(b []byte) (int, error) { copy(b, noConversion) return 2, nil } if err := d.Start(); err != nil { panic(err) } return d, a } var ads1x15TestChannel = map[string]interface{}{ "channel": int(2), } var ads1x15TestChannelGainDataRate = map[string]interface{}{ "channel": int(1), "gain": int(2), "dataRate": int(3), } func TestADS1x15CommandsReadDifferenceWithDefaults(t *testing.T) { // arrange d, _ := initTestADS1x15DriverWithStubbedAdaptor() // act result := d.Command("ReadDifferenceWithDefaults")(ads1x15TestChannel) // assert assert.Nil(t, result.(map[string]interface{})["err"]) assert.InDelta(t, -4.096, result.(map[string]interface{})["val"], 0.0) } func TestADS1x15CommandsReadDifference(t *testing.T) { // arrange d, _ := initTestADS1x15DriverWithStubbedAdaptor() // act result := d.Command("ReadDifference")(ads1x15TestChannelGainDataRate) // assert assert.Nil(t, result.(map[string]interface{})["err"]) assert.InDelta(t, -2.048, result.(map[string]interface{})["val"], 0.0) } func TestADS1x15CommandsReadWithDefaults(t *testing.T) { // arrange d, _ := initTestADS1x15DriverWithStubbedAdaptor() // act result := d.Command("ReadWithDefaults")(ads1x15TestChannel) // assert assert.Nil(t, result.(map[string]interface{})["err"]) assert.InDelta(t, -4.096, result.(map[string]interface{})["val"], 0.0) } func TestADS1x15CommandsRead(t *testing.T) { // arrange d, _ := initTestADS1x15DriverWithStubbedAdaptor() // act result := d.Command("Read")(ads1x15TestChannelGainDataRate) // assert assert.Nil(t, result.(map[string]interface{})["err"]) assert.InDelta(t, -2.048, result.(map[string]interface{})["val"], 0.0) } func TestADS1x15CommandsAnalogRead(t *testing.T) { // arrange d, _ := initTestADS1x15DriverWithStubbedAdaptor() ads1x15TestPin := map[string]interface{}{ "pin": string("2"), } // act result := d.Command("AnalogRead")(ads1x15TestPin) // assert assert.Nil(t, result.(map[string]interface{})["err"]) assert.Equal(t, -32768, result.(map[string]interface{})["val"]) } func TestADS1x15_ads1x15BestGainForVoltage(t *testing.T) { g, _ := ads1x15BestGainForVoltage(1.5) assert.Equal(t, 2, g) _, err := ads1x15BestGainForVoltage(20.0) require.ErrorContains(t, err, "the maximum voltage which can be read is 6.144000") } ================================================ FILE: drivers/i2c/adxl345_driver.go ================================================ package i2c import ( "encoding/binary" "log" ) const adxl345Debug = false // ADXL345 supports 2 addresses, which can be changed by the address pin, there is no internal pull-up/down resistor! // pin to GND: 0x53, pin to VDD: 0x1D const ( ADXL345AddressPullUp = 0x1D // can be used by WithAddress() adxl345DefaultAddress = 0x53 ) type ( ADXL345RateConfig uint8 ADXL345FsRangeConfig uint8 ) const ( // registers are named according to the datasheet adxl345Reg_DEVID = 0x00 // R, 11100101, Device ID adxl345Reg_THRESH_TAP = 0x1D // R/W, 00000000, Tap threshold adxl345Reg_OFSX = 0x1E // R/W, 00000000, X-axis offset adxl345Reg_OFSY = 0x1F // R/W, 00000000, Y-axis offset adxl345Reg_OFSZ = 0x20 // R/W, 00000000, Z-axis offset adxl345Reg_DUR = 0x21 // R/W, 00000000, Tap duration adxl345Reg_LATENT = 0x22 // R/W, 00000000, Tap latency adxl345Reg_WINDOW = 0x23 // R/W, 00000000, Tap window adxl345Reg_THRESH_ACT = 0x24 // R/W, 00000000, Activity threshold adxl345Reg_THRESH_INACT = 0x25 // R/W, 00000000, Inactivity threshold adxl345Reg_TIME_INACT = 0x26 // R/W, 00000000, Inactivity time adxl345Reg_ACT_INACT_CTL = 0x27 // R/W, 00000000, Axis enable control for activity and inactivity detection adxl345Reg_THRESH_FF = 0x28 // R/W, 00000000, Free-fall threshold adxl345Reg_TIME_FF = 0x29 // R/W, 00000000, Free-fall time adxl345Reg_TAP_AXES = 0x2A // R/W, 00000000, Axis control for single tap/double tap adxl345Reg_ACT_TAP_STATUS = 0x2B // R, 00000000, Source of single tap/double tap adxl345Reg_BW_RATE = 0x2C // R/W, 00001010, Data rate and power mode control adxl345Reg_POWER_CTL = 0x2D // R/W, 00000000, Power-saving features control adxl345Reg_INT_ENABLE = 0x2E // R/W, 00000000, Interrupt enable control adxl345Reg_INT_MAP = 0x2F // R/W, 00000000, Interrupt mapping control adxl345Reg_INT_SOUCE = 0x30 // R, 00000010, Source of interrupts adxl345Reg_DATA_FORMAT = 0x31 // R/W, 00000000, Data format control (FS range, justify, full resolution) adxl345Reg_DATAX0 = 0x32 // R, 00000000, X-Axis Data 0 (LSByte) adxl345Reg_DATAX1 = 0x33 // R, 00000000, X-Axis Data 1 (MSByte) adxl345Reg_DATAY0 = 0x34 // R, 00000000, Y-Axis Data 0 adxl345Reg_DATAY1 = 0x35 // R, 00000000, Y-Axis Data 1 adxl345Reg_DATAZ0 = 0x36 // R, 00000000, Z-Axis Data 0 adxl345Reg_DATAZ1 = 0x37 // R, 00000000, Z-Axis Data 1 adxl345Reg_FIFO_CTL = 0x38 // R/W, 00000000, FIFO control adxl345Reg_FIFO_STATUS = 0x39 // R, 00000000, FIFO status adxl345Rate_LowPowerBit = 0x10 // set the device to low power, but increase the noise by ~2.5x ADXL345Rate_100mHZ ADXL345RateConfig = 0x00 // 0.10 Hz ADXL345Rate_200mHZ ADXL345RateConfig = 0x01 // 0.20 Hz ADXL345Rate_390mHZ ADXL345RateConfig = 0x02 // 0.39 Hz ADXL345Rate_780mHZ ADXL345RateConfig = 0x03 // 0.78 Hz ADXL345Rate_1560mHZ ADXL345RateConfig = 0x04 // 1.56 Hz ADXL345Rate_3130mHZ ADXL345RateConfig = 0x05 // 3.13 Hz ADXL345Rate_6250mHZ ADXL345RateConfig = 0x06 // 6.25 Hz ADXL345Rate_12500mHZ ADXL345RateConfig = 0x07 // 12.5 Hz ADXL345Rate_25HZ ADXL345RateConfig = 0x08 // 25 Hz ADXL345Rate_50HZ ADXL345RateConfig = 0x09 // 50 Hz ADXL345Rate_100HZ ADXL345RateConfig = 0x0A // 100 Hz ADXL345Rate_200HZ ADXL345RateConfig = 0x0B // 200 Hz ADXL345Rate_400HZ ADXL345RateConfig = 0x0C // 400 Hz ADXL345Rate_800HZ ADXL345RateConfig = 0x0D // 800 Hz ADXL345Rate_1600HZ ADXL345RateConfig = 0x0E // 1600 Hz ADXL345Rate_3200HZ ADXL345RateConfig = 0x0F // 3200 Hz ADXL345FsRange_2G ADXL345FsRangeConfig = 0x00 // +-2 g ADXL345FsRange_4G ADXL345FsRangeConfig = 0x01 // +-4 g ADXL345FsRange_8G ADXL345FsRangeConfig = 0x02 // +-8 g ADXL345FsRange_16G ADXL345FsRangeConfig = 0x03 // +-16 g) ) // ADXL345Driver is the gobot driver for the digital accelerometer ADXL345 // // Datasheet EN: http://www.analog.com/media/en/technical-documentation/data-sheets/ADXL345.pdf // Datasheet JP: http://www.analog.com/media/jp/technical-documentation/data-sheets/ADXL345_jp.pdf // // Ported from the Arduino driver https://github.com/jakalada/Arduino-ADXL345 type ADXL345Driver struct { *Driver powerCtl adxl345PowerCtl dataFormat adxl345DataFormat bwRate adxl345BwRate } // Internal structure for the power configuration type adxl345PowerCtl struct { link uint8 autoSleep uint8 measure uint8 sleep uint8 wakeUp uint8 } // Internal structure for the sensor's data format configuration type adxl345DataFormat struct { selfTest uint8 spi uint8 intInvert uint8 fullRes uint8 justify uint8 fullScaleRange ADXL345FsRangeConfig } // Internal structure for the sampling rate configuration type adxl345BwRate struct { lowPower bool rate ADXL345RateConfig } // NewADXL345Driver creates a new driver with specified i2c interface // Params: // // c Connector - the Adaptor to use with this Driver // // Optional params: // // i2c.WithBus(int): bus to use with this driver // i2c.WithAddress(int): address to use with this driver func NewADXL345Driver(c Connector, options ...func(Config)) *ADXL345Driver { d := &ADXL345Driver{ Driver: NewDriver(c, "ADXL345", adxl345DefaultAddress), powerCtl: adxl345PowerCtl{ measure: 1, }, dataFormat: adxl345DataFormat{ fullScaleRange: ADXL345FsRange_2G, }, bwRate: adxl345BwRate{ lowPower: true, rate: ADXL345Rate_100HZ, }, } d.afterStart = d.initialize d.beforeHalt = d.shutdown for _, option := range options { option(d) } // TODO: add commands for API return d } // WithADXL345LowPowerMode option modifies the low power mode. func WithADXL345LowPowerMode(val bool) func(Config) { return func(c Config) { if d, ok := c.(*ADXL345Driver); ok { d.bwRate.lowPower = val } else if adxl345Debug { log.Printf("Trying to modify low power mode for non-ADXL345Driver %v", c) } } } // WithADXL345DataOutputRate option sets the data output rate. // Valid settings are of type "ADXL345RateConfig" func WithADXL345DataOutputRate(val ADXL345RateConfig) func(Config) { return func(c Config) { if d, ok := c.(*ADXL345Driver); ok { d.bwRate.rate = val } else if adxl345Debug { log.Printf("Trying to set data output rate for non-ADXL345Driver %v", c) } } } // WithADXL345FullScaleRange option sets the full scale range. // Valid settings are of type "ADXL345FsRangeConfig" func WithADXL345FullScaleRange(val ADXL345FsRangeConfig) func(Config) { return func(c Config) { if d, ok := c.(*ADXL345Driver); ok { d.dataFormat.fullScaleRange = val } else if adxl345Debug { log.Printf("Trying to set full scale range for non-ADXL345Driver %v", c) } } } // UseLowPower change the current rate of the sensor func (d *ADXL345Driver) UseLowPower(lowPower bool) error { d.mutex.Lock() defer d.mutex.Unlock() d.bwRate.lowPower = lowPower return d.writeByteData(adxl345Reg_BW_RATE, d.bwRate.toByte()) } // SetRate change the current rate of the sensor immediately func (d *ADXL345Driver) SetRate(rate ADXL345RateConfig) error { d.mutex.Lock() defer d.mutex.Unlock() d.bwRate.rate = rate return d.writeByteData(adxl345Reg_BW_RATE, d.bwRate.toByte()) } // SetRange change the current range of the sensor immediately func (d *ADXL345Driver) SetRange(fullScaleRange ADXL345FsRangeConfig) error { d.mutex.Lock() defer d.mutex.Unlock() d.dataFormat.fullScaleRange = fullScaleRange return d.writeByteData(adxl345Reg_DATA_FORMAT, d.dataFormat.toByte()) } // XYZ returns the adjusted x, y and z axis, unit [g] func (d *ADXL345Driver) XYZ() (float64, float64, float64, error) { d.mutex.Lock() defer d.mutex.Unlock() xr, yr, zr, err := d.readRawData() if err != nil { return 0, 0, 0, err } return d.dataFormat.convertToG(xr), d.dataFormat.convertToG(yr), d.dataFormat.convertToG(zr), nil } // RawXYZ returns the raw x,y and z axis func (d *ADXL345Driver) RawXYZ() (int16, int16, int16, error) { d.mutex.Lock() defer d.mutex.Unlock() return d.readRawData() } func (d *ADXL345Driver) readRawData() (int16, int16, int16, error) { buf := []byte{0, 0, 0, 0, 0, 0} if err := d.readBlockData(adxl345Reg_DATAX0, buf); err != nil { return 0, 0, 0, err } rx := int16(binary.LittleEndian.Uint16(buf[0:2])) //nolint:gosec // TODO: fix later ry := int16(binary.LittleEndian.Uint16(buf[2:4])) //nolint:gosec // TODO: fix later rz := int16(binary.LittleEndian.Uint16(buf[4:6])) //nolint:gosec // TODO: fix later return rx, ry, rz, nil } func (d *ADXL345Driver) initialize() error { if err := d.writeByteData(adxl345Reg_BW_RATE, d.bwRate.toByte()); err != nil { return err } if err := d.writeByteData(adxl345Reg_POWER_CTL, d.powerCtl.toByte()); err != nil { return err } if err := d.writeByteData(adxl345Reg_DATA_FORMAT, d.dataFormat.toByte()); err != nil { return err } return nil } func (d *ADXL345Driver) shutdown() error { if d.connection == nil { return nil } d.powerCtl.measure = 0 return d.writeByteData(adxl345Reg_POWER_CTL, d.powerCtl.toByte()) } // convertToG converts the given raw value by range configuration to the unit [g] func (d *adxl345DataFormat) convertToG(rawValue int16) float64 { switch d.fullScaleRange { case ADXL345FsRange_2G: return float64(rawValue) * 2 / 512 case ADXL345FsRange_4G: return float64(rawValue) * 4 / 512 case ADXL345FsRange_8G: return float64(rawValue) * 8 / 512 case ADXL345FsRange_16G: return float64(rawValue) * 16 / 512 default: return 0 } } // toByte returns a byte from the powerCtl configuration func (p *adxl345PowerCtl) toByte() uint8 { bits := p.wakeUp bits = bits | (p.sleep << 2) bits = bits | (p.measure << 3) bits = bits | (p.autoSleep << 4) return bits | (p.link << 5) } // toByte returns a byte from the dataFormat configuration func (d *adxl345DataFormat) toByte() uint8 { bits := uint8(d.fullScaleRange) bits = bits | (d.justify << 2) bits = bits | (d.fullRes << 3) bits = bits | (d.intInvert << 5) bits = bits | (d.spi << 6) return bits | (d.selfTest << 7) } // toByte returns a byte from the bwRate configuration func (b *adxl345BwRate) toByte() uint8 { bits := uint8(b.rate) if b.lowPower { bits = bits | adxl345Rate_LowPowerBit } return bits } ================================================ FILE: drivers/i2c/adxl345_driver_test.go ================================================ package i2c import ( "errors" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) // this ensures that the implementation is based on i2c.Driver, which implements the gobot.Driver // and tests all implementations, so no further tests needed here for gobot.Driver interface var _ gobot.Driver = (*ADXL345Driver)(nil) func initTestADXL345WithStubbedAdaptor() (*ADXL345Driver, *i2cTestAdaptor) { a := newI2cTestAdaptor() d := NewADXL345Driver(a) return d, a } func TestNewADXL345Driver(t *testing.T) { var di interface{} = NewADXL345Driver(newI2cTestAdaptor()) d, ok := di.(*ADXL345Driver) if !ok { require.Fail(t, "NewADXL345Driver() should have returned a *ADXL345Driver") } assert.NotNil(t, d.Driver) assert.True(t, strings.HasPrefix(d.Name(), "ADXL345")) assert.Equal(t, 0x53, d.defaultAddress) assert.Equal(t, uint8(1), d.powerCtl.measure) assert.Equal(t, ADXL345FsRangeConfig(0x00), d.dataFormat.fullScaleRange) assert.Equal(t, ADXL345RateConfig(0x0A), d.bwRate.rate) assert.True(t, d.bwRate.lowPower) } func TestADXL345Halt(t *testing.T) { // arrange d := NewADXL345Driver(newI2cTestAdaptor()) // act, assert require.NoError(t, d.Halt()) // must be idempotent require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestADXL345Options(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithBus() option and // least one of this driver. Further tests for options can also be done by call of "WithOption(val)(d)". d := NewADXL345Driver(newI2cTestAdaptor(), WithBus(2), WithADXL345LowPowerMode(false)) assert.Equal(t, 2, d.GetBusOrDefault(1)) assert.False(t, d.bwRate.lowPower) } func TestADXL345WithADXL345DataOutputRate(t *testing.T) { // arrange d, a := initTestADXL345WithStubbedAdaptor() a.written = []byte{} // reset writes of former test const ( setVal = ADXL345RateConfig(0x0E) // 1.6kHz ) // act WithADXL345DataOutputRate(setVal)(d) // assert assert.Equal(t, setVal, d.bwRate.rate) assert.Empty(t, a.written) } func TestADXL345WithADXL345FullScaleRange(t *testing.T) { // arrange d, a := initTestADXL345WithStubbedAdaptor() a.written = []byte{} // reset writes of former test const ( setVal = ADXL345FsRangeConfig(0x02) // +-8 g ) // act WithADXL345FullScaleRange(setVal)(d) // assert assert.Equal(t, setVal, d.dataFormat.fullScaleRange) assert.Empty(t, a.written) } func TestADXL345UseLowPower(t *testing.T) { // sequence to set low power: // * set value in data rate structure // * write the data rate register (0x2C) d, a := initTestADXL345WithStubbedAdaptor() _ = d.Start() a.written = []byte{} // reset writes of former test setVal := !d.bwRate.lowPower const ( wantReg = uint8(0x2C) wantVal = uint8(0x0A) // only 100 Hz left over ) // act err := d.UseLowPower(setVal) // assert require.NoError(t, err) assert.Equal(t, setVal, d.bwRate.lowPower) assert.Len(t, a.written, 2) assert.Equal(t, wantReg, a.written[0]) assert.Equal(t, wantVal, a.written[1]) } func TestADXL345SetRate(t *testing.T) { // sequence to set rate: // * set value in data rate structure // * write the data rate register (0x2C) d, a := initTestADXL345WithStubbedAdaptor() _ = d.Start() a.written = []byte{} // reset writes of former test const ( setVal = ADXL345RateConfig(0x0F) // 3.2kHz wantReg = uint8(0x2C) wantVal = uint8(0x1F) // also low power bit ) // act err := d.SetRate(setVal) // assert require.NoError(t, err) assert.Equal(t, setVal, d.bwRate.rate) assert.Len(t, a.written, 2) assert.Equal(t, wantReg, a.written[0]) assert.Equal(t, wantVal, a.written[1]) } func TestADXL345SetRange(t *testing.T) { // sequence to set range: // * set value in data format structure // * write the data format register (0x31) d, a := initTestADXL345WithStubbedAdaptor() _ = d.Start() a.written = []byte{} // reset writes of former test const ( setVal = ADXL345FsRangeConfig(0x03) // +/- 16 g wantReg = uint8(0x31) wantVal = uint8(0x03) ) // act err := d.SetRange(setVal) // assert require.NoError(t, err) assert.Equal(t, setVal, d.dataFormat.fullScaleRange) assert.Len(t, a.written, 2) assert.Equal(t, wantReg, a.written[0]) assert.Equal(t, wantVal, a.written[1]) } func TestADXL345RawXYZ(t *testing.T) { // sequence to read: // * prepare read, see test of initialize() // * read data output registers (0x32, 3 x 16 bit, LSByte first) // * apply two's complement converter // // arrange tests := map[string]struct { inputX []uint8 inputY []uint8 inputZ []uint8 wantX int16 wantY int16 wantZ int16 }{ "+FS_0_-FS": { inputX: []uint8{0xFF, 0x07}, inputY: []uint8{0x00, 0x00}, inputZ: []uint8{0x00, 0xF8}, wantX: (1<<11 - 1), wantY: 0, wantZ: -(1 << 11), }, "-4096_-1_+1": { inputX: []uint8{0x00, 0xF0}, inputY: []uint8{0xFF, 0xFF}, inputZ: []uint8{0x01, 0x00}, wantX: -4096, wantY: -1, wantZ: 1, }, } d, a := initTestADXL345WithStubbedAdaptor() _ = d.Start() for name, tc := range tests { t.Run(name, func(t *testing.T) { a.written = []byte{} // reset writes of former test and start // arrange reads returnRead := append(append(tc.inputX, tc.inputY...), tc.inputZ...) numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ copy(b, returnRead) return len(b), nil } // act gotX, gotY, gotZ, err := d.RawXYZ() // assert require.NoError(t, err) assert.Equal(t, tc.wantX, gotX) assert.Equal(t, tc.wantY, gotY) assert.Equal(t, tc.wantZ, gotZ) assert.Equal(t, 1, numCallsRead) assert.Len(t, a.written, 1) assert.Equal(t, uint8(0x32), a.written[0]) }) } } func TestADXL345RawXYZError(t *testing.T) { // arrange d, a := initTestADXL345WithStubbedAdaptor() _ = d.Start() a.i2cReadImpl = func(b []byte) (int, error) { return 0, errors.New("read error") } // act x, y, z, err := d.RawXYZ() // assert require.ErrorContains(t, err, "read error") assert.Equal(t, int16(0), x) assert.Equal(t, int16(0), y) assert.Equal(t, int16(0), z) } func TestADXL345XYZ(t *testing.T) { // arrange tests := map[string]struct { inputX []uint8 inputY []uint8 inputZ []uint8 wantX float64 wantY float64 wantZ float64 }{ "null_value": { inputX: []uint8{0, 0}, inputY: []uint8{0, 0}, inputZ: []uint8{0, 0}, wantX: 0, wantY: 0, wantZ: 0, }, "some_value": { inputX: []uint8{218, 0}, inputY: []uint8{251, 255}, inputZ: []uint8{100, 0}, wantX: 0.8515625, wantY: -0.01953125, wantZ: 0.390625, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, a := initTestADXL345WithStubbedAdaptor() _ = d.Start() a.written = []byte{} // reset writes of former test and start // arrange reads returnRead := append(append(tc.inputX, tc.inputY...), tc.inputZ...) numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ copy(b, returnRead) return len(b), nil } // act x, y, z, _ := d.XYZ() // assert assert.InDelta(t, tc.wantX, x, 0.0) assert.InDelta(t, tc.wantY, y, 0.0) assert.InDelta(t, tc.wantZ, z, 0.0) }) } } func TestADXL345XYZError(t *testing.T) { // arrange d, a := initTestADXL345WithStubbedAdaptor() _ = d.Start() a.i2cReadImpl = func(b []byte) (int, error) { return 0, errors.New("read error") } // act x, y, z, err := d.XYZ() // assert require.ErrorContains(t, err, "read error") assert.InDelta(t, 0.0, x, 0.0) assert.InDelta(t, 0.0, y, 0.0) assert.InDelta(t, 0.0, z, 0.0) } func TestADXL345_initialize(t *testing.T) { // sequence to prepare read in initialize(): // * prepare rate register content (data output rate, low power mode) // * prepare power control register content (wake up, sleep, measure, auto sleep, link) // * prepare data format register (fullScaleRange, justify, fullRes, intInvert, spi, selfTest) // * write 3 registers // arrange d, a := initTestADXL345WithStubbedAdaptor() a.written = []byte{} // reset writes of former test const ( wantRateReg = uint8(0x2C) wantRateRegVal = uint8(0x1A) // 100HZ and low power wantPwrReg = uint8(0x2D) wantPwrRegVal = uint8(0x08) // measurement on wantFormatReg = uint8(0x31) wantFormatRegVal = uint8(0x00) // FS to +/-2 g ) // act, assert - initialize() must be called on Start() err := d.Start() // assert require.NoError(t, err) assert.Len(t, a.written, 6) assert.Equal(t, wantRateReg, a.written[0]) assert.Equal(t, wantRateRegVal, a.written[1]) assert.Equal(t, wantPwrReg, a.written[2]) assert.Equal(t, wantPwrRegVal, a.written[3]) assert.Equal(t, wantFormatReg, a.written[4]) assert.Equal(t, wantFormatRegVal, a.written[5]) } func TestADXL345_shutdown(t *testing.T) { // sequence to prepare read in shutdown(): // * reset the measurement bit in structure // * write the power control register (0x2D) d, a := initTestADXL345WithStubbedAdaptor() _ = d.Start() a.written = []byte{} // reset writes of former test const ( wantReg = uint8(0x2D) wantVal = uint8(0x00) ) // act, assert - shutdown() must be called on Halt() err := d.Halt() // assert require.NoError(t, err) assert.Len(t, a.written, 2) assert.Equal(t, wantReg, a.written[0]) assert.Equal(t, wantVal, a.written[1]) } ================================================ FILE: drivers/i2c/bh1750_driver.go ================================================ package i2c import ( "errors" "time" ) const bh1750DefaultAddress = 0x23 const ( BH1750_POWER_DOWN = 0x00 BH1750_POWER_ON = 0x01 BH1750_RESET = 0x07 BH1750_CONTINUOUS_HIGH_RES_MODE = 0x10 BH1750_CONTINUOUS_HIGH_RES_MODE_2 = 0x11 BH1750_CONTINUOUS_LOW_RES_MODE = 0x13 BH1750_ONE_TIME_HIGH_RES_MODE = 0x20 BH1750_ONE_TIME_HIGH_RES_MODE_2 = 0x21 BH1750_ONE_TIME_LOW_RES_MODE = 0x23 ) // BH1750Driver is a driver for the BH1750 digital Ambient Light Sensor IC for I²C bus interface. type BH1750Driver struct { *Driver mode byte } // NewBH1750Driver creates a new driver with specified i2c interface // Params: // // c Connector - the Adaptor to use with this Driver // // Optional params: // // i2c.WithBus(int): bus to use with this driver // i2c.WithAddress(int): address to use with this driver func NewBH1750Driver(c Connector, options ...func(Config)) *BH1750Driver { d := &BH1750Driver{ Driver: NewDriver(c, "BH1750", bh1750DefaultAddress), mode: BH1750_CONTINUOUS_HIGH_RES_MODE, } d.afterStart = d.initialize for _, option := range options { option(d) } // TODO: add commands for API return d } // RawSensorData returns the raw value from the bh1750 func (d *BH1750Driver) RawSensorData() (int, error) { buf := []byte{0, 0} bytesRead, err := d.read(buf) if err != nil { return 0, err } if bytesRead != 2 { return 0, errors.New("wrong number of bytes read") } level := int(buf[0])<<8 | int(buf[1]) return level, nil } // Lux returns the adjusted value from the bh1750 func (d *BH1750Driver) Lux() (int, error) { rawLux, err := d.RawSensorData() lux := int(float64(rawLux) / 1.2) return lux, err } func (d *BH1750Driver) initialize() error { err := d.writeByte(d.mode) time.Sleep(10 * time.Microsecond) if err != nil { return err } return nil } ================================================ FILE: drivers/i2c/bh1750_driver_test.go ================================================ package i2c import ( "bytes" "errors" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) // this ensures that the implementation is based on i2c.Driver, which implements the gobot.Driver // and tests all implementations, so no further tests needed here for gobot.Driver interface var _ gobot.Driver = (*BH1750Driver)(nil) func initTestBH1750DriverWithStubbedAdaptor() (*BH1750Driver, *i2cTestAdaptor) { a := newI2cTestAdaptor() d := NewBH1750Driver(a) if err := d.Start(); err != nil { panic(err) } return d, a } func TestNewBH1750Driver(t *testing.T) { var di interface{} = NewBH1750Driver(newI2cTestAdaptor()) d, ok := di.(*BH1750Driver) if !ok { require.Fail(t, "NewBH1750Driver() should have returned a *BH1750Driver") } assert.NotNil(t, d.Driver) assert.True(t, strings.HasPrefix(d.Name(), "BH1750")) assert.Equal(t, 0x23, d.defaultAddress) } func TestBH1750Options(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithBus() option and // least one of this driver. Further tests for options can also be done by call of "WithOption(val)(d)". d := NewBH1750Driver(newI2cTestAdaptor(), WithBus(2)) assert.Equal(t, 2, d.GetBusOrDefault(1)) } func TestBH1750Start(t *testing.T) { d := NewBH1750Driver(newI2cTestAdaptor()) require.NoError(t, d.Start()) } func TestBH1750Halt(t *testing.T) { d := NewBH1750Driver(newI2cTestAdaptor()) require.NoError(t, d.Halt()) // must be idempotent require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestBH1750NullLux(t *testing.T) { d, _ := initTestBH1750DriverWithStubbedAdaptor() lux, _ := d.Lux() assert.Equal(t, 0, lux) } func TestBH1750Lux(t *testing.T) { d, a := initTestBH1750DriverWithStubbedAdaptor() a.i2cReadImpl = func(b []byte) (int, error) { buf := new(bytes.Buffer) buf.Write([]byte{0x05, 0xb0}) copy(b, buf.Bytes()) return buf.Len(), nil } lux, _ := d.Lux() assert.Equal(t, 1213, lux) } func TestBH1750NullRawSensorData(t *testing.T) { d, _ := initTestBH1750DriverWithStubbedAdaptor() level, _ := d.RawSensorData() assert.Equal(t, 0, level) } func TestBH1750RawSensorData(t *testing.T) { d, a := initTestBH1750DriverWithStubbedAdaptor() a.i2cReadImpl = func(b []byte) (int, error) { buf := new(bytes.Buffer) buf.Write([]byte{0x05, 0xb0}) copy(b, buf.Bytes()) return buf.Len(), nil } level, _ := d.RawSensorData() assert.Equal(t, 1456, level) } func TestBH1750LuxError(t *testing.T) { d, a := initTestBH1750DriverWithStubbedAdaptor() a.i2cReadImpl = func(b []byte) (int, error) { return 0, errors.New("wrong number of bytes read") } _, err := d.Lux() require.ErrorContains(t, err, "wrong number of bytes read") } func TestBH1750RawSensorDataError(t *testing.T) { d, a := initTestBH1750DriverWithStubbedAdaptor() a.i2cReadImpl = func(b []byte) (int, error) { return 0, errors.New("wrong number of bytes read") } _, err := d.RawSensorData() require.ErrorContains(t, err, "wrong number of bytes read") } ================================================ FILE: drivers/i2c/blinkm_driver.go ================================================ package i2c import ( "fmt" ) const blinkmDefaultAddress = 0x09 // BlinkMDriver is a Gobot Driver for a BlinkM LED type BlinkMDriver struct { *Driver } // NewBlinkMDriver creates a new BlinkMDriver. // // Params: // // c Connector - the Adaptor to use with this Driver // // Optional params: // // i2c.WithBus(int): bus to use with this driver // i2c.WithAddress(int): address to use with this driver func NewBlinkMDriver(c Connector, options ...func(Config)) *BlinkMDriver { b := &BlinkMDriver{ Driver: NewDriver(c, "BlinkM", blinkmDefaultAddress), } b.afterStart = b.initialize for _, option := range options { option(b) } //nolint:forcetypeassert // ok here b.AddCommand("Rgb", func(params map[string]interface{}) interface{} { red := byte(params["red"].(float64)) green := byte(params["green"].(float64)) blue := byte(params["blue"].(float64)) return b.Rgb(red, green, blue) }) //nolint:forcetypeassert // ok here b.AddCommand("Fade", func(params map[string]interface{}) interface{} { red := byte(params["red"].(float64)) green := byte(params["green"].(float64)) blue := byte(params["blue"].(float64)) return b.Fade(red, green, blue) }) b.AddCommand("FirmwareVersion", func(_ map[string]interface{}) interface{} { version, err := b.FirmwareVersion() return map[string]interface{}{"version": version, "err": err} }) b.AddCommand("Color", func(_ map[string]interface{}) interface{} { color, err := b.Color() return map[string]interface{}{"color": color, "err": err} }) return b } // Rgb sets color using r,g,b params func (b *BlinkMDriver) Rgb(red byte, green byte, blue byte) error { if _, err := b.connection.Write([]byte("n")); err != nil { return err } _, err := b.connection.Write([]byte{red, green, blue}) return err } // Fade removes color using r,g,b params func (b *BlinkMDriver) Fade(red byte, green byte, blue byte) error { if _, err := b.connection.Write([]byte("c")); err != nil { return err } _, err := b.connection.Write([]byte{red, green, blue}) return err } // FirmwareVersion returns version with MAYOR.minor format func (b *BlinkMDriver) FirmwareVersion() (string, error) { if _, err := b.connection.Write([]byte("Z")); err != nil { return "", err } data := []byte{0, 0} read, err := b.connection.Read(data) if read != 2 || err != nil { return "", err } return fmt.Sprintf("%v.%v", data[0], data[1]), nil } // Color returns an array with current rgb color func (b *BlinkMDriver) Color() ([]byte, error) { if _, err := b.connection.Write([]byte("g")); err != nil { return []byte{}, err } data := []byte{0, 0, 0} read, err := b.connection.Read(data) if read != 3 || err != nil { return []byte{}, err } return []byte{data[0], data[1], data[2]}, nil } func (b *BlinkMDriver) initialize() error { if _, err := b.connection.Write([]byte("o")); err != nil { return err } return nil } ================================================ FILE: drivers/i2c/blinkm_driver_test.go ================================================ //nolint:forcetypeassert // ok here package i2c import ( "errors" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) // this ensures that the implementation is based on i2c.Driver, which implements the gobot.Driver // and tests all implementations, so no further tests needed here for gobot.Driver interface var _ gobot.Driver = (*BlinkMDriver)(nil) func initTestBlinkMDriverWithStubbedAdaptor() (*BlinkMDriver, *i2cTestAdaptor) { a := newI2cTestAdaptor() d := NewBlinkMDriver(a) if err := d.Start(); err != nil { panic(err) } return d, a } func TestNewBlinkMDriver(t *testing.T) { var di interface{} = NewBlinkMDriver(newI2cTestAdaptor()) d, ok := di.(*BlinkMDriver) if !ok { require.Fail(t, "NewBlinkMDriver() should have returned a *BlinkMDriver") } assert.NotNil(t, d.Driver) assert.True(t, strings.HasPrefix(d.Name(), "BlinkM")) assert.Equal(t, 0x09, d.defaultAddress) } func TestBlinkMOptions(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithBus() option and // least one of this driver. Further tests for options can also be done by call of "WithOption(val)(d)". d := NewBlinkMDriver(newI2cTestAdaptor(), WithBus(2)) assert.Equal(t, 2, d.GetBusOrDefault(1)) } func TestBlinkMStart(t *testing.T) { d := NewBlinkMDriver(newI2cTestAdaptor()) require.NoError(t, d.Start()) } func TestBlinkMHalt(t *testing.T) { d := NewBlinkMDriver(newI2cTestAdaptor()) require.NoError(t, d.Halt()) // must be idempotent require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } // Commands func TestNewBlinkMDriverCommands_Rgb(t *testing.T) { d, _ := initTestBlinkMDriverWithStubbedAdaptor() result := d.Command("Rgb")(rgb) assert.Nil(t, result) } func TestNewBlinkMDriverCommands_Fade(t *testing.T) { d, _ := initTestBlinkMDriverWithStubbedAdaptor() result := d.Command("Fade")(rgb) assert.Nil(t, result) } func TestNewBlinkMDriverCommands_FirmwareVersion(t *testing.T) { d, a := initTestBlinkMDriverWithStubbedAdaptor() param := make(map[string]interface{}) // When len(data) is 2 a.i2cReadImpl = func(b []byte) (int, error) { copy(b, []byte{99, 1}) return 2, nil } result := d.Command("FirmwareVersion")(param) version, _ := d.FirmwareVersion() assert.Equal(t, version, result.(map[string]interface{})["version"].(string)) // When len(data) is not 2 a.i2cReadImpl = func(b []byte) (int, error) { copy(b, []byte{99}) return 1, nil } result = d.Command("FirmwareVersion")(param) version, _ = d.FirmwareVersion() assert.Equal(t, version, result.(map[string]interface{})["version"].(string)) } func TestNewBlinkMDriverCommands_Color(t *testing.T) { d, _ := initTestBlinkMDriverWithStubbedAdaptor() param := make(map[string]interface{}) result := d.Command("Color")(param) color, _ := d.Color() assert.Equal(t, color, result.(map[string]interface{})["color"].([]byte)) } func TestBlinkMFirmwareVersion(t *testing.T) { d, a := initTestBlinkMDriverWithStubbedAdaptor() // when len(data) is 2 a.i2cReadImpl = func(b []byte) (int, error) { copy(b, []byte{99, 1}) return 2, nil } version, _ := d.FirmwareVersion() assert.Equal(t, "99.1", version) // when len(data) is not 2 a.i2cReadImpl = func(b []byte) (int, error) { copy(b, []byte{99}) return 1, nil } version, _ = d.FirmwareVersion() assert.Empty(t, version) a.i2cWriteImpl = func([]byte) (int, error) { return 0, errors.New("write error") } _, err := d.FirmwareVersion() require.ErrorContains(t, err, "write error") } func TestBlinkMColor(t *testing.T) { d, a := initTestBlinkMDriverWithStubbedAdaptor() // when len(data) is 3 a.i2cReadImpl = func(b []byte) (int, error) { copy(b, []byte{99, 1, 2}) return 3, nil } color, _ := d.Color() assert.Equal(t, []byte{99, 1, 2}, color) // when len(data) is not 3 a.i2cReadImpl = func(b []byte) (int, error) { copy(b, []byte{99}) return 1, nil } color, _ = d.Color() assert.Equal(t, []byte{}, color) a.i2cWriteImpl = func([]byte) (int, error) { return 0, errors.New("write error") } _, err := d.Color() require.ErrorContains(t, err, "write error") } func TestBlinkMFade(t *testing.T) { d, a := initTestBlinkMDriverWithStubbedAdaptor() a.i2cWriteImpl = func([]byte) (int, error) { return 0, errors.New("write error") } err := d.Fade(100, 100, 100) require.ErrorContains(t, err, "write error") } func TestBlinkMRGB(t *testing.T) { d, a := initTestBlinkMDriverWithStubbedAdaptor() a.i2cWriteImpl = func([]byte) (int, error) { return 0, errors.New("write error") } err := d.Rgb(100, 100, 100) require.ErrorContains(t, err, "write error") } ================================================ FILE: drivers/i2c/bme280_driver.go ================================================ package i2c import ( "bytes" "encoding/binary" "errors" "log" "gobot.io/x/gobot/v2" ) const bme280Debug = true type BME280HumidityOversampling uint8 const ( bme280RegCalibDigH1 = 0xA1 bme280RegCalibDigH2LSB = 0xE1 bme280RegControlHumidity = 0xF2 bme280RegHumidityMSB = 0xFD // bits 0, 1, 3 of control humidity register BME280CtrlHumidityNoMeasurement BME280HumidityOversampling = 0x00 // no measurement (value will be 0x08 0x00 0x00) BME280CtrlHumidityOversampling1 BME280HumidityOversampling = 0x01 BME280CtrlHumidityOversampling2 BME280HumidityOversampling = 0x02 BME280CtrlHumidityOversampling4 BME280HumidityOversampling = 0x03 BME280CtrlHumidityOversampling8 BME280HumidityOversampling = 0x04 BME280CtrlHumidityOversampling16 BME280HumidityOversampling = 0x05 // same as 0x06, 0x07 ) type bmeHumidityCalibrationCoefficients struct { h1 uint8 h2 int16 h3 uint8 h4 int16 h5 int16 h6 int8 } // BME280Driver is a driver for the BME280 temperature/humidity sensor. // It implements all of the same functions as the BMP280Driver, but also // adds the Humidity() function by reading the BME280's humidity sensor. // For details on the BMP280Driver please see: // // https://godoc.org/gobot.io/x/gobot/v2/drivers/i2c#BMP280Driver type BME280Driver struct { *BMP280Driver humCalCoeffs *bmeHumidityCalibrationCoefficients ctrlHumOversamp BME280HumidityOversampling } // NewBME280Driver creates a new driver with specified i2c interface. // Params: // // conn Connector - the Adaptor to use with this Driver // // Optional params: // // i2c.WithBus(int): bus to use with this driver // i2c.WithAddress(int): address to use with this driver func NewBME280Driver(c Connector, options ...func(Config)) *BME280Driver { d := &BME280Driver{ BMP280Driver: NewBMP280Driver(c), humCalCoeffs: &bmeHumidityCalibrationCoefficients{}, ctrlHumOversamp: BME280CtrlHumidityOversampling16, } d.name = gobot.DefaultName("BME280") d.afterStart = d.initializationBME280 // this loop is for options of this class, all options of base class BMP280Driver // must be added in this class for usage for _, option := range options { option(d) } // TODO: expose commands to API return d } // WithBME280PressureOversampling option sets the oversampling for pressure. // Valid settings are of type "BMP280PressureOversampling" func WithBME280PressureOversampling(val BMP280PressureOversampling) func(Config) { return func(c Config) { if d, ok := c.(*BME280Driver); ok { d.ctrlPressOversamp = val } else if bme280Debug { log.Printf("Trying to set pressure oversampling for non-BME280Driver %v", c) } } } // WithBME280TemperatureOversampling option sets oversampling for temperature. // Valid settings are of type "BMP280TemperatureOversampling" func WithBME280TemperatureOversampling(val BMP280TemperatureOversampling) func(Config) { return func(c Config) { if d, ok := c.(*BME280Driver); ok { d.ctrlTempOversamp = val } else if bme280Debug { log.Printf("Trying to set temperature oversampling for non-BME280Driver %v", c) } } } // WithBME280IIRFilter option sets the count of IIR filter coefficients. // Valid settings are of type "BMP280IIRFilter" func WithBME280IIRFilter(val BMP280IIRFilter) func(Config) { return func(c Config) { if d, ok := c.(*BME280Driver); ok { d.confFilter = val } else if bme280Debug { log.Printf("Trying to set IIR filter for non-BME280Driver %v", c) } } } // WithBME280HumidityOversampling option sets the oversampling for humidity. // Valid settings are of type "BME280HumidityOversampling" func WithBME280HumidityOversampling(val BME280HumidityOversampling) func(Config) { return func(c Config) { if d, ok := c.(*BME280Driver); ok { d.ctrlHumOversamp = val } else if bme280Debug { log.Printf("Trying to set humidity oversampling for non-BME280Driver %v", c) } } } // Humidity returns the current humidity in percentage of relative humidity func (d *BME280Driver) Humidity() (float32, error) { d.mutex.Lock() defer d.mutex.Unlock() rawH, err := d.rawHumidity() if err != nil { return 0.0, err } humidity := d.calculateHumidity(rawH) return humidity, nil } func (d *BME280Driver) initializationBME280() error { // call the initialization routine of base class BMP280Driver, which do: // * initializes temperature and pressure calibration coefficients // * set the control register // * set the configuration register if err := d.initialization(); err != nil { return err } if err := d.initHumidity(); err != nil { return err } return nil } // read the humidity calibration coefficients. func (d *BME280Driver) initHumidity() error { hch1, err := d.readByteData(bme280RegCalibDigH1) if err != nil { return err } buf := bytes.NewBuffer([]byte{hch1}) if err := binary.Read(buf, binary.BigEndian, &d.humCalCoeffs.h1); err != nil { return err } coefficients := make([]byte, 7) if err = d.readBlockData(bme280RegCalibDigH2LSB, coefficients); err != nil { return err } buf = bytes.NewBuffer(coefficients) // H4 and H5 laid out strangely on the bme280 var addrE4 byte var addrE5 byte var addrE6 byte // E1 ... if err := binary.Read(buf, binary.LittleEndian, &d.humCalCoeffs.h2); err != nil { return err } // E3 if err := binary.Read(buf, binary.BigEndian, &d.humCalCoeffs.h3); err != nil { return err } // E4 if err := binary.Read(buf, binary.BigEndian, &addrE4); err != nil { return err } // E5 if err := binary.Read(buf, binary.BigEndian, &addrE5); err != nil { return err } // E6 if err := binary.Read(buf, binary.BigEndian, &addrE6); err != nil { return err } // ... E7 if err := binary.Read(buf, binary.BigEndian, &d.humCalCoeffs.h6); err != nil { return err } d.humCalCoeffs.h4 = 0 + (int16(addrE4) << 4) | (int16(addrE5 & 0x0F)) d.humCalCoeffs.h5 = 0 + (int16(addrE6) << 4) | (int16(addrE5) >> 4) // The 'ctrl_hum' register (0xF2) sets the humidity data acquisition options of // the device. Changes to this register only become effective after a write // operation to 'ctrl_meas' (0xF4). So we read the current value in, then write it back if err := d.writeByteData(bme280RegControlHumidity, uint8(d.ctrlHumOversamp)); err != nil { return err } cmr, err := d.readByteData(bmp280RegCtrl) if err != nil { return err } return d.writeByteData(bmp280RegCtrl, cmr) } func (d *BME280Driver) rawHumidity() (uint32, error) { ret := make([]byte, 2) if err := d.readBlockData(bme280RegHumidityMSB, ret); err != nil { return 0, err } if ret[0] == 0x80 && ret[1] == 0x00 { return 0, errors.New("Humidity disabled") } buf := bytes.NewBuffer(ret) var rawH uint16 if err := binary.Read(buf, binary.BigEndian, &rawH); err != nil { return 0, err } return uint32(rawH), nil } // Adapted from https://github.com/BoschSensortec/BME280_driver/blob/master/bme280.c // function bme280_compensate_humidity_double(s32 v_uncom_humidity_s32) func (d *BME280Driver) calculateHumidity(rawH uint32) float32 { var rawT int32 var err error var h float32 rawT, err = d.rawTemp() if err != nil { return 0 } _, tFine := d.calculateTemp(rawT) h = float32(tFine) - 76800 if h == 0 { return 0 // TODO err is 'invalid data' from Bosch - include errors or not? } x := float32(rawH) - (float32(d.humCalCoeffs.h4)*64.0 + (float32(d.humCalCoeffs.h5) / 16384.0 * h)) y := float32(d.humCalCoeffs.h2) / 65536.0 * (1.0 + float32(d.humCalCoeffs.h6)/67108864.0*h* (1.0+float32(d.humCalCoeffs.h3)/67108864.0*h)) h = x * y h = h * (1 - float32(d.humCalCoeffs.h1)*h/524288) return h } ================================================ FILE: drivers/i2c/bme280_driver_test.go ================================================ package i2c import ( "bytes" "errors" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) // this ensures that the implementation is based on i2c.Driver, which implements the gobot.Driver // and tests all implementations, so no further tests needed here for gobot.Driver interface var _ gobot.Driver = (*BME280Driver)(nil) func initTestBME280WithStubbedAdaptor() (*BME280Driver, *i2cTestAdaptor) { adaptor := newI2cTestAdaptor() return NewBME280Driver(adaptor), adaptor } func TestNewBME280Driver(t *testing.T) { var di interface{} = NewBME280Driver(newI2cTestAdaptor()) d, ok := di.(*BME280Driver) if !ok { require.Fail(t, "NewBME280Driver() should have returned a *BME280Driver") } assert.NotNil(t, d.Driver) assert.True(t, strings.HasPrefix(d.Name(), "BME280")) assert.Equal(t, 0x77, d.defaultAddress) assert.Equal(t, uint8(0x03), d.ctrlPwrMode) assert.Equal(t, BMP280PressureOversampling(0x05), d.ctrlPressOversamp) assert.Equal(t, BMP280TemperatureOversampling(0x01), d.ctrlTempOversamp) assert.Equal(t, BME280HumidityOversampling(0x05), d.ctrlHumOversamp) assert.Equal(t, BMP280IIRFilter(0x00), d.confFilter) assert.NotNil(t, d.calCoeffs) } func TestBME280Halt(t *testing.T) { // arrange d := NewBME280Driver(newI2cTestAdaptor()) // act, assert require.NoError(t, d.Halt()) // must be idempotent require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestBME280Options(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithBus() option and // least one of this driver. Further tests for options can also be done by call of "WithOption(val)(d)". d := NewBME280Driver(newI2cTestAdaptor(), WithBus(2), WithBME280PressureOversampling(0x01), WithBME280TemperatureOversampling(0x02), WithBME280IIRFilter(0x03), WithBME280HumidityOversampling(0x04)) assert.Equal(t, 2, d.GetBusOrDefault(1)) assert.Equal(t, BMP280PressureOversampling(0x01), d.ctrlPressOversamp) assert.Equal(t, BMP280TemperatureOversampling(0x02), d.ctrlTempOversamp) assert.Equal(t, BMP280IIRFilter(0x03), d.confFilter) assert.Equal(t, BME280HumidityOversampling(0x04), d.ctrlHumOversamp) } func TestBME280Measurements(t *testing.T) { bme280, adaptor := initTestBME280WithStubbedAdaptor() adaptor.i2cReadImpl = func(b []byte) (int, error) { buf := new(bytes.Buffer) // Values produced by dumping data from actual sensor switch { case adaptor.written[len(adaptor.written)-1] == bmp280RegCalib00: buf.Write([]byte{ 126, 109, 214, 102, 50, 0, 54, 149, 220, 213, 208, 11, 64, 30, 166, 255, 249, 255, 172, 38, 10, 216, 189, 16, }) case adaptor.written[len(adaptor.written)-1] == bme280RegCalibDigH1: buf.Write([]byte{75}) case adaptor.written[len(adaptor.written)-1] == bmp280RegTempData: buf.Write([]byte{129, 0, 0}) case adaptor.written[len(adaptor.written)-1] == bme280RegCalibDigH2LSB: buf.Write([]byte{112, 1, 0, 19, 1, 0, 30}) case adaptor.written[len(adaptor.written)-1] == bme280RegHumidityMSB: buf.Write([]byte{111, 83}) } copy(b, buf.Bytes()) return buf.Len(), nil } _ = bme280.Start() hum, err := bme280.Humidity() require.NoError(t, err) assert.InDelta(t, float32(51.20179), hum, 0.0) } func TestBME280InitH1Error(t *testing.T) { bme280, adaptor := initTestBME280WithStubbedAdaptor() adaptor.i2cReadImpl = func(b []byte) (int, error) { buf := new(bytes.Buffer) // Values produced by dumping data from actual sensor switch { case adaptor.written[len(adaptor.written)-1] == bmp280RegCalib00: buf.Write([]byte{ 126, 109, 214, 102, 50, 0, 54, 149, 220, 213, 208, 11, 64, 30, 166, 255, 249, 255, 172, 38, 10, 216, 189, 16, }) case adaptor.written[len(adaptor.written)-1] == bme280RegCalibDigH1: return 0, errors.New("h1 read error") case adaptor.written[len(adaptor.written)-1] == bme280RegCalibDigH2LSB: buf.Write([]byte{112, 1, 0, 19, 1, 0, 30}) } copy(b, buf.Bytes()) return buf.Len(), nil } require.ErrorContains(t, bme280.Start(), "h1 read error") } func TestBME280InitH2Error(t *testing.T) { bme280, adaptor := initTestBME280WithStubbedAdaptor() adaptor.i2cReadImpl = func(b []byte) (int, error) { buf := new(bytes.Buffer) // Values produced by dumping data from actual sensor switch { case adaptor.written[len(adaptor.written)-1] == bmp280RegCalib00: buf.Write([]byte{ 126, 109, 214, 102, 50, 0, 54, 149, 220, 213, 208, 11, 64, 30, 166, 255, 249, 255, 172, 38, 10, 216, 189, 16, }) case adaptor.written[len(adaptor.written)-1] == bme280RegCalibDigH1: buf.Write([]byte{75}) case adaptor.written[len(adaptor.written)-1] == bme280RegCalibDigH2LSB: return 0, errors.New("h2 read error") } copy(b, buf.Bytes()) return buf.Len(), nil } require.ErrorContains(t, bme280.Start(), "h2 read error") } func TestBME280HumidityWriteError(t *testing.T) { bme280, adaptor := initTestBME280WithStubbedAdaptor() _ = bme280.Start() adaptor.i2cWriteImpl = func([]byte) (int, error) { return 0, errors.New("write error") } hum, err := bme280.Humidity() require.ErrorContains(t, err, "write error") assert.InDelta(t, float32(0.0), hum, 0.0) } func TestBME280HumidityReadError(t *testing.T) { bme280, adaptor := initTestBME280WithStubbedAdaptor() _ = bme280.Start() adaptor.i2cReadImpl = func([]byte) (int, error) { return 0, errors.New("read error") } hum, err := bme280.Humidity() require.ErrorContains(t, err, "read error") assert.InDelta(t, float32(0.0), hum, 0.0) } func TestBME280HumidityNotEnabled(t *testing.T) { bme280, adaptor := initTestBME280WithStubbedAdaptor() adaptor.i2cReadImpl = func(b []byte) (int, error) { buf := new(bytes.Buffer) // Values produced by dumping data from actual sensor switch { case adaptor.written[len(adaptor.written)-1] == bmp280RegCalib00: buf.Write([]byte{ 126, 109, 214, 102, 50, 0, 54, 149, 220, 213, 208, 11, 64, 30, 166, 255, 249, 255, 172, 38, 10, 216, 189, 16, }) case adaptor.written[len(adaptor.written)-1] == bme280RegCalibDigH1: buf.Write([]byte{75}) case adaptor.written[len(adaptor.written)-1] == bmp280RegTempData: buf.Write([]byte{129, 0, 0}) case adaptor.written[len(adaptor.written)-1] == bme280RegCalibDigH2LSB: buf.Write([]byte{112, 1, 0, 19, 1, 0, 30}) case adaptor.written[len(adaptor.written)-1] == bme280RegHumidityMSB: buf.Write([]byte{0x80, 0x00}) } copy(b, buf.Bytes()) return buf.Len(), nil } _ = bme280.Start() hum, err := bme280.Humidity() require.ErrorContains(t, err, "Humidity disabled") assert.InDelta(t, float32(0.0), hum, 0.0) } func TestBME280_initializationBME280(t *testing.T) { bme280, adaptor := initTestBME280WithStubbedAdaptor() readCallCounter := 0 adaptor.i2cReadImpl = func(b []byte) (int, error) { readCallCounter++ if readCallCounter == 1 { // Simulate returning 24 bytes for the coefficients (register bmp280RegCalib00) return 24, nil } if readCallCounter == 2 { // Simulate returning a single byte for the hc.h1 value (register bme280RegCalibDigH1) return 1, nil } if readCallCounter == 3 { // Simulate returning 7 bytes for the coefficients (register bme280RegCalibDigH2LSB) return 7, nil } if readCallCounter == 4 { // Simulate returning 1 byte for the cmr (register bmp280RegControl) return 1, nil } return 0, nil } require.NoError(t, bme280.Start()) } ================================================ FILE: drivers/i2c/bmp180_driver.go ================================================ package i2c import ( "bytes" "encoding/binary" "log" "time" ) const bmp180Debug = false // the default address is applicable for SDO to VDD, for SDO to GND it will be 0x76 const bmp180DefaultAddress = 0x77 const ( bmp180RegisterAC1MSB = 0xAA // 11 x 16 bit calibration data (AC1..AC6, B1, B2, MB, MC, MD) bmp180RegisterCtl = 0xF4 // control the value to read bmp180RegisterDataMSB = 0xF6 // 16 bit data (temperature or pressure) bmp180CtlTemp = 0x2E bmp180CtlPressure = 0x34 ) const ( // BMP180UltraLowPower is the lowest oversampling mode of the pressure measurement. BMP180UltraLowPower BMP180OversamplingMode = iota // BMP180Standard is the standard oversampling mode of the pressure measurement. BMP180Standard // BMP180HighResolution is a high oversampling mode of the pressure measurement. BMP180HighResolution // BMP180UltraHighResolution is the highest oversampling mode of the pressure measurement. BMP180UltraHighResolution ) // BMP180OversamplingMode is the oversampling ratio of the pressure measurement. type BMP180OversamplingMode uint type bmp180CalibrationCoefficients struct { ac1 int16 ac2 int16 ac3 int16 ac4 uint16 ac5 uint16 ac6 uint16 b1 int16 b2 int16 mb int16 mc int16 md int16 } // BMP180Driver is the gobot driver for the Bosch pressure and temperature sensor BMP180. // Device datasheet: https://cdn-shop.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf type BMP180Driver struct { *Driver oversampling BMP180OversamplingMode calCoeffs *bmp180CalibrationCoefficients } // NewBMP180Driver creates a new driver with the i2c interface for the BMP180 device. // Params: // // conn Connector - the Adaptor to use with this Driver // // Optional params: // // i2c.WithBus(int): bus to use with this driver // i2c.WithAddress(int): address to use with this driver func NewBMP180Driver(c Connector, options ...func(Config)) *BMP180Driver { d := &BMP180Driver{ Driver: NewDriver(c, "BMP180", bmp180DefaultAddress), oversampling: BMP180UltraLowPower, calCoeffs: &bmp180CalibrationCoefficients{}, } d.afterStart = d.initialization for _, option := range options { option(d) } // TODO: expose commands to API return d } // WithBMP180OversamplingMode option sets oversampling mode. // Valid settings are of type "BMP180OversamplingMode" func WithBMP180OversamplingMode(val BMP180OversamplingMode) func(Config) { return func(c Config) { if d, ok := c.(*BMP180Driver); ok { d.oversampling = val } else if bmp180Debug { log.Printf("Trying to set oversampling mode for non-BMP180Driver %v", c) } } } // Temperature returns the current temperature, in celsius degrees. func (d *BMP180Driver) Temperature() (float32, error) { d.mutex.Lock() defer d.mutex.Unlock() rawTemp, err := d.rawTemp() if err != nil { return 0, err } return d.calculateTemp(rawTemp), nil } // Pressure returns the current pressure, in pascals. func (d *BMP180Driver) Pressure() (float32, error) { d.mutex.Lock() defer d.mutex.Unlock() rawTemp, err := d.rawTemp() if err != nil { return 0, err } rawPressure, err := d.rawPressure(d.oversampling) if err != nil { return 0, err } return d.calculatePressure(rawTemp, rawPressure, d.oversampling), nil } func (d *BMP180Driver) initialization() error { // read the 11 calibration coefficients. coefficients := make([]byte, 22) if err := d.readBlockData(bmp180RegisterAC1MSB, coefficients); err != nil { return err } buf := bytes.NewBuffer(coefficients) if err := binary.Read(buf, binary.BigEndian, &d.calCoeffs.ac1); err != nil { return err } if err := binary.Read(buf, binary.BigEndian, &d.calCoeffs.ac2); err != nil { return err } if err := binary.Read(buf, binary.BigEndian, &d.calCoeffs.ac3); err != nil { return err } if err := binary.Read(buf, binary.BigEndian, &d.calCoeffs.ac4); err != nil { return err } if err := binary.Read(buf, binary.BigEndian, &d.calCoeffs.ac5); err != nil { return err } if err := binary.Read(buf, binary.BigEndian, &d.calCoeffs.ac6); err != nil { return err } if err := binary.Read(buf, binary.BigEndian, &d.calCoeffs.b1); err != nil { return err } if err := binary.Read(buf, binary.BigEndian, &d.calCoeffs.b2); err != nil { return err } if err := binary.Read(buf, binary.BigEndian, &d.calCoeffs.mb); err != nil { return err } if err := binary.Read(buf, binary.BigEndian, &d.calCoeffs.mc); err != nil { return err } return binary.Read(buf, binary.BigEndian, &d.calCoeffs.md) } func (d *BMP180Driver) rawTemp() (int16, error) { if _, err := d.write([]byte{bmp180RegisterCtl, bmp180CtlTemp}); err != nil { return 0, err } time.Sleep(5 * time.Millisecond) ret := make([]byte, 2) err := d.readBlockData(bmp180RegisterDataMSB, ret) if err != nil { return 0, err } buf := bytes.NewBuffer(ret) var rawTemp int16 if err := binary.Read(buf, binary.BigEndian, &rawTemp); err != nil { return 0, err } return rawTemp, nil } func (d *BMP180Driver) calculateTemp(rawTemp int16) float32 { b5 := d.calculateB5(rawTemp) t := (b5 + 8) >> 4 return float32(t) / 10 } func (d *BMP180Driver) calculateB5(rawTemp int16) int32 { x1 := (int32(rawTemp) - int32(d.calCoeffs.ac6)) * int32(d.calCoeffs.ac5) >> 15 x2 := int32(d.calCoeffs.mc) << 11 / (x1 + int32(d.calCoeffs.md)) return x1 + x2 } func (d *BMP180Driver) rawPressure(oversampling BMP180OversamplingMode) (int32, error) { if _, err := d.write([]byte{bmp180RegisterCtl, bmp180CtlPressure + byte(oversampling<<6)}); err != nil { return 0, err } time.Sleep(bmp180PauseForReading(oversampling)) ret := make([]byte, 3) if err := d.readBlockData(bmp180RegisterDataMSB, ret); err != nil { return 0, err } rawPressure := (int32(ret[0])<<16 + int32(ret[1])<<8 + int32(ret[2])) >> (8 - uint(oversampling)) return rawPressure, nil } func (d *BMP180Driver) calculatePressure( rawTemp int16, rawPressure int32, oversampling BMP180OversamplingMode, ) float32 { b5 := d.calculateB5(rawTemp) b6 := b5 - 4000 x1 := (int32(d.calCoeffs.b2) * (b6 * b6 >> 12)) >> 11 x2 := (int32(d.calCoeffs.ac2) * b6) >> 11 x3 := x1 + x2 b3 := (((int32(d.calCoeffs.ac1)*4 + x3) << uint(oversampling)) + 2) >> 2 x1 = (int32(d.calCoeffs.ac3) * b6) >> 13 x2 = (int32(d.calCoeffs.b1) * ((b6 * b6) >> 12)) >> 16 x3 = ((x1 + x2) + 2) >> 2 b4 := (uint32(d.calCoeffs.ac4) * uint32(x3+32768)) >> 15 //nolint:gosec // TODO: fix later b7 := (uint32(rawPressure-b3) * (50000 >> uint(oversampling))) //nolint:gosec // TODO: fix later var p int32 if b7 < 0x80000000 { p = int32((b7 << 1) / b4) //nolint:gosec // TODO: fix later } else { p = int32((b7 / b4) << 1) //nolint:gosec // TODO: fix later } x1 = (p >> 8) * (p >> 8) x1 = (x1 * 3038) >> 16 x2 = (-7357 * p) >> 16 return float32(p + ((x1 + x2 + 3791) >> 4)) } func bmp180PauseForReading(oversampling BMP180OversamplingMode) time.Duration { var d time.Duration switch oversampling { case BMP180UltraLowPower: d = 5 * time.Millisecond case BMP180Standard: d = 8 * time.Millisecond case BMP180HighResolution: d = 14 * time.Millisecond case BMP180UltraHighResolution: d = 26 * time.Millisecond } return d } ================================================ FILE: drivers/i2c/bmp180_driver_test.go ================================================ package i2c import ( "bytes" "encoding/binary" "errors" "strings" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) // this ensures that the implementation is based on i2c.Driver, which implements the gobot.Driver // and tests all implementations, so no further tests needed here for gobot.Driver interface var _ gobot.Driver = (*BMP180Driver)(nil) func initTestBMP180WithStubbedAdaptor() (*BMP180Driver, *i2cTestAdaptor) { adaptor := newI2cTestAdaptor() return NewBMP180Driver(adaptor), adaptor } func TestNewBMP180Driver(t *testing.T) { // Does it return a pointer to an instance of BMP180Driver? var di interface{} = NewBMP180Driver(newI2cTestAdaptor()) d, ok := di.(*BMP180Driver) if !ok { require.Fail(t, "NewBMP180Driver() should have returned a *BMP180Driver") } assert.NotNil(t, d.Driver) assert.True(t, strings.HasPrefix(d.Name(), "BMP180")) assert.Equal(t, 0x77, d.defaultAddress) assert.Equal(t, BMP180OversamplingMode(0x00), d.oversampling) assert.NotNil(t, d.calCoeffs) } func TestBMP180Halt(t *testing.T) { // arrange d := NewBMP180Driver(newI2cTestAdaptor()) // act, assert require.NoError(t, d.Halt()) // must be idempotent require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestBMP180Options(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithBus() option and // least one of this driver. Further tests for options can also be done by call of "WithOption(val)(d)". d := NewBMP180Driver(newI2cTestAdaptor(), WithBus(2), WithBMP180OversamplingMode(0x01)) assert.Equal(t, 2, d.GetBusOrDefault(1)) assert.Equal(t, BMP180OversamplingMode(0x01), d.oversampling) } func TestBMP180Measurements(t *testing.T) { bmp180, adaptor := initTestBMP180WithStubbedAdaptor() adaptor.i2cReadImpl = func(b []byte) (int, error) { buf := new(bytes.Buffer) // Values from the datasheet example. switch { case adaptor.written[len(adaptor.written)-1] == bmp180RegisterAC1MSB: _ = binary.Write(buf, binary.BigEndian, int16(408)) _ = binary.Write(buf, binary.BigEndian, int16(-72)) _ = binary.Write(buf, binary.BigEndian, int16(-14383)) _ = binary.Write(buf, binary.BigEndian, uint16(32741)) _ = binary.Write(buf, binary.BigEndian, uint16(32757)) _ = binary.Write(buf, binary.BigEndian, uint16(23153)) _ = binary.Write(buf, binary.BigEndian, int16(6190)) _ = binary.Write(buf, binary.BigEndian, int16(4)) _ = binary.Write(buf, binary.BigEndian, int16(-32768)) _ = binary.Write(buf, binary.BigEndian, int16(-8711)) _ = binary.Write(buf, binary.BigEndian, int16(2868)) case adaptor.written[len(adaptor.written)-2] == bmp180CtlTemp && adaptor.written[len(adaptor.written)-1] == bmp180RegisterDataMSB: _ = binary.Write(buf, binary.BigEndian, int16(27898)) case adaptor.written[len(adaptor.written)-2] == bmp180CtlPressure && adaptor.written[len(adaptor.written)-1] == bmp180RegisterDataMSB: _ = binary.Write(buf, binary.BigEndian, int16(23843)) // XLSB, not used in this test. buf.WriteByte(0) } copy(b, buf.Bytes()) return buf.Len(), nil } _ = bmp180.Start() temp, err := bmp180.Temperature() require.NoError(t, err) assert.InDelta(t, float32(15.0), temp, 0.0) pressure, err := bmp180.Pressure() require.NoError(t, err) assert.InDelta(t, float32(69964), pressure, 0.0) } func TestBMP180TemperatureError(t *testing.T) { bmp180, adaptor := initTestBMP180WithStubbedAdaptor() adaptor.i2cReadImpl = func(b []byte) (int, error) { buf := new(bytes.Buffer) // Values from the datasheet example. switch { case adaptor.written[len(adaptor.written)-1] == bmp180RegisterAC1MSB: _ = binary.Write(buf, binary.BigEndian, int16(408)) _ = binary.Write(buf, binary.BigEndian, int16(-72)) _ = binary.Write(buf, binary.BigEndian, int16(-14383)) _ = binary.Write(buf, binary.BigEndian, uint16(32741)) _ = binary.Write(buf, binary.BigEndian, uint16(32757)) _ = binary.Write(buf, binary.BigEndian, uint16(23153)) _ = binary.Write(buf, binary.BigEndian, int16(6190)) _ = binary.Write(buf, binary.BigEndian, int16(4)) _ = binary.Write(buf, binary.BigEndian, int16(-32768)) _ = binary.Write(buf, binary.BigEndian, int16(-8711)) _ = binary.Write(buf, binary.BigEndian, int16(2868)) case adaptor.written[len(adaptor.written)-2] == bmp180CtlTemp && adaptor.written[len(adaptor.written)-1] == bmp180RegisterDataMSB: return 0, errors.New("temp error") case adaptor.written[len(adaptor.written)-2] == bmp180CtlPressure && adaptor.written[len(adaptor.written)-1] == bmp180RegisterDataMSB: _ = binary.Write(buf, binary.BigEndian, int16(23843)) // XLSB, not used in this test. buf.WriteByte(0) } copy(b, buf.Bytes()) return buf.Len(), nil } _ = bmp180.Start() _, err := bmp180.Temperature() require.ErrorContains(t, err, "temp error") } func TestBMP180PressureError(t *testing.T) { bmp180, adaptor := initTestBMP180WithStubbedAdaptor() adaptor.i2cReadImpl = func(b []byte) (int, error) { buf := new(bytes.Buffer) // Values from the datasheet example. switch { case adaptor.written[len(adaptor.written)-1] == bmp180RegisterAC1MSB: _ = binary.Write(buf, binary.BigEndian, int16(408)) _ = binary.Write(buf, binary.BigEndian, int16(-72)) _ = binary.Write(buf, binary.BigEndian, int16(-14383)) _ = binary.Write(buf, binary.BigEndian, uint16(32741)) _ = binary.Write(buf, binary.BigEndian, uint16(32757)) _ = binary.Write(buf, binary.BigEndian, uint16(23153)) _ = binary.Write(buf, binary.BigEndian, int16(6190)) _ = binary.Write(buf, binary.BigEndian, int16(4)) _ = binary.Write(buf, binary.BigEndian, int16(-32768)) _ = binary.Write(buf, binary.BigEndian, int16(-8711)) _ = binary.Write(buf, binary.BigEndian, int16(2868)) case adaptor.written[len(adaptor.written)-2] == bmp180CtlTemp && adaptor.written[len(adaptor.written)-1] == bmp180RegisterDataMSB: _ = binary.Write(buf, binary.BigEndian, int16(27898)) case adaptor.written[len(adaptor.written)-2] == bmp180CtlPressure && adaptor.written[len(adaptor.written)-1] == bmp180RegisterDataMSB: return 0, errors.New("press error") } copy(b, buf.Bytes()) return buf.Len(), nil } _ = bmp180.Start() _, err := bmp180.Pressure() require.ErrorContains(t, err, "press error") } func TestBMP180PressureWriteError(t *testing.T) { bmp180, adaptor := initTestBMP180WithStubbedAdaptor() _ = bmp180.Start() adaptor.i2cWriteImpl = func([]byte) (int, error) { return 0, errors.New("write error") } _, err := bmp180.Pressure() require.ErrorContains(t, err, "write error") } func TestBMP180_initialization(t *testing.T) { // sequence to read in initialization(): // * read 22 bytes (11 x 16 bit calibration data), starting from AC1 register (0xAA) // * fill calibration struct with data (MSByte read first) // arrange d, a := initTestBMP180WithStubbedAdaptor() a.written = []byte{} // reset writes of former test // Values from the datasheet example. ac1 := []uint8{0x01, 0x98} ac2 := []uint8{0xFF, 0xB8} ac3 := []uint8{0xC7, 0xD1} ac4 := []uint8{0x7F, 0xE5} ac5 := []uint8{0x7F, 0xF5} ac6 := []uint8{0x5A, 0x71} b1 := []uint8{0x18, 0x2E} b2 := []uint8{0x00, 0x04} mb := []uint8{0x80, 0x00} mc := []uint8{0xDD, 0xF9} md := []uint8{0x0B, 0x34} returnRead := append(append(append(append(append(ac1, ac2...), ac3...), ac4...), ac5...), ac6...) returnRead = append(append(append(append(append(returnRead, b1...), b2...), mb...), mc...), md...) numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ copy(b, returnRead) return len(b), nil } // act, assert - initialization() must be called on Start() err := d.Start() // assert require.NoError(t, err) assert.Equal(t, 1, numCallsRead) assert.Len(t, a.written, 1) assert.Equal(t, uint8(0xAA), a.written[0]) assert.Equal(t, int16(408), d.calCoeffs.ac1) assert.Equal(t, int16(-72), d.calCoeffs.ac2) assert.Equal(t, int16(-14383), d.calCoeffs.ac3) assert.Equal(t, uint16(32741), d.calCoeffs.ac4) assert.Equal(t, uint16(32757), d.calCoeffs.ac5) assert.Equal(t, uint16(23153), d.calCoeffs.ac6) assert.Equal(t, int16(6190), d.calCoeffs.b1) assert.Equal(t, int16(4), d.calCoeffs.b2) assert.Equal(t, int16(-32768), d.calCoeffs.mb) assert.Equal(t, int16(-8711), d.calCoeffs.mc) assert.Equal(t, int16(2868), d.calCoeffs.md) } func TestBMP180_bmp180PauseForReading(t *testing.T) { assert.Equal(t, 5*time.Millisecond, bmp180PauseForReading(BMP180UltraLowPower)) assert.Equal(t, 8*time.Millisecond, bmp180PauseForReading(BMP180Standard)) assert.Equal(t, 14*time.Millisecond, bmp180PauseForReading(BMP180HighResolution)) assert.Equal(t, 26*time.Millisecond, bmp180PauseForReading(BMP180UltraHighResolution)) } ================================================ FILE: drivers/i2c/bmp280_driver.go ================================================ package i2c import ( "bytes" "encoding/binary" "log" "math" ) const bmp280Debug = true // the default address is applicable for SDO to VDD, for SDO to GND it will be 0x76 // this is also true for bme280 (which using this address as well) const bmp280DefaultAddress = 0x77 type ( BMP280PressureOversampling uint8 BMP280TemperatureOversampling uint8 BMP280IIRFilter uint8 ) const ( bmp280RegCalib00 = 0x88 // 12 x 16 bit calibration data (T1..T3, P1..P9) bmp280RegCtrl = 0xF4 // data acquisition options (oversampling of temperature and pressure, power mode) bmp280RegConf = 0xF5 // rate, IIR-filter and interface options (SPI) bmp280RegPressureData = 0xF7 bmp280RegTempData = 0xFA // bits 0, 1 of control register bmp280CtrlPwrSleepMode = 0x00 bmp280CtrlPwrForcedMode = 0x01 bmp280CtrlPwrForcedMode2 = 0x02 // same function as 0x01 bmp280CtrlPwrNormalMode = 0x03 // bits 2, 3, 4 of control register (will be shifted on write) BMP280CtrlPressNoMeasurement BMP280PressureOversampling = 0x00 // no measurement (value will be 0x08 0x00 0x00) BMP280CtrlPressOversampling1 BMP280PressureOversampling = 0x01 // resolution 16 bit BMP280CtrlPressOversampling2 BMP280PressureOversampling = 0x02 // resolution 17 bit BMP280CtrlPressOversampling4 BMP280PressureOversampling = 0x03 // resolution 18 bit BMP280CtrlPressOversampling8 BMP280PressureOversampling = 0x04 // resolution 19 bit BMP280CtrlPressOversampling16 BMP280PressureOversampling = 0x05 // resolution 20 bit (same as 0x06, 0x07) // bits 5, 6, 7 of control register (will be shifted on write) BMP280CtrlTempNoMeasurement BMP280TemperatureOversampling = 0x00 // no measurement (value will be 0x08 0x00 0x00) BMP280CtrlTempOversampling1 BMP280TemperatureOversampling = 0x01 // resolution 16 bit BMP280CtrlTempOversampling2 BMP280TemperatureOversampling = 0x02 // resolution 17 bit BMP280CtrlTempOversampling4 BMP280TemperatureOversampling = 0x03 // resolution 18 bit BMP280CtrlTempOversampling8 BMP280TemperatureOversampling = 0x04 // resolution 19 bit BMP280CtrlTempOversampling16 BMP280TemperatureOversampling = 0x05 // resolution 20 bit // bit 0 of config register bmp280ConfSPIBit = 0x01 // if set, SPI is used // bits 2, 3, 4 of config register (bit 1 is unused, will be shifted on write) bmp280ConfStandBy0005 = 0x00 // 0.5 ms bmp280ConfStandBy0625 = 0x01 // 62.5 ms bmp280ConfStandBy0125 = 0x02 // 125 ms bmp280ConfStandBy0250 = 0x03 // 250 ms bmp280ConfStandBy0500 = 0x04 // 500 ms bmp280ConfStandBy1000 = 0x05 // 1000 ms bmp280ConfStandBy2000 = 0x06 // 2000 ms bmp280ConfStandBy4000 = 0x07 // 4000 ms // bits 5, 6, 7 of config register BMP280ConfFilterOff BMP280IIRFilter = 0x00 BMP280ConfFilter2 BMP280IIRFilter = 0x01 BMP280ConfFilter4 BMP280IIRFilter = 0x02 BMP280ConfFilter8 BMP280IIRFilter = 0x03 BMP280ConfFilter16 BMP280IIRFilter = 0x04 bmp280SeaLevelPressure = 1013.25 ) type bmp280CalibrationCoefficients struct { t1 uint16 t2 int16 t3 int16 p1 uint16 p2 int16 p3 int16 p4 int16 p5 int16 p6 int16 p7 int16 p8 int16 p9 int16 } // BMP280Driver is a driver for the BMP280 temperature/pressure sensor type BMP280Driver struct { *Driver calCoeffs *bmp280CalibrationCoefficients ctrlPwrMode uint8 ctrlPressOversamp BMP280PressureOversampling ctrlTempOversamp BMP280TemperatureOversampling confFilter BMP280IIRFilter } // NewBMP280Driver creates a new driver with specified i2c interface. // Params: // // c Connector - the Adaptor to use with this Driver // // Optional params: // // i2c.WithBus(int): bus to use with this driver // i2c.WithAddress(int): address to use with this driver func NewBMP280Driver(c Connector, options ...func(Config)) *BMP280Driver { d := &BMP280Driver{ Driver: NewDriver(c, "BMP280", bmp280DefaultAddress), calCoeffs: &bmp280CalibrationCoefficients{}, ctrlPwrMode: bmp280CtrlPwrNormalMode, ctrlPressOversamp: BMP280CtrlPressOversampling16, ctrlTempOversamp: BMP280CtrlTempOversampling1, confFilter: BMP280ConfFilterOff, } d.afterStart = d.initialization for _, option := range options { option(d) } // TODO: expose commands to API return d } // WithBMP280PressureOversampling option sets the oversampling for pressure. // Valid settings are of type "BMP280PressureOversampling" func WithBMP280PressureOversampling(val BMP280PressureOversampling) func(Config) { return func(c Config) { if d, ok := c.(*BMP280Driver); ok { d.ctrlPressOversamp = val } else if bmp280Debug { log.Printf("Trying to set pressure oversampling for non-BMP280Driver %v", c) } } } // WithBMP280TemperatureOversampling option sets oversampling for temperature. // Valid settings are of type "BMP280TemperatureOversampling" func WithBMP280TemperatureOversampling(val BMP280TemperatureOversampling) func(Config) { return func(c Config) { if d, ok := c.(*BMP280Driver); ok { d.ctrlTempOversamp = val } else if bmp280Debug { log.Printf("Trying to set temperature oversampling for non-BMP280Driver %v", c) } } } // WithBMP280IIRFilter option sets the count of IIR filter coefficients. // Valid settings are of type "BMP280IIRFilter" func WithBMP280IIRFilter(val BMP280IIRFilter) func(Config) { return func(c Config) { if d, ok := c.(*BMP280Driver); ok { d.confFilter = val } else if bmp280Debug { log.Printf("Trying to set IIR filter for non-BMP280Driver %v", c) } } } // Temperature returns the current temperature, in celsius degrees. func (d *BMP280Driver) Temperature() (float32, error) { d.mutex.Lock() defer d.mutex.Unlock() rawT, err := d.rawTemp() if err != nil { return 0.0, err } temp, _ := d.calculateTemp(rawT) return temp, nil } // Pressure returns the current barometric pressure, in Pa func (d *BMP280Driver) Pressure() (float32, error) { d.mutex.Lock() defer d.mutex.Unlock() rawT, err := d.rawTemp() if err != nil { return 0.0, err } rawP, err := d.rawPressure() if err != nil { return 0.0, err } _, tFine := d.calculateTemp(rawT) return d.calculatePress(rawP, tFine), nil } // Altitude returns the current altitude in meters based on the // current barometric pressure and estimated pressure at sea level. // Calculation is based on code from Adafruit BME280 library // // https://github.com/adafruit/Adafruit_BME280_Library func (d *BMP280Driver) Altitude() (float32, error) { atmP, err := d.Pressure() if err != nil { return 0, err } atmP /= 100.0 alt := float32(44330.0 * (1.0 - math.Pow(float64(atmP/bmp280SeaLevelPressure), 0.1903))) return alt, nil } // initialization reads the calibration coefficients. func (d *BMP280Driver) initialization() error { coefficients := make([]byte, 24) if err := d.readBlockData(bmp280RegCalib00, coefficients); err != nil { return err } buf := bytes.NewBuffer(coefficients) if err := binary.Read(buf, binary.LittleEndian, &d.calCoeffs.t1); err != nil { return err } if err := binary.Read(buf, binary.LittleEndian, &d.calCoeffs.t2); err != nil { return err } if err := binary.Read(buf, binary.LittleEndian, &d.calCoeffs.t3); err != nil { return err } if err := binary.Read(buf, binary.LittleEndian, &d.calCoeffs.p1); err != nil { return err } if err := binary.Read(buf, binary.LittleEndian, &d.calCoeffs.p2); err != nil { return err } if err := binary.Read(buf, binary.LittleEndian, &d.calCoeffs.p3); err != nil { return err } if err := binary.Read(buf, binary.LittleEndian, &d.calCoeffs.p4); err != nil { return err } if err := binary.Read(buf, binary.LittleEndian, &d.calCoeffs.p5); err != nil { return err } if err := binary.Read(buf, binary.LittleEndian, &d.calCoeffs.p6); err != nil { return err } if err := binary.Read(buf, binary.LittleEndian, &d.calCoeffs.p7); err != nil { return err } if err := binary.Read(buf, binary.LittleEndian, &d.calCoeffs.p8); err != nil { return err } if err := binary.Read(buf, binary.LittleEndian, &d.calCoeffs.p9); err != nil { return err } ctrlReg := d.ctrlPwrMode | uint8(d.ctrlPressOversamp)<<2 | uint8(d.ctrlTempOversamp)<<5 if err := d.writeByteData(bmp280RegCtrl, ctrlReg); err != nil { return err } confReg := uint8(bmp280ConfStandBy0005)<<2 | uint8(d.confFilter)<<5 return d.writeByteData(bmp280RegConf, confReg & ^uint8(bmp280ConfSPIBit)) } func (d *BMP280Driver) rawTemp() (int32, error) { var tp0, tp1, tp2 byte data := make([]byte, 3) if err := d.readBlockData(bmp280RegTempData, data); err != nil { return 0, err } buf := bytes.NewBuffer(data) if err := binary.Read(buf, binary.LittleEndian, &tp0); err != nil { return 0, err } if err := binary.Read(buf, binary.LittleEndian, &tp1); err != nil { return 0, err } if err := binary.Read(buf, binary.LittleEndian, &tp2); err != nil { return 0, err } return ((int32(tp2) >> 4) | (int32(tp1) << 4) | (int32(tp0) << 12)), nil } func (d *BMP280Driver) rawPressure() (int32, error) { var tp0, tp1, tp2 byte data := make([]byte, 3) if err := d.readBlockData(bmp280RegPressureData, data); err != nil { return 0, err } buf := bytes.NewBuffer(data) if err := binary.Read(buf, binary.LittleEndian, &tp0); err != nil { return 0, err } if err := binary.Read(buf, binary.LittleEndian, &tp1); err != nil { return 0, err } if err := binary.Read(buf, binary.LittleEndian, &tp2); err != nil { return 0, err } return ((int32(tp2) >> 4) | (int32(tp1) << 4) | (int32(tp0) << 12)), nil } func (d *BMP280Driver) calculateTemp(rawTemp int32) (float32, int32) { tcvar1 := ((float32(rawTemp) / 16384.0) - (float32(d.calCoeffs.t1) / 1024.0)) * float32(d.calCoeffs.t2) tcvar2 := (((float32(rawTemp) / 131072.0) - (float32(d.calCoeffs.t1) / 8192.0)) * ((float32(rawTemp) / 131072.0) - float32(d.calCoeffs.t1)/8192.0)) * float32(d.calCoeffs.t3) temperatureComp := (tcvar1 + tcvar2) / 5120.0 tFine := int32(tcvar1 + tcvar2) return temperatureComp, tFine } func (d *BMP280Driver) calculatePress(rawPress int32, tFine int32) float32 { var var1, var2, p int64 var1 = int64(tFine) - 128000 var2 = var1 * var1 * int64(d.calCoeffs.p6) var2 = var2 + ((var1 * int64(d.calCoeffs.p5)) << 17) var2 = var2 + (int64(d.calCoeffs.p4) << 35) var1 = (var1 * var1 * int64(d.calCoeffs.p3) >> 8) + ((var1 * int64(d.calCoeffs.p2)) << 12) var1 = ((int64(1) << 47) + var1) * (int64(d.calCoeffs.p1)) >> 33 if var1 == 0 { return 0 // avoid exception caused by division by zero } p = 1048576 - int64(rawPress) p = (((p << 31) - var2) * 3125) / var1 var1 = (int64(d.calCoeffs.p9) * (p >> 13) * (p >> 13)) >> 25 var2 = (int64(d.calCoeffs.p8) * p) >> 19 p = ((p + var1 + var2) >> 8) + (int64(d.calCoeffs.p7) << 4) return float32(p) / 256 } ================================================ FILE: drivers/i2c/bmp280_driver_test.go ================================================ package i2c import ( "bytes" "errors" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) // this ensures that the implementation is based on i2c.Driver, which implements the gobot.Driver // and tests all implementations, so no further tests needed here for gobot.Driver interface var _ gobot.Driver = (*BMP280Driver)(nil) func initTestBMP280WithStubbedAdaptor() (*BMP280Driver, *i2cTestAdaptor) { adaptor := newI2cTestAdaptor() return NewBMP280Driver(adaptor), adaptor } func TestNewBMP280Driver(t *testing.T) { var di interface{} = NewBMP280Driver(newI2cTestAdaptor()) d, ok := di.(*BMP280Driver) if !ok { require.Fail(t, "NewBMP280Driver() should have returned a *BMP280Driver") } assert.NotNil(t, d.Driver) assert.True(t, strings.HasPrefix(d.Name(), "BMP280")) assert.Equal(t, 0x77, d.defaultAddress) assert.Equal(t, uint8(0x03), d.ctrlPwrMode) assert.Equal(t, BMP280PressureOversampling(0x05), d.ctrlPressOversamp) assert.Equal(t, BMP280TemperatureOversampling(0x01), d.ctrlTempOversamp) assert.Equal(t, BMP280IIRFilter(0x00), d.confFilter) assert.NotNil(t, d.calCoeffs) } func TestBMP280Halt(t *testing.T) { // arrange d := NewBMP280Driver(newI2cTestAdaptor()) // act, assert require.NoError(t, d.Halt()) // must be idempotent require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestBMP280Options(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithBus() option and // least one of this driver. Further tests for options can also be done by call of "WithOption(val)(d)". d := NewBMP280Driver(newI2cTestAdaptor(), WithBus(2), WithBMP280PressureOversampling(0x04)) assert.Equal(t, 2, d.GetBusOrDefault(1)) assert.Equal(t, BMP280PressureOversampling(0x04), d.ctrlPressOversamp) } func TestWithBMP280TemperatureOversampling(t *testing.T) { // arrange d, a := initTestBMP280WithStubbedAdaptor() a.written = []byte{} // reset writes of former test const ( setVal = BMP280TemperatureOversampling(0x04) // 8 x ) // act WithBMP280TemperatureOversampling(setVal)(d) // assert assert.Equal(t, setVal, d.ctrlTempOversamp) assert.Empty(t, a.written) } func TestWithBMP280IIRFilter(t *testing.T) { // arrange d, a := initTestBMP280WithStubbedAdaptor() a.written = []byte{} // reset writes of former test const ( setVal = BMP280IIRFilter(0x02) // 4 x ) // act WithBMP280IIRFilter(setVal)(d) // assert assert.Equal(t, setVal, d.confFilter) assert.Empty(t, a.written) } func TestBMP280Measurements(t *testing.T) { d, adaptor := initTestBMP280WithStubbedAdaptor() adaptor.i2cReadImpl = func(b []byte) (int, error) { buf := new(bytes.Buffer) // Values produced by dumping data from actual sensor switch { case adaptor.written[len(adaptor.written)-1] == bmp280RegCalib00: buf.Write([]byte{ 126, 109, 214, 102, 50, 0, 54, 149, 220, 213, 208, 11, 64, 30, 166, 255, 249, 255, 172, 38, 10, 216, 189, 16, }) case adaptor.written[len(adaptor.written)-1] == bmp280RegTempData: buf.Write([]byte{128, 243, 0}) case adaptor.written[len(adaptor.written)-1] == bmp280RegPressureData: buf.Write([]byte{77, 23, 48}) } copy(b, buf.Bytes()) return buf.Len(), nil } _ = d.Start() temp, err := d.Temperature() require.NoError(t, err) assert.InDelta(t, float32(25.014637), temp, 0.0) pressure, err := d.Pressure() require.NoError(t, err) assert.InDelta(t, float32(99545.414), pressure, 0.0) alt, err := d.Altitude() require.NoError(t, err) assert.InDelta(t, float32(149.22713), alt, 0.0) } func TestBMP280TemperatureWriteError(t *testing.T) { d, adaptor := initTestBMP280WithStubbedAdaptor() _ = d.Start() adaptor.i2cWriteImpl = func([]byte) (int, error) { return 0, errors.New("write error") } temp, err := d.Temperature() require.ErrorContains(t, err, "write error") assert.InDelta(t, float32(0.0), temp, 0.0) } func TestBMP280TemperatureReadError(t *testing.T) { d, adaptor := initTestBMP280WithStubbedAdaptor() _ = d.Start() adaptor.i2cReadImpl = func([]byte) (int, error) { return 0, errors.New("read error") } temp, err := d.Temperature() require.ErrorContains(t, err, "read error") assert.InDelta(t, float32(0.0), temp, 0.0) } func TestBMP280PressureWriteError(t *testing.T) { d, adaptor := initTestBMP280WithStubbedAdaptor() _ = d.Start() adaptor.i2cWriteImpl = func([]byte) (int, error) { return 0, errors.New("write error") } press, err := d.Pressure() require.ErrorContains(t, err, "write error") assert.InDelta(t, float32(0.0), press, 0.0) } func TestBMP280PressureReadError(t *testing.T) { d, adaptor := initTestBMP280WithStubbedAdaptor() _ = d.Start() adaptor.i2cReadImpl = func([]byte) (int, error) { return 0, errors.New("read error") } press, err := d.Pressure() require.ErrorContains(t, err, "read error") assert.InDelta(t, float32(0.0), press, 0.0) } func TestBMP280_initialization(t *testing.T) { // sequence to read and write in initialization(): // * read 24 bytes (12 x 16 bit calibration data), starting from TC1 register (0x88) // * fill calibration struct with data (LSByte read first) // * prepare the content of control register // * write the control register (0xF4) // * prepare the content of config register // * write the config register (0xF5) // arrange d, a := initTestBMP280WithStubbedAdaptor() a.written = []byte{} // reset writes of former test const ( wantCalibReg = uint8(0x88) wantCtrlReg = uint8(0xF4) wantCtrlRegVal = uint8(0x37) // normal power mode, 16 x pressure and 1 x temperature oversampling wantConfReg = uint8(0xF5) wantConfRegVal = uint8(0x00) // no SPI, no filter, smallest standby (unused, because normal power mode) ) // Values from the datasheet example. t1 := []uint8{0x70, 0x6B} t2 := []uint8{0x43, 0x67} t3 := []uint8{0x18, 0xFC} p1 := []uint8{0x7D, 0x8E} p2 := []uint8{0x43, 0xD6} p3 := []uint8{0xD0, 0x0B} p4 := []uint8{0x27, 0x0B} p5 := []uint8{0x8C, 0x00} p6 := []uint8{0xF9, 0xFF} p7 := []uint8{0x8C, 0x3C} p8 := []uint8{0xF8, 0xC6} p9 := []uint8{0x70, 0x17} returnRead := append(append(append(append(append(append(t1, t2...), t3...), p1...), p2...), p3...), p4...) returnRead = append(append(append(append(append(returnRead, p5...), p6...), p7...), p8...), p9...) numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ copy(b, returnRead) return len(b), nil } // act, assert - initialization() must be called on Start() err := d.Start() // assert require.NoError(t, err) assert.Equal(t, 1, numCallsRead) assert.Len(t, a.written, 5) assert.Equal(t, wantCalibReg, a.written[0]) assert.Equal(t, wantCtrlReg, a.written[1]) assert.Equal(t, wantCtrlRegVal, a.written[2]) assert.Equal(t, wantConfReg, a.written[3]) assert.Equal(t, wantConfRegVal, a.written[4]) assert.Equal(t, uint16(27504), d.calCoeffs.t1) assert.Equal(t, int16(26435), d.calCoeffs.t2) assert.Equal(t, int16(-1000), d.calCoeffs.t3) assert.Equal(t, uint16(36477), d.calCoeffs.p1) assert.Equal(t, int16(-10685), d.calCoeffs.p2) assert.Equal(t, int16(3024), d.calCoeffs.p3) assert.Equal(t, int16(2855), d.calCoeffs.p4) assert.Equal(t, int16(140), d.calCoeffs.p5) assert.Equal(t, int16(-7), d.calCoeffs.p6) assert.Equal(t, int16(15500), d.calCoeffs.p7) assert.Equal(t, int16(-14600), d.calCoeffs.p8) assert.Equal(t, int16(6000), d.calCoeffs.p9) } ================================================ FILE: drivers/i2c/bmp388_driver.go ================================================ package i2c import ( "bytes" "encoding/binary" "fmt" "log" "math" ) const bmp388Debug = false // the default address is applicable for SDO to VDD, for SDO to GND it will be 0x76 const bmp388DefaultAddress = 0x77 // BMP388Accuracy accuracy type type ( BMP388Accuracy uint8 BMP388IIRFilter uint8 ) const ( bmp388ChipID = 0x50 bmp388RegChipID = 0x00 bmp388RegStatus = 0x03 bmp388RegPressureData = 0x04 // XLSB, 0x05 LSByte, 0x06 MSByte bmp388RegTempData = 0x07 // XLSB, 0x08 LSByte, 0x09 MSByte bmp388RegPWRCTRL = 0x1B // enable/disable pressure and temperature measurement, mode bmp388RegOSR = 0x1C // Oversampling Rates bmp388RegODR = 0x1D // Output Data Rates bmp388RegConf = 0x1F // config filter for IIR coefficients bmp388RegCalib00 = 0x31 bmp388RegCMD = 0x7E // bits 0, 1 of control register bmp388PWRCTRLPressEnableBit = 0x01 bmp388PWRCTRLTempEnableBit = 0x02 // bits 4, 5 of control register (will be shifted on write) bmp388PWRCTRLSleep = 0x00 bmp388PWRCTRLForced = 0x01 // same as 0x02 bmp388PWRCTRLNormal = 0x03 // bits 1, 2 ,3 of config filter IIR filter coefficients (will be shifted on write) bmp388ConfFilterCoef0 BMP388IIRFilter = 0 // bypass-mode bmp388ConfFilterCoef1 BMP388IIRFilter = 1 bmp388ConfFilterCoef3 BMP388IIRFilter = 2 bmp388ConfFilterCoef7 BMP388IIRFilter = 3 bmp388ConfFilterCoef15 BMP388IIRFilter = 4 bmp388ConfFilterCoef31 BMP388IIRFilter = 5 bmp388ConfFilterCoef63 BMP388IIRFilter = 6 bmp388ConfFilterCoef127 BMP388IIRFilter = 7 // oversampling rate, a single value is used (could be different for pressure and temperature) BMP388AccuracyUltraLow BMP388Accuracy = 0 // x1 sample BMP388AccuracyLow BMP388Accuracy = 1 // x2 samples BMP388AccuracyStandard BMP388Accuracy = 2 // x4 samples BMP388AccuracyHigh BMP388Accuracy = 3 // x8 samples BMP388AccuracyUltraHigh BMP388Accuracy = 4 // x16 samples BMP388AccuracyHighest BMP388Accuracy = 5 // x32 samples bmp388CMDReserved = 0x00 // reserved, no command bmp388CMDExtModeEnMiddle = 0x34 bmp388CMDFifoFlush = 0xB0 // clears all data in the FIFO, does not change FIFO_CONFIG registers bmp388CMDSoftReset = 0xB6 // triggers a reset, all user configuration settings are overwritten with defaults bmp388SeaLevelPressure = 1013.25 ) type bmp388CalibrationCoefficients struct { t1 float32 t2 float32 t3 float32 p1 float32 p2 float32 p3 float32 p4 float32 p5 float32 p6 float32 p7 float32 p8 float32 p9 float32 p10 float32 p11 float32 } // BMP388Driver is a driver for the BMP388 temperature/pressure sensor type BMP388Driver struct { *Driver calCoeffs *bmp388CalibrationCoefficients ctrlPwrMode uint8 confFilter BMP388IIRFilter } // NewBMP388Driver creates a new driver with specified i2c interface. // Params: // // c Connector - the Adaptor to use with this Driver // // Optional params: // // i2c.WithBus(int): bus to use with this driver // i2c.WithAddress(int): address to use with this driver func NewBMP388Driver(c Connector, options ...func(Config)) *BMP388Driver { d := &BMP388Driver{ Driver: NewDriver(c, "BMP388", bmp388DefaultAddress), calCoeffs: &bmp388CalibrationCoefficients{}, ctrlPwrMode: bmp388PWRCTRLForced, confFilter: bmp388ConfFilterCoef0, } d.afterStart = d.initialization for _, option := range options { option(d) } // TODO: expose commands to API return d } // WithBMP388IIRFilter option sets count of IIR filter coefficients. // Valid settings are of type "BMP388IIRFilter" func WithBMP388IIRFilter(val BMP388IIRFilter) func(Config) { return func(c Config) { if d, ok := c.(*BMP388Driver); ok { d.confFilter = val } else if bmp388Debug { log.Printf("Trying to set IIR filter for non-BMP388Driver %v", c) } } } // Temperature returns the current temperature, in celsius degrees. func (d *BMP388Driver) Temperature(accuracy BMP388Accuracy) (float32, error) { d.mutex.Lock() defer d.mutex.Unlock() mode := d.ctrlPwrMode<<4 | bmp388PWRCTRLPressEnableBit | bmp388PWRCTRLTempEnableBit if err := d.writeByteData(bmp388RegPWRCTRL, mode); err != nil { return 0, err } // Set Accuracy for temperature if err := d.writeByteData(bmp388RegOSR, uint8(accuracy<<3)); err != nil { return 0, err } rawT, err := d.rawTemp() if err != nil { return 0.0, err } temp := d.calculateTemp(rawT) return temp, nil } // Pressure returns the current barometric pressure, in Pa func (d *BMP388Driver) Pressure(accuracy BMP388Accuracy) (float32, error) { d.mutex.Lock() defer d.mutex.Unlock() mode := d.ctrlPwrMode<<4 | bmp388PWRCTRLPressEnableBit | bmp388PWRCTRLTempEnableBit if err := d.writeByteData(bmp388RegPWRCTRL, mode); err != nil { return 0, err } // Set Standard Accuracy for pressure if err := d.writeByteData(bmp388RegOSR, uint8(accuracy)); err != nil { return 0, err } rawT, err := d.rawTemp() if err != nil { return 0.0, err } rawP, err := d.rawPressure() if err != nil { return 0.0, err } tLin := d.calculateTemp(rawT) return d.calculatePress(rawP, float64(tLin)), nil } // Altitude returns the current altitude in meters based on the // current barometric pressure and estimated pressure at sea level. // https://www.weather.gov/media/epz/wxcalc/pressureAltitude.pdf func (d *BMP388Driver) Altitude(accuracy BMP388Accuracy) (float32, error) { atmP, err := d.Pressure(accuracy) if err != nil { return 0, err } atmP /= 100.0 alt := float32(44307.0 * (1.0 - math.Pow(float64(atmP/bmp388SeaLevelPressure), 0.190284))) return alt, nil } // initialization reads the calibration coefficients. func (d *BMP388Driver) initialization() error { chipID, err := d.readByteData(bmp388RegChipID) if err != nil { return err } if bmp388ChipID != chipID { return fmt.Errorf("incorrect BMP388 chip ID '0%x' Expected 0x%x", chipID, bmp388ChipID) } var ( t1 uint16 t2 uint16 t3 int8 p1 int16 p2 int16 p3 int8 p4 int8 p5 uint16 p6 uint16 p7 int8 p8 int8 p9 int16 p10 int8 p11 int8 ) coefficients := make([]byte, 24) if err = d.readBlockData(bmp388RegCalib00, coefficients); err != nil { return err } buf := bytes.NewBuffer(coefficients) if err := binary.Read(buf, binary.LittleEndian, &t1); err != nil { return err } if err := binary.Read(buf, binary.LittleEndian, &t2); err != nil { return err } if err := binary.Read(buf, binary.LittleEndian, &t3); err != nil { return err } if err := binary.Read(buf, binary.LittleEndian, &p1); err != nil { return err } if err := binary.Read(buf, binary.LittleEndian, &p2); err != nil { return err } if err := binary.Read(buf, binary.LittleEndian, &p3); err != nil { return err } if err := binary.Read(buf, binary.LittleEndian, &p4); err != nil { return err } if err := binary.Read(buf, binary.LittleEndian, &p5); err != nil { return err } if err := binary.Read(buf, binary.LittleEndian, &p6); err != nil { return err } if err := binary.Read(buf, binary.LittleEndian, &p7); err != nil { return err } if err := binary.Read(buf, binary.LittleEndian, &p8); err != nil { return err } if err := binary.Read(buf, binary.LittleEndian, &p9); err != nil { return err } if err := binary.Read(buf, binary.LittleEndian, &p10); err != nil { return err } if err := binary.Read(buf, binary.LittleEndian, &p11); err != nil { return err } d.calCoeffs.t1 = float32(float64(t1) / math.Pow(2, -8)) d.calCoeffs.t2 = float32(float64(t2) / math.Pow(2, 30)) d.calCoeffs.t3 = float32(float64(t3) / math.Pow(2, 48)) d.calCoeffs.p1 = float32((float64(p1) - math.Pow(2, 14)) / math.Pow(2, 20)) d.calCoeffs.p2 = float32((float64(p2) - math.Pow(2, 14)) / math.Pow(2, 29)) d.calCoeffs.p3 = float32(float64(p3) / math.Pow(2, 32)) d.calCoeffs.p4 = float32(float64(p4) / math.Pow(2, 37)) d.calCoeffs.p5 = float32(float64(p5) / math.Pow(2, -3)) d.calCoeffs.p6 = float32(float64(p6) / math.Pow(2, 6)) d.calCoeffs.p7 = float32(float64(p7) / math.Pow(2, 8)) d.calCoeffs.p8 = float32(float64(p8) / math.Pow(2, 15)) d.calCoeffs.p9 = float32(float64(p9) / math.Pow(2, 48)) d.calCoeffs.p10 = float32(float64(p10) / math.Pow(2, 48)) d.calCoeffs.p11 = float32(float64(p11) / math.Pow(2, 65)) if err := d.writeByteData(bmp388RegCMD, bmp388CMDSoftReset); err != nil { return err } return d.writeByteData(bmp388RegConf, uint8(d.confFilter)<<1) } func (d *BMP388Driver) rawTemp() (int32, error) { var tp0, tp1, tp2 byte data := make([]byte, 3) if err := d.readBlockData(bmp388RegTempData, data); err != nil { return 0, err } buf := bytes.NewBuffer(data) // XLSB if err := binary.Read(buf, binary.LittleEndian, &tp0); err != nil { return 0, err } // LSB if err := binary.Read(buf, binary.LittleEndian, &tp1); err != nil { return 0, err } // MSB if err := binary.Read(buf, binary.LittleEndian, &tp2); err != nil { return 0, err } return ((int32(tp2) << 16) | (int32(tp1) << 8) | int32(tp0)), nil } func (d *BMP388Driver) rawPressure() (int32, error) { var tp0, tp1, tp2 byte data := make([]byte, 3) if err := d.readBlockData(bmp388RegPressureData, data); err != nil { return 0, err } buf := bytes.NewBuffer(data) // XLSB if err := binary.Read(buf, binary.LittleEndian, &tp0); err != nil { return 0, err } // LSB if err := binary.Read(buf, binary.LittleEndian, &tp1); err != nil { return 0, err } // MSB if err := binary.Read(buf, binary.LittleEndian, &tp2); err != nil { return 0, err } return ((int32(tp2) << 16) | (int32(tp1) << 8) | int32(tp0)), nil } func (d *BMP388Driver) calculateTemp(rawTemp int32) float32 { // datasheet, sec 9.2 Temperature compensation pd1 := float32(rawTemp) - d.calCoeffs.t1 pd2 := pd1 * d.calCoeffs.t2 temperatureComp := pd2 + (pd1*pd1)*d.calCoeffs.t3 return temperatureComp } func (d *BMP388Driver) calculatePress(rawPress int32, tLin float64) float32 { pd1 := float64(d.calCoeffs.p6) * tLin pd2 := float64(d.calCoeffs.p7) * tLin * tLin pd3 := float64(d.calCoeffs.p8) * tLin * tLin * tLin po1 := float64(d.calCoeffs.p5) + pd1 + pd2 + pd3 pd1 = float64(d.calCoeffs.p2) * tLin pd2 = float64(d.calCoeffs.p3) * tLin * tLin pd3 = float64(d.calCoeffs.p4) * tLin * tLin * tLin po2 := float64(rawPress) * (float64(d.calCoeffs.p1) + pd1 + pd2 + pd3) pd1 = math.Pow(float64(rawPress), 2) pd2 = float64(d.calCoeffs.p9) + float64(d.calCoeffs.p10)*tLin pd3 = pd1 * pd2 pd4 := pd3 + math.Pow(float64(rawPress), 3)*float64(d.calCoeffs.p11) pressure := po1 + po2 + pd4 return float32(pressure) } ================================================ FILE: drivers/i2c/bmp388_driver_test.go ================================================ package i2c import ( "bytes" "encoding/binary" "errors" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) // this ensures that the implementation is based on i2c.Driver, which implements the gobot.Driver // and tests all implementations, so no further tests needed here for gobot.Driver interface var _ gobot.Driver = (*BMP388Driver)(nil) func initTestBMP388WithStubbedAdaptor() (*BMP388Driver, *i2cTestAdaptor) { a := newI2cTestAdaptor() readCallCounter := 0 a.i2cReadImpl = func(b []byte) (int, error) { readCallCounter++ if readCallCounter == 1 { buf := new(bytes.Buffer) // Simulate returning of 0x50 for the // ReadByteData(bmp388RegChipID) call in initialisation() _ = binary.Write(buf, binary.LittleEndian, uint8(0x50)) copy(b, buf.Bytes()) return buf.Len(), nil } if readCallCounter == 2 { // Simulate returning 24 bytes for the coefficients (register bmp388RegCalib00) return 24, nil } return 0, nil } return NewBMP388Driver(a), a } func TestNewBMP388Driver(t *testing.T) { var di interface{} = NewBMP388Driver(newI2cTestAdaptor()) d, ok := di.(*BMP388Driver) if !ok { require.Fail(t, "NewBMP388Driver() should have returned a *BMP388Driver") } assert.NotNil(t, d.Driver) assert.True(t, strings.HasPrefix(d.Name(), "BMP388")) assert.Equal(t, 0x77, d.defaultAddress) assert.Equal(t, uint8(0x01), d.ctrlPwrMode) // forced mode assert.Equal(t, BMP388IIRFilter(0x00), d.confFilter) // filter off assert.NotNil(t, d.calCoeffs) } func TestBMP388Halt(t *testing.T) { // arrange d, _ := initTestBMP388WithStubbedAdaptor() // act, assert require.NoError(t, d.Halt()) // must be idempotent require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestBMP388Options(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithBus() option and // least one of this driver. Further tests for options can also be done by call of "WithOption(val)(d)". d := NewBMP388Driver(newI2cTestAdaptor(), WithBus(2), WithBMP388IIRFilter(BMP388IIRFilter(0x03))) assert.Equal(t, 2, d.GetBusOrDefault(1)) assert.Equal(t, BMP388IIRFilter(0x03), d.confFilter) } func TestBMP388Measurements(t *testing.T) { d, a := initTestBMP388WithStubbedAdaptor() a.i2cReadImpl = func(b []byte) (int, error) { buf := new(bytes.Buffer) lastWritten := a.written[len(a.written)-1] switch lastWritten { case bmp388RegChipID: // Simulate returning of 0x50 for the // ReadByteData(bmp388RegChipID) call in initialisation() _ = binary.Write(buf, binary.LittleEndian, uint8(0x50)) case bmp388RegCalib00: // Values produced by dumping data from actual sensor buf.Write([]byte{ 36, 107, 156, 73, 246, 104, 255, 189, 245, 35, 0, 151, 101, 184, 122, 243, 246, 211, 64, 14, 196, 0, 0, 0, }) case bmp388RegTempData: buf.Write([]byte{0, 28, 127}) case bmp388RegPressureData: buf.Write([]byte{0, 66, 113}) } copy(b, buf.Bytes()) return buf.Len(), nil } _ = d.Start() temp, err := d.Temperature(2) require.NoError(t, err) assert.InDelta(t, float32(22.906143), temp, 0.0) pressure, err := d.Pressure(2) require.NoError(t, err) assert.InDelta(t, float32(98874.85), pressure, 0.0) alt, err := d.Altitude(2) require.NoError(t, err) assert.InDelta(t, float32(205.89395), alt, 0.0) } func TestBMP388TemperatureWriteError(t *testing.T) { d, a := initTestBMP388WithStubbedAdaptor() _ = d.Start() a.i2cWriteImpl = func([]byte) (int, error) { return 0, errors.New("write error") } temp, err := d.Temperature(2) require.ErrorContains(t, err, "write error") assert.InDelta(t, float32(0.0), temp, 0.0) } func TestBMP388TemperatureReadError(t *testing.T) { d, a := initTestBMP388WithStubbedAdaptor() _ = d.Start() a.i2cReadImpl = func([]byte) (int, error) { return 0, errors.New("read error") } temp, err := d.Temperature(2) require.ErrorContains(t, err, "read error") assert.InDelta(t, float32(0.0), temp, 0.0) } func TestBMP388PressureWriteError(t *testing.T) { d, a := initTestBMP388WithStubbedAdaptor() _ = d.Start() a.i2cWriteImpl = func([]byte) (int, error) { return 0, errors.New("write error") } press, err := d.Pressure(2) require.ErrorContains(t, err, "write error") assert.InDelta(t, float32(0.0), press, 0.0) } func TestBMP388PressureReadError(t *testing.T) { d, a := initTestBMP388WithStubbedAdaptor() _ = d.Start() a.i2cReadImpl = func([]byte) (int, error) { return 0, errors.New("read error") } press, err := d.Pressure(2) require.ErrorContains(t, err, "read error") assert.InDelta(t, float32(0.0), press, 0.0) } func TestBMP388_initialization(t *testing.T) { // sequence to read and write in initialization(): // * read chip ID register (0x00) and compare // * read 24 bytes (12 x 16 bit calibration data), starting from TC1 register (0x31) // * fill calibration struct with data (LSByte read first) // * perform a soft reset by command register (0x7E) // * prepare the content of config register // * write the config register (0x1F) // arrange d, a := initTestBMP388WithStubbedAdaptor() a.written = []byte{} // reset writes of former test const ( wantChipIDReg = uint8(0x00) wantCalibReg = uint8(0x31) wantCommandReg = uint8(0x7E) wantCommandRegVal = uint8(0xB6) // soft reset wantConfReg = uint8(0x1F) wantConfRegVal = uint8(0x00) // no filter ) // Values produced by dumping data from actual sensor returnRead := []byte{ 36, 107, 156, 73, 246, 104, 255, 189, 245, 35, 0, 151, 101, 184, 122, 243, 246, 211, 64, 14, 196, 0, 0, 0, } numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ if numCallsRead == 1 { b[0] = 0x50 } else { copy(b, returnRead) } return len(b), nil } // act, assert - initialization() must be called on Start() err := d.Start() // assert require.NoError(t, err) assert.Equal(t, 2, numCallsRead) assert.Len(t, a.written, 6) assert.Equal(t, wantChipIDReg, a.written[0]) assert.Equal(t, wantCalibReg, a.written[1]) assert.Equal(t, wantCommandReg, a.written[2]) assert.Equal(t, wantCommandRegVal, a.written[3]) assert.Equal(t, wantConfReg, a.written[4]) assert.Equal(t, wantConfRegVal, a.written[5]) assert.InDelta(t, float32(7.021568e+06), d.calCoeffs.t1, 0.0) assert.InDelta(t, float32(1.7549843e-05), d.calCoeffs.t2, 0.0) assert.InDelta(t, float32(-3.5527137e-14), d.calCoeffs.t3, 0.0) assert.InDelta(t, float32(-0.015769958), d.calCoeffs.p1, 0.0) assert.InDelta(t, float32(-3.5410747e-05), d.calCoeffs.p2, 0.0) assert.InDelta(t, float32(8.1490725e-09), d.calCoeffs.p3, 0.0) assert.InDelta(t, float32(0), d.calCoeffs.p4, 0.0) assert.InDelta(t, float32(208056), d.calCoeffs.p5, 0.0) assert.InDelta(t, float32(490.875), d.calCoeffs.p6, 0.0) assert.InDelta(t, float32(-0.05078125), d.calCoeffs.p7, 0.0) assert.InDelta(t, float32(-0.00030517578), d.calCoeffs.p8, 0.0) assert.InDelta(t, float32(5.8957283e-11), d.calCoeffs.p9, 0.0) } ================================================ FILE: drivers/i2c/ccs811_driver.go ================================================ package i2c import ( "fmt" "math" "time" ) // CCS811DriveMode type type CCS811DriveMode uint8 // Operating modes which dictate how often measurements are being made. If 0x00 is used as an operating mode, // measurements will be disabled const ( CCS811DriveModeIdle CCS811DriveMode = 0x00 CCS811DriveMode1Sec CCS811DriveMode = 0x01 CCS811DriveMode10Sec CCS811DriveMode = 0x02 CCS811DriveMode60Sec CCS811DriveMode = 0x03 CCS811DriveMode250MS CCS811DriveMode = 0x04 ) const ( // the default I2C address for the ccs811 applies for ADDR to GND, for ADDR to VDD it will be 0x5B ccs811DefaultAddress = 0x5A // Registers, all definitions have been taken from the datasheet // Single byte read only register which indicates if a device is active, if new data is available or if an error // occurred. ccs811RegStatus = 0x00 // This is Single byte register, which is used to enable sensor drive mode and interrupts. ccs811RegMeasMode = 0x01 // This multi-byte read only register contains the calculated eCO2 (ppm) and eTVOC (ppb) values followed by the // STATUS register, ERROR_ID register and the RAW_DATA register. ccs811RegAlgResultData = 0x02 // Two byte read only register which contains the latest readings from the sensor. // ccs811RegRawData = 0x03 // A multi-byte register that can be written with the current Humidity and Temperature values if known. // ccs811RegEnvData = 0x05 // Register that holds the NTC value used for temperature calculations ccs811RegNtc = 0x06 // Asserting the SW_RESET will restart the CCS811 in Boot mode to enable new application firmware to be downloaded. ccs811RegSwReset = 0xFF // Single byte read only register which holds the HW ID which is 0x81 for this family of CCS81x devices. ccs811RegHwID = 0x20 // Single byte read only register that contains the hardware version. The value is 0x1X ccs811RegHwVersion = 0x21 // Two byte read only register which contain the version of the firmware bootloader stored in the CCS811 in the // format Major.Minor.Trivial ccs811RegFwBootVersion = 0x23 // Two byte read only register which contain the version of the firmware application stored in the CCS811 in the // format Major.Minor.Trivial ccs811RegFwAppVersion = 0x24 // To change the mode of the CCS811 from Boot mode to running the application, a single byte write of 0xF4 // is required. ccs811RegAppStart = 0xF4 // Constants // The hardware ID code ccs811HwIDCode = 0x81 ) // The sequence of bytes needed to do a software reset var ccs811SwResetSequence = []byte{0x11, 0xE5, 0x72, 0x8A} // CCS811Status represents the current status of the device defined by the ccs811RegStatus. // The following definitions were taken from // https://ams.com/documents/20143/36005/CCS811_DS000459_6-00.pdf/c7091525-c7e5-37ac-eedb-b6c6828b0dcf#page=15 type CCS811Status struct { // There is some sort of error on the i2c bus or there is an error with the internal sensor HasError byte // A new data sample is ready in ccs811RegAlgResultData DataReady byte // Valid application firmware loaded AppValid byte // Firmware is in application mode. CCS811 is ready to take sensor measurements FwMode byte } // NewCCS811Status returns a new instance of the package ccs811 status definition func NewCCS811Status(data uint8) *CCS811Status { return &CCS811Status{ HasError: data & 0x01, DataReady: (data >> 3) & 0x01, AppValid: (data >> 4) & 0x01, FwMode: (data >> 7) & 0x01, } } // CCS811MeasMode represents the current measurement configuration. // The following definitions were taken from the bit fields of the ccs811RegMeasMode defined in // https://ams.com/documents/20143/36005/CCS811_DS000459_6-00.pdf/c7091525-c7e5-37ac-eedb-b6c6828b0dcf#page=16 type CCS811MeasMode struct { // If intThresh is 1 a data measurement will only be taken when the sensor value meets the threshold constraint. // The threshold value is set in the threshold register (0x10) intThresh uint8 // If intDataRdy is 1, the nINT signal (pin 3 of the device) will be driven low when new data is available. intDataRdy uint8 // driveMode represents the sampling rate of the sensor. If the value is 0, the measurement process is idle. driveMode CCS811DriveMode } // NewCCS811MeasMode returns a new instance of the measurement mode configuration. This represents the desired initial // state of the measurement mode register. func NewCCS811MeasMode() *CCS811MeasMode { return &CCS811MeasMode{ // Disable this by default as this library does not contain the functionality to use the internal interrupt feature. intThresh: 0x00, intDataRdy: 0x00, driveMode: CCS811DriveMode1Sec, } } // GetMeasMode returns the measurement mode func (mm *CCS811MeasMode) GetMeasMode() byte { return (mm.intThresh << 2) | (mm.intDataRdy << 3) | uint8((mm.driveMode << 4)) } // CCS811Driver is the Gobot driver for the CCS811 (air quality sensor) Adafruit breakout board type CCS811Driver struct { *Driver measMode *CCS811MeasMode ntcResistanceValue uint32 } // NewCCS811Driver creates a new driver for the CCS811 (air quality sensor) func NewCCS811Driver(c Connector, options ...func(Config)) *CCS811Driver { d := &CCS811Driver{ Driver: NewDriver(c, "CCS811", ccs811DefaultAddress), measMode: NewCCS811MeasMode(), // Recommended resistance value is 100,000 ntcResistanceValue: 100000, } d.afterStart = d.initialize for _, option := range options { option(d) } return d } // WithCCS811MeasMode sets the sampling rate of the device func WithCCS811MeasMode(mode CCS811DriveMode) func(Config) { return func(c Config) { d, _ := c.(*CCS811Driver) d.measMode.driveMode = mode } } // WithCCS811NTCResistance sets reistor value used in the temperature calculations. // This resistor must be placed between pin 4 and pin 8 of the chip func WithCCS811NTCResistance(val uint32) func(Config) { return func(c Config) { d, _ := c.(*CCS811Driver) d.ntcResistanceValue = val } } // GetHardwareVersion returns the hardware version of the device in the form of 0x1X func (d *CCS811Driver) GetHardwareVersion() (uint8, error) { d.mutex.Lock() defer d.mutex.Unlock() v, err := d.readByteData(ccs811RegHwVersion) if err != nil { return 0, err } return v, nil } // GetFirmwareBootVersion returns the bootloader version func (d *CCS811Driver) GetFirmwareBootVersion() (uint16, error) { d.mutex.Lock() defer d.mutex.Unlock() v, err := d.readWordData(ccs811RegFwBootVersion) if err != nil { return 0, err } return v, nil } // GetFirmwareAppVersion returns the app code version func (d *CCS811Driver) GetFirmwareAppVersion() (uint16, error) { d.mutex.Lock() defer d.mutex.Unlock() v, err := d.readWordData(ccs811RegFwAppVersion) if err != nil { return 0, err } return v, nil } // GetStatus returns the current status of the device func (d *CCS811Driver) GetStatus() (*CCS811Status, error) { d.mutex.Lock() defer d.mutex.Unlock() s, err := d.readByteData(ccs811RegStatus) if err != nil { return nil, err } cs := NewCCS811Status(s) return cs, nil } // GetTemperature returns the device temperature in celsius. // If you do not have an NTC resistor installed, this function should not be called func (d *CCS811Driver) GetTemperature() (float32, error) { d.mutex.Lock() defer d.mutex.Unlock() buf := make([]byte, 4) err := d.readBlockData(ccs811RegNtc, buf) if err != nil { return 0, err } vref := ((uint16(buf[0]) << 8) | uint16(buf[1])) vrntc := ((uint16(buf[2]) << 8) | uint16(buf[3])) rntc := (float32(vrntc) * float32(d.ntcResistanceValue) / float32(vref)) ntcTemp := float32(math.Log(float64(rntc / 10000.0))) ntcTemp /= 3380.0 ntcTemp += 1.0 / (25 + 273.15) ntcTemp = 1.0 / ntcTemp ntcTemp -= 273.15 return ntcTemp, nil } // GetGasData returns the data for the gas sensor. // eco2 is returned in ppm and tvoc is returned in ppb func (d *CCS811Driver) GetGasData() (uint16, uint16, error) { d.mutex.Lock() defer d.mutex.Unlock() data := make([]byte, 4) err := d.readBlockData(ccs811RegAlgResultData, data) if err != nil { return 0, 0, err } // Bit masks defined by // https://ams.com/documents/20143/36005/CCS811_AN000369_2-00.pdf/25d0db9a-92b9-fa7f-362c-a7a4d1e292be#page=14 eco2 := (uint16(data[0]) << 8) | uint16(data[1]) tvoC := (uint16(data[2]) << 8) | uint16(data[3]) return eco2, tvoC, nil } // HasData returns true if the device has not errored and temperature/gas data is available func (d *CCS811Driver) HasData() (bool, error) { s, err := d.GetStatus() if err != nil { return false, err } if (s.DataReady != 0x01) || (s.HasError == 0x01) { return false, nil } return true, nil } // EnableExternalInterrupt enables the external output hardware interrupt pin 3. func (d *CCS811Driver) EnableExternalInterrupt() error { d.mutex.Lock() defer d.mutex.Unlock() d.measMode.intDataRdy = 1 return d.writeByteData(ccs811RegMeasMode, d.measMode.GetMeasMode()) } // DisableExternalInterrupt disables the external output hardware interrupt pin 3. func (d *CCS811Driver) DisableExternalInterrupt() error { d.mutex.Lock() defer d.mutex.Unlock() d.measMode.intDataRdy = 0 return d.writeByteData(ccs811RegMeasMode, d.measMode.GetMeasMode()) } func (d *CCS811Driver) initialize() error { deviceID, err := d.readByteData(ccs811RegHwID) if err != nil { return fmt.Errorf("failed to get the device id from ccs811RegHwID with error: %s", err.Error()) } // Verify that the connected device is the CCS811 sensor if deviceID != ccs811HwIDCode { return fmt.Errorf("the fetched device id %d is not the known id %d with error", deviceID, ccs811HwIDCode) } if err := d.resetDevice(); err != nil { return fmt.Errorf("was not able to reset the device with error: %s", err.Error()) } // Required sleep to allow device to switch states time.Sleep(100 * time.Millisecond) if err := d.startApp(); err != nil { return fmt.Errorf("failed to start app code with error: %s", err.Error()) } if err := d.updateMeasMode(); err != nil { return fmt.Errorf("failed to update the measMode register with error: %s", err.Error()) } return nil } // ResetDevice does a software reset of the device. After this operation is done, // the user must start the app code before the sensor can take any measurements func (d *CCS811Driver) resetDevice() error { return d.writeBlockData(ccs811RegSwReset, ccs811SwResetSequence) } // startApp starts the app code in the device. This operation has to be done after a // software reset to start taking sensor measurements. func (d *CCS811Driver) startApp() error { // Write without data is needed to start the app code _, err := d.write([]byte{ccs811RegAppStart}) return err } // updateMeasMode writes the current value of measMode to the measurement mode register. func (d *CCS811Driver) updateMeasMode() error { return d.writeByteData(ccs811RegMeasMode, d.measMode.GetMeasMode()) } ================================================ FILE: drivers/i2c/ccs811_driver_test.go ================================================ package i2c import ( "errors" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) // this ensures that the implementation is based on i2c.Driver, which implements the gobot.Driver // and tests all implementations, so no further tests needed here for gobot.Driver interface var _ gobot.Driver = (*CCS811Driver)(nil) func initTestCCS811WithStubbedAdaptor() (*CCS811Driver, *i2cTestAdaptor) { a := newI2cTestAdaptor() // mandatory for a successful start a.i2cReadImpl = func(b []byte) (int, error) { b[0] = ccs811HwIDCode return len(b), nil } return NewCCS811Driver(a), a } func TestNewCCS811Driver(t *testing.T) { var di interface{} = NewCCS811Driver(newI2cTestAdaptor()) d, ok := di.(*CCS811Driver) if !ok { require.Fail(t, "NewCCS811Driver() should have returned a *CCS811Driver") } assert.NotNil(t, d.Driver) assert.True(t, strings.HasPrefix(d.Name(), "CCS811")) assert.Equal(t, 0x5A, d.defaultAddress) assert.NotNil(t, d.measMode) assert.Equal(t, uint32(100000), d.ntcResistanceValue) } func TestCCS811Halt(t *testing.T) { // arrange d, _ := initTestCCS811WithStubbedAdaptor() // act, assert require.NoError(t, d.Halt()) // must be idempotent require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestCCS811Options(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithBus() option and // least one of this driver. Further tests for options can also be done by call of "WithOption(val)(d)". d := NewCCS811Driver(newI2cTestAdaptor(), WithBus(2), WithAddress(0xFF), WithCCS811NTCResistance(0xFF)) assert.Equal(t, 2, d.GetBusOrDefault(1)) assert.Equal(t, 0xFF, d.GetAddressOrDefault(0x5a)) assert.Equal(t, uint32(0xFF), d.ntcResistanceValue) } func TestCCS811WithCCS811MeasMode(t *testing.T) { d := NewCCS811Driver(newI2cTestAdaptor(), WithCCS811MeasMode(CCS811DriveMode10Sec)) assert.Equal(t, CCS811DriveMode10Sec, d.measMode.driveMode) } func TestCCS811GetGasData(t *testing.T) { tests := map[string]struct { readReturn func([]byte) (int, error) eco2 uint16 tvoc uint16 err error }{ "ideal values taken from the bus": { readReturn: func(b []byte) (int, error) { copy(b, []byte{1, 156, 0, 86}) return 4, nil }, eco2: 412, tvoc: 86, err: nil, }, "max values possible taken from the bus": { readReturn: func(b []byte) (int, error) { copy(b, []byte{255, 255, 255, 255}) return 4, nil }, eco2: 65535, tvoc: 65535, err: nil, }, "error when the i2c operation fails": { readReturn: func(b []byte) (int, error) { copy(b, []byte{255, 255, 255, 255}) return 4, errors.New("Error") }, eco2: 0, tvoc: 0, err: errors.New("Error"), }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, a := initTestCCS811WithStubbedAdaptor() // Create stub function as it is needed by read submethod in driver code a.i2cWriteImpl = func([]byte) (int, error) { return 0, nil } require.NoError(t, d.Start()) a.i2cReadImpl = tc.readReturn // act eco2, tvoc, err := d.GetGasData() // assert assert.Equal(t, tc.eco2, eco2) assert.Equal(t, tc.tvoc, tvoc) assert.Equal(t, tc.err, err) }) } } func TestCCS811GetTemperature(t *testing.T) { tests := map[string]struct { readReturn func([]byte) (int, error) temp float32 err error }{ "ideal values taken from the bus": { readReturn: func(b []byte) (int, error) { copy(b, []byte{10, 197, 0, 248}) return 4, nil }, temp: 27.811005, err: nil, }, "without bus values overflowing": { readReturn: func(b []byte) (int, error) { copy(b, []byte{129, 197, 10, 248}) return 4, nil }, temp: 29.48822, err: nil, }, "negative temperature": { readReturn: func(b []byte) (int, error) { copy(b, []byte{255, 255, 255, 255}) return 4, nil }, temp: -25.334152, err: nil, }, "error if the i2c bus errors": { readReturn: func(b []byte) (int, error) { copy(b, []byte{129, 197, 0, 248}) return 4, errors.New("Error") }, temp: 0, err: errors.New("Error"), }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, a := initTestCCS811WithStubbedAdaptor() // Create stub function as it is needed by read submethod in driver code a.i2cWriteImpl = func([]byte) (int, error) { return 0, nil } require.NoError(t, d.Start()) a.i2cReadImpl = tc.readReturn // act temp, err := d.GetTemperature() // assert assert.InDelta(t, tc.temp, temp, 0.0) assert.Equal(t, tc.err, err) }) } } func TestCCS811HasData(t *testing.T) { tests := map[string]struct { readReturn func([]byte) (int, error) result bool err error }{ "true for HasError=0 and DataRdy=1": { readReturn: func(b []byte) (int, error) { copy(b, []byte{0x08}) return 1, nil }, result: true, err: nil, }, "false for HasError=1 and DataRdy=1": { readReturn: func(b []byte) (int, error) { copy(b, []byte{0x09}) return 1, nil }, result: false, err: nil, }, "false for HasError=1 and DataRdy=0": { readReturn: func(b []byte) (int, error) { copy(b, []byte{0x01}) return 1, nil }, result: false, err: nil, }, "false for HasError=0 and DataRdy=0": { readReturn: func(b []byte) (int, error) { copy(b, []byte{0x00}) return 1, nil }, result: false, err: nil, }, "error when the i2c read operation fails": { readReturn: func(b []byte) (int, error) { copy(b, []byte{0x00}) return 1, errors.New("Error") }, result: false, err: errors.New("Error"), }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, a := initTestCCS811WithStubbedAdaptor() // Create stub function as it is needed by read submethod in driver code a.i2cWriteImpl = func([]byte) (int, error) { return 0, nil } require.NoError(t, d.Start()) a.i2cReadImpl = tc.readReturn // act result, err := d.HasData() // assert assert.Equal(t, tc.result, result) assert.Equal(t, tc.err, err) }) } } func TestCCS811_initialize(t *testing.T) { // sequence for initialization the device on Start() // * write hardware ID register (0x20) // * read the ID // * prepare software reset register content: a sequence of four bytes must // be written to this register in a single I²C sequence: 0x11, 0xE5, 0x72, 0x8A // * write software reset register content (0xFF) // * write application start register (0xF4) // * prepare measurement mode register content // * INT_THRESH = 0 (normal mode) // * INT_DATARDY = 0 (disable interrupt mode) // * DRIVE_MODE = 0x01 (constant power, value every 1 sec) // * write measure mode register content (0x01) // // arrange d, a := initTestCCS811WithStubbedAdaptor() a.written = []byte{} // reset writes of former test const ( wantChipIDReg = uint8(0x20) wantChipIDRegVal = uint8(0x20) wantResetReg = uint8(0xFF) wantAppStartReg = uint8(0xF4) wantMeasReg = uint8(0x01) wantMeasRegVal = uint8(0x10) ) wantResetRegSequence := []byte{0x11, 0xE5, 0x72, 0x8A} // arrange reads numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ // chip ID b[0] = 0x81 return len(b), nil } // arrange, act - initialize() must be called on Start() err := d.Start() // assert require.NoError(t, err) assert.Equal(t, 1, numCallsRead) assert.Len(t, a.written, 9) assert.Equal(t, wantChipIDReg, a.written[0]) assert.Equal(t, wantResetReg, a.written[1]) assert.Equal(t, wantResetRegSequence, a.written[2:6]) assert.Equal(t, wantAppStartReg, a.written[6]) assert.Equal(t, wantMeasReg, a.written[7]) assert.Equal(t, wantMeasRegVal, a.written[8]) } ================================================ FILE: drivers/i2c/doc.go ================================================ /* Package i2c provides Gobot drivers for i2c devices. Installing: Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) For further information refer to i2c README: https://github.com/hybridgroup/gobot/blob/release/drivers/i2c/README.md */ package i2c // import "gobot.io/x/gobot/v2/drivers/i2c" ================================================ FILE: drivers/i2c/drv2605l_driver.go ================================================ package i2c // DRV2605Mode - operating mode type DRV2605Mode uint8 // Operating modes, for use in SetMode() const ( DRV2605ModeIntTrig DRV2605Mode = 0x00 DRV2605ModeExtTrigEdge DRV2605Mode = 0x01 DRV2605ModeExtTrigLvl DRV2605Mode = 0x02 DRV2605ModePWMAnalog DRV2605Mode = 0x03 DRV2605ModeAudioVibe DRV2605Mode = 0x04 DRV2605ModeRealtime DRV2605Mode = 0x05 DRV2605ModeDiagnose DRV2605Mode = 0x06 DRV2605ModeAutocal DRV2605Mode = 0x07 ) const ( drv2605DefaultAddress = 0x5A drv2605RegStatus = 0x00 drv2605RegMode = 0x01 drv2605Standby = 0x40 drv2605RegRTPin = 0x02 drv2605RegLibrary = 0x03 drv2605RegWaveSeq1 = 0x04 drv2605RegWaveSeq2 = 0x05 drv2605RegWaveSeq3 = 0x06 drv2605RegWaveSeq4 = 0x07 drv2605RegWaveSeq5 = 0x08 drv2605RegWaveSeq6 = 0x09 drv2605RegWaveSeq7 = 0x0A drv2605RegWaveSeq8 = 0x0B drv2605RegGo = 0x0C drv2605RegOverdrive = 0x0D drv2605RegSustainPos = 0x0E drv2605RegSustainNeg = 0x0F drv2605RegBreak = 0x10 drv2605RegAudioCtrl = 0x11 drv2605RegAudioMinLevel = 0x12 drv2605RegAudioMaxLevel = 0x13 drv2605RegAudioMinDrive = 0x14 drv2605RegAudioMaxDrive = 0x15 drv2605RegRatedV = 0x16 drv2605RegClampV = 0x17 drv2605RegAutocalComp = 0x18 drv2605RegAutocalEmp = 0x19 drv2605RegFeedback = 0x1A drv2605RegControl1 = 0x1B drv2605RegControl2 = 0x1C drv2605RegControl3 = 0x1D drv2605RegControl4 = 0x1E drv2605RegVBat = 0x21 drv2605RegLRAResoPeriod = 0x22 ) // DRV2605LDriver is the gobot driver for the TI/Adafruit DRV2605L Haptic Controller // // Device datasheet: http://www.ti.com/lit/ds/symlink/drv2605l.pdf // // Inspired by the Adafruit Python driver by Sean Mealin. // // Basic use: // // haptic := i2c.NewDRV2605Driver(adaptor) // haptic.SetSequence([]byte{1, 13}) // haptic.Go() type DRV2605LDriver struct { *Driver } // NewDRV2605LDriver creates a new driver for the DRV2605L device. // // Params: // // c Connector - the Adaptor to use with this Driver // // Optional params: // // i2c.WithBus(int): bus to use with this driver // i2c.WithAddress(int): address to use with this driver func NewDRV2605LDriver(c Connector, options ...func(Config)) *DRV2605LDriver { d := &DRV2605LDriver{ Driver: NewDriver(c, "DRV2605L", drv2605DefaultAddress), } d.afterStart = d.initialize d.beforeHalt = d.shutdown for _, option := range options { option(d) } return d } // SetMode sets the device in one of the eight modes as described in the // datasheet. Defaults to mode 0, internal trig. func (d *DRV2605LDriver) SetMode(newMode DRV2605Mode) error { mode, err := d.readByteData(drv2605RegMode) if err != nil { return err } // clear mode bits (lower three bits) mode &= 0xf8 // set new mode bits mode |= uint8(newMode) err = d.writeByteData(drv2605RegMode, mode) return err } // SetStandbyMode controls device low power mode func (d *DRV2605LDriver) SetStandbyMode(standby bool) error { modeVal, err := d.readByteData(drv2605RegMode) if err != nil { return err } if standby { modeVal |= drv2605Standby } else { modeVal &= 0xFF ^ drv2605Standby } err = d.writeByteData(drv2605RegMode, modeVal) return err } // SelectLibrary selects which waveform library to play from, 1-7. // See datasheet for more info. func (d *DRV2605LDriver) SelectLibrary(library uint8) error { return d.writeByteData(drv2605RegLibrary, library&0x7) } // GetPauseWaveform returns a special waveform ID used in SetSequence() to encode // pauses between waveforms. Time is specified in tens of milliseconds // ranging from 0ms (delayTime10MS = 0) to 1270ms (delayTime10MS = 127). // Times out of range are clipped to fit. func (d *DRV2605LDriver) GetPauseWaveform(delayTime10MS uint8) uint8 { if delayTime10MS > 127 { delayTime10MS = 127 } return delayTime10MS | 0x80 } // SetSequence sets the sequence of waveforms to be played by the sequencer, // specified by waveform id as described in the datasheet. // The sequencer can play at most 8 waveforms in sequence, longer // sequences will be truncated. // A waveform id of zero marks the end of the sequence. // Pauses can be encoded using GetPauseWaveform(). func (d *DRV2605LDriver) SetSequence(waveforms []uint8) error { if len(waveforms) < 8 { waveforms = append(waveforms, 0) } if len(waveforms) > 8 { waveforms = waveforms[0:8] } for i, w := range waveforms { //nolint:gosec // TODO: fix later if err := d.writeByteData(uint8(drv2605RegWaveSeq1+i), w); err != nil { return err } } return nil } // Go plays the current sequence of waveforms. func (d *DRV2605LDriver) Go() error { return d.writeByteData(drv2605RegGo, 1) } func (d *DRV2605LDriver) writeByteRegisters(regValPairs []struct{ reg, val uint8 }) error { for _, rv := range regValPairs { if err := d.writeByteData(rv.reg, rv.val); err != nil { return err } } return nil } func (d *DRV2605LDriver) initialize() error { feedback, err := d.readByteData(drv2605RegFeedback) if err != nil { return err } control, err := d.readByteData(drv2605RegControl3) if err != nil { return err } return d.writeByteRegisters([]struct{ reg, val uint8 }{ // leave standby, enter "internal trig" mode {drv2605RegMode, 0}, // turn off real-time play {drv2605RegRTPin, 0}, // init wave sequencer with "strong click" {drv2605RegWaveSeq1, 1}, {drv2605RegWaveSeq1, 0}, // no physical parameter tweaks {drv2605RegSustainPos, 0}, {drv2605RegSustainNeg, 0}, {drv2605RegBreak, 0}, // set up ERM open loop {drv2605RegFeedback, feedback & 0x7f}, {drv2605RegControl3, control | 0x20}, }) } func (d *DRV2605LDriver) shutdown() error { if d.connection != nil { // stop playback if err := d.writeByteData(drv2605RegGo, 0); err != nil { return err } // enter standby return d.SetStandbyMode(true) } return nil } ================================================ FILE: drivers/i2c/drv2605l_driver_test.go ================================================ package i2c import ( "bytes" "encoding/binary" "errors" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) // this ensures that the implementation is based on i2c.Driver, which implements the gobot.Driver // and tests all implementations, so no further tests needed here for gobot.Driver interface var _ gobot.Driver = (*DRV2605LDriver)(nil) func initTestDRV2605LDriverWithStubbedAdaptor() (*DRV2605LDriver, *i2cTestAdaptor) { a := newI2cTestAdaptor() // Prime adapter reader to make "Start()" call happy a.i2cReadImpl = func(b []byte) (int, error) { buf := new(bytes.Buffer) _ = binary.Write(buf, binary.LittleEndian, uint8(42)) copy(b, buf.Bytes()) return buf.Len(), nil } d := NewDRV2605LDriver(a) if err := d.Start(); err != nil { panic(err) } return d, a } func TestNewDRV2605LDriver(t *testing.T) { var di interface{} = NewDRV2605LDriver(newI2cTestAdaptor()) d, ok := di.(*DRV2605LDriver) if !ok { require.Fail(t, "NewDRV2605LDriver() should have returned a *DRV2605LDriver") } assert.NotNil(t, d.Driver) assert.True(t, strings.HasPrefix(d.Name(), "DRV2605L")) assert.Equal(t, 0x5a, d.defaultAddress) } func TestDRV2605LOptions(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithBus() option and // least one of this driver. Further tests for options can also be done by call of "WithOption(val)(d)". d := NewDRV2605LDriver(newI2cTestAdaptor(), WithBus(2)) assert.Equal(t, 2, d.GetBusOrDefault(1)) } func TestDRV2605LStart(t *testing.T) { d := NewDRV2605LDriver(newI2cTestAdaptor()) require.NoError(t, d.Start()) } func TestDRV2605LHaltIdempotent(t *testing.T) { // arrange d := NewDRV2605LDriver(newI2cTestAdaptor()) // act, assert require.NoError(t, d.Halt()) // must be idempotent require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestDRV2605LHalt(t *testing.T) { // arrange writeStopPlaybackData := []byte{drv2605RegGo, 0} // single-byte-read starts with a write operation to set the register for reading // see section 8.5.3.5 of data sheet readCurrentStandbyModeData := byte(drv2605RegMode) writeNewStandbyModeData := []byte{drv2605RegMode, 42 | drv2605Standby} d, a := initTestDRV2605LDriverWithStubbedAdaptor() a.written = []byte{} // act require.NoError(t, d.Halt()) // assert assert.Equal(t, append(append(writeStopPlaybackData, readCurrentStandbyModeData), writeNewStandbyModeData...), a.written) } func TestDRV2605LGetPause(t *testing.T) { d, _ := initTestDRV2605LDriverWithStubbedAdaptor() assert.Equal(t, uint8(0x80), d.GetPauseWaveform(0)) assert.Equal(t, uint8(0x81), d.GetPauseWaveform(1)) assert.Equal(t, d.GetPauseWaveform(127), d.GetPauseWaveform(128)) } func TestDRV2605LSequenceTermination(t *testing.T) { d, a := initTestDRV2605LDriverWithStubbedAdaptor() a.written = []byte{} require.NoError(t, d.SetSequence([]byte{1, 2})) assert.Equal(t, []byte{ drv2605RegWaveSeq1, 1, drv2605RegWaveSeq2, 2, drv2605RegWaveSeq3, 0, }, a.written) } func TestDRV2605LSequenceTruncation(t *testing.T) { d, a := initTestDRV2605LDriverWithStubbedAdaptor() a.written = []byte{} require.NoError(t, d.SetSequence([]byte{1, 2, 3, 4, 5, 6, 7, 8, 99, 100})) assert.Equal(t, []byte{ drv2605RegWaveSeq1, 1, drv2605RegWaveSeq2, 2, drv2605RegWaveSeq3, 3, drv2605RegWaveSeq4, 4, drv2605RegWaveSeq5, 5, drv2605RegWaveSeq6, 6, drv2605RegWaveSeq7, 7, drv2605RegWaveSeq8, 8, }, a.written) } func TestDRV2605LSetMode(t *testing.T) { d, _ := initTestDRV2605LDriverWithStubbedAdaptor() require.NoError(t, d.SetMode(DRV2605ModeIntTrig)) } func TestDRV2605LSetModeReadError(t *testing.T) { d, a := initTestDRV2605LDriverWithStubbedAdaptor() a.i2cReadImpl = func(b []byte) (int, error) { return 0, errors.New("read error") } require.ErrorContains(t, d.SetMode(DRV2605ModeIntTrig), "read error") } func TestDRV2605LSetStandbyMode(t *testing.T) { d, _ := initTestDRV2605LDriverWithStubbedAdaptor() require.NoError(t, d.SetStandbyMode(true)) } func TestDRV2605LSetStandbyModeReadError(t *testing.T) { d, a := initTestDRV2605LDriverWithStubbedAdaptor() a.i2cReadImpl = func(b []byte) (int, error) { return 0, errors.New("read error") } require.ErrorContains(t, d.SetStandbyMode(true), "read error") } func TestDRV2605LSelectLibrary(t *testing.T) { d, _ := initTestDRV2605LDriverWithStubbedAdaptor() require.NoError(t, d.SelectLibrary(1)) } func TestDRV2605LGo(t *testing.T) { d, _ := initTestDRV2605LDriverWithStubbedAdaptor() require.NoError(t, d.Go()) } ================================================ FILE: drivers/i2c/generic_driver.go ================================================ package i2c import ( "fmt" "time" ) // GenericDriver implements the interface gobot.Driver. type GenericDriver struct { *Driver } // NewGenericDriver creates a new generic i2c gobot driver, which just forwards all connection functions. func NewGenericDriver(c Connector, name string, address int, options ...func(Config)) *GenericDriver { return &GenericDriver{Driver: NewDriver(c, name, address, options...)} } // WriteByte writes one byte to the i2c device. func (d *GenericDriver) WriteByte(val byte) error { d.mutex.Lock() defer d.mutex.Unlock() return d.writeByte(val) } // WriteByteData writes the given byte value to the given register of an i2c device. func (d *GenericDriver) WriteByteData(reg uint8, val byte) error { d.mutex.Lock() defer d.mutex.Unlock() return d.writeByteData(reg, val) } // WriteWordData writes the given 16 bit value to the given register of an i2c device. func (d *GenericDriver) WriteWordData(reg uint8, val uint16) error { d.mutex.Lock() defer d.mutex.Unlock() return d.writeWordData(reg, val) } // WriteBlockData writes the given buffer to the given register of an i2c device. func (d *GenericDriver) WriteBlockData(reg uint8, data []byte) error { d.mutex.Lock() defer d.mutex.Unlock() return d.writeBlockData(reg, data) } // WriteData writes the given buffer to the given register of an i2c device. // It uses plain write to prevent WriteBlockData(), which is sometimes not supported by adaptor. func (d *GenericDriver) WriteData(reg uint8, data []byte) error { d.mutex.Lock() defer d.mutex.Unlock() buf := make([]byte, len(data)+1) copy(buf[1:], data) buf[0] = reg return d.writeAndCheckCount(buf) } // Write writes the given buffer to the i2c device. func (d *GenericDriver) Write(data []byte) error { d.mutex.Lock() defer d.mutex.Unlock() return d.writeAndCheckCount(data) } // ReadByte reads a byte from the current register of an i2c device. func (d *GenericDriver) ReadByte() (byte, error) { d.mutex.Lock() defer d.mutex.Unlock() return d.readByte() } // ReadByteData reads a byte from the given register of an i2c device. func (d *GenericDriver) ReadByteData(reg uint8) (byte, error) { d.mutex.Lock() defer d.mutex.Unlock() return d.readByteData(reg) } // ReadWordData reads a 16 bit value starting from the given register of an i2c device. func (d *GenericDriver) ReadWordData(reg uint8) (uint16, error) { d.mutex.Lock() defer d.mutex.Unlock() return d.readWordData(reg) } // ReadBlockData fills the given buffer with reads starting from the given register of an i2c device. func (d *GenericDriver) ReadBlockData(reg uint8, data []byte) error { d.mutex.Lock() defer d.mutex.Unlock() return d.readBlockData(reg, data) } // ReadData fills the given buffer with reads from the given register of an i2c device. // It uses plain read to prevent ReadBlockData(), which is sometimes not supported by adaptor. func (d *GenericDriver) ReadData(reg uint8, data []byte) error { d.mutex.Lock() defer d.mutex.Unlock() if err := d.writeByte(reg); err != nil { return err } // write process needs some time, so wait at least 5ms before read a value // when decreasing to much, the check below will fail time.Sleep(10 * time.Millisecond) return d.readAndCheckCount(data) } // Read fills the given buffer with reads of an i2c device. func (d *GenericDriver) Read(data []byte) error { d.mutex.Lock() defer d.mutex.Unlock() return d.readAndCheckCount(data) } func (d *GenericDriver) writeAndCheckCount(data []byte) error { n, err := d.write(data) if err != nil { return err } if n != len(data) { return fmt.Errorf("written count (%d) differ from expected (%d)", n, len(data)) } return nil } func (d *GenericDriver) readAndCheckCount(data []byte) error { n, err := d.read(data) if err != nil { return err } if n != len(data) { return fmt.Errorf("read count (%d) differ from expected (%d)", n, len(data)) } return nil } ================================================ FILE: drivers/i2c/generic_driver_test.go ================================================ package i2c import ( "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) var _ gobot.Driver = (*GenericDriver)(nil) func TestNewGenericDriver(t *testing.T) { // arrange a := newI2cTestAdaptor() // act var di interface{} = NewGenericDriver(a, "GenericI2C", 0x17) // assert d, ok := di.(*GenericDriver) if !ok { require.Fail(t, "NewGenericDriver() should have returned a *GenericDriver") } assert.NotNil(t, d.Driver) assert.True(t, strings.HasPrefix(d.Name(), "GenericI2C")) } ================================================ FILE: drivers/i2c/grove_drivers.go ================================================ package i2c // GroveLcdDriver is a driver for the Jhd1313m1 LCD display which has two i2c addreses, // one belongs to a controller and the other controls solely the backlight. // This module was tested with the Seed Grove LCD RGB Backlight v2.0 display which requires 5V to operate. // http://www.seeedstudio.com/wiki/Grove_-_LCD_RGB_Backlight type GroveLcdDriver struct { *JHD1313M1Driver } // GroveAccelerometerDriver is a driver for the MMA7660 accelerometer type GroveAccelerometerDriver struct { *MMA7660Driver } // NewGroveLcdDriver creates a new driver with specified i2c interface. // Params: // // conn Connector - the Adaptor to use with this Driver // // Optional params: // // i2c.WithBus(int): bus to use with this driver // i2c.WithAddress(int): address to use with this driver func NewGroveLcdDriver(a Connector, options ...func(Config)) *GroveLcdDriver { lcd := &GroveLcdDriver{ JHD1313M1Driver: NewJHD1313M1Driver(a), } for _, option := range options { option(lcd) } return lcd } // NewGroveAccelerometerDriver creates a new driver with specified i2c interface // Params: // // conn Connector - the Adaptor to use with this Driver // // Optional params: // // i2c.WithBus(int): bus to use with this driver // i2c.WithAddress(int): address to use with this driver func NewGroveAccelerometerDriver(a Connector, options ...func(Config)) *GroveAccelerometerDriver { mma := &GroveAccelerometerDriver{ MMA7660Driver: NewMMA7660Driver(a), } for _, option := range options { option(mma) } return mma } ================================================ FILE: drivers/i2c/grove_drivers_test.go ================================================ package i2c import ( "strings" "testing" "github.com/stretchr/testify/assert" "gobot.io/x/gobot/v2" ) var ( _ gobot.Driver = (*GroveLcdDriver)(nil) _ gobot.Driver = (*GroveAccelerometerDriver)(nil) ) func initTestGroveLcdDriver() *GroveLcdDriver { d, _ := initGroveLcdDriverWithStubbedAdaptor() return d } func initGroveLcdDriverWithStubbedAdaptor() (*GroveLcdDriver, *i2cTestAdaptor) { adaptor := newI2cTestAdaptor() return NewGroveLcdDriver(adaptor), adaptor } func initTestGroveAccelerometerDriver() *GroveAccelerometerDriver { d, _ := initGroveAccelerometerDriverWithStubbedAdaptor() return d } func initGroveAccelerometerDriverWithStubbedAdaptor() (*GroveAccelerometerDriver, *i2cTestAdaptor) { adaptor := newI2cTestAdaptor() return NewGroveAccelerometerDriver(adaptor), adaptor } func TestGroveLcdDriverName(t *testing.T) { g := initTestGroveLcdDriver() assert.NotNil(t, g.Connection()) assert.True(t, strings.HasPrefix(g.Name(), "JHD1313M1")) } func TestLcdDriverWithAddress(t *testing.T) { adaptor := newI2cTestAdaptor() g := NewGroveLcdDriver(adaptor, WithAddress(0x66)) assert.Equal(t, 0x66, g.GetAddressOrDefault(0x33)) } func TestGroveAccelerometerDriverName(t *testing.T) { g := initTestGroveAccelerometerDriver() assert.NotNil(t, g.Connection()) assert.True(t, strings.HasPrefix(g.Name(), "MMA7660")) } func TestGroveAccelerometerDriverWithAddress(t *testing.T) { adaptor := newI2cTestAdaptor() g := NewGroveAccelerometerDriver(adaptor, WithAddress(0x66)) assert.Equal(t, 0x66, g.GetAddressOrDefault(0x33)) } ================================================ FILE: drivers/i2c/grovepi_driver.go ================================================ package i2c import ( "encoding/binary" "fmt" "math" "strconv" "strings" "time" ) // default is for grovepi4 installer const grovePiDefaultAddress = 0x04 // commands, see: // * https://www.dexterindustries.com/GrovePi/programming/grovepi-protocol-adding-custom-sensors/ // * https://github.com/DexterInd/GrovePi/tree/1.3.0/Script/multi_grovepi_installer/grovepi4.py const ( commandReadDigital = 1 commandWriteDigital = 2 commandReadAnalog = 3 commandWriteAnalog = 4 commandSetPinMode = 5 commandReadUltrasonic = 7 commandReadFirmwareVersion = 8 commandReadDHT = 40 ) // GrovePiDriver is a driver for the GrovePi+ for I²C bus interface. // https://www.dexterindustries.com/grovepi/ // // To use this driver with the GrovePi, it must be running the firmware >= 1.4.0 and the system version >=3. // https://github.com/DexterInd/GrovePi/tree/1.3.0/README.md type GrovePiDriver struct { *Driver pins map[int]string } // NewGrovePiDriver creates a new driver with specified i2c interface // Params: // // conn Connector - the Adaptor to use with this Driver // // Optional params: // // i2c.WithBus(int): bus to use with this driver // i2c.WithAddress(int): address to use with this driver func NewGrovePiDriver(c Connector, options ...func(Config)) *GrovePiDriver { d := &GrovePiDriver{ Driver: NewDriver(c, "GrovePi", grovePiDefaultAddress), pins: make(map[int]string), } for _, option := range options { option(d) } // TODO: add commands for API return d } // Connect is here to implement the Adaptor interface. func (d *GrovePiDriver) Connect() error { return nil } // Finalize is here to implement the Adaptor interface. func (d *GrovePiDriver) Finalize() error { return nil } // AnalogRead returns value from analog pin implementing the AnalogReader interface. func (d *GrovePiDriver) AnalogRead(pin string) (int, error) { d.mutex.Lock() defer d.mutex.Unlock() pinNum, err := d.preparePin(pin, "input") if err != nil { return 0, err } buf := []byte{commandReadAnalog, byte(pinNum), 0, 0} if _, err := d.write(buf); err != nil { return 0, err } time.Sleep(2 * time.Millisecond) data := make([]byte, 3) if err = d.readForCommand(commandReadAnalog, data); err != nil { return 0, err } return int(data[1])*256 + int(data[2]), nil } // DigitalRead performs a read on a digital pin. func (d *GrovePiDriver) DigitalRead(pin string) (int, error) { d.mutex.Lock() defer d.mutex.Unlock() pinNum, err := d.preparePin(pin, "input") if err != nil { return 0, err } buf := []byte{commandReadDigital, byte(pinNum), 0, 0} if _, err := d.write(buf); err != nil { return 0, err } time.Sleep(2 * time.Millisecond) data := make([]byte, 2) if err = d.readForCommand(commandReadDigital, data); err != nil { return 0, err } return int(data[1]), nil } // UltrasonicRead performs a read on an ultrasonic pin with duration >=2 millisecond. func (d *GrovePiDriver) UltrasonicRead(pin string, duration int) (int, error) { d.mutex.Lock() defer d.mutex.Unlock() if duration < 2 { duration = 2 } pinNum, err := d.preparePin(pin, "input") if err != nil { return 0, err } buf := []byte{commandReadUltrasonic, byte(pinNum), 0, 0} if _, err = d.write(buf); err != nil { return 0, err } time.Sleep(time.Duration(duration) * time.Millisecond) data := make([]byte, 3) if err := d.readForCommand(commandReadUltrasonic, data); err != nil { return 0, err } return int(data[1])*255 + int(data[2]), nil } // FirmwareVersionRead returns the GrovePi firmware version. func (d *GrovePiDriver) FirmwareVersionRead() (string, error) { d.mutex.Lock() defer d.mutex.Unlock() buf := []byte{commandReadFirmwareVersion, 0, 0, 0} if _, err := d.write(buf); err != nil { return "", err } time.Sleep(2 * time.Millisecond) data := make([]byte, 4) if err := d.readForCommand(commandReadFirmwareVersion, data); err != nil { return "", err } return fmt.Sprintf("%v.%v.%v", data[1], data[2], data[3]), nil } // DHTRead performs a read temperature and humidity sensors with duration >=2 millisecond. // DHT11 (blue): sensorType=0 // DHT22 (white): sensorTyp=1 // //nolint:nonamedreturns // is sufficient here func (d *GrovePiDriver) DHTRead(pin string, sensorType byte, duration int) (temp float32, hum float32, err error) { d.mutex.Lock() defer d.mutex.Unlock() if duration < 2 { duration = 2 } pinNum, err := d.preparePin(pin, "input") if err != nil { return 0, 0, err } buf := []byte{commandReadDHT, byte(pinNum), sensorType, 0} if _, err = d.write(buf); err != nil { return 0, 0, err } time.Sleep(time.Duration(duration) * time.Millisecond) data := make([]byte, 9) if err = d.readForCommand(commandReadDHT, data); err != nil { return 0, 0, err } temp = float32Of4BytesLittleEndian(data[1:5]) if temp > 150 { temp = 150 } if temp < -100 { temp = -100 } hum = float32Of4BytesLittleEndian(data[5:9]) if hum > 100 { hum = 100 } if hum < 0 { hum = 0 } return temp, hum, err } // DigitalWrite writes a value to a specific digital pin implementing the DigitalWriter interface. func (d *GrovePiDriver) DigitalWrite(pin string, val byte) error { d.mutex.Lock() defer d.mutex.Unlock() pinNum, err := d.preparePin(pin, "output") if err != nil { return err } buf := []byte{commandWriteDigital, byte(pinNum), val, 0} if _, err := d.write(buf); err != nil { return err } time.Sleep(2 * time.Millisecond) _, err = d.readByte() return err } // AnalogWrite writes PWM aka analog to the GrovePi analog pin implementing the AnalogWriter interface. func (d *GrovePiDriver) AnalogWrite(pin string, val int) error { d.mutex.Lock() defer d.mutex.Unlock() pinNum, err := d.preparePin(pin, "output") if err != nil { return err } buf := []byte{commandWriteAnalog, byte(pinNum), byte(val), 0} if _, err := d.write(buf); err != nil { return err } time.Sleep(2 * time.Millisecond) _, err = d.readByte() return err } // SetPinMode sets the pin mode to input or output. func (d *GrovePiDriver) SetPinMode(pin byte, mode string) error { d.mutex.Lock() defer d.mutex.Unlock() return d.setPinMode(pin, mode) } func getPin(pin string) string { if len(pin) > 1 { if strings.ToUpper(pin[0:1]) == "A" || strings.ToUpper(pin[0:1]) == "D" { return pin[1:] } } return pin } func (d *GrovePiDriver) setPinMode(pin byte, mode string) error { var b []byte if mode == "output" { b = []byte{commandSetPinMode, pin, 1, 0} } else { b = []byte{commandSetPinMode, pin, 0, 0} } if _, err := d.write(b); err != nil { return err } time.Sleep(2 * time.Millisecond) _, err := d.readByte() return err } func (d *GrovePiDriver) ensurePinMode(pinNum int, mode string) error { if dir, ok := d.pins[pinNum]; !ok || dir != mode { if err := d.setPinMode(byte(pinNum), mode); err != nil { return err } d.pins[pinNum] = mode } return nil } func (d *GrovePiDriver) preparePin(pin string, mode string) (int, error) { pin = getPin(pin) pinNum, err := strconv.Atoi(pin) if err != nil { return -1, err } if err := d.ensurePinMode(pinNum, mode); err != nil { return -1, err } return pinNum, nil } func (d *GrovePiDriver) readForCommand(command byte, data []byte) error { cnt, err := d.read(data) if err != nil { return err } if len(data) != cnt { return fmt.Errorf("read count mismatch (%d should be %d)", cnt, len(data)) } if data[0] != command { return fmt.Errorf("answer (%d) was not for command (%d)", data[0], command) } return nil } func float32Of4BytesLittleEndian(bytes []byte) float32 { bits := binary.LittleEndian.Uint32(bytes) float := math.Float32frombits(bits) return float } ================================================ FILE: drivers/i2c/grovepi_driver_test.go ================================================ package i2c import ( "fmt" "strconv" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" "gobot.io/x/gobot/v2/drivers/gpio" ) // this ensures that the implementation is based on i2c.Driver, which implements the gobot.Driver // and tests all implementations, so no further tests needed here for gobot.Driver interface var _ gobot.Driver = (*GrovePiDriver)(nil) // must implement the DigitalReader interface var _ gpio.DigitalReader = (*GrovePiDriver)(nil) // must implement the DigitalWriter interface var _ gpio.DigitalWriter = (*GrovePiDriver)(nil) // must implement the AnalogReader interface var _ aio.AnalogReader = (*GrovePiDriver)(nil) // must implement the AnalogWriter interface var _ aio.AnalogWriter = (*GrovePiDriver)(nil) // must implement the Adaptor interface var _ gobot.Adaptor = (*GrovePiDriver)(nil) func initGrovePiDriverWithStubbedAdaptor() (*GrovePiDriver, *i2cTestAdaptor) { adaptor := newI2cTestAdaptor() return NewGrovePiDriver(adaptor), adaptor } func TestNewGrovePiDriver(t *testing.T) { var di interface{} = NewGrovePiDriver(newI2cTestAdaptor()) d, ok := di.(*GrovePiDriver) if !ok { require.Fail(t, "NewGrovePiDriver() should have returned a *GrovePiDriver") } assert.NotNil(t, d.Driver) assert.True(t, strings.HasPrefix(d.Name(), "GrovePi")) assert.Equal(t, 0x04, d.defaultAddress) assert.NotNil(t, d.pins) } func TestGrovePiOptions(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithBus() option and // least one of this driver. Further tests for options can also be done by call of "WithOption(val)(d)". d := NewGrovePiDriver(newI2cTestAdaptor(), WithBus(2)) assert.Equal(t, 2, d.GetBusOrDefault(1)) } func TestGrovePiSomeRead(t *testing.T) { // arrange tests := map[string]struct { usedPin int wantWritten []uint8 simResponse [][]uint8 wantErr error wantCallsRead int wantResult int wantResultF1 float32 wantResultF2 float32 wantResultString string }{ "DigitalRead": { usedPin: 2, wantWritten: []uint8{commandSetPinMode, 2, 0, 0, commandReadDigital, 2, 0, 0}, simResponse: [][]uint8{{0}, {commandReadDigital, 3}}, wantCallsRead: 2, wantResult: 3, }, "AnalogRead": { usedPin: 3, wantWritten: []uint8{commandSetPinMode, 3, 0, 0, commandReadAnalog, 3, 0, 0}, simResponse: [][]uint8{{0}, {commandReadAnalog, 4, 5}}, wantResult: 1029, }, "UltrasonicRead": { usedPin: 4, wantWritten: []uint8{commandSetPinMode, 4, 0, 0, commandReadUltrasonic, 4, 0, 0}, simResponse: [][]uint8{{0}, {commandReadUltrasonic, 5, 6}}, wantResult: 1281, }, "FirmwareVersionRead": { wantWritten: []uint8{commandReadFirmwareVersion, 0, 0, 0}, simResponse: [][]uint8{{commandReadFirmwareVersion, 7, 8, 9}}, wantResultString: "7.8.9", }, "DHTRead": { usedPin: 5, wantWritten: []uint8{commandSetPinMode, 5, 0, 0, commandReadDHT, 5, 1, 0}, simResponse: [][]uint8{{0}, {commandReadDHT, 164, 112, 69, 193, 20, 174, 54, 66}}, wantResultF1: -12.34, wantResultF2: 45.67, }, "DigitalRead_error_wrong_return_cmd": { usedPin: 15, wantWritten: []uint8{commandSetPinMode, 15, 0, 0, commandReadDigital, 15, 0, 0}, simResponse: [][]uint8{{0}, {0, 2}}, wantErr: fmt.Errorf("answer (0) was not for command (1)"), }, "AnalogRead_error_wrong_return_cmd": { usedPin: 16, wantWritten: []uint8{commandSetPinMode, 16, 0, 0, commandReadAnalog, 16, 0, 0}, simResponse: [][]uint8{{0}, {0, 3, 4}}, wantErr: fmt.Errorf("answer (0) was not for command (3)"), }, "UltrasonicRead_error_wrong_return_cmd": { usedPin: 17, wantWritten: []uint8{commandSetPinMode, 17, 0, 0, commandReadUltrasonic, 17, 0, 0}, simResponse: [][]uint8{{0}, {0, 5, 6}}, wantErr: fmt.Errorf("answer (0) was not for command (7)"), }, "FirmwareVersionRead_error_wrong_return_cmd": { wantWritten: []uint8{commandReadFirmwareVersion, 0, 0, 0}, simResponse: [][]uint8{{0, 7, 8, 9}}, wantErr: fmt.Errorf("answer (0) was not for command (8)"), }, "DHTRead_error_wrong_return_cmd": { usedPin: 18, wantWritten: []uint8{commandSetPinMode, 18, 0, 0, commandReadDHT, 18, 1, 0}, simResponse: [][]uint8{{0}, {0, 164, 112, 69, 193, 20, 174, 54, 66}}, wantErr: fmt.Errorf("answer (0) was not for command (40)"), }, "DigitalRead_error_wrong_data_count": { usedPin: 28, wantWritten: []uint8{commandSetPinMode, 28, 0, 0, commandReadDigital, 28, 0, 0}, simResponse: [][]uint8{{0}, {commandReadDigital, 2, 3}}, wantErr: fmt.Errorf("read count mismatch (3 should be 2)"), }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { g, a := initGrovePiDriverWithStubbedAdaptor() _ = g.Start() a.written = []byte{} // reset writes of former test and start numCallsRead := 0 a.i2cReadImpl = func(bytes []byte) (int, error) { numCallsRead++ copy(bytes, tc.simResponse[numCallsRead-1]) return len(tc.simResponse[numCallsRead-1]), nil } var got int var gotF1, gotF2 float32 var gotString string var err error // act switch { case strings.Contains(name, "DigitalRead"): got, err = g.DigitalRead(strconv.Itoa(tc.usedPin)) case strings.Contains(name, "AnalogRead"): got, err = g.AnalogRead(strconv.Itoa(tc.usedPin)) case strings.Contains(name, "UltrasonicRead"): got, err = g.UltrasonicRead(strconv.Itoa(tc.usedPin), 2) case strings.Contains(name, "FirmwareVersionRead"): gotString, err = g.FirmwareVersionRead() case strings.Contains(name, "DHTRead"): gotF1, gotF2, err = g.DHTRead(strconv.Itoa(tc.usedPin), 1, 2) default: require.Fail(t, "unknown command "+name) return } // assert assert.Equal(t, tc.wantErr, err) assert.Equal(t, tc.wantWritten, a.written) assert.Len(t, tc.simResponse, numCallsRead) assert.Equal(t, tc.wantResult, got) assert.InDelta(t, tc.wantResultF1, gotF1, 0.0) assert.InDelta(t, tc.wantResultF2, gotF2, 0.0) assert.Equal(t, tc.wantResultString, gotString) }) } } func TestGrovePiSomeWrite(t *testing.T) { // arrange tests := map[string]struct { usedPin int usedValue int wantWritten []uint8 simResponse []uint8 }{ "DigitalWrite": { usedPin: 2, usedValue: 3, wantWritten: []uint8{commandSetPinMode, 2, 1, 0, commandWriteDigital, 2, 3, 0}, simResponse: []uint8{4}, }, "AnalogWrite": { usedPin: 5, usedValue: 6, wantWritten: []uint8{commandSetPinMode, 5, 1, 0, commandWriteAnalog, 5, 6, 0}, simResponse: []uint8{7}, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { g, a := initGrovePiDriverWithStubbedAdaptor() _ = g.Start() a.written = []byte{} // reset writes of former test and start a.i2cReadImpl = func(bytes []byte) (int, error) { copy(bytes, tc.simResponse) return len(bytes), nil } var err error // act switch name { case "DigitalWrite": err = g.DigitalWrite(strconv.Itoa(tc.usedPin), byte(tc.usedValue)) case "AnalogWrite": err = g.AnalogWrite(strconv.Itoa(tc.usedPin), tc.usedValue) default: require.Fail(t, "unknown command "+name) return } // assert require.NoError(t, err) assert.Equal(t, tc.wantWritten, a.written) }) } } func TestGrovePi_getPin(t *testing.T) { assert.Equal(t, "1", getPin("a1")) assert.Equal(t, "16", getPin("A16")) assert.Equal(t, "3", getPin("D3")) assert.Equal(t, "22", getPin("d22")) assert.Equal(t, "22", getPin("22")) } ================================================ FILE: drivers/i2c/helpers_test.go ================================================ package i2c import ( "errors" "fmt" "sync" ) var rgb = map[string]interface{}{ "red": 1.0, "green": 1.0, "blue": 1.0, } type i2cTestAdaptor struct { name string bus int address int written []byte mtx sync.Mutex i2cConnectErr bool i2cReadImpl func([]byte) (int, error) i2cWriteImpl func([]byte) (int, error) } func (t *i2cTestAdaptor) Testi2cConnectErr(val bool) { t.mtx.Lock() defer t.mtx.Unlock() t.i2cConnectErr = val } func (t *i2cTestAdaptor) Testi2cReadImpl(f func([]byte) (int, error)) { t.mtx.Lock() defer t.mtx.Unlock() t.i2cReadImpl = f } func (t *i2cTestAdaptor) Testi2cWriteImpl(f func([]byte) (int, error)) { t.mtx.Lock() defer t.mtx.Unlock() t.i2cWriteImpl = f } func (t *i2cTestAdaptor) Read(b []byte) (int, error) { t.mtx.Lock() defer t.mtx.Unlock() return t.i2cReadImpl(b) } func (t *i2cTestAdaptor) Write(b []byte) (int, error) { t.mtx.Lock() defer t.mtx.Unlock() t.written = append(t.written, b...) return t.i2cWriteImpl(b) } func (t *i2cTestAdaptor) Close() error { return nil } func (t *i2cTestAdaptor) ReadByte() (byte, error) { t.mtx.Lock() defer t.mtx.Unlock() bytes := []byte{0} if err := t.readBytes(bytes); err != nil { return 0, err } val := bytes[0] return val, nil } func (t *i2cTestAdaptor) ReadByteData(reg uint8) (uint8, error) { t.mtx.Lock() defer t.mtx.Unlock() if err := t.writeBytes([]byte{reg}); err != nil { return 0, err } bytes := []byte{0} if err := t.readBytes(bytes); err != nil { return 0, err } val := bytes[0] return val, nil } func (t *i2cTestAdaptor) ReadWordData(reg uint8) (uint16, error) { t.mtx.Lock() defer t.mtx.Unlock() if err := t.writeBytes([]byte{reg}); err != nil { return 0, err } bytes := []byte{0, 0} bytesRead, err := t.i2cReadImpl(bytes) if err != nil { return 0, err } if bytesRead != 2 { return 0, fmt.Errorf("buffer underrun") } low, high := bytes[0], bytes[1] return (uint16(high) << 8) | uint16(low), nil } func (t *i2cTestAdaptor) ReadBlockData(reg uint8, b []byte) error { t.mtx.Lock() defer t.mtx.Unlock() if err := t.writeBytes([]byte{reg}); err != nil { return err } return t.readBytes(b) } func (t *i2cTestAdaptor) WriteByte(val byte) error { t.mtx.Lock() defer t.mtx.Unlock() return t.writeBytes([]byte{val}) } func (t *i2cTestAdaptor) WriteByteData(reg uint8, val uint8) error { t.mtx.Lock() defer t.mtx.Unlock() bytes := []byte{reg, val} return t.writeBytes(bytes) } func (t *i2cTestAdaptor) WriteWordData(reg uint8, val uint16) error { t.mtx.Lock() defer t.mtx.Unlock() low := uint8(val & 0xff) //nolint:gosec // ok here high := uint8((val >> 8) & 0xff) //nolint:gosec // ok here bytes := []byte{reg, low, high} return t.writeBytes(bytes) } func (t *i2cTestAdaptor) WriteBlockData(reg uint8, b []byte) error { t.mtx.Lock() defer t.mtx.Unlock() if len(b) > 32 { b = b[:32] } buf := make([]byte, len(b)+1) copy(buf[1:], b) buf[0] = reg return t.writeBytes(buf) } func (t *i2cTestAdaptor) WriteBytes(b []byte) error { t.mtx.Lock() defer t.mtx.Unlock() if len(b) > 32 { b = b[:32] } return t.writeBytes(b) } func (t *i2cTestAdaptor) GetI2cConnection(address int, bus int) (Connection, error) { if t.i2cConnectErr { return nil, errors.New("invalid i2c connection") } t.bus = bus t.address = address return t, nil } func (t *i2cTestAdaptor) DefaultI2cBus() int { return 0 } func (t *i2cTestAdaptor) Name() string { return t.name } func (t *i2cTestAdaptor) SetName(n string) { t.name = n } func (t *i2cTestAdaptor) Connect() error { return nil } func (t *i2cTestAdaptor) Finalize() error { return nil } func newI2cTestAdaptor() *i2cTestAdaptor { return &i2cTestAdaptor{ i2cConnectErr: false, i2cReadImpl: func(b []byte) (int, error) { return len(b), nil }, i2cWriteImpl: func(b []byte) (int, error) { return len(b), nil }, } } func (t *i2cTestAdaptor) readBytes(b []byte) error { n, err := t.i2cReadImpl(b) if err != nil { return err } if n != len(b) { return fmt.Errorf("read %v bytes from device by i2c helpers, expected %v", n, len(b)) } return nil } func (t *i2cTestAdaptor) writeBytes(b []byte) error { t.written = append(t.written, b...) // evaluation of count can be done in test _, err := t.i2cWriteImpl(b) if err != nil { return err } return nil } ================================================ FILE: drivers/i2c/hmc5883l_driver.go ================================================ package i2c import ( "fmt" "log" "math" "sort" ) const ( hmc5883lDebug = false hmc5883lDefaultAddress = 0x1E // default I2C Address ) const ( hmc5883lRegA = 0x00 // Address of Configuration register A hmc5883lRegB = 0x01 // Address of Configuration register B hmc5883lRegMode = 0x02 // Address of node register hmc5883lAxisX = 0x03 // Address of X-axis MSB data register hmc5883lAxisZ = 0x05 // Address of Z-axis MSB data register hmc5883lAxisY = 0x07 // Address of Y-axis MSB data register hmc5883lRegStatus = 0x09 // Address of status register hmc5883lRegIdA = 0x0A // Address of identification register A hmc5883lRegIdB = 0x0B // Address of identification register B hmc5883lRegIdC = 0x0C // Address of identification register C hmc5883lRegA_SamplesAvg1 = 0x00 // no samples averaged hmc5883lRegA_SamplesAvg2 = 0x01 // 2 samples averaged hmc5883lRegA_SamplesAvg4 = 0x02 // 4 samples averaged hmc5883lRegA_SamplesAvg8 = 0x03 // 8 samples averaged hmc5883lRegA_OutputRate750 = 0x00 // data output rate 0.75 Hz hmc5883lRegA_OutputRate1500 = 0x01 // data output rate 1.5 Hz hmc5883lRegA_OutputRate3000 = 0x02 // data output rate 3.0 Hz hmc5883lRegA_OutputRate7500 = 0x03 // data output rate 7.5 Hz hmc5883lRegA_OutputRate15000 = 0x04 // data output rate 15.0 Hz hmc5883lRegA_OutputRate30000 = 0x05 // data output rate 30.0 Hz hmc5883lRegA_OutputRate75000 = 0x06 // data output rate 75.0 Hz hmc5883lRegA_MeasNormal = 0x00 // normal measurement configuration hmc5883lRegA_MeasPositiveBias = 0x01 // positive bias for X, Y, Z hmc5883lRegA_MeasNegativeBias = 0x02 // negative bias for X, Y, Z hmc5883lRegB_Gain1370 = 0x00 // gain is 1370 Gauss hmc5883lRegB_Gain1090 = 0x01 // gain is 1090 Gauss hmc5883lRegB_Gain820 = 0x02 // gain is 820 Gauss hmc5883lRegB_Gain660 = 0x03 // gain is 660 Gauss hmc5883lRegB_Gain440 = 0x04 // gain is 440 Gauss hmc5883lRegB_Gain390 = 0x05 // gain is 390 Gauss hmc5883lRegB_Gain330 = 0x06 // gain is 330 Gauss hmc5883lRegB_Gain230 = 0x07 // gain is 230 Gauss hmc5883lRegM_Continuous = 0x00 // continuous measurement mode hmc5883lRegM_Single = 0x01 // return to idle after a single measurement hmc5883lRegM_Idle = 0x10 // idle mode ) // HMC5883LDriver is a Gobot Driver for a HMC5883 I2C 3 axis digital compass. // // This driver was tested with Tinkerboard & Digispark adaptor and a HMC5883L breakout board GY-273, // available from various distributors. // // datasheet: // http://www.adafruit.com/datasheets/HMC5883L_3-Axis_Digital_Compass_IC.pdf // // reference implementations: // * https://github.com/gvalkov/micropython-esp8266-hmc5883l // * https://github.com/adafruit/Adafruit_HMC5883_Unified type HMC5883LDriver struct { *Driver samplesAvg uint8 outputRate uint32 // in mHz applyBias int8 measurementMode int gain float64 // in 1/Gauss } var hmc5883lSamplesAvgBits = map[uint8]int{ 1: hmc5883lRegA_SamplesAvg1, 2: hmc5883lRegA_SamplesAvg2, 4: hmc5883lRegA_SamplesAvg4, 8: hmc5883lRegA_SamplesAvg8, } var hmc5883lOutputRateBits = map[uint32]int{ 750: hmc5883lRegA_OutputRate750, 1500: hmc5883lRegA_OutputRate1500, 3000: hmc5883lRegA_OutputRate3000, 7500: hmc5883lRegA_OutputRate7500, 15000: hmc5883lRegA_OutputRate15000, 30000: hmc5883lRegA_OutputRate30000, 75000: hmc5883lRegA_OutputRate75000, } var hmc5883lMeasurementFlowBits = map[int8]int{ 0: hmc5883lRegA_MeasNormal, 1: hmc5883lRegA_MeasPositiveBias, -1: hmc5883lRegA_MeasNegativeBias, } var hmc5883lGainBits = map[float64]int{ 1370.0: hmc5883lRegB_Gain1370, 1090.0: hmc5883lRegB_Gain1090, 820.0: hmc5883lRegB_Gain820, 660.0: hmc5883lRegB_Gain660, 440.0: hmc5883lRegB_Gain440, 390.0: hmc5883lRegB_Gain390, 330.0: hmc5883lRegB_Gain330, 230.0: hmc5883lRegB_Gain230, } // NewHMC5883LDriver creates a new driver with specified i2c interface // Params: // // c Connector - the Adaptor to use with this Driver // // Optional params: // // i2c.WithBus(int): bus to use with this driver // i2c.WithAddress(int): address to use with this driver // i2c.WithHMC5883LSamplesAveraged(int) // i2c.WithHMC5883LDataOutputRate(int) // i2c.WithHMC5883LMeasurementFlow(int) // i2c.WithHMC5883LGain(int) func NewHMC5883LDriver(c Connector, options ...func(Config)) *HMC5883LDriver { d := &HMC5883LDriver{ Driver: NewDriver(c, "HMC5883L", hmc5883lDefaultAddress), samplesAvg: 8, outputRate: 15000, applyBias: 0, measurementMode: hmc5883lRegM_Continuous, gain: 390, } d.afterStart = d.initialize for _, option := range options { option(d) } return d } // WithHMC5883LSamplesAveraged option sets the number of samples averaged per measurement. // Valid settings are 1, 2, 4, 8. func WithHMC5883LSamplesAveraged(val int) func(Config) { return func(c Config) { d, ok := c.(*HMC5883LDriver) if ok { if err := hmc5883lValidateSamplesAveraged(val); err != nil { panic(err) } d.samplesAvg = uint8(val) //nolint:gosec // TODO: fix later } else if hmc5883lDebug { log.Printf("Trying to set samples averaged for non-HMC5883LDriver %v", c) } } } // WithHMC5883LDataOutputRate option sets the data output rate in mHz. // Valid settings are 750, 1500, 3000, 7500, 15000, 30000, 75000. func WithHMC5883LDataOutputRate(val int) func(Config) { return func(c Config) { d, ok := c.(*HMC5883LDriver) if ok { if err := hmc5883lValidateOutputRate(val); err != nil { panic(err) } d.outputRate = uint32(val) //nolint:gosec // TODO: fix later } else if hmc5883lDebug { log.Printf("Trying to set data output rate for non-HMC5883LDriver %v", c) } } } // WithHMC5883LApplyBias option sets to apply a measurement bias. // Valid settings are -1 (negative bias), 0 (normal), 1 (positive bias). func WithHMC5883LApplyBias(val int) func(Config) { return func(c Config) { d, ok := c.(*HMC5883LDriver) if ok { if err := hmc5883lValidateApplyBias(val); err != nil { panic(err) } d.applyBias = int8(val) //nolint:gosec // TODO: fix later } else if hmc5883lDebug { log.Printf("Trying to set measurement flow for non-HMC5883LDriver %v", c) } } } // WithHMC5883LGain option sets the gain. // Valid settings are 1370, 1090, 820, 660, 440, 390, 330 230 in 1/Gauss. func WithHMC5883LGain(val int) func(Config) { return func(c Config) { d, ok := c.(*HMC5883LDriver) if ok { if err := hmc5883lValidateGain(val); err != nil { panic(err) } d.gain = float64(val) } else if hmc5883lDebug { log.Printf("Trying to set gain for non-HMC5883LDriver %v", c) } } } // Read reads the values X, Y, Z in Gauss // //nolint:nonamedreturns // is sufficient here func (d *HMC5883LDriver) Read() (x float64, y float64, z float64, err error) { d.mutex.Lock() defer d.mutex.Unlock() xr, yr, zr, err := d.readRawData() if err != nil { return } return float64(xr) / d.gain, float64(yr) / d.gain, float64(zr) / d.gain, nil } // Heading returns the current heading in radians func (d *HMC5883LDriver) Heading() (float64, error) { d.mutex.Lock() defer d.mutex.Unlock() x, y, _, err := d.readRawData() if err != nil { return 0, err } heading := math.Atan2(float64(y), float64(x)) if heading > 2*math.Pi { heading -= 2 * math.Pi } if heading < 0 { heading += 2 * math.Pi } return heading, nil } // readRawData reads the raw values from the X, Y, and Z registers // //nolint:nonamedreturns // sufficient here func (d *HMC5883LDriver) readRawData() (x int16, y int16, z int16, err error) { // read the data, starting from the initial register data := make([]byte, 6) if err = d.readBlockData(hmc5883lAxisX, data); err != nil { return } unsignedX := (uint16(data[0]) << 8) | uint16(data[1]) unsignedZ := (uint16(data[2]) << 8) | uint16(data[3]) unsignedY := (uint16(data[4]) << 8) | uint16(data[5]) return twosComplement16Bit(unsignedX), twosComplement16Bit(unsignedY), twosComplement16Bit(unsignedZ), nil } func (d *HMC5883LDriver) initialize() error { regA := hmc5883lMeasurementFlowBits[d.applyBias] regA |= hmc5883lOutputRateBits[d.outputRate] << 2 regA |= hmc5883lSamplesAvgBits[d.samplesAvg] << 5 //nolint:gosec // TODO: fix later if err := d.writeByteData(hmc5883lRegA, uint8(regA)); err != nil { return err } regB := hmc5883lGainBits[d.gain] << 5 //nolint:gosec // TODO: fix later if err := d.writeByteData(hmc5883lRegB, uint8(regB)); err != nil { return err } //nolint:gosec // TODO: fix later return d.writeByteData(hmc5883lRegMode, uint8(d.measurementMode)) } func hmc5883lValidateSamplesAveraged(samplesAvg int) error { //nolint:gosec // TODO: fix later if _, ok := hmc5883lSamplesAvgBits[uint8(samplesAvg)]; ok { return nil } keys := []int{} for k := range hmc5883lSamplesAvgBits { keys = append(keys, int(k)) } sort.Ints(keys) return fmt.Errorf("samples averaged must be one of: %d", keys) } func hmc5883lValidateOutputRate(outputRate int) error { //nolint:gosec // TODO: fix later if _, ok := hmc5883lOutputRateBits[uint32(outputRate)]; ok { return nil } keys := []int{} for k := range hmc5883lOutputRateBits { keys = append(keys, int(k)) } sort.Ints(keys) return fmt.Errorf("data output rate must be one of: %d", keys) } func hmc5883lValidateApplyBias(applyBias int) error { //nolint:gosec // TODO: fix later if _, ok := hmc5883lMeasurementFlowBits[int8(applyBias)]; ok { return nil } keys := []int{} for k := range hmc5883lMeasurementFlowBits { keys = append(keys, int(k)) } sort.Ints(keys) return fmt.Errorf("apply measurement bias must be one of: %d", keys) } func hmc5883lValidateGain(gain int) error { if _, ok := hmc5883lGainBits[float64(gain)]; ok { return nil } keys := []int{} for k := range hmc5883lGainBits { keys = append(keys, int(k)) } sort.Ints(keys) return fmt.Errorf("gain must be one of: %d", keys) } ================================================ FILE: drivers/i2c/hmc5883l_driver_test.go ================================================ package i2c import ( "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) // this ensures that the implementation is based on i2c.Driver, which implements the gobot.Driver // and tests all implementations, so no further tests needed here for gobot.Driver interface var _ gobot.Driver = (*HMC5883LDriver)(nil) func initTestHMC5883LWithStubbedAdaptor() (*HMC5883LDriver, *i2cTestAdaptor) { a := newI2cTestAdaptor() return NewHMC5883LDriver(a), a } func TestNewHMC5883LDriver(t *testing.T) { var di interface{} = NewHMC5883LDriver(newI2cTestAdaptor()) d, ok := di.(*HMC5883LDriver) if !ok { require.Fail(t, "NewHMC5883LDriver() should have returned a *HMC5883LDriver") } assert.NotNil(t, d.Driver) assert.True(t, strings.HasPrefix(d.name, "HMC5883L")) assert.Equal(t, 0x1E, d.defaultAddress) assert.Equal(t, uint8(8), d.samplesAvg) assert.Equal(t, uint32(15000), d.outputRate) assert.Equal(t, int8(0), d.applyBias) assert.Equal(t, 0, d.measurementMode) assert.InDelta(t, 390.0, d.gain, 0.0) } func TestHMC5883LHalt(t *testing.T) { // arrange d := NewHMC5883LDriver(newI2cTestAdaptor()) // act, assert require.NoError(t, d.Halt()) // must be idempotent require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestHMC5883LOptions(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithBus() option and // least one of this driver. Further tests for options can also be done by call of "WithOption(val)(d)". d := NewHMC5883LDriver(newI2cTestAdaptor(), WithBus(2), WithHMC5883LSamplesAveraged(4)) assert.Equal(t, 2, d.GetBusOrDefault(1)) assert.Equal(t, uint8(4), d.samplesAvg) } func TestHMC5883LWithHMC5883LDataOutputRate(t *testing.T) { d := NewHMC5883LDriver(newI2cTestAdaptor()) WithHMC5883LDataOutputRate(7500)(d) assert.Equal(t, uint32(7500), d.outputRate) } func TestHMC5883LWithHMC5883LApplyBias(t *testing.T) { d := NewHMC5883LDriver(newI2cTestAdaptor()) WithHMC5883LApplyBias(-1)(d) assert.Equal(t, int8(-1), d.applyBias) } func TestHMC5883LWithHMC5883LGain(t *testing.T) { d := NewHMC5883LDriver(newI2cTestAdaptor()) WithHMC5883LGain(230)(d) assert.InDelta(t, 230.0, d.gain, 0.0) } func TestHMC5883LRead(t *testing.T) { // arrange tests := map[string]struct { inputX []uint8 inputY []uint8 inputZ []uint8 gain float64 wantX float64 wantY float64 wantZ float64 }{ "+FS_0_-FS_resolution_0.73mG": { inputX: []uint8{0x07, 0xFF}, inputY: []uint8{0x00, 0x00}, inputZ: []uint8{0xF8, 0x00}, gain: 1370, wantX: 2047.0 / 1370, wantY: 0, wantZ: -2048.0 / 1370, }, "+1_-4096_-1_resolution_0.73mG": { inputX: []uint8{0x00, 0x01}, inputY: []uint8{0xF0, 0x00}, inputZ: []uint8{0xFF, 0xFF}, gain: 1370, wantX: 1.0 / 1370, wantY: -4096.0 / 1370, wantZ: -1.0 / 1370, }, "+FS_0_-FS_resolution_4.35mG": { inputX: []uint8{0x07, 0xFF}, inputY: []uint8{0x00, 0x00}, inputZ: []uint8{0xF8, 0x00}, gain: 230, wantX: 2047.0 / 230, wantY: 0, wantZ: -2048.0 / 230, }, "-1_+1_-4096_resolution_4.35mG": { inputX: []uint8{0xFF, 0xFF}, inputY: []uint8{0x00, 0x01}, inputZ: []uint8{0xF0, 0x00}, gain: 230, wantX: -1.0 / 230, wantY: 1.0 / 230, wantZ: -4096.0 / 230, }, } a := newI2cTestAdaptor() for name, tc := range tests { t.Run(name, func(t *testing.T) { d := NewHMC5883LDriver(a, WithHMC5883LGain(int(tc.gain))) _ = d.Start() // arrange reads returnRead := append(append(tc.inputX, tc.inputZ...), tc.inputY...) a.i2cReadImpl = func(b []byte) (int, error) { copy(b, returnRead) return len(b), nil } // act gotX, gotY, gotZ, err := d.Read() // assert require.NoError(t, err) assert.InDelta(t, tc.wantX, gotX, 0.0) assert.InDelta(t, tc.wantY, gotY, 0.0) assert.InDelta(t, tc.wantZ, gotZ, 0.0) }) } } func TestHMC5883L_readRawData(t *testing.T) { // sequence to read: // * prepare read, see test of Start() // * read data output registers (3 x 16 bit, MSByte first) // * apply two's complement converter // // arrange tests := map[string]struct { inputX []uint8 inputY []uint8 inputZ []uint8 wantX int16 wantY int16 wantZ int16 }{ "+FS_0_-FS": { inputX: []uint8{0x07, 0xFF}, inputY: []uint8{0x00, 0x00}, inputZ: []uint8{0xF8, 0x00}, wantX: (1<<11 - 1), wantY: 0, wantZ: -(1 << 11), }, "-4096_-1_+1": { inputX: []uint8{0xF0, 0x00}, inputY: []uint8{0xFF, 0xFF}, inputZ: []uint8{0x00, 0x01}, wantX: -4096, wantY: -1, wantZ: 1, }, } d, a := initTestHMC5883LWithStubbedAdaptor() _ = d.Start() for name, tc := range tests { t.Run(name, func(t *testing.T) { a.written = []byte{} // reset writes of former test and start // arrange reads returnRead := append(append(tc.inputX, tc.inputZ...), tc.inputY...) numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ copy(b, returnRead) return len(b), nil } // act gotX, gotY, gotZ, err := d.readRawData() // assert require.NoError(t, err) assert.Equal(t, tc.wantX, gotX) assert.Equal(t, tc.wantY, gotY) assert.Equal(t, tc.wantZ, gotZ) assert.Equal(t, 1, numCallsRead) assert.Len(t, a.written, 1) assert.Equal(t, uint8(hmc5883lAxisX), a.written[0]) }) } } func TestHMC5883L_initialize(t *testing.T) { // sequence to prepare read in Start(): // * prepare config register A content (samples averaged, data output rate, measurement mode) // * prepare config register B content (gain) // * prepare mode register (continuous/single/idle) // * write registers A, B, mode // arrange d, a := initTestHMC5883LWithStubbedAdaptor() a.written = []byte{} // reset writes of former test wantRegA := uint8(0x70) wantRegB := uint8(0xA0) wantRegM := uint8(0x00) // act, assert - initialize() must be called on Start() err := d.Start() // assert require.NoError(t, err) assert.Len(t, a.written, 6) assert.Equal(t, uint8(hmc5883lRegA), a.written[0]) assert.Equal(t, wantRegA, a.written[1]) assert.Equal(t, uint8(hmc5883lRegB), a.written[2]) assert.Equal(t, wantRegB, a.written[3]) assert.Equal(t, uint8(hmc5883lRegMode), a.written[4]) assert.Equal(t, wantRegM, a.written[5]) } ================================================ FILE: drivers/i2c/hmc6352_driver.go ================================================ package i2c const hmc6352DefaultAddress = 0x21 // HMC6352Driver is a Driver for a HMC6352 digital compass type HMC6352Driver struct { *Driver } // NewHMC6352Driver creates a new driver with specified i2c interface // Params: // // c Connector - the Adaptor to use with this Driver // // Optional params: // // i2c.WithBus(int): bus to use with this driver // i2c.WithAddress(int): address to use with this driver func NewHMC6352Driver(c Connector, options ...func(Config)) *HMC6352Driver { d := &HMC6352Driver{ Driver: NewDriver(c, "HMC6352", hmc6352DefaultAddress), } d.afterStart = d.initialize for _, option := range options { option(d) } return d } // Heading returns the current heading func (d *HMC6352Driver) Heading() (uint16, error) { if _, err := d.write([]byte("A")); err != nil { return 0, err } buf := []byte{0, 0} bytesRead, err := d.read(buf) if err != nil { return 0, err } if bytesRead == 2 { heading := (uint16(buf[1]) + uint16(buf[0])*256) / 10 return heading, nil } return 0, ErrNotEnoughBytes } func (d *HMC6352Driver) initialize() error { if _, err := d.write([]byte("A")); err != nil { return err } return nil } ================================================ FILE: drivers/i2c/hmc6352_driver_test.go ================================================ package i2c import ( "errors" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) // this ensures that the implementation is based on i2c.Driver, which implements the gobot.Driver // and tests all implementations, so no further tests needed here for gobot.Driver interface var _ gobot.Driver = (*HMC6352Driver)(nil) func initTestHMC6352DriverWithStubbedAdaptor() (*HMC6352Driver, *i2cTestAdaptor) { a := newI2cTestAdaptor() d := NewHMC6352Driver(a) if err := d.Start(); err != nil { panic(err) } return d, a } func TestNewHMC6352Driver(t *testing.T) { var di interface{} = NewHMC6352Driver(newI2cTestAdaptor()) d, ok := di.(*HMC6352Driver) if !ok { require.Fail(t, "NewHMC6352Driver() should have returned a *HMC6352Driver") } assert.NotNil(t, d.Driver) assert.True(t, strings.HasPrefix(d.Name(), "HMC6352")) assert.Equal(t, 0x21, d.defaultAddress) } func TestHMC6352Options(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithBus() option and // least one of this driver. Further tests for options can also be done by call of "WithOption(val)(d)". d := NewHMC6352Driver(newI2cTestAdaptor(), WithBus(2)) assert.Equal(t, 2, d.GetBusOrDefault(1)) } func TestHMC6352Start(t *testing.T) { d := NewHMC6352Driver(newI2cTestAdaptor()) require.NoError(t, d.Start()) } func TestHMC6352Halt(t *testing.T) { // arrange d := NewHMC6352Driver(newI2cTestAdaptor()) // act, assert require.NoError(t, d.Halt()) // must be idempotent require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestHMC6352Heading(t *testing.T) { // when len(data) is 2 d, a := initTestHMC6352DriverWithStubbedAdaptor() a.i2cReadImpl = func(b []byte) (int, error) { copy(b, []byte{99, 1}) return 2, nil } heading, _ := d.Heading() assert.Equal(t, uint16(2534), heading) // when len(data) is not 2 d, a = initTestHMC6352DriverWithStubbedAdaptor() a.i2cReadImpl = func(b []byte) (int, error) { copy(b, []byte{99}) return 1, nil } heading, err := d.Heading() assert.Equal(t, uint16(0), heading) assert.Equal(t, ErrNotEnoughBytes, err) // when read error d, a = initTestHMC6352DriverWithStubbedAdaptor() a.i2cReadImpl = func([]byte) (int, error) { return 0, errors.New("read error") } heading, err = d.Heading() assert.Equal(t, uint16(0), heading) require.ErrorContains(t, err, "read error") // when write error d, a = initTestHMC6352DriverWithStubbedAdaptor() a.i2cWriteImpl = func([]byte) (int, error) { return 0, errors.New("write error") } heading, err = d.Heading() assert.Equal(t, uint16(0), heading) require.ErrorContains(t, err, "write error") } ================================================ FILE: drivers/i2c/i2c_config.go ================================================ package i2c type i2cConfig struct { bus int address int } // NewConfig returns a new I2c Config. func NewConfig() Config { return &i2cConfig{bus: BusNotInitialized, address: AddressNotInitialized} } // WithBus sets which bus to use as a optional param. func WithBus(bus int) func(Config) { return func(i Config) { i.SetBus(bus) } } // WithAddress sets which address to use as a optional param. func WithAddress(address int) func(Config) { return func(i Config) { i.SetAddress(address) } } // SetBus sets preferred bus to use. func (i *i2cConfig) SetBus(bus int) { i.bus = bus } // GetBusOrDefault returns which bus to use, either the one set using WithBus(), // or the default value which is passed in as the one param. func (i *i2cConfig) GetBusOrDefault(d int) int { if i.bus == BusNotInitialized { return d } return i.bus } // SetAddress sets which address to use. func (i *i2cConfig) SetAddress(address int) { i.address = address } // GetAddressOrDefault returns which address to use, either // the one set using WithBus(), or the default value which // is passed in as the param. func (i *i2cConfig) GetAddressOrDefault(a int) int { if i.address == AddressNotInitialized { return a } return i.address } ================================================ FILE: drivers/i2c/i2c_config_test.go ================================================ //nolint:forcetypeassert // ok here package i2c import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestNewConfig(t *testing.T) { // arrange, act ci := NewConfig() // assert c, ok := ci.(*i2cConfig) if !ok { require.Fail(t, "NewConfig() should have returned a *i2cConfig") } assert.Equal(t, BusNotInitialized, c.bus) assert.Equal(t, AddressNotInitialized, c.address) } func TestWithBus(t *testing.T) { // arrange c := NewConfig() // act c.SetBus(0x23) // assert assert.Equal(t, 0x23, c.(*i2cConfig).bus) } func TestWithAddress(t *testing.T) { // arrange c := NewConfig() // act c.SetAddress(0x24) // assert assert.Equal(t, 0x24, c.(*i2cConfig).address) } func TestGetBusOrDefaultWithBusOption(t *testing.T) { tests := map[string]struct { init int bus int want int }{ "not_initialized": {init: -1, bus: 0x25, want: 0x25}, "initialized": {init: 0x26, bus: 0x27, want: 0x26}, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange c := NewConfig() // act WithBus(tc.init)(c) got := c.GetBusOrDefault(tc.bus) // assert assert.Equal(t, tc.want, got) }) } } func TestGetAddressOrDefaultWithAddressOption(t *testing.T) { tests := map[string]struct { init int address int want int }{ "not_initialized": {init: -1, address: 0x28, want: 0x28}, "initialized": {init: 0x29, address: 0x2A, want: 0x29}, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange c := NewConfig() // act WithAddress(tc.init)(c) got := c.GetAddressOrDefault(tc.address) // assert assert.Equal(t, tc.want, got) }) } } ================================================ FILE: drivers/i2c/i2c_connection.go ================================================ package i2c import ( "fmt" "gobot.io/x/gobot/v2" ) const ( // Error event Error = "error" ) const ( // BusNotInitialized is the initial value for a bus BusNotInitialized = -1 // AddressNotInitialized is the initial value for an address AddressNotInitialized = -1 ) var ( // ErrNotEnoughBytes is used when the count of read bytes was too small ErrNotEnoughBytes = fmt.Errorf("not enough bytes read") // ErrNotReady is used when the device is not ready ErrNotReady = fmt.Errorf("device is not ready") ) type bitState uint8 const ( clearBit bitState = 0x00 setBit bitState = 0x01 ) // Connection is a connection to an I2C device with a specified address // on a specific bus. Used as an alternative to the I2c interface. // Implements I2cOperations to talk to the device, wrapping the // calls in SetAddress to always target the specified device. // Provided by an Adaptor by implementing the I2cConnector interface. type Connection gobot.I2cOperations type i2cConnection struct { bus gobot.I2cSystemDevicer address int } // NewConnection creates and returns a new connection to a specific i2c device on a bus and address. func NewConnection(bus gobot.I2cSystemDevicer, address int) *i2cConnection { return &i2cConnection{bus: bus, address: address} } // Read data from an i2c device. func (c *i2cConnection) Read(data []byte) (int, error) { return c.bus.Read(c.address, data) } // Write data to an i2c device. func (c *i2cConnection) Write(data []byte) (int, error) { return c.bus.Write(c.address, data) } // Close connection to i2c device. The bus was created by adaptor and will be closed there. func (c *i2cConnection) Close() error { return nil } // ReadByte reads a single byte from the i2c device. func (c *i2cConnection) ReadByte() (byte, error) { return c.bus.ReadByte(c.address) } // ReadByteData reads a byte value for a register on the i2c device. func (c *i2cConnection) ReadByteData(reg uint8) (uint8, error) { return c.bus.ReadByteData(c.address, reg) } // ReadWordData reads a word value for a register on the i2c device. func (c *i2cConnection) ReadWordData(reg uint8) (uint16, error) { return c.bus.ReadWordData(c.address, reg) } // ReadBlockData reads a block of bytes from a register on the i2c device. func (c *i2cConnection) ReadBlockData(reg uint8, b []byte) error { return c.bus.ReadBlockData(c.address, reg, b) } // WriteByte writes a single byte to the i2c device. func (c *i2cConnection) WriteByte(val byte) error { return c.bus.WriteByte(c.address, val) } // WriteByteData writes a byte value to a register on the i2c device. func (c *i2cConnection) WriteByteData(reg uint8, val uint8) error { return c.bus.WriteByteData(c.address, reg, val) } // WriteWordData writes a word value to a register on the i2c device. func (c *i2cConnection) WriteWordData(reg uint8, val uint16) error { return c.bus.WriteWordData(c.address, reg, val) } // WriteBlockData writes a block of bytes to a register on the i2c device. func (c *i2cConnection) WriteBlockData(reg uint8, b []byte) error { return c.bus.WriteBlockData(c.address, reg, b) } // WriteBytes writes a block of bytes to the current register on the i2c device. func (c *i2cConnection) WriteBytes(b []byte) error { return c.bus.WriteBytes(c.address, b) } func twosComplement16Bit(uValue uint16) int16 { result := int32(uValue) if result&0x8000 != 0 { result -= 1 << 16 } return int16(result) //nolint:gosec // ok here } func swapBytes(value uint16) uint16 { return (value << 8) | (value >> 8) } ================================================ FILE: drivers/i2c/i2c_connection_test.go ================================================ //go:build !windows // +build !windows package i2c import ( "testing" "unsafe" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/system" ) const dev = "/dev/i2c-1" func getSyscallFuncImpl( errorMask byte, ) func(trap, a1, a2 uintptr, a3 unsafe.Pointer) (r1, r2 uintptr, err system.SyscallErrno) { // bit 0: error on function query // bit 1: error on set address // bit 2: error on command //nolint:nonamedreturns // is sufficient here return func(trap, a1, a2 uintptr, a3 unsafe.Pointer) (r1, r2 uintptr, err system.SyscallErrno) { // function query if (trap == system.Syscall_SYS_IOCTL) && (a2 == system.I2C_FUNCS) { if errorMask&0x01 == 0x01 { return 0, 0, 1 } funcPtr := (*uint64)(a3) *funcPtr = system.I2C_FUNC_SMBUS_READ_BYTE | system.I2C_FUNC_SMBUS_READ_BYTE_DATA | system.I2C_FUNC_SMBUS_READ_WORD_DATA | system.I2C_FUNC_SMBUS_WRITE_BYTE | system.I2C_FUNC_SMBUS_WRITE_BYTE_DATA | system.I2C_FUNC_SMBUS_WRITE_WORD_DATA } // set address if (trap == system.Syscall_SYS_IOCTL) && (a2 == system.I2C_TARGET) { if errorMask&0x02 == 0x02 { return 0, 0, 1 } } // command if (trap == system.Syscall_SYS_IOCTL) && (a2 == system.I2C_SMBUS) { if errorMask&0x04 == 0x04 { return 0, 0, 1 } } // Let all operations succeed return 0, 0, 0 } } func initI2CDevice() gobot.I2cSystemDevicer { a := system.NewAccesser() a.UseMockFilesystem([]string{dev}) msc := a.UseMockSyscall() msc.Impl = getSyscallFuncImpl(0x00) d, _ := a.NewI2cDevice(dev) return d } func initI2CDeviceAddressError() gobot.I2cSystemDevicer { a := system.NewAccesser() a.UseMockFilesystem([]string{dev}) msc := a.UseMockSyscall() msc.Impl = getSyscallFuncImpl(0x02) d, _ := a.NewI2cDevice(dev) return d } func TestI2CAddress(t *testing.T) { c := NewConnection(initI2CDevice(), 0x66) assert.Equal(t, 0x66, c.address) } func TestI2CClose(t *testing.T) { c := NewConnection(initI2CDevice(), 0x06) require.NoError(t, c.Close()) } func TestI2CRead(t *testing.T) { c := NewConnection(initI2CDevice(), 0x06) i, _ := c.Read([]byte{}) assert.Equal(t, 0, i) } func TestI2CReadAddressError(t *testing.T) { c := NewConnection(initI2CDeviceAddressError(), 0x06) _, err := c.Read([]byte{}) require.ErrorContains(t, err, "Setting address failed with syscall.Errno operation not permitted") } func TestI2CWrite(t *testing.T) { c := NewConnection(initI2CDevice(), 0x06) i, _ := c.Write([]byte{0x01}) assert.Equal(t, 1, i) } func TestI2CWriteAddressError(t *testing.T) { c := NewConnection(initI2CDeviceAddressError(), 0x06) _, err := c.Write([]byte{0x01}) require.ErrorContains(t, err, "Setting address failed with syscall.Errno operation not permitted") } func TestI2CReadByte(t *testing.T) { c := NewConnection(initI2CDevice(), 0x06) v, _ := c.ReadByte() assert.Equal(t, uint8(0xFC), v) } func TestI2CReadByteAddressError(t *testing.T) { c := NewConnection(initI2CDeviceAddressError(), 0x06) _, err := c.ReadByte() require.ErrorContains(t, err, "Setting address failed with syscall.Errno operation not permitted") } func TestI2CReadByteData(t *testing.T) { c := NewConnection(initI2CDevice(), 0x06) v, _ := c.ReadByteData(0x01) assert.Equal(t, uint8(0xFD), v) } func TestI2CReadByteDataAddressError(t *testing.T) { c := NewConnection(initI2CDeviceAddressError(), 0x06) _, err := c.ReadByteData(0x01) require.ErrorContains(t, err, "Setting address failed with syscall.Errno operation not permitted") } func TestI2CReadWordData(t *testing.T) { c := NewConnection(initI2CDevice(), 0x06) v, _ := c.ReadWordData(0x01) assert.Equal(t, uint16(0xFFFE), v) } func TestI2CReadWordDataAddressError(t *testing.T) { c := NewConnection(initI2CDeviceAddressError(), 0x06) _, err := c.ReadWordData(0x01) require.ErrorContains(t, err, "Setting address failed with syscall.Errno operation not permitted") } func TestI2CWriteByte(t *testing.T) { c := NewConnection(initI2CDevice(), 0x06) err := c.WriteByte(0x01) require.NoError(t, err) } func TestI2CWriteByteAddressError(t *testing.T) { c := NewConnection(initI2CDeviceAddressError(), 0x06) err := c.WriteByte(0x01) require.ErrorContains(t, err, "Setting address failed with syscall.Errno operation not permitted") } func TestI2CWriteByteData(t *testing.T) { c := NewConnection(initI2CDevice(), 0x06) err := c.WriteByteData(0x01, 0x01) require.NoError(t, err) } func TestI2CWriteByteDataAddressError(t *testing.T) { c := NewConnection(initI2CDeviceAddressError(), 0x06) err := c.WriteByteData(0x01, 0x01) require.ErrorContains(t, err, "Setting address failed with syscall.Errno operation not permitted") } func TestI2CWriteWordData(t *testing.T) { c := NewConnection(initI2CDevice(), 0x06) err := c.WriteWordData(0x01, 0x01) require.NoError(t, err) } func TestI2CWriteWordDataAddressError(t *testing.T) { c := NewConnection(initI2CDeviceAddressError(), 0x06) err := c.WriteWordData(0x01, 0x01) require.ErrorContains(t, err, "Setting address failed with syscall.Errno operation not permitted") } func TestI2CWriteBlockData(t *testing.T) { c := NewConnection(initI2CDevice(), 0x06) err := c.WriteBlockData(0x01, []byte{0x01, 0x02}) require.NoError(t, err) } func TestI2CWriteBlockDataAddressError(t *testing.T) { c := NewConnection(initI2CDeviceAddressError(), 0x06) err := c.WriteBlockData(0x01, []byte{0x01, 0x02}) require.ErrorContains(t, err, "Setting address failed with syscall.Errno operation not permitted") } ================================================ FILE: drivers/i2c/i2c_driver.go ================================================ package i2c import ( "encoding/binary" "fmt" "log" "strconv" "sync" "gobot.io/x/gobot/v2" ) // Config is the interface to set and get I2C device related parameters. type Config interface { // SetBus sets which bus to use SetBus(bus int) // GetBusOrDefault gets which bus to use GetBusOrDefault(def int) int // SetAddress sets which address to use SetAddress(address int) // GetAddressOrDefault gets which address to use GetAddressOrDefault(def int) int } // Connector lets adaptors (platforms) provide the interface for Drivers to get access to the I2C buses on platforms // that support I2C. The "I2C" specifier is part of the name to differentiate to SPI at platform level. type Connector interface { // GetI2cConnection creates and returns a connection to device at the specified address // and bus. Bus numbering starts at index 0, the range of valid buses is // platform specific. GetI2cConnection(address int, busNr int) (device Connection, err error) // DefaultI2cBus returns the default I2C bus index DefaultI2cBus() int } // Driver implements the interface gobot.Driver. type Driver struct { Config gobot.Commander name string defaultAddress int connector Connector connection Connection afterStart func() error beforeHalt func() error mutex *sync.Mutex // mutex often needed to ensure that write-read sequences are not interrupted } // NewDriver creates a new generic and basic i2c gobot driver. func NewDriver(c Connector, name string, address int, options ...func(Config)) *Driver { d := &Driver{ name: gobot.DefaultName(name), defaultAddress: address, connector: c, afterStart: func() error { return nil }, beforeHalt: func() error { return nil }, Config: NewConfig(), Commander: gobot.NewCommander(), mutex: &sync.Mutex{}, } for _, option := range options { option(d) } return d } // Name returns the name of the i2c device. func (d *Driver) Name() string { return d.name } // SetName sets the name of the i2c device. func (d *Driver) SetName(name string) { d.name = name } // Connection returns the gobot connection of the i2c device. func (d *Driver) Connection() gobot.Connection { if d.connector == nil { log.Printf("%s has no connector\n", d.name) return nil } if conn, ok := d.connector.(gobot.Connection); ok { return conn } log.Printf("%s has no gobot connection\n", d.name) return nil } // Start initializes the i2c device. func (d *Driver) Start() error { d.mutex.Lock() defer d.mutex.Unlock() if d.connector == nil { return fmt.Errorf("%s has no connector", d.name) } var err error bus := d.GetBusOrDefault(d.connector.DefaultI2cBus()) address := d.GetAddressOrDefault(d.defaultAddress) if d.connection, err = d.connector.GetI2cConnection(address, bus); err != nil { return err } return d.afterStart() } // Halt halts the i2c device. func (d *Driver) Halt() error { d.mutex.Lock() defer d.mutex.Unlock() if err := d.beforeHalt(); err != nil { return err } d.connection = nil return nil } // Write implements a simple write mechanism, starting from the given register of an i2c device. func (d *Driver) Write(pin string, val int) error { d.mutex.Lock() defer d.mutex.Unlock() if d.connection == nil { return fmt.Errorf("i2c driver not started for '%s'", d.name) } register, err := driverParseRegister(pin) if err != nil { return err } if val > 0xFFFF { buf := make([]byte, 4) binary.LittleEndian.PutUint32(buf, uint32(val)) //nolint:gosec // ok here return d.connection.WriteBlockData(register, buf) } if val > 0xFF { return d.connection.WriteWordData(register, uint16(val)) } return d.connection.WriteByteData(register, uint8(val)) //nolint:gosec // ok here } // Read implements a simple read mechanism from the given register of an i2c device. func (d *Driver) Read(pin string) (int, error) { d.mutex.Lock() defer d.mutex.Unlock() if d.connection == nil { return 0, fmt.Errorf("i2c driver not started for '%s'", d.name) } register, err := driverParseRegister(pin) if err != nil { return 0, err } val, err := d.connection.ReadByteData(register) if err != nil { return 0, err } return int(val), nil } func (d *Driver) write(data []byte) (int, error) { if d.connection == nil { return 0, fmt.Errorf("i2c driver not started for '%s'", d.name) } return d.connection.Write(data) } func (d *Driver) writeByte(val byte) error { if d.connection == nil { return fmt.Errorf("i2c driver not started for '%s'", d.name) } return d.connection.WriteByte(val) } func (d *Driver) writeByteData(reg uint8, val byte) error { if d.connection == nil { return fmt.Errorf("i2c driver not started for '%s'", d.name) } return d.connection.WriteByteData(reg, val) } func (d *Driver) writeWordData(reg uint8, val uint16) error { if d.connection == nil { return fmt.Errorf("i2c driver not started for '%s'", d.name) } return d.connection.WriteWordData(reg, val) } func (d *Driver) writeBlockData(reg uint8, data []byte) error { if d.connection == nil { return fmt.Errorf("i2c driver not started for '%s'", d.name) } return d.connection.WriteBlockData(reg, data) } func (d *Driver) read(data []byte) (int, error) { if d.connection == nil { return 0, fmt.Errorf("i2c driver not started for '%s'", d.name) } return d.connection.Read(data) } func (d *Driver) readByte() (byte, error) { if d.connection == nil { return 0, fmt.Errorf("i2c driver not started for '%s'", d.name) } return d.connection.ReadByte() } func (d *Driver) readByteData(reg uint8) (byte, error) { if d.connection == nil { return 0, fmt.Errorf("i2c driver not started for '%s'", d.name) } return d.connection.ReadByteData(reg) } func (d *Driver) readWordData(reg uint8) (uint16, error) { if d.connection == nil { return 0, fmt.Errorf("i2c driver not started for '%s'", d.name) } return d.connection.ReadWordData(reg) } func (d *Driver) readBlockData(reg uint8, data []byte) error { if d.connection == nil { return fmt.Errorf("i2c driver not started for '%s'", d.name) } return d.connection.ReadBlockData(reg, data) } func driverParseRegister(pin string) (uint8, error) { register, err := strconv.ParseUint(pin, 10, 8) if err != nil { return 0, fmt.Errorf("could not parse the register from given pin '%s'", pin) } return uint8(register), nil } ================================================ FILE: drivers/i2c/i2c_driver_test.go ================================================ package i2c import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) var _ gobot.Driver = (*Driver)(nil) func initDriverWithStubbedAdaptor() (*Driver, *i2cTestAdaptor) { a := newI2cTestAdaptor() d := NewDriver(a, "I2C_BASIC", 0x15) return d, a } func initTestDriver() *Driver { d, _ := initDriverWithStubbedAdaptor() return d } func TestNewDriver(t *testing.T) { // arrange a := newI2cTestAdaptor() // act var di interface{} = NewDriver(a, "I2C_BASIC", 0x15) // assert d, ok := di.(*Driver) if !ok { require.Fail(t, "NewDriver() should have returned a *Driver") } assert.Contains(t, d.name, "I2C_BASIC") assert.Equal(t, 0x15, d.defaultAddress) assert.Equal(t, a, d.connector) assert.Nil(t, d.connection) require.NoError(t, d.afterStart()) require.NoError(t, d.beforeHalt()) assert.NotNil(t, d.Config) assert.NotNil(t, d.Commander) assert.NotNil(t, d.mutex) } func TestSetName(t *testing.T) { // arrange d := initTestDriver() // act d.SetName("TESTME") // assert assert.Equal(t, "TESTME", d.Name()) } func TestConnection(t *testing.T) { // arrange d := initTestDriver() // act, assert assert.NotNil(t, d.Connection()) } func TestStart(t *testing.T) { // arrange d, a := initDriverWithStubbedAdaptor() // act, assert require.NoError(t, d.Start()) assert.Equal(t, 0x15, a.address) } func TestStartConnectError(t *testing.T) { // arrange d, a := initDriverWithStubbedAdaptor() a.Testi2cConnectErr(true) // act, assert require.ErrorContains(t, d.Start(), "invalid i2c connection") } func TestHalt(t *testing.T) { // arrange d := initTestDriver() // act, assert require.NoError(t, d.Halt()) // must be idempotent require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestWrite(t *testing.T) { // arrange const ( address = "82" wantAddress = uint8(0x52) value = 0x25 ) d, a := initDriverWithStubbedAdaptor() _ = d.Start() // prepare all writes numCallsWrite := 0 a.i2cWriteImpl = func([]byte) (int, error) { numCallsWrite++ return 0, nil } // act err := d.Write(address, value) // assert require.NoError(t, err) assert.Equal(t, 1, numCallsWrite) assert.Equal(t, wantAddress, a.written[0]) assert.Equal(t, uint8(value), a.written[1]) } func TestRead(t *testing.T) { // arrange const ( address = "83" wantAddress = uint8(0x53) want = uint8(0x44) ) d, a := initDriverWithStubbedAdaptor() _ = d.Start() // prepare all writes numCallsWrite := 0 a.i2cWriteImpl = func(b []byte) (int, error) { numCallsWrite++ return 0, nil } // prepare all reads numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ b[0] = want return len(b), nil } // act val, err := d.Read(address) // assert require.NoError(t, err) assert.Equal(t, int(want), val) assert.Equal(t, 1, numCallsWrite) assert.Equal(t, wantAddress, a.written[0]) assert.Equal(t, 1, numCallsRead) } ================================================ FILE: drivers/i2c/ina3221_driver.go ================================================ package i2c // INA3221Driver is a driver for the Texas Instruments INA3221 device. The INA3221 is a three-channel // current and bus voltage monitor with an I2C and SMBUS compatible interface. // // INA3221 data sheet and specifications can be found at http://www.td.com/product/INA3221 // // This module was tested with SwitchDoc Labs INA3221 breakout board found at http://www.switchdoc.com/ // INA3221Channel type that defines which INA3221 channel to read from. type INA3221Channel uint8 const ( ina3221DefaultAddress = 0x40 // 1000000 (A0+A1=GND) ina3221Read uint8 = 0x01 ina3221RegConfig uint8 = 0x00 // CONFIG REGISTER (R/W) ina3221ConfigReset uint16 = 0x8000 // Reset Bit ina3221ConfigEnableChan1 uint16 = 0x4000 // Enable INA3221 Channel 1 ina3221ConfigEnableChan2 uint16 = 0x2000 // Enable INA3221 Channel 2 ina3221ConfigEnableChan3 uint16 = 0x1000 // Enable INA3221 Channel 3 ina3221ConfigAvg2 uint16 = 0x0800 // AVG Samples Bit 2 - See table 3 spec ina3221ConfigAvg1 uint16 = 0x0400 // AVG Samples Bit 1 - See table 3 spec ina3221ConfigAvg0 uint16 = 0x0200 // AVG Samples Bit 0 - See table 3 spec ina3221ConfigVBusCT2 uint16 = 0x0100 // VBUS bit 2 Conversion time - See table 4 spec ina3221ConfigVBusCT1 uint16 = 0x0080 // VBUS bit 1 Conversion time - See table 4 spec ina3221ConfigVBusCT0 uint16 = 0x0040 // VBUS bit 0 Conversion time - See table 4 spec ina3221ConfigVShCT2 uint16 = 0x0020 // Vshunt bit 2 Conversion time - See table 5 spec ina3221ConfigVShCT1 uint16 = 0x0010 // Vshunt bit 1 Conversion time - See table 5 spec ina3221ConfigVShCT0 uint16 = 0x0008 // Vshunt bit 0 Conversion time - See table 5 spec ina3221ConfigMode2 uint16 = 0x0004 // Operating Mode bit 2 - See table 6 spec ina3221ConfigMode1 uint16 = 0x0002 // Operating Mode bit 1 - See table 6 spec ina3221ConfigMode0 uint16 = 0x0001 // Operating Mode bit 0 - See table 6 spec ina3221RegShuntVoltage1 uint8 = 0x01 // SHUNT VOLTAGE REGISTER (R) ina3221RegBusVoltage1 uint8 = 0x02 // BUS VOLTAGE REGISTER (R) ina3221ShuntResistorValue float64 = 0.1 // default shunt resistor value of 0.1 Ohm INA3221Channel1 INA3221Channel = 1 INA3221Channel2 INA3221Channel = 2 INA3221Channel3 INA3221Channel = 3 ) // INA3221Driver is a driver for the INA3221 three-channel current and bus voltage monitoring device. type INA3221Driver struct { *Driver } // NewINA3221Driver creates a new driver with the specified i2c interface. // Params: // // c Connector - the Adaptor to use with this Driver // // Optional params: // // i2c.WithBus(int): bus to use with this driver // i2c.WithAddress(int): address to use with this driver func NewINA3221Driver(c Connector, options ...func(Config)) *INA3221Driver { d := &INA3221Driver{ Driver: NewDriver(c, "INA3221", ina3221DefaultAddress), } d.afterStart = d.initialize for _, option := range options { option(d) } return d } // GetBusVoltage gets the bus voltage in Volts func (d *INA3221Driver) GetBusVoltage(channel INA3221Channel) (float64, error) { value, err := d.getBusVoltageRaw(channel) if err != nil { return 0, err } return float64(value) * .001, nil } // GetShuntVoltage Gets the shunt voltage in mV func (d *INA3221Driver) GetShuntVoltage(channel INA3221Channel) (float64, error) { value, err := d.getShuntVoltageRaw(channel) if err != nil { return 0, err } return float64(value) * float64(.005), nil } // GetCurrent gets the current value in mA, taking into account the config settings and current LSB func (d *INA3221Driver) GetCurrent(channel INA3221Channel) (float64, error) { value, err := d.GetShuntVoltage(channel) if err != nil { return 0, err } ma := value / ina3221ShuntResistorValue return ma, nil } // GetLoadVoltage gets the load voltage in mV func (d *INA3221Driver) GetLoadVoltage(channel INA3221Channel) (float64, error) { bv, err := d.GetBusVoltage(channel) if err != nil { return 0, err } sv, err := d.GetShuntVoltage(channel) if err != nil { return 0, err } return bv + (sv / 1000.0), nil } // getBusVoltageRaw gets the raw bus voltage (16-bit signed integer, so +-32767) func (d *INA3221Driver) getBusVoltageRaw(channel INA3221Channel) (int16, error) { val, err := d.readWordFromRegister(ina3221RegBusVoltage1 + (uint8(channel)-1)*2) if err != nil { return 0, err } value := int32(val) if value > 0x7FFF { value -= 0x10000 } return int16(value), nil //nolint:gosec // TODO: fix later } // getShuntVoltageRaw gets the raw shunt voltage (16-bit signed integer, so +-32767) func (d *INA3221Driver) getShuntVoltageRaw(channel INA3221Channel) (int16, error) { val, err := d.readWordFromRegister(ina3221RegShuntVoltage1 + (uint8(channel)-1)*2) if err != nil { return 0, err } value := int32(val) if value > 0x7FFF { value -= 0x10000 } return int16(value), nil //nolint:gosec // TODO: fix later } // reads word from supplied register address func (d *INA3221Driver) readWordFromRegister(reg uint8) (uint16, error) { val, err := d.readWordData(reg) if err != nil { return 0, err } return ((val & 0x00FF) << 8) | ((val & 0xFF00) >> 8), nil } // initialize initializes the INA3221 device func (d *INA3221Driver) initialize() error { config := ina3221ConfigEnableChan1 | ina3221ConfigEnableChan2 | ina3221ConfigEnableChan3 | ina3221ConfigAvg1 | ina3221ConfigVBusCT2 | ina3221ConfigVShCT2 | ina3221ConfigMode2 | ina3221ConfigMode1 | ina3221ConfigMode0 return d.writeBlockData(ina3221RegConfig, []byte{byte(config >> 8), byte(config & 0x00FF)}) } ================================================ FILE: drivers/i2c/ina3221_driver_test.go ================================================ package i2c import ( "errors" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) // this ensures that the implementation is based on i2c.Driver, which implements the gobot.Driver // and tests all implementations, so no further tests needed here for gobot.Driver interface var _ gobot.Driver = (*INA3221Driver)(nil) func initTestINA3221DriverWithStubbedAdaptor() (*INA3221Driver, *i2cTestAdaptor) { a := newI2cTestAdaptor() d := NewINA3221Driver(a) if err := d.Start(); err != nil { panic(err) } return d, a } func TestNewINA3221Driver(t *testing.T) { var di interface{} = NewINA3221Driver(newI2cTestAdaptor()) d, ok := di.(*INA3221Driver) if !ok { t.Error("NewINA3221Driver() should return a *INA3221Driver") } assert.NotNil(t, d.Driver) assert.True(t, strings.HasPrefix(d.Name(), "INA3221")) assert.Equal(t, 0x40, d.defaultAddress) } func TestINA3221Options(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithBus() option and // least one of this driver. Further tests for options can also be done by call of "WithOption(val)(d)". d := NewINA3221Driver(newI2cTestAdaptor(), WithBus(2)) assert.Equal(t, 2, d.GetBusOrDefault(1)) } func TestINA3221Start(t *testing.T) { d := NewINA3221Driver(newI2cTestAdaptor()) require.NoError(t, d.Start()) } func TestINA3221Halt(t *testing.T) { // arrange d := NewINA3221Driver(newI2cTestAdaptor()) // act, assert require.NoError(t, d.Halt()) // must be idempotent require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestINA3221GetBusVoltage(t *testing.T) { d, a := initTestINA3221DriverWithStubbedAdaptor() a.i2cReadImpl = func(b []byte) (int, error) { // bus voltage sensor values from 12V battery copy(b, []byte{0x36, 0x68}) return 2, nil } v, err := d.GetBusVoltage(INA3221Channel1) assert.InDelta(t, float64(13.928), v, 0.0) require.NoError(t, err) } func TestINA3221GetBusVoltageReadError(t *testing.T) { d, a := initTestINA3221DriverWithStubbedAdaptor() a.i2cReadImpl = func(b []byte) (int, error) { return 0, errors.New("read error") } _, err := d.GetBusVoltage(INA3221Channel1) require.ErrorContains(t, err, "read error") } func TestINA3221GetShuntVoltage(t *testing.T) { d, a := initTestINA3221DriverWithStubbedAdaptor() a.i2cReadImpl = func(b []byte) (int, error) { // shunt voltage sensor values from 12V battery copy(b, []byte{0x05, 0xD8}) return 2, nil } v, err := d.GetShuntVoltage(INA3221Channel1) assert.InDelta(t, float64(7.48), v, 0.0) require.NoError(t, err) } func TestINA3221GetShuntVoltageReadError(t *testing.T) { d, a := initTestINA3221DriverWithStubbedAdaptor() a.i2cReadImpl = func(b []byte) (int, error) { return 0, errors.New("read error") } _, err := d.GetShuntVoltage(INA3221Channel1) require.ErrorContains(t, err, "read error") } func TestINA3221GetCurrent(t *testing.T) { d, a := initTestINA3221DriverWithStubbedAdaptor() a.i2cReadImpl = func(b []byte) (int, error) { // shunt voltage sensor values from 12V battery copy(b, []byte{0x05, 0x0D8}) return 2, nil } v, err := d.GetCurrent(INA3221Channel1) assert.InDelta(t, float64(74.8), v, 0.0) require.NoError(t, err) } func TestINA3221CurrentReadError(t *testing.T) { d, a := initTestINA3221DriverWithStubbedAdaptor() a.i2cReadImpl = func(b []byte) (int, error) { return 0, errors.New("read error") } _, err := d.GetCurrent(INA3221Channel1) require.ErrorContains(t, err, "read error") } func TestINA3221GetLoadVoltage(t *testing.T) { d, a := initTestINA3221DriverWithStubbedAdaptor() i := 0 a.i2cReadImpl = func(b []byte) (int, error) { // TODO: return test data as read from actual sensor copy(b, []byte{0x36, 0x68, 0x05, 0xd8}[i:i+2]) i += 2 return 2, nil } v, err := d.GetLoadVoltage(INA3221Channel2) assert.InDelta(t, float64(13.935480), v, 0.0) require.NoError(t, err) } func TestINA3221GetLoadVoltageReadError(t *testing.T) { d, a := initTestINA3221DriverWithStubbedAdaptor() a.i2cReadImpl = func(b []byte) (int, error) { return 0, errors.New("read error") } _, err := d.GetLoadVoltage(INA3221Channel2) require.ErrorContains(t, err, "read error") } ================================================ FILE: drivers/i2c/jhd1313m1_driver.go ================================================ package i2c import ( "fmt" "log" "strconv" "time" "gobot.io/x/gobot/v2" ) const ( REG_RED = 0x04 REG_GREEN = 0x03 REG_BLUE = 0x02 LCD_CLEARDISPLAY = 0x01 LCD_RETURNHOME = 0x02 LCD_ENTRYMODESET = 0x04 LCD_DISPLAYCONTROL = 0x08 LCD_CURSORSHIFT = 0x10 LCD_FUNCTIONSET = 0x20 LCD_SETCGRAMADDR = 0x40 LCD_SETDDRAMADDR = 0x80 LCD_ENTRYRIGHT = 0x00 LCD_ENTRYLEFT = 0x02 LCD_ENTRYSHIFTINCREMENT = 0x01 LCD_ENTRYSHIFTDECREMENT = 0x00 LCD_DISPLAYON = 0x04 LCD_DISPLAYOFF = 0x00 LCD_CURSORON = 0x02 LCD_CURSOROFF = 0x00 LCD_BLINKON = 0x01 LCD_BLINKOFF = 0x00 LCD_DISPLAYMOVE = 0x08 LCD_CURSORMOVE = 0x00 LCD_MOVERIGHT = 0x04 LCD_MOVELEFT = 0x00 LCD_2LINE = 0x08 LCD_CMD = 0x80 LCD_DATA = 0x40 LCD_2NDLINEOFFSET = 0x40 ) // CustomLCDChars is a map of CGRAM characters that can be loaded // into a LCD screen to display custom characters. Some LCD screens such // as the Grove screen (jhd1313m1) isn't loaded with latin 1 characters. // It's up to the developer to load the set up to 8 custom characters and // update the input text so the character is swapped by a byte reflecting // the position of the custom character to use. // See SetCustomChar var CustomLCDChars = map[string][8]byte{ "é": {130, 132, 142, 145, 159, 144, 142, 128}, "è": {136, 132, 142, 145, 159, 144, 142, 128}, "ê": {132, 138, 142, 145, 159, 144, 142, 128}, "à": {136, 134, 128, 142, 145, 147, 141, 128}, "â": {132, 138, 128, 142, 145, 147, 141, 128}, "á": {2, 4, 14, 1, 15, 17, 15, 0}, "î": {132, 138, 128, 140, 132, 132, 142, 128}, "í": {2, 4, 12, 4, 4, 4, 14, 0}, "û": {132, 138, 128, 145, 145, 147, 141, 128}, "ù": {136, 134, 128, 145, 145, 147, 141, 128}, "ñ": {14, 0, 22, 25, 17, 17, 17, 0}, "ó": {2, 4, 14, 17, 17, 17, 14, 0}, "heart": {0, 10, 31, 31, 31, 14, 4, 0}, "smiley": {0, 0, 10, 0, 0, 17, 14, 0}, "frowney": {0, 0, 10, 0, 0, 0, 14, 17}, } //nolint:staticcheck // prefix of the driver preferred for unexposed error var jhd1313m1ErrInvalidPosition = fmt.Errorf("invalid position value") // JHD1313M1Driver is a driver for the Jhd1313m1 LCD display which has two i2c addreses, // one belongs to a controller and the other controls solely the backlight. // This module was tested with the Seed Grove LCD RGB Backlight v2.0 display which requires 5V to operate. // http://www.seeedstudio.com/wiki/Grove_-_LCD_RGB_Backlight type JHD1313M1Driver struct { Config gobot.Commander name string connector Connector lcdAddress int lcdConnection Connection rgbAddress int rgbConnection Connection } // NewJHD1313M1Driver creates a new driver with specified i2c interface. // Params: // // conn Connector - the Adaptor to use with this Driver // // Optional params: // // i2c.WithBus(int): bus to use with this driver func NewJHD1313M1Driver(a Connector, options ...func(Config)) *JHD1313M1Driver { d := &JHD1313M1Driver{ name: gobot.DefaultName("JHD1313M1"), connector: a, Config: NewConfig(), Commander: gobot.NewCommander(), lcdAddress: 0x3E, rgbAddress: 0x62, } for _, option := range options { option(d) } //nolint:forcetypeassert // ok here d.AddCommand("SetRGB", func(params map[string]interface{}) interface{} { r, _ := strconv.Atoi(params["r"].(string)) g, _ := strconv.Atoi(params["g"].(string)) b, _ := strconv.Atoi(params["b"].(string)) return d.SetRGB(r, g, b) }) d.AddCommand("Clear", func(_ map[string]interface{}) interface{} { return d.Clear() }) d.AddCommand("Home", func(_ map[string]interface{}) interface{} { return d.Home() }) //nolint:forcetypeassert // ok here d.AddCommand("Write", func(params map[string]interface{}) interface{} { msg := params["msg"].(string) return d.Write(msg) }) //nolint:forcetypeassert // ok here d.AddCommand("SetPosition", func(params map[string]interface{}) interface{} { pos, _ := strconv.Atoi(params["pos"].(string)) return d.SetPosition(pos) }) //nolint:forcetypeassert // ok here d.AddCommand("Scroll", func(params map[string]interface{}) interface{} { lr, _ := strconv.ParseBool(params["lr"].(string)) return d.Scroll(lr) }) return d } // Name returns the name the JHD1313M1 Driver was given when created. func (d *JHD1313M1Driver) Name() string { return d.name } // SetName sets the name for the JHD1313M1 Driver. func (d *JHD1313M1Driver) SetName(n string) { d.name = n } // Connection returns the gobot connection to the device. func (d *JHD1313M1Driver) Connection() gobot.Connection { if d.connector == nil { log.Printf("%s has no connector\n", d.name) return nil } if conn, ok := d.connector.(gobot.Connection); ok { return conn } log.Printf("%s has no gobot connection\n", d.name) return nil } // Start starts the backlit and the screen and initializes the states. func (d *JHD1313M1Driver) Start() error { if d.connector == nil { return fmt.Errorf("%s has no connector", d.name) } bus := d.GetBusOrDefault(d.connector.DefaultI2cBus()) var err error if d.lcdConnection, err = d.connector.GetI2cConnection(d.lcdAddress, bus); err != nil { return err } if d.rgbConnection, err = d.connector.GetI2cConnection(d.rgbAddress, bus); err != nil { return err } // SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION! // according to datasheet, we need at least 40ms after power rises above 2.7V // before sending commands. Arduino can turn on way befer 4.5V so we'll wait 50 time.Sleep(50 * time.Millisecond) // this is according to the hitachi HD44780 datasheet // page 45 figure 23 // Send function set command sequence init_payload := []byte{LCD_CMD, LCD_FUNCTIONSET | LCD_2LINE} if _, err := d.lcdConnection.Write(init_payload); err != nil { return err } // wait more than 4.1ms time.Sleep(4500 * time.Microsecond) // second try if _, err := d.lcdConnection.Write(init_payload); err != nil { return err } time.Sleep(150 * time.Microsecond) // third go if _, err := d.lcdConnection.Write(init_payload); err != nil { return err } if _, err := d.lcdConnection.Write([]byte{LCD_CMD, LCD_DISPLAYCONTROL | LCD_DISPLAYON}); err != nil { return err } time.Sleep(100 * time.Microsecond) if err := d.Clear(); err != nil { return err } if _, err := d.lcdConnection.Write([]byte{ LCD_CMD, LCD_ENTRYMODESET | LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT, }); err != nil { return err } if err := d.setReg(0, 0); err != nil { return err } if err := d.setReg(1, 0); err != nil { return err } if err := d.setReg(0x08, 0xAA); err != nil { return err } return d.SetRGB(255, 255, 255) } // SetRGB sets the Red Green Blue value of backlit. func (d *JHD1313M1Driver) SetRGB(r, g, b int) error { if err := d.setReg(REG_RED, r); err != nil { return err } if err := d.setReg(REG_GREEN, g); err != nil { return err } return d.setReg(REG_BLUE, b) } // Clear clears the text on the lCD display. func (d *JHD1313M1Driver) Clear() error { return d.command([]byte{LCD_CLEARDISPLAY}) } // Home sets the cursor to the origin position on the display. func (d *JHD1313M1Driver) Home() error { err := d.command([]byte{LCD_RETURNHOME}) // This wait fixes a race condition when calling home and clear back to back. time.Sleep(2 * time.Millisecond) return err } // Write displays the passed message on the screen. func (d *JHD1313M1Driver) Write(message string) error { // This wait fixes an odd bug where the clear function doesn't always work properly. time.Sleep(1 * time.Millisecond) for _, val := range message { if val == '\n' { if err := d.SetPosition(16); err != nil { return err } continue } if _, err := d.lcdConnection.Write([]byte{LCD_DATA, byte(val)}); err != nil { return err } } return nil } // SetPosition sets the cursor and the data display to pos. // 0..15 are the positions in the first display line. // 16..32 are the positions in the second display line. func (d *JHD1313M1Driver) SetPosition(pos int) error { if pos < 0 || pos > 31 { return jhd1313m1ErrInvalidPosition } offset := byte(pos) if pos >= 16 { offset -= 16 offset |= LCD_2NDLINEOFFSET } return d.command([]byte{LCD_SETDDRAMADDR | offset}) } // Scroll sets the scrolling direction for the display, either left to right, or // right to left. func (d *JHD1313M1Driver) Scroll(lr bool) error { if lr { _, err := d.lcdConnection.Write([]byte{LCD_CMD, LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT}) return err } _, err := d.lcdConnection.Write([]byte{LCD_CMD, LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT}) return err } // Halt is a noop function. func (d *JHD1313M1Driver) Halt() error { return nil } // SetCustomChar sets one of the 8 CGRAM locations with a custom character. // The custom character can be used by writing a byte of value 0 to 7. // When you are using LCD as 5x8 dots in function set then you can define a total of 8 user defined patterns // (1 Byte for each row and 8 rows for each pattern). // Use http://www.8051projects.net/lcd-interfacing/lcd-custom-character.php to create your own // characters. // To use a custom character, write byte value of the custom character position as a string after // having setup the custom character. func (d *JHD1313M1Driver) SetCustomChar(pos int, charMap [8]byte) error { if pos > 7 { return fmt.Errorf("can't set a custom character at a position greater than 7") } location := uint8(pos) //nolint:gosec // checked before if err := d.command([]byte{LCD_SETCGRAMADDR | (location << 3)}); err != nil { return err } _, err := d.lcdConnection.Write(append([]byte{LCD_DATA}, charMap[:]...)) return err } func (d *JHD1313M1Driver) setReg(command int, data int) error { _, err := d.rgbConnection.Write([]byte{byte(command), byte(data)}) return err } func (d *JHD1313M1Driver) command(buf []byte) error { _, err := d.lcdConnection.Write(append([]byte{LCD_CMD}, buf...)) return err } ================================================ FILE: drivers/i2c/jhd1313m1_driver_test.go ================================================ package i2c import ( "errors" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) var _ gobot.Driver = (*JHD1313M1Driver)(nil) // --------- HELPERS func initTestJHD1313M1Driver() *JHD1313M1Driver { d, _ := initTestJHD1313M1DriverWithStubbedAdaptor() return d } func initTestJHD1313M1DriverWithStubbedAdaptor() (*JHD1313M1Driver, *i2cTestAdaptor) { adaptor := newI2cTestAdaptor() return NewJHD1313M1Driver(adaptor), adaptor } // --------- TESTS func TestNewJHD1313M1Driver(t *testing.T) { // Does it return a pointer to an instance of JHD1313M1Driver? var mpl interface{} = NewJHD1313M1Driver(newI2cTestAdaptor()) _, ok := mpl.(*JHD1313M1Driver) if !ok { require.Fail(t, "NewJHD1313M1Driver() should have returned a *JHD1313M1Driver") } } // Methods func TestJHD1313M1Driver(t *testing.T) { jhd := initTestJHD1313M1Driver() assert.NotNil(t, jhd.Connection()) assert.True(t, strings.HasPrefix(jhd.Name(), "JHD1313M1")) } func TestJHD1313MDriverSetName(t *testing.T) { d := initTestJHD1313M1Driver() d.SetName("TESTME") assert.Equal(t, "TESTME", d.Name()) } func TestJHD1313MDriverOptions(t *testing.T) { d := NewJHD1313M1Driver(newI2cTestAdaptor(), WithBus(2)) assert.Equal(t, 2, d.GetBusOrDefault(1)) } func TestJHD1313MDriverStart(t *testing.T) { d := initTestJHD1313M1Driver() require.NoError(t, d.Start()) } func TestJHD1313MStartConnectError(t *testing.T) { d, adaptor := initTestJHD1313M1DriverWithStubbedAdaptor() adaptor.Testi2cConnectErr(true) require.ErrorContains(t, d.Start(), "invalid i2c connection") } func TestJHD1313MDriverStartWriteError(t *testing.T) { d, adaptor := initTestJHD1313M1DriverWithStubbedAdaptor() adaptor.i2cWriteImpl = func([]byte) (int, error) { return 0, errors.New("write error") } require.ErrorContains(t, d.Start(), "write error") } func TestJHD1313MDriverHalt(t *testing.T) { // arrange d := initTestJHD1313M1Driver() // act, assert require.NoError(t, d.Halt()) // must be idempotent require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestJHD1313MDriverSetRgb(t *testing.T) { d, _ := initTestJHD1313M1DriverWithStubbedAdaptor() _ = d.Start() require.NoError(t, d.SetRGB(0x00, 0x00, 0x00)) } func TestJHD1313MDriverSetRgbError(t *testing.T) { d, a := initTestJHD1313M1DriverWithStubbedAdaptor() _ = d.Start() a.i2cWriteImpl = func([]byte) (int, error) { return 0, errors.New("write error") } require.ErrorContains(t, d.SetRGB(0x00, 0x00, 0x00), "write error") } func TestJHD1313MDriverClear(t *testing.T) { d, _ := initTestJHD1313M1DriverWithStubbedAdaptor() _ = d.Start() require.NoError(t, d.Clear()) } func TestJHD1313MDriverClearError(t *testing.T) { d, a := initTestJHD1313M1DriverWithStubbedAdaptor() _ = d.Start() a.i2cWriteImpl = func([]byte) (int, error) { return 0, errors.New("write error") } require.ErrorContains(t, d.Clear(), "write error") } func TestJHD1313MDriverHome(t *testing.T) { d, _ := initTestJHD1313M1DriverWithStubbedAdaptor() _ = d.Start() require.NoError(t, d.Home()) } func TestJHD1313MDriverWrite(t *testing.T) { d, _ := initTestJHD1313M1DriverWithStubbedAdaptor() _ = d.Start() require.NoError(t, d.Write("Hello")) } func TestJHD1313MDriverWriteError(t *testing.T) { d, a := initTestJHD1313M1DriverWithStubbedAdaptor() _ = d.Start() a.i2cWriteImpl = func([]byte) (int, error) { return 0, errors.New("write error") } require.ErrorContains(t, d.Write("Hello"), "write error") } func TestJHD1313MDriverWriteTwoLines(t *testing.T) { d, _ := initTestJHD1313M1DriverWithStubbedAdaptor() _ = d.Start() require.NoError(t, d.Write("Hello\nthere")) } func TestJHD1313MDriverWriteTwoLinesError(t *testing.T) { d, a := initTestJHD1313M1DriverWithStubbedAdaptor() _ = d.Start() a.i2cWriteImpl = func([]byte) (int, error) { return 0, errors.New("write error") } require.ErrorContains(t, d.Write("Hello\nthere"), "write error") } func TestJHD1313MDriverSetPosition(t *testing.T) { d, _ := initTestJHD1313M1DriverWithStubbedAdaptor() _ = d.Start() require.NoError(t, d.SetPosition(2)) } func TestJHD1313MDriverSetSecondLinePosition(t *testing.T) { d, _ := initTestJHD1313M1DriverWithStubbedAdaptor() _ = d.Start() require.NoError(t, d.SetPosition(18)) } func TestJHD1313MDriverSetPositionInvalid(t *testing.T) { d, _ := initTestJHD1313M1DriverWithStubbedAdaptor() _ = d.Start() assert.Equal(t, jhd1313m1ErrInvalidPosition, d.SetPosition(-1)) assert.Equal(t, jhd1313m1ErrInvalidPosition, d.SetPosition(32)) } func TestJHD1313MDriverScroll(t *testing.T) { d, _ := initTestJHD1313M1DriverWithStubbedAdaptor() _ = d.Start() require.NoError(t, d.Scroll(true)) } func TestJHD1313MDriverReverseScroll(t *testing.T) { d, _ := initTestJHD1313M1DriverWithStubbedAdaptor() _ = d.Start() require.NoError(t, d.Scroll(false)) } func TestJHD1313MDriverSetCustomChar(t *testing.T) { d, _ := initTestJHD1313M1DriverWithStubbedAdaptor() data := [8]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} _ = d.Start() require.NoError(t, d.SetCustomChar(0, data)) } func TestJHD1313MDriverSetCustomCharError(t *testing.T) { d, _ := initTestJHD1313M1DriverWithStubbedAdaptor() data := [8]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} _ = d.Start() require.ErrorContains(t, d.SetCustomChar(10, data), "can't set a custom character at a position greater than 7") } func TestJHD1313MDriverSetCustomCharWriteError(t *testing.T) { d, a := initTestJHD1313M1DriverWithStubbedAdaptor() _ = d.Start() a.i2cWriteImpl = func([]byte) (int, error) { return 0, errors.New("write error") } data := [8]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} require.ErrorContains(t, d.SetCustomChar(0, data), "write error") } func TestJHD1313MDriverCommands(t *testing.T) { d, _ := initTestJHD1313M1DriverWithStubbedAdaptor() _ = d.Start() err := d.Command("SetRGB")(map[string]interface{}{"r": "1", "g": "1", "b": "1"}) assert.Nil(t, err) err = d.Command("Clear")(map[string]interface{}{}) assert.Nil(t, err) err = d.Command("Home")(map[string]interface{}{}) assert.Nil(t, err) err = d.Command("Write")(map[string]interface{}{"msg": "Hello"}) assert.Nil(t, err) err = d.Command("SetPosition")(map[string]interface{}{"pos": "1"}) assert.Nil(t, err) err = d.Command("Scroll")(map[string]interface{}{"lr": "true"}) assert.Nil(t, err) } ================================================ FILE: drivers/i2c/l3gd20h_driver.go ================================================ //nolint:lll // ok here package i2c import ( "bytes" "encoding/binary" "log" ) const ( l3gd20hDebug = false l3gd20hDefaultAddress = 0x6B ) const ( l3gd20hReg_Ctl1 = 0x20 // output data rate selection, bandwidth selection, power mode, axis X/Y/Z enable l3gd20hReg_Ctl4 = 0x23 // block data update, big/little-endian, full scale, level sensitive latch, self test, serial interface mode l3gd20hReg_OutXLSB = 0x28 // X-axis angular rate data, LSB l3gd20hCtl1_NormalModeBit = 0x08 l3gd20hCtl1_EnableZBit = 0x04 l3gd20hCtl1_EnableYBit = 0x02 l3gd20hCtl1_EnableXBit = 0x01 l3gd20hCtl4_FullScaleRangeBits = 0x30 ) // L3GD20HScale is for configurable full scale range. type L3GD20HScale byte const ( // L3GD20HScale250dps is the +/-250 degrees-per-second full scale range (+/-245 from datasheet, but can hold around +/-286). L3GD20HScale250dps L3GD20HScale = 0x00 // L3GD20HScale500dps is the +/-500 degrees-per-second full scale range. L3GD20HScale500dps L3GD20HScale = 0x10 // L3GD20HScale2001dps is the +/-2000 degrees-per-second full scale range by using 0x20 setting. L3GD20HScale2001dps L3GD20HScale = 0x20 // L3GD20HScale2000dps is the +/-2000 degrees-per-second full scale range. L3GD20HScale2000dps L3GD20HScale = 0x30 ) // l3gdhSensibility in °/s, see the mechanical characteristics in the datasheet var l3gdhSensibility = map[L3GD20HScale]float32{ L3GD20HScale250dps: 0.00875, L3GD20HScale500dps: 0.0175, L3GD20HScale2001dps: 0.07, L3GD20HScale2000dps: 0.07, } // L3GD20HDriver is the gobot driver for the Adafruit Triple-Axis Gyroscope L3GD20H. // Device datasheet: http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/DATASHEET/DM00036465.pdf type L3GD20HDriver struct { *Driver scale L3GD20HScale } // NewL3GD20HDriver creates a new Gobot driver for the // L3GD20H I2C Triple-Axis Gyroscope. // // Params: // // c Connector - the Adaptor to use with this Driver // // Optional params: // // i2c.WithBus(int): bus to use with this driver // i2c.WithAddress(int): address to use with this driver func NewL3GD20HDriver(c Connector, options ...func(Config)) *L3GD20HDriver { d := &L3GD20HDriver{ Driver: NewDriver(c, "L3GD20H", l3gd20hDefaultAddress, options...), scale: L3GD20HScale250dps, } d.afterStart = d.initialize // TODO: add commands to API return d } // WithL3GD20HFullScaleRange option sets the full scale range for the gyroscope. // Valid settings are of type "L3GD20HScale" func WithL3GD20HFullScaleRange(val L3GD20HScale) func(Config) { return func(c Config) { d, ok := c.(*L3GD20HDriver) if ok { d.scale = val } else if l3gd20hDebug { log.Printf("Trying to set full scale range of gyroscope for non-L3GD20HDriver %v", c) } } } // SetScale sets the full scale range of the device (deprecated, use WithL3GD20HFullScaleRange() instead). func (d *L3GD20HDriver) SetScale(s L3GD20HScale) { d.scale = s } // Scale returns the full scale range (deprecated, use FullScaleRange() instead). func (d *L3GD20HDriver) Scale() L3GD20HScale { return d.scale } // FullScaleRange returns the full scale range of the device. func (d *L3GD20HDriver) FullScaleRange() (uint8, error) { d.mutex.Lock() defer d.mutex.Unlock() val, err := d.readByteData(l3gd20hReg_Ctl4) if err != nil { return 0, err } return val & l3gd20hCtl4_FullScaleRangeBits, nil } // XYZ returns the current change in degrees per second, for the 3 axis. // //nolint:nonamedreturns // is sufficient here func (d *L3GD20HDriver) XYZ() (x float32, y float32, z float32, err error) { d.mutex.Lock() defer d.mutex.Unlock() measurements := make([]byte, 6) reg := l3gd20hReg_OutXLSB | 0x80 // set auto-increment bit if err := d.readBlockData(uint8(reg), measurements); err != nil { return 0, 0, 0, err } var rawX int16 var rawY int16 var rawZ int16 buf := bytes.NewBuffer(measurements) if err := binary.Read(buf, binary.LittleEndian, &rawX); err != nil { return 0, 0, 0, err } if err := binary.Read(buf, binary.LittleEndian, &rawY); err != nil { return 0, 0, 0, err } if err := binary.Read(buf, binary.LittleEndian, &rawZ); err != nil { return 0, 0, 0, err } sensitivity := l3gdhSensibility[d.scale] return float32(rawX) * sensitivity, float32(rawY) * sensitivity, float32(rawZ) * sensitivity, nil } func (d *L3GD20HDriver) initialize() error { // reset the gyroscope. if err := d.writeByteData(l3gd20hReg_Ctl1, 0x00); err != nil { return err } // Enable Z, Y and X axis. ctl1 := l3gd20hCtl1_NormalModeBit | l3gd20hCtl1_EnableZBit | l3gd20hCtl1_EnableYBit | l3gd20hCtl1_EnableXBit if err := d.writeByteData(l3gd20hReg_Ctl1, uint8(ctl1)); err != nil { return err } // Set the sensitivity scale. if err := d.writeByteData(l3gd20hReg_Ctl4, byte(d.scale)); err != nil { return err } return nil } ================================================ FILE: drivers/i2c/l3gd20h_driver_test.go ================================================ package i2c import ( "errors" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) // this ensures that the implementation is based on i2c.Driver, which implements the gobot.Driver // and tests all implementations, so no further tests needed here for gobot.Driver interface var _ gobot.Driver = (*HMC6352Driver)(nil) func initL3GD20HDriver() *L3GD20HDriver { d, _ := initL3GD20HWithStubbedAdaptor() return d } func initL3GD20HWithStubbedAdaptor() (*L3GD20HDriver, *i2cTestAdaptor) { a := newI2cTestAdaptor() d := NewL3GD20HDriver(a) if err := d.Start(); err != nil { panic(err) } return d, a } func TestNewL3GD20HDriver(t *testing.T) { var di interface{} = NewL3GD20HDriver(newI2cTestAdaptor()) d, ok := di.(*L3GD20HDriver) if !ok { require.Fail(t, "NewL3GD20HDriver() should have returned a *L3GD20HDriver") } assert.NotNil(t, d.Driver) assert.True(t, strings.HasPrefix(d.Name(), "L3GD20H")) assert.Equal(t, 0x6b, d.defaultAddress) assert.Equal(t, L3GD20HScale250dps, d.Scale()) } func TestL3GD20HHalt(t *testing.T) { // arrange d := NewL3GD20HDriver(newI2cTestAdaptor()) // act, assert require.NoError(t, d.Halt()) // must be idempotent require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestL3GD20HOptions(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithBus() option. // Further tests for options can also be done by call of "WithOption(val)(d)". d := NewL3GD20HDriver(newI2cTestAdaptor(), WithBus(2)) assert.Equal(t, 2, d.GetBusOrDefault(1)) } func TestL3GD20HWithL3GD20HFullScaleRange(t *testing.T) { tests := map[string]struct { scale L3GD20HScale want uint8 }{ "250dps": { scale: L3GD20HScale250dps, want: 0x00, }, "500dps": { scale: L3GD20HScale500dps, want: 0x10, }, "2001dps": { scale: L3GD20HScale2001dps, want: 0x20, }, "2000dps": { scale: L3GD20HScale2000dps, want: 0x30, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d := initL3GD20HDriver() // act WithL3GD20HFullScaleRange(tc.scale)(d) // assert assert.Equal(t, L3GD20HScale(tc.want), d.scale) }) } } func TestL3GD20HScale(t *testing.T) { tests := map[string]struct { scale L3GD20HScale want uint8 }{ "250dps": { scale: L3GD20HScale250dps, want: 0x00, }, "500dps": { scale: L3GD20HScale500dps, want: 0x10, }, "2001dps": { scale: L3GD20HScale2001dps, want: 0x20, }, "2000dps": { scale: L3GD20HScale2000dps, want: 0x30, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d := initL3GD20HDriver() // act d.SetScale(tc.scale) // assert assert.Equal(t, L3GD20HScale(tc.want), d.scale) }) } } func TestL3GD20HFullScaleRange(t *testing.T) { // sequence to read full scale range // * write control register 4 (0x23) // * read content and filter FS bits (bit 4, bit 5) // // arrange d, a := initL3GD20HWithStubbedAdaptor() a.written = []byte{} // reset values from Start() and previous tests readValue := uint8(0x10) a.i2cReadImpl = func(b []byte) (int, error) { b[0] = readValue return len(b), nil } // act got, err := d.FullScaleRange() // assert require.NoError(t, err) assert.Len(t, a.written, 1) assert.Equal(t, uint8(0x23), a.written[0]) assert.Equal(t, readValue, got) } func TestL3GD20HMeasurement(t *testing.T) { // sequence for measurement // note: big endian transfer is configured (LSB in lower address, transferred first) // // * write X-axis angular rate data LSB register (0x28) with auto increment bit set (0xA8) // * read 3 x 2 bytes X, Y, Z data, big-endian (LSB, MSB) // * scale values by configured range (sensitivity = 1/gain) // // data table according to data sheet AN4506 example in table 7, supplemented with FS limit values sensitivity := float32(0.00875) // FS=245 dps tests := map[string]struct { gyroData []byte wantX float32 wantY float32 wantZ float32 }{ "245_200_100dps": { gyroData: []byte{0x60, 0x6D, 0x49, 0x59, 0xA4, 0x2C}, wantX: 245, wantY: 199.99875, wantZ: 99.995, }, "-100_-200_-245dps": { gyroData: []byte{0x5C, 0xD3, 0xB7, 0xA6, 0xA0, 0x92}, wantX: -99.995, wantY: -199.99875, wantZ: -245, }, "1_0_-1": { gyroData: []byte{0x72, 0x00, 0x00, 0x00, 0x8D, 0xFF}, wantX: 0.9975, wantY: 0, wantZ: -1.00625, }, "raw_range_int16_-32768_0_+32767": { gyroData: []byte{0x00, 0x80, 0x00, 0x00, 0xFF, 0x7F}, wantX: -286.72, wantY: 0, wantZ: 286.71124, }, "raw_8_5_-3": { gyroData: []byte{0x08, 0x00, 0x05, 0x00, 0xFD, 0xFF}, wantX: float32(8) * sensitivity, wantY: float32(5) * sensitivity, wantZ: float32(-3) * sensitivity, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, a := initL3GD20HWithStubbedAdaptor() a.written = []byte{} // reset values from Start() and previous tests a.i2cReadImpl = func(b []byte) (int, error) { copy(b, tc.gyroData) return len(b), nil } // act x, y, z, err := d.XYZ() // assert require.NoError(t, err) assert.Len(t, a.written, 1) assert.Equal(t, uint8(0xA8), a.written[0]) assert.InDelta(t, tc.wantX, x, 0.0) assert.InDelta(t, tc.wantY, y, 0.0) assert.InDelta(t, tc.wantZ, z, 0.0) }) } } func TestL3GD20HMeasurementError(t *testing.T) { d, a := initL3GD20HWithStubbedAdaptor() a.i2cReadImpl = func(b []byte) (int, error) { return 0, errors.New("read error") } _ = d.Start() x, y, z, err := d.XYZ() require.ErrorContains(t, err, "read error") assert.InDelta(t, 0.0, x, 0.0) assert.InDelta(t, 0.0, y, 0.0) assert.InDelta(t, 0.0, z, 0.0) } func TestL3GD20HMeasurementWriteError(t *testing.T) { d, a := initL3GD20HWithStubbedAdaptor() a.i2cWriteImpl = func(b []byte) (int, error) { return 0, errors.New("write error") } x, y, z, err := d.XYZ() require.ErrorContains(t, err, "write error") assert.InDelta(t, 0.0, x, 0.0) assert.InDelta(t, 0.0, y, 0.0) assert.InDelta(t, 0.0, z, 0.0) } func TestL3GD20H_initialize(t *testing.T) { // sequence for initialization the device on Start() // * write control register 1 (0x20) // * write reset (0x00) // * write control register 1 (0x20) // * prepare register content: // * output data rate for no Low_ODR=100Hz (DR=0x00) // * bandwidth for no Low_ODR=12.5Hz (BW=0x00) // * normal mode and enable all axes (PD=1, X/Y/Z=1) // * write register content (0x0F) // * write control register 4 (0x23) // * prepare register content // * continuous block data update (BDU=0x00) // * use big endian transfer (LSB in lower address, transferred first) (BLE=0x00) // * set full scale selection to configured scale (default=245dps, FS=0x00) // * normal self test (ST=0x00) // * SPI mode to 4 wire (SIM=0x00) // * write register content (0x00) // // all other registers currently untouched // // arrange, act - initialize() must be called on Start() _, a := initL3GD20HWithStubbedAdaptor() // assert assert.Len(t, a.written, 6) assert.Equal(t, uint8(0x20), a.written[0]) assert.Equal(t, uint8(0x00), a.written[1]) assert.Equal(t, uint8(0x20), a.written[2]) assert.Equal(t, uint8(0x0F), a.written[3]) assert.Equal(t, uint8(0x23), a.written[4]) assert.Equal(t, uint8(0x00), a.written[5]) } ================================================ FILE: drivers/i2c/lidarlite_driver.go ================================================ package i2c import ( "time" ) const lidarliteDefaultAddress = 0x62 // LIDARLiteDriver is the Gobot driver for the LIDARLite I2C LIDAR device. type LIDARLiteDriver struct { *Driver } // NewLIDARLiteDriver creates a new driver for the LIDARLite I2C LIDAR device. // // Params: // // c Connector - the Adaptor to use with this Driver // // Optional params: // // i2c.WithBus(int): bus to use with this driver // i2c.WithAddress(int): address to use with this driver func NewLIDARLiteDriver(c Connector, options ...func(Config)) *LIDARLiteDriver { d := &LIDARLiteDriver{ Driver: NewDriver(c, "LIDARLite", lidarliteDefaultAddress), } for _, option := range options { option(d) } // TODO: add commands to API return d } // Distance returns the current distance in cm func (d *LIDARLiteDriver) Distance() (int, error) { if _, err := d.write([]byte{0x00, 0x04}); err != nil { return 0, err } time.Sleep(20 * time.Millisecond) if _, err := d.write([]byte{0x0F}); err != nil { return 0, err } upper := []byte{0} bytesRead, err := d.read(upper) if err != nil { return 0, err } if bytesRead != 1 { return 0, ErrNotEnoughBytes } if _, err := d.write([]byte{0x10}); err != nil { return 0, err } lower := []byte{0} bytesRead, err = d.read(lower) if err != nil { return 0, err } if bytesRead != 1 { return 0, ErrNotEnoughBytes } distance := ((int(upper[0]) & 0xff) << 8) | (int(lower[0]) & 0xff) return distance, nil } ================================================ FILE: drivers/i2c/lidarlite_driver_test.go ================================================ package i2c import ( "bytes" "errors" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) // this ensures that the implementation is based on i2c.Driver, which implements the gobot.Driver // and tests all implementations, so no further tests needed here for gobot.Driver interface var _ gobot.Driver = (*LIDARLiteDriver)(nil) func initTestLIDARLiteDriverWithStubbedAdaptor() (*LIDARLiteDriver, *i2cTestAdaptor) { a := newI2cTestAdaptor() d := NewLIDARLiteDriver(a) if err := d.Start(); err != nil { panic(err) } return d, a } func TestNewLIDARLiteDriver(t *testing.T) { var di interface{} = NewLIDARLiteDriver(newI2cTestAdaptor()) d, ok := di.(*LIDARLiteDriver) if !ok { require.Fail(t, "NewLIDARLiteDriver() should have returned a *LIDARLiteDriver") } assert.NotNil(t, d.Driver) assert.True(t, strings.HasPrefix(d.Name(), "LIDARLite")) assert.Equal(t, 0x62, d.defaultAddress) } func TestLIDARLiteDriverOptions(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithBus() option and // least one of this driver. Further tests for options can also be done by call of "WithOption(val)(d)". d := NewLIDARLiteDriver(newI2cTestAdaptor(), WithBus(2)) assert.Equal(t, 2, d.GetBusOrDefault(1)) } func TestLIDARLiteDriverStart(t *testing.T) { d := NewLIDARLiteDriver(newI2cTestAdaptor()) require.NoError(t, d.Start()) } func TestLIDARLiteDriverHalt(t *testing.T) { // arrange d := NewLIDARLiteDriver(newI2cTestAdaptor()) // act, assert require.NoError(t, d.Halt()) // must be idempotent require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestLIDARLiteDriverDistance(t *testing.T) { // when everything is happy d, a := initTestLIDARLiteDriverWithStubbedAdaptor() first := true a.i2cReadImpl = func(b []byte) (int, error) { if first { first = false copy(b, []byte{99}) return 1, nil } copy(b, []byte{1}) return 1, nil } distance, err := d.Distance() require.NoError(t, err) assert.Equal(t, int(25345), distance) // when insufficient bytes have been read d, a = initTestLIDARLiteDriverWithStubbedAdaptor() a.i2cReadImpl = func([]byte) (int, error) { return 0, nil } distance, err = d.Distance() assert.Equal(t, int(0), distance) assert.Equal(t, ErrNotEnoughBytes, err) // when read error d, a = initTestLIDARLiteDriverWithStubbedAdaptor() a.i2cReadImpl = func([]byte) (int, error) { return 0, errors.New("read error") } distance, err = d.Distance() assert.Equal(t, int(0), distance) require.ErrorContains(t, err, "read error") } func TestLIDARLiteDriverDistanceError1(t *testing.T) { d, a := initTestLIDARLiteDriverWithStubbedAdaptor() a.i2cWriteImpl = func([]byte) (int, error) { return 0, errors.New("write error") } distance, err := d.Distance() assert.Equal(t, int(0), distance) require.ErrorContains(t, err, "write error") } func TestLIDARLiteDriverDistanceError2(t *testing.T) { d, a := initTestLIDARLiteDriverWithStubbedAdaptor() a.i2cWriteImpl = func(b []byte) (int, error) { if b[0] == 0x0f { return 0, errors.New("write error") } return len(b), nil } distance, err := d.Distance() assert.Equal(t, int(0), distance) require.ErrorContains(t, err, "write error") } func TestLIDARLiteDriverDistanceError3(t *testing.T) { d, a := initTestLIDARLiteDriverWithStubbedAdaptor() a.i2cWriteImpl = func(b []byte) (int, error) { if b[0] == 0x10 { return 0, errors.New("write error") } return len(b), nil } a.i2cReadImpl = func(b []byte) (int, error) { buf := new(bytes.Buffer) buf.Write([]byte{0x03}) copy(b, buf.Bytes()) return buf.Len(), nil } distance, err := d.Distance() assert.Equal(t, int(0), distance) require.ErrorContains(t, err, "write error") } ================================================ FILE: drivers/i2c/mcp23017_driver.go ================================================ package i2c import ( "fmt" "log" "strings" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/common/bit" ) // default address for device when a2/a1/a0 pins are all tied to ground // please consider special handling for MCP23S17 const mcp23017DefaultAddress = 0x20 const mcp23017Debug = false // toggle debugging information // port contains all the registers for the device. type port struct { IODIR uint8 // I/O direction register: 0=output / 1=input IPOL uint8 // input polarity register: 0=normal polarity / 1=inversed GPINTEN uint8 // interrupt on change control register: 0=disabled / 1=enabled DEFVAL uint8 // default compare register for interrupt on change // interrupt control register: bit set to 0= use defval bit value to compare pin value/ bit set to 1= pin value // compared to previous pin value INTCON uint8 IOCON uint8 // configuration register GPPU uint8 // pull-up resistor configuration register: 0=enabled / 1=disabled INTF uint8 // interrupt flag register: 0=no interrupt / 1=pin caused interrupt INTCAP uint8 // interrupt capture register, captures pin values during interrupt: 0=logic low / 1=logic high GPIO uint8 // port register, reading from this register reads the port OLAT uint8 // output latch register, write modifies the pins: 0=logic low / 1=logic high } // A bank is made up of PortA and PortB pins. // Port B pins are on the left side of the chip (starting with pin 1), while port A pins are on the right side. type bank struct { portA port portB port } // mcp23017Config contains the device configuration for the IOCON register. // These fields should only be set with values 0 or 1. type mcp23017Config struct { bank uint8 mirror uint8 seqop uint8 disslw uint8 haen uint8 odr uint8 intpol uint8 } type mcp23017Behavior struct { forceRefresh bool autoIODirOff bool } // MCP23017Driver contains the driver configuration parameters. type MCP23017Driver struct { *Driver gobot.Eventer mcpConf mcp23017Config mcpBehav mcp23017Behavior } // NewMCP23017Driver creates a new Gobot Driver to the MCP23017 i2c port expander. // Params: // // c Connector - the Adaptor to use with this Driver // // Optional params: // // i2c.WithBus(int): bus to use with this driver // i2c.WithAddress(int): address to use with this driver // i2c.WithMCP23017Bank(int): MCP23017 bank to use with this driver // i2c.WithMCP23017Mirror(int): MCP23017 mirror to use with this driver // i2c.WithMCP23017Seqop(int): MCP23017 seqop to use with this driver // i2c.WithMCP23017Disslw(int): MCP23017 disslw to use with this driver // i2c.WithMCP23017Haen(int): MCP23017 haen to use with this driver // i2c.WithMCP23017Odr(int): MCP23017 odr to use with this driver // i2c.WithMCP23017Intpol(int): MCP23017 intpol to use with this driver func NewMCP23017Driver(c Connector, options ...func(Config)) *MCP23017Driver { d := &MCP23017Driver{ Driver: NewDriver(c, "MCP23017", mcp23017DefaultAddress), mcpConf: mcp23017Config{}, Eventer: gobot.NewEventer(), } d.afterStart = d.initialize for _, option := range options { option(d) } //nolint:forcetypeassert // ok here d.AddCommand("WriteGPIO", func(params map[string]interface{}) interface{} { pin := params["pin"].(uint8) port := params["port"].(string) val := params["val"].(uint8) err := d.WriteGPIO(pin, port, val) return map[string]interface{}{"err": err} }) //nolint:forcetypeassert // ok here d.AddCommand("ReadGPIO", func(params map[string]interface{}) interface{} { pin := params["pin"].(uint8) port := params["port"].(string) val, err := d.ReadGPIO(pin, port) return map[string]interface{}{"val": val, "err": err} }) return d } // WithMCP23017Bank option sets the MCP23017Driver bank option func WithMCP23017Bank(val uint8) func(Config) { return func(c Config) { d, ok := c.(*MCP23017Driver) if ok { d.mcpConf.bank = val } else if mcp23017Debug { log.Printf("trying to set bank for non-MCP23017Driver %v", c) } } } // WithMCP23017Mirror option sets the MCP23017Driver mirror option func WithMCP23017Mirror(val uint8) func(Config) { return func(c Config) { d, ok := c.(*MCP23017Driver) if ok { d.mcpConf.mirror = val } else if mcp23017Debug { log.Printf("Trying to set mirror for non-MCP23017Driver %v", c) } } } // WithMCP23017Seqop option sets the MCP23017Driver seqop option func WithMCP23017Seqop(val uint8) func(Config) { return func(c Config) { d, ok := c.(*MCP23017Driver) if ok { d.mcpConf.seqop = val } else if mcp23017Debug { log.Printf("Trying to set seqop for non-MCP23017Driver %v", c) } } } // WithMCP23017Disslw option sets the MCP23017Driver disslw option func WithMCP23017Disslw(val uint8) func(Config) { return func(c Config) { d, ok := c.(*MCP23017Driver) if ok { d.mcpConf.disslw = val } else if mcp23017Debug { log.Printf("Trying to set disslw for non-MCP23017Driver %v", c) } } } // WithMCP23017Haen option sets the MCP23017Driver haen option // This feature is only available for MCP23S17, because address pins are always enabled on the MCP23017. func WithMCP23017Haen(val uint8) func(Config) { return func(c Config) { d, ok := c.(*MCP23017Driver) if ok { d.mcpConf.haen = val } else if mcp23017Debug { log.Printf("Trying to set haen for non-MCP23017Driver %v", c) } } } // WithMCP23017Odr option sets the MCP23017Driver odr option func WithMCP23017Odr(val uint8) func(Config) { return func(c Config) { d, ok := c.(*MCP23017Driver) if ok { d.mcpConf.odr = val } else if mcp23017Debug { log.Printf("Trying to set odr for non-MCP23017Driver %v", c) } } } // WithMCP23017Intpol option sets the MCP23017Driver intpol option func WithMCP23017Intpol(val uint8) func(Config) { return func(c Config) { d, ok := c.(*MCP23017Driver) if ok { d.mcpConf.intpol = val } else if mcp23017Debug { log.Printf("Trying to set intpol for non-MCP23017Driver %v", c) } } } // WithMCP23017ForceRefresh option modifies the MCP23017Driver forceRefresh option // Setting to true (1) will force refresh operation to register, although there is no change. // Normally this is not needed, so default is off (0). // When there is something flaky, there is a small chance to stabilize by setting this flag to true. // However, setting this flag to true slows down each IO operation up to 100%. func WithMCP23017ForceRefresh(val uint8) func(Config) { return func(c Config) { d, ok := c.(*MCP23017Driver) if ok { d.mcpBehav.forceRefresh = val > 0 } else if mcp23017Debug { log.Printf("Trying to set forceRefresh for non-MCP23017Driver %v", c) } } } // WithMCP23017AutoIODirOff option modifies the MCP23017Driver autoIODirOff option // Set IO direction at each read or write operation ensures the correct direction, which is the default setting. // Most hardware is configured statically, so this can avoided by setting the direction using SetPinMode(), // e.g. in the start up sequence. If this way is taken, the automatic set of direction at each call can // be safely deactivated with this flag (set to true, 1). // This will speedup each WriteGPIO by 50% and each ReadGPIO by 60%. func WithMCP23017AutoIODirOff(val uint8) func(Config) { return func(c Config) { d, ok := c.(*MCP23017Driver) if ok { d.mcpBehav.autoIODirOff = val > 0 } else if mcp23017Debug { log.Printf("Trying to set autoIODirOff for non-MCP23017Driver %v", c) } } } // SetPinMode set pin mode of a given pin immediately, based on the value: // val = 0 output // val = 1 input func (d *MCP23017Driver) SetPinMode(pin uint8, portStr string, val uint8) error { d.mutex.Lock() defer d.mutex.Unlock() selectedPort := d.getPort(portStr) // Set IODIR register bit for given pin to an output/input. return d.writePin(selectedPort.IODIR, pin, bitState(val)) } // SetPullUp sets the pull up state of a given pin immediately, based on the value: // val = 1 pull up enabled. // val = 0 pull up disabled. func (d *MCP23017Driver) SetPullUp(pin uint8, portStr string, val uint8) error { d.mutex.Lock() defer d.mutex.Unlock() selectedPort := d.getPort(portStr) return d.writePin(selectedPort.GPPU, pin, bitState(val)) } // SetGPIOPolarity will change a given pin's polarity immediately, based on the value: // val = 1 opposite logic state of the input pin. // val = 0 same logic state of the input pin. func (d *MCP23017Driver) SetGPIOPolarity(pin uint8, portStr string, val uint8) error { d.mutex.Lock() defer d.mutex.Unlock() selectedPort := d.getPort(portStr) return d.writePin(selectedPort.IPOL, pin, bitState(val)) } // WriteGPIO writes a value to a gpio pin (0-7) and a port (A or B). func (d *MCP23017Driver) WriteGPIO(pin uint8, portStr string, val uint8) error { d.mutex.Lock() defer d.mutex.Unlock() selectedPort := d.getPort(portStr) if !d.mcpBehav.autoIODirOff { // Set IODIR register bit for given pin to an output by clearing bit. // can't call SetPinMode() because mutex will cause deadlock if err := d.writePin(selectedPort.IODIR, pin, clearBit); err != nil { return err } } // write value to OLAT register bit return d.writePin(selectedPort.OLAT, pin, bitState(val)) } // ReadGPIO reads a value from a given gpio pin (0-7) and a port (A or B). func (d *MCP23017Driver) ReadGPIO(pin uint8, portStr string) (uint8, error) { d.mutex.Lock() defer d.mutex.Unlock() selectedPort := d.getPort(portStr) if !d.mcpBehav.autoIODirOff { // Set IODIR register bit for given pin to an input by set bit. // can't call SetPinMode() because mutex will cause deadlock if err := d.writePin(selectedPort.IODIR, pin, setBit); err != nil { return 0, err } } val, err := d.readReg(selectedPort.GPIO) if err != nil { return val, err } val = 1 << pin & val if val > 1 { val = 1 } return val, nil } func (d *MCP23017Driver) initialize() error { // Set IOCON register with MCP23017 configuration. ioconReg := d.getPort("A").IOCON // IOCON address is the same for Port A or B. ioconVal := d.mcpConf.getUint8Value() _, err := d.write([]uint8{ioconReg, ioconVal}) return err } // write gets the value of the passed in register, and then sets the bit specified // by the pin to the given state. func (d *MCP23017Driver) writePin(reg uint8, pin uint8, state bitState) error { valOrg, err := d.readReg(reg) if err != nil { return fmt.Errorf("MCP write-read: %v", err) } var val uint8 if state == clearBit { val = uint8(bit.Clear(int(valOrg), pin)) //nolint:gosec // TODO: fix later } else { val = uint8(bit.Set(int(valOrg), pin)) //nolint:gosec // TODO: fix later } if val != valOrg || d.mcpBehav.forceRefresh { if mcp23017Debug { log.Printf("write done: MCP forceRefresh: %t, address: 0x%X, register: 0x%X, name: %s, value: 0x%X\n", d.mcpBehav.forceRefresh, d.GetAddressOrDefault(mcp23017DefaultAddress), reg, d.getRegName(reg), val) } if err := d.writeByteData(reg, val); err != nil { return fmt.Errorf("MCP write-WriteByteData(reg=%d,val=%d): %v", reg, val, err) } } else if mcp23017Debug { log.Printf("write skipped: MCP forceRefresh: %t, address: 0x%X, register: 0x%X, name: %s, value: 0x%X\n", d.mcpBehav.forceRefresh, d.GetAddressOrDefault(mcp23017DefaultAddress), reg, d.getRegName(reg), val) } return nil } // read get the data from a given register // it is mainly a wrapper to create additional debug messages, when activated func (d *MCP23017Driver) readReg(reg uint8) (uint8, error) { val, err := d.readByteData(reg) if err != nil { return val, fmt.Errorf("MCP write-ReadByteData(reg=%d): %v", reg, err) } if mcp23017Debug { log.Printf("reading done: MCP autoIODirOff: %t, address: 0x%X, register:0x%X, name: %s, value: 0x%X\n", d.mcpBehav.autoIODirOff, d.GetAddressOrDefault(mcp23017DefaultAddress), reg, d.getRegName(reg), val) } return val, nil } // getPort return the port (A or B) given a string and the bank. // Port A is the default if an incorrect or no port is specified. func (d *MCP23017Driver) getPort(portStr string) port { portStr = strings.ToUpper(portStr) switch portStr { case "A": return mcp23017GetBank(d.mcpConf.bank).portA case "B": return mcp23017GetBank(d.mcpConf.bank).portB default: return mcp23017GetBank(d.mcpConf.bank).portA } } // getRegName returns the name of the given register related to the configured bank // and can be used to write nice debug messages func (d *MCP23017Driver) getRegName(reg uint8) string { b := mcp23017GetBank(d.mcpConf.bank) portStr := "A" regStr := "unknown" for i := 1; i <= 2; i++ { if regStr == "unknown" { p := b.portA if i == 2 { p = b.portB portStr = "B" } switch reg { case p.IODIR: regStr = "IODIR" case p.IPOL: regStr = "IPOL" case p.GPINTEN: regStr = "GPINTEN" case p.DEFVAL: regStr = "DEFVAL" case p.INTCON: regStr = "INTCON" case p.IOCON: regStr = "IOCON" case p.GPPU: regStr = "GPPU" case p.INTF: regStr = "INTF" case p.INTCAP: regStr = "INTCAP" case p.GPIO: regStr = "GPIO" case p.OLAT: regStr = "OLAT" } } } return fmt.Sprintf("%s_%s", regStr, portStr) } // getUint8Value returns the configuration data as a packed value. func (dc *mcp23017Config) getUint8Value() uint8 { return dc.bank<<7 | dc.mirror<<6 | dc.seqop<<5 | dc.disslw<<4 | dc.haen<<3 | dc.odr<<2 | dc.intpol<<1 } // mcp23017GetBank returns a bank's PortA and PortB registers given a bank number (0/1). func mcp23017GetBank(bnk uint8) bank { if bnk == 0 { return bank{ portA: port{0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, 0x10, 0x12, 0x14}, portB: port{0x01, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0F, 0x11, 0x13, 0x15}, } } return bank{ portA: port{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A}, portB: port{0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A}, } } ================================================ FILE: drivers/i2c/mcp23017_driver_test.go ================================================ //nolint:forcetypeassert,gosec // ok here package i2c import ( "errors" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) // this ensures that the implementation is based on i2c.Driver, which implements the gobot.Driver // and tests all implementations, so no further tests needed here for gobot.Driver interface var _ gobot.Driver = (*MCP23017Driver)(nil) var pinValPort = map[string]interface{}{ "pin": uint8(7), "val": uint8(0), "port": "A", } var pinPort = map[string]interface{}{ "pin": uint8(7), "port": "A", } func initTestMCP23017(b uint8) *MCP23017Driver { // create the driver without starting it a := newI2cTestAdaptor() d := NewMCP23017Driver(a, WithMCP23017Bank(b)) return d } func initTestMCP23017WithStubbedAdaptor(b uint8) (*MCP23017Driver, *i2cTestAdaptor) { //nolint:unparam // keep for tests // create the driver, ready to use for tests a := newI2cTestAdaptor() d := NewMCP23017Driver(a, WithMCP23017Bank(b)) if err := d.Start(); err != nil { panic(err) } return d, a } func TestNewMCP23017Driver(t *testing.T) { var di interface{} = NewMCP23017Driver(newI2cTestAdaptor()) d, ok := di.(*MCP23017Driver) if !ok { require.Fail(t, "NewMCP23017Driver() should have returned a *MCP23017Driver") } assert.NotNil(t, d.Driver) assert.True(t, strings.HasPrefix(d.Name(), "MCP23017")) assert.Equal(t, 0x20, d.defaultAddress) assert.NotNil(t, d.mcpConf) assert.NotNil(t, d.mcpBehav) } func TestMCP23017Halt(t *testing.T) { d := NewMCP23017Driver(newI2cTestAdaptor()) require.NoError(t, d.Halt()) // must be idempotent require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestWithMCP23017Bank(t *testing.T) { b := NewMCP23017Driver(newI2cTestAdaptor(), WithMCP23017Bank(1)) assert.Equal(t, uint8(1), b.mcpConf.bank) } func TestWithMCP23017Mirror(t *testing.T) { b := NewMCP23017Driver(newI2cTestAdaptor(), WithMCP23017Mirror(1)) assert.Equal(t, uint8(1), b.mcpConf.mirror) } func TestWithMCP23017Seqop(t *testing.T) { b := NewMCP23017Driver(newI2cTestAdaptor(), WithMCP23017Seqop(1)) assert.Equal(t, uint8(1), b.mcpConf.seqop) } func TestWithMCP23017Disslw(t *testing.T) { b := NewMCP23017Driver(newI2cTestAdaptor(), WithMCP23017Disslw(1)) assert.Equal(t, uint8(1), b.mcpConf.disslw) } func TestWithMCP23017Haen(t *testing.T) { b := NewMCP23017Driver(newI2cTestAdaptor(), WithMCP23017Haen(1)) assert.Equal(t, uint8(1), b.mcpConf.haen) } func TestWithMCP23017Odr(t *testing.T) { b := NewMCP23017Driver(newI2cTestAdaptor(), WithMCP23017Odr(1)) assert.Equal(t, uint8(1), b.mcpConf.odr) } func TestWithMCP23017Intpol(t *testing.T) { b := NewMCP23017Driver(newI2cTestAdaptor(), WithMCP23017Intpol(1)) assert.Equal(t, uint8(1), b.mcpConf.intpol) } func TestWithMCP23017ForceRefresh(t *testing.T) { b := NewMCP23017Driver(newI2cTestAdaptor(), WithMCP23017ForceRefresh(1)) assert.True(t, b.mcpBehav.forceRefresh) } func TestWithMCP23017AutoIODirOff(t *testing.T) { b := NewMCP23017Driver(newI2cTestAdaptor(), WithMCP23017AutoIODirOff(1)) assert.True(t, b.mcpBehav.autoIODirOff) } func TestMCP23017CommandsWriteGPIO(t *testing.T) { // arrange d, _ := initTestMCP23017WithStubbedAdaptor(0) // act result := d.Command("WriteGPIO")(pinValPort) // assert assert.Nil(t, result.(map[string]interface{})["err"]) } func TestMCP23017CommandsReadGPIO(t *testing.T) { // arrange d, _ := initTestMCP23017WithStubbedAdaptor(0) // act result := d.Command("ReadGPIO")(pinPort) // assert assert.Nil(t, result.(map[string]interface{})["err"]) } func TestMCP23017WriteGPIO(t *testing.T) { // sequence to write (we force the refresh by preset with inverse bit state): // * read current state of IODIR (write reg, read val) => see also SetPinMode() // * set IODIR of pin to input (manipulate val, write reg, write val) => see also SetPinMode() // * read current state of OLAT (write reg, read val) // * write OLAT (manipulate val, write reg, write val) // arrange d, a := initTestMCP23017WithStubbedAdaptor(0) for bitState := 0; bitState <= 1; bitState++ { a.written = []byte{} // reset writes of Start() and former test // arrange some values testPort := "A" testPin := uint8(7) wantReg1 := uint8(0x00) // IODIRA wantReg2 := uint8(0x14) // OLATA returnRead := []uint8{0xFF, 0xFF} // emulate all IO's are inputs, emulate bit is on wantReg1Val := returnRead[0] & 0x7F // IODIRA: bit 7 reset, all other untouched wantReg2Val := returnRead[1] & 0x7F // OLATA: bit 7 reset, all other untouched if bitState == 1 { returnRead[1] = 0x7F // emulate bit is off wantReg2Val = returnRead[1] | 0x80 // OLATA: bit 7 set, all other untouched } // arrange reads numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ b[len(b)-1] = returnRead[numCallsRead-1] return len(b), nil } // act err := d.WriteGPIO(testPin, testPort, uint8(bitState)) // assert require.NoError(t, err) assert.Len(t, a.written, 6) assert.Equal(t, wantReg1, a.written[0]) assert.Equal(t, wantReg1, a.written[1]) assert.Equal(t, wantReg1Val, a.written[2]) assert.Equal(t, wantReg2, a.written[3]) assert.Equal(t, wantReg2, a.written[4]) assert.Equal(t, wantReg2Val, a.written[5]) assert.Equal(t, 2, numCallsRead) } } func TestMCP23017WriteGPIONoRefresh(t *testing.T) { // sequence to write with take advantage of refresh optimization (see forceRefresh): // * read current state of IODIR (write reg, read val) => by SetPinMode() // * read current state of OLAT (write reg, read val) // arrange d, a := initTestMCP23017WithStubbedAdaptor(0) for bitState := 0; bitState <= 1; bitState++ { a.written = []byte{} // reset writes of Start() and former test // arrange some values testPort := "B" testPin := uint8(3) wantReg1 := uint8(0x01) // IODIRB wantReg2 := uint8(0x15) // OLATB returnRead := []uint8{0xF7, 0xF7} // emulate all IO's are inputs except pin 3, emulate bit is already off if bitState == 1 { returnRead[1] = 0x08 // emulate bit is already on } // arrange reads numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ b[len(b)-1] = returnRead[numCallsRead-1] return len(b), nil } // act err := d.WriteGPIO(testPin, testPort, uint8(bitState)) // assert require.NoError(t, err) assert.Len(t, a.written, 2) assert.Equal(t, wantReg1, a.written[0]) assert.Equal(t, wantReg2, a.written[1]) assert.Equal(t, 2, numCallsRead) } } func TestMCP23017WriteGPIONoAutoDir(t *testing.T) { // sequence to write with suppressed automatic setting of IODIR: // * read current state of OLAT (write reg, read val) // * write OLAT (manipulate val, write reg, write val) // arrange d, a := initTestMCP23017WithStubbedAdaptor(0) d.mcpBehav.autoIODirOff = true for bitState := 0; bitState <= 1; bitState++ { a.written = []byte{} // reset writes of Start() and former test // arrange some values testPort := "A" testPin := uint8(7) wantReg := uint8(0x14) // OLATA returnRead := uint8(0xFF) // emulate bit is on wantRegVal := returnRead & 0x7F // OLATA: bit 7 reset, all other untouched if bitState == 1 { returnRead = 0x7F // emulate bit is off wantRegVal = returnRead | 0x80 // OLATA: bit 7 set, all other untouched } // arrange reads numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ b[len(b)-1] = returnRead return len(b), nil } // act err := d.WriteGPIO(testPin, testPort, uint8(bitState)) // assert require.NoError(t, err) assert.Len(t, a.written, 3) assert.Equal(t, wantReg, a.written[0]) assert.Equal(t, wantReg, a.written[1]) assert.Equal(t, wantRegVal, a.written[2]) assert.Equal(t, 1, numCallsRead) } } func TestMCP23017CommandsWriteGPIOErrIODIR(t *testing.T) { // arrange d, a := initTestMCP23017WithStubbedAdaptor(0) a.i2cWriteImpl = func([]byte) (int, error) { return 0, errors.New("write error") } // act err := d.WriteGPIO(7, "A", 0) // assert require.ErrorContains(t, err, "MCP write-read: MCP write-ReadByteData(reg=0): write error") } func TestMCP23017CommandsWriteGPIOErrOLAT(t *testing.T) { // arrange d, a := initTestMCP23017WithStubbedAdaptor(0) numCalls := 1 a.i2cWriteImpl = func([]byte) (int, error) { if numCalls == 2 { return 0, errors.New("write error") } numCalls++ return 0, nil } // act err := d.WriteGPIO(7, "A", 0) // assert require.ErrorContains(t, err, "MCP write-read: MCP write-ReadByteData(reg=20): write error") } func TestMCP23017ReadGPIO(t *testing.T) { // sequence to read: // * read current state of IODIR (write reg, read val) => see also SetPinMode() // * set IODIR of pin to input (manipulate val, write reg, write val) => see also SetPinMode() // * read GPIO (write reg, read val) // arrange d, a := initTestMCP23017WithStubbedAdaptor(0) for bitState := 0; bitState <= 1; bitState++ { a.written = []byte{} // reset writes of Start() and former test // arrange some values testPort := "A" testPin := uint8(7) wantReg1 := uint8(0x00) // IODIRA wantReg2 := uint8(0x12) // GPIOA returnRead := []uint8{0x00, 0x7F} // emulate all IO's are outputs, emulate bit is off wantReg1Val := returnRead[0] | 0x80 // IODIRA: bit 7 set, all other untouched if bitState == 1 { returnRead[1] = 0xFF // emulate bit is set } // arrange reads numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ b[len(b)-1] = returnRead[numCallsRead-1] return len(b), nil } // act val, err := d.ReadGPIO(testPin, testPort) // assert require.NoError(t, err) assert.Equal(t, 2, numCallsRead) assert.Len(t, a.written, 4) assert.Equal(t, wantReg1, a.written[0]) assert.Equal(t, wantReg1, a.written[1]) assert.Equal(t, wantReg1Val, a.written[2]) assert.Equal(t, wantReg2, a.written[3]) assert.Equal(t, uint8(bitState), val) } } func TestMCP23017ReadGPIONoRefresh(t *testing.T) { // sequence to read with take advantage of refresh optimization (see forceRefresh): // * read current state of IODIR (write reg, read val) => by SetPinMode() // * read GPIO (write reg, read val) // arrange d, a := initTestMCP23017WithStubbedAdaptor(0) for bitState := 0; bitState <= 1; bitState++ { a.written = []byte{} // reset writes of Start() and former test // arrange some values testPort := "A" testPin := uint8(7) wantReg1 := uint8(0x00) // IODIRA wantReg2 := uint8(0x12) // GPIOA returnRead := []uint8{0x80, 0x7F} // emulate all IO's are outputs except pin 7, emulate bit is off if bitState == 1 { returnRead[1] = 0xFF // emulate bit is set } // arrange reads numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ b[len(b)-1] = returnRead[numCallsRead-1] return len(b), nil } // act val, err := d.ReadGPIO(testPin, testPort) // assert require.NoError(t, err) assert.Equal(t, 2, numCallsRead) assert.Len(t, a.written, 2) assert.Equal(t, wantReg1, a.written[0]) assert.Equal(t, wantReg2, a.written[1]) assert.Equal(t, uint8(bitState), val) } } func TestMCP23017ReadGPIONoAutoDir(t *testing.T) { // sequence to read with suppressed automatic setting of IODIR: // * read GPIO (write reg, read val) // arrange d, a := initTestMCP23017WithStubbedAdaptor(0) d.mcpBehav.autoIODirOff = true for bitState := 0; bitState <= 1; bitState++ { a.written = []byte{} // reset writes of Start() and former test // arrange some values testPort := "A" testPin := uint8(7) wantReg2 := uint8(0x12) // GPIOA returnRead := uint8(0x7F) // emulate bit is off if bitState == 1 { returnRead = 0xFF // emulate bit is set } // arrange reads numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ b[len(b)-1] = returnRead return len(b), nil } // act val, err := d.ReadGPIO(testPin, testPort) // assert require.NoError(t, err) assert.Equal(t, 1, numCallsRead) assert.Len(t, a.written, 1) assert.Equal(t, wantReg2, a.written[0]) assert.Equal(t, uint8(bitState), val) } } func TestMCP23017ReadGPIOErr(t *testing.T) { // arrange d, a := initTestMCP23017WithStubbedAdaptor(0) // arrange reads a.i2cReadImpl = func(b []byte) (int, error) { return len(b), errors.New("read error") } // act _, err := d.ReadGPIO(7, "A") // assert require.ErrorContains(t, err, "MCP write-read: MCP write-ReadByteData(reg=0): read error") } func TestMCP23017SetPinMode(t *testing.T) { // sequence for setting pin direction: // * read current state of IODIR (write reg, read val) // * set IODIR of pin to input or output (manipulate val, write reg, write val) // TODO: can be optimized by not writing, when value is already fine // arrange d, a := initTestMCP23017WithStubbedAdaptor(0) for bitState := 0; bitState <= 1; bitState++ { a.written = []byte{} // reset writes of Start() and former test // arrange some values testPort := "A" testPin := uint8(7) wantReg := uint8(0x00) // IODIRA returnRead := uint8(0xFF) // emulate all ports are inputs wantRegVal := returnRead & 0x7F // bit 7 reset, all other untouched if bitState == 1 { returnRead = 0x00 // emulate all ports are outputs wantRegVal = returnRead | 0x80 // bit 7 set, all other untouched } // arrange reads numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ b[len(b)-1] = returnRead return len(b), nil } // act err := d.SetPinMode(testPin, testPort, uint8(bitState)) // assert require.NoError(t, err) assert.Len(t, a.written, 3) assert.Equal(t, wantReg, a.written[0]) assert.Equal(t, wantReg, a.written[1]) assert.Equal(t, wantRegVal, a.written[2]) assert.Equal(t, 1, numCallsRead) } } func TestMCP23017SetPinModeErr(t *testing.T) { // arrange d, a := initTestMCP23017WithStubbedAdaptor(0) a.i2cWriteImpl = func([]byte) (int, error) { return 0, errors.New("write error") } // act err := d.SetPinMode(7, "A", 0) // assert require.ErrorContains(t, err, "MCP write-read: MCP write-ReadByteData(reg=0): write error") } func TestMCP23017SetPullUp(t *testing.T) { // sequence for setting input pin pull up: // * read current state of GPPU (write reg, read val) // * set GPPU of pin to target state (manipulate val, write reg, write val) // TODO: can be optimized by not writing, when value is already fine // arrange d, a := initTestMCP23017WithStubbedAdaptor(0) for bitState := 0; bitState <= 1; bitState++ { a.written = []byte{} // reset writes of Start() // arrange some values testPort := "A" wantReg := uint8(0x0C) // GPPUA testPin := uint8(5) returnRead := uint8(0xFF) // emulate all I's with pull up wantSetVal := returnRead & 0xDF // bit 5 cleared, all other unchanged if bitState == 1 { returnRead = uint8(0x00) // emulate all I's without pull up wantSetVal = returnRead | 0x20 // bit 5 set, all other unchanged } // arrange reads numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ b[len(b)-1] = returnRead return len(b), nil } // act err := d.SetPullUp(testPin, testPort, uint8(bitState)) // assert require.NoError(t, err) assert.Len(t, a.written, 3) assert.Equal(t, wantReg, a.written[0]) assert.Equal(t, wantReg, a.written[1]) assert.Equal(t, wantSetVal, a.written[2]) assert.Equal(t, 1, numCallsRead) } } func TestMCP23017SetPullUpErr(t *testing.T) { // arrange d, a := initTestMCP23017WithStubbedAdaptor(0) a.i2cWriteImpl = func([]byte) (int, error) { return 0, errors.New("write error") } // act err := d.SetPullUp(7, "A", 0) // assert require.ErrorContains(t, err, "MCP write-read: MCP write-ReadByteData(reg=12): write error") } func TestMCP23017SetGPIOPolarity(t *testing.T) { // sequence for setting input pin polarity: // * read current state of IPOL (write reg, read val) // * set IPOL of pin to target state (manipulate val, write reg, write val) // TODO: can be optimized by not writing, when value is already fine // arrange d, a := initTestMCP23017WithStubbedAdaptor(0) for bitState := 0; bitState <= 1; bitState++ { a.written = []byte{} // reset writes of Start() // arrange some values testPort := "B" wantReg := uint8(0x03) // IPOLB testPin := uint8(6) returnRead := uint8(0xFF) // emulate all I's negotiated wantSetVal := returnRead & 0xBF // bit 6 cleared, all other unchanged if bitState == 1 { returnRead = uint8(0x00) // emulate all I's not negotiated wantSetVal = returnRead | 0x40 // bit 6 set, all other unchanged } // arrange reads numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ b[len(b)-1] = returnRead return len(b), nil } // act err := d.SetGPIOPolarity(testPin, testPort, uint8(bitState)) // assert require.NoError(t, err) assert.Len(t, a.written, 3) assert.Equal(t, wantReg, a.written[0]) assert.Equal(t, wantReg, a.written[1]) assert.Equal(t, wantSetVal, a.written[2]) assert.Equal(t, 1, numCallsRead) } } func TestMCP23017SetGPIOPolarityErr(t *testing.T) { // arrange d, a := initTestMCP23017WithStubbedAdaptor(0) a.i2cWriteImpl = func([]byte) (int, error) { return 0, errors.New("write error") } // act err := d.SetGPIOPolarity(7, "A", 0) // assert require.ErrorContains(t, err, "MCP write-read: MCP write-ReadByteData(reg=2): write error") } func TestMCP23017_write(t *testing.T) { // clear bit d, _ := initTestMCP23017WithStubbedAdaptor(0) port := d.getPort("A") err := d.writePin(port.IODIR, uint8(7), 0) require.NoError(t, err) // set bit d, _ = initTestMCP23017WithStubbedAdaptor(0) port = d.getPort("B") err = d.writePin(port.IODIR, uint8(7), 1) require.NoError(t, err) // write error d, a := initTestMCP23017WithStubbedAdaptor(0) a.i2cWriteImpl = func([]byte) (int, error) { return 0, errors.New("write error") } err = d.writePin(port.IODIR, uint8(7), 0) require.ErrorContains(t, err, "MCP write-read: MCP write-ReadByteData(reg=1): write error") // read error d, a = initTestMCP23017WithStubbedAdaptor(0) a.i2cReadImpl = func(b []byte) (int, error) { return len(b), errors.New("read error") } err = d.writePin(port.IODIR, uint8(7), 0) require.ErrorContains(t, err, "MCP write-read: MCP write-ReadByteData(reg=1): read error") a.i2cReadImpl = func(b []byte) (int, error) { return len(b), nil } err = d.writePin(port.IODIR, uint8(7), 1) require.NoError(t, err) } func TestMCP23017_read(t *testing.T) { // read d, a := initTestMCP23017WithStubbedAdaptor(0) port := d.getPort("A") a.i2cReadImpl = func(b []byte) (int, error) { copy(b, []byte{255}) return 1, nil } val, _ := d.readReg(port.IODIR) assert.Equal(t, uint8(255), val) // read error d, a = initTestMCP23017WithStubbedAdaptor(0) a.i2cReadImpl = func(b []byte) (int, error) { return len(b), errors.New("read error") } val, err := d.readReg(port.IODIR) assert.Equal(t, uint8(0), val) require.ErrorContains(t, err, "MCP write-ReadByteData(reg=0): read error") // read d, a = initTestMCP23017WithStubbedAdaptor(0) port = d.getPort("A") a.i2cReadImpl = func(b []byte) (int, error) { copy(b, []byte{255}) return 1, nil } val, _ = d.readReg(port.IODIR) assert.Equal(t, uint8(255), val) } func TestMCP23017_getPort(t *testing.T) { // port A d := initTestMCP23017(0) wantPort := mcp23017GetBank(0).portA gotPort := d.getPort("A") assert.Equal(t, wantPort, gotPort) // port B d = initTestMCP23017(0) wantPort = mcp23017GetBank(0).portB gotPort = d.getPort("B") assert.Equal(t, wantPort, gotPort) // default d = initTestMCP23017(0) wantPort = mcp23017GetBank(0).portA gotPort = d.getPort("") assert.Equal(t, wantPort, gotPort) // port A bank 1 d = initTestMCP23017(1) wantPort = mcp23017GetBank(1).portA gotPort = d.getPort("") assert.Equal(t, wantPort, gotPort) } ================================================ FILE: drivers/i2c/mfrc522_driver.go ================================================ package i2c import ( "gobot.io/x/gobot/v2/drivers/common/mfrc522" ) const mfrc522DefaultAddress = 0x00 // MFRC522Driver is a wrapper for i2c bus usage. Please refer to the mfrc522.MFRC522Common package // for implementation details. type MFRC522Driver struct { *Driver *mfrc522.MFRC522Common } // NewMFRC522Driver creates a new Gobot Driver for MFRC522 RFID with i2c connection // // Params: // // c Connector - the Adaptor to use with this Driver // // Optional params: // // i2c.WithBus(int): bus to use with this driver // i2c.WithAddress(int): address to use with this driver func NewMFRC522Driver(c Connector, options ...func(Config)) *MFRC522Driver { d := &MFRC522Driver{ Driver: NewDriver(c, "MFRC522", mfrc522DefaultAddress), } d.MFRC522Common = mfrc522.NewMFRC522Common() d.afterStart = d.initialize for _, option := range options { option(d) } return d } func (d *MFRC522Driver) initialize() error { return d.Initialize(d.connection) } ================================================ FILE: drivers/i2c/mma7660_driver.go ================================================ package i2c const mma7660DefaultAddress = 0x4c const ( MMA7660_X = 0x00 MMA7660_Y = 0x01 MMA7660_Z = 0x02 MMA7660_TILT = 0x03 MMA7660_SRST = 0x04 MMA7660_SPCNT = 0x05 MMA7660_INTSU = 0x06 MMA7660_MODE = 0x07 MMA7660_STAND_BY = 0x00 MMA7660_ACTIVE = 0x01 MMA7660_SR = 0x08 MMA7660_AUTO_SLEEP_120 = 0x00 MMA7660_AUTO_SLEEP_64 = 0x01 MMA7660_AUTO_SLEEP_32 = 0x02 MMA7660_AUTO_SLEEP_16 = 0x03 MMA7660_AUTO_SLEEP_8 = 0x04 MMA7660_AUTO_SLEEP_4 = 0x05 MMA7660_AUTO_SLEEP_2 = 0x06 MMA7660_AUTO_SLEEP_1 = 0x07 MMA7660_PDET = 0x09 MMA7660_PD = 0x0A ) type MMA7660Driver struct { *Driver } // NewMMA7660Driver creates a new driver with specified i2c interface // Params: // // c Connector - the Adaptor to use with this Driver // // Optional params: // // i2c.WithBus(int): bus to use with this driver // i2c.WithAddress(int): address to use with this driver func NewMMA7660Driver(c Connector, options ...func(Config)) *MMA7660Driver { d := &MMA7660Driver{ Driver: NewDriver(c, "MMA7660", mma7660DefaultAddress), } d.afterStart = d.initialize for _, option := range options { option(d) } // TODO: add commands for API return d } // Acceleration returns the acceleration of the provided x, y, z // //nolint:nonamedreturns // is sufficient here func (d *MMA7660Driver) Acceleration(x, y, z float64) (ax, ay, az float64) { return x / 21.0, y / 21.0, z / 21.0 } // XYZ returns the raw x,y and z axis from the mma7660 // //nolint:nonamedreturns // is sufficient here func (d *MMA7660Driver) XYZ() (x float64, y float64, z float64, err error) { buf := []byte{0, 0, 0} bytesRead, err := d.read(buf) if err != nil { return } if bytesRead != 3 { err = ErrNotEnoughBytes return } for _, val := range buf { if ((val >> 6) & 0x01) == 1 { err = ErrNotReady return } } x = float64((int8(buf[0]) << 2)) / 4.0 y = float64((int8(buf[1]) << 2)) / 4.0 z = float64((int8(buf[2]) << 2)) / 4.0 return } func (d *MMA7660Driver) initialize() error { if _, err := d.write([]byte{MMA7660_MODE, MMA7660_STAND_BY}); err != nil { return err } if _, err := d.write([]byte{MMA7660_SR, MMA7660_AUTO_SLEEP_32}); err != nil { return err } if _, err := d.write([]byte{MMA7660_MODE, MMA7660_ACTIVE}); err != nil { return err } return nil } ================================================ FILE: drivers/i2c/mma7660_driver_test.go ================================================ package i2c import ( "bytes" "errors" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) // this ensures that the implementation is based on i2c.Driver, which implements the gobot.Driver // and tests all implementations, so no further tests needed here for gobot.Driver interface var _ gobot.Driver = (*MMA7660Driver)(nil) func initTestMMA7660DriverWithStubbedAdaptor() (*MMA7660Driver, *i2cTestAdaptor) { a := newI2cTestAdaptor() d := NewMMA7660Driver(a) if err := d.Start(); err != nil { panic(err) } return d, a } func TestNewMMA7660Driver(t *testing.T) { var di interface{} = NewMMA7660Driver(newI2cTestAdaptor()) d, ok := di.(*MMA7660Driver) if !ok { require.Fail(t, "NewMMA7660Driver() should have returned a *MMA7660Driver") } assert.NotNil(t, d.Driver) assert.True(t, strings.HasPrefix(d.Name(), "MMA7660")) assert.Equal(t, 0x4c, d.defaultAddress) } func TestMMA7660Options(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithBus() option and // least one of this driver. Further tests for options can also be done by call of "WithOption(val)(d)". d := NewMMA7660Driver(newI2cTestAdaptor(), WithBus(2)) assert.Equal(t, 2, d.GetBusOrDefault(1)) } func TestMMA7660Start(t *testing.T) { d := NewMMA7660Driver(newI2cTestAdaptor()) require.NoError(t, d.Start()) } func TestMMA7660Halt(t *testing.T) { // arrange d := NewMMA7660Driver(newI2cTestAdaptor()) // act, assert require.NoError(t, d.Halt()) // must be idempotent require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestMMA7660Acceleration(t *testing.T) { d, _ := initTestMMA7660DriverWithStubbedAdaptor() x, y, z := d.Acceleration(21.0, 21.0, 21.0) assert.InDelta(t, 1.0, x, 0.0) assert.InDelta(t, 1.0, y, 0.0) assert.InDelta(t, 1.0, z, 0.0) } func TestMMA7660NullXYZ(t *testing.T) { d, _ := initTestMMA7660DriverWithStubbedAdaptor() x, y, z, _ := d.XYZ() assert.InDelta(t, 0.0, x, 0.0) assert.InDelta(t, 0.0, y, 0.0) assert.InDelta(t, 0.0, z, 0.0) } func TestMMA7660XYZ(t *testing.T) { d, a := initTestMMA7660DriverWithStubbedAdaptor() a.i2cReadImpl = func(b []byte) (int, error) { buf := new(bytes.Buffer) buf.Write([]byte{0x11, 0x12, 0x13}) copy(b, buf.Bytes()) return buf.Len(), nil } x, y, z, _ := d.XYZ() assert.InDelta(t, 17.0, x, 0.0) assert.InDelta(t, 18.0, y, 0.0) assert.InDelta(t, 19.0, z, 0.0) } func TestMMA7660XYZError(t *testing.T) { d, a := initTestMMA7660DriverWithStubbedAdaptor() a.i2cReadImpl = func(b []byte) (int, error) { return 0, errors.New("read error") } x, y, z, err := d.XYZ() require.ErrorContains(t, err, "read error") assert.InDelta(t, 0.0, x, 0.0) assert.InDelta(t, 0.0, y, 0.0) assert.InDelta(t, 0.0, z, 0.0) } func TestMMA7660XYZNotReady(t *testing.T) { d, a := initTestMMA7660DriverWithStubbedAdaptor() a.i2cReadImpl = func(b []byte) (int, error) { buf := new(bytes.Buffer) buf.Write([]byte{0x40, 0x40, 0x40}) copy(b, buf.Bytes()) return buf.Len(), nil } x, y, z, err := d.XYZ() assert.Equal(t, ErrNotReady, err) assert.InDelta(t, 0.0, x, 0.0) assert.InDelta(t, 0.0, y, 0.0) assert.InDelta(t, 0.0, z, 0.0) } ================================================ FILE: drivers/i2c/mpl115a2_driver.go ================================================ package i2c import ( "bytes" "encoding/binary" "time" "gobot.io/x/gobot/v2" ) const mpl115a2DefaultAddress = 0x60 const ( mpl115A2Reg_PressureMSB = 0x00 // first ADC register mpl115A2Reg_PressureLSB = 0x01 mpl115A2Reg_TempMSB = 0x02 mpl115A2Reg_TempLSB = 0x03 mpl115A2Reg_A0_MSB = 0x04 // first coefficient register mpl115A2Reg_A0_LSB = 0x05 mpl115A2Reg_B1_MSB = 0x06 mpl115A2Reg_B1_LSB = 0x07 mpl115A2Reg_B2_MSB = 0x08 mpl115A2Reg_B2_LSB = 0x09 mpl115A2Reg_C12_MSB = 0x0A mpl115A2Reg_C12_LSB = 0x0B mpl115A2Reg_StartConversion = 0x12 ) // MPL115A2Driver is a Gobot Driver for the MPL115A2 I2C digital pressure/temperature sensor. // datasheet: // https://www.nxp.com/docs/en/data-sheet/MPL115A2.pdf // // reference implementations: // * https://github.com/adafruit/Adafruit_MPL115A2 type MPL115A2Driver struct { *Driver gobot.Eventer a0 float32 b1 float32 b2 float32 c12 float32 } // NewMPL115A2Driver creates a new Gobot Driver for an MPL115A2 // I2C Pressure/Temperature sensor. // // Params: // // c Connector - the Adaptor to use with this Driver // // Optional params: // // i2c.WithBus(int): bus to use with this driver // i2c.WithAddress(int): address to use with this driver func NewMPL115A2Driver(c Connector, options ...func(Config)) *MPL115A2Driver { d := &MPL115A2Driver{ Driver: NewDriver(c, "MPL115A2", mpl115a2DefaultAddress), Eventer: gobot.NewEventer(), } d.afterStart = d.initialization for _, option := range options { option(d) } // TODO: add commands to API d.AddEvent(Error) return d } // Pressure fetches the latest data from the MPL115A2, and returns the pressure in kPa func (d *MPL115A2Driver) Pressure() (float32, error) { d.mutex.Lock() defer d.mutex.Unlock() p, _, err := d.getData() return p, err } // Temperature fetches the latest data from the MPL115A2, and returns the temperature in °C func (d *MPL115A2Driver) Temperature() (float32, error) { d.mutex.Lock() defer d.mutex.Unlock() _, t, err := d.getData() return t, err } func (d *MPL115A2Driver) initialization() error { data := make([]byte, 8) if err := d.readBlockData(mpl115A2Reg_A0_MSB, data); err != nil { return err } var coA0 int16 var coB1 int16 var coB2 int16 var coC12 int16 buf := bytes.NewBuffer(data) if err := binary.Read(buf, binary.BigEndian, &coA0); err != nil { return err } if err := binary.Read(buf, binary.BigEndian, &coB1); err != nil { return err } if err := binary.Read(buf, binary.BigEndian, &coB2); err != nil { return err } if err := binary.Read(buf, binary.BigEndian, &coC12); err != nil { return err } coC12 = coC12 >> 2 d.a0 = float32(coA0) / 8.0 d.b1 = float32(coB1) / 8192.0 d.b2 = float32(coB2) / 16384.0 d.c12 = float32(coC12) / 4194304.0 return nil } // getData fetches the latest data from the MPL115A2 // //nolint:nonamedreturns // is sufficient here func (d *MPL115A2Driver) getData() (p, t float32, err error) { var temperature uint16 var pressure uint16 var pressureComp float32 if err = d.writeByteData(mpl115A2Reg_StartConversion, 0); err != nil { return 0, 0, err } time.Sleep(5 * time.Millisecond) data := []byte{0, 0, 0, 0} if err = d.readBlockData(mpl115A2Reg_PressureMSB, data); err != nil { return 0, 0, err } buf := bytes.NewBuffer(data) if err := binary.Read(buf, binary.BigEndian, &pressure); err != nil { return 0, 0, err } if err := binary.Read(buf, binary.BigEndian, &temperature); err != nil { return 0, 0, err } temperature = temperature >> 6 pressure = pressure >> 6 pressureComp = d.a0 + (d.b1+d.c12*float32(temperature))*float32(pressure) + d.b2*float32(temperature) p = (65.0/1023.0)*pressureComp + 50.0 t = ((float32(temperature) - 498.0) / -5.35) + 25.0 return p, t, err } ================================================ FILE: drivers/i2c/mpl115a2_driver_test.go ================================================ package i2c import ( "errors" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) // this ensures that the implementation is based on i2c.Driver, which implements the gobot.Driver // and tests all implementations, so no further tests needed here for gobot.Driver interface var _ gobot.Driver = (*MPL115A2Driver)(nil) func initTestMPL115A2DriverWithStubbedAdaptor() (*MPL115A2Driver, *i2cTestAdaptor) { a := newI2cTestAdaptor() return NewMPL115A2Driver(a), a } func TestNewMPL115A2Driver(t *testing.T) { var di interface{} = NewMPL115A2Driver(newI2cTestAdaptor()) d, ok := di.(*MPL115A2Driver) if !ok { require.Fail(t, "NewMPL115A2Driver() should have returned a *MPL115A2Driver") } assert.NotNil(t, d.Connection()) assert.True(t, strings.HasPrefix(d.Name(), "MPL115A2")) assert.Equal(t, 0x60, d.defaultAddress) } func TestMPL115A2Options(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithBus() option and // least one of this driver. Further tests for options can also be done by call of "WithOption(val)(d)". d := NewMPL115A2Driver(newI2cTestAdaptor(), WithBus(2)) assert.Equal(t, 2, d.GetBusOrDefault(1)) } func TestMPL115A2Halt(t *testing.T) { // arrange d := NewMPL115A2Driver(newI2cTestAdaptor()) // act, assert require.NoError(t, d.Halt()) // must be idempotent require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestMPL115A2ReadData(t *testing.T) { // sequence for read data // * retrieve the coefficients for temperature compensation of pressure - see test for Start() // * write start conversion register address (0x12) // * write start value - 0x00 // * wait at least 3 ms according to data sheet (tc - conversion time) // * write pressure MSB register address (0x00) // * read pressure (16 bit, order MSB-LSB) // * read temperature (16 bit, order MSB-LSB) // * calculate temperature compensated pressure in kPa according to data sheet // * shift the temperature value right for 6 bits (resolution is 10 bit) // * shift the pressure value right for 6 bits (resolution is 10 bit) // * calculate temperature in °C according to this implementation: // https://github.com/adafruit/Adafruit_MPL115A2/tree/2.0.2/Adafruit_MPL115A2.cpp // // arrange d, a := initTestMPL115A2DriverWithStubbedAdaptor() _ = d.Start() a.written = []byte{} // arrange coefficients according the example from data sheet d.a0 = 2009.75 d.b1 = -2.37585 d.b2 = -0.92047 d.c12 = 0.00079 readReturnP := []byte{0x66, 0x80, 0x7E, 0xC0} // use example from data sheet readReturnT := []byte{0x00, 0x00, 0x7E, 0xC0} // use example from data sheet readCallCounter := 0 a.i2cReadImpl = func(b []byte) (int, error) { readCallCounter++ if readCallCounter == 1 { copy(b, readReturnP) } if readCallCounter == 2 { copy(b, readReturnT) } return len(b), nil } // act press, errP := d.Pressure() temp, errT := d.Temperature() // assert require.NoError(t, errP) require.NoError(t, errT) assert.Equal(t, 2, readCallCounter) assert.Len(t, a.written, 6) assert.Equal(t, uint8(0x12), a.written[0]) assert.Equal(t, uint8(0x00), a.written[1]) assert.Equal(t, uint8(0x00), a.written[2]) assert.Equal(t, uint8(0x12), a.written[3]) assert.Equal(t, uint8(0x00), a.written[4]) assert.Equal(t, uint8(0x00), a.written[5]) assert.InDelta(t, float32(96.585915), press, 1.0e-5) assert.InDelta(t, float32(23.317757), temp, 0.0) } func TestMPL115A2ReadDataError(t *testing.T) { d, a := initTestMPL115A2DriverWithStubbedAdaptor() _ = d.Start() a.i2cWriteImpl = func([]byte) (int, error) { return 0, errors.New("write error") } _, err := d.Pressure() require.ErrorContains(t, err, "write error") } func TestMPL115A2_initialization(t *testing.T) { // sequence for initialization the device on Start(), which calculates // the coefficients for temperature compensation of pressure // * write coefficient A0 MSB register address (0x04) // * read all 4 coefficients (16 bit, order MSB-LSB) // * write signal path reset register address (0x68) // * calculate A0, B1, B2, C12 according to data sheet // // arrange d, a := initTestMPL115A2DriverWithStubbedAdaptor() readCallCounter := 0 readReturn := []byte{0x3E, 0xCE, 0xB3, 0xF9, 0xC5, 0x17, 0x33, 0xC8} // use example from data sheet a.i2cReadImpl = func(b []byte) (int, error) { readCallCounter++ copy(b, readReturn) return len(b), nil } // act, assert - initialization() must be called on Start() err := d.Start() // assert require.NoError(t, err) assert.Equal(t, 1, readCallCounter) assert.Len(t, a.written, 1) assert.Equal(t, uint8(0x04), a.written[0]) assert.InDelta(t, float32(2009.75), d.a0, 0.0) assert.InDelta(t, float32(-2.3758545), d.b1, 0.0) assert.InDelta(t, float32(-0.9204712), d.b2, 0.0) assert.InDelta(t, float32(0.0007901192), d.c12, 0.0) } ================================================ FILE: drivers/i2c/mpu6050_driver.go ================================================ package i2c import ( "bytes" "encoding/binary" "fmt" "log" "time" ) const ( mpu6050Debug = false mpu6050DefaultAddress = 0x68 mpu6050EarthStandardGravity = 9.80665 // [m/s²] standard gravity (pole: 9.834, equator: 9.764) ) type ( MPU6050DlpfConfig uint8 MPU6050FrameSyncConfig uint8 MPU6050GyroFsConfig uint8 MPU6050AccelFsConfig uint8 MPU6050Pwr1ClockConfig uint8 ) const ( mpu6050Reg_GeneralConfig = 0x1A // external frame synchronization and digital low pass filter mpu6050Reg_GyroConfig = 0x1B // self test and full scale range mpu6050Reg_AccelConfig = 0x1C // self test and full scale range mpu6050Reg_AccelXoutH = 0x3B // first data register mpu6050Reg_SignalPathReset = 0x68 mpu6050Reg_PwrMgmt1 = 0x6B MPU6050General_Dlpf260Hz MPU6050DlpfConfig = 0x00 MPU6050General_Dlpf184Hz MPU6050DlpfConfig = 0x01 MPU6050General_Dlpf94Hz MPU6050DlpfConfig = 0x02 MPU6050General_Dlpf44Hz MPU6050DlpfConfig = 0x03 MPU6050General_Dlpf21Hz MPU6050DlpfConfig = 0x04 MPU6050General_Dlpf10Hz MPU6050DlpfConfig = 0x05 MPU6050General_Dlpf5Hz MPU6050DlpfConfig = 0x06 MPU6050General_FrameSyncDisabled MPU6050FrameSyncConfig = 0x00 MPU6050General_FrameSyncTemp MPU6050FrameSyncConfig = 0x01 MPU6050General_FrameSyncGyroX MPU6050FrameSyncConfig = 0x02 MPU6050General_FrameSyncGyroY MPU6050FrameSyncConfig = 0x03 MPU6050General_FrameSyncGyroZ MPU6050FrameSyncConfig = 0x04 MPU6050General_FrameSyncAccelX MPU6050FrameSyncConfig = 0x05 MPU6050General_FrameSyncAccelY MPU6050FrameSyncConfig = 0x06 MPU6050General_FrameSyncAccelZ MPU6050FrameSyncConfig = 0x07 MPU6050Gyro_FsSel250dps MPU6050GyroFsConfig = 0x00 // +/- 250 °/s MPU6050Gyro_FsSel500dps MPU6050GyroFsConfig = 0x01 // +/- 500 °/s MPU6050Gyro_FsSel1000dps MPU6050GyroFsConfig = 0x02 // +/- 1000 °/s MPU6050Gyro_FsSel2000dps MPU6050GyroFsConfig = 0x03 // +/- 2000 °/s MPU6050Accel_AFsSel2g MPU6050AccelFsConfig = 0x00 // +/- 2 g MPU6050Accel_AFsSel4g MPU6050AccelFsConfig = 0x01 // +/- 4 g MPU6050Accel_AFsSel8g MPU6050AccelFsConfig = 0x02 // +/- 8 g MPU6050Accel_AFsSel16g MPU6050AccelFsConfig = 0x03 // +/- 16 g mpu6050SignalReset_TempBit = 0x01 mpu6050SignalReset_AccelBit = 0x02 mpu6050SignalReset_GyroBit = 0x04 MPU6050Pwr1_ClockIntern8G MPU6050Pwr1ClockConfig = 0x00 // internal 8GHz MPU6050Pwr1_ClockPllXGyro MPU6050Pwr1ClockConfig = 0x01 // PLL with X axis gyroscope reference MPU6050Pwr1_ClockPllYGyro MPU6050Pwr1ClockConfig = 0x02 // PLL with Y axis gyroscope reference MPU6050Pwr1_ClockPllZGyro MPU6050Pwr1ClockConfig = 0x03 // PLL with Z axis gyroscope reference MPU6050Pwr1_ClockPllExt32K MPU6050Pwr1ClockConfig = 0x04 // PLL with external 32.768kHz reference MPU6050Pwr1_ClockPllExt19M MPU6050Pwr1ClockConfig = 0x05 // PLL with external 19.2MHz reference MPU6050Pwr1_ClockStop MPU6050Pwr1ClockConfig = 0x07 // Stops the clock and keeps the timing generator in reset mpu6050Pwr1_SleepOnBit = 0x40 // put into low power sleep mode mpu6050Pwr1_DeviceResetBit = 0x80 ) type MPU6050ThreeDData struct { X float64 Y float64 Z float64 } // MPU6050Driver is a Gobot Driver for an MPU6050 I2C Accelerometer/Gyroscope/Temperature sensor. // // This driver was tested with Tinkerboard & Digispark adaptor and a MPU6050 breakout board GY-521, // available from various distributors. // // datasheet: // https://product.tdk.com/system/files/dam/doc/product/sensor/mortion-inertial/imu/data_sheet/mpu-6000-datasheet1.pdf // // reference implementations: // * https://github.com/adafruit/Adafruit_CircuitPython_MPU6050 // * https://github.com/ElectronicCats/mpu6050 type MPU6050Driver struct { *Driver Accelerometer MPU6050ThreeDData Gyroscope MPU6050ThreeDData Temperature float64 dlpf MPU6050DlpfConfig frameSync MPU6050FrameSyncConfig accelFs MPU6050AccelFsConfig gyroFs MPU6050GyroFsConfig clock MPU6050Pwr1ClockConfig gravity float64 // set to 1.0 leads to [g] } // mpu6050AccelGain in 1/g var mpu6050AccelGain = map[MPU6050AccelFsConfig]uint16{ MPU6050Accel_AFsSel2g: 16384, MPU6050Accel_AFsSel4g: 8192, MPU6050Accel_AFsSel8g: 4096, MPU6050Accel_AFsSel16g: 2028, } // mpu6050GyroGain in s/° var mpu6050GyroGain = map[MPU6050GyroFsConfig]float64{ MPU6050Gyro_FsSel250dps: 131.0, MPU6050Gyro_FsSel500dps: 65.5, MPU6050Gyro_FsSel1000dps: 32.8, MPU6050Gyro_FsSel2000dps: 16.4, } // NewMPU6050Driver creates a new Gobot Driver for an MPU6050 I2C Accelerometer/Gyroscope/Temperature sensor. // // Params: // // conn Connector - the Adaptor to use with this Driver // // Optional params: // // i2c.WithBus(int): bus to use with this driver // i2c.WithAddress(int): address to use with this driver func NewMPU6050Driver(a Connector, options ...func(Config)) *MPU6050Driver { d := &MPU6050Driver{ Driver: NewDriver(a, "MPU6050", mpu6050DefaultAddress), dlpf: MPU6050General_Dlpf260Hz, frameSync: MPU6050General_FrameSyncDisabled, accelFs: MPU6050Accel_AFsSel2g, gyroFs: MPU6050Gyro_FsSel250dps, clock: MPU6050Pwr1_ClockPllXGyro, gravity: mpu6050EarthStandardGravity, } d.afterStart = d.initialize for _, option := range options { option(d) } // TODO: add commands to API return d } // WithMPU6050DigitalFilter option sets the digital low pass filter bandwidth frequency. // Valid settings are of type "MPU6050DlpfConfig" func WithMPU6050DigitalFilter(val MPU6050DlpfConfig) func(Config) { return func(c Config) { if d, ok := c.(*MPU6050Driver); ok { d.dlpf = val } else if mpu6050Debug { log.Printf("Trying to set digital low pass filter for non-MPU6050Driver %v", c) } } } // WithMPU6050FrameSync option sets the external frame synchronization. // Valid settings are of type "MPU6050FrameSyncConfig" func WithMPU6050FrameSync(val MPU6050FrameSyncConfig) func(Config) { return func(c Config) { if d, ok := c.(*MPU6050Driver); ok { d.frameSync = val } else if mpu6050Debug { log.Printf("Trying to set external frame synchronization for non-MPU6050Driver %v", c) } } } // WithMPU6050AccelFullScaleRange option sets the full scale range for the accelerometer. // Valid settings are of type "MPU6050AccelFsConfig" func WithMPU6050AccelFullScaleRange(val MPU6050AccelFsConfig) func(Config) { return func(c Config) { if d, ok := c.(*MPU6050Driver); ok { d.accelFs = val } else if mpu6050Debug { log.Printf("Trying to set full scale range of accelerometer for non-MPU6050Driver %v", c) } } } // WithMPU6050GyroFullScaleRange option sets the full scale range for the gyroscope. // Valid settings are of type "MPU6050GyroFsConfig" func WithMPU6050GyroFullScaleRange(val MPU6050GyroFsConfig) func(Config) { return func(c Config) { if d, ok := c.(*MPU6050Driver); ok { d.gyroFs = val } else if mpu6050Debug { log.Printf("Trying to set full scale range of gyroscope for non-MPU6050Driver %v", c) } } } // WithMPU6050ClockSource option sets the clock source. // Valid settings are of type "MPU6050Pwr1ClockConfig" func WithMPU6050ClockSource(val MPU6050Pwr1ClockConfig) func(Config) { return func(c Config) { if d, ok := c.(*MPU6050Driver); ok { d.clock = val } else if mpu6050Debug { log.Printf("Trying to set clock source for non-MPU6050Driver %v", c) } } } // WithMPU6050Gravity option sets the gravity in [m/s²/g]. // Useful settings are "1.0" (to use unit "g") or a value between 9.834 (pole) and 9.764 (equator) func WithMPU6050Gravity(val float64) func(Config) { return func(c Config) { if d, ok := c.(*MPU6050Driver); ok { d.gravity = val } else if mpu6050Debug { log.Printf("Trying to set gravity for non-MPU6050Driver %v", c) } } } // GetData fetches the latest data from the MPU6050 func (d *MPU6050Driver) GetData() error { d.mutex.Lock() defer d.mutex.Unlock() data := make([]byte, 14) if err := d.readBlockData(mpu6050Reg_AccelXoutH, data); err != nil { return err } var accel struct { X int16 Y int16 Z int16 } var temp int16 var gyro struct { X int16 Y int16 Z int16 } buf := bytes.NewBuffer(data) if err := binary.Read(buf, binary.BigEndian, &accel); err != nil { return err } if err := binary.Read(buf, binary.BigEndian, &temp); err != nil { return err } if err := binary.Read(buf, binary.BigEndian, &gyro); err != nil { return err } ag := float64(mpu6050AccelGain[d.accelFs]) / d.gravity d.Accelerometer.X = float64(accel.X) / ag d.Accelerometer.Y = float64(accel.Y) / ag d.Accelerometer.Z = float64(accel.Z) / ag d.Temperature = float64(temp)/340 + 36.53 gg := mpu6050GyroGain[d.gyroFs] d.Gyroscope.X = float64(gyro.X) / gg d.Gyroscope.Y = float64(gyro.Y) / gg d.Gyroscope.Z = float64(gyro.Z) / gg return nil } func (d *MPU6050Driver) waitForReset() error { wait := 100 * time.Millisecond start := time.Now() for { if time.Since(start) > wait { return fmt.Errorf("timeout on wait for reset is done") } if val, err := d.readByteData(mpu6050Reg_PwrMgmt1); (val&mpu6050Pwr1_DeviceResetBit == 0) && (err == nil) { return nil } time.Sleep(wait / 10) } } func (d *MPU6050Driver) initialize() error { // reset device and wait for reset is finished if err := d.writeByteData(mpu6050Reg_PwrMgmt1, mpu6050Pwr1_DeviceResetBit); err != nil { return err } if err := d.waitForReset(); err != nil { return err } // reset signal path register reset := uint8(mpu6050SignalReset_TempBit | mpu6050SignalReset_AccelBit | mpu6050SignalReset_GyroBit) if err := d.writeByteData(mpu6050Reg_SignalPathReset, reset); err != nil { return err } time.Sleep(100 * time.Millisecond) // configure digital filter bandwidth and external frame synchronization (bits 3...5 are used) generalConf := uint8(d.dlpf) | uint8(d.frameSync)<<3 if err := d.writeByteData(mpu6050Reg_GeneralConfig, generalConf); err != nil { return err } // set full scale range of gyroscope (bits 3 and 4 are used) if err := d.writeByteData(mpu6050Reg_GyroConfig, uint8(d.gyroFs)<<3); err != nil { return err } // set full scale range of accelerometer (bits 3 and 4 are used) if err := d.writeByteData(mpu6050Reg_AccelConfig, uint8(d.accelFs)<<3); err != nil { return err } // set clock source and reset sleep pwr1 := uint8(d.clock) & ^uint8(mpu6050Pwr1_SleepOnBit) return d.writeByteData(mpu6050Reg_PwrMgmt1, pwr1) } ================================================ FILE: drivers/i2c/mpu6050_driver_test.go ================================================ package i2c import ( "errors" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) // this ensures that the implementation is based on i2c.Driver, which implements the gobot.Driver // and tests all implementations, so no further tests needed here for gobot.Driver interface var _ gobot.Driver = (*MPU6050Driver)(nil) func initTestMPU6050WithStubbedAdaptor() (*MPU6050Driver, *i2cTestAdaptor) { a := newI2cTestAdaptor() d := NewMPU6050Driver(a) if err := d.Start(); err != nil { panic(err) } return d, a } func TestNewMPU6050Driver(t *testing.T) { var di interface{} = NewMPU6050Driver(newI2cTestAdaptor()) d, ok := di.(*MPU6050Driver) if !ok { require.Fail(t, "NewMPU6050Driver() should have returned a *MPU6050Driver") } assert.NotNil(t, d.Driver) assert.True(t, strings.HasPrefix(d.name, "MPU6050")) assert.Equal(t, 0x68, d.defaultAddress) assert.Equal(t, MPU6050DlpfConfig(0x00), d.dlpf) assert.Equal(t, MPU6050FrameSyncConfig(0x00), d.frameSync) assert.Equal(t, MPU6050AccelFsConfig(0x00), d.accelFs) assert.Equal(t, MPU6050GyroFsConfig(0x00), d.gyroFs) assert.Equal(t, MPU6050Pwr1ClockConfig(0x01), d.clock) assert.InDelta(t, 9.80665, d.gravity, 0.0) } func TestMPU6050Options(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithBus() option and // least one of this driver. Further tests for options can also be done by call of "WithOption(val)(d)". d := NewMPU6050Driver(newI2cTestAdaptor(), WithBus(2), WithMPU6050DigitalFilter(0x06)) assert.Equal(t, 2, d.GetBusOrDefault(1)) assert.Equal(t, MPU6050DlpfConfig(0x06), d.dlpf) } func TestMPU6050Halt(t *testing.T) { // arrange d := NewMPU6050Driver(newI2cTestAdaptor()) // act, assert require.NoError(t, d.Halt()) // must be idempotent require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestWithMPU6050FrameSync(t *testing.T) { d := NewMPU6050Driver(newI2cTestAdaptor(), WithMPU6050FrameSync(0x07)) assert.Equal(t, MPU6050FrameSyncConfig(0x07), d.frameSync) } func TestWithMPU6050AccelFullScaleRange(t *testing.T) { d := NewMPU6050Driver(newI2cTestAdaptor(), WithMPU6050AccelFullScaleRange(0x02)) assert.Equal(t, MPU6050AccelFsConfig(0x02), d.accelFs) } func TestWithMPU6050GyroFullScaleRange(t *testing.T) { d := NewMPU6050Driver(newI2cTestAdaptor(), WithMPU6050GyroFullScaleRange(0x03)) assert.Equal(t, MPU6050GyroFsConfig(0x03), d.gyroFs) } func TestWithMPU6050ClockSource(t *testing.T) { d := NewMPU6050Driver(newI2cTestAdaptor(), WithMPU6050ClockSource(0x05)) assert.Equal(t, MPU6050Pwr1ClockConfig(0x05), d.clock) } func TestWithMPU6050Gravity(t *testing.T) { d := NewMPU6050Driver(newI2cTestAdaptor(), WithMPU6050Gravity(1.0)) assert.InDelta(t, 1.0, d.gravity, 0.0) } func TestMPU6050GetData(t *testing.T) { // sequence to read values // * reset device and prepare config registers, see test for Start() // * write first data register address (0x3B) // * read 3 x 2 bytes acceleration.X, Y, Z data, little-endian (MSB, LSB) // * read 2 bytes temperature data, little-endian (MSB, LSB) // * read 3 x 2 bytes gyroscope.X, Y, Z data, little-endian (MSB, LSB) // * scale // Acceleration: raw value / gain * standard gravity [m/s²] // Temperature: raw value / 340 + 36.53 [°C] // Gyroscope: raw value / gain [°/s] // arrange d, adaptor := initTestMPU6050WithStubbedAdaptor() _ = d.Start() accData := []byte{0x00, 0x01, 0x02, 0x04, 0x08, 0x16} tempData := []byte{0x32, 0x64} gyroData := []byte{0x16, 0x08, 0x04, 0x02, 0x01, 0x00} wantAccel := MPU6050ThreeDData{ X: 0x0001 / 16384.0 * d.gravity, Y: 0x0204 / 16384.0 * d.gravity, Z: 0x0816 / 16384.0 * d.gravity, } wantGyro := MPU6050ThreeDData{ X: 0x1608 / 131.0, Y: 0x0402 / 131.0, Z: 0x0100 / 131.0, } wantTemp := float64(0x3264)/340 + 36.53 adaptor.i2cReadImpl = func(b []byte) (int, error) { copy(b, append(append(accData, tempData...), gyroData...)) return len(b), nil } // act _ = d.GetData() // assert assert.Equal(t, wantAccel, d.Accelerometer) assert.Equal(t, wantGyro, d.Gyroscope) assert.InDelta(t, wantTemp, d.Temperature, 0.0) } func TestMPU6050GetDataReadError(t *testing.T) { d, adaptor := initTestMPU6050WithStubbedAdaptor() _ = d.Start() adaptor.i2cReadImpl = func(b []byte) (int, error) { return 0, errors.New("read error") } require.ErrorContains(t, d.GetData(), "read error") } func TestMPU6050GetDataWriteError(t *testing.T) { d, adaptor := initTestMPU6050WithStubbedAdaptor() _ = d.Start() adaptor.i2cWriteImpl = func(b []byte) (int, error) { return 0, errors.New("write error") } require.ErrorContains(t, d.GetData(), "write error") } func TestMPU6050_initialize(t *testing.T) { // sequence for initialization the device on Start() // reset (according to data sheet) // * write power management 1 register address (0x6B) // * set device reset bit - write 0x80 // * read device reset bit until it becomes false (timeout 100 ms) // * write power management 1 register address (0x6B) // * read value // * wait some time before retry // * write signal path reset register address (0x68) // * reset all sensors - write 0x07 // * wait 100 ms // config // * write general config register address (0x1A) // * disable external sync and set filter bandwidth to 260 HZ - write 0x00 // * write gyroscope config register address (0x1B) // * set full scale to 250 °/s - write 0x00 // * write accelerometer config register address (0x1C) // * set full scale to 2 g - write 0x00 // * write power management 1 register address (0x6B) // * set clock source to PLL with X and switch off sleep bit - write 0x01 // arrange a := newI2cTestAdaptor() d := NewMPU6050Driver(a) readCallCounter := 0 a.i2cReadImpl = func(b []byte) (int, error) { readCallCounter++ // emulate ready b[0] = 0x00 return len(b), nil } // act, assert - initialize() must be called on Start() err := d.Start() // assert require.NoError(t, err) assert.Equal(t, 1, readCallCounter) assert.Len(t, a.written, 13) assert.Equal(t, uint8(0x6B), a.written[0]) assert.Equal(t, uint8(0x80), a.written[1]) assert.Equal(t, uint8(0x6B), a.written[2]) assert.Equal(t, uint8(0x68), a.written[3]) assert.Equal(t, uint8(0x07), a.written[4]) assert.Equal(t, uint8(0x1A), a.written[5]) assert.Equal(t, uint8(0x00), a.written[6]) assert.Equal(t, uint8(0x1B), a.written[7]) assert.Equal(t, uint8(0x00), a.written[8]) assert.Equal(t, uint8(0x1C), a.written[9]) assert.Equal(t, uint8(0x00), a.written[10]) assert.Equal(t, uint8(0x6B), a.written[11]) assert.Equal(t, uint8(0x01), a.written[12]) } ================================================ FILE: drivers/i2c/pca9501_driver.go ================================================ package i2c import "gobot.io/x/gobot/v2/drivers/common/bit" // PCA9501 supports addresses from 0x00 to 0x7F // 0x00 - 0x3F: GPIO, 0x40 - 0x7F: EEPROM // // 0 EE A5 A4 A3 A2 A1 A0|rd // Lowest bit (rd) is mapped to switch between write(0)/read(1), it is not part of the "real" address. // Highest bit (EE) is mapped to switch between GPIO(0)/EEPROM(1). // // The EEPROM address will be generated from GPIO address in this driver. const pca9501DefaultAddress = 0x3F // this applies, if all 6 address pins left open (have pull up resistors) // PCA9501Driver is a Gobot Driver for the PCA9501 8-bit GPIO & 2-kbit EEPROM with 6 address program pins. // 2-kbit EEPROM has 256 byte, means addresses between 0x00-0xFF // // please refer to data sheet: https://www.nxp.com/docs/en/data-sheet/PCA9501.pdf // // PCA9501 is the replacement for PCF8574, so this driver should also work for PCF8574 except EEPROM calls type PCA9501Driver struct { *Driver connectionMem Connection } // NewPCA9501Driver creates a new driver with specified i2c interface // Params: // // a Connector - the Adaptor to use with this Driver // // Optional params: // // i2c.WithBus(int): bus to use with this driver // i2c.WithAddress(int): address to use with this driver func NewPCA9501Driver(a Connector, options ...func(Config)) *PCA9501Driver { d := &PCA9501Driver{ Driver: NewDriver(a, "PCA9501", pca9501DefaultAddress, options...), } d.afterStart = d.initialize // API commands //nolint:forcetypeassert // ok here d.AddCommand("WriteGPIO", func(params map[string]interface{}) interface{} { pin := params["pin"].(uint8) val := params["val"].(uint8) err := d.WriteGPIO(pin, val) return map[string]interface{}{"err": err} }) //nolint:forcetypeassert // ok here d.AddCommand("ReadGPIO", func(params map[string]interface{}) interface{} { pin := params["pin"].(uint8) val, err := d.ReadGPIO(pin) return map[string]interface{}{"val": val, "err": err} }) //nolint:forcetypeassert // ok here d.AddCommand("WriteEEPROM", func(params map[string]interface{}) interface{} { address := params["address"].(uint8) val := params["val"].(uint8) err := d.WriteEEPROM(address, val) return map[string]interface{}{"err": err} }) //nolint:forcetypeassert // ok here d.AddCommand("ReadEEPROM", func(params map[string]interface{}) interface{} { address := params["address"].(uint8) val, err := d.ReadEEPROM(address) return map[string]interface{}{"val": val, "err": err} }) return d } // WriteGPIO writes a value to a gpio pin (0-7) func (d *PCA9501Driver) WriteGPIO(pin uint8, val uint8) error { d.mutex.Lock() defer d.mutex.Unlock() // read current value of CTRL register, 0 is output, 1 is no output iodir, err := d.readByte() if err != nil { return err } // set pin as output by clearing bit iodirVal := bit.Clear(int(iodir), pin) // write CTRL register err = d.writeByte(uint8(iodirVal)) //nolint:gosec // TODO: fix later if err != nil { return err } // read current value of port cVal, err := d.readByte() if err != nil { return err } // set or reset the bit in value var nVal int if val == 0 { nVal = bit.Clear(int(cVal), pin) } else { nVal = bit.Set(int(cVal), pin) } // write new value to port err = d.writeByte(uint8(nVal)) //nolint:gosec // TODO: fix later if err != nil { return err } return nil } // ReadGPIO reads a value from a given gpio pin (0-7) func (d *PCA9501Driver) ReadGPIO(pin uint8) (uint8, error) { d.mutex.Lock() defer d.mutex.Unlock() // read current value of CTRL register, 0 is no input, 1 is an input iodir, err := d.readByte() if err != nil { return 0, err } // set pin as input by setting bit iodirVal := bit.Set(int(iodir), pin) // write CTRL register err = d.writeByte(uint8(iodirVal)) //nolint:gosec // TODO: fix later if err != nil { return 0, err } // read port and create return bit val, err := d.readByte() if err != nil { return val, err } val = 1 << pin & val if val > 1 { val = 1 } return val, nil } // ReadEEPROM reads a value from a given address (0x00-0xFF) // Note: only this sequence for memory read is supported: "STARTW-DATA1-STARTR-DATA2-STOP" // DATA1: EEPROM address, DATA2: read value func (d *PCA9501Driver) ReadEEPROM(address uint8) (uint8, error) { d.mutex.Lock() defer d.mutex.Unlock() return d.connectionMem.ReadByteData(address) } // WriteEEPROM writes a value to a given address in memory (0x00-0xFF) func (d *PCA9501Driver) WriteEEPROM(address uint8, val uint8) error { d.mutex.Lock() defer d.mutex.Unlock() return d.connectionMem.WriteByteData(address, val) } func (d *PCA9501Driver) initialize() error { // initialize the EEPROM connection bus := d.GetBusOrDefault(d.connector.DefaultI2cBus()) addressMem := d.GetAddressOrDefault(pca9501DefaultAddress) | 0x40 var err error d.connectionMem, err = d.connector.GetI2cConnection(addressMem, bus) return err } ================================================ FILE: drivers/i2c/pca9501_driver_test.go ================================================ //nolint:forcetypeassert // ok here package i2c import ( "errors" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) // this ensures that the implementation is based on i2c.Driver, which implements the gobot.Driver // and tests all implementations, so no further tests needed here for gobot.Driver interface var _ gobot.Driver = (*PCA9501Driver)(nil) var ( pinVal = map[string]interface{}{ "pin": uint8(7), "val": uint8(0), } pin = map[string]interface{}{ "pin": uint8(7), } addressVal = map[string]interface{}{ "address": uint8(15), "val": uint8(7), } address = map[string]interface{}{ "address": uint8(15), } ) func initPCA9501WithStubbedAdaptor() (*PCA9501Driver, *i2cTestAdaptor) { a := newI2cTestAdaptor() d := NewPCA9501Driver(a) if err := d.Start(); err != nil { panic(err) } return d, a } func TestNewPCA9501Driver(t *testing.T) { // arrange, act var di interface{} = NewPCA9501Driver(newI2cTestAdaptor()) // assert d, ok := di.(*PCA9501Driver) if !ok { require.Fail(t, "NewPCA9501Driver() should have returned a *PCA9501Driver") } assert.NotNil(t, d.Driver) assert.True(t, strings.HasPrefix(d.Name(), "PCA9501")) assert.Equal(t, 0x3f, d.defaultAddress) } func TestPCA9501Options(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithBus() option and // least one of this driver. Further tests for options can also be done by call of "WithOption(val)(d)". d := NewPCA9501Driver(newI2cTestAdaptor(), WithBus(2)) assert.Equal(t, 2, d.GetBusOrDefault(1)) } func TestPCA9501Halt(t *testing.T) { // arrange d := NewPCA9501Driver(newI2cTestAdaptor()) // act, assert require.NoError(t, d.Halt()) // must be idempotent require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestPCA9501CommandsWriteGPIO(t *testing.T) { // arrange d, a := initPCA9501WithStubbedAdaptor() a.i2cReadImpl = func(b []byte) (int, error) { return len(b), nil } a.i2cWriteImpl = func([]byte) (int, error) { return 0, nil } // act result := d.Command("WriteGPIO")(pinVal) // assert assert.Nil(t, result.(map[string]interface{})["err"]) } func TestPCA9501CommandsReadGPIO(t *testing.T) { // arrange d, a := initPCA9501WithStubbedAdaptor() a.i2cReadImpl = func(b []byte) (int, error) { return len(b), nil } // act result := d.Command("ReadGPIO")(pin) // assert assert.Nil(t, result.(map[string]interface{})["err"]) } func TestPCA9501CommandsWriteEEPROM(t *testing.T) { // arrange d, a := initPCA9501WithStubbedAdaptor() a.i2cWriteImpl = func([]byte) (int, error) { return 0, nil } // act result := d.Command("WriteEEPROM")(addressVal) // assert assert.Nil(t, result.(map[string]interface{})["err"]) } func TestPCA9501CommandsReadEEPROM(t *testing.T) { // arrange d, a := initPCA9501WithStubbedAdaptor() a.i2cWriteImpl = func([]byte) (int, error) { return 0, nil } a.i2cReadImpl = func(b []byte) (int, error) { return len(b), nil } // act result := d.Command("ReadEEPROM")(address) // assert assert.Nil(t, result.(map[string]interface{})["err"]) } func TestPCA9501WriteGPIO(t *testing.T) { tests := map[string]struct { setVal uint8 ioDirAllInput uint8 ioStateAllInput uint8 pin uint8 wantPin uint8 wantState uint8 }{ "clear_bit": { setVal: 0, ioDirAllInput: 0xF1, ioStateAllInput: 0xF2, pin: 6, wantPin: 0xB1, wantState: 0xB2, }, "set_bit": { setVal: 2, ioDirAllInput: 0x1F, ioStateAllInput: 0x20, pin: 3, wantPin: 0x17, wantState: 0x28, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, a := initPCA9501WithStubbedAdaptor() // prepare all reads numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ if numCallsRead == 1 { // first call read current io direction of all pins b[0] = tc.ioDirAllInput } if numCallsRead == 2 { // second call read current state of all pins b[0] = tc.ioStateAllInput } return len(b), nil } // act err := d.WriteGPIO(tc.pin, tc.setVal) // assert require.NoError(t, err) assert.Equal(t, 2, numCallsRead) assert.Len(t, a.written, 2) assert.Equal(t, tc.wantPin, a.written[0]) assert.Equal(t, tc.wantState, a.written[1]) }) } } func TestPCA9501WriteGPIOErrorAtWriteDirection(t *testing.T) { // arrange d, a := initPCA9501WithStubbedAdaptor() wantErr := errors.New("write error") // prepare all reads numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ return len(b), nil } // prepare all writes numCallsWrite := 0 a.i2cWriteImpl = func([]byte) (int, error) { numCallsWrite++ if numCallsWrite == 1 { // first call writes the CTRL register for port direction return 0, wantErr } return 0, nil } // act err := d.WriteGPIO(7, 0) // assert assert.Equal(t, wantErr, err) assert.Less(t, numCallsRead, 2) assert.Equal(t, 1, numCallsWrite) } func TestPCA9501WriteGPIOErrorAtWriteValue(t *testing.T) { // arrange d, a := initPCA9501WithStubbedAdaptor() wantErr := errors.New("write error") // prepare all reads a.i2cReadImpl = func(b []byte) (int, error) { return len(b), nil } // prepare all writes numCallsWrite := 0 a.i2cWriteImpl = func([]byte) (int, error) { numCallsWrite++ if numCallsWrite == 2 { // second call writes the value to IO port return 0, wantErr } return 0, nil } // act err := d.WriteGPIO(7, 0) // assert assert.Equal(t, wantErr, err) assert.Equal(t, 2, numCallsWrite) } func TestPCA9501ReadGPIO(t *testing.T) { tests := map[string]struct { ctrlState uint8 want uint8 }{ "pin_is_set": {ctrlState: 0x80, want: 1}, "pin_is_not_set": {ctrlState: 0x7F, want: 0}, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange const ( pin = uint8(7) wantCtrlState = uint8(0x80) ) d, a := initPCA9501WithStubbedAdaptor() // prepare all reads numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ if numCallsRead == 1 { // current state of io b[0] = 0x00 } if numCallsRead == 2 { b[0] = tc.ctrlState } return len(b), nil } // act got, err := d.ReadGPIO(pin) // assert require.NoError(t, err) assert.Equal(t, tc.want, got) assert.Equal(t, 2, numCallsRead) assert.Len(t, a.written, 1) assert.Equal(t, wantCtrlState, a.written[0]) }) } } func TestPCA9501ReadGPIOErrorAtReadDirection(t *testing.T) { // arrange d, a := initPCA9501WithStubbedAdaptor() wantErr := errors.New("read error") // prepare all reads numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ if numCallsRead == 1 { // first read gets the CTRL register for pin direction return 0, wantErr } return len(b), nil } // prepare all writes numCallsWrite := 0 a.i2cWriteImpl = func([]byte) (int, error) { numCallsWrite++ return 0, nil } // act _, err := d.ReadGPIO(1) // assert assert.Equal(t, wantErr, err) assert.Equal(t, 1, numCallsRead) assert.Equal(t, 0, numCallsWrite) } func TestPCA9501ReadGPIOErrorAtReadValue(t *testing.T) { // arrange d, a := initPCA9501WithStubbedAdaptor() wantErr := errors.New("read error") // prepare all reads numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ if numCallsRead == 2 { // second read gets the value from IO port return 0, wantErr } return len(b), nil } // prepare all writes numCallsWrite := 0 a.i2cWriteImpl = func([]byte) (int, error) { numCallsWrite++ return 0, nil } // act _, err := d.ReadGPIO(2) // assert assert.Equal(t, wantErr, err) assert.Equal(t, 1, numCallsWrite) } func TestPCA9501WriteEEPROM(t *testing.T) { // arrange const ( addressEEPROM = uint8(0x52) want = uint8(0x25) ) d, a := initPCA9501WithStubbedAdaptor() // prepare all writes numCallsWrite := 0 a.i2cWriteImpl = func([]byte) (int, error) { numCallsWrite++ return 0, nil } // act err := d.WriteEEPROM(addressEEPROM, want) // assert require.NoError(t, err) assert.Equal(t, 1, numCallsWrite) assert.Equal(t, addressEEPROM, a.written[0]) assert.Equal(t, want, a.written[1]) } func TestPCA9501ReadEEPROM(t *testing.T) { // arrange const ( addressEEPROM = uint8(51) want = uint8(0x44) ) d, a := initPCA9501WithStubbedAdaptor() // prepare all writes numCallsWrite := 0 a.i2cWriteImpl = func(b []byte) (int, error) { numCallsWrite++ return 0, nil } // prepare all reads numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ b[0] = want return len(b), nil } // act val, err := d.ReadEEPROM(addressEEPROM) // assert require.NoError(t, err) assert.Equal(t, want, val) assert.Equal(t, 1, numCallsWrite) assert.Equal(t, addressEEPROM, a.written[0]) assert.Equal(t, 1, numCallsRead) } func TestPCA9501ReadEEPROMErrorWhileWriteAddress(t *testing.T) { // arrange d, a := initPCA9501WithStubbedAdaptor() wantErr := errors.New("error while write") // prepare all writes a.i2cWriteImpl = func([]byte) (int, error) { return 0, wantErr } // prepare all reads numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ return len(b), nil } // act _, err := d.ReadEEPROM(15) // assert assert.Equal(t, wantErr, err) assert.Equal(t, 0, numCallsRead) } func TestPCA9501ReadEEPROMErrorWhileReadValue(t *testing.T) { // arrange d, a := initPCA9501WithStubbedAdaptor() wantErr := errors.New("error while read") // prepare all writes numCallsWrite := 0 a.i2cWriteImpl = func([]byte) (int, error) { numCallsWrite++ return 0, nil } // prepare all reads a.i2cReadImpl = func(b []byte) (int, error) { return len(b), wantErr } // act _, err := d.ReadEEPROM(15) // assert assert.Equal(t, 1, numCallsWrite) assert.Equal(t, wantErr, err) } func TestPCA9501_initialize(t *testing.T) { // arrange const want = 0x7f d, a := initPCA9501WithStubbedAdaptor() // act err := d.initialize() // assert require.NoError(t, err) assert.Equal(t, want, a.address) } ================================================ FILE: drivers/i2c/pca953x_driver.go ================================================ package i2c import ( "fmt" ) // pca953xDefaultAddress is set to variant PCA9533/2 const ( pca953xDebug = false pca953xDefaultAddress = 0x63 ) type pca953xRegister uint8 // PCA953xGPIOMode is used to set the mode while write GPIO type PCA953xGPIOMode uint8 const ( pca953xRegInp pca953xRegister = 0x00 // input register pca953xRegPsc0 pca953xRegister = 0x01 // r, frequency prescaler 0 pca953xRegPwm0 pca953xRegister = 0x02 // r/w, PWM register 0 pca953xRegPsc1 pca953xRegister = 0x03 // r/w, frequency prescaler 1 pca953xRegPwm1 pca953xRegister = 0x04 // r/w, PWM register 1 pca953xRegLs0 pca953xRegister = 0x05 // r/w, LED selector 0 pca953xRegLs1 pca953xRegister = 0x06 // r/w, LED selector 1 (only in PCA9531, PCA9532) pca953xAiMask = 0x10 // autoincrement bit // PCA953xModeHighImpedance set the GPIO to high (LED off) PCA953xModeHighImpedance PCA953xGPIOMode = 0x00 // PCA953xModeLowImpedance set the GPIO to low (LED on) PCA953xModeLowImpedance PCA953xGPIOMode = 0x01 // PCA953xModePwm0 set the GPIO to PWM (PWM0 & PSC0) PCA953xModePwm0 PCA953xGPIOMode = 0x02 // PCA953xModePwm1 set the GPIO to PWM (PWM1 & PSC1) PCA953xModePwm1 PCA953xGPIOMode = 0x03 ) var ( errToSmallPeriod = fmt.Errorf("given Period to small, must be at least 1/152s (~6.58ms) or 152Hz") errToBigPeriod = fmt.Errorf("given Period to high, must be max. 256/152s (~1.68s) or 152/256Hz (~0.6Hz)") errToSmallDutyCycle = fmt.Errorf("given Duty Cycle to small, must be at least 0%%") errToBigDutyCycle = fmt.Errorf("given Duty Cycle to high, must be max. 100%%") ) // PCA953xDriver is a Gobot Driver for LED Dimmer PCA9530 (2-bit), PCA9533 (4-bit), PCA9531 (8-bit), PCA9532 (16-bit) // Although this is designed for LED's it can be used as a GPIO (read, write, pwm). // The names of the public functions reflect this. // // please refer to data sheet: https://www.nxp.com/docs/en/data-sheet/PCA9533.pdf // // Address range: // * PCA9530 0x60-0x61 (96-97 dec) // * PCA9531 0x60-0x67 (96-103 dec) // * PCA9532 0x60-0x67 (96-103 dec) // * PCA9533/1 0x62 (98 dec) // * PCA9533/2 0x63 (99 dec) // // each new command must start by setting the register and the AI flag // 0 0 0 AI | 0 R2 R1 R0 // AI=1 means auto incrementing for R0-R2, which enable reading/writing all registers sequentially // when AI=1 and reading, then R!=0 // this means: do not start with reading input register, writing input register is recognized but has no effect // => when AI=1 in general start with R>0 type PCA953xDriver struct { *Driver } // NewPCA953xDriver creates a new driver with specified i2c interface // Params: // // conn Connector - the Adaptor to use with this Driver // // Optional params: // // i2c.WithBus(int): bus to use with this driver // i2c.WithAddress(int): address to use with this driver func NewPCA953xDriver(c Connector, options ...func(Config)) *PCA953xDriver { d := &PCA953xDriver{ Driver: NewDriver(c, "PCA953x", pca953xDefaultAddress), } for _, option := range options { option(d) } // TODO: API commands return d } // SetLED sets the mode (LED off, on, PWM0, PWM1) for the LED output (index 0-7) func (d *PCA953xDriver) SetLED(idx uint8, mode PCA953xGPIOMode) error { d.mutex.Lock() defer d.mutex.Unlock() return d.writeLED(idx, mode) } // WriteGPIO writes a value to a gpio output (index 0-7) func (d *PCA953xDriver) WriteGPIO(idx uint8, val uint8) error { d.mutex.Lock() defer d.mutex.Unlock() mode := PCA953xModeLowImpedance if val > 0 { mode = PCA953xModeHighImpedance } return d.writeLED(idx, mode) } // ReadGPIO reads a gpio input (index 0-7) to a value func (d *PCA953xDriver) ReadGPIO(idx uint8) (uint8, error) { d.mutex.Lock() defer d.mutex.Unlock() // read input register val, err := d.readRegister(pca953xRegInp) // create return bit if err != nil { return val, err } val = 1 << idx & val if val > 1 { val = 1 } return val, nil } // WritePeriod set the content of the frequency prescaler of the given index (0,1) with the given value in seconds func (d *PCA953xDriver) WritePeriod(idx uint8, valSec float32) error { d.mutex.Lock() defer d.mutex.Unlock() // period is valid in range ~6.58ms..1.68s val, err := pca953xCalcPsc(valSec) if err != nil && pca953xDebug { fmt.Println(err, "value limited!") } regPsc := pca953xRegPsc0 if idx > 0 { regPsc = pca953xRegPsc1 } return d.writeRegister(regPsc, val) } // ReadPeriod reads the frequency prescaler in seconds of the given index (0,1) func (d *PCA953xDriver) ReadPeriod(idx uint8) (float32, error) { d.mutex.Lock() defer d.mutex.Unlock() regPsc := pca953xRegPsc0 if idx > 0 { regPsc = pca953xRegPsc1 } psc, err := d.readRegister(regPsc) if err != nil { return -1, err } return pca953xCalcPeriod(psc), nil } // WriteFrequency set the content of the frequency prescaler of the given index (0,1) with the given value in Hz func (d *PCA953xDriver) WriteFrequency(idx uint8, valHz float32) error { d.mutex.Lock() defer d.mutex.Unlock() // frequency is valid in range ~0.6..152Hz val, err := pca953xCalcPsc(1 / valHz) if err != nil && pca953xDebug { fmt.Println(err, "value limited!") } regPsc := pca953xRegPsc0 if idx > 0 { regPsc = pca953xRegPsc1 } return d.writeRegister(regPsc, val) } // ReadFrequency read the frequency prescaler in Hz of the given index (0,1) func (d *PCA953xDriver) ReadFrequency(idx uint8) (float32, error) { d.mutex.Lock() defer d.mutex.Unlock() regPsc := pca953xRegPsc0 if idx > 0 { regPsc = pca953xRegPsc1 } psc, err := d.readRegister(regPsc) if err != nil { return -1, err } // valHz = 1/valSec return 1 / pca953xCalcPeriod(psc), nil } // WriteDutyCyclePercent set the PWM duty cycle of the given index (0,1) with the given value in percent func (d *PCA953xDriver) WriteDutyCyclePercent(idx uint8, valPercent float32) error { d.mutex.Lock() defer d.mutex.Unlock() val, err := pca953xCalcPwm(valPercent) if err != nil && pca953xDebug { fmt.Println(err, "value limited!") } regPwm := pca953xRegPwm0 if idx > 0 { regPwm = pca953xRegPwm1 } return d.writeRegister(regPwm, val) } // ReadDutyCyclePercent get the PWM duty cycle in percent of the given index (0,1) func (d *PCA953xDriver) ReadDutyCyclePercent(idx uint8) (float32, error) { d.mutex.Lock() defer d.mutex.Unlock() regPwm := pca953xRegPwm0 if idx > 0 { regPwm = pca953xRegPwm1 } pwm, err := d.readRegister(regPwm) if err != nil { return -1, err } // PWM=0..255 return pca953xCalcDutyCyclePercent(pwm), nil } func (d *PCA953xDriver) writeLED(idx uint8, mode PCA953xGPIOMode) error { // prepare regLs := pca953xRegLs0 if idx > 3 { regLs = pca953xRegLs1 idx = idx - 4 } regLsShift := idx * 2 // read old value regLsVal, err := d.readRegister(regLs) if err != nil { return err } // reset 2 bits at LED position regLsVal &= ^uint8(0x03 << regLsShift) // set 2 bits according to mode at LED position regLsVal |= uint8(mode) << regLsShift // write new value return d.writeRegister(regLs, regLsVal) } func (d *PCA953xDriver) writeRegister(regAddress pca953xRegister, val uint8) error { // ensure AI bit is not set regAddress = regAddress &^ pca953xAiMask // write content of requested register return d.writeByteData(uint8(regAddress), val) } func (d *PCA953xDriver) readRegister(regAddress pca953xRegister) (uint8, error) { // ensure AI bit is not set regAddress = regAddress &^ pca953xAiMask return d.readByteData(uint8(regAddress)) } func pca953xCalcPsc(valSec float32) (uint8, error) { // valSec = (PSC+1)/152; (PSC=0..255) psc := 152*valSec - 1 if psc < 0 { return 0, errToSmallPeriod } if psc > 255 { return 255, errToBigPeriod } // add 0.5 for better rounding experience return uint8(psc + 0.5), nil } func pca953xCalcPeriod(psc uint8) float32 { return (float32(psc) + 1) / 152 } func pca953xCalcPwm(valPercent float32) (uint8, error) { // valPercent = PWM/256*(256/255*100); (PWM=0..255) pwm := 255 * valPercent / 100 if pwm < 0 { return 0, errToSmallDutyCycle } if pwm > 255 { return 255, errToBigDutyCycle } // add 0.5 for better rounding experience return uint8(pwm + 0.5), nil } func pca953xCalcDutyCyclePercent(pwm uint8) float32 { return 100 * float32(pwm) / 255 } ================================================ FILE: drivers/i2c/pca953x_driver_test.go ================================================ package i2c import ( "fmt" "math" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) // this ensures that the implementation is based on i2c.Driver, which implements the gobot.Driver // and tests all implementations, so no further tests needed here for gobot.Driver interface var _ gobot.Driver = (*PCA953xDriver)(nil) func initPCA953xTestDriverWithStubbedAdaptor() (*PCA953xDriver, *i2cTestAdaptor) { a := newI2cTestAdaptor() d := NewPCA953xDriver(a) _ = d.Start() return d, a } func TestNewPCA953xDriver(t *testing.T) { // arrange, act var di interface{} = NewPCA953xDriver(newI2cTestAdaptor()) // assert d, ok := di.(*PCA953xDriver) if !ok { require.Fail(t, "NewPCA953xDriver() should have returned a *PCA953xDriver") } assert.NotNil(t, d.Driver) assert.True(t, strings.HasPrefix(d.Name(), "PCA953x")) assert.Equal(t, 0x63, d.defaultAddress) } func TestPCA953xHalt(t *testing.T) { // arrange d := NewPCA953xDriver(newI2cTestAdaptor()) // act, assert require.NoError(t, d.Halt()) // must be idempotent require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestPCA953xWriteGPIO(t *testing.T) { // sequence to write: // * choose LED select register according to the given GPIO index (0x05 for 0..3, 0x06 for 4..7) // * read current state of LED select register (write reg, read val) // * modify 2 bits according to given index of GPIO // * write the new state to the LED select register (write reg, write val) tests := map[string]struct { idx uint8 ls0State uint8 ls1State uint8 val uint8 wantWritten []uint8 wantErr error }{ "out_0_0": { idx: 0, ls0State: 0xFE, ls1State: 0xAF, val: 0, wantWritten: []byte{0x05, 0x05, 0xFD}, // set lowest bits to "01" for ls0 }, "out_0_1": { idx: 0, ls0State: 0xFF, ls1State: 0xAF, val: 1, wantWritten: []byte{0x05, 0x05, 0xFC}, // set lowest bits to "00" for ls0 }, "out_5_0": { idx: 5, ls0State: 0xAF, ls1State: 0xFB, val: 0, wantWritten: []byte{0x06, 0x06, 0xF7}, // set bit 2,3 to "01" for ls1 }, "out_5_1": { idx: 5, ls0State: 0xAF, ls1State: 0xFF, val: 1, wantWritten: []byte{0x06, 0x06, 0xF3}, // set bit 2,3 to "00" for ls1 }, "read_error": { idx: 3, wantWritten: []byte{0x05}, wantErr: fmt.Errorf("a read error"), }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, a := initPCA953xTestDriverWithStubbedAdaptor() a.written = []byte{} // reset writes of Start() and former test a.i2cReadImpl = func(b []byte) (int, error) { if a.written[0] == 0x05 { b[0] = tc.ls0State } if a.written[0] == 0x06 { b[0] = tc.ls1State } return 1, tc.wantErr } // act err := d.WriteGPIO(tc.idx, tc.val) // assert assert.Equal(t, tc.wantErr, err) assert.Equal(t, tc.wantWritten, a.written) }) } } func TestPCA953xReadGPIO(t *testing.T) { // sequence to read: // * read current state of INPUT register (write reg 0x00, read val) // * convert bit position to output value tests := map[string]struct { idx uint8 want uint8 wantErr error }{ "in_0_0": { idx: 0, want: 0, }, "in_0_1": { idx: 0, want: 1, }, "in_2_0": { idx: 2, want: 0, }, "in_2_1": { idx: 2, want: 1, }, "in_7_0": { idx: 7, want: 0, }, "in_7_1": { idx: 7, want: 1, }, "read_error": { idx: 2, want: 0, wantErr: fmt.Errorf("a read error"), }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange const wantReg = uint8(0x00) // input register d, a := initPCA953xTestDriverWithStubbedAdaptor() a.written = []byte{} // reset writes of Start() and former test bits := tc.want << tc.idx a.i2cReadImpl = func(b []byte) (int, error) { b[0] = bits return 1, tc.wantErr } // act got, err := d.ReadGPIO(tc.idx) // assert assert.Equal(t, tc.wantErr, err) assert.Len(t, a.written, 1) assert.Equal(t, wantReg, a.written[0]) assert.Equal(t, tc.want, got) }) } } func TestPCA953xWritePeriod(t *testing.T) { // sequence to write: // * calculate PSC value (0..255) from given value in seconds, valid values are 0.00658 ... 1.68 [s] // * choose PSC0 (0x01) or PSC1 (0x03) frequency prescaler register by the given index // * write the value to the register (write reg, write val) tests := map[string]struct { idx uint8 val float32 wantWritten []uint8 }{ "write_ok_psc0": { idx: 0, val: 1, wantWritten: []byte{0x01, 151}, }, "write_ok_psc1": { idx: 2, val: 0.5, wantWritten: []byte{0x03, 75}, }, "write_limited_noerror": { idx: 0, val: 2, wantWritten: []byte{0x01, 255}, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, a := initPCA953xTestDriverWithStubbedAdaptor() a.written = []byte{} // reset writes of Start() and former test // act err := d.WritePeriod(tc.idx, tc.val) // assert require.NoError(t, err) assert.Equal(t, tc.wantWritten, a.written) }) } } func TestPCA953xReadPeriod(t *testing.T) { // sequence to write: // * choose PSC0 (0x01) or PSC1 (0x03) frequency prescaler register by the given index // * read the value from the register (write reg, write val) // * calculate value in seconds from PSC value tests := map[string]struct { idx uint8 val uint8 want float32 wantWritten []uint8 wantErr error }{ "read_ok_psc0": { idx: 0, val: 151, want: 1, wantWritten: []byte{0x01}, }, "read_ok_psc1": { idx: 1, val: 75, want: 0.5, wantWritten: []byte{0x03}, }, "read_error": { idx: 5, val: 75, want: -1, wantWritten: []byte{0x03}, wantErr: fmt.Errorf("read psc error"), }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, a := initPCA953xTestDriverWithStubbedAdaptor() a.written = []byte{} // reset writes of Start() and former test a.i2cReadImpl = func(b []byte) (int, error) { b[0] = tc.val return 1, tc.wantErr } // act got, err := d.ReadPeriod(tc.idx) // assert assert.Equal(t, tc.wantErr, err) assert.InDelta(t, tc.want, got, 0.0) assert.Equal(t, tc.wantWritten, a.written) }) } } func TestPCA953xWriteFrequency(t *testing.T) { // sequence to write: // * calculate PSC value (0..255) from given value in Hz, valid values are 0.6 ... 152 [Hz] // * choose PSC0 (0x01) or PSC1 (0x03) frequency prescaler register by the given index // * write the value to the register (write reg, write val) tests := map[string]struct { idx uint8 val float32 wantWritten []uint8 }{ "write_ok_psc0": { idx: 0, val: 1, wantWritten: []byte{0x01, 151}, }, "write_ok_psc1": { idx: 5, val: 2, wantWritten: []byte{0x03, 75}, }, "write_limited_noerror": { idx: 0, val: 153, wantWritten: []byte{0x01, 0}, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, a := initPCA953xTestDriverWithStubbedAdaptor() a.written = []byte{} // reset writes of Start() and former test // act err := d.WriteFrequency(tc.idx, tc.val) // assert require.NoError(t, err) assert.Equal(t, tc.wantWritten, a.written) }) } } func TestPCA953xReadFrequency(t *testing.T) { // sequence to write: // * choose PSC0 (0x01) or PSC1 (0x03) frequency prescaler register by the given index // * read the value from the register (write reg, write val) // * calculate value in Hz from PSC value tests := map[string]struct { idx uint8 val uint8 want float32 wantWritten []uint8 wantErr error }{ "read_ok_psc0": { idx: 0, val: 75, want: 2, wantWritten: []byte{0x01}, }, "read_ok_psc1": { idx: 1, val: 151, want: 1, wantWritten: []byte{0x03}, }, "read_error": { idx: 3, val: 75, want: -1, wantWritten: []byte{0x03}, wantErr: fmt.Errorf("read psc error"), }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, a := initPCA953xTestDriverWithStubbedAdaptor() a.written = []byte{} // reset writes of Start() and former test a.i2cReadImpl = func(b []byte) (int, error) { b[0] = tc.val return 1, tc.wantErr } // act got, err := d.ReadFrequency(tc.idx) // assert assert.Equal(t, tc.wantErr, err) assert.InDelta(t, tc.want, got, 0.0) assert.Equal(t, tc.wantWritten, a.written) }) } } func TestPCA953xWriteDutyCyclePercent(t *testing.T) { // sequence to write: // * calculate PWM value (0..255) from given value in percent, valid values are 0 ... 100 [%] // * choose PWM0 (0x02) or PWM1 (0x04) pwm register by the given index // * write the value to the register (write reg, write val) tests := map[string]struct { idx uint8 val float32 wantWritten []uint8 }{ "write_ok_pwm0": { idx: 0, val: 10, wantWritten: []byte{0x02, 26}, }, "write_ok_pwm1": { idx: 5, val: 50, wantWritten: []byte{0x04, 128}, }, "write_limited_noerror": { idx: 1, val: 101, wantWritten: []byte{0x04, 255}, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, a := initPCA953xTestDriverWithStubbedAdaptor() a.written = []byte{} // reset writes of Start() and former test // act err := d.WriteDutyCyclePercent(tc.idx, tc.val) // assert require.NoError(t, err) assert.Equal(t, tc.wantWritten, a.written) }) } } func TestPCA953xReadDutyCyclePercent(t *testing.T) { // sequence to write: // * choose PWM0 (0x02) or PWM1 (0x04) pwm register by the given index // * read the value from the register (write reg, write val) // * calculate value percent from PWM value tests := map[string]struct { idx uint8 val uint8 want float32 wantWritten []uint8 wantErr error }{ "read_ok_psc0": { idx: 0, val: 128, want: 50.19608, wantWritten: []byte{0x02}, }, "read_ok_psc1": { idx: 1, val: 26, want: 10.196078, wantWritten: []byte{0x04}, }, "read_error": { idx: 0, val: 75, want: -1, wantWritten: []byte{0x02}, wantErr: fmt.Errorf("read psc error"), }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, a := initPCA953xTestDriverWithStubbedAdaptor() a.written = []byte{} // reset writes of Start() and former test a.i2cReadImpl = func(b []byte) (int, error) { b[0] = tc.val return 1, tc.wantErr } // act got, err := d.ReadDutyCyclePercent(tc.idx) // assert assert.Equal(t, tc.wantErr, err) assert.InDelta(t, tc.want, got, 0.0) assert.Equal(t, tc.wantWritten, a.written) }) } } func TestPCA953x_readRegister(t *testing.T) { // arrange const ( wantRegAddress = pca953xRegister(0x03) wantReadByteCount = 1 wantRegVal = uint8(0x04) ) readByteCount := 0 d, a := initPCA953xTestDriverWithStubbedAdaptor() // prepare all writes numCallsWrite := 0 a.i2cWriteImpl = func([]byte) (int, error) { numCallsWrite++ return 0, nil } // prepare all reads numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ readByteCount = len(b) b[0] = wantRegVal return readByteCount, nil } // act val, err := d.readRegister(wantRegAddress) // assert require.NoError(t, err) assert.Equal(t, 1, numCallsRead) assert.Equal(t, 1, numCallsWrite) assert.Equal(t, wantRegVal, val) assert.Equal(t, wantReadByteCount, readByteCount) assert.Len(t, a.written, 1) assert.Equal(t, uint8(wantRegAddress), a.written[0]) } func TestPCA953x_writeRegister(t *testing.T) { // arrange const ( wantRegAddress = pca953xRegister(0x03) wantRegVal = uint8(0x97) wantByteCount = 2 ) d, a := initPCA953xTestDriverWithStubbedAdaptor() // prepare all writes numCallsWrite := 0 a.i2cWriteImpl = func(b []byte) (int, error) { numCallsWrite++ return 0, nil } // act err := d.writeRegister(wantRegAddress, wantRegVal) // assert require.NoError(t, err) assert.Equal(t, 1, numCallsWrite) assert.Equal(t, 1, numCallsWrite) assert.Len(t, a.written, wantByteCount) assert.Equal(t, uint8(wantRegAddress), a.written[0]) assert.Equal(t, wantRegVal, a.written[1]) } func TestPCA953x_pca953xCalcPsc(t *testing.T) { // arrange tests := map[string]struct { period float32 want uint8 wantErr error }{ "error_to_small": {period: 0.0065, want: 0, wantErr: errToSmallPeriod}, "minimum": {period: 0.0066, want: 0, wantErr: nil}, "one": {period: 1, want: 151, wantErr: nil}, "maximum": {period: 1.684, want: 255, wantErr: nil}, "error_to_big5": {period: 1.685, want: 255, wantErr: errToBigPeriod}, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // act val, err := pca953xCalcPsc(tc.period) // assert assert.Equal(t, tc.wantErr, err) assert.Equal(t, tc.want, val) }) } } func TestPCA953x_pca953xCalcPeriod(t *testing.T) { // arrange tests := map[string]struct { psc uint8 want float32 }{ "minimum": {psc: 0, want: 0.0066}, "one": {psc: 1, want: 0.0132}, "one_want": {psc: 151, want: 1}, "maximum": {psc: 255, want: 1.6842}, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // act val := pca953xCalcPeriod(tc.psc) // assert assert.InDelta(t, tc.want, float32(math.Round(float64(val)*10000)/10000), 0.0) }) } } func TestPCA953x_pca953xCalcPwm(t *testing.T) { // arrange tests := map[string]struct { percent float32 want uint8 wantErr error }{ "error_to_small": {percent: -0.1, want: 0, wantErr: errToSmallDutyCycle}, "zero": {percent: 0, want: 0, wantErr: nil}, "below_medium": {percent: 49.9, want: 127, wantErr: nil}, "medium": {percent: 50, want: 128, wantErr: nil}, "maximum": {percent: 100, want: 255, wantErr: nil}, "error_to_big": {percent: 100.1, want: 255, wantErr: errToBigDutyCycle}, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // act val, err := pca953xCalcPwm(tc.percent) // assert assert.Equal(t, tc.wantErr, err) assert.Equal(t, tc.want, val) }) } } func TestPCA953x_pca953xCalcDutyCyclePercent(t *testing.T) { // arrange tests := map[string]struct { pwm uint8 want float32 }{ "minimum": {pwm: 0, want: 0}, "below_medium": {pwm: 127, want: 49.8}, "medium": {pwm: 128, want: 50.2}, "maximum": {pwm: 255, want: 100}, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // act val := pca953xCalcDutyCyclePercent(tc.pwm) // assert assert.InDelta(t, tc.want, float32(math.Round(float64(val)*10)/10), 0.0) }) } } ================================================ FILE: drivers/i2c/pca9685_driver.go ================================================ package i2c import ( "strconv" "time" "gobot.io/x/gobot/v2" ) const pca9685DefaultAddress = 0x40 const ( pca9685Mode1Reg = 0x00 pca9685Mode2Reg = 0x01 pca9685Subadr1Reg = 0x02 pca9685Subadr2Reg = 0x03 pca9685Subadr3Reg = 0x04 pca9685Led0OnLReg = 0x06 pca9685Led0OnHReg = 0x07 pca9685Led0OffLReg = 0x08 pca9685Led0OffHReg = 0x09 pca9685AllLedOnLReg = 0xFA pca9685AllLedOnHReg = 0xFB pca9685AllLedOffLReg = 0xFC pca9685AllLedOffHReg = 0xFD pca9685PrescaleReg = 0xFE pca9685Mode1RegRestartBit = 0x80 // bit 7 - 0: restart disabled (default) pca9685Mode1RegSleepBit = 0x10 // bit 4 - 0: normal, 1: low power (default) pca9685Mode1RegAllCallBit = 0x01 // bit 0 - 0: no response to all-call, 1: respond to all-call (default) pca9685Mode2RegInvertBit = 0x10 // bit 4 - 0: outputs not inverted (default), 1: outputs inverted pca9685Mode2RegOutdrvBit = 0x04 // bit 2 - 0: open-drain, 1: totem-pole (default) pca9685AllLedOffHRegShutDown = 0x10 // bit 4 - 1: orderly shut down ) // PCA9685Driver is a Gobot Driver for the PCA9685 16-channel 12-bit PWM/Servo controller. // // For example, here is the Adafruit board that uses this chip: // https://www.adafruit.com/product/815 type PCA9685Driver struct { *Driver } // NewPCA9685Driver creates a new driver with specified i2c interface // Params: // // c Connector - the Adaptor to use with this Driver // // Optional params: // // i2c.WithBus(int): bus to use with this driver // i2c.WithAddress(int): address to use with this driver func NewPCA9685Driver(c Connector, options ...func(Config)) *PCA9685Driver { d := &PCA9685Driver{ Driver: NewDriver(c, "PCA9685", pca9685DefaultAddress), } d.afterStart = d.initialize d.beforeHalt = d.shutdown for _, option := range options { option(d) } //nolint:forcetypeassert // ok here d.AddCommand("PwmWrite", func(params map[string]interface{}) interface{} { pin := params["pin"].(string) val, _ := strconv.Atoi(params["val"].(string)) return d.PwmWrite(pin, byte(val)) }) //nolint:forcetypeassert // ok here d.AddCommand("ServoWrite", func(params map[string]interface{}) interface{} { pin := params["pin"].(string) val, _ := strconv.Atoi(params["val"].(string)) return d.ServoWrite(pin, byte(val)) }) //nolint:forcetypeassert // ok here d.AddCommand("SetPWM", func(params map[string]interface{}) interface{} { channel, _ := strconv.Atoi(params["channel"].(string)) on, _ := strconv.Atoi(params["on"].(string)) off, _ := strconv.Atoi(params["off"].(string)) return d.SetPWM(channel, uint16(on), uint16(off)) //nolint:gosec // TODO: fix later }) //nolint:forcetypeassert // ok here d.AddCommand("SetPWMFreq", func(params map[string]interface{}) interface{} { freq, _ := strconv.ParseFloat(params["freq"].(string), 32) return d.SetPWMFreq(float32(freq)) }) return d } // SetPWM sets a specific channel to a pwm value from 0-4095. // Params: // // channel int - the channel to send the pulse // on uint16 - the time to start the pulse // off uint16 - the time to stop the pulse // // Most typically you set "on" to a zero value, and then set "off" to your desired duty. func (d *PCA9685Driver) SetPWM(channel int, on uint16, off uint16) error { if _, err := d.write([]byte{byte(pca9685Led0OnLReg + 4*channel), byte(on) & 0xFF}); err != nil { return err } if _, err := d.write([]byte{byte(pca9685Led0OnHReg + 4*channel), byte(on >> 8)}); err != nil { return err } if _, err := d.write([]byte{byte(pca9685Led0OffLReg + 4*channel), byte(off) & 0xFF}); err != nil { return err } _, err := d.write([]byte{byte(pca9685Led0OffHReg + 4*channel), byte(off >> 8)}) return err } // SetAllPWM sets all channels to a pwm value from 0-4095. // Params: // // on uint16 - the time to start the pulse // off uint16 - the time to stop the pulse // // Most typically you set "on" to a zero value, and then set "off" to your desired duty. func (d *PCA9685Driver) SetAllPWM(on uint16, off uint16) error { if _, err := d.write([]byte{byte(pca9685AllLedOnLReg), byte(on) & 0xFF}); err != nil { return err } if _, err := d.write([]byte{byte(pca9685AllLedOnHReg), byte(on >> 8)}); err != nil { return err } if _, err := d.write([]byte{byte(pca9685AllLedOffLReg), byte(off) & 0xFF}); err != nil { return err } _, err := d.write([]byte{byte(pca9685AllLedOffHReg), byte(off >> 8)}) return err } // SetPWMFreq sets the PWM frequency in Hz between 24Hz and 1526Hz, the default is 200Hz. func (d *PCA9685Driver) SetPWMFreq(freq float32) error { // internal IC oscillator frequency is 25 MHz var prescalevel float32 = 25000000 // find frequency of PWM waveform prescalevel /= 4096 // ratio between desired frequency and maximum prescalevel /= freq prescalevel-- // round value to nearest whole prescale := byte(prescalevel + 0.5) if _, err := d.write([]byte{byte(pca9685Mode1Reg)}); err != nil { return err } oldmode, err := d.readByte() if err != nil { return err } // put oscillator in sleep mode, clear the restart bit 7 here to prevent unneeded restart sleepMode := (oldmode &^ pca9685Mode1RegRestartBit) | pca9685Mode1RegSleepBit if _, err := d.write([]byte{byte(pca9685Mode1Reg), sleepMode}); err != nil { return err } // write prescaler value if _, err := d.write([]byte{byte(pca9685PrescaleReg), prescale}); err != nil { return err } // put back to old settings, ensure no sleep noSleepMode := oldmode &^ pca9685Mode1RegSleepBit if _, err := d.write([]byte{byte(pca9685Mode1Reg), noSleepMode}); err != nil { return err } // wait >500us according to data sheet time.Sleep(5 * time.Millisecond) // initiate a restart restartMode := oldmode | pca9685Mode1RegRestartBit _, err = d.write([]byte{byte(pca9685Mode1Reg), restartMode}) return err } // PwmWrite writes a PWM signal to the specified channel aka "pin". // Value values are from 0-255, to conform to the PwmWriter interface. // If you need finer control, please look at SetPWM(). func (d *PCA9685Driver) PwmWrite(pin string, val byte) error { i, err := strconv.Atoi(pin) if err != nil { return err } v := gobot.ToScale(gobot.FromScale(float64(val), 0, 255), 0, 4095) return d.SetPWM(i, 0, uint16(v)) } // ServoWrite writes a servo signal to the specified channel aka "pin". // Valid values are from 0-180, to conform to the ServoWriter interface. // If you need finer control, please look at SetPWM(). func (d *PCA9685Driver) ServoWrite(pin string, val byte) error { i, err := strconv.Atoi(pin) if err != nil { return err } v := gobot.ToScale(gobot.FromScale(float64(val), 0, 180), 200, 500) return d.SetPWM(i, 0, uint16(v)) } // initialize the driver according to the data sheet section "7.3.1.1 Restart mode" // * ensure the sleep bit is unset // * wait > 500us // * write a logic 1 to bit 7 (RESTART) of register "MODE1" func (d *PCA9685Driver) initialize() error { if err := d.SetAllPWM(0, 0); err != nil { return err } // set not inverted (default), outputs change on stop (default), OE reaction to 0 (default), totem-pole (default) if _, err := d.write([]byte{pca9685Mode2Reg, pca9685Mode2RegOutdrvBit}); err != nil { return err } // reset of sleep bit together with set of no restart (default), internal clock (default), no AI (default), // no response to sub address 1, 2 or 3 (default), activate response to all-call (default) if _, err := d.write([]byte{pca9685Mode1Reg, pca9685Mode1RegAllCallBit}); err != nil { return err } time.Sleep(5 * time.Millisecond) // initiate the restart if _, err := d.write([]byte{byte(pca9685Mode1Reg)}); err != nil { return err } oldmode, err := d.readByte() if err != nil { return err } oldmode = oldmode | byte(pca9685Mode1RegRestartBit) if _, err := d.write([]byte{pca9685Mode1Reg, oldmode}); err != nil { return err } time.Sleep(5 * time.Millisecond) return nil } func (d *PCA9685Driver) shutdown() error { if d.connection == nil { return nil } _, err := d.write([]byte{pca9685AllLedOffHReg, pca9685AllLedOffHRegShutDown}) return err } ================================================ FILE: drivers/i2c/pca9685_driver_test.go ================================================ package i2c import ( "errors" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" ) // this ensures that the implementation is based on i2c.Driver, which implements the gobot.Driver // and tests all implementations, so no further tests needed here for gobot.Driver interface var _ gobot.Driver = (*PCA9685Driver)(nil) // and also the PwmWriter and ServoWriter interfaces var ( _ gpio.PwmWriter = (*PCA9685Driver)(nil) _ gpio.ServoWriter = (*PCA9685Driver)(nil) ) func initTestPCA9685WithStubbedAdaptor() (*PCA9685Driver, *i2cTestAdaptor) { a := newI2cTestAdaptor() d := NewPCA9685Driver(a) if err := d.Start(); err != nil { panic(err) } return d, a } func TestNewPCA9685Driver(t *testing.T) { // arrange & act d := NewPCA9685Driver(newI2cTestAdaptor()) // assert assert.IsType(t, &PCA9685Driver{}, d) assert.NotNil(t, d.Driver) assert.True(t, strings.HasPrefix(d.Name(), "PCA9685")) assert.Equal(t, 0x40, d.defaultAddress) } func TestPCA9685Options(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithBus() option and // least one of this driver. Further tests for options can also be done by call of "WithOption(val)(d)". // arrange & act d := NewPCA9685Driver(newI2cTestAdaptor(), WithBus(2)) // assert assert.Equal(t, 2, d.GetBusOrDefault(1)) } func TestPCA9685Start(t *testing.T) { // arrange a := newI2cTestAdaptor() d := NewPCA9685Driver(a) a.i2cReadImpl = func(b []byte) (int, error) { copy(b, []byte{0x01}) return 1, nil } // act & assert require.NoError(t, d.Start()) } func TestPCA9685StartError(t *testing.T) { // arrange a := newI2cTestAdaptor() d := NewPCA9685Driver(a) a.i2cWriteImpl = func([]byte) (int, error) { return 0, errors.New("write error") } // act & assert require.ErrorContains(t, d.Start(), "write error") } func TestPCA9685Halt(t *testing.T) { // arrange d, a := initTestPCA9685WithStubbedAdaptor() a.written = []byte{} // reset writes of former test // act err := d.Halt() // assert require.NoError(t, err) require.NoError(t, err) assert.Len(t, a.written, 2) assert.Equal(t, []byte{0xFD, 0x10}, a.written) } func TestPCA9685HaltError(t *testing.T) { // arrange d, a := initTestPCA9685WithStubbedAdaptor() a.i2cWriteImpl = func([]byte) (int, error) { return 0, errors.New("write error") } // act & assert require.ErrorContains(t, d.Halt(), "write error") } func TestPCA9685HaltIdempotent(t *testing.T) { // arrange d := NewPCA9685Driver(newI2cTestAdaptor()) // act, assert require.NoError(t, d.Halt()) // must be idempotent require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestPCA9685SetPWM(t *testing.T) { // sequence to set PWM for PCA9685: // * set LEDn ON-time register (n=0: 0x06, 0x07, n=1: 0x0A, 0x0B ... n=14: 0x3E, 0x3F, n=15: 0x42, 0x43) // * set LEDn OFF-time register (n=0: 0x08, 0x09, n=1: 0x0C, 0x0D ... n=14: 0x40, 0x41, n=15: 0x44, 0x45) tests := map[string]struct { pin int onCounts uint16 offCounts uint16 wantLedOnTimeOffTimeSet []uint8 }{ "example1_datasheet": { pin: 0, onCounts: 409, offCounts: 1228, wantLedOnTimeOffTimeSet: []uint8{0x06, 0x99, 0x07, 0x01, 0x08, 0xCC, 0x09, 0x04}, }, "example2_datasheet": { pin: 4, onCounts: 3685, offCounts: 3275, wantLedOnTimeOffTimeSet: []uint8{0x16, 0x65, 0x17, 0x0E, 0x18, 0xCB, 0x19, 0x0C}, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, a := initTestPCA9685WithStubbedAdaptor() a.written = []byte{} // reset writes of former test // act err := d.SetPWM(tc.pin, tc.onCounts, tc.offCounts) // assert require.NoError(t, err) assert.Len(t, a.written, 8) for writeIdx, wantVal := range tc.wantLedOnTimeOffTimeSet { assert.Equal(t, wantVal, a.written[writeIdx], "index %d differs", writeIdx) } }) } } func TestPCA9685SetPWMError(t *testing.T) { // arrange d, a := initTestPCA9685WithStubbedAdaptor() a.i2cWriteImpl = func([]byte) (int, error) { return 0, errors.New("write error") } // act & assert require.ErrorContains(t, d.SetPWM(0, 0, 256), "write error") } func TestPCA9685SetAllPWM(t *testing.T) { // sequence to set PWM for PCA9685: // * set LEDn ON-time register (n=0: 0x06, 0x07, n=1: 0x0A, 0x0B ... n=14: 0x3E, 0x3F, n=15: 0x42, 0x43) // * set LEDn OFF-time register (n=0: 0x08, 0x09, n=1: 0x0C, 0x0D ... n=14: 0x40, 0x41, n=15: 0x44, 0x45) tests := map[string]struct { pin byte onCounts uint16 offCounts uint16 wantLedOnTimeOffTimeSet []uint8 }{ "example1_datasheet": { onCounts: 409, offCounts: 1228, wantLedOnTimeOffTimeSet: []uint8{0xFA, 0x99, 0xFB, 0x01, 0xFC, 0xCC, 0xFD, 0x04}, }, "example2_datasheet": { onCounts: 3685, offCounts: 3275, wantLedOnTimeOffTimeSet: []uint8{0xFA, 0x65, 0xFB, 0x0E, 0xFC, 0xCB, 0xFD, 0x0C}, }, "own_example": { onCounts: 1234, offCounts: 4321, wantLedOnTimeOffTimeSet: []uint8{0xFA, 0xD2, 0xFB, 0x04, 0xFC, 0xE1, 0xFD, 0x10}, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, a := initTestPCA9685WithStubbedAdaptor() a.written = []byte{} // reset writes of former test // act err := d.SetAllPWM(tc.onCounts, tc.offCounts) // assert require.NoError(t, err) assert.Len(t, a.written, 8) for writeIdx, wantVal := range tc.wantLedOnTimeOffTimeSet { assert.Equal(t, wantVal, a.written[writeIdx], "index %d differs", writeIdx) } }) } } func TestPCA9685SetAllPWMError(t *testing.T) { // arrange d, a := initTestPCA9685WithStubbedAdaptor() a.i2cWriteImpl = func([]byte) (int, error) { return 0, errors.New("write error") } // act & assert require.ErrorContains(t, d.SetAllPWM(0, 256), "write error") } func TestPCA9685SetPWMFreq(t *testing.T) { // sequence to set PWM frequency prescaler for PCA9685 (can only be set in sleep mode): // * read MODE1 register (0x00) // * prepare MODE1 register with sleep mode set (bit 4 - 0x10, no stopping of PWM channels done before) // * write MODE1 register // * write the prescaler value to PRE_SCALE register (0xFE) // * prepare MIODE1 register with sleep mode bit reset // * write MODE1 register // * wait > 500us // * prepare the MODE1 register with set of reset bit // * write MODE1 register const readMode1Val = 0x0F // to check for only sleep mode bit (0x10) or reset bit (0x80) will be set var ( wantMode1SleepSequence = []uint8{0x00, 0x1F} wantMode1NoSleepSequence = []uint8{0x00, readMode1Val} wantMode1ResetSequence = []uint8{0x00, 0x8F} ) tests := map[string]struct { freq float32 wantPrescalerSequence []uint8 }{ "example_datasheet": { freq: 200, wantPrescalerSequence: []uint8{0xFE, 0x1E}, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, a := initTestPCA9685WithStubbedAdaptor() // arrange read for MODE1 register numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ b[0] = readMode1Val return len(b), nil } a.written = []byte{} // reset writes of former test // act err := d.SetPWMFreq(tc.freq) // assert require.NoError(t, err) assert.Len(t, a.written, 9) var writeIdx int // for read old mode: assert.Equal(t, wantMode1SleepSequence[0], a.written[writeIdx], "index %d differs", writeIdx) writeIdx++ for idx, wantVal := range wantMode1SleepSequence { assert.Equal(t, wantVal, a.written[writeIdx], "index %d (%d) differs", writeIdx, idx) writeIdx++ } for idx, wantVal := range tc.wantPrescalerSequence { assert.Equal(t, wantVal, a.written[writeIdx], "index %d (%d) differs", writeIdx, idx) writeIdx++ } for idx, wantVal := range wantMode1NoSleepSequence { assert.Equal(t, wantVal, a.written[writeIdx], "index %d (%d) differs", writeIdx, idx) writeIdx++ } for idx, wantVal := range wantMode1ResetSequence { assert.Equal(t, wantVal, a.written[writeIdx], "index %d (%d) differs", writeIdx, idx) writeIdx++ } assert.Equal(t, 1, numCallsRead) }) } } func TestPCA9685SetPWMFreqReadError(t *testing.T) { // arrange d, a := initTestPCA9685WithStubbedAdaptor() a.i2cReadImpl = func(b []byte) (int, error) { return 0, errors.New("read error") } // act & assert require.ErrorContains(t, d.SetPWMFreq(60), "read error") } func TestPCA9685SetPWMFreqWriteError(t *testing.T) { // arrange d, a := initTestPCA9685WithStubbedAdaptor() a.i2cWriteImpl = func([]byte) (int, error) { return 0, errors.New("write error") } // act & assert require.ErrorContains(t, d.SetPWMFreq(60), "write error") } func TestPCA9685Commands(t *testing.T) { // arrange d, _ := initTestPCA9685WithStubbedAdaptor() // act & assert assert.Nil(t, d.Command("PwmWrite")(map[string]interface{}{"pin": "1", "val": "1"})) assert.Nil(t, d.Command("ServoWrite")(map[string]interface{}{"pin": "1", "val": "1"})) assert.Nil(t, d.Command("SetPWM")(map[string]interface{}{"channel": "1", "on": "0", "off": "1024"})) assert.Nil(t, d.Command("SetPWMFreq")(map[string]interface{}{"freq": "60"})) } func TestPCA9685_initialize(t *testing.T) { // sequence to reset the PCA9685 in initialize(): // * set all LED ON-time and OFF-time registers (0xFA..0xFD for 16 channels, each for low and high byte) // * set MODE2 register (0x01) to defaults: not inverted, outputs change on stop, OE reaction to 0, totem-pole // * set MODE1 register (0x00) to defaults, except sleep: no restart, internal clock, no AI, no sleep (not default), // no response to sub address 1, 2 or 3, activate response to all-call // * wait > 500us, read back the MODE1 register // * prepare the MODE1 register with set of reset bit // * write MODE1 register // arrange d, a := initTestPCA9685WithStubbedAdaptor() a.written = []byte{} // reset writes of former test wantAllLedOnTimeOffTimeSequence := []uint8{0xFA, 0x00, 0xFB, 0x00, 0xFC, 0x00, 0xFD, 0x00} wantMode2RegSetDefaultsSequence := []uint8{0x01, 0x04} wantMode1RegSetDefaultsNoSleepSequence := []uint8{0x00, 0x01} wantMode1RegResetSequence := []uint8{0x00, 0x81} // arrange read for MODE1 register numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ b[0] = wantMode1RegSetDefaultsNoSleepSequence[1] return len(b), nil } // act, assert - initialize() must be called on Start() err := d.Start() // assert require.NoError(t, err) assert.Len(t, a.written, 15) var writeIdx int for idx, wantVal := range wantAllLedOnTimeOffTimeSequence { assert.Equal(t, wantVal, a.written[writeIdx], "index %d (%d) differs", writeIdx, idx) writeIdx++ } for idx, wantVal := range wantMode2RegSetDefaultsSequence { assert.Equal(t, wantVal, a.written[writeIdx], "index %d (%d) differs", writeIdx, idx) writeIdx++ } for idx, wantVal := range wantMode1RegSetDefaultsNoSleepSequence { assert.Equal(t, wantVal, a.written[writeIdx], "index %d (%d) differs", writeIdx, idx) writeIdx++ } // for read old mode: assert.Equal(t, wantMode1RegSetDefaultsNoSleepSequence[0], a.written[writeIdx], "index %d differs", writeIdx) writeIdx++ for idx, wantVal := range wantMode1RegResetSequence { assert.Equal(t, wantVal, a.written[writeIdx], "index %d (%d) differs", writeIdx, idx) writeIdx++ } assert.Equal(t, 1, numCallsRead) } ================================================ FILE: drivers/i2c/pcf8583_driver.go ================================================ package i2c import ( "fmt" "log" "time" ) const ( pcf8583Debug = false // PCF8583 supports addresses 0x50 and 0x51 // The default address applies when the address pin is grounded. pcf8583DefaultAddress = 0x50 // default is 0x10, when set to 0 also some free or unused RAM can be accessed pcf8583RamOffset = 0x10 ) // PCF8583Control is used to specify control and status register content type PCF8583Control uint8 const ( // registers are named according to the datasheet pcf8583Reg_CTRL = iota // 0x00 pcf8583Reg_SUBSEC_D0D1 // 0x01 pcf8583Reg_SEC_D2D3 // 0x02 pcf8583Reg_MIN_D4D5 // 0x03 pcf8583Reg_HOUR // 0x04 pcf8583Reg_YEARDATE // 0x05 pcf8583Reg_WEEKDAYMONTH // 0x06 pcf8583Reg_TIMER // 0x07 pcf8583Reg_ALARMCTRL // 0x08, offset for all alarm registers 0x09 ... 0xF pcf8583CtrlTimerFlag PCF8583Control = 0x01 // 50% duty factor, seconds flag if alarm enable bit is 0 pcf8583CtrlAlarmFlag PCF8583Control = 0x02 // 50% duty factor, minutes flag if alarm enable bit is 0 pcf8583CtrlAlarmEnable PCF8583Control = 0x04 // if enabled, memory 08h is alarm control register pcf8583CtrlMask PCF8583Control = 0x08 // 0: read 05h, 06h unmasked, 1: read date and month count directly PCF8583CtrlModeClock50 PCF8583Control = 0x10 // clock mode with 50 Hz PCF8583CtrlModeCounter PCF8583Control = 0x20 // event counter mode PCF8583CtrlModeTest PCF8583Control = 0x30 // test mode pcf8583CtrlHoldLastCount PCF8583Control = 0x40 // 0: count, 1: store and hold count in capture latches pcf8583CtrlStopCounting PCF8583Control = 0x80 // 0: count, 1: stop counting, reset divider ) // PCF8583Driver is a driver for the PCF8583 clock and calendar chip & 240 x 8-bit bit RAM with 1 address program pin. // please refer to data sheet: https://www.nxp.com/docs/en/data-sheet/PCF8583.pdf // // 0 1 0 1 0 0 0 A0|rd // Lowest bit (rd) is mapped to switch between write(0)/read(1), it is not part of the "real" address. // // # PCF8583 is mainly compatible to PCF8593, so this driver should also work for PCF8593 except RAM calls // // This driver was tested with Tinkerboard. type PCF8583Driver struct { *Driver mode PCF8583Control // clock 32.768kHz (default), clock 50Hz, event counter yearOffset int ramOffset byte } // NewPCF8583Driver creates a new driver with specified i2c interface // Params: // // c Connector - the Adaptor to use with this Driver // // Optional params: // // i2c.WithBus(int): bus to use with this driver // i2c.WithAddress(int): address to use with this driver // i2c.WithPCF8583Mode(PCF8583Control): mode of this driver func NewPCF8583Driver(c Connector, options ...func(Config)) *PCF8583Driver { d := &PCF8583Driver{ Driver: NewDriver(c, "PCF8583", pcf8583DefaultAddress), ramOffset: pcf8583RamOffset, } d.afterStart = d.initialize for _, option := range options { option(d) } // API commands //nolint:forcetypeassert // ok here d.AddCommand("WriteTime", func(params map[string]interface{}) interface{} { val := params["val"].(time.Time) err := d.WriteTime(val) return map[string]interface{}{"err": err} }) d.AddCommand("ReadTime", func(_ map[string]interface{}) interface{} { val, err := d.ReadTime() return map[string]interface{}{"val": val, "err": err} }) //nolint:forcetypeassert // ok here d.AddCommand("WriteCounter", func(params map[string]interface{}) interface{} { val := params["val"].(int32) err := d.WriteCounter(val) return map[string]interface{}{"err": err} }) d.AddCommand("ReadCounter", func(_ map[string]interface{}) interface{} { val, err := d.ReadCounter() return map[string]interface{}{"val": val, "err": err} }) //nolint:forcetypeassert // ok here d.AddCommand("WriteRAM", func(params map[string]interface{}) interface{} { address := params["address"].(uint8) val := params["val"].(uint8) err := d.WriteRAM(address, val) return map[string]interface{}{"err": err} }) //nolint:forcetypeassert // ok here d.AddCommand("ReadRAM", func(params map[string]interface{}) interface{} { address := params["address"].(uint8) val, err := d.ReadRAM(address) return map[string]interface{}{"val": val, "err": err} }) return d } // WithPCF8583Mode is used to change the mode between 32.678kHz clock, 50Hz clock, event counter // Valid settings are of type "PCF8583Control" func WithPCF8583Mode(mode PCF8583Control) func(Config) { return func(c Config) { d, ok := c.(*PCF8583Driver) if ok { if !mode.isClockMode() && !mode.isCounterMode() { panic(fmt.Sprintf("%s: mode 0x%02x is not supported", d.name, mode)) } d.mode = mode } else if pcf8583Debug { log.Printf("trying to set mode for non-PCF8583Driver %v", c) } } } // WriteTime setup the clock registers with the given time func (d *PCF8583Driver) WriteTime(val time.Time) error { d.mutex.Lock() defer d.mutex.Unlock() // according to chapter 7.11 of the product data sheet, the stop counting flag of the control/status register // must be set before, so we read the control byte before and only set/reset the stop ctrlRegVal, err := d.readByteData(uint8(pcf8583Reg_CTRL)) if err != nil { return err } if !PCF8583Control(ctrlRegVal).isClockMode() { return fmt.Errorf("%s: can't write time because the device is in wrong mode 0x%02x", d.name, ctrlRegVal) } year, month, day := val.Date() err = d.writeBlockData(uint8(pcf8583Reg_CTRL), []byte{ ctrlRegVal | uint8(pcf8583CtrlStopCounting), // sub seconds in 1/10th seconds pcf8583encodeBcd(uint8(val.Nanosecond() / 1000000 / 10)), //nolint:gosec // TODO: fix later pcf8583encodeBcd(uint8(val.Second())), //nolint:gosec // TODO: fix later pcf8583encodeBcd(uint8(val.Minute())), //nolint:gosec // TODO: fix later pcf8583encodeBcd(uint8(val.Hour())), //nolint:gosec // TODO: fix later // year, date (we keep the year counter zero and set the offset) pcf8583encodeBcd(uint8(day)), //nolint:gosec // TODO: fix later // month, weekday (not BCD): Sunday = 0, Monday = 1 ... uint8(val.Weekday())<<5 | pcf8583encodeBcd(uint8(month)), //nolint:gosec // TODO: fix later }) if err != nil { return err } d.yearOffset = year return d.run(ctrlRegVal) } // ReadTime reads the clock and returns the value func (d *PCF8583Driver) ReadTime() (time.Time, error) { d.mutex.Lock() defer d.mutex.Unlock() // according to chapter 7.1 of the product data sheet, the setting of "hold last count" flag // is not needed when reading with auto increment ctrlRegVal, err := d.readByteData(uint8(pcf8583Reg_CTRL)) if err != nil { return time.Time{}, err } if !PCF8583Control(ctrlRegVal).isClockMode() { return time.Time{}, fmt.Errorf("%s: can't read time because the device is in wrong mode 0x%02x", d.name, ctrlRegVal) } // auto increment feature is used clockDataSize := 6 data := make([]byte, clockDataSize) read, err := d.read(data) if err != nil { return time.Time{}, err } if read != clockDataSize { return time.Time{}, fmt.Errorf("%s: %d bytes read, but %d expected", d.name, read, clockDataSize) } nanos := int(pcf8583decodeBcd(data[0])) * 1000000 * 10 // sub seconds in 1/10th seconds seconds := int(pcf8583decodeBcd(data[1])) minutes := int(pcf8583decodeBcd(data[2])) hours := int(pcf8583decodeBcd(data[3])) // year, date (the device can only count 4 years) year := int(data[4]>>6) + d.yearOffset // use the first two bits, no BCD date := int(pcf8583decodeBcd(data[4] & 0x3F)) // remove the year-bits for date // weekday (not used here), month month := time.Month(pcf8583decodeBcd(data[5] & 0x1F)) // remove the weekday-bits return time.Date(year, month, date, hours, minutes, seconds, nanos, time.UTC), nil } // WriteCounter writes the counter registers func (d *PCF8583Driver) WriteCounter(val int32) error { d.mutex.Lock() defer d.mutex.Unlock() // we don't care of negative values here // according to chapter 7.11 of the product data sheet, the stop counting flag of the control/status register // must be set before, so we read the control byte before and only set/reset the stop ctrlRegVal, err := d.readByteData(uint8(pcf8583Reg_CTRL)) if err != nil { return err } if !PCF8583Control(ctrlRegVal).isCounterMode() { return fmt.Errorf("%s: can't write counter because the device is in wrong mode 0x%02x", d.name, ctrlRegVal) } err = d.writeBlockData(uint8(pcf8583Reg_CTRL), []byte{ ctrlRegVal | uint8(pcf8583CtrlStopCounting), // stop //nolint:gosec // TODO: fix later pcf8583encodeBcd(uint8(val % 100)), // 2 lowest digits //nolint:gosec // TODO: fix later pcf8583encodeBcd(uint8((val / 100) % 100)), // 2 middle digits //nolint:gosec // TODO: fix later pcf8583encodeBcd(uint8((val / 10000) % 100)), // 2 highest digits }) if err != nil { return err } return d.run(ctrlRegVal) } // ReadCounter reads the counter registers func (d *PCF8583Driver) ReadCounter() (int32, error) { d.mutex.Lock() defer d.mutex.Unlock() // according to chapter 7.1 of the product data sheet, the setting of "hold last count" flag // is not needed when reading with auto increment ctrlRegVal, err := d.readByteData(uint8(pcf8583Reg_CTRL)) if err != nil { return 0, err } if !PCF8583Control(ctrlRegVal).isCounterMode() { return 0, fmt.Errorf("%s: can't read counter because the device is in wrong mode 0x%02x", d.name, ctrlRegVal) } // auto increment feature is used counterDataSize := 3 data := make([]byte, counterDataSize) read, err := d.read(data) if err != nil { return 0, err } if read != counterDataSize { return 0, fmt.Errorf("%s: %d bytes read, but %d expected", d.name, read, counterDataSize) } return int32(pcf8583decodeBcd(data[0])) + int32(pcf8583decodeBcd(data[1]))*100 + int32(pcf8583decodeBcd(data[2]))*10000, nil } // WriteRAM writes a value to a given address in memory (0x00-0xFF) func (d *PCF8583Driver) WriteRAM(address uint8, val uint8) error { d.mutex.Lock() defer d.mutex.Unlock() realAddress := uint16(address) + uint16(d.ramOffset) if realAddress > 0xFF { return fmt.Errorf("%s: RAM address overflow %d", d.name, realAddress) } return d.writeByteData(uint8(realAddress), val) } // ReadRAM reads a value from a given address (0x00-0xFF) func (d *PCF8583Driver) ReadRAM(address uint8) (uint8, error) { d.mutex.Lock() defer d.mutex.Unlock() realAddress := uint16(address) + uint16(d.ramOffset) if realAddress > 0xFF { return 0, fmt.Errorf("%s: RAM address overflow %d", d.name, realAddress) } return d.readByteData(uint8(realAddress)) } func (d *PCF8583Driver) run(ctrlRegVal uint8) error { ctrlRegVal = ctrlRegVal & ^uint8(pcf8583CtrlStopCounting) // reset stop bit return d.writeByteData(uint8(pcf8583Reg_CTRL), ctrlRegVal) } func (d *PCF8583Driver) initialize() error { // switch to configured mode ctrlRegVal, err := d.readByteData(uint8(pcf8583Reg_CTRL)) if err != nil { return err } if d.mode.isModeDiffer(PCF8583Control(ctrlRegVal)) { ctrlRegVal = ctrlRegVal&^uint8(PCF8583CtrlModeTest) | uint8(d.mode) if err = d.writeByteData(uint8(pcf8583Reg_CTRL), ctrlRegVal); err != nil { return err } if pcf8583Debug { if PCF8583Control(ctrlRegVal).isCounterMode() { log.Printf("%s switched to counter mode 0x%02x", d.name, ctrlRegVal) } else { log.Printf("%s switched to clock mode 0x%02x", d.name, ctrlRegVal) } } } return nil } func (c PCF8583Control) isClockMode() bool { return uint8(c)&uint8(PCF8583CtrlModeCounter) == 0 } func (c PCF8583Control) isCounterMode() bool { counterModeSet := (uint8(c) & uint8(PCF8583CtrlModeCounter)) != 0 clockMode50Set := (uint8(c) & uint8(PCF8583CtrlModeClock50)) != 0 return counterModeSet && !clockMode50Set } func (c PCF8583Control) isModeDiffer(mode PCF8583Control) bool { return uint8(c)&uint8(PCF8583CtrlModeTest) != uint8(mode)&uint8(PCF8583CtrlModeTest) } func pcf8583encodeBcd(val byte) byte { // decimal 12 => 0x12 if val > 99 { val = 99 if pcf8583Debug { log.Printf("PCF8583 BCD value (%d) exceeds limit of 99, now limited.", val) } } hi, lo := val/10, val%10 return hi<<4 | lo } func pcf8583decodeBcd(bcd byte) byte { // 0x12 => decimal 12 hi, lo := bcd>>4, bcd&0x0f if hi > 9 { hi = 9 if pcf8583Debug { log.Printf("PCF8583 BCD value (%02x) exceeds limit 0x99 on most significant digit, now limited", bcd) } } if lo > 9 { lo = 9 if pcf8583Debug { log.Printf("PCF8583 BCD value (%02x) exceeds limit 0x99 on least significant digit, now limited", bcd) } } return 10*hi + lo } ================================================ FILE: drivers/i2c/pcf8583_driver_test.go ================================================ //nolint:forcetypeassert // ok here package i2c import ( "strings" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) // this ensures that the implementation is based on i2c.Driver, which implements the gobot.Driver // and tests all implementations, so no further tests needed here for gobot.Driver interface var _ gobot.Driver = (*PCF8583Driver)(nil) func initTestPCF8583WithStubbedAdaptor() (*PCF8583Driver, *i2cTestAdaptor) { a := newI2cTestAdaptor() d := NewPCF8583Driver(a) _ = d.Start() return d, a } func TestNewPCF8583Driver(t *testing.T) { var di interface{} = NewPCF8583Driver(newI2cTestAdaptor()) d, ok := di.(*PCF8583Driver) if !ok { require.Fail(t, "NewPCF8583Driver() should have returned a *PCF8583Driver") } assert.NotNil(t, d.Driver) assert.True(t, strings.HasPrefix(d.name, "PCF8583")) assert.Equal(t, 0x50, d.defaultAddress) assert.Equal(t, PCF8583Control(0x00), d.mode) assert.Equal(t, 0, d.yearOffset) assert.Equal(t, uint8(0x10), d.ramOffset) } func TestPCF8583Halt(t *testing.T) { // arrange d := NewPCF8583Driver(newI2cTestAdaptor()) // act, assert require.NoError(t, d.Halt()) // must be idempotent require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestPCF8583Options(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithBus() option and // least one of this driver. Further tests for options can also be done by call of "WithOption(val)(d)". d := NewPCF8583Driver(newI2cTestAdaptor(), WithBus(2), WithPCF8583Mode(PCF8583CtrlModeClock50)) assert.Equal(t, 2, d.GetBusOrDefault(1)) assert.Equal(t, PCF8583CtrlModeClock50, d.mode) } func TestPCF8583CommandsWriteTime(t *testing.T) { // arrange d, a := initTestPCF8583WithStubbedAdaptor() readCtrlState := uint8(0x10) // clock 50Hz // arrange writes a.i2cWriteImpl = func(b []byte) (int, error) { return len(b), nil } // arrange reads numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ b[len(b)-1] = readCtrlState return len(b), nil } // act result := d.Command("WriteTime")(map[string]interface{}{"val": time.Now()}) // assert assert.Nil(t, result.(map[string]interface{})["err"]) } func TestPCF8583CommandsReadTime(t *testing.T) { // arrange d, a := initTestPCF8583WithStubbedAdaptor() d.yearOffset = 2019 const millis = 550 * time.Millisecond // 0.55 sec = 550 ms want := time.Date(2021, time.December, 24, 18, 0, 0, int(millis), time.UTC) reg0Val := uint8(0x00) // clock mode 32.768 kHz reg1Val := uint8(0x55) // BCD: 1/10 and 1/100 sec (55) reg2Val := uint8(0x00) // BCD: 10 and 1 sec (00) reg3Val := uint8(0x00) // BCD: 10 and 1 min (00) reg4Val := uint8(0x18) // BCD: 10 and 1 hour (18) reg5Val := uint8(0xA4) // year (2) and BCD: date (24) reg6Val := uint8(0xB2) // weekday 5, bit 5 and bit 7 (0xA0) and BCD: month (0x12) returnRead := [2][]uint8{ {reg0Val}, {reg1Val, reg2Val, reg3Val, reg4Val, reg5Val, reg6Val}, } // arrange reads // arrange reads numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ rr := returnRead[numCallsRead-1] for i := 0; i < len(b); i++ { b[i] = rr[i] } return len(b), nil } // act result := d.Command("ReadTime")(map[string]interface{}{}) // assert assert.Nil(t, result.(map[string]interface{})["err"]) assert.Equal(t, want, result.(map[string]interface{})["val"]) } func TestPCF8583CommandsWriteCounter(t *testing.T) { // arrange d, a := initTestPCF8583WithStubbedAdaptor() readCtrlState := uint8(0x20) // counter // arrange writes a.i2cWriteImpl = func(b []byte) (int, error) { return len(b), nil } // arrange reads numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ b[len(b)-1] = readCtrlState return len(b), nil } // act result := d.Command("WriteCounter")(map[string]interface{}{"val": int32(123456)}) // assert assert.Nil(t, result.(map[string]interface{})["err"]) } func TestPCF8583CommandsReadCounter(t *testing.T) { // arrange d, a := initTestPCF8583WithStubbedAdaptor() want := int32(123456) reg0Val := uint8(0x20) // counter mode reg1Val := uint8(0x56) // BCD: 56 reg2Val := uint8(0x34) // BCD: 34 reg3Val := uint8(0x12) // BCD: 12 returnRead := [2][]uint8{ {reg0Val}, {reg1Val, reg2Val, reg3Val}, } // arrange reads // arrange reads numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ rr := returnRead[numCallsRead-1] for i := 0; i < len(b); i++ { b[i] = rr[i] } return len(b), nil } // act result := d.Command("ReadCounter")(map[string]interface{}{}) // assert assert.Nil(t, result.(map[string]interface{})["err"]) assert.Equal(t, want, result.(map[string]interface{})["val"]) } func TestPCF8583CommandsWriteRAM(t *testing.T) { // arrange d, _ := initTestPCF8583WithStubbedAdaptor() addressValue := map[string]interface{}{ "address": uint8(0x12), "val": uint8(0x45), } // act result := d.Command("WriteRAM")(addressValue) // assert assert.Nil(t, result.(map[string]interface{})["err"]) } func TestPCF8583CommandsReadRAM(t *testing.T) { // arrange d, _ := initTestPCF8583WithStubbedAdaptor() address := map[string]interface{}{ "address": uint8(0x34), } // act result := d.Command("ReadRAM")(address) // assert assert.Nil(t, result.(map[string]interface{})["err"]) assert.Equal(t, uint8(0), result.(map[string]interface{})["val"]) } func TestPCF8583WriteTime(t *testing.T) { // sequence to write the time: // * read control register for get current state and ensure an clock mode is set // * write the control register (stop counting) // * create the values for date registers (default is 24h mode) // * write the clock and calendar registers with auto increment // * write the control register (start counting) // arrange d, a := initTestPCF8583WithStubbedAdaptor() a.written = []byte{} // reset writes of Start() and former test readCtrlState := uint8(0x07) // 32.768kHz clock mode const millis = 210 * time.Millisecond // 0.21 sec = 210 ms initDate := time.Date(2022, time.December, 16, 15, 14, 13, int(millis), time.UTC) wantCtrlStop := uint8(0x87) // stop counting bit is set wantReg1Val := uint8(0x21) // BCD: 1/10 and 1/100 sec (21) wantReg2Val := uint8(0x13) // BCD: 10 and 1 sec (13) wantReg3Val := uint8(0x14) // BCD: 10 and 1 min (14) wantReg4Val := uint8(0x15) // BCD: 10 and 1 hour (15) wantReg5Val := uint8(0x16) // year (0) and BCD: date (16) wantReg6Val := uint8(0xB2) // weekday 5, bit 5 and bit 7 (0xA0) and BCD: month (0x12) wantCrtlStart := uint8(0x07) // stop counting bit is reset // arrange writes a.i2cWriteImpl = func(b []byte) (int, error) { return len(b), nil } // arrange reads numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ b[len(b)-1] = readCtrlState return len(b), nil } // act err := d.WriteTime(initDate) // assert require.NoError(t, err) assert.Equal(t, initDate.Year(), d.yearOffset) assert.Equal(t, 1, numCallsRead) assert.Len(t, a.written, 11) assert.Equal(t, uint8(pcf8583Reg_CTRL), a.written[0]) assert.Equal(t, uint8(pcf8583Reg_CTRL), a.written[1]) assert.Equal(t, wantCtrlStop, a.written[2]) assert.Equal(t, wantReg1Val, a.written[3]) assert.Equal(t, wantReg2Val, a.written[4]) assert.Equal(t, wantReg3Val, a.written[5]) assert.Equal(t, wantReg4Val, a.written[6]) assert.Equal(t, wantReg5Val, a.written[7]) assert.Equal(t, wantReg6Val, a.written[8]) assert.Equal(t, uint8(pcf8583Reg_CTRL), a.written[9]) assert.Equal(t, wantCrtlStart, a.written[10]) } func TestPCF8583WriteTimeNoTimeModeFails(t *testing.T) { // arrange d, a := initTestPCF8583WithStubbedAdaptor() a.written = []byte{} // reset writes of Start() and former test readCtrlState := uint8(0x30) // test mode // arrange writes a.i2cWriteImpl = func(b []byte) (int, error) { return len(b), nil } // arrange reads numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ b[len(b)-1] = readCtrlState return len(b), nil } // act err := d.WriteTime(time.Now()) // assert require.Error(t, err) require.ErrorContains(t, err, "wrong mode 0x30") assert.Len(t, a.written, 1) assert.Equal(t, uint8(pcf8583Reg_CTRL), a.written[0]) assert.Equal(t, 1, numCallsRead) } func TestPCF8583ReadTime(t *testing.T) { // sequence to read the time: // * read the control register to determine mask flag and ensure an clock mode is set // * read the clock and calendar registers with auto increment // * create the value out of registers content // arrange d, a := initTestPCF8583WithStubbedAdaptor() a.written = []byte{} // reset writes of Start() and former test d.yearOffset = 2020 const millis = 210 * time.Millisecond // 0.21 sec = 210 ms want := time.Date(2022, time.December, 16, 15, 14, 13, int(millis), time.UTC) reg0Val := uint8(0x10) // clock mode 50Hz reg1Val := uint8(0x21) // BCD: 1/10 and 1/100 sec (21) reg2Val := uint8(0x13) // BCD: 10 and 1 sec (13) reg3Val := uint8(0x14) // BCD: 10 and 1 min (14) reg4Val := uint8(0x15) // BCD: 10 and 1 hour (15) reg5Val := uint8(0x96) // year (2) and BCD: date (16) reg6Val := uint8(0xB2) // weekday 5, bit 5 and bit 7 (0xA0) and BCD: month (0x12) returnRead := [2][]uint8{ {reg0Val}, {reg1Val, reg2Val, reg3Val, reg4Val, reg5Val, reg6Val}, } // arrange writes a.i2cWriteImpl = func(b []byte) (int, error) { return len(b), nil } // arrange reads numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ rr := returnRead[numCallsRead-1] for i := 0; i < len(b); i++ { b[i] = rr[i] } return len(b), nil } // act got, err := d.ReadTime() // assert require.NoError(t, err) assert.Len(t, a.written, 1) assert.Equal(t, uint8(pcf8583Reg_CTRL), a.written[0]) assert.Equal(t, 2, numCallsRead) assert.Equal(t, want, got) } func TestPCF8583ReadTimeNoTimeModeFails(t *testing.T) { // arrange d, a := initTestPCF8583WithStubbedAdaptor() a.written = []byte{} // reset writes of Start() and former test readCtrlState := uint8(0x20) // counter mode // arrange writes a.i2cWriteImpl = func(b []byte) (int, error) { return len(b), nil } // arrange reads numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ b[len(b)-1] = readCtrlState return len(b), nil } // act got, err := d.ReadTime() // assert require.Error(t, err) require.ErrorContains(t, err, "wrong mode 0x20") assert.Equal(t, time.Time{}, got) assert.Len(t, a.written, 1) assert.Equal(t, uint8(pcf8583Reg_CTRL), a.written[0]) assert.Equal(t, 1, numCallsRead) } func TestPCF8583WriteCounter(t *testing.T) { // sequence to write the counter: // * read control register for get current state and ensure the event counter mode is set // * write the control register (stop counting) // * create the values for counter registers // * write the counter registers // * write the control register (start counting) // arrange d, a := initTestPCF8583WithStubbedAdaptor() a.written = []byte{} // reset writes of Start() and former test readCtrlState := uint8(0x27) // counter mode initCount := int32(654321) // 6 digits used of 10 possible with int32 wantCtrlStop := uint8(0xA7) // stop counting bit is set wantReg1Val := uint8(0x21) // BCD: 21 wantReg2Val := uint8(0x43) // BCD: 43 wantReg3Val := uint8(0x65) // BCD: 65 wantCtrlStart := uint8(0x27) // counter mode // arrange writes a.i2cWriteImpl = func(b []byte) (int, error) { return len(b), nil } // arrange reads numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ b[len(b)-1] = readCtrlState return len(b), nil } // act err := d.WriteCounter(initCount) // assert require.NoError(t, err) assert.Equal(t, 1, numCallsRead) assert.Len(t, a.written, 8) assert.Equal(t, uint8(pcf8583Reg_CTRL), a.written[0]) assert.Equal(t, uint8(pcf8583Reg_CTRL), a.written[1]) assert.Equal(t, wantCtrlStop, a.written[2]) assert.Equal(t, wantReg1Val, a.written[3]) assert.Equal(t, wantReg2Val, a.written[4]) assert.Equal(t, wantReg3Val, a.written[5]) assert.Equal(t, uint8(pcf8583Reg_CTRL), a.written[6]) assert.Equal(t, wantCtrlStart, a.written[7]) } func TestPCF8583WriteCounterNoCounterModeFails(t *testing.T) { // arrange d, a := initTestPCF8583WithStubbedAdaptor() a.written = []byte{} // reset writes of Start() and former test readCtrlState := uint8(0x10) // 50Hz mode // arrange writes a.i2cWriteImpl = func(b []byte) (int, error) { return len(b), nil } // arrange reads numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ b[len(b)-1] = readCtrlState return len(b), nil } // act err := d.WriteCounter(123) // assert require.Error(t, err) require.ErrorContains(t, err, "wrong mode 0x10") assert.Len(t, a.written, 1) assert.Equal(t, uint8(pcf8583Reg_CTRL), a.written[0]) assert.Equal(t, 1, numCallsRead) } func TestPCF8583ReadCounter(t *testing.T) { // sequence to read the counter: // * read the control register to ensure the event counter mode is set // * read the counter registers // * create the value out of registers content // arrange d, a := initTestPCF8583WithStubbedAdaptor() a.written = []byte{} // reset writes of Start() and former test want := int32(654321) reg0Val := uint8(0x20) // counter mode reg1Val := uint8(0x21) // BCD: 21 reg2Val := uint8(0x43) // BCD: 43 reg3Val := uint8(0x65) // BCD: 65 returnRead := [2][]uint8{ {reg0Val}, {reg1Val, reg2Val, reg3Val}, } // arrange writes a.i2cWriteImpl = func(b []byte) (int, error) { return len(b), nil } // arrange reads numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ rr := returnRead[numCallsRead-1] for i := 0; i < len(b); i++ { b[i] = rr[i] } return len(b), nil } // act got, err := d.ReadCounter() // assert require.NoError(t, err) assert.Len(t, a.written, 1) assert.Equal(t, uint8(pcf8583Reg_CTRL), a.written[0]) assert.Equal(t, 2, numCallsRead) assert.Equal(t, want, got) } func TestPCF8583ReadCounterNoCounterModeFails(t *testing.T) { // arrange d, a := initTestPCF8583WithStubbedAdaptor() a.written = []byte{} // reset writes of Start() and former test readCtrlState := uint8(0x30) // test mode // arrange writes a.i2cWriteImpl = func(b []byte) (int, error) { return len(b), nil } // arrange reads numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ b[len(b)-1] = readCtrlState return len(b), nil } // act got, err := d.ReadCounter() // assert require.Error(t, err) require.ErrorContains(t, err, "wrong mode 0x30") assert.Equal(t, int32(0), got) assert.Len(t, a.written, 1) assert.Equal(t, uint8(pcf8583Reg_CTRL), a.written[0]) assert.Equal(t, 1, numCallsRead) } func TestPCF8583WriteRam(t *testing.T) { // sequence to write the RAM: // * calculate the RAM address and check for valid range // * write the given value to the given RAM address // arrange d, a := initTestPCF8583WithStubbedAdaptor() a.written = []byte{} // reset writes of Start() and former test wantRAMAddress := uint8(0xFF) wantRAMValue := uint8(0xEF) // arrange writes a.i2cWriteImpl = func(b []byte) (int, error) { return len(b), nil } // act err := d.WriteRAM(wantRAMAddress-pcf8583RamOffset, wantRAMValue) // assert require.NoError(t, err) assert.Len(t, a.written, 2) assert.Equal(t, wantRAMAddress, a.written[0]) assert.Equal(t, wantRAMValue, a.written[1]) } func TestPCF8583WriteRamAddressOverflowFails(t *testing.T) { // arrange d, a := initTestPCF8583WithStubbedAdaptor() a.written = []byte{} // reset writes of Start() and former test // act err := d.WriteRAM(uint8(0xF0), 15) // assert require.Error(t, err) require.ErrorContains(t, err, "overflow 256") assert.Empty(t, a.written) } func TestPCF8583ReadRam(t *testing.T) { // sequence to read the RAM: // * calculate the RAM address and check for valid range // * read the value from the given RAM address // arrange d, a := initTestPCF8583WithStubbedAdaptor() a.written = []byte{} // reset writes of Start() and former test wantRAMAddress := uint8(pcf8583RamOffset) want := uint8(0xAB) // arrange writes a.i2cWriteImpl = func(b []byte) (int, error) { return len(b), nil } // arrange reads numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ b[len(b)-1] = want return len(b), nil } // act got, err := d.ReadRAM(wantRAMAddress - pcf8583RamOffset) // assert require.NoError(t, err) assert.Equal(t, want, got) assert.Len(t, a.written, 1) assert.Equal(t, wantRAMAddress, a.written[0]) assert.Equal(t, 1, numCallsRead) } func TestPCF8583ReadRamAddressOverflowFails(t *testing.T) { // arrange d, a := initTestPCF8583WithStubbedAdaptor() a.written = []byte{} // reset writes of Start() and former test // arrange writes a.i2cWriteImpl = func(b []byte) (int, error) { return len(b), nil } // arrange reads numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ return len(b), nil } // act got, err := d.ReadRAM(uint8(0xF0)) // assert require.Error(t, err) require.ErrorContains(t, err, "overflow 256") assert.Equal(t, uint8(0), got) assert.Empty(t, a.written) assert.Equal(t, 0, numCallsRead) } func TestPCF8583_initializeNoModeSwitch(t *testing.T) { // arrange a := newI2cTestAdaptor() d := NewPCF8583Driver(a) a.written = []byte{} // reset writes of former tests readCtrlState := uint8(0x01) // 32.768kHz clock mode // arrange writes a.i2cWriteImpl = func(b []byte) (int, error) { return len(b), nil } // arrange reads numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ b[len(b)-1] = readCtrlState return len(b), nil } // act, assert - initialize() must be called on Start() err := d.Start() // assert require.NoError(t, err) assert.Equal(t, 1, numCallsRead) assert.Len(t, a.written, 1) assert.Equal(t, uint8(pcf8583Reg_CTRL), a.written[0]) } func TestPCF8583_initializeWithModeSwitch(t *testing.T) { // sequence to change mode: // * read control register for get current state // * reset old mode bits and set new mode bit // * write the control register // arrange a := newI2cTestAdaptor() d := NewPCF8583Driver(a) d.mode = PCF8583CtrlModeCounter a.written = []byte{} // reset writes of former tests readCtrlState := uint8(0x02) // 32.768kHz clock mode wantReg0Val := uint8(0x22) // event counter mode // arrange writes a.i2cWriteImpl = func(b []byte) (int, error) { return len(b), nil } // arrange reads numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ b[len(b)-1] = readCtrlState return len(b), nil } // act, assert - initialize() must be called on Start() err := d.Start() // assert require.NoError(t, err) assert.Equal(t, 1, numCallsRead) assert.Len(t, a.written, 3) assert.Equal(t, uint8(pcf8583Reg_CTRL), a.written[0]) assert.Equal(t, uint8(pcf8583Reg_CTRL), a.written[1]) assert.Equal(t, wantReg0Val, a.written[2]) } ================================================ FILE: drivers/i2c/pcf8591_driver.go ================================================ package i2c import ( "fmt" "log" "strings" "time" ) // PCF8591 supports addresses from 0x48 to 0x4F // The default address applies when all address pins connected to ground. const pcf8591DefaultAddress = 0x48 const ( pcf8591Debug = false ) type ( pcf8591Mode uint8 PCF8591Channel uint8 ) const ( pcf8591_CHAN0 PCF8591Channel = 0x00 pcf8591_CHAN1 PCF8591Channel = 0x01 pcf8591_CHAN2 PCF8591Channel = 0x02 pcf8591_CHAN3 PCF8591Channel = 0x03 ) const pcf8591_AION = 0x04 // auto increment, only relevant for ADC const ( pcf8591_ALLSINGLE pcf8591Mode = 0x00 pcf8591_THREEDIFF pcf8591Mode = 0x10 pcf8591_MIXED pcf8591Mode = 0x20 pcf8591_TWODIFF pcf8591Mode = 0x30 pcf8591_ANAON pcf8591Mode = 0x40 ) const pcf8591_ADMASK = 0x33 // channels and mode type pcf8591ModeChan struct { mode pcf8591Mode channel PCF8591Channel } // modeMap is to define the relation between a given description and the mode and channel // beside the long form there are some short forms available without risk of confusion // // pure single mode // "s.0"..."s.3": read single value of input n => channel n // pure differential mode // "d.0-1": differential value between input 0 and 1 => channel 0 // "d.2-3": differential value between input 2 and 3 => channel 1 // mixed mode // "m.0": single value of input 0 => channel 0 // "m.1": single value of input 1 => channel 1 // "m.2-3": differential value between input 2 and 3 => channel 2 // three differential inputs, related to input 3 // "t.0-3": differential value between input 0 and 3 => channel 0 // "t.1-3": differential value between input 1 and 3 => channel 1 // "t.2-3": differential value between input 1 and 3 => channel 2 var pcf8591ModeMap = map[string]pcf8591ModeChan{ "s.0": {pcf8591_ALLSINGLE, pcf8591_CHAN0}, "0": {pcf8591_ALLSINGLE, pcf8591_CHAN0}, "s.1": {pcf8591_ALLSINGLE, pcf8591_CHAN1}, "1": {pcf8591_ALLSINGLE, pcf8591_CHAN1}, "s.2": {pcf8591_ALLSINGLE, pcf8591_CHAN2}, "2": {pcf8591_ALLSINGLE, pcf8591_CHAN2}, "s.3": {pcf8591_ALLSINGLE, pcf8591_CHAN3}, "3": {pcf8591_ALLSINGLE, pcf8591_CHAN3}, "d.0-1": {pcf8591_TWODIFF, pcf8591_CHAN0}, "0-1": {pcf8591_TWODIFF, pcf8591_CHAN0}, "d.2-3": {pcf8591_TWODIFF, pcf8591_CHAN1}, "m.0": {pcf8591_MIXED, pcf8591_CHAN0}, "m.1": {pcf8591_MIXED, pcf8591_CHAN1}, "m.2-3": {pcf8591_MIXED, pcf8591_CHAN2}, "t.0-3": {pcf8591_THREEDIFF, pcf8591_CHAN0}, "0-3": {pcf8591_THREEDIFF, pcf8591_CHAN0}, "t.1-3": {pcf8591_THREEDIFF, pcf8591_CHAN1}, "1-3": {pcf8591_THREEDIFF, pcf8591_CHAN1}, "t.2-3": {pcf8591_THREEDIFF, pcf8591_CHAN2}, } // PCF8591Driver is a Gobot Driver for the PCF8591 8-bit 4xA/D & 1xD/A converter with i2c (100 kHz) and 3 address pins. // The analog inputs can be used as differential inputs in different ways. // // All values are linear scaled to 3.3V by default. This can be changed, see example "tinkerboard_pcf8591.go". // // Address specification: // 1 0 0 1 A2 A1 A0|rd // Lowest bit (rd) is mapped to switch between write(0)/read(1), it is not part of the "real" address. // // Example: A1,A2=1, others are 0 // Address mask => 1001110|1 => real 7-bit address mask 0100 1110 = 0x4E // // For example, here is the Adafruit board that uses this chip: // https://www.adafruit.com/product/4648 // // This driver was tested with Tinkerboard and the YL-40 driver. type PCF8591Driver struct { *Driver lastCtrlByte byte lastAnaOut byte additionalReadWrite uint8 additionalRead uint8 forceRefresh bool LastRead [][]byte // for debugging purposes } // NewPCF8591Driver creates a new driver with specified i2c interface // Params: // // c Connector - the Adaptor to use with this Driver // // Optional params: // // i2c.WithBus(int): bus to use with this driver // i2c.WithAddress(int): address to use with this driver // i2c.WithPCF8591With400kbitStabilization(uint8, uint8): stabilize read in 400 kbit mode func NewPCF8591Driver(c Connector, options ...func(Config)) *PCF8591Driver { d := &PCF8591Driver{ Driver: NewDriver(c, "PCF8591", pcf8591DefaultAddress), } d.afterStart = d.initialize d.beforeHalt = d.shutdown for _, option := range options { option(d) } return d } // WithPCF8591With400kbitStabilization option sets the PCF8591 additionalReadWrite and additionalRead value func WithPCF8591With400kbitStabilization(additionalReadWrite, additionalRead int) func(Config) { return func(c Config) { d, ok := c.(*PCF8591Driver) if ok { if additionalReadWrite < 0 { additionalReadWrite = 1 // works in most cases } if additionalRead < 0 { additionalRead = 2 // works in most cases } d.additionalReadWrite = uint8(additionalReadWrite) //nolint:gosec // checked before d.additionalRead = uint8(additionalRead) //nolint:gosec // checked before if pcf8591Debug { log.Printf("400 kbit stabilization for PCF8591Driver set rw: %d, r: %d", d.additionalReadWrite, d.additionalRead) } } else if pcf8591Debug { log.Printf("trying to set 400 kbit stabilization for non-PCF8591Driver %v", c) } } } // WithPCF8591ForceRefresh option modifies the PCF8591Driver forceRefresh option // Setting to true (1) will force refresh operation to register, although there is no change. // Normally this is not needed, so default is off (0). // When there is something flaky, there is a small chance to stabilize by setting this flag to true. // However, setting this flag to true slows down each IO operation up to 100%. func WithPCF8591ForceRefresh(val uint8) func(Config) { return func(c Config) { d, ok := c.(*PCF8591Driver) if ok { d.forceRefresh = val > 0 } else if pcf8591Debug { log.Printf("Trying to set forceRefresh for non-PCF8591Driver %v", c) } } } // AnalogRead returns value from analog reading of given input description // // Vlsb = (Vref-Vagnd)/256, value = (Van+ - Van-)/Vlsb, Van-=Vagnd for single mode // // The first read contains the last converted value (usually the last read). // After the channel was switched this means the value of the previous read channel. // After power on, the first byte read will be 80h, because the read is one cycle behind. // // Important note for 440 kbit mode: // With a bus speed of 100 kBit/sec, the ADC conversion has ~80 us + ACK (time to transfer the previous value). // This time is the limit for A-D conversion (datasheet 90 us). // An i2c bus extender (LTC4311) don't fix it (it seems rather the opposite). // // This leads to following behavior: // - the control byte is not written correctly // - the transition process takes an additional cycle, very often // - some circuits takes one cycle longer transition time in addition // - reading more than one byte by Read([]byte), e.g. to calculate an average, is not sufficient, // because some missing integration steps in each conversion (each byte value is a little bit lower than expected) // // So, for default, we drop the first three bytes to get the right value. func (d *PCF8591Driver) AnalogRead(description string) (int, error) { d.mutex.Lock() defer d.mutex.Unlock() mc, err := PCF8591ParseModeChan(description) if err != nil { return 0, err } // reset channel and mode ctrlByte := d.lastCtrlByte & ^uint8(pcf8591_ADMASK) // set to current channel and mode, AI must be off, because we need reading twice ctrlByte = ctrlByte | uint8(mc.mode) | uint8(mc.channel) & ^uint8(pcf8591_AION) var uval byte d.LastRead = make([][]byte, d.additionalReadWrite+1) // repeated write and read cycle to stabilize value in 400 kbit mode for writeReadCycle := uint8(1); writeReadCycle <= d.additionalReadWrite+1; writeReadCycle++ { if err = d.writeCtrlByte(ctrlByte, d.forceRefresh || writeReadCycle > 1); err != nil { return 0, err } // initiate read but skip some bytes if err := d.readBuf(writeReadCycle, 1+d.additionalRead); err != nil { return 0, err } // additional relax time time.Sleep(1 * time.Millisecond) // real used read if uval, err = d.readByte(); err != nil { return 0, err } if pcf8591Debug { d.LastRead[writeReadCycle-1] = append(d.LastRead[writeReadCycle-1], uval) } } // prepare return value value := int(uval) if mc.pcf8591IsDiff() { if uval > 127 { // first bit is set, means negative value = int(uval) - 256 } } return value, nil } // AnalogWrite writes the given value to the analog output (DAC) // Vlsb = (Vref-Vagnd)/256, Vaout = Vagnd+Vlsb*value // implements the aio.AnalogWriter interface, pin is unused here func (d *PCF8591Driver) AnalogWrite(pin string, value int) error { d.mutex.Lock() defer d.mutex.Unlock() byteVal := byte(value) if d.lastAnaOut == byteVal { if pcf8591Debug { log.Printf("write skipped because value unchanged: 0x%X\n", byteVal) } return nil } ctrlByte := d.lastCtrlByte | byte(pcf8591_ANAON) if err := d.writeByteData(ctrlByte, byteVal); err != nil { return err } d.lastCtrlByte = ctrlByte d.lastAnaOut = byteVal return nil } // AnalogOutputState enables or disables the analog output // Please note that in case of using the internal oscillator // and the auto increment mode the output should not switched off. // Otherwise conversion errors could occur. func (d *PCF8591Driver) AnalogOutputState(state bool) error { d.mutex.Lock() defer d.mutex.Unlock() return d.analogOutputState(state) } // PCF8591ParseModeChan is used to get a working combination between mode (single, mixed, 2 differential, // 3 differential) and the related channel to read from, parsed from the given description string. func PCF8591ParseModeChan(description string) (*pcf8591ModeChan, error) { mc, ok := pcf8591ModeMap[description] if !ok { descriptions := []string{} for k := range pcf8591ModeMap { descriptions = append(descriptions, k) } ds := strings.Join(descriptions, ", ") return nil, fmt.Errorf("unknown description '%s' for read analog value, accepted values: %s", description, ds) } return &mc, nil } func (d *PCF8591Driver) writeCtrlByte(ctrlByte uint8, forceRefresh bool) error { if d.lastCtrlByte != ctrlByte || forceRefresh { if err := d.writeByte(ctrlByte); err != nil { return err } d.lastCtrlByte = ctrlByte } else if pcf8591Debug { log.Printf("write skipped because control byte unchanged: 0x%X\n", ctrlByte) } return nil } func (d *PCF8591Driver) readBuf(nr uint8, cntBytes uint8) error { buf := make([]byte, cntBytes) cntRead, err := d.read(buf) if err != nil { return err } if cntRead != len(buf) { return fmt.Errorf("not enough bytes (%d of %d) read", cntRead, len(buf)) } if pcf8591Debug { d.LastRead[nr-1] = buf } return nil } func (mc pcf8591ModeChan) pcf8591IsDiff() bool { switch mc.mode { case pcf8591_TWODIFF: return true case pcf8591_THREEDIFF: return true case pcf8591_MIXED: return mc.channel == pcf8591_CHAN2 default: return false } } func (d *PCF8591Driver) initialize() error { return d.analogOutputState(false) } func (d *PCF8591Driver) shutdown() error { return d.analogOutputState(false) } func (d *PCF8591Driver) analogOutputState(state bool) error { var ctrlByte uint8 if state { ctrlByte = d.lastCtrlByte | byte(pcf8591_ANAON) } else { ctrlByte = d.lastCtrlByte & ^uint8(pcf8591_ANAON) } if err := d.writeCtrlByte(ctrlByte, d.forceRefresh); err != nil { return err } return nil } ================================================ FILE: drivers/i2c/pcf8591_driver_test.go ================================================ package i2c import ( "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) // this ensures that the implementation is based on i2c.Driver, which implements the gobot.Driver // and tests all implementations, so no further tests needed here for gobot.Driver interface var _ gobot.Driver = (*PCF8591Driver)(nil) func initTestPCF8591DriverWithStubbedAdaptor() (*PCF8591Driver, *i2cTestAdaptor) { a := newI2cTestAdaptor() d := NewPCF8591Driver(a, WithPCF8591With400kbitStabilization(0, 2)) d.lastCtrlByte = 0xFF // prevent skipping of write if err := d.Start(); err != nil { panic(err) } return d, a } func TestNewPCF8591Driver(t *testing.T) { var di interface{} = NewPCF8591Driver(newI2cTestAdaptor()) d, ok := di.(*PCF8591Driver) if !ok { require.Fail(t, "NewPCF8591Driver() should have returned a *PCF8591Driver") } assert.NotNil(t, d.Driver) assert.True(t, strings.HasPrefix(d.Name(), "PCF8591")) assert.Equal(t, 0x48, d.defaultAddress) } func TestPCF8591Start(t *testing.T) { d := NewPCF8591Driver(newI2cTestAdaptor()) require.NoError(t, d.Start()) } func TestPCF8591Halt(t *testing.T) { // arrange d := NewPCF8591Driver(newI2cTestAdaptor()) // act, assert require.NoError(t, d.Halt()) // must be idempotent require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestPCF8591WithPCF8591With400kbitStabilization(t *testing.T) { d := NewPCF8591Driver(newI2cTestAdaptor(), WithPCF8591With400kbitStabilization(5, 6)) assert.Equal(t, uint8(5), d.additionalReadWrite) assert.Equal(t, uint8(6), d.additionalRead) } func TestPCF8591AnalogReadSingle(t *testing.T) { // sequence to read the input channel: // * prepare value (with channel and mode) and write control register // * read 3 values to drop (see description in implementation) // * read the analog value // // arrange d, a := initTestPCF8591DriverWithStubbedAdaptor() a.written = []byte{} // reset writes of Start() and former test description := "s.1" d.lastCtrlByte = 0x00 ctrlByteOn := uint8(pcf8591_ALLSINGLE) | uint8(pcf8591_CHAN1) returnRead := []uint8{0x01, 0x02, 0x03, 0xFF} want := int(returnRead[3]) // arrange reads numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ if numCallsRead == 1 { b = returnRead[0:len(b)] } if numCallsRead == 2 { b[0] = returnRead[len(returnRead)-1] } return len(b), nil } // act got, err := d.AnalogRead(description) // assert require.NoError(t, err) assert.Len(t, a.written, 1) assert.Equal(t, ctrlByteOn, a.written[0]) assert.Equal(t, 2, numCallsRead) assert.Equal(t, want, got) } func TestPCF8591AnalogReadDiff(t *testing.T) { // sequence to read the input channel: // * prepare value (with channel and mode) and write control register // * read 3 values to drop (see description in implementation) // * read the analog value // * convert to 8-bit two's complement (-127...128) // // arrange d, a := initTestPCF8591DriverWithStubbedAdaptor() a.written = []byte{} // reset writes of Start() and former test description := "m.2-3" d.lastCtrlByte = 0x00 ctrlByteOn := uint8(pcf8591_MIXED) | uint8(pcf8591_CHAN2) // some two' complements // 0x80 => -128 // 0xFF => -1 // 0x00 => 0 // 0x7F => 127 returnRead := []uint8{0x01, 0x02, 0x03, 0xFF} want := -1 // arrange reads numCallsRead := 0 a.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ if numCallsRead == 1 { b = returnRead[0:len(b)] } if numCallsRead == 2 { b[0] = returnRead[len(returnRead)-1] } return len(b), nil } // act got, err := d.AnalogRead(description) // assert require.NoError(t, err) assert.Len(t, a.written, 1) assert.Equal(t, ctrlByteOn, a.written[0]) assert.Equal(t, 2, numCallsRead) assert.Equal(t, want, got) } func TestPCF8591AnalogWrite(t *testing.T) { // sequence to write the output: // * create new value for the control register (ANAON) // * write the control register and value // // arrange d, a := initTestPCF8591DriverWithStubbedAdaptor() a.written = []byte{} // reset writes of Start() and former test d.lastCtrlByte = 0x00 d.lastAnaOut = 0x00 ctrlByteOn := uint8(pcf8591_ANAON) want := uint8(0x15) // arrange writes a.i2cWriteImpl = func(b []byte) (int, error) { return len(b), nil } // act err := d.AnalogWrite("", int(want)) // assert require.NoError(t, err) assert.Len(t, a.written, 2) assert.Equal(t, ctrlByteOn, a.written[0]) assert.Equal(t, want, a.written[1]) } func TestPCF8591AnalogOutputState(t *testing.T) { // sequence to set the state: // * create the new value (ctrlByte) for the control register (ANAON) // * write the register value // // arrange d, a := initTestPCF8591DriverWithStubbedAdaptor() for bitState := 0; bitState <= 1; bitState++ { a.written = []byte{} // reset writes of Start() and former test // arrange some values d.lastCtrlByte = uint8(0x00) wantCtrlByteVal := uint8(pcf8591_ANAON) if bitState == 0 { d.lastCtrlByte = uint8(0xFF) wantCtrlByteVal = uint8(0xFF & ^pcf8591_ANAON) } // act err := d.AnalogOutputState(bitState == 1) // assert require.NoError(t, err) assert.Len(t, a.written, 1) assert.Equal(t, wantCtrlByteVal, a.written[0]) } } ================================================ FILE: drivers/i2c/sht2x_driver.go ================================================ /* * Copyright (c) 2016-2017 Weston Schmidt * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package i2c // SHT2xDriver is a driver for the SHT2x based devices. // // This module was tested with Sensirion SHT21 Breakout. import ( "errors" "time" "github.com/sigurn/crc8" ) const sht2xDefaultAddress = 0x40 const ( // SHT2xAccuracyLow is the faster, but lower accuracy sample setting // 0/1 = 8bit RH, 12bit Temp SHT2xAccuracyLow = byte(0x01) // SHT2xAccuracyMedium is the medium accuracy and speed sample setting // 1/0 = 10bit RH, 13bit Temp SHT2xAccuracyMedium = byte(0x80) // SHT2xAccuracyHigh is the high accuracy and slowest sample setting // 0/0 = 12bit RH, 14bit Temp // Power on default is 0/0 SHT2xAccuracyHigh = byte(0x00) // SHT2xTriggerTempMeasureHold is the command for measuring temperature in hold controller mode SHT2xTriggerTempMeasureHold = 0xe3 // SHT2xTriggerHumdMeasureHold is the command for measuring humidity in hold controller mode SHT2xTriggerHumdMeasureHold = 0xe5 // SHT2xTriggerTempMeasureNohold is the command for measuring humidity in no hold controller mode SHT2xTriggerTempMeasureNohold = 0xf3 // SHT2xTriggerHumdMeasureNohold is the command for measuring humidity in no hold controller mode SHT2xTriggerHumdMeasureNohold = 0xf5 // SHT2xWriteUserReg is the command for writing user register SHT2xWriteUserReg = 0xe6 // SHT2xReadUserReg is the command for reading user register SHT2xReadUserReg = 0xe7 // SHT2xReadUserReg is the command for reading user register SHT2xSoftReset = 0xfe ) // SHT2xDriver is a Driver for a SHT2x humidity and temperature sensor type SHT2xDriver struct { *Driver Units string accuracy byte crcTable *crc8.Table } // NewSHT2xDriver creates a new driver with specified i2c interface // Params: // // c Connector - the Adaptor to use with this Driver // // Optional params: // // i2c.WithBus(int): bus to use with this driver // i2c.WithAddress(int): address to use with this driver func NewSHT2xDriver(c Connector, options ...func(Config)) *SHT2xDriver { // From the document "CRC Checksum Calculation -- For Safe Communication with SHT2x Sensors": crc8Params := crc8.Params{ Poly: 0x31, Init: 0x00, RefIn: false, RefOut: false, XorOut: 0x00, Check: 0x00, Name: "CRC-8/SENSIRION-SHT2x", } d := &SHT2xDriver{ Driver: NewDriver(c, "SHT2x", sht2xDefaultAddress), Units: "C", crcTable: crc8.MakeTable(crc8Params), } d.afterStart = d.initialize for _, option := range options { option(d) } return d } func (d *SHT2xDriver) Accuracy() byte { return d.accuracy } // SetAccuracy sets the accuracy of the sampling func (d *SHT2xDriver) SetAccuracy(acc byte) error { d.accuracy = acc if d.connection != nil { return d.sendAccuracy() } return nil } // Reset does a software reset of the device func (d *SHT2xDriver) Reset() error { if err := d.writeByte(SHT2xSoftReset); err != nil { return err } time.Sleep(15 * time.Millisecond) // 15ms delay (from the datasheet 5.5) return nil } // Temperature returns the current temperature, in celsius degrees. func (d *SHT2xDriver) Temperature() (float32, error) { rawT, err := d.readSensor(SHT2xTriggerTempMeasureNohold) if err != nil { return 0, err } // From the datasheet 6.2: // T[C] = -46.85 + 175.72 * St / 2^16 temp := -46.85 + 175.72/65536.0*float32(rawT) return temp, nil } // Humidity returns the current humidity in percentage of relative humidity func (d *SHT2xDriver) Humidity() (float32, error) { rawH, err := d.readSensor(SHT2xTriggerHumdMeasureNohold) if err != nil { return 0, err } // From the datasheet 6.1: // RH = -6 + 125 * Srh / 2^16 humidity := -6.0 + 125.0/65536.0*float32(rawH) return humidity, nil } // sendCommandDelayGetResponse is a helper function to reduce duplicated code func (d *SHT2xDriver) readSensor(cmd byte) (uint16, error) { if err := d.writeByte(cmd); err != nil { return 0, err } // Hang out while measurement is taken. 85ms max, page 9 of datasheet. time.Sleep(85 * time.Millisecond) // Comes back in three bytes, data(MSB) / data(LSB) / Checksum buf := make([]byte, 3) counter := 0 for { got, err := d.read(buf) counter++ if counter > 50 { return 0, err } if err == nil { if got != 3 { return 0, ErrNotEnoughBytes } break } time.Sleep(1 * time.Millisecond) } // Store the result crc := crc8.Checksum(buf[0:2], d.crcTable) if buf[2] != crc { return 0, errors.New("invalid crc") } read := uint16(buf[0])<<8 | uint16(buf[1]) read &= 0xfffc // clear two low bits (status bits) return read, nil } func (d *SHT2xDriver) initialize() error { if err := d.Reset(); err != nil { return err } return d.sendAccuracy() } func (d *SHT2xDriver) sendAccuracy() error { if err := d.writeByte(SHT2xReadUserReg); err != nil { return err } userRegister, err := d.readByte() if err != nil { return err } userRegister &= 0x7e // Turn off the resolution bits acc := d.accuracy acc &= 0x81 // Turn off all other bits but resolution bits userRegister |= acc // Mask in the requested resolution bits // Request a write to user register if _, err := d.write([]byte{SHT2xWriteUserReg, userRegister}); err != nil { return err } _, err = d.readByte() return err } ================================================ FILE: drivers/i2c/sht2x_driver_test.go ================================================ package i2c import ( "bytes" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) // this ensures that the implementation is based on i2c.Driver, which implements the gobot.Driver // and tests all implementations, so no further tests needed here for gobot.Driver interface var _ gobot.Driver = (*SHT2xDriver)(nil) func initTestSHT2xDriverWithStubbedAdaptor() (*SHT2xDriver, *i2cTestAdaptor) { a := newI2cTestAdaptor() d := NewSHT2xDriver(a) if err := d.Start(); err != nil { panic(err) } return d, a } func TestNewSHT2xDriver(t *testing.T) { var di interface{} = NewSHT2xDriver(newI2cTestAdaptor()) d, ok := di.(*SHT2xDriver) if !ok { require.Fail(t, "NewSHT2xDriver() should have returned a *SHT2xDriver") } assert.NotNil(t, d.Driver) assert.True(t, strings.HasPrefix(d.Name(), "SHT2x")) assert.Equal(t, 0x40, d.defaultAddress) } func TestSHT2xOptions(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithBus() option and // least one of this driver. Further tests for options can also be done by call of "WithOption(val)(d)". b := NewSHT2xDriver(newI2cTestAdaptor(), WithBus(2)) assert.Equal(t, 2, b.GetBusOrDefault(1)) } func TestSHT2xStart(t *testing.T) { d := NewSHT2xDriver(newI2cTestAdaptor()) require.NoError(t, d.Start()) } func TestSHT2xHalt(t *testing.T) { // arrange d := NewSHT2xDriver(newI2cTestAdaptor()) // act, assert require.NoError(t, d.Halt()) // must be idempotent require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestSHT2xReset(t *testing.T) { d, a := initTestSHT2xDriverWithStubbedAdaptor() a.i2cReadImpl = func(b []byte) (int, error) { return 0, nil } _ = d.Start() err := d.Reset() require.NoError(t, err) } func TestSHT2xMeasurements(t *testing.T) { d, a := initTestSHT2xDriverWithStubbedAdaptor() a.i2cReadImpl = func(b []byte) (int, error) { buf := new(bytes.Buffer) // Values produced by dumping data from actual sensor if a.written[len(a.written)-1] == SHT2xTriggerTempMeasureNohold { buf.Write([]byte{95, 168, 59}) } else if a.written[len(a.written)-1] == SHT2xTriggerHumdMeasureNohold { buf.Write([]byte{94, 202, 22}) } copy(b, buf.Bytes()) return buf.Len(), nil } _ = d.Start() temp, err := d.Temperature() require.NoError(t, err) assert.InDelta(t, float32(18.809052), temp, 1.0e-5) hum, err := d.Humidity() require.NoError(t, err) assert.InDelta(t, float32(40.279907), hum, 0.0) } func TestSHT2xAccuracy(t *testing.T) { d, a := initTestSHT2xDriverWithStubbedAdaptor() a.i2cReadImpl = func(b []byte) (int, error) { buf := new(bytes.Buffer) switch { case a.written[len(a.written)-1] == SHT2xReadUserReg: buf.Write([]byte{0x3a}) case a.written[len(a.written)-2] == SHT2xWriteUserReg: buf.Write([]byte{a.written[len(a.written)-1]}) default: return 0, nil } copy(b, buf.Bytes()) return buf.Len(), nil } _ = d.Start() _ = d.SetAccuracy(SHT2xAccuracyLow) assert.Equal(t, SHT2xAccuracyLow, d.Accuracy()) err := d.sendAccuracy() require.NoError(t, err) } func TestSHT2xTemperatureCrcError(t *testing.T) { d, a := initTestSHT2xDriverWithStubbedAdaptor() _ = d.Start() a.i2cReadImpl = func(b []byte) (int, error) { buf := new(bytes.Buffer) if a.written[len(a.written)-1] == SHT2xTriggerTempMeasureNohold { buf.Write([]byte{95, 168, 0}) } copy(b, buf.Bytes()) return buf.Len(), nil } temp, err := d.Temperature() require.ErrorContains(t, err, "invalid crc") assert.InDelta(t, float32(0.0), temp, 0.0) } func TestSHT2xHumidityCrcError(t *testing.T) { d, a := initTestSHT2xDriverWithStubbedAdaptor() _ = d.Start() a.i2cReadImpl = func(b []byte) (int, error) { buf := new(bytes.Buffer) if a.written[len(a.written)-1] == SHT2xTriggerHumdMeasureNohold { buf.Write([]byte{94, 202, 0}) } copy(b, buf.Bytes()) return buf.Len(), nil } hum, err := d.Humidity() require.ErrorContains(t, err, "invalid crc") assert.InDelta(t, float32(0.0), hum, 0.0) } func TestSHT2xTemperatureLengthError(t *testing.T) { d, a := initTestSHT2xDriverWithStubbedAdaptor() _ = d.Start() a.i2cReadImpl = func(b []byte) (int, error) { buf := new(bytes.Buffer) if a.written[len(a.written)-1] == SHT2xTriggerTempMeasureNohold { buf.Write([]byte{95, 168}) } copy(b, buf.Bytes()) return buf.Len(), nil } temp, err := d.Temperature() assert.Equal(t, ErrNotEnoughBytes, err) assert.InDelta(t, float32(0.0), temp, 0.0) } func TestSHT2xHumidityLengthError(t *testing.T) { d, a := initTestSHT2xDriverWithStubbedAdaptor() _ = d.Start() a.i2cReadImpl = func(b []byte) (int, error) { buf := new(bytes.Buffer) if a.written[len(a.written)-1] == SHT2xTriggerHumdMeasureNohold { buf.Write([]byte{94, 202}) } copy(b, buf.Bytes()) return buf.Len(), nil } hum, err := d.Humidity() assert.Equal(t, ErrNotEnoughBytes, err) assert.InDelta(t, float32(0.0), hum, 0.0) } ================================================ FILE: drivers/i2c/sht3x_driver.go ================================================ /* * Copyright (c) 2016-2017 Weston Schmidt * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package i2c // SHT3xDriver is a driver for the SHT3x-D based devices. // // This module was tested with AdaFruit Sensiron SHT32-D Breakout. // https://www.adafruit.com/products/2857 import ( "errors" "time" "github.com/sigurn/crc8" ) // SHT3xAddressA is the default address of device const SHT3xAddressA = 0x44 // SHT3xAddressB is the optional address of device const SHT3xAddressB = 0x45 // SHT3xAccuracyLow is the faster, but lower accuracy sample setting const SHT3xAccuracyLow = 0x16 // SHT3xAccuracyMedium is the medium accuracy and speed sample setting const SHT3xAccuracyMedium = 0x0b // SHT3xAccuracyHigh is the high accuracy and slowest sample setting const SHT3xAccuracyHigh = 0x00 var ( crc8Params = crc8.Params{ Poly: 0x31, Init: 0xff, RefIn: false, RefOut: false, XorOut: 0x00, Check: 0xf7, Name: "CRC-8/SENSIRON", } ErrInvalidAccuracy = errors.New("invalid accuracy") ErrInvalidCrc = errors.New("invalid crc") ErrInvalidTemp = errors.New("invalid temperature units") ) // SHT3xDriver is a Driver for a SHT3x humidity and temperature sensor type SHT3xDriver struct { *Driver Units string accuracy byte delay time.Duration crcTable *crc8.Table } // NewSHT3xDriver creates a new driver with specified i2c interface // Params: // // c Connector - the Adaptor to use with this Driver // // Optional params: // // i2c.WithBus(int): bus to use with this driver // i2c.WithAddress(int): address to use with this driver func NewSHT3xDriver(c Connector, options ...func(Config)) *SHT3xDriver { d := &SHT3xDriver{ Driver: NewDriver(c, "SHT3x", SHT3xAddressA), Units: "C", crcTable: crc8.MakeTable(crc8Params), } if err := d.SetAccuracy(SHT3xAccuracyHigh); err != nil { panic(err) } for _, option := range options { option(d) } return d } // Accuracy returns the accuracy of the sampling func (d *SHT3xDriver) Accuracy() byte { return d.accuracy } // SetAccuracy sets the accuracy of the sampling func (d *SHT3xDriver) SetAccuracy(a byte) error { switch a { case SHT3xAccuracyLow: d.delay = 5 * time.Millisecond // Actual max is 4, wait 1 ms longer case SHT3xAccuracyMedium: d.delay = 7 * time.Millisecond // Actual max is 6, wait 1 ms longer case SHT3xAccuracyHigh: d.delay = 16 * time.Millisecond // Actual max is 15, wait 1 ms longer default: return ErrInvalidAccuracy } d.accuracy = a return nil } // SerialNumber returns the serial number of the chip func (d *SHT3xDriver) SerialNumber() (uint32, error) { ret, err := d.sendCommandDelayGetResponse([]byte{0x37, 0x80}, nil, 2) if err != nil { return 0, err } sn := (uint32(ret[0]) << 16) | uint32(ret[1]) return sn, nil } // Heater returns true if the heater is enabled func (d *SHT3xDriver) Heater() (bool, error) { sr, err := d.getStatusRegister() if err != nil { return false, err } if sr&(1<<13) == 1<<13 { return true, nil } return false, nil } // SetHeater enables or disables the heater on the device func (d *SHT3xDriver) SetHeater(enabled bool) error { out := []byte{0x30, 0x66} if enabled { out[1] = 0x6d } _, err := d.write(out) return err } // Sample returns the temperature in celsius and relative humidity for one sample // //nolint:nonamedreturns // is sufficient here func (d *SHT3xDriver) Sample() (temp float32, rh float32, err error) { ret, err := d.sendCommandDelayGetResponse([]byte{0x24, d.accuracy}, &d.delay, 2) if nil != err { return } // From the datasheet: // RH = 100 * Srh / (2^16 - 1) rhSample := uint64(ret[1]) rh = float32((uint64(1000000)*rhSample)/uint64(0xffff)) / 10000.0 tempSample := uint64(ret[0]) switch d.Units { case "C": // From the datasheet: // T[C] = -45 + 175 * (St / (2^16 - 1)) temp = float32((uint64(1750000)*tempSample)/uint64(0xffff)-uint64(450000)) / 10000.0 case "F": // From the datasheet: // T[F] = -49 + 315 * (St / (2^16 - 1)) temp = float32((uint64(3150000)*tempSample)/uint64(0xffff)-uint64(490000)) / 10000.0 default: err = ErrInvalidTemp } return } // getStatusRegister returns the device status register func (d *SHT3xDriver) getStatusRegister() (uint16, error) { ret, err := d.sendCommandDelayGetResponse([]byte{0xf3, 0x2d}, nil, 1) if err != nil { return 0, err } return ret[0], nil } // sendCommandDelayGetResponse is a helper function to reduce duplicated code func (d *SHT3xDriver) sendCommandDelayGetResponse(send []byte, delay *time.Duration, expect int) ([]uint16, error) { if _, err := d.write(send); err != nil { return nil, err } if nil != delay { time.Sleep(*delay) } buf := make([]byte, 3*expect) got, err := d.read(buf) if err != nil { return nil, err } if got != (3 * expect) { return nil, ErrNotEnoughBytes } read := make([]uint16, expect) for i := 0; i < expect; i++ { crc := crc8.Checksum(buf[i*3:i*3+2], d.crcTable) if buf[i*3+2] != crc { return nil, ErrInvalidCrc } read[i] = uint16(buf[i*3])<<8 | uint16(buf[i*3+1]) } return read, nil } ================================================ FILE: drivers/i2c/sht3x_driver_test.go ================================================ package i2c import ( "errors" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) // this ensures that the implementation is based on i2c.Driver, which implements the gobot.Driver // and tests all implementations, so no further tests needed here for gobot.Driver interface var _ gobot.Driver = (*SHT3xDriver)(nil) func initTestSHT3xDriverWithStubbedAdaptor() (*SHT3xDriver, *i2cTestAdaptor) { a := newI2cTestAdaptor() d := NewSHT3xDriver(a) if err := d.Start(); err != nil { panic(err) } return d, a } func TestNewSHT3xDriver(t *testing.T) { var di interface{} = NewSHT3xDriver(newI2cTestAdaptor()) d, ok := di.(*SHT3xDriver) if !ok { require.Fail(t, "NewSHT3xDriver() should have returned a *SHT3xDriver") } assert.NotNil(t, d.Driver) assert.True(t, strings.HasPrefix(d.Name(), "SHT3x")) assert.Equal(t, 0x44, d.defaultAddress) } func TestSHT3xOptions(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithBus() option and // least one of this driver. Further tests for options can also be done by call of "WithOption(val)(d)". d := NewSHT3xDriver(newI2cTestAdaptor(), WithBus(2)) assert.Equal(t, 2, d.GetBusOrDefault(1)) } func TestSHT3xStart(t *testing.T) { d := NewSHT3xDriver(newI2cTestAdaptor()) require.NoError(t, d.Start()) } func TestSHT3xHalt(t *testing.T) { // arrange d := NewSHT3xDriver(newI2cTestAdaptor()) // act, assert require.NoError(t, d.Halt()) // must be idempotent require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestSHT3xSampleNormal(t *testing.T) { d, a := initTestSHT3xDriverWithStubbedAdaptor() a.i2cReadImpl = func(b []byte) (int, error) { copy(b, []byte{0xbe, 0xef, 0x92, 0xbe, 0xef, 0x92}) return 6, nil } temp, rh, _ := d.Sample() assert.InDelta(t, float32(85.523003), temp, 0.0) assert.InDelta(t, float32(74.5845), rh, 0.0) // check the temp with the units in F d.Units = "F" temp, _, _ = d.Sample() assert.InDelta(t, float32(185.9414), temp, 0.0) } func TestSHT3xSampleBadCrc(t *testing.T) { d, a := initTestSHT3xDriverWithStubbedAdaptor() // Check that the 1st crc failure is caught a.i2cReadImpl = func(b []byte) (int, error) { copy(b, []byte{0xbe, 0xef, 0x00, 0xbe, 0xef, 0x92}) return 6, nil } _, _, err := d.Sample() assert.Equal(t, ErrInvalidCrc, err) // Check that the 2nd crc failure is caught a.i2cReadImpl = func(b []byte) (int, error) { copy(b, []byte{0xbe, 0xef, 0x92, 0xbe, 0xef, 0x00}) return 6, nil } _, _, err = d.Sample() assert.Equal(t, ErrInvalidCrc, err) } func TestSHT3xSampleBadRead(t *testing.T) { d, a := initTestSHT3xDriverWithStubbedAdaptor() // Check that the 1st crc failure is caught a.i2cReadImpl = func(b []byte) (int, error) { copy(b, []byte{0xbe, 0xef, 0x00, 0xbe, 0xef}) return 5, nil } _, _, err := d.Sample() assert.Equal(t, ErrNotEnoughBytes, err) } func TestSHT3xSampleUnits(t *testing.T) { d, a := initTestSHT3xDriverWithStubbedAdaptor() // Check that the 1st crc failure is caught a.i2cReadImpl = func(b []byte) (int, error) { copy(b, []byte{0xbe, 0xef, 0x92, 0xbe, 0xef, 0x92}) return 6, nil } d.Units = "K" _, _, err := d.Sample() assert.Equal(t, ErrInvalidTemp, err) } // Test internal sendCommandDelayGetResponse func TestSHT3xSCDGRIoFailures(t *testing.T) { d, a := initTestSHT3xDriverWithStubbedAdaptor() invalidRead := errors.New("read error") invalidWrite := errors.New("write error") // Only send 5 bytes a.i2cReadImpl = func(b []byte) (int, error) { copy(b, []byte{0xbe, 0xef, 0x92, 0xbe, 0xef}) return 5, nil } _, err := d.sendCommandDelayGetResponse(nil, nil, 2) assert.Equal(t, ErrNotEnoughBytes, err) // Don't read any bytes and return an error a.i2cReadImpl = func([]byte) (int, error) { return 0, invalidRead } _, err = d.sendCommandDelayGetResponse(nil, nil, 1) assert.Equal(t, invalidRead, err) // Don't write any bytes and return an error a.i2cWriteImpl = func([]byte) (int, error) { return 42, invalidWrite } _, err = d.sendCommandDelayGetResponse(nil, nil, 1) assert.Equal(t, invalidWrite, err) } // Test Heater and getStatusRegister func TestSHT3xHeater(t *testing.T) { d, a := initTestSHT3xDriverWithStubbedAdaptor() // heater enabled a.i2cReadImpl = func(b []byte) (int, error) { copy(b, []byte{0x20, 0x00, 0x5d}) return 3, nil } status, err := d.Heater() require.NoError(t, err) assert.True(t, status) // heater disabled a.i2cReadImpl = func(b []byte) (int, error) { copy(b, []byte{0x00, 0x00, 0x81}) return 3, nil } status, err = d.Heater() require.NoError(t, err) assert.False(t, status) // heater crc failed a.i2cReadImpl = func(b []byte) (int, error) { copy(b, []byte{0x00, 0x00, 0x00}) return 3, nil } _, err = d.Heater() assert.Equal(t, ErrInvalidCrc, err) // heater read failed a.i2cReadImpl = func(b []byte) (int, error) { copy(b, []byte{0x00, 0x00}) return 2, nil } _, err = d.Heater() require.Error(t, err) } func TestSHT3xSetHeater(t *testing.T) { d, _ := initTestSHT3xDriverWithStubbedAdaptor() _ = d.SetHeater(false) _ = d.SetHeater(true) } func TestSHT3xSetAccuracy(t *testing.T) { d, _ := initTestSHT3xDriverWithStubbedAdaptor() assert.Equal(t, byte(SHT3xAccuracyHigh), d.Accuracy()) err := d.SetAccuracy(SHT3xAccuracyMedium) require.NoError(t, err) assert.Equal(t, byte(SHT3xAccuracyMedium), d.Accuracy()) err = d.SetAccuracy(SHT3xAccuracyLow) require.NoError(t, err) assert.Equal(t, byte(SHT3xAccuracyLow), d.Accuracy()) err = d.SetAccuracy(0xff) assert.Equal(t, ErrInvalidAccuracy, err) } func TestSHT3xSerialNumber(t *testing.T) { d, a := initTestSHT3xDriverWithStubbedAdaptor() a.i2cReadImpl = func(b []byte) (int, error) { copy(b, []byte{0x20, 0x00, 0x5d, 0xbe, 0xef, 0x92}) return 6, nil } sn, err := d.SerialNumber() require.NoError(t, err) assert.Equal(t, uint32(0x2000beef), sn) } ================================================ FILE: drivers/i2c/ssd1306_driver.go ================================================ package i2c import ( "fmt" "image" ) const ssd1306DefaultAddress = 0x3c // register addresses for the ssd1306 const ( // default values ssd1306Width = 128 ssd1306Height = 64 ssd1306ExternalVCC = false ssd1306SetStartLine = 0x40 // fundamental commands ssd1306SetComOutput0 = 0xC0 ssd1306SetComOutput1 = 0xC1 ssd1306SetComOutput2 = 0xC2 ssd1306SetComOutput3 = 0xC3 ssd1306SetComOutput4 = 0xC4 ssd1306SetComOutput5 = 0xC5 ssd1306SetComOutput6 = 0xC6 ssd1306SetComOutput7 = 0xC7 ssd1306SetComOutput8 = 0xC8 ssd1306SetContrast = 0x81 // scrolling commands // ssd1306ContinuousHScrollRight = 0x26 // ssd1306ContinuousHScrollLeft = 0x27 // ssd1306ContinuousVHScrollRight = 0x29 // ssd1306ContinuousVHScrollLeft = 0x2A // ssd1306StopScroll = 0x2E // ssd1306StartScroll = 0x2F // addressing settings commands ssd1306SetMemoryAddressingMode = 0x20 ssd1306ColumnAddr = 0x21 ssd1306PageAddr = 0x22 // hardware configuration commands ssd1306SetSegmentRemap0 = 0xA0 ssd1306SetSegmentRemap127 = 0xA1 ssd1306DisplayOnResumeToRAM = 0xA4 ssd1306SetDisplayNormal = 0xA6 ssd1306SetDisplayInverse = 0xA7 ssd1306SetDisplayOff = 0xAE ssd1306SetDisplayOn = 0xAF // timing and driving scheme commands ssd1306SetDisplayClock = 0xD5 ssd1306SetPrechargePeriod = 0xD9 ssd1306SetVComDeselectLevel = 0xDB ssd1306SetMultiplexRatio = 0xA8 ssd1306SetComPins = 0xDA ssd1306SetDisplayOffset = 0xD3 // charge pump command ssd1306ChargePumpSetting = 0x8D ) // SSD1306Init contains the initialization settings for the ssd1306 display. type SSD1306Init struct { displayClock byte multiplexRatio byte displayOffset byte startLine byte chargePumpSetting byte memoryAddressingMode byte comPins byte contrast byte prechargePeriod byte vComDeselectLevel byte } // GetSequence returns the initialization sequence for the ssd1306 display. func (i *SSD1306Init) GetSequence() []byte { return []byte{ ssd1306SetDisplayNormal, ssd1306SetDisplayOff, ssd1306SetDisplayClock, i.displayClock, ssd1306SetMultiplexRatio, i.multiplexRatio, ssd1306SetDisplayOffset, i.displayOffset, ssd1306SetStartLine | i.startLine, ssd1306ChargePumpSetting, i.chargePumpSetting, ssd1306SetMemoryAddressingMode, i.memoryAddressingMode, ssd1306SetSegmentRemap0, ssd1306SetComOutput0, ssd1306SetComPins, i.comPins, ssd1306SetContrast, i.contrast, ssd1306SetPrechargePeriod, i.prechargePeriod, ssd1306SetVComDeselectLevel, i.vComDeselectLevel, ssd1306DisplayOnResumeToRAM, ssd1306SetDisplayNormal, } } // 128x64 init sequence var ssd1306Init128x64 = &SSD1306Init{ displayClock: 0x80, multiplexRatio: 0x3F, displayOffset: 0x00, startLine: 0x00, chargePumpSetting: 0x14, // 0x10 if external vcc is set memoryAddressingMode: 0x00, comPins: 0x12, contrast: 0xCF, // 0x9F if external vcc is set prechargePeriod: 0xF1, // 0x22 if external vcc is set vComDeselectLevel: 0x40, } // 128x32 init sequence var ssd1306Init128x32 = &SSD1306Init{ displayClock: 0x80, multiplexRatio: 0x1F, displayOffset: 0x00, startLine: 0x00, chargePumpSetting: 0x14, // 0x10 if external vcc is set memoryAddressingMode: 0x00, comPins: 0x02, contrast: 0x8F, // 0x9F if external vcc is set prechargePeriod: 0xF1, // 0x22 if external vcc is set vComDeselectLevel: 0x40, } // 96x16 init sequence var ssd1306Init96x16 = &SSD1306Init{ displayClock: 0x60, multiplexRatio: 0x0F, displayOffset: 0x00, startLine: 0x00, chargePumpSetting: 0x14, // 0x10 if external vcc is set memoryAddressingMode: 0x00, comPins: 0x02, contrast: 0x8F, // 0x9F if external vcc is set prechargePeriod: 0xF1, // 0x22 if external vcc is set vComDeselectLevel: 0x40, } // DisplayBuffer represents the display buffer intermediate memory. type DisplayBuffer struct { width, height, pageSize int buffer []byte } // NewDisplayBuffer creates a new DisplayBuffer. func NewDisplayBuffer(width, height, pageSize int) *DisplayBuffer { d := &DisplayBuffer{ width: width, height: height, pageSize: pageSize, } d.buffer = make([]byte, d.Size()) return d } // Size returns the memory size of the display buffer. func (d *DisplayBuffer) Size() int { return (d.width * d.height) / d.pageSize } // Clear the contents of the display buffer. func (d *DisplayBuffer) Clear() { d.buffer = make([]byte, d.Size()) } // SetPixel sets the x, y pixel with c color. func (d *DisplayBuffer) SetPixel(x, y, c int) { idx := x + (y/d.pageSize)*d.width bit := uint(y) % uint(d.pageSize) //nolint:gosec // TODO: fix later if c == 0 { d.buffer[idx] &= ^(1 << bit) } else { d.buffer[idx] |= (1 << bit) } } // Set sets the display buffer with the given buffer. func (d *DisplayBuffer) Set(buf []byte) { d.buffer = buf } // SSD1306Driver is a Gobot Driver for a SSD1306 Display. type SSD1306Driver struct { *Driver initSequence *SSD1306Init displayWidth int displayHeight int externalVCC bool pageSize int buffer *DisplayBuffer } // NewSSD1306Driver creates a new SSD1306Driver. // // Params: // // c Connector - the Adaptor to use with this Driver // // Optional params: // // WithBus(int): bus to use with this driver // WithAddress(int): address to use with this driver // WithSSD1306DisplayWidth(int): width of display (defaults to 128) // WithSSD1306DisplayHeight(int): height of display (defaults to 64) // WithSSD1306ExternalVCC: set true when using an external OLED supply (defaults to false) func NewSSD1306Driver(c Connector, options ...func(Config)) *SSD1306Driver { d := &SSD1306Driver{ Driver: NewDriver(c, "SSD1306", ssd1306DefaultAddress), displayHeight: ssd1306Height, displayWidth: ssd1306Width, externalVCC: ssd1306ExternalVCC, } d.afterStart = d.initialize // set options for _, option := range options { option(d) } // set page size d.pageSize = 8 // set display buffer d.buffer = NewDisplayBuffer(d.displayWidth, d.displayHeight, d.pageSize) // add commands d.AddCommand("Display", func(_ map[string]interface{}) interface{} { err := d.Display() return map[string]interface{}{"err": err} }) d.AddCommand("On", func(_ map[string]interface{}) interface{} { err := d.On() return map[string]interface{}{"err": err} }) d.AddCommand("Off", func(_ map[string]interface{}) interface{} { err := d.Off() return map[string]interface{}{"err": err} }) d.AddCommand("Clear", func(_ map[string]interface{}) interface{} { d.Clear() return map[string]interface{}{} }) //nolint:forcetypeassert // ok here d.AddCommand("SetContrast", func(params map[string]interface{}) interface{} { contrast := params["contrast"].(byte) err := d.SetContrast(contrast) return map[string]interface{}{"err": err} }) //nolint:forcetypeassert // ok here d.AddCommand("Set", func(params map[string]interface{}) interface{} { x := params["x"].(int) y := params["y"].(int) c := params["c"].(int) d.Set(x, y, c) return nil }) return d } // WithSSD1306DisplayWidth option sets the SSD1306Driver DisplayWidth option. func WithSSD1306DisplayWidth(val int) func(Config) { return func(c Config) { d, ok := c.(*SSD1306Driver) if ok { d.displayWidth = val } } } // WithSSD1306DisplayHeight option sets the SSD1306Driver DisplayHeight option. func WithSSD1306DisplayHeight(val int) func(Config) { return func(c Config) { d, ok := c.(*SSD1306Driver) if ok { d.displayHeight = val } } } // WithSSD1306ExternalVCC option sets the SSD1306Driver ExternalVCC option. func WithSSD1306ExternalVCC(val bool) func(Config) { return func(c Config) { d, ok := c.(*SSD1306Driver) if ok { d.externalVCC = val } } } // Init initializes the ssd1306 display. func (d *SSD1306Driver) Init() error { // turn off screen if err := d.Off(); err != nil { return err } // run through initialization commands if err := d.commands(d.initSequence.GetSequence()); err != nil { return err } if err := d.commands([]byte{ssd1306ColumnAddr, 0, byte(d.buffer.width) - 1}); err != nil { return err } return d.commands([]byte{ssd1306PageAddr, 0, (byte(d.buffer.height / d.pageSize)) - 1}) } // On turns on the display. func (d *SSD1306Driver) On() error { return d.command(ssd1306SetDisplayOn) } // Off turns off the display. func (d *SSD1306Driver) Off() error { return d.command(ssd1306SetDisplayOff) } // Clear clears the display buffer. func (d *SSD1306Driver) Clear() { d.buffer.Clear() } // Set sets a pixel in the buffer. func (d *SSD1306Driver) Set(x, y, c int) { d.buffer.SetPixel(x, y, c) } // Reset clears display. func (d *SSD1306Driver) Reset() error { if err := d.Off(); err != nil { return err } d.Clear() return d.On() } // SetContrast sets the display contrast. func (d *SSD1306Driver) SetContrast(contrast byte) error { return d.commands([]byte{ssd1306SetContrast, contrast}) } // Display sends the memory buffer to the display. func (d *SSD1306Driver) Display() error { _, err := d.write(append([]byte{0x40}, d.buffer.buffer...)) return err } // ShowImage takes a standard Go image and displays it in monochrome. func (d *SSD1306Driver) ShowImage(img image.Image) error { if img.Bounds().Dx() != d.displayWidth || img.Bounds().Dy() != d.displayHeight { return fmt.Errorf("image must match display width and height: %dx%d", d.displayWidth, d.displayHeight) } d.Clear() for y, w, h := 0, img.Bounds().Dx(), img.Bounds().Dy(); y < h; y++ { for x := 0; x < w; x++ { c := img.At(x, y) if r, g, b, _ := c.RGBA(); r > 0 || g > 0 || b > 0 { d.Set(x, y, 1) } } } return d.Display() } // command sends a command to the ssd1306 func (d *SSD1306Driver) command(b byte) error { _, err := d.write([]byte{0x80, b}) return err } // commands sends a command sequence to the ssd1306 func (d *SSD1306Driver) commands(commands []byte) error { var command []byte for _, d := range commands { command = append(command, []byte{0x80, d}...) } _, err := d.write(command) return err } func (d *SSD1306Driver) initialize() error { // check device size for supported resolutions switch { case d.displayWidth == 128 && d.displayHeight == 64: d.initSequence = ssd1306Init128x64 case d.displayWidth == 128 && d.displayHeight == 32: d.initSequence = ssd1306Init128x32 case d.displayWidth == 96 && d.displayHeight == 16: d.initSequence = ssd1306Init96x16 default: return fmt.Errorf("%dx%d resolution is unsupported, supported resolutions: 128x64, 128x32, 96x16", d.displayWidth, d.displayHeight) } // check for external vcc if d.externalVCC { d.initSequence.chargePumpSetting = 0x10 d.initSequence.contrast = 0x9F d.initSequence.prechargePeriod = 0x22 } if err := d.Init(); err != nil { return err } return d.On() } ================================================ FILE: drivers/i2c/ssd1306_driver_test.go ================================================ //nolint:forcetypeassert // ok here package i2c import ( "fmt" "image" "reflect" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) // this ensures that the implementation is based on i2c.Driver, which implements the gobot.Driver // and tests all implementations, so no further tests needed here for gobot.Driver interface var _ gobot.Driver = (*SSD1306Driver)(nil) func initTestSSD1306DriverWithStubbedAdaptor( width, height int, externalVCC bool, //nolint:unparam // keep for tests ) (*SSD1306Driver, *i2cTestAdaptor) { a := newI2cTestAdaptor() d := NewSSD1306Driver(a, WithSSD1306DisplayWidth(width), WithSSD1306DisplayHeight(height), WithSSD1306ExternalVCC(externalVCC)) if err := d.Start(); err != nil { panic(err) } return d, a } func TestNewSSD1306Driver(t *testing.T) { var di interface{} = NewSSD1306Driver(newI2cTestAdaptor()) d, ok := di.(*SSD1306Driver) if !ok { require.Fail(t, "new should have returned a *SSD1306Driver") } assert.NotNil(t, d.Driver) assert.True(t, strings.HasPrefix(d.Name(), "SSD1306")) assert.Equal(t, 0x3c, d.defaultAddress) } func TestSSD1306StartDefault(t *testing.T) { const ( width = 128 height = 64 externalVCC = false ) d := NewSSD1306Driver(newI2cTestAdaptor(), WithSSD1306DisplayWidth(width), WithSSD1306DisplayHeight(height), WithSSD1306ExternalVCC(externalVCC)) require.NoError(t, d.Start()) } func TestSSD1306Start128x32(t *testing.T) { const ( width = 128 height = 32 externalVCC = false ) d := NewSSD1306Driver(newI2cTestAdaptor(), WithSSD1306DisplayWidth(width), WithSSD1306DisplayHeight(height), WithSSD1306ExternalVCC(externalVCC)) require.NoError(t, d.Start()) } func TestSSD1306Start96x16(t *testing.T) { const ( width = 96 height = 16 externalVCC = false ) d := NewSSD1306Driver(newI2cTestAdaptor(), WithSSD1306DisplayWidth(width), WithSSD1306DisplayHeight(height), WithSSD1306ExternalVCC(externalVCC)) require.NoError(t, d.Start()) } func TestSSD1306StartExternalVCC(t *testing.T) { const ( width = 128 height = 32 externalVCC = true ) d := NewSSD1306Driver(newI2cTestAdaptor(), WithSSD1306DisplayWidth(width), WithSSD1306DisplayHeight(height), WithSSD1306ExternalVCC(externalVCC)) require.NoError(t, d.Start()) } func TestSSD1306StartSizeError(t *testing.T) { const ( width = 128 height = 54 externalVCC = false ) d := NewSSD1306Driver(newI2cTestAdaptor(), WithSSD1306DisplayWidth(width), WithSSD1306DisplayHeight(height), WithSSD1306ExternalVCC(externalVCC)) require.ErrorContains(t, d.Start(), "128x54 resolution is unsupported, supported resolutions: 128x64, 128x32, 96x16") } func TestSSD1306Halt(t *testing.T) { // arrange d := NewSSD1306Driver(newI2cTestAdaptor(), WithSSD1306DisplayWidth(128), WithSSD1306DisplayHeight(64), WithSSD1306ExternalVCC(false)) // act, assert require.NoError(t, d.Halt()) // must be idempotent require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestSSD1306Options(t *testing.T) { s := NewSSD1306Driver(newI2cTestAdaptor(), WithBus(2), WithSSD1306DisplayHeight(32), WithSSD1306DisplayWidth(128)) assert.Equal(t, 2, s.GetBusOrDefault(1)) assert.Equal(t, 32, s.displayHeight) assert.Equal(t, 128, s.displayWidth) } func TestSSD1306Display(t *testing.T) { s, _ := initTestSSD1306DriverWithStubbedAdaptor(96, 16, false) _ = s.Start() require.NoError(t, s.Display()) } func TestSSD1306ShowImage(t *testing.T) { s, _ := initTestSSD1306DriverWithStubbedAdaptor(128, 64, false) _ = s.Start() img := image.NewRGBA(image.Rect(0, 0, 640, 480)) require.ErrorContains(t, s.ShowImage(img), "image must match display width and height: 128x64") img = image.NewRGBA(image.Rect(0, 0, 128, 64)) require.NoError(t, s.ShowImage(img)) } func TestSSD1306Command(t *testing.T) { s, a := initTestSSD1306DriverWithStubbedAdaptor(128, 64, false) _ = s.Start() a.i2cWriteImpl = func(got []byte) (int, error) { expected := []byte{0x80, 0xFF} if !reflect.DeepEqual(got, expected) { t.Logf("sequence error, got %+v, expected %+v", got, expected) return 0, fmt.Errorf("oops") } return 0, nil } err := s.command(0xFF) require.NoError(t, err) } func TestSSD1306Commands(t *testing.T) { s, a := initTestSSD1306DriverWithStubbedAdaptor(128, 64, false) _ = s.Start() a.i2cWriteImpl = func(got []byte) (int, error) { expected := []byte{0x80, 0x00, 0x80, 0xFF} if !reflect.DeepEqual(got, expected) { t.Logf("sequence error, got %+v, expected %+v", got, expected) return 0, fmt.Errorf("oops") } return 0, nil } err := s.commands([]byte{0x00, 0xFF}) require.NoError(t, err) } func TestSSD1306On(t *testing.T) { s, a := initTestSSD1306DriverWithStubbedAdaptor(128, 64, false) _ = s.Start() a.i2cWriteImpl = func(got []byte) (int, error) { expected := []byte{0x80, ssd1306SetDisplayOn} if !reflect.DeepEqual(got, expected) { t.Logf("sequence error, got %+v, expected %+v", got, expected) return 0, fmt.Errorf("oops") } return 0, nil } err := s.On() require.NoError(t, err) } func TestSSD1306Off(t *testing.T) { s, a := initTestSSD1306DriverWithStubbedAdaptor(128, 64, false) _ = s.Start() a.i2cWriteImpl = func(got []byte) (int, error) { expected := []byte{0x80, ssd1306SetDisplayOff} if !reflect.DeepEqual(got, expected) { t.Logf("sequence error, got %+v, expected %+v", got, expected) return 0, fmt.Errorf("oops") } return 0, nil } err := s.Off() require.NoError(t, err) } func TestSSD1306Reset(t *testing.T) { s, a := initTestSSD1306DriverWithStubbedAdaptor(128, 64, false) _ = s.Start() a.i2cWriteImpl = func(got []byte) (int, error) { expectedOff := []byte{0x80, ssd1306SetDisplayOff} expectedOn := []byte{0x80, ssd1306SetDisplayOn} if !reflect.DeepEqual(got, expectedOff) && !reflect.DeepEqual(got, expectedOn) { t.Logf("sequence error, got %+v, expected: %+v or %+v", got, expectedOff, expectedOn) return 0, fmt.Errorf("oops") } return 0, nil } err := s.Reset() require.NoError(t, err) } // COMMANDS func TestSSD1306CommandsDisplay(t *testing.T) { s, _ := initTestSSD1306DriverWithStubbedAdaptor(128, 64, false) result := s.Command("Display")(map[string]interface{}{}) assert.Nil(t, result.(map[string]interface{})["err"]) } func TestSSD1306CommandsOn(t *testing.T) { s, _ := initTestSSD1306DriverWithStubbedAdaptor(128, 64, false) result := s.Command("On")(map[string]interface{}{}) assert.Nil(t, result.(map[string]interface{})["err"]) } func TestSSD1306CommandsOff(t *testing.T) { s, _ := initTestSSD1306DriverWithStubbedAdaptor(128, 64, false) result := s.Command("Off")(map[string]interface{}{}) assert.Nil(t, result.(map[string]interface{})["err"]) } func TestSSD1306CommandsClear(t *testing.T) { s, _ := initTestSSD1306DriverWithStubbedAdaptor(128, 64, false) result := s.Command("Clear")(map[string]interface{}{}) assert.Nil(t, result.(map[string]interface{})["err"]) } func TestSSD1306CommandsSetContrast(t *testing.T) { s, a := initTestSSD1306DriverWithStubbedAdaptor(128, 64, false) a.i2cWriteImpl = func(got []byte) (int, error) { expected := []byte{0x80, ssd1306SetContrast, 0x80, 0x10} if !reflect.DeepEqual(got, expected) { t.Logf("sequence error, got %+v, expected %+v", got, expected) return 0, fmt.Errorf("oops") } return 0, nil } result := s.Command("SetContrast")(map[string]interface{}{ "contrast": byte(0x10), }) assert.Nil(t, result.(map[string]interface{})["err"]) } func TestSSD1306CommandsSet(t *testing.T) { s, _ := initTestSSD1306DriverWithStubbedAdaptor(128, 64, false) assert.Equal(t, byte(0), s.buffer.buffer[0]) s.Command("Set")(map[string]interface{}{ "x": int(0), "y": int(0), "c": int(1), }) assert.Equal(t, byte(1), s.buffer.buffer[0]) } func TestDisplayBuffer(t *testing.T) { width := 128 height := 64 size := 1024 // (width*height) / 8 display := NewDisplayBuffer(width, height, 8) require.Equal(t, size, display.Size()) require.Len(t, display.buffer, size) assert.Equal(t, byte(0), display.buffer[0]) assert.Equal(t, byte(0), display.buffer[1]) display.SetPixel(0, 0, 1) display.SetPixel(1, 0, 1) display.SetPixel(2, 0, 1) display.SetPixel(0, 1, 1) assert.Equal(t, byte(3), display.buffer[0]) assert.Equal(t, byte(1), display.buffer[1]) display.SetPixel(0, 1, 0) assert.Equal(t, byte(1), display.buffer[0]) assert.Equal(t, byte(1), display.buffer[1]) } ================================================ FILE: drivers/i2c/th02_driver.go ================================================ /* * Copyright (c) 2018 Nick Potts * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package i2c // TH02Driver is a driver for the TH02-D based devices. // // This module was tested with a Grove "Temperature&Humidity Sensor (High-Accuracy & Mini ) v1.0" // from https://www.seeedstudio.com/Grove-Temperature-Humidity-Sensor-High-Accuracy-Min-p-1921.htm // Datasheet is at http://www.hoperf.com/upload/sensor/TH02_V1.1.pdf import ( "fmt" "log" "time" ) const ( th02Debug = false th02DefaultAddress = 0x40 ) const ( th02Reg_Status = 0x00 th02Reg_DataMSB = 0x01 th02Reg_DataLSB = 0x02 th02Reg_Config = 0x03 th02Reg_ID = 0x11 // th02Status_ReadyBit = 0x01 // D0 is /RDY th02Config_StartBit = 0x01 // D0 is START th02Config_HeatBit = 0x02 // D1 is HEAT th02Config_TempBit = 0x10 // D4 is TEMP (if not set read humidity) th02Config_FastBit = 0x20 // D5 is FAST (if set use 18 ms, but lower accuracy T: 13 bit, H: 11 bit) ) // Accuracy constants for the TH02 devices (deprecated, use WithFastMode() instead) const ( TH02HighAccuracy = 0 // High Accuracy (T: 14 bit, H: 12 bit), normal (35 ms) TH02LowAccuracy = 1 // Lower Accuracy (T: 13 bit, H: 11 bit), fast (18 ms) ) // TH02Driver is a Driver for a TH02 humidity and temperature sensor type TH02Driver struct { *Driver Units string heating bool fastMode bool } // NewTH02Driver creates a new driver with specified i2c interface. // Defaults to: // - Using high accuracy (lower speed) measurements cycles. // - Emitting values in "C". If you want F, set Units to "F" // // Params: // // conn Connector - the Adaptor to use with this Driver // // Optional params: // // i2c.WithBus(int): bus to use with this driver // i2c.WithAddress(int): address to use with this driver func NewTH02Driver(a Connector, options ...func(Config)) *TH02Driver { d := &TH02Driver{ Driver: NewDriver(a, "TH02", th02DefaultAddress, options...), Units: "C", heating: false, fastMode: false, } for _, option := range options { option(d) } return d } // WithTH02FastMode option sets the fast mode (leads to lower accuracy). // Valid settings are <=0 (off), >0 (on). func WithTH02FastMode(val int) func(Config) { return func(c Config) { d, ok := c.(*TH02Driver) if ok { d.fastMode = (val > 0) } else if th02Debug { log.Printf("Trying to set fast mode for non-TH02Driver %v", c) } } } // Accuracy returns the accuracy of the sampling (deprecated, use FastMode() instead) func (d *TH02Driver) Accuracy() byte { if d.fastMode { return TH02LowAccuracy } return TH02HighAccuracy } // SetAccuracy sets the accuracy of the sampling. (deprecated, use WithFastMode() instead) // It will only be used on the next measurement request. Invalid value will use the default of High func (d *TH02Driver) SetAccuracy(a byte) { d.fastMode = (a == TH02LowAccuracy) } // SerialNumber returns the serial number of the chip func (d *TH02Driver) SerialNumber() (uint8, error) { d.mutex.Lock() defer d.mutex.Unlock() ret, err := d.readByteData(th02Reg_ID) return ret >> 4, err } // FastMode returns true if the fast mode is enabled in the device func (d *TH02Driver) FastMode() (bool, error) { d.mutex.Lock() defer d.mutex.Unlock() cfg, err := d.readByteData(th02Reg_Config) return (th02Config_FastBit & cfg) == th02Config_FastBit, err } // SetHeater sets the heater of the device to the given state. func (d *TH02Driver) SetHeater(state bool) error { d.mutex.Lock() defer d.mutex.Unlock() d.heating = state return d.writeByteData(th02Reg_Config, d.createConfig(false, false)) } // Heater returns true if the heater is enabled in the device func (d *TH02Driver) Heater() (bool, error) { d.mutex.Lock() defer d.mutex.Unlock() cfg, err := d.readByteData(th02Reg_Config) return (th02Config_HeatBit & cfg) == th02Config_HeatBit, err } // Sample returns the temperature in celsius and relative humidity for one sample // //nolint:nonamedreturns // is sufficient here func (d *TH02Driver) Sample() (temperature float32, relhumidity float32, _ error) { d.mutex.Lock() defer d.mutex.Unlock() // read humidity if err := d.writeByteData(th02Reg_Config, d.createConfig(true, false)); err != nil { return 0, 0, err } rawrh, err := d.waitAndReadData() if err != nil { return 0, 0, err } relhumidity = float32(rawrh>>4)/16.0 - 24.0 // read temperature if err := d.writeByteData(th02Reg_Config, d.createConfig(true, true)); err != nil { return 0, relhumidity, err } rawt, err := d.waitAndReadData() if err != nil { return 0, relhumidity, err } temperature = float32(rawt>>2)/32.0 - 50.0 if d.Units == "F" { temperature = 9.0/5.0*temperature + 32.0 } return temperature, relhumidity, nil } func (d *TH02Driver) createConfig(measurement bool, readTemp bool) byte { cfg := byte(0x00) if measurement { cfg = cfg | th02Config_StartBit if readTemp { cfg = cfg | th02Config_TempBit } if d.fastMode { cfg = cfg | th02Config_FastBit } } if d.heating { cfg = cfg | th02Config_HeatBit } return cfg } func (d *TH02Driver) waitAndReadData() (uint16, error) { if err := d.waitForReady(nil); err != nil { return 0, err } rcvd := make([]byte, 2) err := d.readBlockData(th02Reg_DataMSB, rcvd) if err != nil { return 0, err } return uint16(rcvd[0])<<8 + uint16(rcvd[1]), nil } // waitForReady blocks for up to the passed duration (which defaults to 50mS if nil) // until the ~RDY bit is cleared, meaning a sample has been fully sampled and is ready for reading. func (d *TH02Driver) waitForReady(dur *time.Duration) error { wait := 100 * time.Millisecond if dur != nil { wait = *dur } start := time.Now() for { if time.Since(start) > wait { return fmt.Errorf("timeout on \\RDY") } if reg, err := d.readByteData(th02Reg_Status); (reg == 0) && (err == nil) { return nil } time.Sleep(wait / 10) } } ================================================ FILE: drivers/i2c/th02_driver_test.go ================================================ package i2c import ( "fmt" "strings" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) // this ensures that the implementation is based on i2c.Driver, which implements the gobot.Driver // and tests all implementations, so no further tests needed here for gobot.Driver interface var _ gobot.Driver = (*TH02Driver)(nil) func initTestTH02DriverWithStubbedAdaptor() (*TH02Driver, *i2cTestAdaptor) { adaptor := newI2cTestAdaptor() driver := NewTH02Driver(adaptor) if err := driver.Start(); err != nil { panic(err) } return driver, adaptor } func TestNewTH02Driver(t *testing.T) { var di interface{} = NewTH02Driver(newI2cTestAdaptor()) d, ok := di.(*TH02Driver) if !ok { require.Fail(t, "NewTH02Driver() should have returned a *NewTH02Driver") } assert.NotNil(t, d.Driver) assert.True(t, strings.HasPrefix(d.Name(), "TH02")) assert.Equal(t, 0x40, d.defaultAddress) } func TestTH02Halt(t *testing.T) { // arrange d := NewTH02Driver(newI2cTestAdaptor()) // act, assert require.NoError(t, d.Halt()) // must be idempotent require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestTH02Options(t *testing.T) { // This is a general test, that options are applied in constructor by using the common options. // Further tests for options can also be done by call of "WithOption(val)(d)". d := NewTH02Driver(newI2cTestAdaptor(), WithBus(2), WithAddress(0x42)) assert.Equal(t, 2, d.GetBusOrDefault(1)) assert.Equal(t, 0x42, d.GetAddressOrDefault(0x33)) } func TestTH02SetAccuracy(t *testing.T) { b := NewTH02Driver(newI2cTestAdaptor()) if b.SetAccuracy(0x42); b.Accuracy() != TH02HighAccuracy { t.Error("Setting an invalid accuracy should resolve to TH02HighAccuracy") } if b.SetAccuracy(TH02LowAccuracy); b.Accuracy() != TH02LowAccuracy { t.Error("Expected setting low accuracy to actually set to low accuracy") } if acc := b.Accuracy(); acc != TH02LowAccuracy { require.Fail(t, "Accuracy() didn't return what was expected") } } func TestTH02WithFastMode(t *testing.T) { tests := map[string]struct { value int want bool }{ "fast_on_for >0": {value: 1, want: true}, "fast_off_for =0": {value: 0, want: false}, "fast_off_for <0": {value: -1, want: false}, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d := NewTH02Driver(newI2cTestAdaptor()) // act WithTH02FastMode(tc.value)(d) // assert assert.Equal(t, tc.want, d.fastMode) }) } } func TestTH02FastMode(t *testing.T) { // sequence to read the fast mode status // * write config register address (0x03) // * read register content // * if sixth bit (D5) is set, the fast mode is configured on, otherwise off tests := map[string]struct { read uint8 want bool }{ "fast on": {read: 0x20, want: true}, "fast off": {read: ^uint8(0x20), want: false}, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, a := initTestTH02DriverWithStubbedAdaptor() a.i2cReadImpl = func(b []byte) (int, error) { b[0] = tc.read return len(b), nil } // act got, err := d.FastMode() // assert require.NoError(t, err) assert.Len(t, a.written, 1) assert.Equal(t, uint8(0x03), a.written[0]) assert.Equal(t, tc.want, got) }) } } func TestTH02SetHeater(t *testing.T) { // sequence to set the heater status // * set the local heater state // * write config register address (0x03) // * prepare config value by set/reset the heater bit (0x02, D1) // * write the config value tests := map[string]struct { heater bool want uint8 }{ "heater on": {heater: true, want: 0x02}, "heater off": {heater: false, want: 0x00}, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, a := initTestTH02DriverWithStubbedAdaptor() // act err := d.SetHeater(tc.heater) // assert require.NoError(t, err) assert.Equal(t, tc.heater, d.heating) assert.Len(t, a.written, 2) assert.Equal(t, uint8(0x03), a.written[0]) assert.Equal(t, tc.want, a.written[1]) }) } } func TestTH02Heater(t *testing.T) { // sequence to read the heater status // * write config register address (0x03) // * read register content // * if second bit (D1) is set, the heater is configured on, otherwise off tests := map[string]struct { read uint8 want bool }{ "heater on": {read: 0x02, want: true}, "heater off": {read: ^uint8(0x02), want: false}, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, a := initTestTH02DriverWithStubbedAdaptor() a.i2cReadImpl = func(b []byte) (int, error) { b[0] = tc.read return len(b), nil } // act got, err := d.Heater() // assert require.NoError(t, err) assert.Len(t, a.written, 1) assert.Equal(t, uint8(0x03), a.written[0]) assert.Equal(t, tc.want, got) }) } } func TestTH02SerialNumber(t *testing.T) { // sequence to read SN // * write identification register address (0x11) // * read register content // * use the higher nibble of byte // arrange d, a := initTestTH02DriverWithStubbedAdaptor() a.i2cReadImpl = func(b []byte) (int, error) { b[0] = 0x4F return len(b), nil } want := uint8(0x04) // act sn, err := d.SerialNumber() // assert require.NoError(t, err) assert.Len(t, a.written, 1) assert.Equal(t, uint8(0x11), a.written[0]) assert.Equal(t, want, sn) } func TestTH02Sample(t *testing.T) { // sequence to read values // * write config register address (0x03) // * prepare config bits (START, HEAT, TEMP, FAST) // * write config register with config // * write status register address (0x00) // * read until value is "0" (means ready) // * write data register MSB address (0x01) // * read 2 bytes little-endian (MSB, LSB) // * shift and scale // RH: 4 bits shift right, RH[%]=RH/16-24 // T: 2 bits shift right, T[°C]=T/32-50 // test table according to data sheet page 15, 17 // operating range of the temperature sensor is -40..85 °C (F-grade 0..70 °C) tests := map[string]struct { hData uint16 tData uint16 wantRH float32 wantT float32 }{ "RH 0, T -40": { hData: 0x0180, wantRH: 0.0, tData: 0x0140, wantT: -40.0, }, "RH 10, T -20": { hData: 0x0220, wantRH: 10.0, tData: 0x03C0, wantT: -20.0, }, "RH 20, T -10": { hData: 0x02C0, wantRH: 20.0, tData: 0x0500, wantT: -10.0, }, "RH 30, T 0": { hData: 0x0360, wantRH: 30.0, tData: 0x0640, wantT: 0.0, }, "RH 40, T 10": { hData: 0x0400, wantRH: 40.0, tData: 0x0780, wantT: 10.0, }, "RH 50, T 20": { hData: 0x04A0, wantRH: 50.0, tData: 0x08C0, wantT: 20.0, }, "RH 60, T 30": { hData: 0x0540, wantRH: 60.0, tData: 0x0A00, wantT: 30.0, }, "RH 70, T 40": { hData: 0x05E0, wantRH: 70.0, tData: 0x0B40, wantT: 40.0, }, "RH 80, T 50": { hData: 0x0680, wantRH: 80.0, tData: 0x0C80, wantT: 50.0, }, "RH 90, T 60": { hData: 0x0720, wantRH: 90.0, tData: 0x0DC0, wantT: 60.0, }, "RH 100, T 70": { hData: 0x07C0, wantRH: 100.0, tData: 0x0F00, wantT: 70.0, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, a := initTestTH02DriverWithStubbedAdaptor() var reg uint8 var regVal uint8 a.i2cWriteImpl = func(b []byte) (int, error) { reg = b[0] if len(b) == 2 { regVal = b[1] } return len(b), nil } a.i2cReadImpl = func(b []byte) (int, error) { switch reg { case 0x00: // status b[0] = 0 case 0x01: // data register MSB var data uint16 if (regVal & 0x10) == 0x10 { // temperature data = tc.tData << 2 // data sheet values are after shift 2 bits } else { // humidity data = tc.hData << 4 // data sheet values are after shift 4 bits } b[0] = byte(data >> 8) // first read MSB from register 0x01 b[1] = byte(data & 0xFF) // second read LSB from register 0x02 default: assert.Equal(t, "only register 0 and 1 expected", fmt.Sprintf("unexpected register %d", reg)) return 0, nil } return len(b), nil } // act temp, rh, err := d.Sample() // assert require.NoError(t, err) assert.InDelta(t, tc.wantRH, rh, 0.0) assert.InDelta(t, tc.wantT, temp, 0.0) }) } } func TestTH02_readData(t *testing.T) { d, a := initTestTH02DriverWithStubbedAdaptor() var callCounter int tests := map[string]struct { rd func([]byte) (int, error) wr func([]byte) (int, error) rtn uint16 wantErr error }{ "example RH": { rd: func(b []byte) (int, error) { callCounter++ if callCounter == 1 { // read for ready b[0] = 0x00 } else { copy(b, []byte{0x07, 0xC0}) } return len(b), nil }, rtn: 1984, }, "example T": { rd: func(b []byte) (int, error) { callCounter++ if callCounter == 1 { // read for ready b[0] = 0x00 } else { copy(b, []byte{0x12, 0xC0}) } return len(b), nil }, rtn: 4800, }, "timeout - no wait for ready": { rd: func(b []byte) (int, error) { time.Sleep(200 * time.Millisecond) // simulate not ready b[0] = 0x01 return len(b), nil }, wantErr: fmt.Errorf("timeout on \\RDY"), rtn: 0, }, "unable to write status register": { rd: func(b []byte) (int, error) { callCounter++ if callCounter == 1 { // read for ready b[0] = 0x00 } return len(b), nil }, wr: func(b []byte) (int, error) { return len(b), fmt.Errorf("an write error") }, wantErr: fmt.Errorf("timeout on \\RDY"), rtn: 0, }, "unable to write data register": { rd: func(b []byte) (int, error) { callCounter++ if callCounter == 1 { // read for ready b[0] = 0x00 } return len(b), nil }, wr: func(b []byte) (int, error) { if len(b) == 1 && b[0] == 0x00 { // register of ready check return len(b), nil } // data register return len(b), fmt.Errorf("nope") }, wantErr: fmt.Errorf("nope"), rtn: 0, }, "unable to read doesn't provide enough data": { rd: func(b []byte) (int, error) { callCounter++ if callCounter == 1 { // read for ready b[0] = 0x00 } else { b = []byte{0x01} } return len(b), nil }, wantErr: fmt.Errorf("read 1 bytes from device by i2c helpers, expected 2"), rtn: 0, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange a.i2cReadImpl = tc.rd if tc.wr != nil { oldwr := a.i2cWriteImpl a.i2cWriteImpl = tc.wr defer func() { a.i2cWriteImpl = oldwr }() } callCounter = 0 // act got, err := d.waitAndReadData() // assert assert.Equal(t, tc.wantErr, err) assert.Equal(t, tc.rtn, got) }) } } func TestTH02_waitForReadyFailOnTimeout(t *testing.T) { d, a := initTestTH02DriverWithStubbedAdaptor() a.i2cReadImpl = func(b []byte) (int, error) { time.Sleep(50 * time.Millisecond) b[0] = 0x01 return len(b), nil } timeout := 10 * time.Microsecond if err := d.waitForReady(&timeout); err == nil { t.Error("Expected a timeout error") } } func TestTH02_waitForReadyFailOnReadError(t *testing.T) { d, a := initTestTH02DriverWithStubbedAdaptor() a.i2cReadImpl = func(b []byte) (int, error) { time.Sleep(50 * time.Millisecond) b[0] = 0x00 wrongLength := 2 return wrongLength, nil } timeout := 10 * time.Microsecond if err := d.waitForReady(&timeout); err == nil { t.Error("Expected a timeout error") } } func TestTH02_createConfig(t *testing.T) { d := &TH02Driver{} tests := map[string]struct { meas bool fast bool readTemp bool heating bool want byte }{ "meas, no fast, RH, no heating": {meas: true, fast: false, readTemp: false, heating: false, want: 0x01}, "meas, no fast, RH, heating": {meas: true, fast: false, readTemp: false, heating: true, want: 0x03}, "meas, no fast, TE, no heating": {meas: true, fast: false, readTemp: true, heating: false, want: 0x11}, "meas, no fast, TE, heating": {meas: true, fast: false, readTemp: true, heating: true, want: 0x13}, "meas, fast, RH, no heating": {meas: true, fast: true, readTemp: false, heating: false, want: 0x21}, "meas, fast, RH, heating": {meas: true, fast: true, readTemp: false, heating: true, want: 0x23}, "meas, fast, TE, no heating": {meas: true, fast: true, readTemp: true, heating: false, want: 0x31}, "meas, fast, TE, heating": {meas: true, fast: true, readTemp: true, heating: true, want: 0x33}, "no meas, no fast, RH, no heating": {meas: false, fast: false, readTemp: false, heating: false, want: 0x00}, "no meas, no fast, RH, heating": {meas: false, fast: false, readTemp: false, heating: true, want: 0x02}, "no meas, no fast, TE, no heating": {meas: false, fast: false, readTemp: true, heating: false, want: 0x00}, "no meas, no fast, TE, heating": {meas: false, fast: false, readTemp: true, heating: true, want: 0x02}, "no meas, fast, RH, no heating": {meas: false, fast: true, readTemp: false, heating: false, want: 0x00}, "no meas, fast, RH, heating": {meas: false, fast: true, readTemp: false, heating: true, want: 0x02}, "no meas, fast, TE, no heating": {meas: false, fast: true, readTemp: true, heating: false, want: 0x00}, "no meas, fast, TE, heating": {meas: false, fast: true, readTemp: true, heating: true, want: 0x02}, } for name, tc := range tests { t.Run(name, func(t *testing.T) { d.fastMode = tc.fast d.heating = tc.heating got := d.createConfig(tc.meas, tc.readTemp) assert.Equal(t, tc.want, got) }) } } ================================================ FILE: drivers/i2c/tsl2561_driver.go ================================================ package i2c import ( "fmt" "time" ) const ( // TSL2561AddressLow - the address of the device when address pin is low TSL2561AddressLow = 0x29 // TSL2561AddressFloat - the address of the device when address pin is floating TSL2561AddressFloat = 0x39 // TSL2561AddressHigh - the address of the device when address pin is high TSL2561AddressHigh = 0x49 tsl2561CommandBit = 0x80 // Must be 1 tsl2561ClearBit = 0x40 // Clears any pending interrupt (write 1 to clear) tsl2561WordBit = 0x20 // 1 = read/write word (rather than byte) tsl2561BlockBit = 0x10 // 1 = using block read/write tsl2561ControlPowerOn = 0x03 tsl2561ControlPowerOff = 0x00 tsl2561LuxLuxScale = 14 // Scale by 2^14 tsl2561LuxRatioScale = 9 // Scale ratio by 2^9 tsl2561LuxChScale = 10 // Scale channel values by 2^10 tsl2561LuxCHScaleTInt0 = 0x7517 // 322/11 * 2^tsl2561LUXCHSCALE tsl2561LuxChScaleTInt1 = 0x0FE7 // 322/81 * 2^tsl2561LUXCHSCALE // T, FN and CL package values tsl2561LuxK1T = 0x0040 // 0.125 * 2^RATIO_SCALE tsl2561LuxB1T = 0x01f2 // 0.0304 * 2^LUX_SCALE tsl2561LuxM1T = 0x01be // 0.0272 * 2^LUX_SCALE tsl2561LuxK2T = 0x0080 // 0.250 * 2^RATIO_SCALE tsl2561LuxB2T = 0x0214 // 0.0325 * 2^LUX_SCALE tsl2561LuxM2T = 0x02d1 // 0.0440 * 2^LUX_SCALE tsl2561LuxK3T = 0x00c0 // 0.375 * 2^RATIO_SCALE tsl2561LuxB3T = 0x023f // 0.0351 * 2^LUX_SCALE tsl2561LuxM3T = 0x037b // 0.0544 * 2^LUX_SCALE tsl2561LuxK4T = 0x0100 // 0.50 * 2^RATIO_SCALE tsl2561LuxB4T = 0x0270 // 0.0381 * 2^LUX_SCALE tsl2561LuxM4T = 0x03fe // 0.0624 * 2^LUX_SCALE tsl2561LuxK5T = 0x0138 // 0.61 * 2^RATIO_SCALE tsl2561LuxB5T = 0x016f // 0.0224 * 2^LUX_SCALE tsl2561LuxM5T = 0x01fc // 0.0310 * 2^LUX_SCALE tsl2561LuxK6T = 0x019a // 0.80 * 2^RATIO_SCALE tsl2561LuxB6T = 0x00d2 // 0.0128 * 2^LUX_SCALE tsl2561LuxM6T = 0x00fb // 0.0153 * 2^LUX_SCALE tsl2561LuxK7T = 0x029a // 1.3 * 2^RATIO_SCALE tsl2561LuxB7T = 0x0018 // 0.00146 * 2^LUX_SCALE tsl2561LuxM7T = 0x0012 // 0.00112 * 2^LUX_SCALE tsl2561LuxK8T = 0x029a // 1.3 * 2^RATIO_SCALE tsl2561LuxB8T = 0x0000 // 0.000 * 2^LUX_SCALE tsl2561LuxM8T = 0x0000 // 0.000 * 2^LUX_SCALE // Auto-gain thresholds tsl2561AgcTHi13MS = 4850 // Max value at Ti 13ms = 5047 tsl2561AgcTLo13MS = 100 tsl2561AgcTHi101MS = 36000 // Max value at Ti 101ms = 37177 tsl2561AgcTLo101MS = 200 tsl2561AgcTHi402MS = 63000 // Max value at Ti 402ms = 65535 tsl2561AgcTLo402MS = 500 // Clipping thresholds tsl2561Clipping13MS = 4900 tsl2561Clipping101MS = 37000 tsl2561Clipping402MS = 65000 ) const ( tsl2561RegisterControl = 0x00 tsl2561RegisterTiming = 0x01 tsl2561RegisterThreshholdLLow = 0x02 tsl2561RegisterThreshholdLHigh = 0x03 tsl2561RegisterThreshholdHLow = 0x04 tsl2561RegisterThreshholdHHigh = 0x05 tsl2561RegisterInterrupt = 0x06 tsl2561RegisterCRC = 0x08 tsl2561RegisterID = 0x0A tsl2561RegisterChan0Low = 0x0C tsl2561RegisterChan0High = 0x0D tsl2561RegisterChan1Low = 0x0E tsl2561RegisterChan1High = 0x0F ) // TSL2561IntegrationTime is the type of all valid integration time settings type TSL2561IntegrationTime int const ( // TSL2561IntegrationTime13MS integration time 13ms TSL2561IntegrationTime13MS TSL2561IntegrationTime = iota // 13.7ms // TSL2561IntegrationTime101MS integration time 101ms TSL2561IntegrationTime101MS // 101ms // TSL2561IntegrationTime402MS integration time 402ms TSL2561IntegrationTime402MS // 402ms ) // TSL2561Gain is the type of all valid gain settings type TSL2561Gain int const ( // TSL2561Gain1X gain == 1x TSL2561Gain1X TSL2561Gain = 0x00 // No gain // TSL2561Gain16X gain == 16x TSL2561Gain16X = 0x10 // 16x gain ) // TSL2561Driver is the gobot driver for the Adafruit Digital Luminosity/Lux/Light Sensor // // Datasheet: http://www.adafruit.com/datasheets/TSL2561.pdf // // Ported from the Adafruit driver at https://github.com/adafruit/Adafruit_TSL2561 by // K. Townsend type TSL2561Driver struct { *Driver autoGain bool gain TSL2561Gain integrationTime TSL2561IntegrationTime } // NewTSL2561Driver creates a new driver for the TSL2561 device. // // Params: // // c Connector - the Adaptor to use with this Driver // // Optional params: // // i2c.WithBus(int): bus to use with this driver // i2c.WithAddress(int): address to use with this driver // i2c.WithTSL2561Gain1X: sets the gain to 1X // i2c.WithTSL2561Gain16X: sets the gain to 16X // i2c.WithTSL2561AutoGain: turns on auto gain // i2c.WithTSL2561IntegrationTime13MS: sets integration time to 13ms // i2c.WithTSL2561IntegrationTime101MS: sets integration time to 101ms // i2c.WithTSL2561IntegrationTime402MS: sets integration time to 402ms func NewTSL2561Driver(c Connector, options ...func(Config)) *TSL2561Driver { d := &TSL2561Driver{ Driver: NewDriver(c, "TSL2561", TSL2561AddressFloat), integrationTime: TSL2561IntegrationTime402MS, gain: TSL2561Gain1X, autoGain: false, } d.afterStart = d.initialize for _, option := range options { option(d) } return d } // WithTSL2561Gain1X option sets the TSL2561Driver gain to 1X func WithTSL2561Gain1X(c Config) { d, ok := c.(*TSL2561Driver) if ok { d.gain = TSL2561Gain1X return } // TODO: return errors.New("Trying to set Gain for non-TSL2561Driver") } // WithTSL2561Gain16X option sets the TSL2561Driver gain to 16X func WithTSL2561Gain16X(c Config) { d, ok := c.(*TSL2561Driver) if ok { d.gain = TSL2561Gain16X return } // TODO: return errors.New("Trying to set Gain for non-TSL2561Driver") } // WithTSL2561AutoGain option turns on TSL2561Driver auto gain func WithTSL2561AutoGain(c Config) { d, ok := c.(*TSL2561Driver) if ok { d.autoGain = true return } // TODO: return errors.New("Trying to set Auto Gain for non-TSL2561Driver") } func withTSL2561IntegrationTime(iTime TSL2561IntegrationTime) func(Config) { return func(c Config) { d, ok := c.(*TSL2561Driver) if ok { d.integrationTime = iTime return } // TODO: return errors.New("Trying to set integration time for non-TSL2561Driver") } } // WithTSL2561IntegrationTime13MS option sets the TSL2561Driver integration time // to 13ms func WithTSL2561IntegrationTime13MS(c Config) { withTSL2561IntegrationTime(TSL2561IntegrationTime13MS)(c) } // WithTSL2561IntegrationTime101MS option sets the TSL2561Driver integration time // to 101ms func WithTSL2561IntegrationTime101MS(c Config) { withTSL2561IntegrationTime(TSL2561IntegrationTime101MS)(c) } // WithTSL2561IntegrationTime402MS option sets the TSL2561Driver integration time // to 402ms func WithTSL2561IntegrationTime402MS(c Config) { withTSL2561IntegrationTime(TSL2561IntegrationTime402MS)(c) } // SetIntegrationTime sets integrations time for the TSL2561 func (d *TSL2561Driver) SetIntegrationTime(time TSL2561IntegrationTime) error { if err := d.enable(); err != nil { return err } timeGainVal := uint8(time) | uint8(d.gain) //nolint:gosec // TODO: fix later if err := d.writeByteData(tsl2561CommandBit|tsl2561RegisterTiming, timeGainVal); err != nil { return err } d.integrationTime = time return d.disable() } // SetGain adjusts the TSL2561 gain (sensitivity to light) func (d *TSL2561Driver) SetGain(gain TSL2561Gain) error { if err := d.enable(); err != nil { return err } timeGainVal := uint8(d.integrationTime) | uint8(gain) //nolint:gosec // TODO: fix later if err := d.writeByteData(tsl2561CommandBit|tsl2561RegisterTiming, timeGainVal); err != nil { return err } d.gain = gain return d.disable() } // GetLuminocity gets the broadband and IR only values from the TSL2561, // adjusting gain if auto-gain is enabled func (d *TSL2561Driver) GetLuminocity() (uint16, uint16, error) { // if auto gain disabled get a single reading and continue if !d.autoGain { return d.getData() } agcCheck := false hi, lo := d.getHiLo() // Read data until we find a valid range var broadband uint16 var ir uint16 var err error valid := false for { broadband, ir, err = d.getData() if err != nil { return broadband, ir, err } // Run an auto-gain check if we haven't already done so if !agcCheck { switch { case (broadband < lo) && (d.gain == TSL2561Gain1X): // increase gain and try again err = d.SetGain(TSL2561Gain16X) if err != nil { return broadband, ir, err } agcCheck = true case (broadband > hi) && (d.gain == TSL2561Gain16X): // drop gain and try again err = d.SetGain(TSL2561Gain1X) if err != nil { return broadband, ir, err } agcCheck = true default: // Reading is either valid, or we're already at the chips // limits valid = true } } else { // If we've already adjusted the gain once, just return the new results. // This avoids endless loops where a value is at one extreme pre-gain, // and the other extreme post-gain valid = true } if valid { break } } return broadband, ir, err } // CalculateLux converts raw sensor values to the standard SI Lux equivalent. // Returns 65536 if the sensor is saturated. func (d *TSL2561Driver) CalculateLux(broadband uint16, ir uint16) uint32 { var channel1 uint32 var channel0 uint32 // Set cliplevel and scaling based on integration time clipThreshold, chScale := d.getClipScaling() // Saturated sensor if (broadband > clipThreshold) || (ir > clipThreshold) { return 65536 } // Adjust scale for gain if d.gain == TSL2561Gain1X { chScale = chScale * 16 } channel0 = (uint32(broadband) * chScale) >> tsl2561LuxChScale channel1 = (uint32(ir) * chScale) >> tsl2561LuxChScale // Find the ratio of the channel values (channel1 / channel0) var ratio1 uint32 if channel0 != 0 { ratio1 = (channel1 << (tsl2561LuxRatioScale + 1)) / channel0 } // Round the ratio value ratio := (ratio1 + 1) / 2 b, m := d.getBM(ratio) var temp uint32 if (channel0 * b) > (channel1 * m) { temp = (channel0 * b) - (channel1 * m) } // Round lsb (2^(LUX_SCALE+1)) temp += (1 << (tsl2561LuxLuxScale - 1)) // Strip off fractional portion lux := temp >> tsl2561LuxLuxScale return lux } func (d *TSL2561Driver) enable() error { return d.writeByteData(uint8(tsl2561CommandBit|tsl2561RegisterControl), tsl2561ControlPowerOn) } func (d *TSL2561Driver) disable() error { return d.writeByteData(uint8(tsl2561CommandBit|tsl2561RegisterControl), tsl2561ControlPowerOff) } func (d *TSL2561Driver) getData() (uint16, uint16, error) { if err := d.enable(); err != nil { return 0, 0, err } d.waitForADC() // Reads a two byte value from channel 0 (visible + infrared) broadband, err := d.readWordData(tsl2561CommandBit | tsl2561WordBit | tsl2561RegisterChan0Low) if err != nil { return 0, 0, err } // Reads a two byte value from channel 1 (infrared) ir, err := d.readWordData(tsl2561CommandBit | tsl2561WordBit | tsl2561RegisterChan1Low) if err != nil { return 0, 0, err } err = d.disable() return broadband, ir, err } //nolint:nonamedreturns // is sufficient here func (d *TSL2561Driver) getHiLo() (hi, lo uint16) { switch d.integrationTime { case TSL2561IntegrationTime13MS: hi = tsl2561AgcTHi13MS lo = tsl2561AgcTLo13MS case TSL2561IntegrationTime101MS: hi = tsl2561AgcTHi101MS lo = tsl2561AgcTLo101MS case TSL2561IntegrationTime402MS: hi = tsl2561AgcTHi402MS lo = tsl2561AgcTLo402MS } return } //nolint:nonamedreturns // is sufficient here func (d *TSL2561Driver) getClipScaling() (clipThreshold uint16, chScale uint32) { switch d.integrationTime { case TSL2561IntegrationTime13MS: clipThreshold = tsl2561Clipping13MS chScale = tsl2561LuxCHScaleTInt0 case TSL2561IntegrationTime101MS: clipThreshold = tsl2561Clipping101MS chScale = tsl2561LuxChScaleTInt1 case TSL2561IntegrationTime402MS: clipThreshold = tsl2561Clipping402MS chScale = (1 << tsl2561LuxChScale) } return } //nolint:nonamedreturns // is sufficient here func (d *TSL2561Driver) getBM(ratio uint32) (b uint32, m uint32) { switch { case ratio <= tsl2561LuxK1T: b = tsl2561LuxB1T m = tsl2561LuxM1T case (ratio <= tsl2561LuxK2T): b = tsl2561LuxB2T m = tsl2561LuxM2T case (ratio <= tsl2561LuxK3T): b = tsl2561LuxB3T m = tsl2561LuxM3T case (ratio <= tsl2561LuxK4T): b = tsl2561LuxB4T m = tsl2561LuxM4T case (ratio <= tsl2561LuxK5T): b = tsl2561LuxB5T m = tsl2561LuxM5T case (ratio <= tsl2561LuxK6T): b = tsl2561LuxB6T m = tsl2561LuxM6T case (ratio <= tsl2561LuxK7T): b = tsl2561LuxB7T m = tsl2561LuxM7T case (ratio > tsl2561LuxK8T): // TODO: there is a gap here... b = tsl2561LuxB8T m = tsl2561LuxM8T } return } func (d *TSL2561Driver) waitForADC() { switch d.integrationTime { case TSL2561IntegrationTime13MS: time.Sleep(15 * time.Millisecond) case TSL2561IntegrationTime101MS: time.Sleep(120 * time.Millisecond) case TSL2561IntegrationTime402MS: time.Sleep(450 * time.Millisecond) } } func (d *TSL2561Driver) initialize() error { if err := d.enable(); err != nil { return err } if initialized, err := d.readByteData(tsl2561RegisterID); err != nil { return err } else if (initialized & 0x0A) == 0 { return fmt.Errorf("TSL2561 device not found (0x%X)", initialized) } if err := d.SetIntegrationTime(d.integrationTime); err != nil { return err } if err := d.SetGain(d.gain); err != nil { return err } if err := d.disable(); err != nil { return err } return nil } ================================================ FILE: drivers/i2c/tsl2561_driver_test.go ================================================ package i2c import ( "bytes" "encoding/binary" "errors" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) // this ensures that the implementation is based on i2c.Driver, which implements the gobot.Driver // and tests all implementations, so no further tests needed here for gobot.Driver interface var _ gobot.Driver = (*TSL2561Driver)(nil) func initTestTSL2561DriverStarted() (*TSL2561Driver, *i2cTestAdaptor) { d, a := initTestTSL2561Driver() if err := d.Start(); err != nil { panic(err) } return d, a } func initTestTSL2561Driver() (*TSL2561Driver, *i2cTestAdaptor) { a := newI2cTestAdaptor() d := NewTSL2561Driver(a, WithTSL2561IntegrationTime13MS) // to reduce sleep time to minimum a.i2cReadImpl = func(b []byte) (int, error) { buf := new(bytes.Buffer) // Mock device responding 0xA _ = binary.Write(buf, binary.LittleEndian, uint8(0x0A)) copy(b, buf.Bytes()) return buf.Len(), nil } return d, a } func TestNewTSL2561Driver(t *testing.T) { var di interface{} = NewTSL2561Driver(newI2cTestAdaptor()) d, ok := di.(*TSL2561Driver) if !ok { require.Fail(t, "NewTSL2561Driver() should have returned a *TSL2561Driver") } assert.NotNil(t, d.Driver) assert.True(t, strings.HasPrefix(d.Name(), "TSL2561")) assert.Equal(t, 0x39, d.defaultAddress) assert.False(t, d.autoGain) assert.Equal(t, TSL2561Gain(0), d.gain) assert.Equal(t, TSL2561IntegrationTime(2), d.integrationTime) } func TestTSL2561DriverOptions(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithBus() option and // least one of this driver. Further tests for options can also be done by call of "WithOption(val)(d)". d := NewTSL2561Driver(newI2cTestAdaptor(), WithBus(2), WithTSL2561AutoGain) assert.Equal(t, 2, d.GetBusOrDefault(1)) assert.True(t, d.autoGain) } func TestTSL2561DriverStart(t *testing.T) { // arrange d, _ := initTestTSL2561Driver() // act, assert require.NoError(t, d.Start()) } func TestTSL2561DriverStartNotFound(t *testing.T) { d, a := initTestTSL2561Driver() a.i2cReadImpl = func(b []byte) (int, error) { buf := new(bytes.Buffer) buf.Write([]byte{1}) copy(b, buf.Bytes()) return buf.Len(), nil } require.ErrorContains(t, d.Start(), "TSL2561 device not found (0x1)") } func TestTSL2561DriverHalt(t *testing.T) { // arrange d, _ := initTestTSL2561Driver() // act, assert require.NoError(t, d.Halt()) // must be idempotent require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestTSL2561DriverValidOptions(t *testing.T) { a := newI2cTestAdaptor() d := NewTSL2561Driver(a, WithTSL2561IntegrationTime101MS, WithAddress(TSL2561AddressLow), WithTSL2561AutoGain) assert.NotNil(t, d) assert.True(t, d.autoGain) assert.Equal(t, TSL2561IntegrationTime101MS, d.integrationTime) } func TestTSL2561DriverMoreOptions(t *testing.T) { a := newI2cTestAdaptor() d := NewTSL2561Driver(a, WithTSL2561IntegrationTime101MS, WithAddress(TSL2561AddressLow), WithTSL2561Gain16X) assert.NotNil(t, d) assert.False(t, d.autoGain) assert.Equal(t, TSL2561Gain(TSL2561Gain16X), d.gain) } func TestTSL2561DriverEvenMoreOptions(t *testing.T) { a := newI2cTestAdaptor() d := NewTSL2561Driver(a, WithTSL2561IntegrationTime13MS, WithAddress(TSL2561AddressLow), WithTSL2561Gain1X) assert.NotNil(t, d) assert.False(t, d.autoGain) assert.Equal(t, TSL2561Gain1X, d.gain) assert.Equal(t, TSL2561IntegrationTime13MS, d.integrationTime) } func TestTSL2561DriverYetEvenMoreOptions(t *testing.T) { a := newI2cTestAdaptor() d := NewTSL2561Driver(a, WithTSL2561IntegrationTime402MS, WithAddress(TSL2561AddressLow), WithTSL2561AutoGain) assert.NotNil(t, d) assert.True(t, d.autoGain) assert.Equal(t, TSL2561IntegrationTime402MS, d.integrationTime) } func TestTSL2561DriverGetDataWriteError(t *testing.T) { d, a := initTestTSL2561DriverStarted() a.i2cWriteImpl = func([]byte) (int, error) { return 0, errors.New("write error") } _, _, err := d.getData() require.ErrorContains(t, err, "write error") } func TestTSL2561DriverGetDataReadError(t *testing.T) { d, a := initTestTSL2561DriverStarted() a.i2cReadImpl = func([]byte) (int, error) { return 0, errors.New("read error") } _, _, err := d.getData() require.ErrorContains(t, err, "read error") } func TestTSL2561DriverGetLuminocity(t *testing.T) { d, a := initTestTSL2561DriverStarted() // TODO: obtain real sensor data here for testing a.i2cReadImpl = func(b []byte) (int, error) { buf := new(bytes.Buffer) buf.Write([]byte{77, 48}) copy(b, buf.Bytes()) return buf.Len(), nil } bb, ir, err := d.GetLuminocity() require.NoError(t, err) assert.Equal(t, uint16(12365), bb) assert.Equal(t, uint16(12365), ir) d.integrationTime = TSL2561IntegrationTime402MS assert.Equal(t, uint32(72), d.CalculateLux(bb, ir)) } func TestTSL2561DriverGetLuminocityAutoGain(t *testing.T) { a := newI2cTestAdaptor() d := NewTSL2561Driver(a, WithTSL2561IntegrationTime13MS, // to reduce sleep time to minimum WithAddress(TSL2561AddressLow), WithTSL2561AutoGain) // TODO: obtain real sensor data here for testing a.i2cReadImpl = func(b []byte) (int, error) { buf := new(bytes.Buffer) buf.Write([]byte{77, 48}) copy(b, buf.Bytes()) return buf.Len(), nil } _ = d.Start() // because we override start procedure bb, ir, err := d.GetLuminocity() require.NoError(t, err) assert.Equal(t, uint16(12365), bb) assert.Equal(t, uint16(12365), ir) d.integrationTime = TSL2561IntegrationTime402MS assert.Equal(t, uint32(72), d.CalculateLux(bb, ir)) } func TestTSL2561SetIntegrationTimeError(t *testing.T) { d, a := initTestTSL2561DriverStarted() a.i2cWriteImpl = func([]byte) (int, error) { return 0, errors.New("write error") } require.ErrorContains(t, d.SetIntegrationTime(TSL2561IntegrationTime101MS), "write error") } func TestTSL2561SetGainError(t *testing.T) { d, a := initTestTSL2561DriverStarted() a.i2cWriteImpl = func([]byte) (int, error) { return 0, errors.New("write error") } require.ErrorContains(t, d.SetGain(TSL2561Gain16X), "write error") } func TestTSL2561getHiLo13MS(t *testing.T) { a := newI2cTestAdaptor() d := NewTSL2561Driver(a, WithTSL2561IntegrationTime13MS, WithTSL2561AutoGain) hi, lo := d.getHiLo() assert.Equal(t, uint16(tsl2561AgcTHi13MS), hi) assert.Equal(t, uint16(tsl2561AgcTLo13MS), lo) } func TestTSL2561getHiLo101MS(t *testing.T) { a := newI2cTestAdaptor() d := NewTSL2561Driver(a, WithTSL2561IntegrationTime101MS, WithTSL2561AutoGain) hi, lo := d.getHiLo() assert.Equal(t, uint16(tsl2561AgcTHi101MS), hi) assert.Equal(t, uint16(tsl2561AgcTLo101MS), lo) } func TestTSL2561getHiLo402MS(t *testing.T) { a := newI2cTestAdaptor() d := NewTSL2561Driver(a, WithTSL2561IntegrationTime402MS, WithTSL2561AutoGain) hi, lo := d.getHiLo() assert.Equal(t, uint16(tsl2561AgcTHi402MS), hi) assert.Equal(t, uint16(tsl2561AgcTLo402MS), lo) } func TestTSL2561getClipScaling13MS(t *testing.T) { a := newI2cTestAdaptor() d := NewTSL2561Driver(a, WithTSL2561IntegrationTime13MS, WithTSL2561AutoGain) c, s := d.getClipScaling() d.waitForADC() assert.Equal(t, uint16(tsl2561Clipping13MS), c) assert.Equal(t, uint32(tsl2561LuxCHScaleTInt0), s) } func TestTSL2561getClipScaling101MS(t *testing.T) { a := newI2cTestAdaptor() d := NewTSL2561Driver(a, WithTSL2561IntegrationTime101MS, WithTSL2561AutoGain) c, s := d.getClipScaling() d.waitForADC() assert.Equal(t, uint16(tsl2561Clipping101MS), c) assert.Equal(t, uint32(tsl2561LuxChScaleTInt1), s) } func TestTSL2561getClipScaling402MS(t *testing.T) { a := newI2cTestAdaptor() d := NewTSL2561Driver(a, WithTSL2561IntegrationTime402MS, WithTSL2561AutoGain) c, s := d.getClipScaling() d.waitForADC() assert.Equal(t, uint16(tsl2561Clipping402MS), c) assert.Equal(t, uint32(1< 0 { return fmt.Errorf("'Halt' the driver %s", strings.Join(errors, ", ")) } return nil } // Read returns the current reading from the given pin of the driver // For the analog output pin the last written value is returned func (y *YL40Driver) Read(pin YL40Pin) (float64, error) { switch pin { case YL40Bri: return y.aBri.Read() case YL40Temp: return y.aTemp.Read() case YL40AIN2: return y.aAIN2.Read() case YL40Poti: return y.aPoti.Read() case YL40AOUT: return y.aOut.Value(), nil default: return 0, fmt.Errorf("analog reading from pin '%s' not supported", pin) } } // ReadBrightness returns the current reading from brightness pin of the driver func (y *YL40Driver) ReadBrightness() (float64, error) { return y.Read(YL40Bri) } // ReadTemperature returns the current reading from temperature pin of the driver func (y *YL40Driver) ReadTemperature() (float64, error) { return y.Read(YL40Temp) } // ReadAIN2 returns the current reading from analog input pin 2 pin of the driver func (y *YL40Driver) ReadAIN2() (float64, error) { return y.Read(YL40AIN2) } // ReadPotentiometer returns the current reading from potentiometer pin of the driver func (y *YL40Driver) ReadPotentiometer() (float64, error) { return y.Read(YL40Poti) } // Value returns the last read or written value from the given pin of the driver func (y *YL40Driver) Value(pin YL40Pin) (float64, error) { switch pin { case YL40Bri: return y.aBri.Value(), nil case YL40Temp: return y.aTemp.Value(), nil case YL40AIN2: return y.aAIN2.Value(), nil case YL40Poti: return y.aPoti.Value(), nil case YL40AOUT: return y.aOut.Value(), nil default: return 0, fmt.Errorf("get analog value from pin '%s' not supported", pin) } } // Brightness returns the last read brightness of the driver func (y *YL40Driver) Brightness() (float64, error) { return y.Value(YL40Bri) } // Temperature returns the last read temperature of the driver func (y *YL40Driver) Temperature() (float64, error) { return y.Value(YL40Temp) } // AIN2 returns the last read analog input value of the driver func (y *YL40Driver) AIN2() (float64, error) { return y.Value(YL40AIN2) } // Potentiometer returns the last read potentiometer value of the driver func (y *YL40Driver) Potentiometer() (float64, error) { return y.Value(YL40Poti) } // AOUT returns the last written value of the driver func (y *YL40Driver) AOUT() (float64, error) { return y.Value(YL40AOUT) } // Write writes the given value to the analog output func (y *YL40Driver) Write(val float64) error { return y.aOut.Write(val) } ================================================ FILE: drivers/i2c/yl40_driver_test.go ================================================ package i2c import ( "fmt" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func initTestYL40DriverWithStubbedAdaptor() (*YL40Driver, *i2cTestAdaptor) { adaptor := newI2cTestAdaptor() yl := NewYL40Driver(adaptor, WithPCF8591With400kbitStabilization(0, 2)) WithPCF8591ForceRefresh(1)(yl.PCF8591Driver) _ = yl.Start() return yl, adaptor } func TestNewYL40Driver(t *testing.T) { // arrange, act yl := NewYL40Driver(newI2cTestAdaptor()) // assert assert.NotNil(t, yl.PCF8591Driver) assert.Equal(t, time.Duration(0), yl.conf.sensors[YL40Bri].interval) assert.NotNil(t, yl.conf.sensors[YL40Bri].scaler) assert.Equal(t, time.Duration(0), yl.conf.sensors[YL40Temp].interval) assert.NotNil(t, yl.conf.sensors[YL40Temp].scaler) assert.Equal(t, time.Duration(0), yl.conf.sensors[YL40AIN2].interval) assert.NotNil(t, yl.conf.sensors[YL40AIN2].scaler) assert.Equal(t, time.Duration(0), yl.conf.sensors[YL40Poti].interval) assert.NotNil(t, yl.conf.sensors[YL40Poti].scaler) assert.NotNil(t, yl.conf.aOutScaler) assert.NotNil(t, yl.aBri) assert.NotNil(t, yl.aTemp) assert.NotNil(t, yl.aAIN2) assert.NotNil(t, yl.aPoti) assert.NotNil(t, yl.aOut) } func TestYL40DriverWithYL40Interval(t *testing.T) { // arrange, act yl := NewYL40Driver(newI2cTestAdaptor(), WithYL40Interval(YL40Bri, 100), WithYL40Interval(YL40Temp, 101), WithYL40Interval(YL40AIN2, 102), WithYL40Interval(YL40Poti, 103), ) // assert assert.Equal(t, time.Duration(100), yl.conf.sensors[YL40Bri].interval) assert.Equal(t, time.Duration(101), yl.conf.sensors[YL40Temp].interval) assert.Equal(t, time.Duration(102), yl.conf.sensors[YL40AIN2].interval) assert.Equal(t, time.Duration(103), yl.conf.sensors[YL40Poti].interval) } func TestYL40DriverWithYL40InputScaler(t *testing.T) { // arrange yl := NewYL40Driver(newI2cTestAdaptor()) f1 := func(input int) float64 { return 0.1 } f2 := func(input int) float64 { return 0.2 } f3 := func(input int) float64 { return 0.3 } f4 := func(input int) float64 { return 0.4 } // act WithYL40InputScaler(YL40Bri, f1)(yl) WithYL40InputScaler(YL40Temp, f2)(yl) WithYL40InputScaler(YL40AIN2, f3)(yl) WithYL40InputScaler(YL40Poti, f4)(yl) // assert assert.True(t, fEqual(yl.conf.sensors[YL40Bri].scaler, f1)) assert.True(t, fEqual(yl.conf.sensors[YL40Temp].scaler, f2)) assert.True(t, fEqual(yl.conf.sensors[YL40AIN2].scaler, f3)) assert.True(t, fEqual(yl.conf.sensors[YL40Poti].scaler, f4)) } func TestYL40DriverWithYL40WithYL40OutputScaler(t *testing.T) { // arrange yl := NewYL40Driver(newI2cTestAdaptor()) fo := func(input float64) int { return 123 } // act WithYL40OutputScaler(fo)(yl) // assert assert.True(t, fEqual(yl.conf.aOutScaler, fo)) } func TestYL40DriverReadBrightness(t *testing.T) { // sequence to read the input with PCF8591, see there tests // arrange yl, adaptor := initTestYL40DriverWithStubbedAdaptor() adaptor.written = []byte{} // reset writes of Start() and former test // ANAOUT was switched on by Start() ctrlByteOn := uint8(pcf8591_ANAON) | uint8(pcf8591_ALLSINGLE) | uint8(pcf8591_CHAN0) returnRead := []uint8{0x01, 0x02, 0x03, 73} // scaler for brightness is 255..0 => 0..1000 want := float64(255-returnRead[3]) * 1000 / 255 // arrange reads numCallsRead := 0 adaptor.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ if numCallsRead == 1 { b = returnRead[0:len(b)] } if numCallsRead == 2 { b[0] = returnRead[len(returnRead)-1] } return len(b), nil } // act got, err := yl.ReadBrightness() got2, err2 := yl.Brightness() // assert require.NoError(t, err) assert.Len(t, adaptor.written, 1) assert.Equal(t, ctrlByteOn, adaptor.written[0]) assert.Equal(t, 2, numCallsRead) assert.InDelta(t, want, got, 0.0) require.NoError(t, err2) assert.InDelta(t, want, got2, 0.0) } func TestYL40DriverReadTemperature(t *testing.T) { // sequence to read the input with PCF8591, see there tests // arrange yl, adaptor := initTestYL40DriverWithStubbedAdaptor() adaptor.written = []byte{} // reset writes of Start() and former test // ANAOUT was switched on by Start() ctrlByteOn := uint8(pcf8591_ANAON) | uint8(pcf8591_ALLSINGLE) | uint8(pcf8591_CHAN1) returnRead := []uint8{0x01, 0x02, 0x03, 232} // scaler for temperature is 255..0 => NTC °C, 232 relates to nearly 25°C // in TestTemperatureSensorDriverNtcScaling we have already used this NTC values want := 24.805280460718336 // arrange reads numCallsRead := 0 adaptor.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ if numCallsRead == 1 { b = returnRead[0:len(b)] } if numCallsRead == 2 { b[0] = returnRead[len(returnRead)-1] } return len(b), nil } // act got, err := yl.ReadTemperature() got2, err2 := yl.Temperature() // assert require.NoError(t, err) assert.Len(t, adaptor.written, 1) assert.Equal(t, ctrlByteOn, adaptor.written[0]) assert.Equal(t, 2, numCallsRead) assert.InDelta(t, want, got, 0.0) require.NoError(t, err2) assert.InDelta(t, want, got2, 0.0) } func TestYL40DriverReadAIN2(t *testing.T) { // sequence to read the input with PCF8591, see there tests // arrange yl, adaptor := initTestYL40DriverWithStubbedAdaptor() adaptor.written = []byte{} // reset writes of Start() and former test // ANAOUT was switched on by Start() ctrlByteOn := uint8(pcf8591_ANAON) | uint8(pcf8591_ALLSINGLE) | uint8(pcf8591_CHAN2) returnRead := []uint8{0x01, 0x02, 0x03, 72} // scaler for analog input 2 is 0..255 => 0..3.3 want := float64(returnRead[3]) * 33 / 2550 // arrange reads numCallsRead := 0 adaptor.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ if numCallsRead == 1 { b = returnRead[0:len(b)] } if numCallsRead == 2 { b[0] = returnRead[len(returnRead)-1] } return len(b), nil } // act got, err := yl.ReadAIN2() got2, err2 := yl.AIN2() // assert require.NoError(t, err) assert.Len(t, adaptor.written, 1) assert.Equal(t, ctrlByteOn, adaptor.written[0]) assert.Equal(t, 2, numCallsRead) assert.InDelta(t, want, got, 0.0) require.NoError(t, err2) assert.InDelta(t, want, got2, 0.0) } func TestYL40DriverReadPotentiometer(t *testing.T) { // sequence to read the input with PCF8591, see there tests // arrange yl, adaptor := initTestYL40DriverWithStubbedAdaptor() adaptor.written = []byte{} // reset writes of Start() and former test // ANAOUT was switched on by Start() ctrlByteOn := uint8(pcf8591_ANAON) | uint8(pcf8591_ALLSINGLE) | uint8(pcf8591_CHAN3) returnRead := []uint8{0x01, 0x02, 0x03, 63} // scaler for potentiometer is 255..0 => -100..100 want := float64(returnRead[3])*-200/255 + 100 // arrange reads numCallsRead := 0 adaptor.i2cReadImpl = func(b []byte) (int, error) { numCallsRead++ if numCallsRead == 1 { b = returnRead[0:len(b)] } if numCallsRead == 2 { b[0] = returnRead[len(returnRead)-1] } return len(b), nil } // act got, err := yl.ReadPotentiometer() got2, err2 := yl.Potentiometer() // assert require.NoError(t, err) assert.Len(t, adaptor.written, 1) assert.Equal(t, ctrlByteOn, adaptor.written[0]) assert.Equal(t, 2, numCallsRead) assert.InDelta(t, want, got, 0.0) require.NoError(t, err2) assert.InDelta(t, want, got2, 0.0) } func TestYL40DriverAnalogWrite(t *testing.T) { // sequence to write the output of PCF8591, see there // arrange pcf, adaptor := initTestYL40DriverWithStubbedAdaptor() adaptor.written = []byte{} // reset writes of Start() and former test ctrlByteOn := uint8(pcf8591_ANAON) want := uint8(175) // write is scaled by 0..3.3V => 0..255 write := float64(want) * 33 / 2550 // arrange writes adaptor.i2cWriteImpl = func(b []byte) (int, error) { return len(b), nil } // act err := pcf.Write(write) // assert require.NoError(t, err) assert.Len(t, adaptor.written, 2) assert.Equal(t, ctrlByteOn, adaptor.written[0]) assert.Equal(t, want, adaptor.written[1]) } func TestYL40DriverStart(t *testing.T) { yl := NewYL40Driver(newI2cTestAdaptor()) require.NoError(t, yl.Start()) } func TestYL40DriverHalt(t *testing.T) { yl := NewYL40Driver(newI2cTestAdaptor()) require.NoError(t, yl.Halt()) // must be idempotent require.NoError(t, yl.Start()) require.NoError(t, yl.Halt()) } func fEqual(want interface{}, got interface{}) bool { return fmt.Sprintf("%v", want) == fmt.Sprintf("%v", got) } ================================================ FILE: drivers/onewire/README.md ================================================ # 1-wire This package provides drivers for [1-wire](https://en.wikipedia.org/wiki/1-Wire) devices supported by Linux Kernel w1-gpio drivers. It must be used along with an adaptor such as [Tinker Board](https://gobot.io/documentation/platforms/asus/tinkerboard/) that supports the needed interfaces for 1-wire devices. ## Getting Started Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) ## Hardware Support Gobot has a extensible system for connecting to hardware devices. The following 1-wire devices are currently supported: - DS18B20 Temperature Sensor ================================================ FILE: drivers/onewire/ds18b20_driver.go ================================================ package onewire import ( "fmt" "math" "time" ) const ( ds18b20DefaultResolution = 12 ds18b20DefaultConversionTime = 750 temperatureCommand = "temperature" extPowerCommand = "ext_power" resolutionCommand = "resolution" convTimeCommand = "conv_time" ) // ds18b20OptionApplier needs to be implemented by each configurable option type type ds18b20OptionApplier interface { apply(cfg *ds18b20Configuration) } // ds18b20Configuration contains all changeable attributes of the driver. type ds18b20Configuration struct { scaleUnit func(int) float32 resolution uint8 conversionTime uint16 } // ds18b20UnitscalerOption is the type for applying another unit scaler to the configuration type ds18b20UnitscalerOption struct { unitscaler func(int) float32 } type ds18b20ResolutionOption uint8 type ds18b20ConversionTimeOption uint16 // DS18B20Driver is a driver for the DS18B20 1-wire temperature sensor. type DS18B20Driver struct { *driver ds18b20Cfg *ds18b20Configuration } // NewDS18B20Driver creates a new Gobot Driver for DS18B20 one wire temperature sensor. // // Params: // // a *Adaptor - the Adaptor to use with this Driver. // serial number int - the serial number of the device, without the family code // // Optional params: // // onewire.WithFahrenheit() // onewire.WithResolution(byte) // onewire.WithConversionTime(uint16) func NewDS18B20Driver(a connector, serialNumber uint64, opts ...interface{}) *DS18B20Driver { d := &DS18B20Driver{ driver: newDriver(a, "DS18B20", 0x28, serialNumber), ds18b20Cfg: &ds18b20Configuration{ scaleUnit: func(input int) float32 { return float32(input) / 1000 }, // 1000:1 in °C resolution: ds18b20DefaultResolution, conversionTime: ds18b20DefaultConversionTime, }, } d.afterStart = d.initialize d.beforeHalt = d.shutdown for _, opt := range opts { switch o := opt.(type) { case optionApplier: o.apply(d.driverCfg) case ds18b20OptionApplier: o.apply(d.ds18b20Cfg) default: panic(fmt.Sprintf("'%s' can not be applied on '%s'", opt, d.driverCfg.name)) } } return d } // WithFahrenheit substitute the default °C scaler by a scaler for °F func WithFahrenheit() ds18b20OptionApplier { // (1°C × 9/5) + 32 = 33,8°F unitscaler := func(input int) float32 { return float32(input)/1000*9.0/5.0 + 32.0 } return ds18b20UnitscalerOption{unitscaler: unitscaler} } // WithResolution substitute the default 12 bit resolution by the given one (9, 10, 11). The device will adjust // the conversion time automatically. Each smaller resolution will decrease the conversion time by a factor of 2. // Note: some devices are fixed in 12 bit mode only and do not support this feature (I/O error or just ignore it). // WithConversionTime() is most likely supported. func WithResolution(resolution uint8) ds18b20OptionApplier { return ds18b20ResolutionOption(resolution) } // WithConversionTime substitute the default 750 ms by the given one (93, 187, 375, 750). // Note: Devices will not adjust the resolution automatically. Some devices accept conversion time values different // from common specification. E.g. 10...1000, which leads to real conversion time of conversionTime+50ms. This needs // to be tested for your device and measured for your needs, e.g. by DebugConversionTime(0, 500, 5, true). func WithConversionTime(conversionTime uint16) ds18b20OptionApplier { return ds18b20ConversionTimeOption(conversionTime) } // Temperature returns the current temperature, in celsius degrees, if the default unit scaler is used. func (d *DS18B20Driver) Temperature() (float32, error) { d.mutex.Lock() defer d.mutex.Unlock() val, err := d.readInteger(temperatureCommand) if err != nil { return 0, err } return d.ds18b20Cfg.scaleUnit(val), nil } // Resolution returns the current resolution in bits (9, 10, 11, 12) func (d *DS18B20Driver) Resolution() (uint8, error) { d.mutex.Lock() defer d.mutex.Unlock() val, err := d.readInteger(resolutionCommand) if err != nil { return 0, err } if val < 9 || val > 12 { return 0, fmt.Errorf("the read value '%d' is out of range (9, 10, 11, 12)", val) } return uint8(val), nil } // IsExternalPowered returns whether the device is external or parasitic powered func (d *DS18B20Driver) IsExternalPowered() (bool, error) { d.mutex.Lock() defer d.mutex.Unlock() val, err := d.readInteger(extPowerCommand) if err != nil { return false, err } return val > 0, nil } // ConversionTime returns the conversion time in ms func (d *DS18B20Driver) ConversionTime() (uint16, error) { d.mutex.Lock() defer d.mutex.Unlock() val, err := d.readInteger(convTimeCommand) if err != nil { return 0, err } if val < 0 || val > math.MaxUint16 { return 0, fmt.Errorf("the read value '%d' is out of range (uint16)", val) } return uint16(val), nil } // DebugConversionTime try to set the conversion time and compare with real time to read temperature. func (d *DS18B20Driver) DebugConversionTime(start, end uint16, stepwide uint16, skipInvalid bool) { r, _ := d.Resolution() id, err := d.id() if err != nil { fmt.Println(err.Error()) return } fmt.Printf("\n---- Conversion time check for '%s'@%dbit %d..%d +%d ----\n", id, r, start, end, stepwide) fmt.Println("|r1(err)\t|w(err)\t\t|r2(err)\t|T(err)\t\t|real\t\t|diff\t\t|") fmt.Println("--------------------------------------------------------------------------------") for ct := start; ct < end; ct += stepwide { r1, e1 := d.ConversionTime() ew := d.writeInteger(convTimeCommand, int(ct)) r2, e2 := d.ConversionTime() time.Sleep(100 * time.Millisecond) // relax the system start := time.Now() temp, err := d.Temperature() dur := time.Since(start) valid := ct == r2 if valid || !skipInvalid { diff := dur - time.Duration(r2)*time.Millisecond fmt.Printf("|%d(%t)\t|%d(%t)\t|%d(%t)\t|%v(%t)\t|%s\t|%s\t|\n", r1, e1 != nil, ct, ew != nil, r2, e2 != nil, temp, err != nil, dur, diff) } } } func (d *DS18B20Driver) initialize() error { if d.ds18b20Cfg.resolution != ds18b20DefaultResolution { if err := d.writeInteger(resolutionCommand, int(d.ds18b20Cfg.resolution)); err != nil { return err } } if d.ds18b20Cfg.conversionTime != ds18b20DefaultConversionTime { return d.writeInteger(convTimeCommand, int(d.ds18b20Cfg.conversionTime)) } return nil } func (d *DS18B20Driver) shutdown() error { if d.connection == nil { return nil } if d.ds18b20Cfg.resolution != ds18b20DefaultResolution { if err := d.writeInteger(resolutionCommand, ds18b20DefaultResolution); err != nil { return err } } if d.ds18b20Cfg.conversionTime != ds18b20DefaultConversionTime { return d.writeInteger(convTimeCommand, int(ds18b20DefaultConversionTime)) } return nil } func (o ds18b20UnitscalerOption) apply(cfg *ds18b20Configuration) { cfg.scaleUnit = o.unitscaler } func (o ds18b20ResolutionOption) apply(cfg *ds18b20Configuration) { cfg.resolution = uint8(o) } func (o ds18b20ConversionTimeOption) apply(cfg *ds18b20Configuration) { cfg.conversionTime = uint16(o) } ================================================ FILE: drivers/onewire/ds18b20_driver_test.go ================================================ package onewire import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestNewDS18B20Driver(t *testing.T) { // arrange & act a := newOneWireTestAdaptor() d := NewDS18B20Driver(a, 2345) // assert assert.IsType(t, &DS18B20Driver{}, d) assert.NotNil(t, d.driver) assert.NotNil(t, d.ds18b20Cfg) assert.Equal(t, uint8(12), d.ds18b20Cfg.resolution) assert.Equal(t, uint16(750), d.ds18b20Cfg.conversionTime) assert.InDelta(t, float32(1), d.ds18b20Cfg.scaleUnit(1000), 0.0) } func TestDS18B20Start(t *testing.T) { tests := map[string]struct { cfgResolution uint8 cfgConvTime uint16 simulateErr bool wantCommands []string wantErr string }{ "start_ok": { cfgResolution: 12, cfgConvTime: 750, }, "start_change_resolution": { cfgResolution: 9, cfgConvTime: 750, wantCommands: []string{"resolution"}, }, "start_change_conversiontime": { cfgResolution: 12, cfgConvTime: 250, wantCommands: []string{"conv_time"}, }, "start_change_all": { cfgResolution: 8, cfgConvTime: 150, wantCommands: []string{"resolution", "conv_time"}, }, "error_start": { simulateErr: true, wantErr: "GetOneWireConnection error", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange a := newOneWireTestAdaptor() d := NewDS18B20Driver(a, 987654321) d.ds18b20Cfg.resolution = tc.cfgResolution d.ds18b20Cfg.conversionTime = tc.cfgConvTime a.retErr = tc.simulateErr // act err := d.Start() // assert if tc.wantErr != "" { require.EqualError(t, err, tc.wantErr) } else { require.NoError(t, err) } assert.Equal(t, tc.wantCommands, a.sendCommands) }) } } func TestDS18B20Halt(t *testing.T) { tests := map[string]struct { cfgResolution uint8 cfgConvTime uint16 simulateErr bool wantCommands []string wantErr string }{ "start_ok": { cfgResolution: 12, cfgConvTime: 750, }, "start_change_resolution": { cfgResolution: 9, cfgConvTime: 750, wantCommands: []string{"resolution"}, }, "start_change_conversiontime": { cfgResolution: 12, cfgConvTime: 250, wantCommands: []string{"conv_time"}, }, "start_change_all": { cfgResolution: 8, cfgConvTime: 150, wantCommands: []string{"resolution", "conv_time"}, }, "error_halt": { cfgResolution: 8, // to force writing simulateErr: true, wantCommands: []string{"resolution"}, wantErr: "WriteInteger error", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange a := newOneWireTestAdaptor() d := NewDS18B20Driver(a, 987654321) require.NoError(t, d.Start()) d.ds18b20Cfg.resolution = tc.cfgResolution d.ds18b20Cfg.conversionTime = tc.cfgConvTime a.retErr = tc.simulateErr // act err := d.Halt() // assert if tc.wantErr != "" { require.EqualError(t, err, tc.wantErr) } else { require.NoError(t, err) } assert.Equal(t, tc.wantCommands, a.sendCommands) }) } } func TestDS18B20HaltIdempotent(t *testing.T) { // arrange d := NewDS18B20Driver(newOneWireTestAdaptor(), 2345) // to trigger write calls: d.ds18b20Cfg.resolution = ds18b20DefaultResolution + 1 d.ds18b20Cfg.conversionTime = ds18b20DefaultConversionTime + 2 // act, assert require.NoError(t, d.Halt()) // must be idempotent require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestDS18B20Temperature(t *testing.T) { const readValue = 24500 tests := map[string]struct { simulateErr bool wantVal float32 wantErr string }{ "read_ok": { wantVal: 24.5, }, "error_read": { simulateErr: true, wantErr: "ReadInteger error", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange a := newOneWireTestAdaptor() a.lastValue = readValue d := NewDS18B20Driver(a, 987654321) require.NoError(t, d.Start()) a.retErr = tc.simulateErr // act got, err := d.Temperature() // assert if tc.wantErr != "" { require.EqualError(t, err, tc.wantErr) } else { require.NoError(t, err) } assert.Equal(t, []string{"temperature"}, a.sendCommands) assert.InDelta(t, tc.wantVal, got, 0.0) }) } } func TestDS18B20Resolution(t *testing.T) { tests := map[string]struct { readValue int simulateErr bool wantVal float32 wantErr string }{ "read_ok": { readValue: 9, wantVal: 9, }, "error_below_min": { readValue: 8, wantErr: "the read value '8' is out of range (9, 10, 11, 12)", }, "error_above_max": { readValue: 13, wantErr: "the read value '13' is out of range (9, 10, 11, 12)", }, "error_read": { simulateErr: true, wantErr: "ReadInteger error", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange a := newOneWireTestAdaptor() a.lastValue = tc.readValue d := NewDS18B20Driver(a, 987654321) require.NoError(t, d.Start()) a.retErr = tc.simulateErr // act got, err := d.Resolution() // assert if tc.wantErr != "" { require.EqualError(t, err, tc.wantErr) } else { require.NoError(t, err) } assert.Equal(t, []string{"resolution"}, a.sendCommands) assert.InDelta(t, tc.wantVal, got, 0.0) }) } } func TestDS18B20IsExternalPowered(t *testing.T) { tests := map[string]struct { readValue int simulateErr bool wantVal bool wantErr string }{ "read_true": { readValue: 1, wantVal: true, }, "read_false": { readValue: 0, wantVal: false, }, "error_read": { simulateErr: true, wantErr: "ReadInteger error", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange a := newOneWireTestAdaptor() a.lastValue = tc.readValue d := NewDS18B20Driver(a, 987654321) require.NoError(t, d.Start()) a.retErr = tc.simulateErr // act got, err := d.IsExternalPowered() // assert if tc.wantErr != "" { require.EqualError(t, err, tc.wantErr) } else { require.NoError(t, err) } assert.Equal(t, []string{"ext_power"}, a.sendCommands) assert.Equal(t, tc.wantVal, got) }) } } func TestDS18B20ConversionTime(t *testing.T) { tests := map[string]struct { readValue int simulateErr bool wantVal float32 wantErr string }{ "read_ok": { readValue: 20, wantVal: 20, }, "error_below_min": { readValue: -1, wantErr: "the read value '-1' is out of range (uint16)", }, "error_above_max": { readValue: 65536, wantErr: "the read value '65536' is out of range (uint16)", }, "error_read": { simulateErr: true, wantErr: "ReadInteger error", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange a := newOneWireTestAdaptor() a.lastValue = tc.readValue d := NewDS18B20Driver(a, 987654321) require.NoError(t, d.Start()) a.retErr = tc.simulateErr // act got, err := d.ConversionTime() // assert if tc.wantErr != "" { require.EqualError(t, err, tc.wantErr) } else { require.NoError(t, err) } assert.Equal(t, []string{"conv_time"}, a.sendCommands) assert.InDelta(t, tc.wantVal, got, 0.0) }) } } func TestDS18B20WithName(t *testing.T) { // This is a general test, that parent options are applied by using the WithName() option. // All other configuration options can also be tested by With..(val).apply(cfg). // arrange const newName = "new name" a := newOneWireTestAdaptor() // act d := NewDS18B20Driver(a, 2345, WithName(newName)) // assert assert.Equal(t, newName, d.Name()) } func TestDS18B20WithResolution(t *testing.T) { // This is a general test, that options are applied by using the WithResolution() option. // All other configuration options can also be tested by With..(val).apply(cfg). // arrange const newValue = uint8(9) a := newOneWireTestAdaptor() // act d := NewDS18B20Driver(a, 2345, WithResolution(newValue)) // assert assert.Equal(t, newValue, d.ds18b20Cfg.resolution) } func TestDS18B20WithConversionTime(t *testing.T) { // arrange const newValue = uint16(93) cfg := ds18b20Configuration{conversionTime: 15} // act WithConversionTime(newValue).apply(&cfg) // assert assert.Equal(t, newValue, cfg.conversionTime) } func TestDS18B20WithFahrenheit(t *testing.T) { // arrange cfg := ds18b20Configuration{} // act WithFahrenheit().apply(&cfg) // assert assert.InDelta(t, 33.8, cfg.scaleUnit(1000), 0.01) } ================================================ FILE: drivers/onewire/helpers_test.go ================================================ package onewire import ( "errors" "sync" ) type oneWireAdaptorMock struct { mtx sync.Mutex familyCode byte serialNumber uint64 sendCommands []string lastValue int retErr bool } func newOneWireTestAdaptor() *oneWireAdaptorMock { return &oneWireAdaptorMock{} } func (am *oneWireAdaptorMock) GetOneWireConnection(familyCode byte, serialNumber uint64) (Connection, error) { am.mtx.Lock() defer am.mtx.Unlock() if am.retErr { return nil, errors.New("GetOneWireConnection error") } am.familyCode = familyCode am.serialNumber = serialNumber return am, nil } // implementations of gobot.OneWireOperations func (am *oneWireAdaptorMock) ID() string { return "" } func (am *oneWireAdaptorMock) ReadData(command string, data []byte) error { am.sendCommands = append(am.sendCommands, command) return nil } func (am *oneWireAdaptorMock) WriteData(command string, data []byte) error { am.sendCommands = append(am.sendCommands, command) return nil } func (am *oneWireAdaptorMock) ReadInteger(command string) (int, error) { am.sendCommands = append(am.sendCommands, command) if am.retErr { return 0, errors.New("ReadInteger error") } return am.lastValue, nil } func (am *oneWireAdaptorMock) WriteInteger(command string, val int) error { am.sendCommands = append(am.sendCommands, command) if am.retErr { return errors.New("WriteInteger error") } return nil } func (am *oneWireAdaptorMock) Close() error { return nil } // implementations of gobot.Connection, respectively gobot.Adaptor func (am *oneWireAdaptorMock) Name() string { return "" } func (am *oneWireAdaptorMock) SetName(name string) {} func (am *oneWireAdaptorMock) Connect() error { return nil } func (am *oneWireAdaptorMock) Finalize() error { return nil } type oneWireSystemDeviceMock struct { id string lastValue int lastData []byte retErr error lastCommand string } //nolint:unparam // ok here func newOneWireTestSystemDevice(id string) *oneWireSystemDeviceMock { return &oneWireSystemDeviceMock{id: id} } func (dm *oneWireSystemDeviceMock) ID() string { return dm.id } func (dm *oneWireSystemDeviceMock) ReadData(command string, data []byte) error { dm.lastCommand = command copy(data, dm.lastData) return dm.retErr } func (dm *oneWireSystemDeviceMock) WriteData(command string, data []byte) error { dm.lastCommand = command dm.lastData = make([]byte, len(data)) copy(dm.lastData, data) return dm.retErr } func (dm *oneWireSystemDeviceMock) ReadInteger(command string) (int, error) { dm.lastCommand = command return dm.lastValue, dm.retErr } func (dm *oneWireSystemDeviceMock) WriteInteger(command string, val int) error { dm.lastCommand = command dm.lastValue = val return dm.retErr } func (dm *oneWireSystemDeviceMock) Close() error { return dm.retErr } ================================================ FILE: drivers/onewire/onewire_connection.go ================================================ package onewire import ( "sync" "gobot.io/x/gobot/v2" ) // onewireConnection is the common implementation of the 1-wire bus interface. type onewireConnection struct { onewireSystem gobot.OneWireSystemDevicer mutex *sync.Mutex } // NewConnection uses the given 1-wire system device and provides it as gobot.OneWireOperations. func NewConnection(onewireSystem gobot.OneWireSystemDevicer) *onewireConnection { return &onewireConnection{onewireSystem: onewireSystem, mutex: &sync.Mutex{}} } // ID returns the device id in the form "family code"-"serial number". Implements gobot.OneWireOperations. func (d *onewireConnection) ID() string { return d.onewireSystem.ID() } // ReadData reads the data according the command, e.g. from the specified file on sysfs bus. // Implements gobot.OneWireOperations. func (c *onewireConnection) ReadData(command string, data []byte) error { c.mutex.Lock() defer c.mutex.Unlock() return c.onewireSystem.ReadData(command, data) } // WriteData writes the data according the command, e.g. to the specified file on sysfs bus. // Implements gobot.OneWireOperations. func (c *onewireConnection) WriteData(command string, data []byte) error { c.mutex.Lock() defer c.mutex.Unlock() return c.onewireSystem.WriteData(command, data) } // ReadInteger reads the value according the command, e.g. to the specified file on sysfs bus. // Implements gobot.OneWireOperations. func (c *onewireConnection) ReadInteger(command string) (int, error) { c.mutex.Lock() defer c.mutex.Unlock() return c.onewireSystem.ReadInteger(command) } // WriteInteger writes the value according the command, e.g. to the specified file on sysfs bus. // Implements gobot.OneWireOperations. func (c *onewireConnection) WriteInteger(command string, val int) error { c.mutex.Lock() defer c.mutex.Unlock() return c.onewireSystem.WriteInteger(command, val) } // Close connection to underlying 1-wire device. Implements functions of onewire.Connection respectively // gobot.OneWireOperations. func (c *onewireConnection) Close() error { c.mutex.Lock() defer c.mutex.Unlock() return c.onewireSystem.Close() } ================================================ FILE: drivers/onewire/onewire_connection_test.go ================================================ package onewire import ( "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestNewConnection(t *testing.T) { // arrange & act c := NewConnection(newOneWireTestSystemDevice("id")) // assert assert.IsType(t, &onewireConnection{}, c) assert.Equal(t, "id", c.ID()) } func TestClose(t *testing.T) { tests := map[string]struct { simulateErr bool wantErr string }{ "close_ok": {}, "error_close": { wantErr: "close error", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange sysCon := newOneWireTestSystemDevice("id") if tc.wantErr != "" { sysCon.retErr = errors.New(tc.wantErr) } c := NewConnection(sysCon) // act err := c.Close() // assert if tc.wantErr != "" { require.EqualError(t, err, tc.wantErr) } else { require.NoError(t, err) } }) } } func TestReadData(t *testing.T) { data := []byte{10, 11, 21, 32} tests := map[string]struct { data []byte wantData []byte wantErr string }{ "read_ok": { // only to test the parameter passing data: []byte{0, 0, 0}, wantData: []byte{10, 11, 21}, }, "error_read": { data: []byte{0, 0}, wantData: []byte{10, 11}, wantErr: "read error", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange const command = "read data command" sysCon := newOneWireTestSystemDevice("id") sysCon.lastData = data if tc.wantErr != "" { sysCon.retErr = errors.New(tc.wantErr) } c := NewConnection(sysCon) // act err := c.ReadData(command, tc.data) // assert if tc.wantErr != "" { require.EqualError(t, err, tc.wantErr) } else { require.NoError(t, err) } assert.Equal(t, command, sysCon.lastCommand) assert.Equal(t, tc.wantData, tc.data) }) } } func TestWriteData(t *testing.T) { tests := map[string]struct { data []byte wantErr string }{ "write_ok": { data: []byte{10, 11, 21}, }, "error_write": { data: []byte{11, 32}, wantErr: "read error", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange const command = "write data command" sysCon := newOneWireTestSystemDevice("id") if tc.wantErr != "" { sysCon.retErr = errors.New(tc.wantErr) } c := NewConnection(sysCon) // act err := c.WriteData(command, tc.data) // assert if tc.wantErr != "" { require.EqualError(t, err, tc.wantErr) } else { require.NoError(t, err) } assert.Equal(t, command, sysCon.lastCommand) assert.Equal(t, tc.data, sysCon.lastData) }) } } func TestReadInteger(t *testing.T) { tests := map[string]struct { wantValue int wantErr string }{ "read_ok": { wantValue: 12, }, "error_read": { wantErr: "read error", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange const command = "read data command" sysCon := newOneWireTestSystemDevice("id") sysCon.lastValue = tc.wantValue if tc.wantErr != "" { sysCon.retErr = errors.New(tc.wantErr) } c := NewConnection(sysCon) // act got, err := c.ReadInteger(command) // assert if tc.wantErr != "" { require.EqualError(t, err, tc.wantErr) } else { require.NoError(t, err) } assert.Equal(t, command, sysCon.lastCommand) assert.Equal(t, tc.wantValue, got) }) } } func TestWriteInteger(t *testing.T) { tests := map[string]struct { value int wantErr string }{ "write_ok": { value: 21, }, "error_write": { wantErr: "read error", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange const command = "write data command" sysCon := newOneWireTestSystemDevice("id") if tc.wantErr != "" { sysCon.retErr = errors.New(tc.wantErr) } c := NewConnection(sysCon) // act err := c.WriteInteger(command, tc.value) // assert if tc.wantErr != "" { require.EqualError(t, err, tc.wantErr) } else { require.NoError(t, err) } assert.Equal(t, command, sysCon.lastCommand) assert.Equal(t, tc.value, sysCon.lastValue) }) } } ================================================ FILE: drivers/onewire/onewire_driver.go ================================================ package onewire import ( "fmt" "log" "sync" "gobot.io/x/gobot/v2" ) // connector lets adaptors provide the drivers to get access to the 1-wire devices on platforms. type connector interface { // GetOneWireConnection returns a connection to a 1-wire device with family code and serial number. GetOneWireConnection(familyCode byte, serialNumber uint64) (Connection, error) } // Connection is a connection to a 1-wire device with family code and serial number on a specific bus, provided by // an adaptor, usually just by calling the onewire package's GetOneWireConnection() function. type Connection gobot.OneWireOperations // optionApplier needs to be implemented by each configurable option type type optionApplier interface { apply(cfg *configuration) } // configuration contains all changeable attributes of the driver. type configuration struct { name string familyCode byte serialNumber uint64 } // nameOption is the type for applying another name to the configuration type nameOption string // Driver implements the interface gobot.Driver. type driver struct { gobot.Commander driverCfg *configuration connector connector connection Connection afterStart func() error beforeHalt func() error mutex *sync.Mutex // mutex often needed to ensure that write-read sequences are not interrupted } // newDriver creates a new generic and basic 1-wire gobot driver. // // Supported options: // // "WithName" func newDriver(a connector, name string, familyCode byte, serialNumber uint64, opts ...interface{}) *driver { d := &driver{ driverCfg: &configuration{name: gobot.DefaultName(name), familyCode: familyCode, serialNumber: serialNumber}, connector: a, afterStart: func() error { return nil }, beforeHalt: func() error { return nil }, Commander: gobot.NewCommander(), mutex: &sync.Mutex{}, } for _, opt := range opts { switch o := opt.(type) { case optionApplier: o.apply(d.driverCfg) default: panic(fmt.Sprintf("'%s' can not be applied on '%s'", opt, d.driverCfg.name)) } } return d } // WithName is used to replace the default name of the driver. func WithName(name string) optionApplier { return nameOption(name) } // Name returns the name of the device. func (d *driver) Name() string { return d.driverCfg.name } // SetName sets the name of the device (deprecated, use WithName() instead). func (d *driver) SetName(name string) { d.driverCfg.name = name } // Connection returns the gobot connection of the device. func (d *driver) Connection() gobot.Connection { if d.connection == nil { log.Printf("1-wire driver not started for '%s'\n", d.driverCfg.name) return nil } if conn, ok := d.connection.(gobot.Connection); ok { return conn } log.Printf("%s has no gobot connection\n", d.driverCfg.name) return nil } // Start initializes the device. func (d *driver) Start() error { d.mutex.Lock() defer d.mutex.Unlock() if d.connector == nil { return fmt.Errorf("%s has no connector", d.driverCfg.name) } var err error d.connection, err = d.connector.GetOneWireConnection(d.driverCfg.familyCode, d.driverCfg.serialNumber) if err != nil { return err } return d.afterStart() } // Halt halts the device. func (d *driver) Halt() error { d.mutex.Lock() defer d.mutex.Unlock() if err := d.beforeHalt(); err != nil { return err } // the connection is also cached on adaptor side and will be closed on adaptor Finalize() d.connection = nil return nil } func (d *driver) id() (string, error) { if d.connection == nil { return "", fmt.Errorf("1-wire driver not started for '%s'", d.driverCfg.name) } return d.connection.ID(), nil } //nolint:unused // ok for now func (d *driver) readData(command string, data []byte) error { if d.connection == nil { return fmt.Errorf("1-wire driver not started for '%s'", d.driverCfg.name) } return d.connection.ReadData(command, data) } //nolint:unused // ok for now func (d *driver) writeData(command string, data []byte) error { if d.connection == nil { return fmt.Errorf("1-wire driver not started for '%s'", d.driverCfg.name) } return d.connection.WriteData(command, data) } func (d *driver) readInteger(command string) (int, error) { if d.connection == nil { return 0, fmt.Errorf("1-wire driver not started for '%s'", d.driverCfg.name) } return d.connection.ReadInteger(command) } func (d *driver) writeInteger(command string, val int) error { if d.connection == nil { return fmt.Errorf("1-wire driver not started for '%s'", d.driverCfg.name) } return d.connection.WriteInteger(command, val) } func (o nameOption) String() string { return "name option for 1-wire drivers" } // apply change the name in the configuration. func (o nameOption) apply(c *configuration) { c.name = string(o) } ================================================ FILE: drivers/onewire/onewire_driver_test.go ================================================ package onewire import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func initTestDriver() *driver { d, _ := initDriverWithStubbedAdaptor() return d } func initDriverWithStubbedAdaptor() (*driver, *oneWireAdaptorMock) { a := newOneWireTestAdaptor() return newDriver(a, "name", 28, 9876), a } func Test_newDriver(t *testing.T) { // arrange const ( familyCode = 99 serialNumber = 1234567890 ) // act d := newDriver(newOneWireTestAdaptor(), "name", familyCode, serialNumber) // assert assert.IsType(t, &driver{}, d) assert.NotNil(t, d.driverCfg) assert.NotNil(t, d.connector) assert.NotNil(t, d.afterStart) assert.NotNil(t, d.beforeHalt) assert.NotNil(t, d.Commander) assert.NotNil(t, d.mutex) } func TestConnection(t *testing.T) { // arrange d := initTestDriver() require.NoError(t, d.Start()) // act, assert assert.NotNil(t, d.Connection()) } func TestStart(t *testing.T) { // arrange d := initTestDriver() // act, assert require.NoError(t, d.Start()) } func TestStartConnectError(t *testing.T) { // arrange d, c := initDriverWithStubbedAdaptor() c.retErr = true // act, assert require.ErrorContains(t, d.Start(), "GetOneWireConnection error") } func TestHalt(t *testing.T) { // arrange d := initTestDriver() // act, assert require.NoError(t, d.Halt()) // must be idempotent require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestWithName(t *testing.T) { // This is a general test, that options are applied by using the WithName() option. // All other configuration options can also be tested by With..(val).apply(cfg). // arrange const newName = "new name" a := newOneWireTestAdaptor() // act d := newDriver(a, "name", 28, 9876, WithName(newName)) // assert assert.Equal(t, newName, d.driverCfg.name) assert.Equal(t, newName, d.Name()) } ================================================ FILE: drivers/serial/LICENSE ================================================ Copyright (c) 2013-2018 The Hybrid Group Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: drivers/serial/README.md ================================================ # Serial This package provides drivers based on [Serial](https://en.wikipedia.org/wiki/Serial_port) communication ([UART](https://en.wikipedia.org/wiki/Universal_asynchronous_receiver-transmitter)). devices. It is normally used by connecting an adaptor such as [SerialPort](https://gobot.io/documentation/platforms/serialport/) that supports the needed interfaces for serial devices. ## Getting Started Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) ## Hardware Support Gobot has a extensible system for connecting to hardware devices. The following Serial devices are currently supported: - Sphero: Sphero - Neurosky: MindWave - MegaPi: MotorDriver ================================================ FILE: drivers/serial/doc.go ================================================ /* Package serial provides Gobot drivers for Serial Port communication based devices. For further information refer to readme: https://github.com/hybridgroup/gobot/blob/release/drivers/serial/README.md */ package serial // import "gobot.io/x/gobot/v2/drivers/serial" ================================================ FILE: drivers/serial/megapi/motor_driver.go ================================================ package megapi import ( "bytes" "encoding/binary" "log" "sync" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/serial" ) var _ gobot.Driver = (*MotorDriver)(nil) type megapiMotorSerialAdaptor interface { gobot.Adaptor serial.SerialWriter } // MotorDriver represents a motor type MotorDriver struct { *serial.Driver port byte halted bool writeBytesChannel chan []byte finalizeChannel chan struct{} syncRoot *sync.Mutex } // NewMotorDriver creates a new MotorDriver at the given port func NewMotorDriver(a megapiMotorSerialAdaptor, port byte, opts ...serial.OptionApplier) *MotorDriver { d := &MotorDriver{ port: port, halted: true, syncRoot: &sync.Mutex{}, writeBytesChannel: make(chan []byte), finalizeChannel: make(chan struct{}), } d.Driver = serial.NewDriver(a, "MegaPiMotor", d.initialize, d.shutdown, opts...) return d } // Speed sets the motors speed to the specified value func (d *MotorDriver) Speed(speed int16) error { d.syncRoot.Lock() defer d.syncRoot.Unlock() if d.halted { return nil } return d.speedHelper(speed) } // initialize implements the Driver interface func (d *MotorDriver) initialize() error { d.syncRoot.Lock() defer d.syncRoot.Unlock() // sleeping is required to give the board a chance to reset after connection is done time.Sleep(2 * time.Second) // kick off thread to send bytes to the board go func() { for { select { case bytes := <-d.writeBytesChannel: if _, err := d.adaptor().SerialWrite(bytes); err != nil { panic(err) } time.Sleep(10 * time.Millisecond) case <-d.finalizeChannel: d.finalizeChannel <- struct{}{} return default: time.Sleep(10 * time.Millisecond) } } }() d.halted = false return d.speedHelper(0) } // Halt terminates the Driver interface func (d *MotorDriver) shutdown() error { d.syncRoot.Lock() defer d.syncRoot.Unlock() d.finalizeChannel <- struct{}{} <-d.finalizeChannel d.halted = true return d.speedHelper(0) } // there is some sort of bug on the hardware such that you cannot // send the exact same speed to 2 different motors consecutively // hence we ensure we always alternate speeds func (d *MotorDriver) speedHelper(speed int16) error { if err := d.sendSpeed(speed - 1); err != nil { return err } return d.sendSpeed(speed) } // sendSpeed sets the motors speed to the specified value func (d *MotorDriver) sendSpeed(speed int16) error { bufOut := new(bytes.Buffer) // byte sequence: 0xff, 0x55, id, action, device, port bufOut.Write([]byte{0xff, 0x55, 0x6, 0x0, 0x2, 0xa, d.port}) if err := binary.Write(bufOut, binary.LittleEndian, speed); err != nil { return err } bufOut.Write([]byte{0xa}) d.writeBytesChannel <- bufOut.Bytes() return nil } func (d *MotorDriver) adaptor() megapiMotorSerialAdaptor { if a, ok := d.Connection().(megapiMotorSerialAdaptor); ok { return a } log.Printf("%s has no MegaPi serial connector\n", d.Name()) return nil } ================================================ FILE: drivers/serial/neurosky/LICENSE ================================================ Copyright (c) 2013-2018 The Hybrid Group Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: drivers/serial/neurosky/mindwave_driver.go ================================================ package neurosky import ( "bytes" "log" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/serial" ) type mindWaveSerialAdaptor interface { gobot.Adaptor serial.SerialReader } const ( // mindWaveBTSync is the sync code mindWaveBTSync byte = 0xAA // mindWaveCodeEx Extended code mindWaveCodeEx byte = 0x55 // mindWaveCodeSignalQuality POOR_SIGNAL quality 0-255 mindWaveCodeSignalQuality byte = 0x02 // mindWaveCodeAttention ATTENTION eSense 0-100 mindWaveCodeAttention byte = 0x04 // mindWaveCodeMeditation MEDITATION eSense 0-100 mindWaveCodeMeditation byte = 0x05 // mindWaveCodeBlink BLINK strength 0-255 mindWaveCodeBlink byte = 0x16 // mindWaveCodeWave RAW wave value: 2-byte big-endian 2s-complement mindWaveCodeWave byte = 0x80 // mindWaveCodeAsicEEG ASIC EEG POWER 8 3-byte big-endian integers mindWaveCodeAsicEEG byte = 0x83 ExtendedEvent = "extended" SignalEvent = "signal" AttentionEvent = "attention" MeditationEvent = "meditation" BlinkEvent = "blink" WaveEvent = "wave" EEGEvent = "eeg" ErrorEvent = "error" ) // MindWaveDriver is the Gobot driver for the Neurosky MindWave Sensor type MindWaveDriver struct { *serial.Driver gobot.Eventer } // MindWaveEEGData is the EEG raw data returned from the sensor type MindWaveEEGData struct { Delta int Theta int LoAlpha int HiAlpha int LoBeta int HiBeta int LoGamma int MidGamma int } // NewMindWaveDriver creates a driver for Neurosky MindWave // and adds the following events: // // extended - user's current extended level // signal - shows signal strength // attention - user's current attention level // meditation - user's current meditation level // blink - user's current blink level // wave - shows wave data // eeg - showing eeg data func NewMindWaveDriver(a mindWaveSerialAdaptor, opts ...serial.OptionApplier) *MindWaveDriver { d := &MindWaveDriver{ Eventer: gobot.NewEventer(), } d.Driver = serial.NewDriver(a, "MindWave", d.initialize, nil, opts...) d.AddEvent(ExtendedEvent) d.AddEvent(SignalEvent) d.AddEvent(AttentionEvent) d.AddEvent(MeditationEvent) d.AddEvent(BlinkEvent) d.AddEvent(WaveEvent) d.AddEvent(EEGEvent) d.AddEvent(ErrorEvent) return d } // initialize creates a go routine to listen from serial port and parse buffer readings // TODO: stop the go routine gracefully on Halt() func (d *MindWaveDriver) initialize() error { go func() { for { buff := make([]byte, 1024) _, err := d.adaptor().SerialRead(buff) if err != nil { d.Publish(d.Event("error"), err) } else { if err := d.parse(bytes.NewBuffer(buff)); err != nil { panic(err) } } } }() return nil } // parse converts bytes buffer into packets until no more data is present func (d *MindWaveDriver) parse(buf *bytes.Buffer) error { for buf.Len() > 2 { b1, _ := buf.ReadByte() b2, _ := buf.ReadByte() if b1 == mindWaveBTSync && b2 == mindWaveBTSync { length, _ := buf.ReadByte() payload := make([]byte, length) if _, err := buf.Read(payload); err != nil { return err } // checksum, _ := buf.ReadByte() buf.Next(1) if err := d.parsePacket(bytes.NewBuffer(payload)); err != nil { panic(err) } } } return nil } // parsePacket publishes event according to data parsed func (d *MindWaveDriver) parsePacket(buf *bytes.Buffer) error { for buf.Len() > 0 { b, _ := buf.ReadByte() switch b { case mindWaveCodeEx: d.Publish(d.Event(ExtendedEvent), nil) case mindWaveCodeSignalQuality: ret, _ := buf.ReadByte() d.Publish(d.Event(SignalEvent), ret) case mindWaveCodeAttention: ret, _ := buf.ReadByte() d.Publish(d.Event(AttentionEvent), ret) case mindWaveCodeMeditation: ret, _ := buf.ReadByte() d.Publish(d.Event(MeditationEvent), ret) case mindWaveCodeBlink: ret, _ := buf.ReadByte() d.Publish(d.Event(BlinkEvent), ret) case mindWaveCodeWave: buf.Next(1) ret := make([]byte, 2) if _, err := buf.Read(ret); err != nil { return err } d.Publish(d.Event(WaveEvent), int16(ret[0])<<8|int16(ret[1])) case mindWaveCodeAsicEEG: ret := make([]byte, 25) i, _ := buf.Read(ret) if i == 25 { d.Publish(d.Event(EEGEvent), d.parseEEG(ret)) } } } return nil } // parseEEG returns data converted into EEG map func (d *MindWaveDriver) parseEEG(data []byte) MindWaveEEGData { return MindWaveEEGData{ Delta: d.parse3ByteInteger(data[0:3]), Theta: d.parse3ByteInteger(data[3:6]), LoAlpha: d.parse3ByteInteger(data[6:9]), HiAlpha: d.parse3ByteInteger(data[9:12]), LoBeta: d.parse3ByteInteger(data[12:15]), HiBeta: d.parse3ByteInteger(data[15:18]), LoGamma: d.parse3ByteInteger(data[18:21]), MidGamma: d.parse3ByteInteger(data[21:25]), } } func (d *MindWaveDriver) parse3ByteInteger(data []byte) int { return ((int(data[0]) << 16) | (((1 << 16) - 1) & (int(data[1]) << 8)) | (((1 << 8) - 1) & int(data[2]))) } func (d *MindWaveDriver) adaptor() mindWaveSerialAdaptor { if a, ok := d.Connection().(mindWaveSerialAdaptor); ok { return a } log.Printf("%s has no Neurosky serial connector\n", d.Name()) return nil } ================================================ FILE: drivers/serial/neurosky/mindwave_driver_test.go ================================================ //nolint:forcetypeassert // ok here package neurosky import ( "bytes" "errors" "strings" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/serial/testutil" ) var _ gobot.Driver = (*MindWaveDriver)(nil) func initTestNeuroskyDriver() *MindWaveDriver { a := testutil.NewSerialTestAdaptor() _ = a.Connect() return NewMindWaveDriver(a) } func TestNeuroskyDriver(t *testing.T) { d := initTestNeuroskyDriver() assert.NotNil(t, d.Connection()) } func TestNeuroskyDriverName(t *testing.T) { d := initTestNeuroskyDriver() assert.True(t, strings.HasPrefix(d.Name(), "MindWave")) d.SetName("NewName") assert.Equal(t, "NewName", d.Name()) } func TestNeuroskyDriverStart(t *testing.T) { sem := make(chan bool) a := testutil.NewSerialTestAdaptor() _ = a.Connect() a.SetSimulateReadError(true) d := NewMindWaveDriver(a) e := errors.New("read error") _ = d.Once(d.Event(ErrorEvent), func(data interface{}) { assert.Equal(t, e, data.(error)) sem <- true }) require.NoError(t, d.Start()) time.Sleep(50 * time.Millisecond) select { case <-sem: case <-time.After(100 * time.Millisecond): { require.Fail(t, "error was not emitted") } } } func TestNeuroskyDriverHalt(t *testing.T) { d := initTestNeuroskyDriver() require.NoError(t, d.Halt()) } func TestNeuroskyDriverParse(t *testing.T) { sem := make(chan bool) d := initTestNeuroskyDriver() // mindWaveCodeEx go func() { time.Sleep(5 * time.Millisecond) _ = d.parse(bytes.NewBuffer([]byte{0xAA, 0xAA, 1, 0x55, 0x00})) }() _ = d.On(d.Event(ExtendedEvent), func(data interface{}) { sem <- true }) select { case <-sem: case <-time.After(100 * time.Millisecond): require.Fail(t, "Event \"extended\" was not published") } // mindWaveCodeSignalQuality go func() { time.Sleep(5 * time.Millisecond) _ = d.parse(bytes.NewBuffer([]byte{0xAA, 0xAA, 2, 0x02, 100, 0x00})) }() _ = d.On(d.Event(SignalEvent), func(data interface{}) { assert.Equal(t, byte(100), data.(byte)) sem <- true }) <-sem // mindWaveCodeAttention go func() { time.Sleep(5 * time.Millisecond) _ = d.parse(bytes.NewBuffer([]byte{0xAA, 0xAA, 2, 0x04, 40, 0x00})) }() _ = d.On(d.Event(AttentionEvent), func(data interface{}) { assert.Equal(t, byte(40), data.(byte)) sem <- true }) <-sem // mindWaveCodeMeditation go func() { time.Sleep(5 * time.Millisecond) _ = d.parse(bytes.NewBuffer([]byte{0xAA, 0xAA, 2, 0x05, 60, 0x00})) }() _ = d.On(d.Event(MeditationEvent), func(data interface{}) { assert.Equal(t, byte(60), data.(byte)) sem <- true }) <-sem // mindWaveCodeBlink go func() { time.Sleep(5 * time.Millisecond) _ = d.parse(bytes.NewBuffer([]byte{0xAA, 0xAA, 2, 0x16, 150, 0x00})) }() _ = d.On(d.Event(BlinkEvent), func(data interface{}) { assert.Equal(t, byte(150), data.(byte)) sem <- true }) <-sem // mindWaveCodeWave go func() { time.Sleep(5 * time.Millisecond) _ = d.parse(bytes.NewBuffer([]byte{0xAA, 0xAA, 4, 0x80, 0x00, 0x40, 0x11, 0x00})) }() _ = d.On(d.Event(WaveEvent), func(data interface{}) { assert.Equal(t, int16(16401), data.(int16)) sem <- true }) <-sem // mindWaveCodeAsicEEG go func() { time.Sleep(5 * time.Millisecond) _ = d.parse(bytes.NewBuffer([]byte{ 0xAA, 0xAA, 30, 0x83, 24, 1, 121, 89, 0, 97, 26, 0, 30, 189, 0, 57, 1, 0, 62, 160, 0, 31, 127, 0, 18, 207, 0, 13, 108, 0x00, })) }() _ = d.On(d.Event(EEGEvent), func(data interface{}) { assert.Equal(t, MindWaveEEGData{ Delta: 1573241, Theta: 5832801, LoAlpha: 1703966, HiAlpha: 12386361, LoBeta: 65598, HiBeta: 10485791, LoGamma: 8323090, MidGamma: 13565965, }, data.(MindWaveEEGData)) sem <- true }) <-sem } ================================================ FILE: drivers/serial/serial_driver.go ================================================ package serial import ( "log" "sync" "gobot.io/x/gobot/v2" ) type SerialReader interface { SerialRead(b []byte) (n int, err error) } type SerialWriter interface { SerialWrite(b []byte) (n int, err error) } // OptionApplier needs to be implemented by each configurable option type type OptionApplier interface { apply(cfg *configuration) } // configuration contains all changeable attributes of the driver. type configuration struct { name string } // nameOption is the type for applying another name to the configuration type nameOption string // Driver implements the interface gobot.Driver. type Driver struct { gobot.Commander connection interface{} driverCfg *configuration afterStart func() error beforeHalt func() error mutex *sync.Mutex } // NewDriver creates a new basic serial gobot driver. func NewDriver(a interface{}, name string, afterStart func() error, beforeHalt func() error, opts ...OptionApplier, ) *Driver { if afterStart == nil { afterStart = func() error { return nil } } if beforeHalt == nil { beforeHalt = func() error { return nil } } d := Driver{ Commander: gobot.NewCommander(), connection: a, driverCfg: &configuration{name: gobot.DefaultName(name)}, afterStart: afterStart, beforeHalt: beforeHalt, mutex: &sync.Mutex{}, } for _, o := range opts { o.apply(d.driverCfg) } return &d } // WithName is used to replace the default name of the driver. func WithName(name string) OptionApplier { return nameOption(name) } // Name returns the name of the driver. func (d *Driver) Name() string { return d.driverCfg.name } // SetName sets the name of the driver. // Deprecated: Please use option [serial.WithName] instead. func (d *Driver) SetName(name string) { WithName(name).apply(d.driverCfg) } // Connection returns the gobot connection of the driver. func (d *Driver) Connection() gobot.Connection { if d.connection == nil { log.Printf("%s has no connection\n", d.driverCfg.name) return nil } if conn, ok := d.connection.(gobot.Connection); ok { return conn } log.Printf("%s has no gobot connection\n", d.driverCfg.name) return nil } // Start initializes the driver. func (d *Driver) Start() error { d.mutex.Lock() defer d.mutex.Unlock() // currently there is nothing to do here for the driver return d.afterStart() } // Halt halts the driver. func (d *Driver) Halt() error { d.mutex.Lock() defer d.mutex.Unlock() // currently there is nothing to do after halt for the driver return d.beforeHalt() } func (d *Driver) Mutex() *sync.Mutex { return d.mutex } // apply change the name in the configuration. func (o nameOption) apply(c *configuration) { c.name = string(o) } ================================================ FILE: drivers/serial/serial_driver_test.go ================================================ package serial import ( "fmt" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/serial/testutil" ) var _ gobot.Driver = (*Driver)(nil) func initTestDriver() *Driver { a := testutil.NewSerialTestAdaptor() d := NewDriver(a, "SERIAL_BASIC", nil, nil) return d } func TestNewDriver(t *testing.T) { // arrange const name = "mybot" a := testutil.NewSerialTestAdaptor() // act d := NewDriver(a, name, nil, nil) // assert assert.IsType(t, &Driver{}, d) assert.NotNil(t, d.driverCfg) assert.True(t, strings.HasPrefix(d.Name(), name)) assert.Equal(t, a, d.Connection()) require.NoError(t, d.afterStart()) require.NoError(t, d.beforeHalt()) assert.NotNil(t, d.Commander) assert.NotNil(t, d.mutex) } func Test_newDriverWithName(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithName() option. Further // tests for options can also be done by call of "WithOption(val).apply(cfg)". // arrange const ( name = "mybot" newName = "overwrite mybot" ) a := testutil.NewSerialTestAdaptor() // act d := NewDriver(a, name, nil, nil, WithName(newName)) // assert assert.Equal(t, newName, d.Name()) } func Test_applyWithName(t *testing.T) { // arrange const name = "mybot" cfg := configuration{name: "oldname"} // act WithName(name).apply(&cfg) // assert assert.Equal(t, name, cfg.name) } func TestStart(t *testing.T) { // arrange d := initTestDriver() // act, assert require.NoError(t, d.Start()) // arrange after start function d.afterStart = func() error { return fmt.Errorf("after start error") } // act, assert require.EqualError(t, d.Start(), "after start error") } func TestHalt(t *testing.T) { // arrange d := initTestDriver() // act, assert require.NoError(t, d.Halt()) // arrange after start function d.beforeHalt = func() error { return fmt.Errorf("before halt error") } // act, assert require.EqualError(t, d.Halt(), "before halt error") } ================================================ FILE: drivers/serial/sphero/LICENSE ================================================ Copyright (c) 2013-2018 The Hybrid Group Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: drivers/serial/sphero/sphero_driver.go ================================================ package sphero import ( "bytes" "encoding/binary" "errors" "log" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/common/spherocommon" "gobot.io/x/gobot/v2/drivers/serial" ) type spheroSerialAdaptor interface { gobot.Adaptor serial.SerialReader serial.SerialWriter IsConnected() bool } type packet struct { header []uint8 body []uint8 checksum uint8 } // SpheroDriver Represents a Sphero 2.0 type SpheroDriver struct { *serial.Driver gobot.Eventer seq uint8 asyncResponse [][]uint8 syncResponse [][]uint8 packetChannel chan *packet responseChannel chan []uint8 originalColor []uint8 // Only used for calibration. shutdownWaitTime time.Duration } // NewSpheroDriver returns a new SpheroDriver given a Sphero Adaptor. // // Adds the following API Commands: // // "ConfigureLocator" - See SpheroDriver.ConfigureLocator // "Roll" - See SpheroDriver.Roll // "Stop" - See SpheroDriver.Stop // "GetRGB" - See SpheroDriver.GetRGB // "ReadLocator" - See SpheroDriver.ReadLocator // "SetBackLED" - See SpheroDriver.SetBackLED // "SetHeading" - See SpheroDriver.SetHeading // "SetStabilization" - See SpheroDriver.SetStabilization // "SetDataStreaming" - See SpheroDriver.SetDataStreaming // "SetRotationRate" - See SpheroDriver.SetRotationRate func NewSpheroDriver(a spheroSerialAdaptor, opts ...serial.OptionApplier) *SpheroDriver { d := &SpheroDriver{ Eventer: gobot.NewEventer(), packetChannel: make(chan *packet, 1024), responseChannel: make(chan []uint8, 1024), shutdownWaitTime: 1 * time.Second, } d.Driver = serial.NewDriver(a, "Sphero", d.initialize, d.shutdown, opts...) d.AddEvent(spherocommon.ErrorEvent) d.AddEvent(spherocommon.CollisionEvent) d.AddEvent(spherocommon.SensorDataEvent) //nolint:forcetypeassert // ok here d.AddCommand("SetRGB", func(params map[string]interface{}) interface{} { r := uint8(params["r"].(float64)) g := uint8(params["g"].(float64)) b := uint8(params["b"].(float64)) d.SetRGB(r, g, b) return nil }) //nolint:forcetypeassert // ok here d.AddCommand("Roll", func(params map[string]interface{}) interface{} { speed := uint8(params["speed"].(float64)) heading := uint16(params["heading"].(float64)) d.Roll(speed, heading) return nil }) d.AddCommand("Stop", func(_ map[string]interface{}) interface{} { d.Stop() return nil }) d.AddCommand("GetRGB", func(_ map[string]interface{}) interface{} { return d.GetRGB() }) d.AddCommand("ReadLocator", func(_ map[string]interface{}) interface{} { return d.ReadLocator() }) //nolint:forcetypeassert // ok here d.AddCommand("SetBackLED", func(params map[string]interface{}) interface{} { level := uint8(params["level"].(float64)) d.SetBackLED(level) return nil }) //nolint:forcetypeassert // ok here d.AddCommand("SetRotationRate", func(params map[string]interface{}) interface{} { level := uint8(params["level"].(float64)) d.SetRotationRate(level) return nil }) //nolint:forcetypeassert // ok here d.AddCommand("SetHeading", func(params map[string]interface{}) interface{} { heading := uint16(params["heading"].(float64)) d.SetHeading(heading) return nil }) //nolint:forcetypeassert // ok here d.AddCommand("SetStabilization", func(params map[string]interface{}) interface{} { on := params["enable"].(bool) d.SetStabilization(on) return nil }) //nolint:forcetypeassert // ok here d.AddCommand("SetDataStreaming", func(params map[string]interface{}) interface{} { N := uint16(params["N"].(float64)) M := uint16(params["M"].(float64)) Mask := uint32(params["Mask"].(float64)) Pcnt := uint8(params["Pcnt"].(float64)) Mask2 := uint32(params["Mask2"].(float64)) d.SetDataStreaming(spherocommon.DataStreamingConfig{N: N, M: M, Mask2: Mask2, Pcnt: Pcnt, Mask: Mask}) return nil }) //nolint:forcetypeassert // ok here d.AddCommand("ConfigureLocator", func(params map[string]interface{}) interface{} { Flags := uint8(params["Flags"].(float64)) X := int16(params["X"].(float64)) Y := int16(params["Y"].(float64)) YawTare := int16(params["YawTare"].(float64)) d.ConfigureLocator(spherocommon.LocatorConfig{Flags: Flags, X: X, Y: Y, YawTare: YawTare}) return nil }) return d } // SetRGB sets the Sphero to the given r, g, and b values func (d *SpheroDriver) SetRGB(r uint8, g uint8, b uint8) { d.sendCraftPacket([]uint8{r, g, b, 0x01}, 0x20) } // GetRGB returns the current r, g, b value of the Sphero func (d *SpheroDriver) GetRGB() []uint8 { buf := d.getSyncResponse(d.craftPacket([]uint8{}, 0x22)) if len(buf) == 9 { return []uint8{buf[5], buf[6], buf[7]} } return []uint8{} } // ReadLocator reads Sphero's current position (X,Y), component velocities and SOG (speed over ground). func (d *SpheroDriver) ReadLocator() []int16 { buf := d.getSyncResponse(d.craftPacket([]uint8{}, 0x15)) if len(buf) == 16 { vals := make([]int16, 5) _ = binary.Read(bytes.NewReader(buf[5:15]), binary.BigEndian, &vals) return vals } return []int16{} } // SetBackLED sets the Sphero Back LED to the specified brightness func (d *SpheroDriver) SetBackLED(level uint8) { d.sendCraftPacket([]uint8{level}, 0x21) } // SetRotationRate sets the Sphero rotation rate // A value of 255 jumps to the maximum (currently 400 degrees/sec). func (d *SpheroDriver) SetRotationRate(level uint8) { d.sendCraftPacket([]uint8{level}, 0x03) } // SetHeading sets the heading of the Sphero func (d *SpheroDriver) SetHeading(heading uint16) { //nolint:gosec // TODO: fix later d.sendCraftPacket([]uint8{uint8(heading >> 8), uint8(heading & 0xFF)}, 0x01) } // SetStabilization enables or disables the built-in auto stabilizing features of the Sphero func (d *SpheroDriver) SetStabilization(on bool) { b := uint8(0x01) if !on { b = 0x00 } d.sendCraftPacket([]uint8{b}, 0x02) } // Roll sends a roll command to the Sphero gives a speed and heading func (d *SpheroDriver) Roll(speed uint8, heading uint16) { //nolint:gosec // TODO: fix later d.sendCraftPacket([]uint8{speed, uint8(heading >> 8), uint8(heading & 0xFF), 0x01}, 0x30) } // ConfigureLocator configures and enables the Locator func (d *SpheroDriver) ConfigureLocator(lc spherocommon.LocatorConfig) { buf := new(bytes.Buffer) if err := binary.Write(buf, binary.BigEndian, lc); err != nil { panic(err) } d.sendCraftPacket(buf.Bytes(), 0x13) } // SetDataStreaming enables sensor data streaming func (d *SpheroDriver) SetDataStreaming(dsc spherocommon.DataStreamingConfig) { buf := new(bytes.Buffer) if err := binary.Write(buf, binary.BigEndian, dsc); err != nil { panic(err) } d.sendCraftPacket(buf.Bytes(), 0x11) } // Stop sets the Sphero to a roll speed of 0 func (d *SpheroDriver) Stop() { d.Roll(0, 0) } // ConfigureCollisionDetection configures the sensitivity of the detection. func (d *SpheroDriver) ConfigureCollisionDetection(cc spherocommon.CollisionConfig) { d.sendCraftPacket([]uint8{cc.Method, cc.Xt, cc.Yt, cc.Xs, cc.Ys, cc.Dead}, 0x12) } // SetCalibration sets up Sphero for manual heading calibration. // It does this by turning on the tail light (so you can tell where it's // facing) and disabling stabilization (so you can adjust the heading). // // When done, call FinishCalibration to set the new heading, and re-enable // stabilization. func (d *SpheroDriver) StartCalibration() { d.originalColor = d.GetRGB() d.SetRGB(0, 0, 0) d.SetBackLED(127) d.SetStabilization(false) } // FinishCalibration ends Sphero's calibration mode, by setting // the new heading as current, and re-enabling normal defaults. This is a NOP // in case StartCalibration was not called. func (d *SpheroDriver) FinishCalibration() { if d.originalColor == nil { // Piggybacking on the original color being set to know if we are // calibrating or not. return } d.SetHeading(0) d.SetRGB(d.originalColor[0], d.originalColor[1], d.originalColor[2]) d.SetBackLED(0) d.SetStabilization(true) d.originalColor = nil } // initialize starts the SpheroDriver and enables Collision Detection. // Returns true on successful start. // // Emits the Events: // // Collision spherocommon.CollisionPacket - On Collision Detected // SensorData spherocommon.DataStreamingPacket - On Data Streaming event // Error error- On error while processing asynchronous response // // TODO: stop the go routines gracefully on shutdown() func (d *SpheroDriver) initialize() error { go func() { for { packet := <-d.packetChannel err := d.write(packet) if err != nil { d.Publish(spherocommon.ErrorEvent, err) } } }() go func() { for { response := <-d.responseChannel d.syncResponse = append(d.syncResponse, response) } }() go func() { for { header := d.readHeader() if len(header) > 0 { body := d.readBody(header[4]) data := append(header, body...) checksum := data[len(data)-1] if checksum != spherocommon.CalculateChecksum(data[2:len(data)-1]) { continue } switch header[1] { case 0xFE: d.asyncResponse = append(d.asyncResponse, data) case 0xFF: d.responseChannel <- data } } } }() go func() { for { var evt []uint8 for len(d.asyncResponse) != 0 { evt, d.asyncResponse = d.asyncResponse[len(d.asyncResponse)-1], d.asyncResponse[:len(d.asyncResponse)-1] switch evt[2] { case 0x07: d.handleCollisionDetected(evt) case 0x03: d.handleDataStreaming(evt) } } time.Sleep(100 * time.Millisecond) } }() d.ConfigureCollisionDetection(spheroDefaultCollisionConfig()) d.enableStopOnDisconnect() return nil } // shutdown halts the SpheroDriver and sends a SpheroDriver.Stop command to the Sphero. func (d *SpheroDriver) shutdown() error { if d.adaptor().IsConnected() { gobot.Every(10*time.Millisecond, func() { d.Stop() }) time.Sleep(d.shutdownWaitTime) } return nil } func (d *SpheroDriver) enableStopOnDisconnect() { d.sendCraftPacket([]uint8{0x00, 0x00, 0x00, 0x01}, 0x37) } func (d *SpheroDriver) handleCollisionDetected(data []uint8) { // ensure data is the right length: if len(data) != 22 || data[4] != 17 { return } var collision spherocommon.CollisionPacket buffer := bytes.NewBuffer(data[5:]) // skip header if err := binary.Read(buffer, binary.BigEndian, &collision); err != nil { panic(err) } d.Publish(spherocommon.CollisionEvent, collision) } func (d *SpheroDriver) handleDataStreaming(data []uint8) { // ensure data is the right length: if len(data) != 90 { return } var dataPacket spherocommon.DataStreamingPacket buffer := bytes.NewBuffer(data[5:]) // skip header if err := binary.Read(buffer, binary.BigEndian, &dataPacket); err != nil { panic(err) } d.Publish(spherocommon.SensorDataEvent, dataPacket) } func (d *SpheroDriver) getSyncResponse(packet *packet) []byte { d.packetChannel <- packet for i := 0; i < 500; i++ { for key := range d.syncResponse { if d.syncResponse[key][3] == packet.header[4] && len(d.syncResponse[key]) > 6 { var response []byte response, d.syncResponse = d.syncResponse[len(d.syncResponse)-1], d.syncResponse[:len(d.syncResponse)-1] return response } } time.Sleep(100 * time.Microsecond) } return []byte{} } func (d *SpheroDriver) sendCraftPacket(body []uint8, cid byte) { d.packetChannel <- d.craftPacket(body, cid) } func (d *SpheroDriver) craftPacket(body []uint8, cid byte) *packet { dlen := len(body) + 1 did := uint8(0x02) hdr := []uint8{0xFF, 0xFF, did, cid, d.seq, uint8(dlen)} //nolint:gosec // TODO: fix later buf := append(hdr, body...) packet := &packet{ body: body, header: hdr, checksum: spherocommon.CalculateChecksum(buf[2:]), } return packet } func (d *SpheroDriver) write(packet *packet) error { d.Mutex().Lock() defer d.Mutex().Unlock() buf := append(packet.header, packet.body...) buf = append(buf, packet.checksum) length, err := d.adaptor().SerialWrite(buf) if err != nil { return err } if length != len(buf) { return errors.New("not enough bytes written") } d.seq++ return nil } func (d *SpheroDriver) readHeader() []uint8 { return d.readNextChunk(5) } func (d *SpheroDriver) readBody(length uint8) []uint8 { return d.readNextChunk(int(length)) } func (d *SpheroDriver) readNextChunk(length int) []uint8 { read := make([]uint8, length) bytesRead := 0 for bytesRead < length { time.Sleep(1 * time.Millisecond) n, err := d.adaptor().SerialRead(read[bytesRead:]) if err != nil { return nil } bytesRead += n } return read } func (d *SpheroDriver) adaptor() spheroSerialAdaptor { if a, ok := d.Connection().(spheroSerialAdaptor); ok { return a } log.Printf("%s has no Sphero serial connector\n", d.Name()) return nil } // spheroDefaultCollisionConfig returns a CollisionConfig with sensible collision defaults func spheroDefaultCollisionConfig() spherocommon.CollisionConfig { return spherocommon.CollisionConfig{ Method: 0x01, Xt: 0x80, Yt: 0x80, Xs: 0x80, Ys: 0x80, Dead: 0x60, } } // spheroDefaultLocatorConfig returns a LocatorConfig with defaults func spheroDefaultLocatorConfig() spherocommon.LocatorConfig { return spherocommon.LocatorConfig{ Flags: 0x01, X: 0x00, Y: 0x00, YawTare: 0x00, } } ================================================ FILE: drivers/serial/sphero/sphero_driver_test.go ================================================ //nolint:forcetypeassert // ok here package sphero import ( "bytes" "encoding/binary" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/common/spherocommon" "gobot.io/x/gobot/v2/drivers/serial" "gobot.io/x/gobot/v2/drivers/serial/testutil" ) var _ gobot.Driver = (*SpheroDriver)(nil) func initTestSpheroDriver() *SpheroDriver { a := testutil.NewSerialTestAdaptor() d := NewSpheroDriver(a) d.shutdownWaitTime = 0 // to speed up the tests return d } func TestNewSpheroDriver(t *testing.T) { d := initTestSpheroDriver() assert.True(t, strings.HasPrefix(d.Name(), "Sphero")) assert.NotNil(t, d.Eventer) } func TestNewSpheroDriverWithName(t *testing.T) { // This is a general test, that options are applied in constructor by using the common WithName() option. Further // tests for options can also be done by call of "WithOption(val).apply(cfg)". // arrange const newName = "new name" a := testutil.NewSerialTestAdaptor() // act d := NewSpheroDriver(a, serial.WithName(newName)) // assert assert.Equal(t, newName, d.Name()) } func TestSpheroCommands(t *testing.T) { d := initTestSpheroDriver() var ret interface{} ret = d.Command("SetRGB")( map[string]interface{}{"r": 100.0, "g": 100.0, "b": 100.0}, ) assert.Nil(t, ret) ret = d.Command("Roll")( map[string]interface{}{"speed": 100.0, "heading": 100.0}, ) assert.Nil(t, ret) ret = d.Command("SetBackLED")( map[string]interface{}{"level": 100.0}, ) assert.Nil(t, ret) ret = d.Command("ConfigureLocator")( map[string]interface{}{"Flags": 1.0, "X": 100.0, "Y": 100.0, "YawTare": 100.0}, ) assert.Nil(t, ret) ret = d.Command("SetHeading")( map[string]interface{}{"heading": 100.0}, ) assert.Nil(t, ret) ret = d.Command("SetRotationRate")( map[string]interface{}{"level": 100.0}, ) assert.Nil(t, ret) ret = d.Command("SetStabilization")( map[string]interface{}{"enable": true}, ) assert.Nil(t, ret) ret = d.Command("SetStabilization")( map[string]interface{}{"enable": false}, ) assert.Nil(t, ret) ret = d.Command("Stop")(nil) assert.Nil(t, ret) ret = d.Command("GetRGB")(nil) assert.Equal(t, []byte{}, ret.([]byte)) ret = d.Command("ReadLocator")(nil) assert.Equal(t, []int16{}, ret) } func TestSpheroStart(t *testing.T) { d := initTestSpheroDriver() require.NoError(t, d.Start()) } func TestSpheroHalt(t *testing.T) { a := testutil.NewSerialTestAdaptor() _ = a.Connect() d := NewSpheroDriver(a) d.shutdownWaitTime = 0 // to speed up the tests require.NoError(t, d.Halt()) } func TestSpheroSetDataStreaming(t *testing.T) { d := initTestSpheroDriver() d.SetDataStreaming(spherocommon.DefaultDataStreamingConfig()) data := <-d.packetChannel buf := new(bytes.Buffer) _ = binary.Write(buf, binary.BigEndian, spherocommon.DefaultDataStreamingConfig()) assert.Equal(t, buf.Bytes(), data.body) ret := d.Command("SetDataStreaming")( map[string]interface{}{ "N": 100.0, "M": 200.0, "Mask": 300.0, "Pcnt": 255.0, "Mask2": 400.0, }, ) assert.Nil(t, ret) data = <-d.packetChannel dconfig := spherocommon.DataStreamingConfig{N: 100, M: 200, Mask: 300, Pcnt: 255, Mask2: 400} buf = new(bytes.Buffer) _ = binary.Write(buf, binary.BigEndian, dconfig) assert.Equal(t, buf.Bytes(), data.body) } func TestSpheroConfigureLocator(t *testing.T) { d := initTestSpheroDriver() d.ConfigureLocator(spheroDefaultLocatorConfig()) data := <-d.packetChannel buf := new(bytes.Buffer) _ = binary.Write(buf, binary.BigEndian, spheroDefaultLocatorConfig()) assert.Equal(t, buf.Bytes(), data.body) ret := d.Command("ConfigureLocator")( map[string]interface{}{ "Flags": 1.0, "X": 100.0, "Y": 100.0, "YawTare": 0.0, }, ) assert.Nil(t, ret) data = <-d.packetChannel lconfig := spherocommon.LocatorConfig{Flags: 1, X: 100, Y: 100, YawTare: 0} buf = new(bytes.Buffer) _ = binary.Write(buf, binary.BigEndian, lconfig) assert.Equal(t, buf.Bytes(), data.body) } ================================================ FILE: drivers/serial/testutil/testutil.go ================================================ package testutil import "fmt" type serialTestAdaptor struct { isConnected bool name string simulateConnectErr bool simulateReadErr bool simulateWriteErr bool } func NewSerialTestAdaptor() *serialTestAdaptor { return &serialTestAdaptor{} } func (t *serialTestAdaptor) SetSimulateConnectError(val bool) { t.simulateConnectErr = val } func (t *serialTestAdaptor) SetSimulateReadError(val bool) { t.simulateReadErr = val } func (t *serialTestAdaptor) SetSimulateWriteError(val bool) { t.simulateWriteErr = val } func (t *serialTestAdaptor) IsConnected() bool { return t.isConnected } func (t *serialTestAdaptor) SerialRead(b []byte) (int, error) { if t.simulateReadErr { return 0, fmt.Errorf("read error") } return len(b), nil } func (t *serialTestAdaptor) SerialWrite(b []byte) (int, error) { if t.simulateWriteErr { return 0, fmt.Errorf("write error") } return len(b), nil } // gobot.Adaptor interfaces func (t *serialTestAdaptor) Connect() error { if t.simulateConnectErr { return fmt.Errorf("connect error") } t.isConnected = true return nil } func (t *serialTestAdaptor) Finalize() error { return nil } func (t *serialTestAdaptor) Name() string { return t.name } func (t *serialTestAdaptor) SetName(n string) { t.name = n } ================================================ FILE: drivers/spi/README.md ================================================ # SPI This package provides drivers for [SPI](https://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus) devices. ## Getting Started Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) ## Hardware Support Gobot has a extensible system for connecting to hardware devices. The following SPI Devices are currently supported: - APA102 Programmable LEDs - MCP3002 Analog/Digital Converter - MCP3004 Analog/Digital Converter - MCP3008 Analog/Digital Converter - MCP3202 Analog/Digital Converter - MCP3204 Analog/Digital Converter - MCP3208 Analog/Digital Converter - MCP3304 Analog/Digital Converter - MFRC522 RFID Card Reader - SSD1306 OLED Display Controller - GoPiGo3 Robot The following SPI system drivers are currently supported: - SPI by `/dev/spidevX.Y` with the awesome [periph.io](https://periph.io/) which currently only works on Linux systems - SPI via GPIO's ================================================ FILE: drivers/spi/apa102.go ================================================ package spi import ( "image/color" "math" ) // APA102Driver is a driver for the APA102 programmable RGB LEDs. type APA102Driver struct { *Driver vals []color.RGBA brightness uint8 } // NewAPA102Driver creates a new Gobot Driver for APA102 RGB LEDs. // // Params: // // a *Adaptor - the Adaptor to use with this Driver. // count int - how many LEDs are in the array controlled by this driver. // bright - the default brightness to apply for all LEDs (must be between 0 and 31). // // Optional params: // // spi.WithBusNumber(int): bus to use with this driver. // spi.WithChipNumber(int): chip to use with this driver. // spi.WithMode(int): mode to use with this driver. // spi.WithBitCount(int): number of bits to use with this driver. // spi.WithSpeed(int64): speed in Hz to use with this driver. func NewAPA102Driver(a Connector, count int, bright uint8, options ...func(Config)) *APA102Driver { d := &APA102Driver{ Driver: NewDriver(a, "APA102"), vals: make([]color.RGBA, count), brightness: uint8(math.Min(float64(bright), 31)), } for _, option := range options { option(d) } return d } // SetRGBA sets the ith LED's color to the given RGBA value. // A subsequent call to Draw is required to transmit values // to the LED strip. func (d *APA102Driver) SetRGBA(i int, v color.RGBA) { d.vals[i] = v } // SetBrightness sets the ith LED's brightness to the given value. // Must be between 0 and 31. func (d *APA102Driver) SetBrightness(i uint8) { d.brightness = uint8(math.Min(float64(i), 31)) } // Brightness return driver brightness value. func (d *APA102Driver) Brightness() uint8 { return d.brightness } // Draw displays the RGBA values set on the actual LED strip. func (d *APA102Driver) Draw() error { // TODO(jbd): dotstar allows other RGBA alignments, support those layouts. n := len(d.vals) tx := make([]byte, 4*(n+1)+(n/2+1)) tx[0] = 0x00 tx[1] = 0x00 tx[2] = 0x00 tx[3] = 0x00 for i, c := range d.vals { j := (i + 1) * 4 if c.A != 0 { tx[j] = 0xe0 + byte(math.Min(float64(c.A), 31)) } else { tx[j] = 0xe0 + d.brightness } tx[j+1] = c.B tx[j+2] = c.G tx[j+3] = c.R } // end frame with at least n/2 0xff vals for i := (n + 1) * 4; i < len(tx); i++ { tx[i] = 0xff } return d.writeBytes(tx) } ================================================ FILE: drivers/spi/apa102_test.go ================================================ package spi import ( "image/color" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) // this ensures that the implementation is based on spi.Driver, which implements the gobot.Driver // and tests all implementations, so no further tests needed here for gobot.Driver interface var _ gobot.Driver = (*APA102Driver)(nil) func initTestAPA102DriverWithStubbedAdaptor() *APA102Driver { a := newSpiTestAdaptor() d := NewAPA102Driver(a, 10, 31) if err := d.Start(); err != nil { panic(err) } return d } func TestNewAPA102Driver(t *testing.T) { var di interface{} = NewAPA102Driver(newSpiTestAdaptor(), 10, 31) d, ok := di.(*APA102Driver) if !ok { require.Fail(t, "NewAPA102Driver() should have returned a *APA102Driver") } assert.NotNil(t, d.Driver) assert.True(t, strings.HasPrefix(d.Name(), "APA102")) } func TestAPA102Halt(t *testing.T) { // arrange d := NewAPA102Driver(newSpiTestAdaptor(), 10, 31) // act, assert require.NoError(t, d.Halt()) // must be idempotent require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestDriverLEDs(t *testing.T) { d := initTestAPA102DriverWithStubbedAdaptor() d.SetRGBA(0, color.RGBA{255, 255, 255, 15}) d.SetRGBA(1, color.RGBA{255, 255, 255, 15}) d.SetRGBA(2, color.RGBA{255, 255, 255, 15}) d.SetRGBA(3, color.RGBA{255, 255, 255, 15}) require.NoError(t, d.Draw()) } ================================================ FILE: drivers/spi/doc.go ================================================ /* Package spi provides Gobot drivers for spi devices. Uses periph.io for spi Installing: Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) For further information refer to spi README: https://github.com/hybridgroup/gobot/blob/release/drivers/spi/README.md */ package spi // import "gobot.io/x/gobot/v2/drivers/spi" ================================================ FILE: drivers/spi/helpers_test.go ================================================ package spi import ( "fmt" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/system" ) // make sure that this SpiBusAdaptor fulfills all the required interfaces var ( _ Connector = (*spiTestAdaptor)(nil) _ gobot.Connection = (*spiTestAdaptor)(nil) ) type spiTestAdaptor struct { sys *system.Accesser // busNum int spiConnectErr bool spi *system.MockSpiAccess connection Connection } func newSpiTestAdaptor() *spiTestAdaptor { sys := system.NewAccesser() spi := sys.UseMockSpi() a := &spiTestAdaptor{ sys: sys, spi: spi, } return a } // spi.Connector interfaces func (a *spiTestAdaptor) GetSpiConnection(busNum, chipNum, mode, bits int, maxSpeed int64) (Connection, error) { if a.spiConnectErr { return nil, fmt.Errorf("invalid SPI connection in helper") } // a.busNum = busNum sysdev, err := a.sys.NewSpiDevice(busNum, chipNum, mode, bits, maxSpeed) a.connection = NewConnection(sysdev) return a.connection, err } func (a *spiTestAdaptor) SpiDefaultBusNumber() int { return 0 } func (a *spiTestAdaptor) SpiDefaultChipNumber() int { return 0 } func (a *spiTestAdaptor) SpiDefaultMode() int { return 0 } func (a *spiTestAdaptor) SpiDefaultBitCount() int { return 0 } func (a *spiTestAdaptor) SpiDefaultMaxSpeed() int64 { return 0 } // gobot.Connection interfaces func (a *spiTestAdaptor) Connect() error { return nil } func (a *spiTestAdaptor) Finalize() error { return nil } func (a *spiTestAdaptor) Name() string { return "board name" } func (a *spiTestAdaptor) SetName(string) {} ================================================ FILE: drivers/spi/mcp3002.go ================================================ package spi import ( "fmt" "strconv" ) // MCP3002DriverMaxChannel is the number of channels of this A/D converter. const MCP3002DriverMaxChannel = 2 // MCP3002Driver is a driver for the MCP3002 A/D converter. type MCP3002Driver struct { *Driver } // NewMCP3002Driver creates a new Gobot Driver for MCP3002 A/D converter // // Params: // // a *Adaptor - the Adaptor to use with this Driver // // Optional params: // // spi.WithBusNumber(int): bus to use with this driver // spi.WithChipNumber(int): chip to use with this driver // spi.WithMode(int): mode to use with this driver // spi.WithBitCount(int): number of bits to use with this driver // spi.WithSpeed(int64): speed in Hz to use with this driver func NewMCP3002Driver(a Connector, options ...func(Config)) *MCP3002Driver { d := &MCP3002Driver{ Driver: NewDriver(a, "MCP3002"), } for _, option := range options { option(d) } return d } // Read reads the current analog data for the desired channel. func (d *MCP3002Driver) Read(channel int) (int, error) { if channel < 0 || channel > MCP3002DriverMaxChannel-1 { return 0, fmt.Errorf("invalid channel '%d' for read", channel) } tx := make([]byte, 2) tx[0] = 0x68 + (byte(channel) << 4) tx[1] = 0x00 rx := make([]byte, 2) if err := d.readCommandData(tx, rx); err != nil { return 0, err } return int((rx[0]&0x3))<<8 + int(rx[1]), nil } // AnalogRead returns value from analog reading of specified pin func (d *MCP3002Driver) AnalogRead(pin string) (int, error) { channel, _ := strconv.Atoi(pin) return d.Read(channel) } ================================================ FILE: drivers/spi/mcp3002_test.go ================================================ package spi import ( "fmt" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" ) // this ensures that the implementation is based on spi.Driver, which implements the gobot.Driver // and tests all implementations, so no further tests needed here for gobot.Driver interface var _ gobot.Driver = (*MCP3002Driver)(nil) // must implement the AnalogReader interface var _ aio.AnalogReader = (*MCP3002Driver)(nil) func initTestMCP3002DriverWithStubbedAdaptor() (*MCP3002Driver, *spiTestAdaptor) { a := newSpiTestAdaptor() d := NewMCP3002Driver(a) if err := d.Start(); err != nil { panic(err) } return d, a } func TestNewMCP3002Driver(t *testing.T) { var di interface{} = NewMCP3002Driver(newSpiTestAdaptor()) d, ok := di.(*MCP3002Driver) if !ok { require.Fail(t, "NewMCP3002Driver() should have returned a *MCP3002Driver") } assert.NotNil(t, d.Driver) assert.True(t, strings.HasPrefix(d.Name(), "MCP3002")) } func TestMCP3002Halt(t *testing.T) { // arrange d := NewMCP3002Driver(newSpiTestAdaptor()) // act, assert require.NoError(t, d.Halt()) // must be idempotent require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestMCP3002Read(t *testing.T) { tests := map[string]struct { chanNum int simRead []byte want int wantWritten []byte wantErr error }{ "number_negative_error": { chanNum: -1, wantErr: fmt.Errorf("invalid channel '-1' for read"), }, "number_0_ok": { chanNum: 0, simRead: []byte{0xFF, 0xFF}, wantWritten: []byte{0x68, 0x00}, want: 0x3FF, }, "number_1_ok": { chanNum: 1, simRead: []byte{0xF2, 0x22}, wantWritten: []byte{0x78, 0x00}, want: 0x222, }, "number_2_error": { chanNum: 2, wantErr: fmt.Errorf("invalid channel '2' for read"), }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, a := initTestMCP3002DriverWithStubbedAdaptor() a.spi.SetSimRead(tc.simRead) // act got, err := d.Read(tc.chanNum) // assert assert.Equal(t, tc.wantErr, err) assert.Equal(t, tc.want, got) assert.Equal(t, tc.wantWritten, a.spi.Written()) }) } } func TestMCP3002ReadWithError(t *testing.T) { // arrange d, a := initTestMCP3002DriverWithStubbedAdaptor() a.spi.SetReadError(true) // act got, err := d.Read(0) // assert require.ErrorContains(t, err, "error while SPI read in mock") assert.Equal(t, 0, got) } ================================================ FILE: drivers/spi/mcp3004.go ================================================ package spi import ( "fmt" "strconv" ) // MCP3004DriverMaxChannel is the number of channels of this A/D converter. const MCP3004DriverMaxChannel = 4 // MCP3004Driver is a driver for the MCP3008 A/D converter. type MCP3004Driver struct { *Driver } // NewMCP3004Driver creates a new Gobot Driver for MCP3004 A/D converter // // Params: // // a *Adaptor - the Adaptor to use with this Driver // // Optional params: // // spi.WithBusNumber(int): bus to use with this driver // spi.WithChipNumber(int): chip to use with this driver // spi.WithMode(int): mode to use with this driver // spi.WithBitCount(int): number of bits to use with this driver // spi.WithSpeed(int64): speed in Hz to use with this driver func NewMCP3004Driver(a Connector, options ...func(Config)) *MCP3004Driver { d := &MCP3004Driver{ Driver: NewDriver(a, "MCP3004"), } for _, option := range options { option(d) } return d } // Read reads the current analog data for the desired channel. func (d *MCP3004Driver) Read(channel int) (int, error) { if channel < 0 || channel > MCP3004DriverMaxChannel-1 { return 0, fmt.Errorf("invalid channel '%d' for read", channel) } tx := make([]byte, 3) tx[0] = 0x01 tx[1] = byte(8+channel) << 4 tx[2] = 0x00 rx := make([]byte, 3) if err := d.readCommandData(tx, rx); err != nil || len(rx) != 3 { return 0, err } result := int((rx[1]&0x3))<<8 + int(rx[2]) return result, nil } // AnalogRead returns value from analog reading of specified pin func (d *MCP3004Driver) AnalogRead(pin string) (int, error) { channel, _ := strconv.Atoi(pin) return d.Read(channel) } ================================================ FILE: drivers/spi/mcp3004_test.go ================================================ package spi import ( "fmt" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" ) // this ensures that the implementation is based on spi.Driver, which implements the gobot.Driver // and tests all implementations, so no further tests needed here for gobot.Driver interface var _ gobot.Driver = (*MCP3004Driver)(nil) // must implement the AnalogReader interface var _ aio.AnalogReader = (*MCP3004Driver)(nil) func initTestMCP3004DriverWithStubbedAdaptor() (*MCP3004Driver, *spiTestAdaptor) { a := newSpiTestAdaptor() d := NewMCP3004Driver(a) if err := d.Start(); err != nil { panic(err) } return d, a } func TestNewMCP3004Driver(t *testing.T) { var di interface{} = NewMCP3004Driver(newSpiTestAdaptor()) d, ok := di.(*MCP3004Driver) if !ok { require.Fail(t, "NewMCP3004Driver() should have returned a *MCP3004Driver") } assert.NotNil(t, d.Driver) assert.True(t, strings.HasPrefix(d.Name(), "MCP3004")) } func TestMCP3004Halt(t *testing.T) { // arrange d := NewMCP3004Driver(newSpiTestAdaptor()) // act, assert require.NoError(t, d.Halt()) // must be idempotent require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestMCP3004Read(t *testing.T) { tests := map[string]struct { chanNum int simRead []byte want int wantWritten []byte wantErr error }{ "number_negative_error": { chanNum: -1, wantErr: fmt.Errorf("invalid channel '-1' for read"), }, "number_0_ok": { chanNum: 0, simRead: []byte{0xFF, 0xFF, 0xFF}, wantWritten: []byte{0x01, 0x80, 0x00}, want: 0x03FF, }, "number_1_ok": { chanNum: 1, simRead: []byte{0xFF, 0xF1, 0xFF}, wantWritten: []byte{0x01, 0x90, 0x00}, want: 0x01FF, }, "number_3_ok": { chanNum: 3, simRead: []byte{0xFF, 0xF2, 0x11}, wantWritten: []byte{0x01, 0xB0, 0x00}, want: 0x0211, }, "number_4_error": { chanNum: 4, wantErr: fmt.Errorf("invalid channel '4' for read"), }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, a := initTestMCP3004DriverWithStubbedAdaptor() a.spi.SetSimRead(tc.simRead) // act got, err := d.Read(tc.chanNum) // assert assert.Equal(t, tc.wantErr, err) assert.Equal(t, tc.want, got) assert.Equal(t, tc.wantWritten, a.spi.Written()) }) } } func TestMCP3004ReadWithError(t *testing.T) { // arrange d, a := initTestMCP3004DriverWithStubbedAdaptor() a.spi.SetReadError(true) // act got, err := d.Read(0) // assert require.ErrorContains(t, err, "error while SPI read in mock") assert.Equal(t, 0, got) } ================================================ FILE: drivers/spi/mcp3008.go ================================================ package spi import ( "fmt" "strconv" ) // MCP3008DriverMaxChannel is the number of channels of this A/D converter. const MCP3008DriverMaxChannel = 8 // MCP3008Driver is a driver for the MCP3008 A/D converter. type MCP3008Driver struct { *Driver } // NewMCP3008Driver creates a new Gobot Driver for MCP3008Driver A/D converter // // Params: // // a *Adaptor - the Adaptor to use with this Driver // // Optional params: // // spi.WithBusNumber(int): bus to use with this driver // spi.WithChipNumber(int): chip to use with this driver // spi.WithMode(int): mode to use with this driver // spi.WithBitCount(int): number of bits to use with this driver // spi.WithSpeed(int64): speed in Hz to use with this driver func NewMCP3008Driver(a Connector, options ...func(Config)) *MCP3008Driver { d := &MCP3008Driver{ Driver: NewDriver(a, "MCP3008"), } for _, option := range options { option(d) } return d } // Read reads the current analog data for the desired channel. func (d *MCP3008Driver) Read(channel int) (int, error) { if channel < 0 || channel > MCP3008DriverMaxChannel-1 { return 0, fmt.Errorf("invalid channel '%d' for read", channel) } tx := make([]byte, 3) tx[0] = 0x01 tx[1] = byte(8+channel) << 4 tx[2] = 0x00 rx := make([]byte, 3) if err := d.readCommandData(tx, rx); err != nil || len(rx) != 3 { return 0, err } result := int((rx[1]&0x3))<<8 + int(rx[2]) return result, nil } // AnalogRead returns value from analog reading of specified pin func (d *MCP3008Driver) AnalogRead(pin string) (int, error) { channel, _ := strconv.Atoi(pin) return d.Read(channel) } ================================================ FILE: drivers/spi/mcp3008_test.go ================================================ package spi import ( "fmt" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" ) // this ensures that the implementation is based on spi.Driver, which implements the gobot.Driver // and tests all implementations, so no further tests needed here for gobot.Driver interface var _ gobot.Driver = (*MCP3008Driver)(nil) // must implement the AnalogReader interface var _ aio.AnalogReader = (*MCP3008Driver)(nil) func initTestMCP3008DriverWithStubbedAdaptor() (*MCP3008Driver, *spiTestAdaptor) { a := newSpiTestAdaptor() d := NewMCP3008Driver(a) if err := d.Start(); err != nil { panic(err) } return d, a } func TestNewMCP3008Driver(t *testing.T) { var di interface{} = NewMCP3008Driver(newSpiTestAdaptor()) d, ok := di.(*MCP3008Driver) if !ok { require.Fail(t, "NewMCP3008Driver() should have returned a *MCP3008Driver") } assert.NotNil(t, d.Driver) assert.True(t, strings.HasPrefix(d.Name(), "MCP3008")) } func TestMCP3008Halt(t *testing.T) { // arrange d := NewMCP3008Driver(newSpiTestAdaptor()) // act, assert require.NoError(t, d.Halt()) // must be idempotent require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestMCP3008Read(t *testing.T) { tests := map[string]struct { chanNum int simRead []byte want int wantWritten []byte wantErr error }{ "number_negative_error": { chanNum: -1, wantErr: fmt.Errorf("invalid channel '-1' for read"), }, "number_0_ok": { chanNum: 0, simRead: []byte{0xFF, 0xFF, 0xFF}, wantWritten: []byte{0x01, 0x80, 0x00}, want: 0x03FF, }, "number_1_ok": { chanNum: 1, simRead: []byte{0xFF, 0xF1, 0xFF}, wantWritten: []byte{0x01, 0x90, 0x00}, want: 0x01FF, }, "number_7_ok": { chanNum: 7, simRead: []byte{0xFF, 0xF2, 0x11}, wantWritten: []byte{0x01, 0xF0, 0x00}, want: 0x0211, }, "number_8_error": { chanNum: 8, wantErr: fmt.Errorf("invalid channel '8' for read"), }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, a := initTestMCP3008DriverWithStubbedAdaptor() a.spi.SetSimRead(tc.simRead) // act got, err := d.Read(tc.chanNum) // assert assert.Equal(t, tc.wantErr, err) assert.Equal(t, tc.want, got) assert.Equal(t, tc.wantWritten, a.spi.Written()) }) } } func TestMCP3008ReadWithError(t *testing.T) { // arrange d, a := initTestMCP3008DriverWithStubbedAdaptor() a.spi.SetReadError(true) // act got, err := d.Read(0) // assert require.ErrorContains(t, err, "error while SPI read in mock") assert.Equal(t, 0, got) } ================================================ FILE: drivers/spi/mcp3202.go ================================================ package spi import ( "fmt" "strconv" "gobot.io/x/gobot/v2" ) // MCP3202DriverMaxChannel is the number of channels of this A/D converter. const MCP3202DriverMaxChannel = 2 // MCP3202Driver is a driver for the MCP3202 A/D converter. type MCP3202Driver struct { *Driver } // NewMCP3202Driver creates a new Gobot Driver for MCP3202Driver A/D converter // // Params: // // a *Adaptor - the Adaptor to use with this Driver // // Optional params: // // spi.WithBusNumber(int): bus to use with this driver // spi.WithChipNumber(int): chip to use with this driver // spi.WithMode(int): mode to use with this driver // spi.WithBitCount(int): number of bits to use with this driver // spi.WithSpeed(int64): speed in Hz to use with this driver func NewMCP3202Driver(a Connector, options ...func(Config)) *MCP3202Driver { d := &MCP3202Driver{ Driver: NewDriver(a, "MCP3202"), } for _, option := range options { option(d) } return d } // Read reads the current analog data for the desired channel. func (d *MCP3202Driver) Read(channel int) (int, error) { if channel < 0 || channel > MCP3202DriverMaxChannel-1 { return 0, fmt.Errorf("invalid channel '%d' for read", channel) } tx := make([]byte, 3) tx[0] = 0x01 tx[1] = 0xa0 + byte(channel)<<6 tx[2] = 0x00 rx := make([]byte, 3) if err := d.readCommandData(tx, rx); err != nil || len(rx) != 3 { return 0, err } result := int((rx[1]&0xf))<<8 + int(rx[2]) return result, nil } // AnalogRead returns value from analog reading of specified pin, scaled to 0-1023 value. func (d *MCP3202Driver) AnalogRead(pin string) (int, error) { channel, _ := strconv.Atoi(pin) value, err := d.Read(channel) if err != nil { return 0, err } return int(gobot.ToScale(gobot.FromScale(float64(value), 0, 4095), 0, 1023)), err } ================================================ FILE: drivers/spi/mcp3202_test.go ================================================ package spi import ( "fmt" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" ) // this ensures that the implementation is based on spi.Driver, which implements the gobot.Driver // and tests all implementations, so no further tests needed here for gobot.Driver interface var _ gobot.Driver = (*MCP3202Driver)(nil) // must implement the AnalogReader interface var _ aio.AnalogReader = (*MCP3202Driver)(nil) func initTestMCP3202DriverWithStubbedAdaptor() (*MCP3202Driver, *spiTestAdaptor) { a := newSpiTestAdaptor() d := NewMCP3202Driver(a) if err := d.Start(); err != nil { panic(err) } return d, a } func TestNewMCP3202Driver(t *testing.T) { var di interface{} = NewMCP3202Driver(newSpiTestAdaptor()) d, ok := di.(*MCP3202Driver) if !ok { require.Fail(t, "NewMCP3202Driver() should have returned a *MCP3202Driver") } assert.NotNil(t, d.Driver) assert.True(t, strings.HasPrefix(d.Name(), "MCP3202")) } func TestMCP3202Halt(t *testing.T) { // arrange d := NewMCP3202Driver(newSpiTestAdaptor()) // act, assert require.NoError(t, d.Halt()) // must be idempotent require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestMCP3202Read(t *testing.T) { tests := map[string]struct { chanNum int simRead []byte want int wantWritten []byte wantErr error }{ "number_negative_error": { chanNum: -1, wantErr: fmt.Errorf("invalid channel '-1' for read"), }, "number_0_ok": { chanNum: 0, simRead: []byte{0xFF, 0xFF, 0xFF}, wantWritten: []byte{0x01, 0xA0, 0x00}, want: 0x0FFF, }, "number_1_ok": { chanNum: 1, simRead: []byte{0xFF, 0xFE, 0xFF}, wantWritten: []byte{0x01, 0xE0, 0x00}, want: 0x0EFF, }, "number_2_error": { chanNum: 2, wantErr: fmt.Errorf("invalid channel '2' for read"), }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, a := initTestMCP3202DriverWithStubbedAdaptor() a.spi.SetSimRead(tc.simRead) // act got, err := d.Read(tc.chanNum) // assert assert.Equal(t, tc.wantErr, err) assert.Equal(t, tc.want, got) assert.Equal(t, tc.wantWritten, a.spi.Written()) }) } } func TestMCP3202ReadWithError(t *testing.T) { // arrange d, a := initTestMCP3202DriverWithStubbedAdaptor() a.spi.SetReadError(true) // act got, err := d.Read(0) // assert require.ErrorContains(t, err, "error while SPI read in mock") assert.Equal(t, 0, got) } ================================================ FILE: drivers/spi/mcp3204.go ================================================ package spi import ( "fmt" "strconv" "gobot.io/x/gobot/v2" ) // MCP3204DriverMaxChannel is the number of channels of this A/D converter. const MCP3204DriverMaxChannel = 4 // MCP3204Driver is a driver for the MCP3204 A/D converter. type MCP3204Driver struct { *Driver } // NewMCP3204Driver creates a new Gobot Driver for MCP3204Driver A/D converter // // Params: // // a *Adaptor - the Adaptor to use with this Driver // // Optional params: // // spi.WithBusNumber(int): bus to use with this driver // spi.WithChipNumber(int): chip to use with this driver // spi.WithMode(int): mode to use with this driver // spi.WithBitCount(int): number of bits to use with this driver // spi.WithSpeed(int64): speed in Hz to use with this driver func NewMCP3204Driver(a Connector, options ...func(Config)) *MCP3204Driver { d := &MCP3204Driver{ Driver: NewDriver(a, "MCP3204"), } for _, option := range options { option(d) } return d } // Read reads the current analog data for the desired channel. func (d *MCP3204Driver) Read(channel int) (int, error) { if channel < 0 || channel > MCP3204DriverMaxChannel-1 { return 0, fmt.Errorf("invalid channel '%d' for read", channel) } tx := make([]byte, 3) tx[0] = 0x06 + (byte(channel) >> 2) tx[1] = (byte(channel) & 0x03) << 6 tx[2] = 0x00 rx := make([]byte, 3) if err := d.readCommandData(tx, rx); err != nil || len(rx) != 3 { return 0, err } result := int((rx[1]&0xf))<<8 + int(rx[2]) return result, nil } // AnalogRead returns value from analog reading of specified pin, scaled to 0-1023 value. func (d *MCP3204Driver) AnalogRead(pin string) (int, error) { channel, _ := strconv.Atoi(pin) value, err := d.Read(channel) if err != nil { return 0, err } return int(gobot.ToScale(gobot.FromScale(float64(value), 0, 4095), 0, 1023)), err } ================================================ FILE: drivers/spi/mcp3204_test.go ================================================ package spi import ( "fmt" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" ) // this ensures that the implementation is based on spi.Driver, which implements the gobot.Driver // and tests all implementations, so no further tests needed here for gobot.Driver interface var _ gobot.Driver = (*MCP3204Driver)(nil) // must implement the AnalogReader interface var _ aio.AnalogReader = (*MCP3204Driver)(nil) func initTestMCP3204DriverWithStubbedAdaptor() (*MCP3204Driver, *spiTestAdaptor) { a := newSpiTestAdaptor() d := NewMCP3204Driver(a) if err := d.Start(); err != nil { panic(err) } return d, a } func TestNewMCP3204Driver(t *testing.T) { var di interface{} = NewMCP3204Driver(newSpiTestAdaptor()) d, ok := di.(*MCP3204Driver) if !ok { require.Fail(t, "NewMCP3204Driver() should have returned a *MCP3204Driver") } assert.NotNil(t, d.Driver) assert.True(t, strings.HasPrefix(d.Name(), "MCP3204")) } func TestMCP3204Halt(t *testing.T) { // arrange d := NewMCP3204Driver(newSpiTestAdaptor()) // act, assert require.NoError(t, d.Halt()) // must be idempotent require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestMCP3204Read(t *testing.T) { tests := map[string]struct { chanNum int simRead []byte want int wantWritten []byte wantErr error }{ "number_negative_error": { chanNum: -1, wantErr: fmt.Errorf("invalid channel '-1' for read"), }, "number_0_ok": { chanNum: 0, simRead: []byte{0xFF, 0xFF, 0xFF}, wantWritten: []byte{0x06, 0x00, 0x00}, want: 0x0FFF, }, "number_1_ok": { chanNum: 1, simRead: []byte{0xFF, 0xFE, 0xFF}, wantWritten: []byte{0x06, 0x40, 0x00}, want: 0x0EFF, }, "number_3_ok": { chanNum: 3, simRead: []byte{0xFF, 0xF3, 0x21}, wantWritten: []byte{0x06, 0xC0, 0x00}, want: 0x0321, }, "number_4_error": { chanNum: 4, wantErr: fmt.Errorf("invalid channel '4' for read"), }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, a := initTestMCP3204DriverWithStubbedAdaptor() a.spi.SetSimRead(tc.simRead) // act got, err := d.Read(tc.chanNum) // assert assert.Equal(t, tc.wantErr, err) assert.Equal(t, tc.want, got) assert.Equal(t, tc.wantWritten, a.spi.Written()) }) } } func TestMCP3204ReadWithError(t *testing.T) { // arrange d, a := initTestMCP3204DriverWithStubbedAdaptor() a.spi.SetReadError(true) // act got, err := d.Read(0) // assert require.ErrorContains(t, err, "error while SPI read in mock") assert.Equal(t, 0, got) } ================================================ FILE: drivers/spi/mcp3208.go ================================================ package spi import ( "fmt" "strconv" "gobot.io/x/gobot/v2" ) // MCP3208DriverMaxChannel is the number of channels of this A/D converter. const MCP3208DriverMaxChannel = 8 // MCP3208Driver is a driver for the MCP3208 A/D converter. type MCP3208Driver struct { *Driver } // NewMCP3208Driver creates a new Gobot Driver for MCP3208Driver A/D converter // // Params: // // a *Adaptor - the Adaptor to use with this Driver // // Optional params: // // spi.WithBusNumber(int): bus to use with this driver // spi.WithChipNumber(int): chip to use with this driver // spi.WithMode(int): mode to use with this driver // spi.WithBitCount(int): number of bits to use with this driver // spi.WithSpeed(int64): speed in Hz to use with this driver func NewMCP3208Driver(a Connector, options ...func(Config)) *MCP3208Driver { d := &MCP3208Driver{ Driver: NewDriver(a, "MCP3208"), } for _, option := range options { option(d) } return d } // Read reads the current analog data for the desired channel. func (d *MCP3208Driver) Read(channel int) (int, error) { if channel < 0 || channel > MCP3208DriverMaxChannel-1 { return 0, fmt.Errorf("invalid channel '%d' for read", channel) } tx := make([]byte, 3) tx[0] = 0x06 + (byte(channel) >> 2) tx[1] = (byte(channel) & 0x03) << 6 tx[2] = 0x00 rx := make([]byte, 3) if err := d.readCommandData(tx, rx); err != nil || len(rx) != 3 { return 0, err } result := int((rx[1]&0xf))<<8 + int(rx[2]) return result, nil } // AnalogRead returns value from analog reading of specified pin, scaled to 0-1023 value. func (d *MCP3208Driver) AnalogRead(pin string) (int, error) { channel, _ := strconv.Atoi(pin) value, err := d.Read(channel) if err != nil { return 0, err } return int(gobot.ToScale(gobot.FromScale(float64(value), 0, 4095), 0, 1023)), err } ================================================ FILE: drivers/spi/mcp3208_test.go ================================================ package spi import ( "fmt" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" ) // this ensures that the implementation is based on spi.Driver, which implements the gobot.Driver // and tests all implementations, so no further tests needed here for gobot.Driver interface var _ gobot.Driver = (*MCP3208Driver)(nil) // must implement the AnalogReader interface var _ aio.AnalogReader = (*MCP3208Driver)(nil) func initTestMCP3208DriverWithStubbedAdaptor() (*MCP3208Driver, *spiTestAdaptor) { a := newSpiTestAdaptor() d := NewMCP3208Driver(a) if err := d.Start(); err != nil { panic(err) } return d, a } func TestNewMCP3208Driver(t *testing.T) { var di interface{} = NewMCP3208Driver(newSpiTestAdaptor()) d, ok := di.(*MCP3208Driver) if !ok { require.Fail(t, "NewMCP3208Driver() should have returned a *MCP3208Driver") } assert.NotNil(t, d.Driver) assert.True(t, strings.HasPrefix(d.Name(), "MCP3208")) } func TestMCP3208Halt(t *testing.T) { // arrange d := NewMCP3208Driver(newSpiTestAdaptor()) // act, assert require.NoError(t, d.Halt()) // must be idempotent require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestMCP3208Read(t *testing.T) { tests := map[string]struct { chanNum int simRead []byte want int wantWritten []byte wantErr error }{ "number_negative_error": { chanNum: -1, wantErr: fmt.Errorf("invalid channel '-1' for read"), }, "number_0_ok": { chanNum: 0, simRead: []byte{0xFF, 0xFF, 0xFF}, wantWritten: []byte{0x06, 0x00, 0x00}, want: 0x0FFF, }, "number_1_ok": { chanNum: 1, simRead: []byte{0xFF, 0xFE, 0xFF}, wantWritten: []byte{0x06, 0x40, 0x00}, want: 0x0EFF, }, "number_7_ok": { chanNum: 7, simRead: []byte{0xFF, 0xF7, 0x65}, wantWritten: []byte{0x07, 0xC0, 0x00}, want: 0x0765, }, "number_8_error": { chanNum: 8, wantErr: fmt.Errorf("invalid channel '8' for read"), }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, a := initTestMCP3208DriverWithStubbedAdaptor() a.spi.SetSimRead(tc.simRead) // act got, err := d.Read(tc.chanNum) // assert assert.Equal(t, tc.wantErr, err) assert.Equal(t, tc.want, got) assert.Equal(t, tc.wantWritten, a.spi.Written()) }) } } func TestMCP3208ReadWithError(t *testing.T) { // arrange d, a := initTestMCP3208DriverWithStubbedAdaptor() a.spi.SetReadError(true) // act got, err := d.Read(0) // assert require.ErrorContains(t, err, "error while SPI read in mock") assert.Equal(t, 0, got) } ================================================ FILE: drivers/spi/mcp3304.go ================================================ package spi import ( "fmt" "strconv" "gobot.io/x/gobot/v2" ) // MCP3304DriverMaxChannel is the number of channels of this A/D converter. const MCP3304DriverMaxChannel = 8 // MCP3304Driver is a driver for the MCP3304 A/D converter. type MCP3304Driver struct { *Driver } // NewMCP3304Driver creates a new Gobot Driver for MCP3304Driver A/D converter // // Params: // // a *Adaptor - the Adaptor to use with this Driver // // Optional params: // // spi.WithBusNumber(int): bus to use with this driver // spi.WithChipNumber(int): chip to use with this driver // spi.WithMode(int): mode to use with this driver // spi.WithBitCount(int): number of bits to use with this driver // spi.WithSpeed(int64): speed in Hz to use with this driver func NewMCP3304Driver(a Connector, options ...func(Config)) *MCP3304Driver { d := &MCP3304Driver{ Driver: NewDriver(a, "MCP3304"), } for _, option := range options { option(d) } return d } // Read reads the current analog data for the desired channel. func (d *MCP3304Driver) Read(channel int) (int, error) { if channel < 0 || channel > MCP3304DriverMaxChannel-1 { return 0, fmt.Errorf("invalid channel '%d' for read", channel) } tx := make([]byte, 3) tx[0] = 0x0c + (byte(channel) >> 1) tx[1] = (byte(channel) & 0x01) << 7 tx[2] = 0x00 rx := make([]byte, 3) if err := d.readCommandData(tx, rx); err != nil || len(rx) != 3 { return 0, err } result := int((rx[1]&0xf))<<8 + int(rx[2]) return result, nil } // AnalogRead returns value from analog reading of specified pin, scaled to 0-1023 value. func (d *MCP3304Driver) AnalogRead(pin string) (int, error) { channel, _ := strconv.Atoi(pin) value, err := d.Read(channel) if err != nil { return 0, err } return int(gobot.ToScale(gobot.FromScale(float64(value), 0, 4095), 0, 1023)), err } ================================================ FILE: drivers/spi/mcp3304_test.go ================================================ package spi import ( "fmt" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" ) // this ensures that the implementation is based on spi.Driver, which implements the gobot.Driver // and tests all implementations, so no further tests needed here for gobot.Driver interface var _ gobot.Driver = (*MCP3304Driver)(nil) // must implement the AnalogReader interface var _ aio.AnalogReader = (*MCP3304Driver)(nil) func initTestMCP3304DriverWithStubbedAdaptor() (*MCP3304Driver, *spiTestAdaptor) { a := newSpiTestAdaptor() d := NewMCP3304Driver(a) if err := d.Start(); err != nil { panic(err) } return d, a } func TestNewMCP3304Driver(t *testing.T) { var di interface{} = NewMCP3304Driver(newSpiTestAdaptor()) d, ok := di.(*MCP3304Driver) if !ok { require.Fail(t, "NewMCP3304Driver() should have returned a *MCP3304Driver") } assert.NotNil(t, d.Driver) assert.True(t, strings.HasPrefix(d.Name(), "MCP3304")) } func TestMCP3304Halt(t *testing.T) { // arrange d := NewMCP3304Driver(newSpiTestAdaptor()) // act, assert require.NoError(t, d.Halt()) // must be idempotent require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestMCP3304Read(t *testing.T) { tests := map[string]struct { chanNum int simRead []byte want int wantWritten []byte wantErr error }{ "number_negative_error": { chanNum: -1, wantErr: fmt.Errorf("invalid channel '-1' for read"), }, "number_0_ok": { chanNum: 0, simRead: []byte{0xFF, 0xFF, 0xFF}, wantWritten: []byte{0x0C, 0x00, 0x00}, want: 0x0FFF, }, "number_1_ok": { chanNum: 1, simRead: []byte{0xFF, 0xFE, 0xFF}, wantWritten: []byte{0x0C, 0x80, 0x00}, want: 0x0EFF, }, "number_7_ok": { chanNum: 7, simRead: []byte{0xFF, 0xF7, 0x65}, wantWritten: []byte{0x0F, 0x80, 0x00}, want: 0x0765, }, "number_8_error": { chanNum: 8, wantErr: fmt.Errorf("invalid channel '8' for read"), }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, a := initTestMCP3304DriverWithStubbedAdaptor() a.spi.SetSimRead(tc.simRead) // act got, err := d.Read(tc.chanNum) // assert assert.Equal(t, tc.wantErr, err) assert.Equal(t, tc.want, got) assert.Equal(t, tc.wantWritten, a.spi.Written()) }) } } func TestMCP3304ReadWithError(t *testing.T) { // arrange d, a := initTestMCP3304DriverWithStubbedAdaptor() a.spi.SetReadError(true) // act got, err := d.Read(0) // assert require.ErrorContains(t, err, "error while SPI read in mock") assert.Equal(t, 0, got) } ================================================ FILE: drivers/spi/mfrc522_driver.go ================================================ package spi import ( "gobot.io/x/gobot/v2/drivers/common/mfrc522" ) // MFRC522Driver is a wrapper for SPI bus usage. Please refer to the mfrc522.MFRC522Common package // for implementation details. type MFRC522Driver struct { *Driver *mfrc522.MFRC522Common } // NewMFRC522Driver creates a new Gobot Driver for MFRC522 RFID with SPI connection // // Params: // // a *Adaptor - the Adaptor to use with this Driver // // Optional params: // // spi.WithBusNumber(int): bus to use with this driver // spi.WithChipNumber(int): chip to use with this driver // spi.WithMode(int): mode to use with this driver // spi.WithBitCount(int): number of bits to use with this driver // spi.WithSpeed(int64): speed in Hz to use with this driver func NewMFRC522Driver(a Connector, options ...func(Config)) *MFRC522Driver { d := &MFRC522Driver{ Driver: NewDriver(a, "MFRC522"), } d.MFRC522Common = mfrc522.NewMFRC522Common() d.afterStart = d.initialize for _, option := range options { option(d) } return d } func (d *MFRC522Driver) initialize() error { wrapper := &conWrapper{origCon: d.connection} return d.Initialize(wrapper) } // this is necessary due to special behavior of shift bytes and set first bit type conWrapper struct { origCon Connection } func (w *conWrapper) ReadByteData(reg uint8) (uint8, error) { // MSBit=1 for reading, LSBit not used for first byte (address/register) return w.origCon.ReadByteData(0x80 | (reg << 1)) } func (w *conWrapper) WriteByteData(reg uint8, val uint8) error { // LSBit not used for first byte (address/register) return w.origCon.WriteByteData(reg<<1, val) } ================================================ FILE: drivers/spi/mfrc522_driver_test.go ================================================ package spi import ( "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) // this ensures that the implementation is based on spi.Driver, which implements the gobot.Driver // and tests all implementations, so no further tests needed here for gobot.Driver interface var _ gobot.Driver = (*MFRC522Driver)(nil) func initTestMFRC522DriverWithStubbedAdaptor() (*MFRC522Driver, *spiTestAdaptor) { a := newSpiTestAdaptor() d := NewMFRC522Driver(a) if err := d.Start(); err != nil { panic(err) } // reset the written bytes during Start() a.spi.Reset() return d, a } func TestNewMFRC522Driver(t *testing.T) { var di interface{} = NewMFRC522Driver(newSpiTestAdaptor()) d, ok := di.(*MFRC522Driver) if !ok { require.Fail(t, "NewMFRC522Driver() should have returned a *MFRC522Driver") } assert.NotNil(t, d.Driver) assert.True(t, strings.HasPrefix(d.Name(), "MFRC522")) } func TestMFRC522Halt(t *testing.T) { // arrange d := NewMFRC522Driver(newSpiTestAdaptor()) // act, assert require.NoError(t, d.Halt()) // must be idempotent require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestMFRC522WriteByteData(t *testing.T) { // arrange d, a := initTestMFRC522DriverWithStubbedAdaptor() // act err := d.connection.WriteByteData(0x00, 0x00) // assert require.NoError(t, err) assert.Equal(t, []byte{0x00, 0x00}, a.spi.Written()) } ================================================ FILE: drivers/spi/spi_config.go ================================================ package spi type spiConfig struct { bus int chip int mode int bits int speed int64 } // NewConfig returns a new SPI Config. func NewConfig() Config { return &spiConfig{ bus: NotInitialized, chip: NotInitialized, mode: NotInitialized, bits: NotInitialized, speed: NotInitialized, } } // WithBusNumber sets which bus to use as a optional param. func WithBusNumber(busNum int) func(Config) { return func(s Config) { s.SetBusNumber(busNum) } } // WithChipNumber sets which chip to use as a optional param. func WithChipNumber(chipNum int) func(Config) { return func(s Config) { s.SetChipNumber(chipNum) } } // WithMode sets which mode to use as a optional param. func WithMode(mode int) func(Config) { return func(s Config) { s.SetMode(mode) } } // WithBitCount sets how many bits to use as a optional param. func WithBitCount(bitCount int) func(Config) { return func(s Config) { s.SetBitCount(bitCount) } } // WithSpeed sets what speed to use as a optional param. func WithSpeed(speed int64) func(Config) { return func(s Config) { s.SetSpeed(speed) } } // SetBusNumber sets preferred bus to use. func (s *spiConfig) SetBusNumber(bus int) { s.bus = bus } // GetBusNumberOrDefault returns which bus to use, either the one set using WithBus(), // or the default value which is passed in as the one param. func (s *spiConfig) GetBusNumberOrDefault(d int) int { if s.bus == NotInitialized { return d } return s.bus } // SetChipNumber sets preferred chip to use. func (s *spiConfig) SetChipNumber(chip int) { s.chip = chip } // GetChipNumberOrDefault returns which chip to use, either the one set using WithChip(), // or the default value which is passed in as the one param. func (s *spiConfig) GetChipNumberOrDefault(d int) int { if s.chip == NotInitialized { return d } return s.chip } // SetMode sets SPI mode to use. func (s *spiConfig) SetMode(mode int) { s.mode = mode } // GetModeOrDefault returns which mode to use, either the one set using WithChip(), // or the default value which is passed in as the one param. func (s *spiConfig) GetModeOrDefault(d int) int { if s.mode == NotInitialized { return d } return s.mode } // SetBitCount sets how many SPI bits to use. func (s *spiConfig) SetBitCount(bits int) { s.bits = bits } // GetBitCountOrDefault returns how many to use, either the one set using WithBits(), // or the default value which is passed in as the one param. func (s *spiConfig) GetBitCountOrDefault(d int) int { if s.bits == NotInitialized { return d } return s.bits } // SetSpeed sets which SPI speed to use. func (s *spiConfig) SetSpeed(speed int64) { s.speed = speed } // GetSpeedOrDefault returns what speed to use, either the one set using WithSpeed(), // or the default value which is passed in as the one param. func (s *spiConfig) GetSpeedOrDefault(d int64) int64 { if s.speed == NotInitialized { return d } return s.speed } ================================================ FILE: drivers/spi/spi_connection.go ================================================ package spi import ( "fmt" "sync" "gobot.io/x/gobot/v2" ) const ( spiDebugByte = false spiDebugBlock = false ) // spiConnection is the common implementation of the SPI bus interface. type spiConnection struct { spiSystem gobot.SpiSystemDevicer mutex sync.Mutex } // NewConnection uses the given SPI system device and provides it as gobot.SpiOperations // and Implements gobot.BusOperations. func NewConnection(spiSystem gobot.SpiSystemDevicer) *spiConnection { return &spiConnection{spiSystem: spiSystem} } // Close connection to underlying SPI device. func (c *spiConnection) Close() error { c.mutex.Lock() defer c.mutex.Unlock() return c.spiSystem.Close() } // ReadCommandData uses the SPI device TX to send/receive data. Implements gobot.SpiOperations // On write command, the first byte normally contains the address and mode. // On read data, the return value is most likely one byte behind the command. // The length of command and data needs to be the same (except data is nil). func (c *spiConnection) ReadCommandData(command []byte, data []byte) error { c.mutex.Lock() defer c.mutex.Unlock() return c.txRxAndCheckReadLength(command, data) } // ReadByteData reads a byte from the given register of SPI device. Implements gobot.BusOperations. func (c *spiConnection) ReadByteData(reg uint8) (uint8, error) { c.mutex.Lock() defer c.mutex.Unlock() buf := []byte{0x0} if err := c.readAlignedBlockData(reg, buf); err != nil { return 0, err } if spiDebugByte { fmt.Printf("ReadByteData: register 0x%02X/0x%02X : 0x%02X %dd\n", reg, reg&0x7F>>1, buf[0], buf[0]) } return buf[0], nil } // ReadBlockData fills the given buffer with reads starting from the given register of SPI device. // Implements gobot.BusOperations. func (c *spiConnection) ReadBlockData(reg uint8, data []byte) error { c.mutex.Lock() defer c.mutex.Unlock() if err := c.readAlignedBlockData(reg, data); err != nil { return err } if spiDebugBlock { fmt.Printf("ReadBlockData: register 0x%02X/0x%02X : %v\n", reg, reg&0x7F>>1, data) } return nil } // WriteByte writes the given byte value to the current register of SPI device. Implements gobot.BusOperations. func (c *spiConnection) WriteByte(val byte) error { c.mutex.Lock() defer c.mutex.Unlock() return c.writeBytes([]byte{val}) } // WriteByteData writes the given byte value to the given register of SPI device. Implements gobot.BusOperations. func (c *spiConnection) WriteByteData(reg byte, data byte) error { c.mutex.Lock() defer c.mutex.Unlock() return c.writeBytes([]byte{reg, data}) } // WriteBlockData writes the given data starting from the given register of SPI device. Implements gobot.BusOperations. func (c *spiConnection) WriteBlockData(reg byte, data []byte) error { c.mutex.Lock() defer c.mutex.Unlock() buf := make([]byte, len(data)+1) copy(buf[1:], data) buf[0] = reg return c.writeBytes(buf) } // WriteBytes writes the given data starting from the current register of bus device. Implements gobot.BusOperations. func (c *spiConnection) WriteBytes(data []byte) error { c.mutex.Lock() defer c.mutex.Unlock() return c.writeBytes(data) } func (c *spiConnection) readAlignedBlockData(reg uint8, data []byte) error { // length of TX needs to equal length of RX // the read value is one cycle behind the write, so for n bytes to read, we need n+1 bytes (to read and write) buflen := len(data) + 1 writeBuf := make([]byte, buflen) readBuf := make([]byte, buflen) writeBuf[0] = reg if err := c.txRxAndCheckReadLength(writeBuf, readBuf); err != nil { return err } copy(data, readBuf[1:]) return nil } func (c *spiConnection) writeBytes(data []byte) error { return c.txRxAndCheckReadLength(data, nil) } func (c *spiConnection) txRxAndCheckReadLength(tx []byte, rx []byte) error { dataLen := len(rx) if err := c.spiSystem.TxRx(tx, rx); err != nil { return err } if len(rx) != dataLen { return fmt.Errorf("read length (%d) differ to expected (%d)", len(rx), dataLen) } return nil } ================================================ FILE: drivers/spi/spi_connection_test.go ================================================ package spi import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/system" ) var _ gobot.SpiOperations = (*spiConnection)(nil) func initTestConnectionWithMockedSystem() (Connection, *system.MockSpiAccess) { a := system.NewAccesser() sysdev := a.UseMockSpi() const ( busNum = 15 chipNum = 14 mode = 13 bits = 12 maxSpeed = int64(11) ) d, err := a.NewSpiDevice(busNum, chipNum, mode, bits, maxSpeed) if err != nil { panic(err) } c := NewConnection(d) return c, sysdev } func TestReadCommandData(t *testing.T) { // arrange command := []byte{0x11, 0x12} want := []byte{0x31, 0x32} c, sysdev := initTestConnectionWithMockedSystem() sysdev.SetSimRead(want) // act got := []byte{0x01, 0x02} err := c.ReadCommandData(command, got) // assert require.NoError(t, err) assert.Equal(t, command, sysdev.Written()) assert.Equal(t, want, got) } func TestReadByteData(t *testing.T) { // arrange const ( reg = 0x15 want = uint8(0x41) ) c, sysdev := initTestConnectionWithMockedSystem() sysdev.SetSimRead([]byte{0x00, want}) // the answer is one cycle behind // act got, err := c.ReadByteData(reg) // assert require.NoError(t, err) assert.Equal(t, []byte{reg, 0x00}, sysdev.Written()) // for read register we need n+1 bytes assert.Equal(t, want, got) } func TestReadBlockData(t *testing.T) { // arrange const ( reg = 0x16 ) want := []byte{42, 24, 56, 65} c, sysdev := initTestConnectionWithMockedSystem() sysdev.SetSimRead(append([]byte{0x00}, want...)) // the answer is one cycle behind // act got := make([]byte, 4) err := c.ReadBlockData(reg, got) // assert require.NoError(t, err) assert.Equal(t, []byte{reg, 0x00, 0x00, 0x00, 0x00}, sysdev.Written()) // for read registers we need n+1 bytes assert.Equal(t, want, got) } func TestWriteByte(t *testing.T) { // arrange const want = 0x02 c, sysdev := initTestConnectionWithMockedSystem() // act err := c.WriteByte(want) // assert require.NoError(t, err) assert.Equal(t, []byte{want}, sysdev.Written()) } func TestWriteByteData(t *testing.T) { // arrange const ( reg = 0x22 val = 0x33 ) c, sysdev := initTestConnectionWithMockedSystem() // act err := c.WriteByteData(reg, val) // assert require.NoError(t, err) assert.Equal(t, []byte{reg, val}, sysdev.Written()) } func TestWriteBlockData(t *testing.T) { // arrange const reg = 0x33 data := []byte{0x22, 0x11} c, sysdev := initTestConnectionWithMockedSystem() // act err := c.WriteBlockData(reg, data) // assert require.NoError(t, err) assert.Equal(t, append([]byte{reg}, data...), sysdev.Written()) } func TestWriteBytes(t *testing.T) { // arrange want := []byte{0x03} c, sysdev := initTestConnectionWithMockedSystem() // act err := c.WriteBytes(want) // assert require.NoError(t, err) assert.Equal(t, want, sysdev.Written()) } ================================================ FILE: drivers/spi/spi_driver.go ================================================ package spi import ( "fmt" "log" "sync" "gobot.io/x/gobot/v2" ) const ( // NotInitialized is the initial value for a bus/chip NotInitialized = -1 ) // Connector lets adaptors provide the interface for Drivers // to get access to the SPI buses on platforms that support SPI. type Connector interface { // GetSpiConnection returns a connection to a SPI device at the specified bus and chip. // Bus numbering starts at index 0, the range of valid buses is // platform specific. Same with chip numbering. GetSpiConnection(busNum, chip, mode, bits int, maxSpeed int64) (device Connection, err error) // SpiDefaultBusNumber returns the default SPI bus index SpiDefaultBusNumber() int // SpiDefaultChipNumber returns the default SPI chip index SpiDefaultChipNumber() int // DefaultMode returns the default SPI mode (0/1/2/3) SpiDefaultMode() int // SpiDefaultBitCount returns the default SPI number of bits (8) SpiDefaultBitCount() int // SpiDefaultMaxSpeed returns the max SPI speed SpiDefaultMaxSpeed() int64 } // Connection is a connection to a SPI device with a specific bus/chip. // Provided by an Adaptor, usually just by calling the spi package's GetSpiConnection() function. type Connection gobot.SpiOperations // Config is the interface which describes how a Driver can specify // optional SPI params such as which SPI bus it wants to use. type Config interface { // SetBusNumber sets which bus to use SetBusNumber(bus int) // GetBusNumberOrDefault gets which bus to use GetBusNumberOrDefault(def int) int // SetChipNumber sets which chip to use SetChipNumber(chip int) // GetChipNumberOrDefault gets which chip to use GetChipNumberOrDefault(def int) int // SetMode sets which mode to use SetMode(mode int) // GetModeOrDefault gets which mode to use GetModeOrDefault(def int) int // SetUsedBits sets how many bits to use SetBitCount(count int) // GetBitCountOrDefault gets how many bits to use GetBitCountOrDefault(def int) int // SetSpeed sets which speed to use (in Hz) SetSpeed(speed int64) // GetSpeedOrDefault gets which speed to use (in Hz) GetSpeedOrDefault(def int64) int64 } // Driver implements the interface gobot.Driver for SPI devices. type Driver struct { Config gobot.Commander name string connector Connector connection Connection afterStart func() error beforeHalt func() error mutex sync.Mutex } // NewDriver creates a new generic and basic SPI gobot driver. func NewDriver(a Connector, name string, options ...func(Config)) *Driver { d := &Driver{ name: gobot.DefaultName(name), connector: a, afterStart: func() error { return nil }, beforeHalt: func() error { return nil }, Config: NewConfig(), Commander: gobot.NewCommander(), } for _, option := range options { option(d) } return d } // Name returns the name of the SPI device. func (d *Driver) Name() string { return d.name } // SetName sets the name of the SPI device. func (d *Driver) SetName(n string) { d.name = n } // Connection returns the gobot connection of the SPI device. func (d *Driver) Connection() gobot.Connection { if d.connector == nil { log.Printf("%s has no connector\n", d.name) return nil } if conn, ok := d.connector.(gobot.Connection); ok { return conn } log.Printf("%s has no gobot connection\n", d.name) return nil } // Start initializes the driver. func (d *Driver) Start() error { d.mutex.Lock() defer d.mutex.Unlock() if d.connector == nil { return fmt.Errorf("%s has no connector", d.name) } bus := d.GetBusNumberOrDefault(d.connector.SpiDefaultBusNumber()) chip := d.GetChipNumberOrDefault(d.connector.SpiDefaultChipNumber()) mode := d.GetModeOrDefault(d.connector.SpiDefaultMode()) bits := d.GetBitCountOrDefault(d.connector.SpiDefaultBitCount()) maxSpeed := d.GetSpeedOrDefault(d.connector.SpiDefaultMaxSpeed()) var err error d.connection, err = d.connector.GetSpiConnection(bus, chip, mode, bits, maxSpeed) if err != nil { return err } return d.afterStart() } // Halt stops the driver. func (d *Driver) Halt() error { d.mutex.Lock() defer d.mutex.Unlock() if err := d.beforeHalt(); err != nil { return err } d.connection = nil // currently there is nothing to do here for the driver, the connection is cached on adaptor side // and will be closed on adaptor Finalize() return nil } func (d *Driver) readCommandData(command []byte, data []byte) error { if d.connection == nil { return fmt.Errorf("spi driver not started for '%s'", d.name) } return d.connection.ReadCommandData(command, data) } //nolint:unused // ok for now func (d *Driver) readByteData(reg uint8) (uint8, error) { if d.connection == nil { return 0, fmt.Errorf("spi driver not started for '%s'", d.name) } return d.connection.ReadByteData(reg) } //nolint:unused // ok for now func (d *Driver) readBlockData(reg uint8, data []byte) error { if d.connection == nil { return fmt.Errorf("spi driver not started for '%s'", d.name) } return d.connection.ReadBlockData(reg, data) } func (d *Driver) writeByte(val byte) error { if d.connection == nil { return fmt.Errorf("spi driver not started for '%s'", d.name) } return d.connection.WriteByte(val) } //nolint:unused // ok for now func (d *Driver) writeByteData(reg byte, data byte) error { if d.connection == nil { return fmt.Errorf("spi driver not started for '%s'", d.name) } return d.connection.WriteByteData(reg, data) } func (d *Driver) writeBlockData(reg byte, data []byte) error { if d.connection == nil { return fmt.Errorf("spi driver not started for '%s'", d.name) } return d.connection.WriteBlockData(reg, data) } func (d *Driver) writeBytes(data []byte) error { if d.connection == nil { return fmt.Errorf("spi driver not started for '%s'", d.name) } return d.connection.WriteBytes(data) } ================================================ FILE: drivers/spi/spi_driver_test.go ================================================ package spi import ( "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) var _ gobot.Driver = (*Driver)(nil) func initTestDriverWithStubbedAdaptor() (*Driver, *spiTestAdaptor) { //nolint:unparam // keep for further tests a := newSpiTestAdaptor() d := NewDriver(a, "SPI_BASIC") if err := d.Start(); err != nil { panic(err) } return d, a } func TestNewDriver(t *testing.T) { var di interface{} = NewDriver(newSpiTestAdaptor(), "SPI_BASIC") d, ok := di.(*Driver) if !ok { require.Fail(t, "NewDriver() should have returned a *Driver") } assert.True(t, strings.HasPrefix(d.Name(), "SPI_BASIC")) } func TestStart(t *testing.T) { d := NewDriver(newSpiTestAdaptor(), "SPI_BASIC") require.NoError(t, d.Start()) } func TestHalt(t *testing.T) { // arrange d := NewDriver(newSpiTestAdaptor(), "SPI_BASIC") // act, assert require.NoError(t, d.Halt()) // must be idempotent require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestSetName(t *testing.T) { // arrange d, _ := initTestDriverWithStubbedAdaptor() // act d.SetName("TESTME") // assert assert.Equal(t, "TESTME", d.Name()) } func TestConnection(t *testing.T) { d, _ := initTestDriverWithStubbedAdaptor() assert.NotNil(t, d.Connection()) } ================================================ FILE: drivers/spi/ssd1306_driver.go ================================================ package spi import ( "fmt" "image" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" ) const ( // default values ssd1306Width = 128 ssd1306Height = 64 ssd1306DcPin = "16" // for raspberry pi ssd1306RstPin = "18" // for raspberry pi ssd1306ExternalVcc = false ssd1306SetStartLine = 0x40 // fundamental commands ssd1306SetContrast = 0x81 ssd1306DisplayOnResumeToRAM = 0xA4 ssd1306DisplayOnResume = 0xA5 ssd1306SetDisplayNormal = 0xA6 ssd1306SetDisplayInverse = 0xA7 ssd1306SetDisplayOff = 0xAE ssd1306SetDisplayOn = 0xAF // scrolling commands ssd1306RightHorizontalScroll = 0x26 ssd1306LeftHorizontalScroll = 0x27 ssd1306VerticalAndRightHorizontalScroll = 0x29 ssd1306VerticalAndLeftHorizontalScroll = 0x2A ssd1306DeactivateScroll = 0x2E ssd1306ActivateScroll = 0x2F ssd1306SetVerticalScrollArea = 0xA3 // addressing settings commands ssd1306SetMemoryAddressingMode = 0x20 ssd1306ColumnAddr = 0x21 ssd1306PageAddr = 0x22 // hardware configuration commands ssd1306SetSegmentRemap0 = 0xA0 ssd1306SetSegmentRemap127 = 0xA1 ssd1306SetMultiplexRatio = 0xA8 ssd1306ComScanInc = 0xC0 ssd1306ComScanDec = 0xC8 ssd1306SetDisplayOffset = 0xD3 ssd1306SetComPins = 0xDA // timing and driving scheme commands ssd1306SetDisplayClock = 0xD5 ssd1306SetPrechargePeriod = 0xD9 ssd1306SetVComDeselectLevel = 0xDB ssd1306NOOP = 0xE3 // charge pump command ssd1306ChargePumpSetting = 0x8D ) // DisplayBuffer represents the display buffer intermediate memory type DisplayBuffer struct { width, height, pageSize int buffer []byte } // NewDisplayBuffer creates a new DisplayBuffer func NewDisplayBuffer(width, height, pageSize int) *DisplayBuffer { d := &DisplayBuffer{ width: width, height: height, pageSize: pageSize, } d.buffer = make([]byte, d.Size()) return d } // Size returns the memory size of the display buffer func (d *DisplayBuffer) Size() int { return (d.width * d.height) / d.pageSize } // Clear the contents of the display buffer func (d *DisplayBuffer) Clear() { d.buffer = make([]byte, d.Size()) } // SetPixel sets the x, y pixel with c color func (d *DisplayBuffer) SetPixel(x, y, c int) { idx := x + (y/d.pageSize)*d.width bit := uint(y) % uint(d.pageSize) //nolint:gosec // TODO: fix later if c == 0 { d.buffer[idx] &= ^(1 << bit) } else { d.buffer[idx] |= (1 << bit) } } // Set sets the display buffer with the given buffer func (d *DisplayBuffer) Set(buf []byte) { d.buffer = buf } // SSD1306Driver is a Gobot Driver for a SSD1306 Display type SSD1306Driver struct { *Driver dcDriver *gpio.DirectPinDriver rstDriver *gpio.DirectPinDriver pageSize int DisplayWidth int DisplayHeight int DCPin string RSTPin string ExternalVcc bool buffer *DisplayBuffer } // NewSSD1306Driver creates a new SSD1306Driver. // // Params: // // conn Connector - the Adaptor to use with this Driver // // Optional params: // // spi.WithBusNumber(int): bus to use with this driver // spi.WithChipNumber(int): chip to use with this driver // spi.WithMode(int): mode to use with this driver // spi.WithBitCount(int): number of bits to use with this driver // spi.WithSpeed(int64): speed in Hz to use with this driver // spi.WithDisplayWidth(int): width of display (defaults to 128) // spi.WithDisplayHeight(int): height of display (defaults to 64) // spi.WithDCPin(string): gpio pin number connected to dc pin on display (defaults to "16") // spi.WithRstPin(string): gpio pin number connected to rst pin on display (defaults to "18") // spi.WithExternalVCC(bool): set to true if using external vcc (defaults to false) func NewSSD1306Driver(a gobot.Adaptor, options ...func(Config)) *SSD1306Driver { // cast adaptor to spi connector since we also need the adaptor for gpio b, ok := a.(Connector) if !ok { panic("unable to get gobot connector for ssd1306") } d := &SSD1306Driver{ Driver: NewDriver(b, "SSD1306"), DisplayWidth: ssd1306Width, DisplayHeight: ssd1306Height, DCPin: ssd1306DcPin, RSTPin: ssd1306RstPin, ExternalVcc: ssd1306ExternalVcc, } d.afterStart = d.initialize d.beforeHalt = d.shutdown for _, option := range options { option(d) } d.dcDriver = gpio.NewDirectPinDriver(a, d.DCPin) d.rstDriver = gpio.NewDirectPinDriver(a, d.RSTPin) d.pageSize = d.DisplayHeight / 8 d.buffer = NewDisplayBuffer(d.DisplayWidth, d.DisplayHeight, d.pageSize) d.AddCommand("Display", func(_ map[string]interface{}) interface{} { err := d.Display() return map[string]interface{}{"err": err} }) d.AddCommand("On", func(_ map[string]interface{}) interface{} { err := d.On() return map[string]interface{}{"err": err} }) d.AddCommand("Off", func(_ map[string]interface{}) interface{} { err := d.Off() return map[string]interface{}{"err": err} }) d.AddCommand("Clear", func(_ map[string]interface{}) interface{} { err := d.Clear() return map[string]interface{}{"err": err} }) //nolint:forcetypeassert // ok here d.AddCommand("SetContrast", func(params map[string]interface{}) interface{} { contrast := params["contrast"].(byte) err := d.SetContrast(contrast) return map[string]interface{}{"err": err} }) //nolint:forcetypeassert // ok here d.AddCommand("Set", func(params map[string]interface{}) interface{} { x := params["x"].(int) y := params["y"].(int) c := params["c"].(int) d.Set(x, y, c) return nil }) return d } // WithDisplayWidth option sets the SSD1306Driver DisplayWidth option. func WithDisplayWidth(val int) func(Config) { return func(c Config) { d, ok := c.(*SSD1306Driver) if ok { d.DisplayWidth = val } else { panic("unable to set display width for ssd1306") } } } // WithDisplayHeight option sets the SSD1306Driver DisplayHeight option. func WithDisplayHeight(val int) func(Config) { return func(c Config) { d, ok := c.(*SSD1306Driver) if ok { d.DisplayHeight = val } else { panic("unable to set display height for ssd1306") } } } // WithDCPin option sets the SSD1306Driver DC Pin option. func WithDCPin(val string) func(Config) { return func(c Config) { d, ok := c.(*SSD1306Driver) if ok { d.DCPin = val } else { panic("unable to set dc pin for ssd1306") } } } // WithRstPin option sets the SSD1306Driver RST pin option. func WithRstPin(val string) func(Config) { return func(c Config) { d, ok := c.(*SSD1306Driver) if ok { d.RSTPin = val } else { panic("unable to set rst pin for ssd1306") } } } // WithExternalVCC option sets the SSD1306Driver external vcc option. func WithExternalVCC(val bool) func(Config) { return func(c Config) { d, ok := c.(*SSD1306Driver) if ok { d.ExternalVcc = val } else { panic("unable to set rst pin for ssd1306") } } } // On turns on the display. func (d *SSD1306Driver) On() error { return d.command(ssd1306SetDisplayOn) } // Off turns off the display. func (d *SSD1306Driver) Off() error { return d.command(ssd1306SetDisplayOff) } // Clear clears the display buffer. func (d *SSD1306Driver) Clear() error { d.buffer.Clear() return nil } // Set sets a pixel in the display buffer. func (d *SSD1306Driver) Set(x, y, c int) { d.buffer.SetPixel(x, y, c) } // Reset re-initializes the device to a clean state. func (d *SSD1306Driver) Reset() error { if err := d.rstDriver.DigitalWrite(1); err != nil { return err } time.Sleep(10 * time.Millisecond) if err := d.rstDriver.DigitalWrite(0); err != nil { return err } time.Sleep(10 * time.Millisecond) if err := d.rstDriver.DigitalWrite(1); err != nil { return err } return nil } // SetBufferAndDisplay sets the display buffer with the given buffer and displays the image. func (d *SSD1306Driver) SetBufferAndDisplay(buf []byte) error { d.buffer.Set(buf) return d.Display() } // SetContrast sets the display contrast (0-255). func (d *SSD1306Driver) SetContrast(contrast byte) error { if err := d.command(ssd1306SetContrast); err != nil { return err } return d.command(contrast) } // Display sends the memory buffer to the display. func (d *SSD1306Driver) Display() error { if err := d.command(ssd1306ColumnAddr); err != nil { return err } if err := d.command(0); err != nil { return err } //nolint:gosec // TODO: fix later if err := d.command(uint8(d.DisplayWidth) - 1); err != nil { return err } if err := d.command(ssd1306PageAddr); err != nil { return err } if err := d.command(0); err != nil { return err } //nolint:gosec // TODO: fix later if err := d.command(uint8(d.pageSize) - 1); err != nil { return err } if err := d.dcDriver.DigitalWrite(1); err != nil { return err } return d.writeBlockData(0x40, d.buffer.buffer) } // ShowImage takes a standard Go image and shows it on the display in monochrome. func (d *SSD1306Driver) ShowImage(img image.Image) error { if img.Bounds().Dx() != d.DisplayWidth || img.Bounds().Dy() != d.DisplayHeight { return fmt.Errorf("image must match the display width and height") } if err := d.Clear(); err != nil { return err } for y, w, h := 0, img.Bounds().Dx(), img.Bounds().Dy(); y < h; y++ { for x := 0; x < w; x++ { c := img.At(x, y) if r, g, b, _ := c.RGBA(); r > 0 || g > 0 || b > 0 { d.Set(x, y, 1) } } } return d.Display() } // command sends a unique command func (d *SSD1306Driver) command(b byte) error { if err := d.dcDriver.DigitalWrite(0); err != nil { return err } return d.writeByte(b) } // initialize configures the ssd1306 based on the options passed in when the driver was created func (d *SSD1306Driver) initialize() error { if err := d.command(ssd1306SetDisplayOff); err != nil { return err } if err := d.command(ssd1306SetDisplayClock); err != nil { return err } if d.DisplayHeight == 16 { if err := d.command(0x60); err != nil { return err } } else { if err := d.command(0x80); err != nil { return err } } if err := d.command(ssd1306SetMultiplexRatio); err != nil { return err } //nolint:gosec // TODO: fix later if err := d.command(uint8(d.DisplayHeight) - 1); err != nil { return err } if err := d.command(ssd1306SetDisplayOffset); err != nil { return err } if err := d.command(0x0); err != nil { return err } if err := d.command(ssd1306SetStartLine); err != nil { return err } if err := d.command(0x0); err != nil { return err } if err := d.command(ssd1306ChargePumpSetting); err != nil { return err } if d.ExternalVcc { if err := d.command(0x10); err != nil { return err } } else { if err := d.command(0x14); err != nil { return err } } if err := d.command(ssd1306SetMemoryAddressingMode); err != nil { return err } if err := d.command(0x00); err != nil { return err } if err := d.command(ssd1306SetSegmentRemap0); err != nil { return err } if err := d.command(0x01); err != nil { return err } if err := d.command(ssd1306ComScanInc); err != nil { return err } if err := d.command(ssd1306SetComPins); err != nil { return err } if d.DisplayHeight == 64 { if err := d.command(0x12); err != nil { return err } } else { if err := d.command(0x02); err != nil { return err } } if err := d.command(ssd1306SetContrast); err != nil { return err } if d.DisplayHeight == 64 { if d.ExternalVcc { if err := d.command(0x9F); err != nil { return err } } else { if err := d.command(0xCF); err != nil { return err } } } else { if err := d.command(0x8F); err != nil { return err } } if err := d.command(ssd1306SetPrechargePeriod); err != nil { return err } if d.ExternalVcc { if err := d.command(0x22); err != nil { return err } } else { if err := d.command(0xF1); err != nil { return err } } if err := d.command(ssd1306SetVComDeselectLevel); err != nil { return err } if err := d.command(0x40); err != nil { return err } if err := d.command(ssd1306DisplayOnResumeToRAM); err != nil { return err } if err := d.command(ssd1306SetDisplayNormal); err != nil { return err } if err := d.command(ssd1306DeactivateScroll); err != nil { return err } return d.command(ssd1306SetDisplayOn) } func (d *SSD1306Driver) shutdown() error { if d.connection == nil { // not started yet return nil } if err := d.Reset(); err != nil { return err } return d.Off() } ================================================ FILE: drivers/spi/ssd1306_driver_test.go ================================================ package spi import ( "image" "sync" "testing" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) // this ensures that the implementation is based on spi.Driver, which implements the gobot.Driver // and tests all implementations, so no further tests needed here for gobot.Driver interface var _ gobot.Driver = (*SSD1306Driver)(nil) func initTestSSDDriver() *SSD1306Driver { return NewSSD1306Driver(newGpioTestAdaptor()) } func TestDriverSSDStart(t *testing.T) { d := initTestSSDDriver() require.NoError(t, d.Start()) } func TestDriverSSDHalt(t *testing.T) { // arrange d := initTestSSDDriver() // act, assert require.NoError(t, d.Halt()) // must be idempotent require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestDriverSSDDisplay(t *testing.T) { d := initTestSSDDriver() _ = d.Start() require.NoError(t, d.Display()) } func TestSSD1306DriverShowImage(t *testing.T) { d := initTestSSDDriver() _ = d.Start() img := image.NewRGBA(image.Rect(0, 0, 640, 480)) require.ErrorContains(t, d.ShowImage(img), "image must match the display width and height") img = image.NewRGBA(image.Rect(0, 0, 128, 64)) require.NoError(t, d.ShowImage(img)) } type gpioTestAdaptor struct { Connector name string port string mtx sync.Mutex digitalWriteFunc func() error servoWriteFunc func() error pwmWriteFunc func() error analogReadFunc func() (val int, err error) digitalReadFunc func() (val int, err error) } func (t *gpioTestAdaptor) ServoWrite(string, byte) error { t.mtx.Lock() defer t.mtx.Unlock() return t.servoWriteFunc() } func (t *gpioTestAdaptor) PwmWrite(string, byte) error { t.mtx.Lock() defer t.mtx.Unlock() return t.pwmWriteFunc() } func (t *gpioTestAdaptor) AnalogRead(string) (int, error) { t.mtx.Lock() defer t.mtx.Unlock() return t.analogReadFunc() } func (t *gpioTestAdaptor) DigitalRead(string) (int, error) { t.mtx.Lock() defer t.mtx.Unlock() return t.digitalReadFunc() } func (t *gpioTestAdaptor) DigitalWrite(string, byte) error { t.mtx.Lock() defer t.mtx.Unlock() return t.digitalWriteFunc() } func (t *gpioTestAdaptor) Connect() error { return nil } func (t *gpioTestAdaptor) Finalize() error { return nil } func (t *gpioTestAdaptor) Name() string { return t.name } func (t *gpioTestAdaptor) SetName(n string) { t.name = n } func (t *gpioTestAdaptor) Port() string { return t.port } func newGpioTestAdaptor() *gpioTestAdaptor { a := newSpiTestAdaptor() return &gpioTestAdaptor{ port: "/dev/null", digitalWriteFunc: func() error { return nil }, servoWriteFunc: func() error { return nil }, pwmWriteFunc: func() error { return nil }, analogReadFunc: func() (int, error) { return 99, nil }, digitalReadFunc: func() (int, error) { return 1, nil }, Connector: a, } } ================================================ FILE: event.go ================================================ package gobot // Event represents when something asynchronous happens in a Driver // or Adaptor type Event struct { Name string Data interface{} } // NewEvent returns a new Event and its associated data. func NewEvent(name string, data interface{}) *Event { return &Event{Name: name, Data: data} } ================================================ FILE: eventer.go ================================================ package gobot import "sync" type eventChannel chan *Event type eventer struct { // map of valid Event names eventnames map[string]string // new events get put in to the event channel in eventChannel // map of out channels used by subscribers outs map[eventChannel]eventChannel // mutex to protect the eventChannel map eventsMutex sync.Mutex } const eventChanBufferSize = 10 // Eventer is the interface which describes how a Driver or Adaptor // handles events. type Eventer interface { // Events returns the map of valid Event names. Events() (eventnames map[string]string) // Event returns an Event string from map of valid Event names. // Mostly used to validate that an Event name is valid. Event(name string) string // AddEvent registers a new Event name. AddEvent(name string) // DeleteEvent removes a previously registered Event name. DeleteEvent(name string) // Publish new events to any subscriber Publish(name string, data interface{}) // Subscribe to events Subscribe() (events eventChannel) // Unsubscribe from an event channel Unsubscribe(events eventChannel) // Event handler On(name string, f func(s interface{})) error // Event handler, only executes one time Once(name string, f func(s interface{})) error } // NewEventer returns a new Eventer. func NewEventer() Eventer { evtr := &eventer{ eventnames: make(map[string]string), in: make(eventChannel, eventChanBufferSize), outs: make(map[eventChannel]eventChannel), } // goroutine to cascade "in" events to all "out" event channels go func() { for { evt := <-evtr.in evtr.eventsMutex.Lock() for _, out := range evtr.outs { out <- evt } evtr.eventsMutex.Unlock() } }() return evtr } // Events returns the map of valid Event names. func (e *eventer) Events() map[string]string { return e.eventnames } // Event returns an Event string from map of valid Event names. // Mostly used to validate that an Event name is valid. func (e *eventer) Event(name string) string { return e.eventnames[name] } // AddEvent registers a new Event name. func (e *eventer) AddEvent(name string) { e.eventnames[name] = name } // DeleteEvent removes a previously registered Event name. func (e *eventer) DeleteEvent(name string) { delete(e.eventnames, name) } // Publish new events to anyone that is subscribed func (e *eventer) Publish(name string, data interface{}) { evt := NewEvent(name, data) e.in <- evt } // Subscribe to any events from this eventer func (e *eventer) Subscribe() eventChannel { e.eventsMutex.Lock() defer e.eventsMutex.Unlock() out := make(eventChannel, eventChanBufferSize) e.outs[out] = out return out } // Unsubscribe from the event channel func (e *eventer) Unsubscribe(events eventChannel) { e.eventsMutex.Lock() defer e.eventsMutex.Unlock() delete(e.outs, events) } // On executes the event handler f when e is Published to. func (e *eventer) On(n string, f func(s interface{})) error { out := e.Subscribe() go func() { for { evt := <-out if evt.Name == n { f(evt.Data) } } }() return nil } // Once is similar to On except that it only executes f one time. func (e *eventer) Once(n string, f func(s interface{})) error { out := e.Subscribe() go func() { ProcessEvents: for evt := range out { if evt.Name == n { f(evt.Data) e.Unsubscribe(out) break ProcessEvents } } }() return nil } ================================================ FILE: eventer_test.go ================================================ package gobot import ( "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestEventerAddEvent(t *testing.T) { e := NewEventer() e.AddEvent("test") if _, ok := e.Events()["test"]; !ok { require.Fail(t, "Could not add event to list of Event names") } assert.Equal(t, "test", e.Event("test")) assert.Empty(t, e.Event("unknown")) } func TestEventerDeleteEvent(t *testing.T) { e := NewEventer() e.AddEvent("test1") e.DeleteEvent("test1") if _, ok := e.Events()["test1"]; ok { require.Fail(t, "Could not add delete event from list of Event names") } } func TestEventerOn(t *testing.T) { e := NewEventer() sem := make(chan bool) _ = e.On("test", func(data interface{}) { sem <- true }) // wait some time to ensure the eventer go routine is working time.Sleep(10 * time.Millisecond) e.Publish("test", true) select { case <-sem: case <-time.After(10 * time.Millisecond): require.Fail(t, "On was not called") } } func TestEventerOnce(t *testing.T) { e := NewEventer() sem := make(chan bool) _ = e.Once("test", func(data interface{}) { sem <- true }) // wait some time to ensure the eventer go routine is working time.Sleep(10 * time.Millisecond) e.Publish("test", true) select { case <-sem: case <-time.After(10 * time.Millisecond): require.Fail(t, "Once was not called") } e.Publish("test", true) select { case <-sem: require.Fail(t, "Once was called twice") case <-time.After(10 * time.Millisecond): } } ================================================ FILE: examples/ardrone.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/parrot/ardrone" ) func main() { ardroneAdaptor := ardrone.NewAdaptor() drone := ardrone.NewDriver(ardroneAdaptor) work := func() { _ = drone.On(ardrone.Flying, func(data interface{}) { gobot.After(3*time.Second, func() { drone.Land() }) }) drone.TakeOff() } robot := gobot.NewRobot("drone", []gobot.Connection{ardroneAdaptor}, []gobot.Device{drone}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/ardrone_face_tracking.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "image" "math" "path" "runtime" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/opencv" "gobot.io/x/gobot/v2/platforms/parrot/ardrone" "gocv.io/x/gocv" ) func main() { runtime.GOMAXPROCS(runtime.NumCPU()) _, currentfile, _, _ := runtime.Caller(0) cascade := path.Join(path.Dir(currentfile), "haarcascade_frontalface_alt.xml") window := opencv.NewWindowDriver() camera := opencv.NewCameraDriver("tcp://192.168.1.1:5555") ardroneAdaptor := ardrone.NewAdaptor() drone := ardrone.NewDriver(ardroneAdaptor) work := func() { detect := false drone.TakeOff() var img gocv.Mat camera.On(opencv.Frame, func(data interface{}) { img = data.(gocv.Mat) if !detect { window.IMShow(img) window.WaitKey(1) } }) _ = drone.On(ardrone.Flying, func(data interface{}) { gobot.After(1*time.Second, func() { drone.Up(0.2) }) gobot.After(2*time.Second, func() { drone.Hover() }) gobot.After(5*time.Second, func() { detect = true gobot.Every(300*time.Millisecond, func() { drone.Hover() i := img faces := opencv.DetectObjects(cascade, i) biggest := 0 var face image.Rectangle for _, f := range faces { if f.Width() > biggest { biggest = f.Width() face = f } } if face != nil { opencv.DrawRectangles(i, []img.Rectangle{face}, 0, 255, 0, 5) centerX := float64(img.Size()).X * 0.5 turn := -(float64(face.Min.X - centerX)) / centerX fmt.Println("turning:", turn) if turn < 0 { drone.Clockwise(math.Abs(turn * 0.4)) } else { drone.CounterClockwise(math.Abs(turn * 0.4)) } } window.IMShow(i) window.WaitKey(1) }) gobot.After(20*time.Second, func() { drone.Land() }) }) }) } robot := gobot.NewRobot("face", []gobot.Connection{ardroneAdaptor}, []gobot.Device{window, camera, drone}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/ardrone_ps3.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "sync/atomic" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/joystick" "gobot.io/x/gobot/v2/platforms/parrot/ardrone" ) type pair struct { x float64 y float64 } var leftX, leftY, rightX, rightY atomic.Value const offset = 32767.0 func main() { joystickAdaptor := joystick.NewAdaptor("0") stick := joystick.NewDriver(joystickAdaptor, "dualshock3") ardroneAdaptor := ardrone.NewAdaptor() drone := ardrone.NewDriver(ardroneAdaptor) leftX.Store(float64(0.0)) leftY.Store(float64(0.0)) rightX.Store(float64(0.0)) rightY.Store(float64(0.0)) work := func() { _ = stick.On(joystick.SquarePress, func(data interface{}) { drone.TakeOff() }) _ = stick.On(joystick.TrianglePress, func(data interface{}) { drone.Hover() }) _ = stick.On(joystick.XPress, func(data interface{}) { drone.Land() }) _ = stick.On(joystick.LeftX, func(data interface{}) { val := float64(data.(int)) leftX.Store(val) }) _ = stick.On(joystick.LeftY, func(data interface{}) { val := float64(data.(int)) leftY.Store(val) }) _ = stick.On(joystick.RightX, func(data interface{}) { val := float64(data.(int)) rightX.Store(val) }) _ = stick.On(joystick.RightY, func(data interface{}) { val := float64(data.(int)) rightY.Store(val) }) gobot.Every(10*time.Millisecond, func() { leftStick := getLeftStick() switch { case leftStick.y < -10: drone.Forward(ardrone.ValidatePitch(leftStick.y, offset)) case leftStick.y > 10: drone.Backward(ardrone.ValidatePitch(leftStick.y, offset)) default: drone.Forward(0) } switch { case leftStick.x > 10: drone.Right(ardrone.ValidatePitch(leftStick.x, offset)) case leftStick.x < -10: drone.Left(ardrone.ValidatePitch(leftStick.x, offset)) default: drone.Right(0) } }) gobot.Every(10*time.Millisecond, func() { rightStick := getRightStick() switch { case rightStick.y < -10: drone.Up(ardrone.ValidatePitch(rightStick.y, offset)) case rightStick.y > 10: drone.Down(ardrone.ValidatePitch(rightStick.y, offset)) default: drone.Up(0) } switch { case rightStick.x > 20: drone.Clockwise(ardrone.ValidatePitch(rightStick.x, offset)) case rightStick.x < -20: drone.CounterClockwise(ardrone.ValidatePitch(rightStick.x, offset)) default: drone.Clockwise(0) } }) } robot := gobot.NewRobot("ardrone", []gobot.Connection{joystickAdaptor, ardroneAdaptor}, []gobot.Device{stick, drone}, work, ) if err := robot.Start(); err != nil { panic(err) } } func getLeftStick() pair { s := pair{x: 0, y: 0} s.x = leftX.Load().(float64) s.y = leftY.Load().(float64) return s } func getRightStick() pair { s := pair{x: 0, y: 0} s.x = rightX.Load().(float64) s.y = rightY.Load().(float64) return s } ================================================ FILE: examples/audio.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/audio" ) func main() { e := audio.NewAdaptor() laser := audio.NewDriver(e, "./examples/laser.mp3") work := func() { gobot.Every(2*time.Second, func() { laser.Play() }) } robot := gobot.NewRobot("soundBot", []gobot.Connection{e}, []gobot.Device{laser}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/batty.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/api" ) func main() { gbot := gobot.NewManager() api.NewAPI(gbot).Start() gbot.AddCommand("echo", func(params map[string]interface{}) interface{} { return params["a"] }) loopback := NewLoopbackAdaptor("/dev/null") ping := NewPingDriver(loopback, "1") work := func() { gobot.Every(5*time.Second, func() { fmt.Println(ping.Ping()) }) } r := gobot.NewRobot("TestBot", []gobot.Connection{loopback}, []gobot.Device{ping}, work, ) r.AddCommand("hello", func(params map[string]interface{}) interface{} { return fmt.Sprintf("Hello, %v!", params["greeting"]) }) gbot.AddRobot(r) if err := gbot.Start(); err != nil { fmt.Println(err) } } var _ gobot.Adaptor = (*loopbackAdaptor)(nil) type loopbackAdaptor struct { name string port string } func (t *loopbackAdaptor) Finalize() error { return nil } func (t *loopbackAdaptor) Connect() error { return nil } func (t *loopbackAdaptor) Name() string { return t.name } func (t *loopbackAdaptor) SetName(n string) { t.name = n } func (t *loopbackAdaptor) Port() string { return t.port } func NewLoopbackAdaptor(port string) *loopbackAdaptor { return &loopbackAdaptor{ name: "Loopback", port: port, } } var _ gobot.Driver = (*pingDriver)(nil) type pingDriver struct { gobot.Eventer gobot.Commander name string pin string connection gobot.Connection } func (t *pingDriver) Start() error { return nil } func (t *pingDriver) Halt() error { return nil } func (t *pingDriver) Name() string { return t.name } func (t *pingDriver) SetName(n string) { t.name = n } func (t *pingDriver) Pin() string { return t.pin } func (t *pingDriver) Connection() gobot.Connection { return t.connection } func NewPingDriver(adaptor *loopbackAdaptor, pin string) *pingDriver { t := &pingDriver{ name: "Ping", connection: adaptor, pin: pin, Eventer: gobot.NewEventer(), Commander: gobot.NewCommander(), } t.AddEvent("ping") t.AddCommand("ping", func(params map[string]interface{}) interface{} { return t.Ping() }) return t } func (t *pingDriver) Ping() string { t.Publish(t.Event("ping"), "ping") return "pong" } ================================================ FILE: examples/beaglebone_basic_direct_pin.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/beagleboard/beaglebone" ) func main() { // Use Gobot to control BeagleBone's digital pins directly beagleboneAdaptor := beaglebone.NewAdaptor() gpioPin := gpio.NewDirectPinDriver(beagleboneAdaptor, "P9_12") // Initialize the internal representation of the pinout if err := beagleboneAdaptor.Connect(); err != nil { fmt.Println(err) } // Cast to byte because we are returning an int from a function // and not passing in an int literal. if err := gpioPin.DigitalWrite(byte(myStateFunction())); err != nil { fmt.Println(err) } } // myStateFunction determines what the GPIO state should be func myStateFunction() int { return 1 } ================================================ FILE: examples/beaglebone_blink.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/beagleboard/beaglebone" ) func main() { beagleboneAdaptor := beaglebone.NewAdaptor() led := gpio.NewLedDriver(beagleboneAdaptor, "P9_12") work := func() { gobot.Every(1*time.Second, func() { if err := led.Toggle(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("blinkBot", []gobot.Connection{beagleboneAdaptor}, []gobot.Device{led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/beaglebone_blink_usr_led.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/beagleboard/beaglebone" ) func main() { beagleboneAdaptor := beaglebone.NewAdaptor() led := gpio.NewLedDriver(beagleboneAdaptor, "usr1") work := func() { gobot.Every(1*time.Second, func() { if err := led.Toggle(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("blinkBot", []gobot.Connection{beagleboneAdaptor}, []gobot.Device{led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/beaglebone_blinkm.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/beagleboard/beaglebone" ) func main() { beagleboneAdaptor := beaglebone.NewAdaptor() blinkm := i2c.NewBlinkMDriver(beagleboneAdaptor) work := func() { gobot.Every(1*time.Second, func() { r := byte(gobot.Rand(255)) g := byte(gobot.Rand(255)) b := byte(gobot.Rand(255)) if err := blinkm.Rgb(r, g, b); err != nil { fmt.Println(err) } color, err := blinkm.Color() if err != nil { fmt.Println(err) } fmt.Printf("color %v\n", color) }) } robot := gobot.NewRobot("blinkmBot", []gobot.Connection{beagleboneAdaptor}, []gobot.Device{blinkm}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/beaglebone_button.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/beagleboard/beaglebone" ) func main() { beagleboneAdaptor := beaglebone.NewAdaptor() button := gpio.NewButtonDriver(beagleboneAdaptor, "P8_09") work := func() { _ = button.On(gpio.ButtonPush, func(data interface{}) { fmt.Println("button pressed") }) _ = button.On(gpio.ButtonRelease, func(data interface{}) { fmt.Println("button released") }) } robot := gobot.NewRobot("buttonBot", []gobot.Connection{beagleboneAdaptor}, []gobot.Device{button}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/beaglebone_grove_accelerometer.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/beagleboard/beaglebone" ) func main() { board := beaglebone.NewAdaptor() accel := i2c.NewGroveAccelerometerDriver(board) work := func() { gobot.Every(500*time.Millisecond, func() { if x, y, z, err := accel.XYZ(); err == nil { fmt.Println(x, y, z) fmt.Println(accel.Acceleration(x, y, z)) } else { fmt.Println(err) } }) } robot := gobot.NewRobot("accelBot", []gobot.Connection{board}, []gobot.Device{accel}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/beaglebone_led_brightness.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/beagleboard/beaglebone" ) func main() { beagleboneAdaptor := beaglebone.NewAdaptor() led := gpio.NewLedDriver(beagleboneAdaptor, "P9_14") work := func() { brightness := uint8(0) fadeAmount := uint8(5) gobot.Every(100*time.Millisecond, func() { if err := led.Brightness(brightness); err != nil { fmt.Println(err) } brightness = brightness + fadeAmount if brightness == 0 || brightness == 255 { fadeAmount = -fadeAmount } }) } robot := gobot.NewRobot("pwmBot", []gobot.Connection{beagleboneAdaptor}, []gobot.Device{led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/beaglebone_led_brightness_with_analog_input.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/beagleboard/beaglebone" ) func main() { beagleboneAdaptor := beaglebone.NewAdaptor() sensor := aio.NewAnalogSensorDriver(beagleboneAdaptor, "P9_33", aio.WithSensorCyclicRead(500*time.Millisecond)) led := gpio.NewLedDriver(beagleboneAdaptor, "P9_14") work := func() { _ = sensor.On(sensor.Event("data"), func(data interface{}) { brightness := uint8( gobot.ToScale(gobot.FromScale(float64(data.(int)), 0, 1024), 0, 255), ) fmt.Println("sensor", data) fmt.Println("brightness", brightness) if err := led.Brightness(brightness); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("sensorBot", []gobot.Connection{beagleboneAdaptor}, []gobot.Device{sensor, led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/beaglepocket_direct_pin.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/adaptors" "gobot.io/x/gobot/v2/platforms/beagleboard/pocketbeagle" ) // Wiring // PWR Pocket: P1.14, P2.23 (+3.3V, VCC); P1.15, P1.16, P1.22, P2.15, P2.21 (GND) // GPIO Pocket: header pin P1.34 is input, pin P1.35 is normal output, pin P1.36 is inverted output // Button: the input pin is wired with a button to GND, an external pull up resistor is needed (e.g. 2kOhm to VCC) // LED's: the output pins are wired to the cathode of the LED, the anode is wired with a resistor (70-130Ohm for 20mA) // to VCC // Expected behavior: always one LED is on, the other in opposite state, if button is pressed the state changes // note: you can also use user LEDs, e.g. "usr0", "usr3" func main() { const ( inPinNum = "P1_34" outPinNum = "P1_35" outPinInvertedNum = "P1_36" ) board := pocketbeagle.NewAdaptor(adaptors.WithGpiosActiveLow(outPinInvertedNum)) inPin := gpio.NewDirectPinDriver(board, inPinNum) outPin := gpio.NewDirectPinDriver(board, outPinNum) outPinInverted := gpio.NewDirectPinDriver(board, outPinInvertedNum) work := func() { level := byte(1) gobot.Every(500*time.Millisecond, func() { read, err := inPin.DigitalRead() fmt.Printf("pin %s state is %d\n", inPinNum, read) if err != nil { fmt.Println(err) if level == 1 { level = 0 } else { level = 1 } } else { level = byte(read) } err = outPin.DigitalWrite(level) fmt.Printf("pin %s is now %d\n", outPinNum, level) if err != nil { fmt.Println(err) } err = outPinInverted.DigitalWrite(level) fmt.Printf("pin %s is now not %d\n", outPinInvertedNum, level) if err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("pinBot", []gobot.Connection{board}, []gobot.Device{inPin, outPin, outPinInverted}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/bebop.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/parrot/bebop" ) func main() { bebopAdaptor := bebop.NewAdaptor() drone := bebop.NewDriver(bebopAdaptor) work := func() { _ = drone.On(bebop.Flying, func(data interface{}) { gobot.After(10*time.Second, func() { if err := drone.Land(); err != nil { fmt.Println(err) } }) }) if err := drone.HullProtection(true); err != nil { fmt.Println(err) } drone.TakeOff() } robot := gobot.NewRobot("drone", []gobot.Connection{bebopAdaptor}, []gobot.Device{drone}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/bebop.sdp ================================================ c=IN IP4 192.168.42.1 m=video 55004 RTP/AVP 96 a=rtpmap:96 H264/90000 ================================================ FILE: examples/bebop_ps3.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "sync/atomic" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/joystick" "gobot.io/x/gobot/v2/platforms/parrot/bebop" ) type pair struct { x float64 y float64 } var leftX, leftY, rightX, rightY atomic.Value const offset = 32767.0 func main() { joystickAdaptor := joystick.NewAdaptor("0") stick := joystick.NewDriver(joystickAdaptor, "dualshock3") bebopAdaptor := bebop.NewAdaptor() drone := bebop.NewDriver(bebopAdaptor) work := func() { leftX.Store(float64(0.0)) leftY.Store(float64(0.0)) rightX.Store(float64(0.0)) rightY.Store(float64(0.0)) recording := false _ = stick.On(joystick.CirclePress, func(data interface{}) { if recording { if err := drone.StopRecording(); err != nil { fmt.Println(err) } } else { if err := drone.StartRecording(); err != nil { fmt.Println(err) } } recording = !recording }) _ = stick.On(joystick.SquarePress, func(data interface{}) { if err := drone.HullProtection(true); err != nil { fmt.Println(err) } drone.TakeOff() }) _ = stick.On(joystick.TrianglePress, func(data interface{}) { if err := drone.Stop(); err != nil { fmt.Println(err) } }) _ = stick.On(joystick.XPress, func(data interface{}) { if err := drone.Land(); err != nil { fmt.Println(err) } }) _ = stick.On(joystick.LeftX, func(data interface{}) { val := float64(data.(int)) leftX.Store(val) }) _ = stick.On(joystick.LeftY, func(data interface{}) { val := float64(data.(int)) leftY.Store(val) }) _ = stick.On(joystick.RightX, func(data interface{}) { val := float64(data.(int)) rightX.Store(val) }) _ = stick.On(joystick.RightY, func(data interface{}) { val := float64(data.(int)) rightY.Store(val) }) gobot.Every(10*time.Millisecond, func() { leftStick := getLeftStick() switch { case leftStick.y < -10: if err := drone.Forward(bebop.ValidatePitch(leftStick.y, offset)); err != nil { fmt.Println(err) } case leftStick.y > 10: if err := drone.Backward(bebop.ValidatePitch(leftStick.y, offset)); err != nil { fmt.Println(err) } default: if err := drone.Forward(0); err != nil { fmt.Println(err) } } switch { case leftStick.x > 10: if err := drone.Right(bebop.ValidatePitch(leftStick.x, offset)); err != nil { fmt.Println(err) } case leftStick.x < -10: if err := drone.Left(bebop.ValidatePitch(leftStick.x, offset)); err != nil { fmt.Println(err) } default: if err := drone.Right(0); err != nil { fmt.Println(err) } } }) gobot.Every(10*time.Millisecond, func() { rightStick := getRightStick() switch { case rightStick.y < -10: if err := drone.Up(bebop.ValidatePitch(rightStick.y, offset)); err != nil { fmt.Println(err) } case rightStick.y > 10: if err := drone.Down(bebop.ValidatePitch(rightStick.y, offset)); err != nil { fmt.Println(err) } default: if err := drone.Up(0); err != nil { fmt.Println(err) } } switch { case rightStick.x > 20: if err := drone.Clockwise(bebop.ValidatePitch(rightStick.x, offset)); err != nil { fmt.Println(err) } case rightStick.x < -20: if err := drone.CounterClockwise(bebop.ValidatePitch(rightStick.x, offset)); err != nil { fmt.Println(err) } default: if err := drone.Clockwise(0); err != nil { fmt.Println(err) } } }) } robot := gobot.NewRobot("bebop", []gobot.Connection{joystickAdaptor, bebopAdaptor}, []gobot.Device{stick, drone}, work, ) if err := robot.Start(); err != nil { panic(err) } } func getLeftStick() pair { s := pair{x: 0, y: 0} s.x = leftX.Load().(float64) s.y = leftY.Load().(float64) return s } func getRightStick() pair { s := pair{x: 0, y: 0} s.x = rightX.Load().(float64) s.y = rightY.Load().(float64) return s } ================================================ FILE: examples/bebop_ps3_video.go ================================================ //go:build example // +build example // // Do not build by default. /* This example will connect to the Parrot Bebop allowing you to control it using a PS3 controller. It also streams the drone video to a webpage via ffserver. This requires you to have both ffmpeg and ffserver installed on your computer. In order to run this example you will first need to start ffserver with: $ ffserver -f ff.conf then in a separate terminal run this program: $ go run bebop_ps3_video.go You can view the video feed by navigating to http://localhost:8090/bebop.mjpeg in a web browser. *NOTE* firefox works best for viewing the video feed. */ package main import ( "fmt" "io" "os/exec" "sync/atomic" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/joystick" "gobot.io/x/gobot/v2/platforms/parrot/bebop" ) type pair struct { x float64 y float64 } var leftX, leftY, rightX, rightY atomic.Value const offset = 32767.0 func ffmpeg() (io.WriteCloser, io.ReadCloser, error) { ffmpeg := exec.Command("ffmpeg", "-i", "pipe:0", "http://localhost:8090/bebop.ffm") stderr, err := ffmpeg.StderrPipe() if err != nil { return nil, stderr, err } stdin, err := ffmpeg.StdinPipe() if err != nil { return stdin, stderr, err } if err := ffmpeg.Start(); err != nil { return stdin, stderr, err } go func() { for { buf, err := io.ReadAll(stderr) if err != nil { fmt.Println(err) } if len(buf) > 0 { fmt.Println(string(buf)) } } }() return stdin, stderr, nil } func main() { joystickAdaptor := joystick.NewAdaptor("0") stick := joystick.NewDriver(joystickAdaptor, "dualshock3") bebopAdaptor := bebop.NewAdaptor() drone := bebop.NewDriver(bebopAdaptor) work := func() { if err := drone.VideoEnable(true); err != nil { fmt.Println(err) } video, _, _ := ffmpeg() go func() { for { if _, err := video.Write(<-drone.Video()); err != nil { fmt.Println(err) return } } }() leftX.Store(float64(0.0)) leftY.Store(float64(0.0)) rightX.Store(float64(0.0)) rightY.Store(float64(0.0)) recording := false _ = stick.On(joystick.CirclePress, func(data interface{}) { if recording { if err := drone.StopRecording(); err != nil { fmt.Println(err) } } else { if err := drone.StartRecording(); err != nil { fmt.Println(err) } } recording = !recording }) _ = stick.On(joystick.SquarePress, func(data interface{}) { if err := drone.HullProtection(true); err != nil { fmt.Println(err) } drone.TakeOff() }) _ = stick.On(joystick.TrianglePress, func(data interface{}) { if err := drone.Stop(); err != nil { fmt.Println(err) } }) _ = stick.On(joystick.XPress, func(data interface{}) { if err := drone.Land(); err != nil { fmt.Println(err) } }) _ = stick.On(joystick.LeftX, func(data interface{}) { val := float64(data.(int)) leftX.Store(val) }) _ = stick.On(joystick.LeftY, func(data interface{}) { val := float64(data.(int)) leftY.Store(val) }) _ = stick.On(joystick.RightX, func(data interface{}) { val := float64(data.(int)) rightX.Store(val) }) _ = stick.On(joystick.RightY, func(data interface{}) { val := float64(data.(int)) rightY.Store(val) }) gobot.Every(10*time.Millisecond, func() { leftStick := getLeftStick() switch { case leftStick.y < -10: if err := drone.Forward(bebop.ValidatePitch(leftStick.y, offset)); err != nil { fmt.Println(err) } case leftStick.y > 10: if err := drone.Backward(bebop.ValidatePitch(leftStick.y, offset)); err != nil { fmt.Println(err) } default: if err := drone.Forward(0); err != nil { fmt.Println(err) } } switch { case leftStick.x > 10: if err := drone.Right(bebop.ValidatePitch(leftStick.x, offset)); err != nil { fmt.Println(err) } case leftStick.x < -10: if err := drone.Left(bebop.ValidatePitch(leftStick.x, offset)); err != nil { fmt.Println(err) } default: if err := drone.Right(0); err != nil { fmt.Println(err) } } }) gobot.Every(10*time.Millisecond, func() { rightStick := getRightStick() switch { case rightStick.y < -10: if err := drone.Up(bebop.ValidatePitch(rightStick.y, offset)); err != nil { fmt.Println(err) } case rightStick.y > 10: if err := drone.Down(bebop.ValidatePitch(rightStick.y, offset)); err != nil { fmt.Println(err) } default: if err := drone.Up(0); err != nil { fmt.Println(err) } } switch { case rightStick.x > 20: if err := drone.Clockwise(bebop.ValidatePitch(rightStick.x, offset)); err != nil { fmt.Println(err) } case rightStick.x < -20: if err := drone.CounterClockwise(bebop.ValidatePitch(rightStick.x, offset)); err != nil { fmt.Println(err) } default: if err := drone.Clockwise(0); err != nil { fmt.Println(err) } } }) } robot := gobot.NewRobot("bebop", []gobot.Connection{joystickAdaptor, bebopAdaptor}, []gobot.Device{stick, drone}, work, ) if err := robot.Start(); err != nil { panic(err) } } func getLeftStick() pair { s := pair{x: 0, y: 0} s.x = leftX.Load().(float64) s.y = leftY.Load().(float64) return s } func getRightStick() pair { s := pair{x: 0, y: 0} s.x = rightX.Load().(float64) s.y = rightY.Load().(float64) return s } ================================================ FILE: examples/bebop_rtp_video.go ================================================ //go:build example // +build example // // Do not build by default. /* This example will connect to the Parrot Bebop and streams the drone video via the RTP protocol. In order to run this example you will first need to connect to the drone with: $ go run bebop_ps3_video.go then in a separate terminal run this program: $ mplayer examples/bebop.sdp You can view the video feed by navigating to http://localhost:8090/bebop.mjpeg in a web browser. *NOTE* firefox works best for viewing the video feed. */ package main import ( "fmt" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/parrot/bebop" ) func main() { bebopAdaptor := bebop.NewAdaptor() drone := bebop.NewDriver(bebopAdaptor) work := func() { if err := drone.VideoEnable(true); err != nil { fmt.Println(err) } } robot := gobot.NewRobot("drone", []gobot.Connection{bebopAdaptor}, []gobot.Device{drone}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/bleclient_battery.go ================================================ //go:build example // +build example // // Do not build by default. /* How to run Pass the Bluetooth address or name as the first param: go run examples/ble_battery.go BB-1234 NOTE: sudo is required to use BLE in Linux */ package main import ( "fmt" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble" "gobot.io/x/gobot/v2/platforms/bleclient" ) func main() { bleAdaptor := bleclient.NewAdaptor(os.Args[1], bleclient.WithScanTimeout(30*time.Second)) battery := ble.NewBatteryDriver(bleAdaptor) work := func() { gobot.Every(5*time.Second, func() { level, err := battery.GetBatteryLevel() if err != nil { fmt.Println(err) } fmt.Println("Battery level:", level) }) } robot := gobot.NewRobot("bleBot", []gobot.Connection{bleAdaptor}, []gobot.Device{battery}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/bleclient_bb8-collision.go ================================================ //go:build example // +build example // // Do not build by default. /* How to run Pass the Bluetooth address or name as the first param: go run examples/bb8-collision.go BB-1234 NOTE: sudo is required to use BLE in Linux */ package main import ( "fmt" "os" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble/sphero" "gobot.io/x/gobot/v2/platforms/bleclient" ) func main() { bleAdaptor := bleclient.NewAdaptor(os.Args[1]) bb := sphero.NewBB8Driver(bleAdaptor) work := func() { _ = bb.On("collision", func(data interface{}) { fmt.Printf("collision detected = %+v \n", data) bb.SetRGB(255, 0, 0) }) bb.SetRGB(0, 255, 0) bb.Roll(80, 0) } robot := gobot.NewRobot("bb8", []gobot.Connection{bleAdaptor}, []gobot.Device{bb}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/bleclient_bb8.go ================================================ //go:build example // +build example // // Do not build by default. /* How to run Pass the Bluetooth address or name as the first param: go run examples/bb8.go BB-1234 NOTE: sudo is required to use BLE in Linux */ //nolint:gosec // ok here package main import ( "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble/sphero" "gobot.io/x/gobot/v2/platforms/bleclient" ) func main() { bleAdaptor := bleclient.NewAdaptor(os.Args[1]) bb8 := sphero.NewBB8Driver(bleAdaptor) work := func() { gobot.Every(1*time.Second, func() { r := uint8(gobot.Rand(255)) g := uint8(gobot.Rand(255)) b := uint8(gobot.Rand(255)) bb8.SetRGB(r, g, b) }) } robot := gobot.NewRobot("bbBot", []gobot.Connection{bleAdaptor}, []gobot.Device{bb8}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/bleclient_device_info.go ================================================ //go:build example // +build example // // Do not build by default. /* How to run Pass the Bluetooth address or name as the first param: go run examples/ble_device_info.go BB-1234 NOTE: sudo is required to use BLE in Linux */ package main import ( "fmt" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble" "gobot.io/x/gobot/v2/platforms/bleclient" ) func main() { bleAdaptor := bleclient.NewAdaptor(os.Args[1], bleclient.WithScanTimeout(30*time.Second), bleclient.WithDebug()) info := ble.NewDeviceInformationDriver(bleAdaptor) work := func() { modelNo, err := info.GetModelNumber() if err != nil { fmt.Println(err) } fmt.Println("Model number:", modelNo) fwRev, err := info.GetFirmwareRevision() if err != nil { fmt.Println(err) } fmt.Println("Firmware rev:", fwRev) hwRev, err := info.GetHardwareRevision() if err != nil { fmt.Println(err) } fmt.Println("Hardware rev:", hwRev) manuName, err := info.GetManufacturerName() if err != nil { fmt.Println(err) } fmt.Println("Manufacturer name:", manuName) pid, err := info.GetPnPId() if err != nil { fmt.Println(err) } fmt.Println("PnPId:", pid) } robot := gobot.NewRobot("bleBot", []gobot.Connection{bleAdaptor}, []gobot.Device{info}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/bleclient_firmata_blink.go ================================================ //go:build example // +build example // // Do not build by default. /* How to run Pass the BLE address or BLE name as first param: go run examples/ble_firmata_blink.go FIRMATA NOTE: sudo is required to use BLE in Linux */ package main import ( "fmt" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/firmata" ) func main() { firmataAdaptor := firmata.NewBLEAdaptor(os.Args[1]) led := gpio.NewLedDriver(firmataAdaptor, "13") work := func() { gobot.Every(1*time.Second, func() { if err := led.Toggle(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("bot", []gobot.Connection{firmataAdaptor}, []gobot.Device{led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/bleclient_firmata_curie_imu.go ================================================ //go:build example // +build example // // Do not build by default. /* How to run Pass the BLE address or BLE name as first param: go run examples/ble_firmata_curie_imu.go FIRMATA NOTE: sudo is required to use BLE in Linux */ package main import ( "fmt" "log" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/firmata" "gobot.io/x/gobot/v2/platforms/intel-iot/curie" ) func main() { var bleAdaptor interface{} = firmata.NewBLEAdaptor(os.Args[1]) firmataAdaptor := bleAdaptor.(*firmata.Adaptor) led := gpio.NewLedDriver(firmataAdaptor, "13") imu := curie.NewIMUDriver(firmataAdaptor) work := func() { _ = imu.On("Accelerometer", func(data interface{}) { log.Println("Accelerometer", data) }) _ = imu.On("Gyroscope", func(data interface{}) { log.Println("Gyroscope", data) }) _ = imu.On("Temperature", func(data interface{}) { log.Println("Temperature", data) }) gobot.Every(1*time.Second, func() { if err := led.Toggle(); err != nil { fmt.Println(err) } }) gobot.Every(100*time.Millisecond, func() { if err := imu.ReadAccelerometer(); err != nil { fmt.Println(err) } if err := imu.ReadGyroscope(); err != nil { fmt.Println(err) } if err := imu.ReadTemperature(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("bot", []gobot.Connection{firmataAdaptor}, []gobot.Device{led, imu}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/bleclient_generic_access.go ================================================ //go:build example // +build example // // Do not build by default. /* How to run Pass the Bluetooth address or name as the first param: go run examples/ble_generic_access.go BB-1234 NOTE: sudo is required to use BLE in Linux */ package main import ( "fmt" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble" "gobot.io/x/gobot/v2/platforms/bleclient" ) func main() { bleAdaptor := bleclient.NewAdaptor(os.Args[1], bleclient.WithScanTimeout(30*time.Second), bleclient.WithDebug()) access := ble.NewGenericAccessDriver(bleAdaptor) work := func() { devName, err := access.GetDeviceName() if err != nil { fmt.Println(err) } fmt.Println("Device name:", devName) appearance, err := access.GetAppearance() if err != nil { fmt.Println(err) } fmt.Println("Appearance:", appearance) } robot := gobot.NewRobot("bleBot", []gobot.Connection{bleAdaptor}, []gobot.Device{access}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/bleclient_microbit_accelerometer.go ================================================ //go:build example // +build example // // Do not build by default. /* How to setup You must be using a BBC Microbit microcontroller that has been flashed with the firmware from @sandeepmistry More info: https://gobot.io/documentation/platforms/microbit/#how-to-install This example uses the Microbit's built-in accelerometer. You run the Go program on your computer and communicate wirelessly with the Microbit. How to run Pass the Bluetooth name or address as first param: go run examples/microbit_accelerometer.go "BBC micro:bit [yowza]" NOTE: sudo is required to use BLE in Linux */ package main import ( "fmt" "os" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble/microbit" "gobot.io/x/gobot/v2/platforms/bleclient" ) func main() { bleAdaptor := bleclient.NewAdaptor(os.Args[1]) ubit := microbit.NewAccelerometerDriver(bleAdaptor) work := func() { _ = ubit.On(microbit.AccelerometerEvent, func(data interface{}) { fmt.Println("Accelerometer", data) }) } robot := gobot.NewRobot("buttonBot", []gobot.Connection{bleAdaptor}, []gobot.Device{ubit}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/bleclient_microbit_blink.go ================================================ //go:build example // +build example // // Do not build by default. /* How to setup You must be using a BBC Microbit microcontroller that has been flashed with the firmware from @sandeepmistry More info: https://gobot.io/documentation/platforms/microbit/#how-to-install This example requires that you wire an external LED to pin number 0 on the Microbit, as this example is intended to demonstrate the Microbit IOPinDriver. You then run the Go program on your computer and communicate wirelessly with the Microbit. How to run Pass the Bluetooth name or address as first param: go run examples/microbit_blink.go "BBC micro:bit [yowza]" NOTE: sudo is required to use BLE in Linux */ package main import ( "fmt" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble/microbit" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/bleclient" ) func main() { bleAdaptor := bleclient.NewAdaptor(os.Args[1]) ubit := microbit.NewIOPinDriver(bleAdaptor) led := gpio.NewLedDriver(ubit, "0") work := func() { gobot.Every(1*time.Second, func() { if err := led.Toggle(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("bot", []gobot.Connection{bleAdaptor}, []gobot.Device{ubit, led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/bleclient_microbit_buttons.go ================================================ //go:build example // +build example // // Do not build by default. /* How to setup You must be using a BBC Microbit microcontroller that has been flashed with the firmware from @sandeepmistry More info: https://gobot.io/documentation/platforms/microbit/#how-to-install This example uses the Microbit's built-in buttons. You run the Go program on your computer and communicate wirelessly with the Microbit. How to run Pass the Bluetooth name or address as first param: go run examples/microbit_buttons_led.go "BBC micro:bit [yowza]" */ package main import ( "fmt" "os" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble/microbit" "gobot.io/x/gobot/v2/platforms/bleclient" ) func main() { bleAdaptor := bleclient.NewAdaptor(os.Args[1]) ubit := microbit.NewButtonDriver(bleAdaptor) work := func() { _ = ubit.On(microbit.ButtonAEvent, func(data interface{}) { fmt.Println("button A", data) }) _ = ubit.On(microbit.ButtonBEvent, func(data interface{}) { fmt.Println("button B", data) }) } robot := gobot.NewRobot("buttonBot", []gobot.Connection{bleAdaptor}, []gobot.Device{ubit}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/bleclient_microbit_buttons_leds.go ================================================ //go:build example // +build example // // Do not build by default. /* How to setup You must be using a BBC Microbit microcontroller that has been flashed with the firmware from @sandeepmistry More info: https://gobot.io/documentation/platforms/microbit/#how-to-install This example uses the Microbit's built-in buttons and built-in LED matrix. You run the Go program on your computer and communicate wirelessly with the Microbit. How to run Pass the Bluetooth name or address as first param: go run examples/microbit_buttons_led.go "BBC micro:bit [yowza]" NOTE: sudo is required to use BLE in Linux */ package main import ( "fmt" "os" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble/microbit" "gobot.io/x/gobot/v2/platforms/bleclient" ) func main() { bleAdaptor := bleclient.NewAdaptor(os.Args[1]) buttons := microbit.NewButtonDriver(bleAdaptor) leds := microbit.NewLEDDriver(bleAdaptor) work := func() { _ = buttons.On(microbit.ButtonAEvent, func(data interface{}) { if data.([]byte)[0] == 1 { if err := leds.UpLeftArrow(); err != nil { fmt.Println(err) } return } if err := leds.Blank(); err != nil { fmt.Println(err) } }) _ = buttons.On(microbit.ButtonBEvent, func(data interface{}) { if data.([]byte)[0] == 1 { if err := leds.UpRightArrow(); err != nil { fmt.Println(err) } return } if err := leds.Blank(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("buttonBot", []gobot.Connection{bleAdaptor}, []gobot.Device{buttons, leds}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/bleclient_microbit_io_button.go ================================================ //go:build example // +build example // // Do not build by default. /* How to setup You must be using a BBC Microbit microcontroller that has been flashed with the firmware from @sandeepmistry More info: https://gobot.io/documentation/platforms/microbit/#how-to-install This example requires that you wire an external button to pin number 0 on the Microbit, and also wire an external LED to pin number 1 on the Microbit. This example is intended to demonstrate using Gobot GPIO drivers with the Microbit. You run the Go program on your computer and communicate wirelessly with the Microbit. How to run Pass the Bluetooth name or address as first param: go run examples/microbit_io_button.go "BBC micro:bit [yowza]" NOTE: sudo is required to use BLE in Linux */ package main import ( "fmt" "os" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble/microbit" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/bleclient" ) func main() { bleAdaptor := bleclient.NewAdaptor(os.Args[1]) ubit := microbit.NewIOPinDriver(bleAdaptor) button := gpio.NewButtonDriver(ubit, "0") led := gpio.NewLedDriver(ubit, "1") work := func() { _ = button.On(gpio.ButtonPush, func(data interface{}) { if err := led.On(); err != nil { fmt.Println(err) } }) _ = button.On(gpio.ButtonRelease, func(data interface{}) { if err := led.Off(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("buttonBot", []gobot.Connection{bleAdaptor}, []gobot.Device{ubit, button, led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/bleclient_microbit_led.go ================================================ //go:build example // +build example // // Do not build by default. /* How to setup You must be using a BBC Microbit microcontroller that has been flashed with the firmware from @sandeepmistry More info: https://gobot.io/documentation/platforms/microbit/#how-to-install This example uses the Microbit's built-in LED matrix. You run the Go program on your computer and communicate wirelessly with the Microbit. How to run Pass the Bluetooth name or address as first param: go run examples/microbit_led.go "BBC micro:bit [yowza]" NOTE: sudo is required to use BLE in Linux */ package main import ( "fmt" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble/microbit" "gobot.io/x/gobot/v2/platforms/bleclient" ) func main() { bleAdaptor := bleclient.NewAdaptor(os.Args[1]) ubit := microbit.NewLEDDriver(bleAdaptor) work := func() { if err := ubit.Blank(); err != nil { fmt.Println(err) } gobot.After(1*time.Second, func() { if err := ubit.WriteText("Hello"); err != nil { fmt.Println(err) } }) gobot.After(7*time.Second, func() { if err := ubit.Smile(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("blinkBot", []gobot.Connection{bleAdaptor}, []gobot.Device{ubit}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/bleclient_microbit_magnetometer.go ================================================ //go:build example // +build example // // Do not build by default. /* How to setup You must be using a BBC Microbit microcontroller that has been flashed with the firmware from @sandeepmistry More info: https://gobot.io/documentation/platforms/microbit/#how-to-install This example uses the Microbit's built-in magnetometer. You run the Go program on your computer and communicate wirelessly with the Microbit. How to run Pass the Bluetooth name or address as first param: go run examples/microbit_magnetometer.go "BBC micro:bit [yowza]" NOTE: sudo is required to use BLE in Linux */ package main import ( "fmt" "os" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble/microbit" "gobot.io/x/gobot/v2/platforms/bleclient" ) func main() { bleAdaptor := bleclient.NewAdaptor(os.Args[1]) ubit := microbit.NewMagnetometerDriver(bleAdaptor) work := func() { _ = ubit.On(microbit.MagnetometerEvent, func(data interface{}) { fmt.Println("Magnetometer", data) }) } robot := gobot.NewRobot("magnetoBot", []gobot.Connection{bleAdaptor}, []gobot.Device{ubit}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/bleclient_microbit_temperature.go ================================================ //go:build example // +build example // // Do not build by default. /* How to setup You must be using a BBC Microbit microcontroller that has been flashed with the firmware from @sandeepmistry More info: https://gobot.io/documentation/platforms/microbit/#how-to-install This example uses the Microbit's built-in thermometer. You run the Go program on your computer and communicate wirelessly with the Microbit. How to run Pass the Bluetooth name or address as first param: go run examples/microbit_temperature.go "BBC micro:bit [yowza]" NOTE: sudo is required to use BLE in Linux */ package main import ( "fmt" "os" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble/microbit" "gobot.io/x/gobot/v2/platforms/bleclient" ) func main() { bleAdaptor := bleclient.NewAdaptor(os.Args[1]) ubit := microbit.NewTemperatureDriver(bleAdaptor) work := func() { _ = ubit.On(microbit.TemperatureEvent, func(data interface{}) { fmt.Println("Temperature", data) }) } robot := gobot.NewRobot("thermoBot", []gobot.Connection{bleAdaptor}, []gobot.Device{ubit}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/bleclient_minidrone.go ================================================ //go:build example // +build example // // Do not build by default. /* How to run Pass the Bluetooth name or address as first param: go run examples/minidrone.go "Mambo_1234" NOTE: sudo is required to use BLE in Linux */ package main import ( "fmt" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble/parrot" "gobot.io/x/gobot/v2/platforms/bleclient" ) func main() { bleAdaptor := bleclient.NewAdaptor(os.Args[1]) drone := parrot.NewMinidroneDriver(bleAdaptor) work := func() { if err := drone.TakeOff(); err != nil { fmt.Println(err) } gobot.After(5*time.Second, func() { if err := drone.Land(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("minidrone", []gobot.Connection{bleAdaptor}, []gobot.Device{drone}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/bleclient_minidrone_events.go ================================================ //go:build example // +build example // // Do not build by default. /* How to run Pass the Bluetooth name or address as first param: go run examples/minidrone_events.go "Mambo_1234" NOTE: sudo is required to use BLE in Linux */ package main import ( "fmt" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble/parrot" "gobot.io/x/gobot/v2/platforms/bleclient" ) func main() { bleAdaptor := bleclient.NewAdaptor(os.Args[1]) drone := parrot.NewMinidroneDriver(bleAdaptor) work := func() { _ = drone.On(parrot.BatteryEvent, func(data interface{}) { fmt.Printf("battery: %d\n", data) }) _ = drone.On(parrot.FlightStatusEvent, func(data interface{}) { fmt.Printf("flight status: %d\n", data) }) _ = drone.On(parrot.TakeoffEvent, func(data interface{}) { fmt.Println("taking off...") }) _ = drone.On(parrot.HoveringEvent, func(data interface{}) { fmt.Println("hovering!") gobot.After(5*time.Second, func() { if err := drone.Land(); err != nil { fmt.Println(err) } }) }) _ = drone.On(parrot.LandingEvent, func(data interface{}) { fmt.Println("landing...") }) _ = drone.On(parrot.LandedEvent, func(data interface{}) { fmt.Println("landed.") }) time.Sleep(1000 * time.Millisecond) if err := drone.TakeOff(); err != nil { fmt.Println(err) } } robot := gobot.NewRobot("minidrone", []gobot.Connection{bleAdaptor}, []gobot.Device{drone}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/bleclient_minidrone_mambo_ps3.go ================================================ //go:build example // +build example // // Do not build by default. /* How to setup You must be using a PS3 or compatible controller, along with one of the Parrot Mambo drones to run this example. You run the Go program on your computer and communicate wirelessly with the Mambo. How to run Pass the Bluetooth name or address as first param: go run examples/minidrone_mambo_ps3.go "Mambo_1234" NOTE: sudo is required to use BLE in Linux */ package main import ( "fmt" "os" "sync/atomic" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble/parrot" "gobot.io/x/gobot/v2/platforms/bleclient" "gobot.io/x/gobot/v2/platforms/joystick" ) type pair struct { x float64 y float64 } var leftX, leftY, rightX, rightY atomic.Value const offset = 32767.0 func main() { joystickAdaptor := joystick.NewAdaptor("0") stick := joystick.NewDriver(joystickAdaptor, "./platforms/joystick/configs/dualshock3.json", ) droneAdaptor := bleclient.NewAdaptor(os.Args[1]) drone := parrot.NewMinidroneDriver(droneAdaptor) work := func() { leftX.Store(float64(0.0)) leftY.Store(float64(0.0)) rightX.Store(float64(0.0)) rightY.Store(float64(0.0)) clawOpen := false _ = stick.On(joystick.CirclePress, func(data interface{}) { if clawOpen { if err := drone.ClawControl(0, parrot.ClawClosed); err != nil { fmt.Println(err) } clawOpen = false } else { if err := drone.ClawControl(0, parrot.ClawOpen); err != nil { fmt.Println(err) } clawOpen = true } }) _ = stick.On(joystick.R2Press, func(data interface{}) { if clawOpen { if err := drone.ClawControl(0, parrot.ClawClosed); err != nil { fmt.Println(err) } clawOpen = false } else { if err := drone.ClawControl(0, parrot.ClawOpen); err != nil { fmt.Println(err) } clawOpen = true } }) _ = stick.On(joystick.TrianglePress, func(data interface{}) { if err := drone.HullProtection(true); err != nil { fmt.Println(err) } if err := drone.TakeOff(); err != nil { fmt.Println(err) } }) _ = stick.On(joystick.XPress, func(data interface{}) { if err := drone.Land(); err != nil { fmt.Println(err) } }) _ = stick.On(joystick.LeftX, func(data interface{}) { val := float64(data.(int)) leftX.Store(val) }) _ = stick.On(joystick.LeftY, func(data interface{}) { val := float64(data.(int)) leftY.Store(val) }) _ = stick.On(joystick.RightX, func(data interface{}) { val := float64(data.(int)) rightX.Store(val) }) _ = stick.On(joystick.RightY, func(data interface{}) { val := float64(data.(int)) rightY.Store(val) }) gobot.Every(10*time.Millisecond, func() { rightStick := getRightStick() switch { case rightStick.y < -10: if err := drone.Forward(parrot.ValidatePitch(rightStick.y, offset)); err != nil { fmt.Println(err) } case rightStick.y > 10: if err := drone.Backward(parrot.ValidatePitch(rightStick.y, offset)); err != nil { fmt.Println(err) } default: if err := drone.Forward(0); err != nil { fmt.Println(err) } } switch { case rightStick.x > 10: if err := drone.Right(parrot.ValidatePitch(rightStick.x, offset)); err != nil { fmt.Println(err) } case rightStick.x < -10: if err := drone.Left(parrot.ValidatePitch(rightStick.x, offset)); err != nil { fmt.Println(err) } default: if err := drone.Right(0); err != nil { fmt.Println(err) } } }) gobot.Every(10*time.Millisecond, func() { leftStick := getLeftStick() switch { case leftStick.y < -10: if err := drone.Up(parrot.ValidatePitch(leftStick.y, offset)); err != nil { fmt.Println(err) } case leftStick.y > 10: if err := drone.Down(parrot.ValidatePitch(leftStick.y, offset)); err != nil { fmt.Println(err) } default: if err := drone.Up(0); err != nil { fmt.Println(err) } } switch { case leftStick.x > 20: if err := drone.Clockwise(parrot.ValidatePitch(leftStick.x, offset)); err != nil { fmt.Println(err) } case leftStick.x < -20: if err := drone.CounterClockwise(parrot.ValidatePitch(leftStick.x, offset)); err != nil { fmt.Println(err) } default: if err := drone.Clockwise(0); err != nil { fmt.Println(err) } } }) } robot := gobot.NewRobot("minidrone", []gobot.Connection{joystickAdaptor, droneAdaptor}, []gobot.Device{stick, drone}, work, ) if err := robot.Start(); err != nil { panic(err) } } func getLeftStick() pair { s := pair{x: 0, y: 0} s.x = leftX.Load().(float64) s.y = leftY.Load().(float64) return s } func getRightStick() pair { s := pair{x: 0, y: 0} s.x = rightX.Load().(float64) s.y = rightY.Load().(float64) return s } ================================================ FILE: examples/bleclient_minidrone_ps3.go ================================================ //go:build example // +build example // // Do not build by default. /* How to setup You must be using a PS3 or compatible controller, along with any of the Parrot Minidrone drones to run this example. You run the Go program on your computer and communicate wirelessly with the Parrot Minidrone. How to run Pass the Bluetooth name or address as first param: go run examples/minidrone_ps3.go "Travis_1234" NOTE: sudo is required to use BLE in Linux */ package main import ( "fmt" "os" "sync/atomic" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble/parrot" "gobot.io/x/gobot/v2/platforms/bleclient" "gobot.io/x/gobot/v2/platforms/joystick" ) type pair struct { x float64 y float64 } var leftX, leftY, rightX, rightY atomic.Value const offset = 32767.0 func main() { joystickAdaptor := joystick.NewAdaptor("0") stick := joystick.NewDriver(joystickAdaptor, "dualshock3") droneAdaptor := bleclient.NewAdaptor(os.Args[1]) drone := parrot.NewMinidroneDriver(droneAdaptor) work := func() { leftX.Store(float64(0.0)) leftY.Store(float64(0.0)) rightX.Store(float64(0.0)) rightY.Store(float64(0.0)) recording := false _ = stick.On(joystick.CirclePress, func(data interface{}) { if recording { if err := drone.StopRecording(); err != nil { fmt.Println(err) } } else { if err := drone.StartRecording(); err != nil { fmt.Println(err) } } recording = !recording }) _ = stick.On(joystick.SquarePress, func(data interface{}) { if err := drone.Stop(); err != nil { fmt.Println(err) } }) _ = stick.On(joystick.TrianglePress, func(data interface{}) { if err := drone.HullProtection(true); err != nil { fmt.Println(err) } if err := drone.TakeOff(); err != nil { fmt.Println(err) } }) _ = stick.On(joystick.XPress, func(data interface{}) { if err := drone.Land(); err != nil { fmt.Println(err) } }) _ = stick.On(joystick.LeftX, func(data interface{}) { val := float64(data.(int)) leftX.Store(val) }) _ = stick.On(joystick.LeftY, func(data interface{}) { val := float64(data.(int)) leftY.Store(val) }) _ = stick.On(joystick.RightX, func(data interface{}) { val := float64(data.(int)) rightX.Store(val) }) _ = stick.On(joystick.RightY, func(data interface{}) { val := float64(data.(int)) rightY.Store(val) }) gobot.Every(10*time.Millisecond, func() { rightStick := getRightStick() switch { case rightStick.y < -10: if err := drone.Forward(parrot.ValidatePitch(rightStick.y, offset)); err != nil { fmt.Println(err) } case rightStick.y > 10: if err := drone.Backward(parrot.ValidatePitch(rightStick.y, offset)); err != nil { fmt.Println(err) } default: if err := drone.Forward(0); err != nil { fmt.Println(err) } } switch { case rightStick.x > 10: if err := drone.Right(parrot.ValidatePitch(rightStick.x, offset)); err != nil { fmt.Println(err) } case rightStick.x < -10: if err := drone.Left(parrot.ValidatePitch(rightStick.x, offset)); err != nil { fmt.Println(err) } default: if err := drone.Right(0); err != nil { fmt.Println(err) } } }) gobot.Every(10*time.Millisecond, func() { leftStick := getLeftStick() switch { case leftStick.y < -10: if err := drone.Up(parrot.ValidatePitch(leftStick.y, offset)); err != nil { fmt.Println(err) } case leftStick.y > 10: if err := drone.Down(parrot.ValidatePitch(leftStick.y, offset)); err != nil { fmt.Println(err) } default: if err := drone.Up(0); err != nil { fmt.Println(err) } } switch { case leftStick.x > 20: if err := drone.Clockwise(parrot.ValidatePitch(leftStick.x, offset)); err != nil { fmt.Println(err) } case leftStick.x < -20: if err := drone.CounterClockwise(parrot.ValidatePitch(leftStick.x, offset)); err != nil { fmt.Println(err) } default: if err := drone.Clockwise(0); err != nil { fmt.Println(err) } } }) } robot := gobot.NewRobot("minidrone", []gobot.Connection{joystickAdaptor, droneAdaptor}, []gobot.Device{stick, drone}, work, ) if err := robot.Start(); err != nil { panic(err) } } func getLeftStick() pair { s := pair{x: 0, y: 0} s.x = leftX.Load().(float64) s.y = leftY.Load().(float64) return s } func getRightStick() pair { s := pair{x: 0, y: 0} s.x = rightX.Load().(float64) s.y = rightY.Load().(float64) return s } ================================================ FILE: examples/bleclient_multiple_generic.go ================================================ //go:build example // +build example // // Do not build by default. /* How to run Pass the Bluetooth address or name as the first param: go run examples/ble_multiple_generic.go BB-1234 BB-1235 NOTE: sudo is required to use BLE in Linux */ package main import ( "fmt" "os" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/api" "gobot.io/x/gobot/v2/drivers/ble" "gobot.io/x/gobot/v2/platforms/bleclient" ) func NewSwarmBot(port string) *gobot.Robot { bleAdaptor := bleclient.NewAdaptor(port) access := ble.NewGenericAccessDriver(bleAdaptor) work := func() { devName, err := access.GetDeviceName() if err != nil { fmt.Println(err) } fmt.Println("Device name:", devName) appearance, err := access.GetAppearance() if err != nil { fmt.Println(err) } fmt.Println("Appearance:", appearance) } robot := gobot.NewRobot("bot "+port, []gobot.Connection{bleAdaptor}, []gobot.Device{access}, work, ) return robot } func main() { manager := gobot.NewManager() api.NewAPI(manager).Start() for _, port := range os.Args[1:] { bot := NewSwarmBot(port) manager.AddRobot(bot) } if err := manager.Start(); err != nil { panic(err) } } ================================================ FILE: examples/bleclient_multiple_info.go ================================================ //go:build example // +build example // // Do not build by default. /* How to run Pass the Bluetooth address or name as the first param: go run examples/ble_multiple_info.go BB-1234 BB-1235 NOTE: sudo is required to use BLE in Linux */ package main import ( "fmt" "os" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/api" "gobot.io/x/gobot/v2/drivers/ble" "gobot.io/x/gobot/v2/platforms/bleclient" ) func NewSwarmBot(port string) *gobot.Robot { bleAdaptor := bleclient.NewAdaptor(port) info := ble.NewDeviceInformationDriver(bleAdaptor) work := func() { modelNo, err := info.GetModelNumber() if err != nil { fmt.Println(err) } fmt.Println("Model number:", modelNo) fwRev, err := info.GetFirmwareRevision() if err != nil { fmt.Println(err) } fmt.Println("Firmware rev:", fwRev) hwRev, err := info.GetHardwareRevision() if err != nil { fmt.Println(err) } fmt.Println("Hardware rev:", hwRev) manuName, err := info.GetManufacturerName() if err != nil { fmt.Println(err) } fmt.Println("Manufacturer name:", manuName) pid, err := info.GetPnPId() if err != nil { fmt.Println(err) } fmt.Println("PnPId:", pid) } robot := gobot.NewRobot("bot "+port, []gobot.Connection{bleAdaptor}, []gobot.Device{info}, work, ) return robot } func main() { manager := gobot.NewManager() api.NewAPI(manager).Start() for _, port := range os.Args[1:] { bot := NewSwarmBot(port) manager.AddRobot(bot) } if err := manager.Start(); err != nil { panic(err) } } ================================================ FILE: examples/bleclient_ollie.go ================================================ //go:build example // +build example // // Do not build by default. //nolint:gosec // ok here package main import ( "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble/sphero" "gobot.io/x/gobot/v2/platforms/bleclient" ) func main() { bleAdaptor := bleclient.NewAdaptor(os.Args[1]) ollie := sphero.NewOllieDriver(bleAdaptor) work := func() { gobot.Every(1*time.Second, func() { r := uint8(gobot.Rand(255)) g := uint8(gobot.Rand(255)) b := uint8(gobot.Rand(255)) ollie.SetRGB(r, g, b) }) } robot := gobot.NewRobot("ollieBot", []gobot.Connection{bleAdaptor}, []gobot.Device{ollie}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/bleclient_ollie_boost.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble/sphero" "gobot.io/x/gobot/v2/platforms/bleclient" ) func main() { bleAdaptor := bleclient.NewAdaptor(os.Args[1]) ollieBot := sphero.NewOllieDriver(bleAdaptor) work := func() { head := uint16(90) ollieBot.SetRGB(255, 0, 0) ollieBot.Boost(true) gobot.Every(1*time.Second, func() { ollieBot.Roll(0, head) time.Sleep(1 * time.Second) head += 90 head = head % 360 }) } robot := gobot.NewRobot("ollieBot", []gobot.Connection{bleAdaptor}, []gobot.Device{ollieBot}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/bleclient_ollie_crazy.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble/sphero" "gobot.io/x/gobot/v2/platforms/bleclient" ) func main() { bleAdaptor := bleclient.NewAdaptor(os.Args[1]) ollieBot := sphero.NewOllieDriver(bleAdaptor) work := func() { ollieBot.SetRGB(255, 0, 255) gobot.Every(1*time.Second, func() { // Ollie performs 'crazy-ollie' trick ollieBot.SetRawMotorValues(sphero.Forward, uint8(255), sphero.Forward, uint8(255)) }) } robot := gobot.NewRobot("ollieBot", []gobot.Connection{bleAdaptor}, []gobot.Device{ollieBot}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/bleclient_ollie_mqtt.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "os" "strconv" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble/sphero" "gobot.io/x/gobot/v2/platforms/bleclient" "gobot.io/x/gobot/v2/platforms/mqtt" ) const ( FRENTE = 0 DERECHA = 90 ATRAS = 180 IZQUIERDA = 270 ) func main() { bleAdaptor := bleclient.NewAdaptor(os.Args[1]) ollie := sphero.NewOllieDriver(bleAdaptor) mqttAdaptor := mqtt.NewAdaptor("tcp://iot.eclipse.org:1883", "ollie") work := func() { ollie.SetRGB(255, 0, 255) _ = mqttAdaptor.On("sensors/dial", func(msg mqtt.Message) { val, _ := strconv.Atoi(string(msg.Payload())) if val > 2000 { ollie.SetRGB(0, 255, 0) return } if val > 1000 { ollie.SetRGB(255, 255, 0) return } ollie.SetRGB(255, 0, 0) }) _ = mqttAdaptor.On("rover/frente", func(msg mqtt.Message) { ollie.Roll(40, FRENTE) gobot.After(1*time.Second, func() { ollie.Stop() }) }) _ = mqttAdaptor.On("rover/derecha", func(msg mqtt.Message) { ollie.Roll(40, DERECHA) gobot.After(1*time.Second, func() { ollie.Stop() }) }) _ = mqttAdaptor.On("rover/atras", func(msg mqtt.Message) { ollie.Roll(40, ATRAS) gobot.After(1*time.Second, func() { ollie.Stop() }) }) _ = mqttAdaptor.On("rover/izquierda", func(msg mqtt.Message) { ollie.Roll(40, IZQUIERDA) gobot.After(1*time.Second, func() { ollie.Stop() }) }) } robot := gobot.NewRobot("ollieBot", []gobot.Connection{bleAdaptor, mqttAdaptor}, []gobot.Device{ollie}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/bleclient_ollie_multiple.go ================================================ //go:build example // +build example // // Do not build by default. /* To run this example, pass the BLE address or BLE name as first param: go run examples/ollie_multiple.go 2B-1234 2B-5678 NOTE: sudo is required to use BLE in Linux */ //nolint:gosec // ok here package main import ( "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/api" "gobot.io/x/gobot/v2/drivers/ble/sphero" "gobot.io/x/gobot/v2/platforms/bleclient" ) func NewSwarmBot(port string) *gobot.Robot { bleAdaptor := bleclient.NewAdaptor(port) ollieDriver := sphero.NewOllieDriver(bleAdaptor) work := func() { gobot.Every(1*time.Second, func() { ollieDriver.SetRGB(uint8(gobot.Rand(255)), uint8(gobot.Rand(255)), uint8(gobot.Rand(255)), ) }) } robot := gobot.NewRobot("ollie "+port, []gobot.Connection{bleAdaptor}, []gobot.Device{ollieDriver}, work, ) return robot } func main() { manager := gobot.NewManager() api.NewAPI(manager).Start() for _, port := range os.Args[1:] { bot := NewSwarmBot(port) manager.AddRobot(bot) } if err := manager.Start(); err != nil { panic(err) } } ================================================ FILE: examples/bleclient_ollie_roll.go ================================================ //go:build example // +build example // // Do not build by default. //nolint:gosec // ok here package main import ( "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble/sphero" "gobot.io/x/gobot/v2/platforms/bleclient" ) func main() { bleAdaptor := bleclient.NewAdaptor(os.Args[1]) ollie := sphero.NewOllieDriver(bleAdaptor) work := func() { ollie.SetRGB(255, 0, 255) gobot.Every(3*time.Second, func() { ollie.Roll(40, uint16(gobot.Rand(360))) }) } robot := gobot.NewRobot("ollieBot", []gobot.Connection{bleAdaptor}, []gobot.Device{ollie}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/bleclient_ollie_spin.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble/sphero" "gobot.io/x/gobot/v2/platforms/bleclient" ) func main() { bleAdaptor := bleclient.NewAdaptor(os.Args[1]) ollieBot := sphero.NewOllieDriver(bleAdaptor) work := func() { ollieBot.SetRGB(255, 0, 255) gobot.Every(1*time.Second, func() { // Ollie performs 360 spin trick ollieBot.SetRawMotorValues(sphero.Forward, uint8(255), sphero.Reverse, uint8(255)) }) } robot := gobot.NewRobot("ollieBot", []gobot.Connection{bleAdaptor}, []gobot.Device{ollieBot}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/bleclient_sprkplus.go ================================================ //go:build example // +build example // // Do not build by default. /* How to run Pass the Bluetooth address or name as the first param: go run examples/sprkplus.go SK-1234 NOTE: sudo is required to use BLE in Linux */ //nolint:gosec // ok here package main import ( "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble/sphero" "gobot.io/x/gobot/v2/platforms/bleclient" ) func main() { bleAdaptor := bleclient.NewAdaptor(os.Args[1]) sprk := sphero.NewSPRKPlusDriver(bleAdaptor) work := func() { gobot.Every(1*time.Second, func() { r := uint8(gobot.Rand(255)) g := uint8(gobot.Rand(255)) b := uint8(gobot.Rand(255)) sprk.SetRGB(r, g, b) }) } robot := gobot.NewRobot("sprkBot", []gobot.Connection{bleAdaptor}, []gobot.Device{sprk}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/bleclient_sprkplus_collision.go ================================================ //go:build example // +build example // // Do not build by default. /* How to run Pass the Bluetooth address or name as the first param: go run examples/bb8-collision.go BB-1234 NOTE: sudo is required to use BLE in Linux */ package main import ( "fmt" "os" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble/sphero" "gobot.io/x/gobot/v2/platforms/bleclient" ) func main() { bleAdaptor := bleclient.NewAdaptor(os.Args[1]) ball := sphero.NewSPRKPlusDriver(bleAdaptor) work := func() { _ = ball.On("collision", func(data interface{}) { fmt.Printf("collision detected = %+v \n", data) ball.SetRGB(255, 0, 0) }) ball.SetRGB(0, 255, 0) ball.Roll(80, 0) } robot := gobot.NewRobot("sprkplus", []gobot.Connection{bleAdaptor}, []gobot.Device{ball}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/chip_blink.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/chip" ) func main() { chipAdaptor := chip.NewAdaptor() led := gpio.NewLedDriver(chipAdaptor, "XIO-P6") work := func() { gobot.Every(1*time.Second, func() { if err := led.Toggle(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("blinkBot", []gobot.Connection{chipAdaptor}, []gobot.Device{led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/chip_blinkm.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/chip" ) func main() { a := chip.NewAdaptor() blinkm := i2c.NewBlinkMDriver(a) work := func() { gobot.Every(1*time.Second, func() { r := byte(gobot.Rand(255)) g := byte(gobot.Rand(255)) b := byte(gobot.Rand(255)) if err := blinkm.Rgb(r, g, b); err != nil { fmt.Println(err) } color, err := blinkm.Color() if err != nil { fmt.Println(err) } fmt.Printf("color %v\n", color) }) } robot := gobot.NewRobot("blinkmBot", []gobot.Connection{a}, []gobot.Device{blinkm}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/chip_button.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/chip" ) func main() { chipAdaptor := chip.NewAdaptor() button := gpio.NewButtonDriver(chipAdaptor, "XIO-P0") work := func() { _ = button.On(gpio.ButtonPush, func(data interface{}) { fmt.Println("button pressed") }) _ = button.On(gpio.ButtonRelease, func(data interface{}) { fmt.Println("button released") }) } robot := gobot.NewRobot("buttonBot", []gobot.Connection{chipAdaptor}, []gobot.Device{button}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/chip_button_led.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/chip" ) func main() { chipAdaptor := chip.NewAdaptor() button := gpio.NewButtonDriver(chipAdaptor, "XIO-P6") led := gpio.NewLedDriver(chipAdaptor, "XIO-P7") work := func() { _ = button.On(gpio.ButtonPush, func(data interface{}) { if err := led.On(); err != nil { fmt.Println(err) } }) _ = button.On(gpio.ButtonRelease, func(data interface{}) { if err := led.Off(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("buttonBot", []gobot.Connection{chipAdaptor}, []gobot.Device{button, led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/chip_drv2605l.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/chip" ) func main() { board := chip.NewAdaptor() haptic := i2c.NewDRV2605LDriver(board) work := func() { gobot.Every(3*time.Second, func() { pause := haptic.GetPauseWaveform(50) if err := haptic.SetSequence([]byte{1, pause, 1, pause, 1}); err != nil { fmt.Println(err) } if err := haptic.Go(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("DRV2605LBot", []gobot.Connection{board}, []gobot.Device{haptic}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/chip_grove_accelerometer.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/chip" ) func main() { board := chip.NewAdaptor() accel := i2c.NewGroveAccelerometerDriver(board) work := func() { gobot.Every(500*time.Millisecond, func() { if x, y, z, err := accel.XYZ(); err == nil { fmt.Println(x, y, z) fmt.Println(accel.Acceleration(x, y, z)) } else { fmt.Println(err) } }) } robot := gobot.NewRobot("accelBot", []gobot.Connection{board}, []gobot.Device{accel}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/chip_grove_lcd.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/chip" ) func main() { board := chip.NewAdaptor() screen := i2c.NewGroveLcdDriver(board) work := func() { if err := screen.Write("hello"); err != nil { fmt.Println(err) } if err := screen.SetRGB(255, 0, 0); err != nil { fmt.Println(err) } gobot.After(5*time.Second, func() { if err := screen.Clear(); err != nil { fmt.Println(err) } if err := screen.Home(); err != nil { fmt.Println(err) } if err := screen.SetRGB(0, 255, 0); err != nil { fmt.Println(err) } // set a custom character in the first position if err := screen.SetCustomChar(0, i2c.CustomLCDChars["smiley"]); err != nil { fmt.Println(err) } // add the custom character at the end of the string if err := screen.Write("goodbye\nhave a nice day " + string(byte(0))); err != nil { fmt.Println(err) } gobot.Every(500*time.Millisecond, func() { if err := screen.Scroll(false); err != nil { fmt.Println(err) } }) }) if err := screen.Home(); err != nil { fmt.Println(err) } time.Sleep(1 * time.Second) if err := screen.SetRGB(0, 0, 255); err != nil { fmt.Println(err) } } robot := gobot.NewRobot("screenBot", []gobot.Connection{board}, []gobot.Device{screen}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/chip_mpu6050.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/chip" ) func main() { board := chip.NewAdaptor() mpu6050 := i2c.NewMPU6050Driver(board) work := func() { gobot.Every(100*time.Millisecond, func() { if err := mpu6050.GetData(); err != nil { fmt.Println(err) } fmt.Println("Accelerometer", mpu6050.Accelerometer) fmt.Println("Gyroscope", mpu6050.Gyroscope) fmt.Println("Temperature", mpu6050.Temperature) }) } robot := gobot.NewRobot("mpu6050Bot", []gobot.Connection{board}, []gobot.Device{mpu6050}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/chip_tsl2561.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/chip" ) func main() { board := chip.NewAdaptor() luxSensor := i2c.NewTSL2561Driver(board, i2c.WithTSL2561Gain16X) work := func() { gobot.Every(1*time.Second, func() { broadband, ir, err := luxSensor.GetLuminocity() if err != nil { fmt.Println("Err:", err) } else { light := luxSensor.CalculateLux(broadband, ir) fmt.Printf("BB: %v, IR: %v, Lux: %v\n", broadband, ir, light) } }) } robot := gobot.NewRobot("tsl2561Bot", []gobot.Connection{board}, []gobot.Device{luxSensor}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/chip_wiichuck.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/chip" ) func main() { chipAdaptor := chip.NewAdaptor() wiichuck := i2c.NewWiichuckDriver(chipAdaptor) work := func() { _ = wiichuck.On(wiichuck.Event("joystick"), func(data interface{}) { fmt.Println("joystick", data) }) _ = wiichuck.On(wiichuck.Event("c"), func(data interface{}) { fmt.Println("c") }) _ = wiichuck.On(wiichuck.Event("z"), func(data interface{}) { fmt.Println("z") }) _ = wiichuck.On(wiichuck.Event("error"), func(data interface{}) { fmt.Println("Wiichuck error:", data) }) } robot := gobot.NewRobot("chuck", []gobot.Connection{chipAdaptor}, []gobot.Device{wiichuck}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/digispark_api.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/api" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/digispark" ) func main() { manager := gobot.NewManager() api.NewAPI(manager).Start() digisparkAdaptor := digispark.NewAdaptor() led := gpio.NewLedDriver(digisparkAdaptor, "0") robot := gobot.NewRobot("digispark", []gobot.Connection{digisparkAdaptor}, []gobot.Device{led}, ) manager.AddRobot(robot) if err := manager.Start(); err != nil { panic(err) } } ================================================ FILE: examples/digispark_blink.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/digispark" ) func main() { digisparkAdaptor := digispark.NewAdaptor() led := gpio.NewLedDriver(digisparkAdaptor, "0") work := func() { gobot.Every(1*time.Second, func() { if err := led.Toggle(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("blinkBot", []gobot.Connection{digisparkAdaptor}, []gobot.Device{led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/digispark_blinkm.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/digispark" ) func main() { board := digispark.NewAdaptor() blinkm := i2c.NewBlinkMDriver(board) work := func() { gobot.Every(3*time.Second, func() { r := byte(gobot.Rand(255)) g := byte(gobot.Rand(255)) b := byte(gobot.Rand(255)) if err := blinkm.Rgb(r, g, b); err != nil { fmt.Println(err) } color, err := blinkm.Color() if err != nil { fmt.Println(err) } fmt.Printf("color %v\n", color) }) } robot := gobot.NewRobot("blinkBot", []gobot.Connection{board}, []gobot.Device{blinkm}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/digispark_driver.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "strconv" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/digispark" ) // This is an example for using the generic I2C driver to write and read values // to an i2c device. It is suitable for simple devices, e.g. EEPROM. // The example was tested with the EEPROM part of PCA9501. // // Procedure: // * write value to register (EEPROM address) // * read value back from register (EEPROM address) and check for differences func main() { const ( defaultAddress = 0x7F myAddress = 0x44 // needs to be adjusted for your configuration ) board := digispark.NewAdaptor() drv := i2c.NewDriver(board, "PCA9501-EEPROM", defaultAddress, i2c.WithAddress(myAddress)) var eepromAddr uint8 = 0x00 var register string var valWr uint8 = 0xFF var valRd int var err error work := func() { gobot.Every(50*time.Millisecond, func() { // write a value 0-255 to EEPROM address 255-0 eepromAddr-- valWr++ register = strconv.Itoa(int(eepromAddr)) err = drv.Write(register, int(valWr)) if err != nil { fmt.Println("err write:", err) } // write process needs some time, so wait at least 5ms before read a value // when decreasing to much, the check below will fail time.Sleep(5 * time.Millisecond) // read value back and check for unexpected differences valRd, err = drv.Read(register) if err != nil { fmt.Println("err read:", err) } if int(valWr) != valRd { fmt.Printf("addr: %d wr: %d differ rd: %d\n", eepromAddr, valWr, valRd) } if eepromAddr%10 == 0 { fmt.Printf("addr: %d, wr: %d rd: %d\n", eepromAddr, valWr, valRd) } }) } robot := gobot.NewRobot("simpleDriverI2c", []gobot.Connection{board}, []gobot.Device{drv}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/digispark_led_brightness.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/digispark" ) func main() { digisparkAdaptor := digispark.NewAdaptor() led := gpio.NewLedDriver(digisparkAdaptor, "0") work := func() { brightness := uint8(0) fadeAmount := uint8(15) gobot.Every(100*time.Millisecond, func() { if err := led.Brightness(brightness); err != nil { fmt.Println(err) } brightness = brightness + fadeAmount if brightness == 0 || brightness == 255 { fadeAmount = -fadeAmount } }) } robot := gobot.NewRobot("pwmBot", []gobot.Connection{digisparkAdaptor}, []gobot.Device{led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/digispark_mpl115a2.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/digispark" ) func main() { board := digispark.NewAdaptor() mpl115a2 := i2c.NewMPL115A2Driver(board) work := func() { gobot.Every(1*time.Second, func() { press, _ := mpl115a2.Pressure() fmt.Println("Pressure", press) temp, _ := mpl115a2.Temperature() fmt.Println("Temperature", temp) }) } robot := gobot.NewRobot("mpl115Bot", []gobot.Connection{board}, []gobot.Device{mpl115a2}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/digispark_pca9501.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/digispark" ) // Program use EEPROM with GPIO to rotate pins, get best experience, when // add LED's between +5V and each pin with an resistor of ~180 Ohm. // // Procedure: // * write value to EEPROM // * read value back from EEPROM and check for differences // * use read value to set GPIO func main() { board := digispark.NewAdaptor() pca := i2c.NewPCA9501Driver(board, i2c.WithAddress(0x04)) var addressMem uint8 = 0x00 var valMemW uint8 = 0xFF var valMemR uint8 var pin uint8 = 0 var newPin uint8 = 0 var pinState uint8 = 0 var err error work := func() { gobot.Every(50*time.Millisecond, func() { // write a value 0-255 to EEPROM address 255-0 addressMem-- valMemW++ err = pca.WriteEEPROM(addressMem, valMemW) if err != nil { fmt.Println("err MEMw:", err) } // write process needs some time, so wait at least 5ms before read a value // when decreasing to much, the check below will fail time.Sleep(5 * time.Millisecond) // read value back and check for unexpected differences valMemR, err = pca.ReadEEPROM(addressMem) if err != nil { fmt.Println("err MEMr:", err) } if valMemW != valMemR { fmt.Printf("addr: %d valMemW: %d differ valMemR: %d\n", addressMem, valMemW, valMemR) } // convert it to a pin 0-7 newPin = valMemR % 8 // write only when something has changed if newPin != pin { pin = newPin fmt.Println("set Pin:", pin, "to:", pinState) err = pca.WriteGPIO(pin, pinState) if err != nil { fmt.Println("err GPIO:", err) } // when all LED's are on switch off if pin >= 7 { if pinState == 0 { pinState = 1 } else { pinState = 0 } } } }) } robot := gobot.NewRobot("rotatePinsI2c", []gobot.Connection{board}, []gobot.Device{pca}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/digispark_servo.go ================================================ //go:build example // +build example // // Do not build by default. //nolint:gosec // ok here package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/digispark" ) func main() { digisparkAdaptor := digispark.NewAdaptor() servo := gpio.NewServoDriver(digisparkAdaptor, "0") work := func() { gobot.Every(1*time.Second, func() { i := uint8(gobot.Rand(180)) fmt.Println("Turning", i) if err := servo.Move(i); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("servoBot", []gobot.Connection{digisparkAdaptor}, []gobot.Device{servo}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/dragonboard_button.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/dragonboard" ) func main() { dragonAdaptor := dragonboard.NewAdaptor() button := gpio.NewButtonDriver(dragonAdaptor, "GPIO_A") work := func() { _ = button.On(gpio.ButtonPush, func(data interface{}) { fmt.Println("button pressed") }) _ = button.On(gpio.ButtonRelease, func(data interface{}) { fmt.Println("button released") }) } robot := gobot.NewRobot("buttonBot", []gobot.Connection{dragonAdaptor}, []gobot.Device{button}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/edison_blink.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/intel-iot/edison" ) const boardType = "arduino" // "sparkfun" for a Sparkfun Edison board with the GPIO block func main() { e := edison.NewAdaptor(boardType) led := gpio.NewLedDriver(e, "13") work := func() { gobot.Every(1*time.Second, func() { if err := led.Toggle(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("blinkBot", []gobot.Connection{e}, []gobot.Device{led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/edison_blink_without_all_gobot_framework.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/intel-iot/edison" ) // Example of a simple led toggle without the initialization of // the entire gobot framework. // This might be useful if you want to use gobot as another // golang library to interact with sensors and other devices. func main() { e := edison.NewAdaptor() if err := e.Connect(); err != nil { fmt.Println(err) } led := gpio.NewLedDriver(e, "13") if err := led.Start(); err != nil { fmt.Println(err) } for { if err := led.Toggle(); err != nil { fmt.Println(err) } time.Sleep(1000 * time.Millisecond) } } ================================================ FILE: examples/edison_blinkm.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/intel-iot/edison" ) func main() { e := edison.NewAdaptor() blinkm := i2c.NewBlinkMDriver(e) work := func() { gobot.Every(3*time.Second, func() { r := byte(gobot.Rand(255)) g := byte(gobot.Rand(255)) b := byte(gobot.Rand(255)) if err := blinkm.Rgb(r, g, b); err != nil { fmt.Println(err) } color, err := blinkm.Color() if err != nil { fmt.Println(err) } fmt.Printf("color %v\n", color) }) } robot := gobot.NewRobot("blinkmBot", []gobot.Connection{e}, []gobot.Device{blinkm}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/edison_bme280.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/intel-iot/edison" ) func main() { a := edison.NewAdaptor() bme280 := i2c.NewBME280Driver(a, i2c.WithAddress(0x76)) work := func() { gobot.Every(1*time.Second, func() { t, e := bme280.Temperature() fmt.Println("Temperature", t) if e != nil { fmt.Println(e) } p, e := bme280.Pressure() fmt.Println("Pressure", p) if e != nil { fmt.Println(e) } a, e := bme280.Altitude() fmt.Println("Altitude", a) if e != nil { fmt.Println(e) } h, e := bme280.Humidity() fmt.Println("Humidity", h) if e != nil { fmt.Println(e) } }) } robot := gobot.NewRobot("bme280bot", []gobot.Connection{a}, []gobot.Device{bme280}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/edison_button.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/intel-iot/edison" ) func main() { e := edison.NewAdaptor() button := gpio.NewButtonDriver(e, "5") led := gpio.NewLedDriver(e, "13") work := func() { _ = button.On(gpio.ButtonPush, func(data interface{}) { if err := led.On(); err != nil { fmt.Println(err) } }) _ = button.On(gpio.ButtonRelease, func(data interface{}) { if err := led.Off(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("buttonBot", []gobot.Connection{e}, []gobot.Device{led, button}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/edison_button_led.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/intel-iot/edison" ) func main() { e := edison.NewAdaptor() button := gpio.NewButtonDriver(e, "2") led := gpio.NewLedDriver(e, "4") work := func() { _ = button.On(gpio.ButtonPush, func(data interface{}) { if err := led.On(); err != nil { fmt.Println(err) } }) _ = button.On(gpio.ButtonRelease, func(data interface{}) { if err := led.Off(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("buttonBot", []gobot.Connection{e}, []gobot.Device{led, button}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/edison_button_led_api.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/api" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/intel-iot/edison" ) func main() { manager := gobot.NewManager() api.NewAPI(manager).Start() e := edison.NewAdaptor() button := gpio.NewButtonDriver(e, "2") led := gpio.NewLedDriver(e, "4") work := func() { _ = button.On(gpio.ButtonPush, func(data interface{}) { if err := led.On(); err != nil { fmt.Println(err) } }) _ = button.On(gpio.ButtonRelease, func(data interface{}) { if err := led.Off(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("buttonBot", []gobot.Connection{e}, []gobot.Device{led, button}, work, ) manager.AddRobot(robot) if err := manager.Start(); err != nil { panic(err) } } ================================================ FILE: examples/edison_grove_accelerometer.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/intel-iot/edison" ) func main() { board := edison.NewAdaptor() accel := i2c.NewGroveAccelerometerDriver(board) work := func() { gobot.Every(500*time.Millisecond, func() { if x, y, z, err := accel.XYZ(); err == nil { fmt.Println(x, y, z) fmt.Println(accel.Acceleration(x, y, z)) } else { fmt.Println(err) } }) } robot := gobot.NewRobot("accelBot", []gobot.Connection{board}, []gobot.Device{accel}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/edison_grove_buzzer.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/intel-iot/edison" ) func main() { board := edison.NewAdaptor() buzzer := gpio.NewBuzzerDriver(board, "3") work := func() { type note struct { tone float64 duration float64 } song := []note{ {gpio.C4, gpio.Quarter}, {gpio.C4, gpio.Quarter}, {gpio.G4, gpio.Quarter}, {gpio.G4, gpio.Quarter}, {gpio.A4, gpio.Quarter}, {gpio.A4, gpio.Quarter}, {gpio.G4, gpio.Half}, {gpio.F4, gpio.Quarter}, {gpio.F4, gpio.Quarter}, {gpio.E4, gpio.Quarter}, {gpio.E4, gpio.Quarter}, {gpio.D4, gpio.Quarter}, {gpio.D4, gpio.Quarter}, {gpio.C4, gpio.Half}, } for _, val := range song { if err := buzzer.Tone(val.tone, val.duration); err != nil { fmt.Println(err) } time.Sleep(10 * time.Millisecond) } } robot := gobot.NewRobot("bot", []gobot.Connection{board}, []gobot.Device{buzzer}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/edison_grove_lcd.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/intel-iot/edison" ) func main() { board := edison.NewAdaptor() screen := i2c.NewGroveLcdDriver(board) work := func() { if err := screen.Write("hello"); err != nil { fmt.Println(err) } if err := screen.SetRGB(255, 0, 0); err != nil { fmt.Println(err) } gobot.After(5*time.Second, func() { if err := screen.Clear(); err != nil { fmt.Println(err) } if err := screen.Home(); err != nil { fmt.Println(err) } if err := screen.SetRGB(0, 255, 0); err != nil { fmt.Println(err) } // set a custom character in the first position if err := screen.SetCustomChar(0, i2c.CustomLCDChars["smiley"]); err != nil { fmt.Println(err) } // add the custom character at the end of the string if err := screen.Write("goodbye\nhave a nice day " + string(byte(0))); err != nil { fmt.Println(err) } gobot.Every(500*time.Millisecond, func() { if err := screen.Scroll(false); err != nil { fmt.Println(err) } }) }) if err := screen.Home(); err != nil { fmt.Println(err) } time.Sleep(1 * time.Second) if err := screen.SetRGB(0, 0, 255); err != nil { fmt.Println(err) } } robot := gobot.NewRobot("screenBot", []gobot.Connection{board}, []gobot.Device{screen}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/edison_grove_light_sensor.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" "gobot.io/x/gobot/v2/platforms/intel-iot/edison" ) func main() { board := edison.NewAdaptor() sensor := aio.NewGroveLightSensorDriver(board, "0", aio.WithSensorCyclicRead(500*time.Millisecond)) work := func() { _ = sensor.On(sensor.Event("data"), func(data interface{}) { fmt.Println("sensor", data) }) } robot := gobot.NewRobot("sensorBot", []gobot.Connection{board}, []gobot.Device{sensor}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/edison_grove_piezo_vibration.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" "gobot.io/x/gobot/v2/platforms/intel-iot/edison" ) func main() { board := edison.NewAdaptor() sensor := aio.NewGrovePiezoVibrationSensorDriver(board, "0", aio.WithSensorCyclicRead(500*time.Millisecond)) work := func() { _ = sensor.On(aio.Vibration, func(data interface{}) { fmt.Println("got one!") }) } robot := gobot.NewRobot("bot", []gobot.Connection{board}, []gobot.Device{sensor}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/edison_grove_rotary_sensor.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" "gobot.io/x/gobot/v2/platforms/intel-iot/edison" ) func main() { board := edison.NewAdaptor() sensor := aio.NewGroveRotaryDriver(board, "0", aio.WithSensorCyclicRead(500*time.Millisecond)) work := func() { _ = sensor.On(aio.Data, func(data interface{}) { fmt.Println("sensor", data) }) } robot := gobot.NewRobot("sensorBot", []gobot.Connection{board}, []gobot.Device{sensor}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/edison_grove_sound_sensor.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" "gobot.io/x/gobot/v2/platforms/intel-iot/edison" ) func main() { board := edison.NewAdaptor() sensor := aio.NewGroveSoundSensorDriver(board, "0", aio.WithSensorCyclicRead(500*time.Millisecond)) work := func() { _ = sensor.On(aio.Data, func(data interface{}) { fmt.Println("sensor", data) }) } robot := gobot.NewRobot("sensorBot", []gobot.Connection{board}, []gobot.Device{sensor}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/edison_grove_temperature_sensor.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" "gobot.io/x/gobot/v2/platforms/intel-iot/edison" ) func main() { board := edison.NewAdaptor() sensor := aio.NewGroveTemperatureSensorDriver(board, "0", aio.WithSensorCyclicRead(500*time.Millisecond)) work := func() { gobot.Every(500*time.Millisecond, func() { fmt.Println("current temp (c): ", sensor.Temperature()) }) } robot := gobot.NewRobot("sensorBot", []gobot.Connection{board}, []gobot.Device{sensor}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/edison_led_brightness.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/intel-iot/edison" ) func main() { e := edison.NewAdaptor() led := gpio.NewLedDriver(e, "3") work := func() { brightness := uint8(0) fadeAmount := uint8(15) gobot.Every(100*time.Millisecond, func() { if err := led.Brightness(brightness); err != nil { fmt.Println(err) } brightness = brightness + fadeAmount if brightness == 0 || brightness == 255 { fadeAmount = -fadeAmount } }) } robot := gobot.NewRobot("pwmBot", []gobot.Connection{e}, []gobot.Device{led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/edison_led_brightness_with_analog_input.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/intel-iot/edison" ) func main() { e := edison.NewAdaptor() sensor := aio.NewAnalogSensorDriver(e, "0", aio.WithSensorCyclicRead(500*time.Millisecond)) led := gpio.NewLedDriver(e, "3") work := func() { _ = sensor.On(aio.Data, func(data interface{}) { brightness := uint8( gobot.ToScale(gobot.FromScale(float64(data.(int)), 0, 4096), 0, 255), ) fmt.Println("sensor", data) fmt.Println("brightness", brightness) if err := led.Brightness(brightness); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("sensorBot", []gobot.Connection{e}, []gobot.Device{sensor, led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/edison_miniboard_grove_accelerometer.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/intel-iot/edison" ) func main() { board := edison.NewAdaptor("miniboard") accel := i2c.NewGroveAccelerometerDriver(board) work := func() { gobot.Every(500*time.Millisecond, func() { if x, y, z, err := accel.XYZ(); err == nil { fmt.Println(x, y, z) fmt.Println(accel.Acceleration(x, y, z)) } else { fmt.Println(err) } }) } robot := gobot.NewRobot("accelBot", []gobot.Connection{board}, []gobot.Device{accel}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/every_done.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" ) func main() { robot := gobot.NewRobot( "hello", func() { done := gobot.Every(750*time.Millisecond, func() { fmt.Println("Greetings human") }) gobot.After(5*time.Second, func() { done.Stop() fmt.Println("We're done here") }) }, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/firmata_adxl345.go ================================================ //go:build example // +build example // // Do not build by default. /* How to run Pass serial port to use as the first param: go run examples/firmata_adxl345.go /dev/ttyACM0 */ package main import ( "fmt" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/firmata" ) func main() { firmataAdaptor := firmata.NewAdaptor(os.Args[1]) adxl345 := i2c.NewADXL345Driver(firmataAdaptor) work := func() { gobot.Every(100*time.Millisecond, func() { x, y, z, _ := adxl345.XYZ() fmt.Printf("x: %.7f | y: %.7f | z: %.7f \n", x, y, z) }) } robot := gobot.NewRobot("adxl345Bot", []gobot.Connection{firmataAdaptor}, []gobot.Device{adxl345}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/firmata_aip1640.go ================================================ //go:build example // +build example // // Do not build by default. /* How to run Pass serial port to use as the first param: go run examples/firmata_aip1640.go /dev/ttyACM0 */ package main import ( "fmt" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/firmata" ) func main() { firmataAdaptor := firmata.NewAdaptor(os.Args[1]) // In the WEMOS D1 Mini LED Matrix Shield clockPin = 14, dataPin = 13 aip1640 := gpio.NewAIP1640Driver(firmataAdaptor, "14", "13") smiles := [3][8]byte{ {0x3C, 0x42, 0xA5, 0x81, 0xA5, 0x99, 0x42, 0x3C}, // happy :) {0x3C, 0x42, 0xA5, 0x81, 0xBD, 0x81, 0x42, 0x3C}, // normal :| {0x3C, 0x42, 0xA5, 0x81, 0x99, 0xA5, 0x42, 0x3C}, // sad :( } s := 0 work := func() { aip1640.Clear() gobot.Every(600*time.Millisecond, func() { aip1640.DrawMatrix(smiles[s]) if err := aip1640.Display(); err != nil { fmt.Println(err) } s++ if s > 2 { s = 0 } }) } robot := gobot.NewRobot("aip1640Bot", []gobot.Connection{firmataAdaptor}, []gobot.Device{aip1640}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/firmata_blink.go ================================================ //go:build example // +build example // // Do not build by default. /* How to run Pass serial port to use as the first param: go run examples/firmata_blink.go /dev/ttyACM0 */ package main import ( "fmt" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/firmata" ) func main() { firmataAdaptor := firmata.NewAdaptor(os.Args[1]) led := gpio.NewLedDriver(firmataAdaptor, "13") work := func() { gobot.Every(1*time.Second, func() { if err := led.Toggle(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("bot", []gobot.Connection{firmataAdaptor}, []gobot.Device{led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/firmata_blink_api.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/api" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/firmata" ) func main() { manager := gobot.NewManager() a := api.NewAPI(manager) a.Start() firmataAdaptor := firmata.NewAdaptor("/dev/ttyACM0") led := gpio.NewLedDriver(firmataAdaptor, "13") work := func() { gobot.Every(1*time.Second, func() { if err := led.Toggle(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("bot", []gobot.Connection{firmataAdaptor}, []gobot.Device{led}, work, ) manager.AddRobot(robot) if err := manager.Start(); err != nil { panic(err) } } ================================================ FILE: examples/firmata_blink_metal.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/firmata" ) // Example of a simple led toggle without the initialization of // the entire gobot framework. // This might be useful if you want to use gobot as another // golang library to interact with sensors and other devices. func main() { f := firmata.NewAdaptor("/dev/ttyACM0") if err := f.Connect(); err != nil { fmt.Println(err) } led := gpio.NewLedDriver(f, "13") if err := led.Start(); err != nil { fmt.Println(err) } for { if err := led.Toggle(); err != nil { fmt.Println(err) } time.Sleep(1000 * time.Millisecond) } } ================================================ FILE: examples/firmata_blink_robot.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/firmata" ) func main() { firmataAdaptor := firmata.NewAdaptor("/dev/ttyACM0") led := gpio.NewLedDriver(firmataAdaptor, "13") work := func() { gobot.Every(1*time.Second, func() { if err := led.Toggle(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("bot", []gobot.Connection{firmataAdaptor}, []gobot.Device{led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/firmata_blinkm.go ================================================ //go:build example // +build example // // Do not build by default. /* How to run Pass serial port to use as the first param: go run examples/firmata_blinkm.go /dev/ttyACM0 */ package main import ( "fmt" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/firmata" ) func main() { firmataAdaptor := firmata.NewAdaptor(os.Args[1]) blinkm := i2c.NewBlinkMDriver(firmataAdaptor) work := func() { gobot.Every(3*time.Second, func() { r := byte(gobot.Rand(255)) g := byte(gobot.Rand(255)) b := byte(gobot.Rand(255)) if err := blinkm.Rgb(r, g, b); err != nil { fmt.Println(err) } color, err := blinkm.Color() if err != nil { fmt.Println(err) } fmt.Printf("color %v\n", color) }) } robot := gobot.NewRobot("blinkmBot", []gobot.Connection{firmataAdaptor}, []gobot.Device{blinkm}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/firmata_bme280.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/firmata" ) func main() { firmataAdaptor := firmata.NewAdaptor(os.Args[1]) bme280 := i2c.NewBME280Driver(firmataAdaptor) work := func() { gobot.Every(1*time.Second, func() { t, _ := bme280.Temperature() fmt.Println("Temperature", t) p, _ := bme280.Pressure() fmt.Println("Pressure", p) a, _ := bme280.Altitude() fmt.Println("Altitude", a) h, _ := bme280.Humidity() fmt.Println("Humidity", h) }) } robot := gobot.NewRobot("bme280bot", []gobot.Connection{firmataAdaptor}, []gobot.Device{bme280}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/firmata_bmp180.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/firmata" ) func main() { firmataAdaptor := firmata.NewAdaptor(os.Args[1]) bmp180 := i2c.NewBMP180Driver(firmataAdaptor) work := func() { gobot.Every(1*time.Second, func() { t, _ := bmp180.Temperature() fmt.Println("Temperature", t) p, _ := bmp180.Pressure() fmt.Println("Pressure", p) }) } robot := gobot.NewRobot("bmp180bot", []gobot.Connection{firmataAdaptor}, []gobot.Device{bmp180}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/firmata_bmp280.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/firmata" ) func main() { firmataAdaptor := firmata.NewAdaptor(os.Args[1]) bmp280 := i2c.NewBMP280Driver(firmataAdaptor) work := func() { gobot.Every(1*time.Second, func() { t, _ := bmp280.Temperature() fmt.Println("Temperature", t) p, _ := bmp280.Pressure() fmt.Println("Pressure", p) a, _ := bmp280.Altitude() fmt.Println("Altitude", a) }) } robot := gobot.NewRobot("bmp280bot", []gobot.Connection{firmataAdaptor}, []gobot.Device{bmp280}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/firmata_button.go ================================================ //go:build example // +build example // // Do not build by default. /* How to run Pass serial port to use as the first param: go run examples/firmata_button.go /dev/ttyACM0 */ package main import ( "fmt" "os" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/firmata" ) func main() { firmataAdaptor := firmata.NewAdaptor(os.Args[1]) button := gpio.NewButtonDriver(firmataAdaptor, "2") led := gpio.NewLedDriver(firmataAdaptor, "3") work := func() { _ = button.On(gpio.ButtonPush, func(data interface{}) { if err := led.On(); err != nil { fmt.Println(err) } }) _ = button.On(gpio.ButtonRelease, func(data interface{}) { if err := led.Off(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("buttonBot", []gobot.Connection{firmataAdaptor}, []gobot.Device{button, led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/firmata_buzzer.go ================================================ //go:build example // +build example // // Do not build by default. /* How to run Pass serial port to use as the first param: go run examples/firmata_buzzer.go /dev/ttyACM0 */ package main import ( "fmt" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/firmata" ) func main() { firmataAdaptor := firmata.NewAdaptor(os.Args[1]) buzzer := gpio.NewBuzzerDriver(firmataAdaptor, "3") work := func() { type note struct { tone float64 duration float64 } song := []note{ {gpio.C4, gpio.Quarter}, {gpio.C4, gpio.Quarter}, {gpio.G4, gpio.Quarter}, {gpio.G4, gpio.Quarter}, {gpio.A4, gpio.Quarter}, {gpio.A4, gpio.Quarter}, {gpio.G4, gpio.Half}, {gpio.F4, gpio.Quarter}, {gpio.F4, gpio.Quarter}, {gpio.E4, gpio.Quarter}, {gpio.E4, gpio.Quarter}, {gpio.D4, gpio.Quarter}, {gpio.D4, gpio.Quarter}, {gpio.C4, gpio.Half}, } for _, val := range song { if err := buzzer.Tone(val.tone, val.duration); err != nil { fmt.Println(err) } time.Sleep(10 * time.Millisecond) } } robot := gobot.NewRobot("bot", []gobot.Connection{firmataAdaptor}, []gobot.Device{buzzer}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/firmata_cat_toy.go ================================================ //go:build example // +build example // // Do not build by default. /* How to run Pass serial port to use as the first param: go run examples/firmata_cat_toy.go /dev/ttyACM0 */ package main import ( "fmt" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/firmata" "gobot.io/x/gobot/v2/platforms/leap" ) func main() { firmataAdaptor := firmata.NewAdaptor(os.Args[1]) servo1 := gpio.NewServoDriver(firmataAdaptor, "5") servo2 := gpio.NewServoDriver(firmataAdaptor, "3") leapAdaptor := leap.NewAdaptor("127.0.0.1:6437") leapDriver := leap.NewDriver(leapAdaptor) work := func() { x := 90.0 z := 90.0 _ = leapDriver.On(leap.MessageEvent, func(data interface{}) { if len(data.(leap.Frame).Hands) > 0 { hand := data.(leap.Frame).Hands[0] x = gobot.ToScale(gobot.FromScale(hand.X(), -300, 300), 30, 150) z = gobot.ToScale(gobot.FromScale(hand.Z(), -300, 300), 30, 150) } }) gobot.Every(10*time.Millisecond, func() { if err := servo1.Move(uint8(x)); err != nil { fmt.Println(err) } if err := servo2.Move(uint8(z)); err != nil { fmt.Println(err) } fmt.Println("Current Angle: ", servo1.Angle(), ",", servo2.Angle()) }) } robot := gobot.NewRobot("pwmBot", []gobot.Connection{firmataAdaptor, leapAdaptor}, []gobot.Device{servo1, servo2, leapDriver}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/firmata_curie_imu.go ================================================ //go:build example // +build example // // Do not build by default. /* How to run Pass serial port to use as the first param: go run examples/firmata_curie_imu.go /dev/ttyACM0 */ package main import ( "fmt" "log" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/firmata" "gobot.io/x/gobot/v2/platforms/intel-iot/curie" ) func main() { firmataAdaptor := firmata.NewAdaptor(os.Args[1]) led := gpio.NewLedDriver(firmataAdaptor, "13") imu := curie.NewIMUDriver(firmataAdaptor) work := func() { _ = imu.On("Accelerometer", func(data interface{}) { log.Println("Accelerometer", data) }) _ = imu.On("Gyroscope", func(data interface{}) { log.Println("Gyroscope", data) }) _ = imu.On("Temperature", func(data interface{}) { log.Println("Temperature", data) }) _ = imu.On("Motion", func(data interface{}) { log.Println("Motion", data) }) gobot.Every(1*time.Second, func() { if err := led.Toggle(); err != nil { fmt.Println(err) } }) gobot.Every(100*time.Millisecond, func() { if err := imu.ReadAccelerometer(); err != nil { fmt.Println(err) } if err := imu.ReadGyroscope(); err != nil { fmt.Println(err) } if err := imu.ReadTemperature(); err != nil { fmt.Println(err) } if err := imu.ReadMotion(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("curieBot", []gobot.Connection{firmataAdaptor}, []gobot.Device{imu, led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/firmata_curie_imu_shock_detect.go ================================================ //go:build example // +build example // // Do not build by default. /* How to run Pass serial port to use as the first param: go run examples/firmata_curie_imu_shock_detect.go /dev/ttyACM0 */ package main import ( "fmt" "log" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/firmata" "gobot.io/x/gobot/v2/platforms/intel-iot/curie" ) func main() { firmataAdaptor := firmata.NewAdaptor(os.Args[1]) led := gpio.NewLedDriver(firmataAdaptor, "13") imu := curie.NewIMUDriver(firmataAdaptor) work := func() { _ = imu.On("Shock", func(data interface{}) { log.Println("Shock", data) }) gobot.Every(1*time.Second, func() { if err := led.Toggle(); err != nil { fmt.Println(err) } }) if err := imu.EnableShockDetection(true); err != nil { fmt.Println(err) } } robot := gobot.NewRobot("curieBot", []gobot.Connection{firmataAdaptor}, []gobot.Device{imu, led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/firmata_curie_imu_step_counter.go ================================================ //go:build example // +build example // // Do not build by default. /* How to run Pass serial port to use as the first param: go run examples/firmata_curie_imu_step_counter.go /dev/ttyACM0 */ package main import ( "fmt" "log" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/firmata" "gobot.io/x/gobot/v2/platforms/intel-iot/curie" ) func main() { firmataAdaptor := firmata.NewAdaptor(os.Args[1]) led := gpio.NewLedDriver(firmataAdaptor, "13") imu := curie.NewIMUDriver(firmataAdaptor) work := func() { _ = imu.On("Steps", func(data interface{}) { log.Println("Steps", data) }) gobot.Every(1*time.Second, func() { if err := led.Toggle(); err != nil { fmt.Println(err) } }) if err := imu.EnableStepCounter(true); err != nil { fmt.Println(err) } } robot := gobot.NewRobot("curieBot", []gobot.Connection{firmataAdaptor}, []gobot.Device{imu, led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/firmata_curie_imu_tap_detect.go ================================================ //go:build example // +build example // // Do not build by default. /* How to run Pass serial port to use as the first param: go run examples/firmata_curie_imu_tap_detect.go /dev/ttyACM0 */ package main import ( "fmt" "log" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/firmata" "gobot.io/x/gobot/v2/platforms/intel-iot/curie" ) func main() { firmataAdaptor := firmata.NewAdaptor(os.Args[1]) led := gpio.NewLedDriver(firmataAdaptor, "13") imu := curie.NewIMUDriver(firmataAdaptor) work := func() { _ = imu.On("Tap", func(data interface{}) { log.Println("Tap", data) }) gobot.Every(1*time.Second, func() { if err := led.Toggle(); err != nil { fmt.Println(err) } }) if err := imu.EnableTapDetection(true); err != nil { fmt.Println(err) } } robot := gobot.NewRobot("curieBot", []gobot.Connection{firmataAdaptor}, []gobot.Device{imu, led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/firmata_direct_pin.go ================================================ //go:build example // +build example // // Do not build by default. /* How to run Pass serial port to use as the first param: go run examples/firmata_direct_pin.go /dev/ttyACM0 */ package main import ( "fmt" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/firmata" ) func main() { firmataAdaptor := firmata.NewAdaptor(os.Args[1]) pin := gpio.NewDirectPinDriver(firmataAdaptor, "13") work := func() { level := byte(1) gobot.Every(1*time.Second, func() { if err := pin.DigitalWrite(level); err != nil { fmt.Println(err) } if level == 1 { level = 0 } else { level = 1 } }) } robot := gobot.NewRobot("pinBot", []gobot.Connection{firmataAdaptor}, []gobot.Device{pin}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/firmata_gpio_max7219.go ================================================ //go:build example // +build example // // Do not build by default. /* How to setup This examples requires you to daisy-chain 4 led matrices based on MAX7219. It will turn on one led at a time, from the first led at the first matrix to the last led of the last matrix. How to run Pass serial port to use as the first param: go run examples/firmata_gpio_max7219.go /dev/ttyACM0 */ package main import ( "fmt" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/firmata" ) func main() { firmataAdaptor := firmata.NewAdaptor(os.Args[1]) maxim := gpio.NewMAX7219Driver(firmataAdaptor, "11", "10", "9", 4) var digit byte = 1 // digit address goes from 0x01 (MAX7219Digit0) to 0x08 (MAX7219Digit8) var bits byte = 1 var module uint count := 0 work := func() { gobot.Every(100*time.Millisecond, func() { if err := maxim.ClearAll(); err != nil { fmt.Println(err) } if err := maxim.One(module, digit, bits); err != nil { fmt.Println(err) } bits = bits << 1 count++ if count > 7 { count = 0 digit++ bits = 1 if digit > 8 { digit = 1 module++ if module >= 4 { module = 0 count = 0 } } } }) } robot := gobot.NewRobot("Max7219Bot", []gobot.Connection{firmataAdaptor}, []gobot.Device{maxim}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/firmata_grove_lcd.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/firmata" ) func main() { board := firmata.NewAdaptor(os.Args[1]) screen := i2c.NewGroveLcdDriver(board) work := func() { if err := screen.Write("hello"); err != nil { fmt.Println(err) } if err := screen.SetRGB(255, 0, 0); err != nil { fmt.Println(err) } gobot.After(5*time.Second, func() { if err := screen.Clear(); err != nil { fmt.Println(err) } if err := screen.Home(); err != nil { fmt.Println(err) } if err := screen.SetRGB(0, 255, 0); err != nil { fmt.Println(err) } // set a custom character in the first position if err := screen.SetCustomChar(0, i2c.CustomLCDChars["smiley"]); err != nil { fmt.Println(err) } // add the custom character at the end of the string if err := screen.Write("goodbye\nhave a nice day " + string(byte(0))); err != nil { fmt.Println(err) } gobot.Every(500*time.Millisecond, func() { if err := screen.Scroll(false); err != nil { fmt.Println(err) } }) }) if err := screen.Home(); err != nil { fmt.Println(err) } time.Sleep(1 * time.Second) if err := screen.SetRGB(0, 0, 255); err != nil { fmt.Println(err) } } robot := gobot.NewRobot("screenBot", []gobot.Connection{board}, []gobot.Device{screen}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/firmata_grove_sound_sensor.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" "gobot.io/x/gobot/v2/platforms/firmata" ) func main() { board := firmata.NewAdaptor(os.Args[1]) sensor := aio.NewGroveSoundSensorDriver(board, "3", aio.WithSensorCyclicRead(500*time.Millisecond)) work := func() { _ = sensor.On(aio.Data, func(data interface{}) { fmt.Println("sensor", data) }) } robot := gobot.NewRobot("sensorBot", []gobot.Connection{board}, []gobot.Device{sensor}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/firmata_hmc6352.go ================================================ //go:build example // +build example // // Do not build by default. /* How to run Pass serial port to use as the first param: go run examples/firmata_hmc6352.go /dev/ttyACM0 */ package main import ( "fmt" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/firmata" ) func main() { firmataAdaptor := firmata.NewAdaptor(os.Args[1]) hmc6352 := i2c.NewHMC6352Driver(firmataAdaptor) work := func() { gobot.Every(100*time.Millisecond, func() { heading, _ := hmc6352.Heading() fmt.Println("Heading", heading) }) } robot := gobot.NewRobot("hmc6352Bot", []gobot.Connection{firmataAdaptor}, []gobot.Device{hmc6352}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/firmata_integration.go ================================================ //go:build example // +build example // // Do not build by default. /* How to run Pass serial port to use as the first param: go run examples/firmata_integration.go /dev/ttyACM0 */ package main import ( "fmt" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/firmata" ) func main() { firmataAdaptor := firmata.NewAdaptor(os.Args[1]) led1 := gpio.NewLedDriver(firmataAdaptor, "3") led2 := gpio.NewLedDriver(firmataAdaptor, "4") button := gpio.NewButtonDriver(firmataAdaptor, "2") sensor := aio.NewAnalogSensorDriver(firmataAdaptor, "0", aio.WithSensorCyclicRead(500*time.Millisecond)) work := func() { gobot.Every(1*time.Second, func() { if err := led1.Toggle(); err != nil { fmt.Println(err) } }) gobot.Every(2*time.Second, func() { if err := led2.Toggle(); err != nil { fmt.Println(err) } }) _ = button.On(gpio.ButtonPush, func(data interface{}) { if err := led2.On(); err != nil { fmt.Println(err) } }) _ = button.On(gpio.ButtonRelease, func(data interface{}) { if err := led2.Off(); err != nil { fmt.Println(err) } }) _ = sensor.On(aio.Data, func(data interface{}) { fmt.Println("sensor", data) }) } robot := gobot.NewRobot("bot", []gobot.Connection{firmataAdaptor}, []gobot.Device{led1, led2, button, sensor}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/firmata_led_brightness.go ================================================ //go:build example // +build example // // Do not build by default. /* How to run Pass serial port to use as the first param: go run examples/firmata_led_brightness.go /dev/ttyACM0 */ package main import ( "fmt" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/firmata" ) func main() { firmataAdaptor := firmata.NewAdaptor(os.Args[1]) led := gpio.NewLedDriver(firmataAdaptor, "3") work := func() { brightness := uint8(0) fadeAmount := uint8(15) gobot.Every(100*time.Millisecond, func() { if err := led.Brightness(brightness); err != nil { fmt.Println(err) } brightness = brightness + fadeAmount if brightness == 0 || brightness == 255 { fadeAmount = -fadeAmount } }) } robot := gobot.NewRobot("pwmBot", []gobot.Connection{firmataAdaptor}, []gobot.Device{led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/firmata_led_brightness_with_analog_input.go ================================================ //go:build example // +build example // // Do not build by default. /* How to run Pass serial port to use as the first param: go run examples/firmata_led_brightness_with_analog_input.go /dev/ttyACM0 */ package main import ( "fmt" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/firmata" ) func main() { firmataAdaptor := firmata.NewAdaptor(os.Args[1]) sensor := aio.NewAnalogSensorDriver(firmataAdaptor, "0", aio.WithSensorCyclicRead(500*time.Millisecond)) led := gpio.NewLedDriver(firmataAdaptor, "3") work := func() { _ = sensor.On(aio.Data, func(data interface{}) { brightness := uint8( gobot.ToScale(gobot.FromScale(float64(data.(int)), 0, 1024), 0, 255), ) fmt.Println("sensor", data) fmt.Println("brightness", brightness) if err := led.Brightness(brightness); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("sensorBot", []gobot.Connection{firmataAdaptor}, []gobot.Device{sensor, led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/firmata_lidarlite.go ================================================ //go:build example // +build example // // Do not build by default. /* How to run Pass serial port to use as the first param: go run examples/firmata_lidarlite.go /dev/ttyACM0 */ package main import ( "fmt" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/firmata" ) func main() { firmataAdaptor := firmata.NewAdaptor(os.Args[1]) lidar := i2c.NewLIDARLiteDriver(firmataAdaptor) work := func() { gobot.Every(100*time.Millisecond, func() { distance, _ := lidar.Distance() fmt.Println("Distance", distance) }) } robot := gobot.NewRobot("lidarbot", []gobot.Connection{firmataAdaptor}, []gobot.Device{lidar}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/firmata_metal_button.go ================================================ //go:build example // +build example // // Do not build by default. // TO RUN: // // firmata_metal_button // // EXAMPLE: // // go run ./examples/firmata_metal_button /dev/ttyACM0 package main import ( "fmt" "os" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/firmata" ) func main() { f := firmata.NewAdaptor(os.Args[1]) if err := f.Connect(); err != nil { fmt.Println(err) } led := gpio.NewLedDriver(f, "2") if err := led.Start(); err != nil { fmt.Println(err) } if err := led.Off(); err != nil { fmt.Println(err) } button := gpio.NewButtonDriver(f, "3") if err := button.Start(); err != nil { fmt.Println(err) } buttonEvents := button.Subscribe() for event := range buttonEvents { fmt.Println("Event:", event.Name, event.Data) if event.Name == gpio.ButtonPush { if err := led.Toggle(); err != nil { fmt.Println(err) } } } } ================================================ FILE: examples/firmata_mma7660.go ================================================ //go:build example // +build example // // Do not build by default. /* How to run Pass serial port to use as the first param: go run examples/firmata_mma7660.go /dev/ttyACM0 */ package main import ( "fmt" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/firmata" ) func main() { firmataAdaptor := firmata.NewAdaptor(os.Args[1]) mma7660 := i2c.NewMMA7660Driver(firmataAdaptor) work := func() { gobot.Every(500*time.Millisecond, func() { if x, y, z, err := mma7660.XYZ(); err == nil { fmt.Println(x, y, z) fmt.Println(mma7660.Acceleration(x, y, z)) } else { fmt.Println(err) } }) } robot := gobot.NewRobot("mma76602Bot", []gobot.Connection{firmataAdaptor}, []gobot.Device{mma7660}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/firmata_motor.go ================================================ //go:build example // +build example // // Do not build by default. /* How to run Pass serial port to use as the first param: go run examples/firmata_motor.go /dev/ttyACM0 */ package main import ( "fmt" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/firmata" ) func main() { firmataAdaptor := firmata.NewAdaptor(os.Args[1]) motor := gpio.NewMotorDriver(firmataAdaptor, "3") work := func() { speed := byte(0) fadeAmount := byte(15) gobot.Every(100*time.Millisecond, func() { if err := motor.SetSpeed(speed); err != nil { fmt.Println(err) } speed = speed + fadeAmount if speed == 0 || speed == 255 { fadeAmount = -fadeAmount } }) } robot := gobot.NewRobot("motorBot", []gobot.Connection{firmataAdaptor}, []gobot.Device{motor}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/firmata_mpl115a2.go ================================================ //go:build example // +build example // // Do not build by default. /* How to run Pass serial port to use as the first param: go run examples/firmata_mpl115a2.go /dev/ttyACM0 */ package main import ( "fmt" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/firmata" ) func main() { firmataAdaptor := firmata.NewAdaptor(os.Args[1]) mpl115a2 := i2c.NewMPL115A2Driver(firmataAdaptor) work := func() { gobot.Every(1*time.Second, func() { press, _ := mpl115a2.Pressure() fmt.Println("Pressure", press) temp, _ := mpl115a2.Temperature() fmt.Println("Temperature", temp) }) } robot := gobot.NewRobot("mpl115a2Bot", []gobot.Connection{firmataAdaptor}, []gobot.Device{mpl115a2}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/firmata_mpu6050.go ================================================ //go:build example // +build example // // Do not build by default. /* How to run Pass serial port to use as the first param: go run examples/firmata_mpu6050.go /dev/ttyACM0 */ package main import ( "fmt" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/firmata" ) func main() { firmataAdaptor := firmata.NewAdaptor(os.Args[1]) mpu6050 := i2c.NewMPU6050Driver(firmataAdaptor) work := func() { gobot.Every(100*time.Millisecond, func() { if err := mpu6050.GetData(); err != nil { fmt.Println(err) } fmt.Println("Accelerometer", mpu6050.Accelerometer) fmt.Println("Gyroscope", mpu6050.Gyroscope) fmt.Println("Temperature", mpu6050.Temperature) }) } robot := gobot.NewRobot("mpu6050Bot", []gobot.Connection{firmataAdaptor}, []gobot.Device{mpu6050}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/firmata_pca9685.go ================================================ //go:build example // +build example // // Do not build by default. /* How to run Pass serial port to use as the first param: go run examples/firmata_pca9685.go /dev/ttyACM0 */ //nolint:gosec // ok here package main import ( "fmt" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/firmata" ) func main() { firmataAdaptor := firmata.NewAdaptor(os.Args[1]) pca9685 := i2c.NewPCA9685Driver(firmataAdaptor) servo := gpio.NewServoDriver(pca9685, "15") work := func() { if err := pca9685.SetPWMFreq(60); err != nil { fmt.Println(err) } for i := 10; i < 150; i += 10 { fmt.Println("Turning", i) if err := servo.Move(uint8(i)); err != nil { fmt.Println(err) } time.Sleep(1 * time.Second) } for i := 150; i > 10; i -= 10 { fmt.Println("Turning", i) if err := servo.Move(uint8(i)); err != nil { fmt.Println(err) } time.Sleep(1 * time.Second) } } robot := gobot.NewRobot("servoBot", []gobot.Connection{firmataAdaptor}, []gobot.Device{pca9685, servo}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/firmata_pir_motion.go ================================================ //go:build example // +build example // // Do not build by default. /* How to run Pass serial port to use as the first param: go run examples/firmata_pir_motion.go /dev/ttyACM0 */ package main import ( "fmt" "os" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/firmata" ) func main() { firmataAdaptor := firmata.NewAdaptor(os.Args[1]) sensor := gpio.NewPIRMotionDriver(firmataAdaptor, "5") led := gpio.NewLedDriver(firmataAdaptor, "13") work := func() { _ = sensor.On(gpio.MotionDetected, func(data interface{}) { fmt.Println(gpio.MotionDetected) if err := led.On(); err != nil { fmt.Println(err) } }) _ = sensor.On(gpio.MotionStopped, func(data interface{}) { fmt.Println(gpio.MotionStopped) if err := led.Off(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("motionBot", []gobot.Connection{firmataAdaptor}, []gobot.Device{sensor, led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/firmata_rgb_led.go ================================================ //go:build example // +build example // // Do not build by default. /* How to run Pass serial port to use as the first param: go run examples/firmata_rgb_led.go /dev/ttyACM0 */ //nolint:gosec // ok here package main import ( "fmt" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/firmata" ) func main() { board := firmata.NewAdaptor(os.Args[1]) led := gpio.NewRgbLedDriver(board, "3", "5", "6") work := func() { gobot.Every(1*time.Second, func() { r := uint8(gobot.Rand(255)) g := uint8(gobot.Rand(255)) b := uint8(gobot.Rand(255)) if err := led.SetRGB(r, g, b); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("rgbBot", []gobot.Connection{board}, []gobot.Device{led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/firmata_servo.go ================================================ //go:build example // +build example // // Do not build by default. /* How to run Pass serial port to use as the first param: go run examples/firmata_servo.go /dev/ttyACM0 */ //nolint:gosec // ok here package main import ( "fmt" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/firmata" ) func main() { firmataAdaptor := firmata.NewAdaptor(os.Args[1]) servo := gpio.NewServoDriver(firmataAdaptor, "3") work := func() { gobot.Every(1*time.Second, func() { i := uint8(gobot.Rand(180)) fmt.Println("Turning", i) if err := servo.Move(i); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("servoBot", []gobot.Connection{firmataAdaptor}, []gobot.Device{servo}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/firmata_ssd1306.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/firmata" ) func main() { width := 128 height := 64 r := firmata.NewAdaptor(os.Args[1]) oled := i2c.NewSSD1306Driver(r, i2c.WithAddress(0x3c), i2c.WithSSD1306DisplayWidth(width), i2c.WithSSD1306DisplayHeight(height)) stage := false work := func() { gobot.Every(1*time.Second, func() { fmt.Println("displaying") oled.Clear() if stage { for x := 0; x < width; x += 5 { for y := 0; y < height; y++ { oled.Set(x, y, 1) } } } stage = !stage if err := oled.Display(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("ssd1306Robot", []gobot.Connection{r}, []gobot.Device{oled}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/firmata_temp36.go ================================================ //go:build example // +build example // // Do not build by default. /* How to run Pass serial port to use as the first param: go run examples/firmata_temp36.go /dev/ttyACM0 */ package main import ( "fmt" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/firmata" ) func main() { firmataAdaptor := firmata.NewAdaptor(os.Args[1]) work := func() { gobot.Every(1*time.Second, func() { val, err := firmataAdaptor.AnalogRead("0") if err != nil { fmt.Println(err) return } voltage := (float64(val) * 5) / 1024 // if using 3.3V replace 5 with 3.3 tempC := (voltage - 0.5) * 100 tempF := (tempC * 9 / 5) + 32 fmt.Printf("%.2f°C\n", tempC) fmt.Printf("%.2f°F\n", tempF) }) } robot := gobot.NewRobot("sensorBot", []gobot.Connection{firmataAdaptor}, []gobot.Device{}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/firmata_tm1638.go ================================================ //go:build example // +build example // // Do not build by default. /* How to run Pass serial port to use as the first param: go run examples/firmata_tm1638.go /dev/ttyACM0 */ package main import ( "fmt" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/firmata" ) func main() { firmataAdaptor := firmata.NewAdaptor(os.Args[1]) // Even thought the modules are connected among them, they are independent (not chained) modules := make([]*gpio.TM1638Driver, 4) modules[0] = gpio.NewTM1638Driver(firmataAdaptor, "9", "8", "7") modules[1] = gpio.NewTM1638Driver(firmataAdaptor, "9", "8", "6") modules[2] = gpio.NewTM1638Driver(firmataAdaptor, "9", "8", "5") modules[3] = gpio.NewTM1638Driver(firmataAdaptor, "9", "8", "4") var ledInt byte var color byte var offset int // Repeat and concat strings until long enough that with scroll it still shows text const showText = " HELLO WORLD - gobot.io - TM1638 " text := showText for len(text)-len(showText) < len(modules)*8 { text += showText } work := func() { gobot.Every(400*time.Millisecond, func() { // Enable and change the color of the LEDs if err := modules[0].SetLED(color, ledInt); err != nil { fmt.Println(err) } if err := modules[1].SetLED(color, ledInt); err != nil { fmt.Println(err) } if err := modules[2].SetLED(color, ledInt); err != nil { fmt.Println(err) } if err := modules[3].SetLED(color, ledInt); err != nil { fmt.Println(err) } ledInt++ if ledInt > 7 { ledInt = 0 color++ if color > 2 { color = 0 } } // Scroll the text for i := 0; i < 4; i++ { if err := modules[i].SetDisplayText(text[offset+8*i : offset+8*i+8]); err != nil { fmt.Println(err) } } offset++ if offset >= len(showText) { offset = 0 } }) } robot := gobot.NewRobot("tm1638Bot", []gobot.Connection{firmataAdaptor}, []gobot.Device{modules[0], modules[1], modules[2], modules[3]}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/firmata_travis.go ================================================ //go:build example // +build example // // Do not build by default. /* How to run Pass serial port to use as the first param: go run examples/firmata_travis.go /dev/ttyACM0 */ package main import ( "encoding/json" "fmt" "io" "net/http" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/firmata" ) type TravisResponse struct { ID int `json:"id"` Slug string `json:"slug"` Description string `json:"description"` PublicKey string `json:"public_key"` LastBuildID int `json:"last_build_id"` LastBuildNumber string `json:"last_build_number"` LastBuildStatus int `json:"last_build_status"` LastBuildResult int `json:"last_build_result"` LastBuildDuration int `json:"last_build_duration"` LastBuildLanguage string `json:"last_build_language"` LastBuildStartedAt string `json:"last_build_started_at"` LastBuildFinishedAt string `json:"last_build_finished_at"` } func turnOn(robot *gobot.Robot, device string) { if err := robot.Device(device).(*gpio.LedDriver).On(); err != nil { fmt.Println(err) } } func resetLeds(robot *gobot.Robot) { if err := robot.Device("red").(*gpio.LedDriver).Off(); err != nil { fmt.Println(err) } if err := robot.Device("green").(*gpio.LedDriver).Off(); err != nil { fmt.Println(err) } if err := robot.Device("blue").(*gpio.LedDriver).Off(); err != nil { fmt.Println(err) } } func checkTravis(robot *gobot.Robot) { resetLeds(robot) user := "hybridgroup" name := "gobot" // name := "broken-arrow" fmt.Printf("Checking repo %s/%s\n", user, name) turnOn(robot, "blue") resp, err := http.Get(fmt.Sprintf("https://api.travis-ci.org/repos/%s/%s.json", user, name)) if err != nil { panic(err) } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { panic(err) } var travis TravisResponse if err := json.Unmarshal(body, &travis); err != nil { fmt.Println(err) } resetLeds(robot) if travis.LastBuildStatus == 0 { turnOn(robot, "green") } else { turnOn(robot, "red") } } func main() { manager := gobot.NewManager() firmataAdaptor := firmata.NewAdaptor(os.Args[1]) red := gpio.NewLedDriver(firmataAdaptor, "7", gpio.WithName("red")) green := gpio.NewLedDriver(firmataAdaptor, "6", gpio.WithName("green")) blue := gpio.NewLedDriver(firmataAdaptor, "5", gpio.WithName("blue")) work := func() { checkTravis(manager.Robot("travis")) gobot.Every(10*time.Second, func() { checkTravis(manager.Robot("travis")) }) } robot := gobot.NewRobot("travis", []gobot.Connection{firmataAdaptor}, []gobot.Device{red, green, blue}, work, ) manager.AddRobot(robot) if err := manager.Start(); err != nil { panic(err) } } ================================================ FILE: examples/firmata_wiichuck.go ================================================ //go:build example // +build example // // Do not build by default. /* How to run Pass serial port to use as the first param: go run examples/firmata_wiichuck.go /dev/ttyACM0 */ package main import ( "fmt" "os" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/firmata" ) func main() { firmataAdaptor := firmata.NewAdaptor(os.Args[1]) wiichuck := i2c.NewWiichuckDriver(firmataAdaptor) work := func() { _ = wiichuck.On(wiichuck.Event("joystick"), func(data interface{}) { fmt.Println("joystick", data) }) _ = wiichuck.On(wiichuck.Event("c"), func(data interface{}) { fmt.Println("c") }) _ = wiichuck.On(wiichuck.Event("z"), func(data interface{}) { fmt.Println("z") }) _ = wiichuck.On(wiichuck.Event("error"), func(data interface{}) { fmt.Println("Wiichuck error:", data) }) } robot := gobot.NewRobot("chuck", []gobot.Connection{firmataAdaptor}, []gobot.Device{wiichuck}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/gopigo3.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/dexter/gopigo3" "gobot.io/x/gobot/v2/platforms/raspi" ) func main() { raspiAdaptor := raspi.NewAdaptor() gpg3 := gopigo3.NewDriver(raspiAdaptor) work := func() { on := uint8(0xFF) gobot.Every(1000*time.Millisecond, func() { err := gpg3.SetLED(gopigo3.LED_EYE_RIGHT, 0x00, 0x00, on) if err != nil { fmt.Println(err) } err = gpg3.SetLED(gopigo3.LED_EYE_LEFT, ^on, 0x00, 0x00) if err != nil { fmt.Println(err) } on = ^on }) } robot := gobot.NewRobot("gopigo3eyeleds", []gobot.Connection{raspiAdaptor}, []gobot.Device{gpg3}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/gopigo3_grove_button.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/dexter/gopigo3" "gobot.io/x/gobot/v2/platforms/raspi" ) func main() { raspiAdaptor := raspi.NewAdaptor() gpg3 := gopigo3.NewDriver(raspiAdaptor) led := gpio.NewLedDriver(gpg3, "AD_1_1") button := gpio.NewButtonDriver(gpg3, "AD_2_1") work := func() { _ = button.On(gpio.ButtonPush, func(data interface{}) { fmt.Println("On!") if err := led.On(); err != nil { fmt.Println(err) } }) _ = button.On(gpio.ButtonRelease, func(data interface{}) { fmt.Println("Off!") if err := led.Off(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("gopigo3button", []gobot.Connection{raspiAdaptor}, []gobot.Device{gpg3, button, led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/gopigo3_grove_lcd.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/dexter/gopigo3" "gobot.io/x/gobot/v2/platforms/raspi" ) func main() { raspiAdaptor := raspi.NewAdaptor() gpg3 := gopigo3.NewDriver(raspiAdaptor) screen := i2c.NewGroveLcdDriver(raspiAdaptor) work := func() { manufacturerName, _ := gpg3.GetManufacturerName() boardName, _ := gpg3.GetBoardName() hardwareVersion, _ := gpg3.GetHardwareVersion() if err := screen.Write(manufacturerName[0:15]); err != nil { fmt.Println(err) } if err := screen.SetPosition(16); err != nil { fmt.Println(err) } if err := screen.Write(boardName + " " + hardwareVersion); err != nil { fmt.Println(err) } if err := screen.SetRGB(0, 0, 255); err != nil { fmt.Println(err) } if err := screen.Home(); err != nil { fmt.Println(err) } } robot := gobot.NewRobot("gopigo3lcd", []gobot.Connection{raspiAdaptor}, []gobot.Device{gpg3, screen}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/gopigo3_grove_light_sensor.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" "gobot.io/x/gobot/v2/platforms/dexter/gopigo3" "gobot.io/x/gobot/v2/platforms/raspi" ) func main() { raspiAdaptor := raspi.NewAdaptor() gpg3 := gopigo3.NewDriver(raspiAdaptor) sensor := aio.NewGroveLightSensorDriver(gpg3, "AD_1_1", aio.WithSensorCyclicRead(500*time.Millisecond)) work := func() { _ = sensor.On(sensor.Event("data"), func(data interface{}) { fmt.Println("sensor", data) }) } robot := gobot.NewRobot("gopigo3sensor", []gobot.Connection{raspiAdaptor}, []gobot.Device{gpg3, sensor}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/gopigo3_led_brightness.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/dexter/gopigo3" "gobot.io/x/gobot/v2/platforms/raspi" ) func main() { raspiAdaptor := raspi.NewAdaptor() gpg3 := gopigo3.NewDriver(raspiAdaptor) led := gpio.NewLedDriver(gpg3, "AD_1_1") work := func() { brightness := uint8(0) fadeAmount := uint8(15) gobot.Every(100*time.Millisecond, func() { if err := led.Brightness(brightness); err != nil { fmt.Println(err) } brightness = brightness + fadeAmount if brightness == 0 || brightness == 255 { fadeAmount = -fadeAmount } }) } robot := gobot.NewRobot("gopigo3pwm", []gobot.Connection{raspiAdaptor}, []gobot.Device{gpg3, led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/gopigo3_servo.go ================================================ //go:build example // +build example // // Do not build by default. //nolint:gosec // ok here package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/dexter/gopigo3" "gobot.io/x/gobot/v2/platforms/raspi" ) func main() { raspiAdaptor := raspi.NewAdaptor() gpg3 := gopigo3.NewDriver(raspiAdaptor) servo := gpio.NewServoDriver(gpg3, "SERVO_1") work := func() { gobot.Every(1*time.Second, func() { i := uint8(gobot.Rand(180)) fmt.Println("Turning", i) if err := servo.Move(i); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("gopigo3servo", []gobot.Connection{raspiAdaptor}, []gobot.Device{gpg3, servo}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/haarcascade_frontalface_alt.xml ================================================ 20 20 <_> <_> <_> <_>3 7 14 4 -1. <_>3 9 14 2 2. 0 4.0141958743333817e-003 0.0337941907346249 0.8378106951713562 <_> <_> <_>1 2 18 4 -1. <_>7 2 6 4 3. 0 0.0151513395830989 0.1514132022857666 0.7488812208175659 <_> <_> <_>1 7 15 9 -1. <_>1 10 15 3 3. 0 4.2109931819140911e-003 0.0900492817163467 0.6374819874763489 0.8226894140243530 -1 -1 <_> <_> <_> <_>5 6 2 6 -1. <_>5 9 2 3 2. 0 1.6227109590545297e-003 0.0693085864186287 0.7110946178436279 <_> <_> <_>7 5 6 3 -1. <_>9 5 2 3 3. 0 2.2906649392098188e-003 0.1795803010463715 0.6668692231178284 <_> <_> <_>4 0 12 9 -1. <_>4 3 12 3 3. 0 5.0025708042085171e-003 0.1693672984838486 0.6554006934165955 <_> <_> <_>6 9 10 8 -1. <_>6 13 10 4 2. 0 7.9659894108772278e-003 0.5866332054138184 0.0914145186543465 <_> <_> <_>3 6 14 8 -1. <_>3 10 14 4 2. 0 -3.5227010957896709e-003 0.1413166970014572 0.6031895875930786 <_> <_> <_>14 1 6 10 -1. <_>14 1 3 10 2. 0 0.0366676896810532 0.3675672113895416 0.7920318245887756 <_> <_> <_>7 8 5 12 -1. <_>7 12 5 4 3. 0 9.3361474573612213e-003 0.6161385774612427 0.2088509947061539 <_> <_> <_>1 1 18 3 -1. <_>7 1 6 3 3. 0 8.6961314082145691e-003 0.2836230993270874 0.6360273957252502 <_> <_> <_>1 8 17 2 -1. <_>1 9 17 1 2. 0 1.1488880263641477e-003 0.2223580926656723 0.5800700783729553 <_> <_> <_>16 6 4 2 -1. <_>16 7 4 1 2. 0 -2.1484689787030220e-003 0.2406464070081711 0.5787054896354675 <_> <_> <_>5 17 2 2 -1. <_>5 18 2 1 2. 0 2.1219060290604830e-003 0.5559654831886292 0.1362237036228180 <_> <_> <_>14 2 6 12 -1. <_>14 2 3 12 2. 0 -0.0939491465687752 0.8502737283706665 0.4717740118503571 <_> <_> <_>4 0 4 12 -1. <_>4 0 2 6 2. <_>6 6 2 6 2. 0 1.3777789426967502e-003 0.5993673801422119 0.2834529876708984 <_> <_> <_>2 11 18 8 -1. <_>8 11 6 8 3. 0 0.0730631574988365 0.4341886043548584 0.7060034275054932 <_> <_> <_>5 7 10 2 -1. <_>5 8 10 1 2. 0 3.6767389974556863e-004 0.3027887940406799 0.6051574945449829 <_> <_> <_>15 11 5 3 -1. <_>15 12 5 1 3. 0 -6.0479710809886456e-003 0.1798433959484100 0.5675256848335266 6.9566087722778320 0 -1 <_> <_> <_> <_>5 3 10 9 -1. <_>5 6 10 3 3. 0 -0.0165106896311045 0.6644225120544434 0.1424857974052429 <_> <_> <_>9 4 2 14 -1. <_>9 11 2 7 2. 0 2.7052499353885651e-003 0.6325352191925049 0.1288477033376694 <_> <_> <_>3 5 4 12 -1. <_>3 9 4 4 3. 0 2.8069869149476290e-003 0.1240288019180298 0.6193193197250366 <_> <_> <_>4 5 12 5 -1. <_>8 5 4 5 3. 0 -1.5402400167658925e-003 0.1432143002748489 0.5670015811920166 <_> <_> <_>5 6 10 8 -1. <_>5 10 10 4 2. 0 -5.6386279175058007e-004 0.1657433062791824 0.5905207991600037 <_> <_> <_>8 0 6 9 -1. <_>8 3 6 3 3. 0 1.9253729842603207e-003 0.2695507109165192 0.5738824009895325 <_> <_> <_>9 12 1 8 -1. <_>9 16 1 4 2. 0 -5.0214841030538082e-003 0.1893538981676102 0.5782774090766907 <_> <_> <_>0 7 20 6 -1. <_>0 9 20 2 3. 0 2.6365420781075954e-003 0.2309329062700272 0.5695425868034363 <_> <_> <_>7 0 6 17 -1. <_>9 0 2 17 3. 0 -1.5127769438549876e-003 0.2759602069854736 0.5956642031669617 <_> <_> <_>9 0 6 4 -1. <_>11 0 2 4 3. 0 -0.0101574398577213 0.1732538044452667 0.5522047281265259 <_> <_> <_>5 1 6 4 -1. <_>7 1 2 4 3. 0 -0.0119536602869630 0.1339409947395325 0.5559014081954956 <_> <_> <_>12 1 6 16 -1. <_>14 1 2 16 3. 0 4.8859491944313049e-003 0.3628703951835632 0.6188849210739136 <_> <_> <_>0 5 18 8 -1. <_>0 5 9 4 2. <_>9 9 9 4 2. 0 -0.0801329165697098 0.0912110507488251 0.5475944876670837 <_> <_> <_>8 15 10 4 -1. <_>13 15 5 2 2. <_>8 17 5 2 2. 0 1.0643280111253262e-003 0.3715142905712128 0.5711399912834168 <_> <_> <_>3 1 4 8 -1. <_>3 1 2 4 2. <_>5 5 2 4 2. 0 -1.3419450260698795e-003 0.5953313708305359 0.3318097889423370 <_> <_> <_>3 6 14 10 -1. <_>10 6 7 5 2. <_>3 11 7 5 2. 0 -0.0546011403203011 0.1844065934419632 0.5602846145629883 <_> <_> <_>2 1 6 16 -1. <_>4 1 2 16 3. 0 2.9071690514683723e-003 0.3594244122505188 0.6131715178489685 <_> <_> <_>0 18 20 2 -1. <_>0 19 20 1 2. 0 7.4718717951327562e-004 0.5994353294372559 0.3459562957286835 <_> <_> <_>8 13 4 3 -1. <_>8 14 4 1 3. 0 4.3013808317482471e-003 0.4172652065753937 0.6990845203399658 <_> <_> <_>9 14 2 3 -1. <_>9 15 2 1 3. 0 4.5017572119832039e-003 0.4509715139865875 0.7801457047462463 <_> <_> <_>0 12 9 6 -1. <_>0 14 9 2 3. 0 0.0241385009139776 0.5438212752342224 0.1319826990365982 9.4985427856445313 1 -1 <_> <_> <_> <_>5 7 3 4 -1. <_>5 9 3 2 2. 0 1.9212230108678341e-003 0.1415266990661621 0.6199870705604553 <_> <_> <_>9 3 2 16 -1. <_>9 11 2 8 2. 0 -1.2748669541906565e-004 0.6191074252128601 0.1884928941726685 <_> <_> <_>3 6 13 8 -1. <_>3 10 13 4 2. 0 5.1409931620582938e-004 0.1487396955490112 0.5857927799224854 <_> <_> <_>12 3 8 2 -1. <_>12 3 4 2 2. 0 4.1878609918057919e-003 0.2746909856796265 0.6359239816665649 <_> <_> <_>8 8 4 12 -1. <_>8 12 4 4 3. 0 5.1015717908740044e-003 0.5870851278305054 0.2175628989934921 <_> <_> <_>11 3 8 6 -1. <_>15 3 4 3 2. <_>11 6 4 3 2. 0 -2.1448440384119749e-003 0.5880944728851318 0.2979590892791748 <_> <_> <_>7 1 6 19 -1. <_>9 1 2 19 3. 0 -2.8977119363844395e-003 0.2373327016830444 0.5876647233963013 <_> <_> <_>9 0 6 4 -1. <_>11 0 2 4 3. 0 -0.0216106791049242 0.1220654994249344 0.5194202065467835 <_> <_> <_>3 1 9 3 -1. <_>6 1 3 3 3. 0 -4.6299318782985210e-003 0.2631230950355530 0.5817409157752991 <_> <_> <_>8 15 10 4 -1. <_>13 15 5 2 2. <_>8 17 5 2 2. 0 5.9393711853772402e-004 0.3638620078563690 0.5698544979095459 <_> <_> <_>0 3 6 10 -1. <_>3 3 3 10 2. 0 0.0538786612451077 0.4303531050682068 0.7559366226196289 <_> <_> <_>3 4 15 15 -1. <_>3 9 15 5 3. 0 1.8887349870055914e-003 0.2122603058815002 0.5613427162170410 <_> <_> <_>6 5 8 6 -1. <_>6 7 8 2 3. 0 -2.3635339457541704e-003 0.5631849169731140 0.2642767131328583 <_> <_> <_>4 4 12 10 -1. <_>10 4 6 5 2. <_>4 9 6 5 2. 0 0.0240177996456623 0.5797107815742493 0.2751705944538117 <_> <_> <_>6 4 4 4 -1. <_>8 4 2 4 2. 0 2.0543030404951423e-004 0.2705242037773132 0.5752568840980530 <_> <_> <_>15 11 1 2 -1. <_>15 12 1 1 2. 0 8.4790197433903813e-004 0.5435624718666077 0.2334876954555512 <_> <_> <_>3 11 2 2 -1. <_>3 12 2 1 2. 0 1.4091329649090767e-003 0.5319424867630005 0.2063155025243759 <_> <_> <_>16 11 1 3 -1. <_>16 12 1 1 3. 0 1.4642629539594054e-003 0.5418980717658997 0.3068861067295075 <_> <_> <_>3 15 6 4 -1. <_>3 15 3 2 2. <_>6 17 3 2 2. 0 1.6352549428120255e-003 0.3695372939109802 0.6112868189811707 <_> <_> <_>6 7 8 2 -1. <_>6 8 8 1 2. 0 8.3172752056270838e-004 0.3565036952495575 0.6025236248970032 <_> <_> <_>3 11 1 3 -1. <_>3 12 1 1 3. 0 -2.0998890977352858e-003 0.1913982033729553 0.5362827181816101 <_> <_> <_>6 0 12 2 -1. <_>6 1 12 1 2. 0 -7.4213981861248612e-004 0.3835555016994476 0.5529310107231140 <_> <_> <_>9 14 2 3 -1. <_>9 15 2 1 3. 0 3.2655049581080675e-003 0.4312896132469177 0.7101895809173584 <_> <_> <_>7 15 6 2 -1. <_>7 16 6 1 2. 0 8.9134991867467761e-004 0.3984830975532532 0.6391963958740234 <_> <_> <_>0 5 4 6 -1. <_>0 7 4 2 3. 0 -0.0152841797098517 0.2366732954978943 0.5433713793754578 <_> <_> <_>4 12 12 2 -1. <_>8 12 4 2 3. 0 4.8381411470472813e-003 0.5817500948905945 0.3239189088344574 <_> <_> <_>6 3 1 9 -1. <_>6 6 1 3 3. 0 -9.1093179071322083e-004 0.5540593862533569 0.2911868989467621 <_> <_> <_>10 17 3 2 -1. <_>11 17 1 2 3. 0 -6.1275060288608074e-003 0.1775255054235458 0.5196629166603088 <_> <_> <_>9 9 2 2 -1. <_>9 10 2 1 2. 0 -4.4576259097084403e-004 0.3024170100688934 0.5533593893051148 <_> <_> <_>7 6 6 4 -1. <_>9 6 2 4 3. 0 0.0226465407758951 0.4414930939674377 0.6975377202033997 <_> <_> <_>7 17 3 2 -1. <_>8 17 1 2 3. 0 -1.8804960418492556e-003 0.2791394889354706 0.5497952103614807 <_> <_> <_>10 17 3 3 -1. <_>11 17 1 3 3. 0 7.0889107882976532e-003 0.5263199210166931 0.2385547012090683 <_> <_> <_>8 12 3 2 -1. <_>8 13 3 1 2. 0 1.7318050377070904e-003 0.4319379031658173 0.6983600854873657 <_> <_> <_>9 3 6 2 -1. <_>11 3 2 2 3. 0 -6.8482700735330582e-003 0.3082042932510376 0.5390920042991638 <_> <_> <_>3 11 14 4 -1. <_>3 13 14 2 2. 0 -1.5062530110299122e-005 0.5521922111511231 0.3120366036891937 <_> <_> <_>1 10 18 4 -1. <_>10 10 9 2 2. <_>1 12 9 2 2. 0 0.0294755697250366 0.5401322841644287 0.1770603060722351 <_> <_> <_>0 10 3 3 -1. <_>0 11 3 1 3. 0 8.1387329846620560e-003 0.5178617835044861 0.1211019009351730 <_> <_> <_>9 1 6 6 -1. <_>11 1 2 6 3. 0 0.0209429506212473 0.5290294289588928 0.3311221897602081 <_> <_> <_>8 7 3 6 -1. <_>9 7 1 6 3. 0 -9.5665529370307922e-003 0.7471994161605835 0.4451968967914581 18.4129695892333980 2 -1 <_> <_> <_> <_>1 0 18 9 -1. <_>1 3 18 3 3. 0 -2.8206960996612906e-004 0.2064086049795151 0.6076732277870178 <_> <_> <_>12 10 2 6 -1. <_>12 13 2 3 2. 0 1.6790600493550301e-003 0.5851997137069702 0.1255383938550949 <_> <_> <_>0 5 19 8 -1. <_>0 9 19 4 2. 0 6.9827912375330925e-004 0.0940184295177460 0.5728961229324341 <_> <_> <_>7 0 6 9 -1. <_>9 0 2 9 3. 0 7.8959012171253562e-004 0.1781987994909287 0.5694308876991272 <_> <_> <_>5 3 6 1 -1. <_>7 3 2 1 3. 0 -2.8560499195009470e-003 0.1638399064540863 0.5788664817810059 <_> <_> <_>11 3 6 1 -1. <_>13 3 2 1 3. 0 -3.8122469559311867e-003 0.2085440009832382 0.5508564710617065 <_> <_> <_>5 10 4 6 -1. <_>5 13 4 3 2. 0 1.5896620461717248e-003 0.5702760815620422 0.1857215017080307 <_> <_> <_>11 3 6 1 -1. <_>13 3 2 1 3. 0 0.0100783398374915 0.5116943120956421 0.2189770042896271 <_> <_> <_>4 4 12 6 -1. <_>4 6 12 2 3. 0 -0.0635263025760651 0.7131379842758179 0.4043813049793243 <_> <_> <_>15 12 2 6 -1. <_>15 14 2 2 3. 0 -9.1031491756439209e-003 0.2567181885242462 0.5463973283767700 <_> <_> <_>9 3 2 2 -1. <_>10 3 1 2 2. 0 -2.4035000242292881e-003 0.1700665950775147 0.5590974092483521 <_> <_> <_>9 3 3 1 -1. <_>10 3 1 1 3. 0 1.5226360410451889e-003 0.5410556793212891 0.2619054019451141 <_> <_> <_>1 1 4 14 -1. <_>3 1 2 14 2. 0 0.0179974399507046 0.3732436895370483 0.6535220742225647 <_> <_> <_>9 0 4 4 -1. <_>11 0 2 2 2. <_>9 2 2 2 2. 0 -6.4538191072642803e-003 0.2626481950283051 0.5537446141242981 <_> <_> <_>7 5 1 14 -1. <_>7 12 1 7 2. 0 -0.0118807600811124 0.2003753930330277 0.5544745922088623 <_> <_> <_>19 0 1 4 -1. <_>19 2 1 2 2. 0 1.2713660253211856e-003 0.5591902732849121 0.3031975924968720 <_> <_> <_>5 5 6 4 -1. <_>8 5 3 4 2. 0 1.1376109905540943e-003 0.2730407118797302 0.5646508932113648 <_> <_> <_>9 18 3 2 -1. <_>10 18 1 2 3. 0 -4.2651998810470104e-003 0.1405909061431885 0.5461820960044861 <_> <_> <_>8 18 3 2 -1. <_>9 18 1 2 3. 0 -2.9602861031889915e-003 0.1795035004615784 0.5459290146827698 <_> <_> <_>4 5 12 6 -1. <_>4 7 12 2 3. 0 -8.8448226451873779e-003 0.5736783146858215 0.2809219956398010 <_> <_> <_>3 12 2 6 -1. <_>3 14 2 2 3. 0 -6.6430689767003059e-003 0.2370675951242447 0.5503826141357422 <_> <_> <_>10 8 2 12 -1. <_>10 12 2 4 3. 0 3.9997808635234833e-003 0.5608199834823608 0.3304282128810883 <_> <_> <_>7 18 3 2 -1. <_>8 18 1 2 3. 0 -4.1221720166504383e-003 0.1640105992555618 0.5378993153572083 <_> <_> <_>9 0 6 2 -1. <_>11 0 2 2 3. 0 0.0156249096617103 0.5227649211883545 0.2288603931665421 <_> <_> <_>5 11 9 3 -1. <_>5 12 9 1 3. 0 -0.0103564197197557 0.7016193866729736 0.4252927899360657 <_> <_> <_>9 0 6 2 -1. <_>11 0 2 2 3. 0 -8.7960809469223022e-003 0.2767347097396851 0.5355830192565918 <_> <_> <_>1 1 18 5 -1. <_>7 1 6 5 3. 0 0.1622693985700607 0.4342240095138550 0.7442579269409180 <_> <_> <_>8 0 4 4 -1. <_>10 0 2 2 2. <_>8 2 2 2 2. 0 4.5542530715465546e-003 0.5726485848426819 0.2582125067710877 <_> <_> <_>3 12 1 3 -1. <_>3 13 1 1 3. 0 -2.1309209987521172e-003 0.2106848061084747 0.5361018776893616 <_> <_> <_>8 14 5 3 -1. <_>8 15 5 1 3. 0 -0.0132084200158715 0.7593790888786316 0.4552468061447144 <_> <_> <_>5 4 10 12 -1. <_>5 4 5 6 2. <_>10 10 5 6 2. 0 -0.0659966766834259 0.1252475976943970 0.5344039797782898 <_> <_> <_>9 6 9 12 -1. <_>9 10 9 4 3. 0 7.9142656177282333e-003 0.3315384089946747 0.5601043105125427 <_> <_> <_>2 2 12 14 -1. <_>2 2 6 7 2. <_>8 9 6 7 2. 0 0.0208942797034979 0.5506049990653992 0.2768838107585907 15.3241395950317380 3 -1 <_> <_> <_> <_>4 7 12 2 -1. <_>8 7 4 2 3. 0 1.1961159761995077e-003 0.1762690991163254 0.6156241297721863 <_> <_> <_>7 4 6 4 -1. <_>7 6 6 2 2. 0 -1.8679830245673656e-003 0.6118106842041016 0.1832399964332581 <_> <_> <_>4 5 11 8 -1. <_>4 9 11 4 2. 0 -1.9579799845814705e-004 0.0990442633628845 0.5723816156387329 <_> <_> <_>3 10 16 4 -1. <_>3 12 16 2 2. 0 -8.0255657667294145e-004 0.5579879879951477 0.2377282977104187 <_> <_> <_>0 0 16 2 -1. <_>0 1 16 1 2. 0 -2.4510810617357492e-003 0.2231457978487015 0.5858935117721558 <_> <_> <_>7 5 6 2 -1. <_>9 5 2 2 3. 0 5.0361850298941135e-004 0.2653993964195252 0.5794103741645813 <_> <_> <_>3 2 6 10 -1. <_>3 2 3 5 2. <_>6 7 3 5 2. 0 4.0293349884450436e-003 0.5803827047348023 0.2484865039587021 <_> <_> <_>10 5 8 15 -1. <_>10 10 8 5 3. 0 -0.0144517095759511 0.1830351948738098 0.5484204888343811 <_> <_> <_>3 14 8 6 -1. <_>3 14 4 3 2. <_>7 17 4 3 2. 0 2.0380979403853416e-003 0.3363558948040009 0.6051092743873596 <_> <_> <_>14 2 2 2 -1. <_>14 3 2 1 2. 0 -1.6155190533027053e-003 0.2286642044782639 0.5441246032714844 <_> <_> <_>1 10 7 6 -1. <_>1 13 7 3 2. 0 3.3458340913057327e-003 0.5625913143157959 0.2392338067293167 <_> <_> <_>15 4 4 3 -1. <_>15 4 2 3 2. 0 1.6379579901695251e-003 0.3906993865966797 0.5964621901512146 <_> <_> <_>2 9 14 6 -1. <_>2 9 7 3 2. <_>9 12 7 3 2. 0 0.0302512105554342 0.5248482227325440 0.1575746983289719 <_> <_> <_>5 7 10 4 -1. <_>5 9 10 2 2. 0 0.0372519902884960 0.4194310903549194 0.6748418807983398 <_> <_> <_>6 9 8 8 -1. <_>6 9 4 4 2. <_>10 13 4 4 2. 0 -0.0251097902655602 0.1882549971342087 0.5473451018333435 <_> <_> <_>14 1 3 2 -1. <_>14 2 3 1 2. 0 -5.3099058568477631e-003 0.1339973062276840 0.5227110981941223 <_> <_> <_>1 4 4 2 -1. <_>3 4 2 2 2. 0 1.2086479691788554e-003 0.3762088119983673 0.6109635829925537 <_> <_> <_>11 10 2 8 -1. <_>11 14 2 4 2. 0 -0.0219076797366142 0.2663142979145050 0.5404006838798523 <_> <_> <_>0 0 5 3 -1. <_>0 1 5 1 3. 0 5.4116579703986645e-003 0.5363578796386719 0.2232273072004318 <_> <_> <_>2 5 18 8 -1. <_>11 5 9 4 2. <_>2 9 9 4 2. 0 0.0699463263154030 0.5358232855796814 0.2453698068857193 <_> <_> <_>6 6 1 6 -1. <_>6 9 1 3 2. 0 3.4520021290518343e-004 0.2409671992063522 0.5376930236816406 <_> <_> <_>19 1 1 3 -1. <_>19 2 1 1 3. 0 1.2627709656953812e-003 0.5425856709480286 0.3155693113803864 <_> <_> <_>7 6 6 6 -1. <_>9 6 2 6 3. 0 0.0227195098996162 0.4158405959606171 0.6597865223884583 <_> <_> <_>19 1 1 3 -1. <_>19 2 1 1 3. 0 -1.8111000536009669e-003 0.2811253070831299 0.5505244731903076 <_> <_> <_>3 13 2 3 -1. <_>3 14 2 1 3. 0 3.3469670452177525e-003 0.5260028243064880 0.1891465038061142 <_> <_> <_>8 4 8 12 -1. <_>12 4 4 6 2. <_>8 10 4 6 2. 0 4.0791751234792173e-004 0.5673509240150452 0.3344210088253021 <_> <_> <_>5 2 6 3 -1. <_>7 2 2 3 3. 0 0.0127347996458411 0.5343592166900635 0.2395612001419067 <_> <_> <_>6 1 9 10 -1. <_>6 6 9 5 2. 0 -7.3119727894663811e-003 0.6010890007019043 0.4022207856178284 <_> <_> <_>0 4 6 12 -1. <_>2 4 2 12 3. 0 -0.0569487512111664 0.8199151158332825 0.4543190896511078 <_> <_> <_>15 13 2 3 -1. <_>15 14 2 1 3. 0 -5.0116591155529022e-003 0.2200281023979187 0.5357710719108582 <_> <_> <_>7 14 5 3 -1. <_>7 15 5 1 3. 0 6.0334368608891964e-003 0.4413081109523773 0.7181751132011414 <_> <_> <_>15 13 3 3 -1. <_>15 14 3 1 3. 0 3.9437441155314445e-003 0.5478860735893250 0.2791733145713806 <_> <_> <_>6 14 8 3 -1. <_>6 15 8 1 3. 0 -3.6591119132936001e-003 0.6357867717742920 0.3989723920822144 <_> <_> <_>15 13 3 3 -1. <_>15 14 3 1 3. 0 -3.8456181064248085e-003 0.3493686020374298 0.5300664901733398 <_> <_> <_>2 13 3 3 -1. <_>2 14 3 1 3. 0 -7.1926261298358440e-003 0.1119614988565445 0.5229672789573669 <_> <_> <_>4 7 12 12 -1. <_>10 7 6 6 2. <_>4 13 6 6 2. 0 -0.0527989417314529 0.2387102991342545 0.5453451275825501 <_> <_> <_>9 7 2 6 -1. <_>10 7 1 6 2. 0 -7.9537667334079742e-003 0.7586917877197266 0.4439376890659332 <_> <_> <_>8 9 5 2 -1. <_>8 10 5 1 2. 0 -2.7344180271029472e-003 0.2565476894378662 0.5489321947097778 <_> <_> <_>8 6 3 4 -1. <_>9 6 1 4 3. 0 -1.8507939530536532e-003 0.6734347939491272 0.4252474904060364 <_> <_> <_>9 6 2 8 -1. <_>9 10 2 4 2. 0 0.0159189198166132 0.5488352775573731 0.2292661964893341 <_> <_> <_>7 7 3 6 -1. <_>8 7 1 6 3. 0 -1.2687679845839739e-003 0.6104331016540527 0.4022389948368073 <_> <_> <_>11 3 3 3 -1. <_>12 3 1 3 3. 0 6.2883910723030567e-003 0.5310853123664856 0.1536193042993546 <_> <_> <_>5 4 6 1 -1. <_>7 4 2 1 3. 0 -6.2259892001748085e-003 0.1729111969470978 0.5241606235504150 <_> <_> <_>5 6 10 3 -1. <_>5 7 10 1 3. 0 -0.0121325999498367 0.6597759723663330 0.4325182139873505 21.0106391906738280 4 -1 <_> <_> <_> <_>7 3 6 9 -1. <_>7 6 6 3 3. 0 -3.9184908382594585e-003 0.6103435158729553 0.1469330936670303 <_> <_> <_>6 7 9 1 -1. <_>9 7 3 1 3. 0 1.5971299726516008e-003 0.2632363140583038 0.5896466970443726 <_> <_> <_>2 8 16 8 -1. <_>2 12 16 4 2. 0 0.0177801102399826 0.5872874259948731 0.1760361939668655 <_> <_> <_>14 6 2 6 -1. <_>14 9 2 3 2. 0 6.5334769897162914e-004 0.1567801982164383 0.5596066117286682 <_> <_> <_>1 5 6 15 -1. <_>1 10 6 5 3. 0 -2.8353091329336166e-004 0.1913153976202011 0.5732036232948303 <_> <_> <_>10 0 6 9 -1. <_>10 3 6 3 3. 0 1.6104689566418529e-003 0.2914913892745972 0.5623080730438232 <_> <_> <_>6 6 7 14 -1. <_>6 13 7 7 2. 0 -0.0977506190538406 0.1943476945161820 0.5648233294487000 <_> <_> <_>13 7 3 6 -1. <_>13 9 3 2 3. 0 5.5182358482852578e-004 0.3134616911411285 0.5504639744758606 <_> <_> <_>1 8 15 4 -1. <_>6 8 5 4 3. 0 -0.0128582203760743 0.2536481916904450 0.5760142803192139 <_> <_> <_>11 2 3 10 -1. <_>11 7 3 5 2. 0 4.1530239395797253e-003 0.5767722129821777 0.3659774065017700 <_> <_> <_>3 7 4 6 -1. <_>3 9 4 2 3. 0 1.7092459602281451e-003 0.2843191027641296 0.5918939113616943 <_> <_> <_>13 3 6 10 -1. <_>15 3 2 10 3. 0 7.5217359699308872e-003 0.4052427113056183 0.6183109283447266 <_> <_> <_>5 7 8 10 -1. <_>5 7 4 5 2. <_>9 12 4 5 2. 0 2.2479810286313295e-003 0.5783755183219910 0.3135401010513306 <_> <_> <_>4 4 12 12 -1. <_>10 4 6 6 2. <_>4 10 6 6 2. 0 0.0520062111318111 0.5541312098503113 0.1916636973619461 <_> <_> <_>1 4 6 9 -1. <_>3 4 2 9 3. 0 0.0120855299755931 0.4032655954360962 0.6644591093063355 <_> <_> <_>11 3 2 5 -1. <_>11 3 1 5 2. 0 1.4687820112158079e-005 0.3535977900028229 0.5709382891654968 <_> <_> <_>7 3 2 5 -1. <_>8 3 1 5 2. 0 7.1395188570022583e-006 0.3037444949150085 0.5610269904136658 <_> <_> <_>10 14 2 3 -1. <_>10 15 2 1 3. 0 -4.6001640148460865e-003 0.7181087136268616 0.4580326080322266 <_> <_> <_>5 12 6 2 -1. <_>8 12 3 2 2. 0 2.0058949012309313e-003 0.5621951818466187 0.2953684031963348 <_> <_> <_>9 14 2 3 -1. <_>9 15 2 1 3. 0 4.5050270855426788e-003 0.4615387916564941 0.7619017958641052 <_> <_> <_>4 11 12 6 -1. <_>4 14 12 3 2. 0 0.0117468303069472 0.5343837141990662 0.1772529035806656 <_> <_> <_>11 11 5 9 -1. <_>11 14 5 3 3. 0 -0.0583163388073444 0.1686245948076248 0.5340772271156311 <_> <_> <_>6 15 3 2 -1. <_>6 16 3 1 2. 0 2.3629379575140774e-004 0.3792056143283844 0.6026803851127625 <_> <_> <_>11 0 3 5 -1. <_>12 0 1 5 3. 0 -7.8156180679798126e-003 0.1512867063283920 0.5324323773384094 <_> <_> <_>5 5 6 7 -1. <_>8 5 3 7 2. 0 -0.0108761601150036 0.2081822007894516 0.5319945216178894 <_> <_> <_>13 0 1 9 -1. <_>13 3 1 3 3. 0 -2.7745519764721394e-003 0.4098246991634369 0.5210328102111816 <_> <_> <_>3 2 4 8 -1. <_>3 2 2 4 2. <_>5 6 2 4 2. 0 -7.8276381827890873e-004 0.5693274140357971 0.3478842079639435 <_> <_> <_>13 12 4 6 -1. <_>13 14 4 2 3. 0 0.0138704096898437 0.5326750874519348 0.2257698029279709 <_> <_> <_>3 12 4 6 -1. <_>3 14 4 2 3. 0 -0.0236749108880758 0.1551305055618286 0.5200707912445068 <_> <_> <_>13 11 3 4 -1. <_>13 13 3 2 2. 0 -1.4879409718560055e-005 0.5500566959381104 0.3820176124572754 <_> <_> <_>4 4 4 3 -1. <_>4 5 4 1 3. 0 3.6190641112625599e-003 0.4238683879375458 0.6639748215675354 <_> <_> <_>7 5 11 8 -1. <_>7 9 11 4 2. 0 -0.0198171101510525 0.2150038033723831 0.5382357835769653 <_> <_> <_>7 8 3 4 -1. <_>8 8 1 4 3. 0 -3.8154039066284895e-003 0.6675711274147034 0.4215297102928162 <_> <_> <_>9 1 6 1 -1. <_>11 1 2 1 3. 0 -4.9775829538702965e-003 0.2267289012670517 0.5386328101158142 <_> <_> <_>5 5 3 3 -1. <_>5 6 3 1 3. 0 2.2441020701080561e-003 0.4308691024780273 0.6855735778808594 <_> <_> <_>0 9 20 6 -1. <_>10 9 10 3 2. <_>0 12 10 3 2. 0 0.0122824599966407 0.5836614966392517 0.3467479050159454 <_> <_> <_>8 6 3 5 -1. <_>9 6 1 5 3. 0 -2.8548699337989092e-003 0.7016944885253906 0.4311453998088837 <_> <_> <_>11 0 1 3 -1. <_>11 1 1 1 3. 0 -3.7875669077038765e-003 0.2895345091819763 0.5224946141242981 <_> <_> <_>4 2 4 2 -1. <_>4 3 4 1 2. 0 -1.2201230274513364e-003 0.2975570857524872 0.5481644868850708 <_> <_> <_>12 6 4 3 -1. <_>12 7 4 1 3. 0 0.0101605998352170 0.4888817965984345 0.8182697892189026 <_> <_> <_>5 0 6 4 -1. <_>7 0 2 4 3. 0 -0.0161745697259903 0.1481492966413498 0.5239992737770081 <_> <_> <_>9 7 3 8 -1. <_>10 7 1 8 3. 0 0.0192924607545137 0.4786309897899628 0.7378190755844116 <_> <_> <_>9 7 2 2 -1. <_>10 7 1 2 2. 0 -3.2479539513587952e-003 0.7374222874641419 0.4470643997192383 <_> <_> <_>6 7 14 4 -1. <_>13 7 7 2 2. <_>6 9 7 2 2. 0 -9.3803480267524719e-003 0.3489154875278473 0.5537996292114258 <_> <_> <_>0 5 3 6 -1. <_>0 7 3 2 3. 0 -0.0126061299815774 0.2379686981439591 0.5315443277359009 <_> <_> <_>13 11 3 4 -1. <_>13 13 3 2 2. 0 -0.0256219301372766 0.1964688003063202 0.5138769745826721 <_> <_> <_>4 11 3 4 -1. <_>4 13 3 2 2. 0 -7.5741496402770281e-005 0.5590522885322571 0.3365853130817413 <_> <_> <_>5 9 12 8 -1. <_>11 9 6 4 2. <_>5 13 6 4 2. 0 -0.0892108827829361 0.0634046569466591 0.5162634849548340 <_> <_> <_>9 12 1 3 -1. <_>9 13 1 1 3. 0 -2.7670480776578188e-003 0.7323467731475830 0.4490706026554108 <_> <_> <_>10 15 2 4 -1. <_>10 17 2 2 2. 0 2.7152578695677221e-004 0.4114834964275360 0.5985518097877502 23.9187908172607420 5 -1 <_> <_> <_> <_>7 7 6 1 -1. <_>9 7 2 1 3. 0 1.4786219689995050e-003 0.2663545012474060 0.6643316745758057 <_> <_> <_>12 3 6 6 -1. <_>15 3 3 3 2. <_>12 6 3 3 2. 0 -1.8741659587249160e-003 0.6143848896026611 0.2518512904644013 <_> <_> <_>0 4 10 6 -1. <_>0 6 10 2 3. 0 -1.7151009524241090e-003 0.5766341090202332 0.2397463023662567 <_> <_> <_>8 3 8 14 -1. <_>12 3 4 7 2. <_>8 10 4 7 2. 0 -1.8939269939437509e-003 0.5682045817375183 0.2529144883155823 <_> <_> <_>4 4 7 15 -1. <_>4 9 7 5 3. 0 -5.3006052039563656e-003 0.1640675961971283 0.5556079745292664 <_> <_> <_>12 2 6 8 -1. <_>15 2 3 4 2. <_>12 6 3 4 2. 0 -0.0466625317931175 0.6123154163360596 0.4762830138206482 <_> <_> <_>2 2 6 8 -1. <_>2 2 3 4 2. <_>5 6 3 4 2. 0 -7.9431332414969802e-004 0.5707858800888062 0.2839404046535492 <_> <_> <_>2 13 18 7 -1. <_>8 13 6 7 3. 0 0.0148916700854898 0.4089672863483429 0.6006367206573486 <_> <_> <_>4 3 8 14 -1. <_>4 3 4 7 2. <_>8 10 4 7 2. 0 -1.2046529445797205e-003 0.5712450742721558 0.2705289125442505 <_> <_> <_>18 1 2 6 -1. <_>18 3 2 2 3. 0 6.0619381256401539e-003 0.5262504220008850 0.3262225985527039 <_> <_> <_>9 11 2 3 -1. <_>9 12 2 1 3. 0 -2.5286648888140917e-003 0.6853830814361572 0.4199256896972656 <_> <_> <_>18 1 2 6 -1. <_>18 3 2 2 3. 0 -5.9010218828916550e-003 0.3266282081604004 0.5434812903404236 <_> <_> <_>0 1 2 6 -1. <_>0 3 2 2 3. 0 5.6702760048210621e-003 0.5468410849571228 0.2319003939628601 <_> <_> <_>1 5 18 6 -1. <_>1 7 18 2 3. 0 -3.0304100364446640e-003 0.5570667982101440 0.2708238065242767 <_> <_> <_>0 2 6 7 -1. <_>3 2 3 7 2. 0 2.9803649522364140e-003 0.3700568974018097 0.5890625715255737 <_> <_> <_>7 3 6 14 -1. <_>7 10 6 7 2. 0 -0.0758405104279518 0.2140070050954819 0.5419948101043701 <_> <_> <_>3 7 13 10 -1. <_>3 12 13 5 2. 0 0.0192625392228365 0.5526772141456604 0.2726590037345886 <_> <_> <_>11 15 2 2 -1. <_>11 16 2 1 2. 0 1.8888259364757687e-004 0.3958011865615845 0.6017209887504578 <_> <_> <_>2 11 16 4 -1. <_>2 11 8 2 2. <_>10 13 8 2 2. 0 0.0293695498257875 0.5241373777389526 0.1435758024454117 <_> <_> <_>13 7 6 4 -1. <_>16 7 3 2 2. <_>13 9 3 2 2. 0 1.0417619487270713e-003 0.3385409116744995 0.5929983258247376 <_> <_> <_>6 10 3 9 -1. <_>6 13 3 3 3. 0 2.6125640142709017e-003 0.5485377907752991 0.3021597862243652 <_> <_> <_>14 6 1 6 -1. <_>14 9 1 3 2. 0 9.6977467183023691e-004 0.3375276029109955 0.5532032847404480 <_> <_> <_>5 10 4 1 -1. <_>7 10 2 1 2. 0 5.9512659208849072e-004 0.5631743073463440 0.3359399139881134 <_> <_> <_>3 8 15 5 -1. <_>8 8 5 5 3. 0 -0.1015655994415283 0.0637350380420685 0.5230425000190735 <_> <_> <_>1 6 5 4 -1. <_>1 8 5 2 2. 0 0.0361566990613937 0.5136963129043579 0.1029528975486755 <_> <_> <_>3 1 17 6 -1. <_>3 3 17 2 3. 0 3.4624140243977308e-003 0.3879320025444031 0.5558289289474487 <_> <_> <_>6 7 8 2 -1. <_>10 7 4 2 2. 0 0.0195549800992012 0.5250086784362793 0.1875859946012497 <_> <_> <_>9 7 3 2 -1. <_>10 7 1 2 3. 0 -2.3121440317481756e-003 0.6672028899192810 0.4679641127586365 <_> <_> <_>8 7 3 2 -1. <_>9 7 1 2 3. 0 -1.8605289515107870e-003 0.7163379192352295 0.4334670901298523 <_> <_> <_>8 9 4 2 -1. <_>8 10 4 1 2. 0 -9.4026362057775259e-004 0.3021360933780670 0.5650203227996826 <_> <_> <_>8 8 4 3 -1. <_>8 9 4 1 3. 0 -5.2418331615626812e-003 0.1820009052753449 0.5250256061553955 <_> <_> <_>9 5 6 4 -1. <_>9 5 3 4 2. 0 1.1729019752237946e-004 0.3389188051223755 0.5445973277091980 <_> <_> <_>8 13 4 3 -1. <_>8 14 4 1 3. 0 1.1878840159624815e-003 0.4085349142551422 0.6253563165664673 <_> <_> <_>4 7 12 6 -1. <_>10 7 6 3 2. <_>4 10 6 3 2. 0 -0.0108813596889377 0.3378399014472961 0.5700082778930664 <_> <_> <_>8 14 4 3 -1. <_>8 15 4 1 3. 0 1.7354859737679362e-003 0.4204635918140411 0.6523038744926453 <_> <_> <_>9 7 3 3 -1. <_>9 8 3 1 3. 0 -6.5119052305817604e-003 0.2595216035842896 0.5428143739700317 <_> <_> <_>7 4 3 8 -1. <_>8 4 1 8 3. 0 -1.2136430013924837e-003 0.6165143847465515 0.3977893888950348 <_> <_> <_>10 0 3 6 -1. <_>11 0 1 6 3. 0 -0.0103542404249310 0.1628028005361557 0.5219504833221436 <_> <_> <_>6 3 4 8 -1. <_>8 3 2 8 2. 0 5.5858830455690622e-004 0.3199650943279266 0.5503574013710022 <_> <_> <_>14 3 6 13 -1. <_>14 3 3 13 2. 0 0.0152996499091387 0.4103994071483612 0.6122388243675232 <_> <_> <_>8 13 3 6 -1. <_>8 16 3 3 2. 0 -0.0215882100164890 0.1034912988543510 0.5197384953498840 <_> <_> <_>14 3 6 13 -1. <_>14 3 3 13 2. 0 -0.1283462941646576 0.8493865132331848 0.4893102943897247 <_> <_> <_>0 7 10 4 -1. <_>0 7 5 2 2. <_>5 9 5 2 2. 0 -2.2927189711481333e-003 0.3130157887935638 0.5471575260162354 <_> <_> <_>14 3 6 13 -1. <_>14 3 3 13 2. 0 0.0799151062965393 0.4856320917606354 0.6073989272117615 <_> <_> <_>0 3 6 13 -1. <_>3 3 3 13 2. 0 -0.0794410929083824 0.8394674062728882 0.4624533057212830 <_> <_> <_>9 1 4 1 -1. <_>9 1 2 1 2. 0 -5.2800010889768600e-003 0.1881695985794067 0.5306698083877564 <_> <_> <_>8 0 2 1 -1. <_>9 0 1 1 2. 0 1.0463109938427806e-003 0.5271229147911072 0.2583065927028656 <_> <_> <_>10 16 4 4 -1. <_>12 16 2 2 2. <_>10 18 2 2 2. 0 2.6317298761568964e-004 0.4235304892063141 0.5735440850257874 <_> <_> <_>9 6 2 3 -1. <_>10 6 1 3 2. 0 -3.6173160187900066e-003 0.6934396028518677 0.4495444893836975 <_> <_> <_>4 5 12 2 -1. <_>8 5 4 2 3. 0 0.0114218797534704 0.5900921225547791 0.4138193130493164 <_> <_> <_>8 7 3 5 -1. <_>9 7 1 5 3. 0 -1.9963278900831938e-003 0.6466382741928101 0.4327239990234375 24.5278797149658200 6 -1 <_> <_> <_> <_>6 4 8 6 -1. <_>6 6 8 2 3. 0 -9.9691245704889297e-003 0.6142324209213257 0.2482212036848068 <_> <_> <_>9 5 2 12 -1. <_>9 11 2 6 2. 0 7.3073059320449829e-004 0.5704951882362366 0.2321965992450714 <_> <_> <_>4 6 6 8 -1. <_>4 10 6 4 2. 0 6.4045301405712962e-004 0.2112251967191696 0.5814933180809021 <_> <_> <_>12 2 8 5 -1. <_>12 2 4 5 2. 0 4.5424019917845726e-003 0.2950482070446014 0.5866311788558960 <_> <_> <_>0 8 18 3 -1. <_>0 9 18 1 3. 0 9.2477443104144186e-005 0.2990990877151489 0.5791326761245728 <_> <_> <_>8 12 4 8 -1. <_>8 16 4 4 2. 0 -8.6603146046400070e-003 0.2813029885292053 0.5635542273521423 <_> <_> <_>0 2 8 5 -1. <_>4 2 4 5 2. 0 8.0515816807746887e-003 0.3535369038581848 0.6054757237434387 <_> <_> <_>13 11 3 4 -1. <_>13 13 3 2 2. 0 4.3835240649059415e-004 0.5596532225608826 0.2731510996818543 <_> <_> <_>5 11 6 1 -1. <_>7 11 2 1 3. 0 -9.8168973636347800e-005 0.5978031754493713 0.3638561069965363 <_> <_> <_>11 3 3 1 -1. <_>12 3 1 1 3. 0 -1.1298790341243148e-003 0.2755252122879028 0.5432729125022888 <_> <_> <_>7 13 5 3 -1. <_>7 14 5 1 3. 0 6.4356150105595589e-003 0.4305641949176788 0.7069833278656006 <_> <_> <_>11 11 7 6 -1. <_>11 14 7 3 2. 0 -0.0568293295800686 0.2495242953300476 0.5294997096061707 <_> <_> <_>2 11 7 6 -1. <_>2 14 7 3 2. 0 4.0668169967830181e-003 0.5478553175926209 0.2497723996639252 <_> <_> <_>12 14 2 6 -1. <_>12 16 2 2 3. 0 4.8164798499783501e-005 0.3938601016998291 0.5706356167793274 <_> <_> <_>8 14 3 3 -1. <_>8 15 3 1 3. 0 6.1795017682015896e-003 0.4407606124877930 0.7394766807556152 <_> <_> <_>11 0 3 5 -1. <_>12 0 1 5 3. 0 6.4985752105712891e-003 0.5445243120193481 0.2479152977466583 <_> <_> <_>6 1 4 9 -1. <_>8 1 2 9 2. 0 -1.0211090557277203e-003 0.2544766962528229 0.5338971018791199 <_> <_> <_>10 3 6 1 -1. <_>12 3 2 1 3. 0 -5.4247528314590454e-003 0.2718858122825623 0.5324069261550903 <_> <_> <_>8 8 3 4 -1. <_>8 10 3 2 2. 0 -1.0559899965301156e-003 0.3178288042545319 0.5534508824348450 <_> <_> <_>8 12 4 2 -1. <_>8 13 4 1 2. 0 6.6465808777138591e-004 0.4284219145774841 0.6558194160461426 <_> <_> <_>5 18 4 2 -1. <_>5 19 4 1 2. 0 -2.7524109464138746e-004 0.5902860760688782 0.3810262978076935 <_> <_> <_>2 1 18 6 -1. <_>2 3 18 2 3. 0 4.2293202131986618e-003 0.3816489875316620 0.5709385871887207 <_> <_> <_>6 0 3 2 -1. <_>7 0 1 2 3. 0 -3.2868210691958666e-003 0.1747743934392929 0.5259544253349304 <_> <_> <_>13 8 6 2 -1. <_>16 8 3 1 2. <_>13 9 3 1 2. 0 1.5611879643984139e-004 0.3601722121238709 0.5725612044334412 <_> <_> <_>6 10 3 6 -1. <_>6 13 3 3 2. 0 -7.3621381488919724e-006 0.5401858091354370 0.3044497072696686 <_> <_> <_>0 13 20 4 -1. <_>10 13 10 2 2. <_>0 15 10 2 2. 0 -0.0147672500461340 0.3220770061016083 0.5573434829711914 <_> <_> <_>7 7 6 5 -1. <_>9 7 2 5 3. 0 0.0244895908981562 0.4301528036594391 0.6518812775611877 <_> <_> <_>11 0 2 2 -1. <_>11 1 2 1 2. 0 -3.7652091123163700e-004 0.3564583063125610 0.5598236918449402 <_> <_> <_>1 8 6 2 -1. <_>1 8 3 1 2. <_>4 9 3 1 2. 0 7.3657688517414499e-006 0.3490782976150513 0.5561897754669190 <_> <_> <_>0 2 20 2 -1. <_>10 2 10 1 2. <_>0 3 10 1 2. 0 -0.0150999398902059 0.1776272058486939 0.5335299968719482 <_> <_> <_>7 14 5 3 -1. <_>7 15 5 1 3. 0 -3.8316650316119194e-003 0.6149687767028809 0.4221394062042236 <_> <_> <_>7 13 6 6 -1. <_>10 13 3 3 2. <_>7 16 3 3 2. 0 0.0169254001230001 0.5413014888763428 0.2166585028171539 <_> <_> <_>9 12 2 3 -1. <_>9 13 2 1 3. 0 -3.0477850232273340e-003 0.6449490785598755 0.4354617893695831 <_> <_> <_>16 11 1 6 -1. <_>16 13 1 2 3. 0 3.2140589319169521e-003 0.5400155186653137 0.3523217141628265 <_> <_> <_>3 11 1 6 -1. <_>3 13 1 2 3. 0 -4.0023201145231724e-003 0.2774524092674255 0.5338417291641235 <_> <_> <_>4 4 14 12 -1. <_>11 4 7 6 2. <_>4 10 7 6 2. 0 7.4182129465043545e-003 0.5676739215850830 0.3702817857265472 <_> <_> <_>5 4 3 3 -1. <_>5 5 3 1 3. 0 -8.8764587417244911e-003 0.7749221920967102 0.4583688974380493 <_> <_> <_>12 3 3 3 -1. <_>13 3 1 3 3. 0 2.7311739977449179e-003 0.5338721871376038 0.3996661007404327 <_> <_> <_>6 6 8 3 -1. <_>6 7 8 1 3. 0 -2.5082379579544067e-003 0.5611963272094727 0.3777498900890350 <_> <_> <_>12 3 3 3 -1. <_>13 3 1 3 3. 0 -8.0541074275970459e-003 0.2915228903293610 0.5179182887077332 <_> <_> <_>3 1 4 10 -1. <_>3 1 2 5 2. <_>5 6 2 5 2. 0 -9.7938813269138336e-004 0.5536432862281799 0.3700192868709564 <_> <_> <_>5 7 10 2 -1. <_>5 7 5 2 2. 0 -5.8745909482240677e-003 0.3754391074180603 0.5679376125335693 <_> <_> <_>8 7 3 3 -1. <_>9 7 1 3 3. 0 -4.4936719350516796e-003 0.7019699215888977 0.4480949938297272 <_> <_> <_>15 12 2 3 -1. <_>15 13 2 1 3. 0 -5.4389229044318199e-003 0.2310364991426468 0.5313386917114258 <_> <_> <_>7 8 3 4 -1. <_>8 8 1 4 3. 0 -7.5094640487805009e-004 0.5864868760108948 0.4129343032836914 <_> <_> <_>13 4 1 12 -1. <_>13 10 1 6 2. 0 1.4528800420521293e-005 0.3732407093048096 0.5619621276855469 <_> <_> <_>4 5 12 12 -1. <_>4 5 6 6 2. <_>10 11 6 6 2. 0 0.0407580696046352 0.5312091112136841 0.2720521986484528 <_> <_> <_>7 14 7 3 -1. <_>7 15 7 1 3. 0 6.6505931317806244e-003 0.4710015952587128 0.6693493723869324 <_> <_> <_>3 12 2 3 -1. <_>3 13 2 1 3. 0 4.5759351924061775e-003 0.5167819261550903 0.1637275964021683 <_> <_> <_>3 2 14 2 -1. <_>10 2 7 1 2. <_>3 3 7 1 2. 0 6.5269311890006065e-003 0.5397608876228333 0.2938531935214996 <_> <_> <_>0 1 3 10 -1. <_>1 1 1 10 3. 0 -0.0136603796854615 0.7086488008499146 0.4532200098037720 <_> <_> <_>9 0 6 5 -1. <_>11 0 2 5 3. 0 0.0273588690906763 0.5206481218338013 0.3589231967926025 <_> <_> <_>5 7 6 2 -1. <_>8 7 3 2 2. 0 6.2197551596909761e-004 0.3507075905799866 0.5441123247146606 <_> <_> <_>7 1 6 10 -1. <_>7 6 6 5 2. 0 -3.3077080734074116e-003 0.5859522819519043 0.4024891853332520 <_> <_> <_>1 1 18 3 -1. <_>7 1 6 3 3. 0 -0.0106311095878482 0.6743267178535461 0.4422602951526642 <_> <_> <_>16 3 3 6 -1. <_>16 5 3 2 3. 0 0.0194416493177414 0.5282716155052185 0.1797904968261719 27.1533508300781250 7 -1 <_> <_> <_> <_>6 3 7 6 -1. <_>6 6 7 3 2. 0 -5.5052167735993862e-003 0.5914731025695801 0.2626559138298035 <_> <_> <_>4 7 12 2 -1. <_>8 7 4 2 3. 0 1.9562279339879751e-003 0.2312581986188889 0.5741627216339111 <_> <_> <_>0 4 17 10 -1. <_>0 9 17 5 2. 0 -8.8924784213304520e-003 0.1656530052423477 0.5626654028892517 <_> <_> <_>3 4 15 16 -1. <_>3 12 15 8 2. 0 0.0836383774876595 0.5423449873924255 0.1957294940948486 <_> <_> <_>7 15 6 4 -1. <_>7 17 6 2 2. 0 1.2282270472496748e-003 0.3417904078960419 0.5992503762245178 <_> <_> <_>15 2 4 9 -1. <_>15 2 2 9 2. 0 5.7629169896245003e-003 0.3719581961631775 0.6079903841018677 <_> <_> <_>2 3 3 2 -1. <_>2 4 3 1 2. 0 -1.6417410224676132e-003 0.2577486038208008 0.5576915740966797 <_> <_> <_>13 6 7 9 -1. <_>13 9 7 3 3. 0 3.4113149158656597e-003 0.2950749099254608 0.5514171719551086 <_> <_> <_>8 11 4 3 -1. <_>8 12 4 1 3. 0 -0.0110693201422691 0.7569358944892883 0.4477078914642334 <_> <_> <_>0 2 20 6 -1. <_>10 2 10 3 2. <_>0 5 10 3 2. 0 0.0348659716546535 0.5583708882331848 0.2669621109962463 <_> <_> <_>3 2 6 10 -1. <_>3 2 3 5 2. <_>6 7 3 5 2. 0 6.5701099811121821e-004 0.5627313256263733 0.2988890111446381 <_> <_> <_>13 10 3 4 -1. <_>13 12 3 2 2. 0 -0.0243391301482916 0.2771185040473938 0.5108863115310669 <_> <_> <_>4 10 3 4 -1. <_>4 12 3 2 2. 0 5.9435202274471521e-004 0.5580651760101318 0.3120341897010803 <_> <_> <_>7 5 6 3 -1. <_>9 5 2 3 3. 0 2.2971509024500847e-003 0.3330250084400177 0.5679075717926025 <_> <_> <_>7 6 6 8 -1. <_>7 10 6 4 2. 0 -3.7801829166710377e-003 0.2990534901618958 0.5344808101654053 <_> <_> <_>0 11 20 6 -1. <_>0 14 20 3 2. 0 -0.1342066973447800 0.1463858932256699 0.5392568111419678 <_> <_> <_>4 13 4 6 -1. <_>4 13 2 3 2. <_>6 16 2 3 2. 0 7.5224548345431685e-004 0.3746953904628754 0.5692734718322754 <_> <_> <_>6 0 8 12 -1. <_>10 0 4 6 2. <_>6 6 4 6 2. 0 -0.0405455417931080 0.2754747867584229 0.5484297871589661 <_> <_> <_>2 0 15 2 -1. <_>2 1 15 1 2. 0 1.2572970008477569e-003 0.3744584023952484 0.5756075978279114 <_> <_> <_>9 12 2 3 -1. <_>9 13 2 1 3. 0 -7.4249948374927044e-003 0.7513859272003174 0.4728231132030487 <_> <_> <_>3 12 1 2 -1. <_>3 13 1 1 2. 0 5.0908129196614027e-004 0.5404896736145020 0.2932321131229401 <_> <_> <_>9 11 2 3 -1. <_>9 12 2 1 3. 0 -1.2808450264856219e-003 0.6169779896736145 0.4273349046707153 <_> <_> <_>7 3 3 1 -1. <_>8 3 1 1 3. 0 -1.8348860321566463e-003 0.2048496007919312 0.5206472277641296 <_> <_> <_>17 7 3 6 -1. <_>17 9 3 2 3. 0 0.0274848695844412 0.5252984762191773 0.1675522029399872 <_> <_> <_>7 2 3 2 -1. <_>8 2 1 2 3. 0 2.2372419480234385e-003 0.5267782807350159 0.2777658104896545 <_> <_> <_>11 4 5 3 -1. <_>11 5 5 1 3. 0 -8.8635291904211044e-003 0.6954557895660400 0.4812048971652985 <_> <_> <_>4 4 5 3 -1. <_>4 5 5 1 3. 0 4.1753971017897129e-003 0.4291887879371643 0.6349195837974548 <_> <_> <_>19 3 1 2 -1. <_>19 4 1 1 2. 0 -1.7098189564421773e-003 0.2930536866188049 0.5361248850822449 <_> <_> <_>5 5 4 3 -1. <_>5 6 4 1 3. 0 6.5328548662364483e-003 0.4495325088500977 0.7409694194793701 <_> <_> <_>17 7 3 6 -1. <_>17 9 3 2 3. 0 -9.5372907817363739e-003 0.3149119913578033 0.5416501760482788 <_> <_> <_>0 7 3 6 -1. <_>0 9 3 2 3. 0 0.0253109894692898 0.5121892094612122 0.1311707943677902 <_> <_> <_>14 2 6 9 -1. <_>14 5 6 3 3. 0 0.0364609695971012 0.5175911784172058 0.2591339945793152 <_> <_> <_>0 4 5 6 -1. <_>0 6 5 2 3. 0 0.0208543296903372 0.5137140154838562 0.1582316011190414 <_> <_> <_>10 5 6 2 -1. <_>12 5 2 2 3. 0 -8.7207747856155038e-004 0.5574309825897217 0.4398978948593140 <_> <_> <_>4 5 6 2 -1. <_>6 5 2 2 3. 0 -1.5227000403683633e-005 0.5548940896987915 0.3708069920539856 <_> <_> <_>8 1 4 6 -1. <_>8 3 4 2 3. 0 -8.4316509310156107e-004 0.3387419879436493 0.5554211139678955 <_> <_> <_>0 2 3 6 -1. <_>0 4 3 2 3. 0 3.6037859972566366e-003 0.5358061790466309 0.3411171138286591 <_> <_> <_>6 6 8 3 -1. <_>6 7 8 1 3. 0 -6.8057891912758350e-003 0.6125202775001526 0.4345862865447998 <_> <_> <_>0 1 5 9 -1. <_>0 4 5 3 3. 0 -0.0470216609537601 0.2358165979385376 0.5193738937377930 <_> <_> <_>16 0 4 15 -1. <_>16 0 2 15 2. 0 -0.0369541086256504 0.7323111295700073 0.4760943949222565 <_> <_> <_>1 10 3 2 -1. <_>1 11 3 1 2. 0 1.0439479956403375e-003 0.5419455170631409 0.3411330878734589 <_> <_> <_>14 4 1 10 -1. <_>14 9 1 5 2. 0 -2.1050689974799752e-004 0.2821694016456604 0.5554947257041931 <_> <_> <_>0 1 4 12 -1. <_>2 1 2 12 2. 0 -0.0808315873146057 0.9129930138587952 0.4697434902191162 <_> <_> <_>11 11 4 2 -1. <_>11 11 2 2 2. 0 -3.6579059087671340e-004 0.6022670269012451 0.3978292942047119 <_> <_> <_>5 11 4 2 -1. <_>7 11 2 2 2. 0 -1.2545920617412776e-004 0.5613213181495667 0.3845539987087250 <_> <_> <_>3 8 15 5 -1. <_>8 8 5 5 3. 0 -0.0687864869832993 0.2261611968278885 0.5300496816635132 <_> <_> <_>0 0 6 10 -1. <_>3 0 3 10 2. 0 0.0124157899990678 0.4075691998004913 0.5828812122344971 <_> <_> <_>11 4 3 2 -1. <_>12 4 1 2 3. 0 -4.7174817882478237e-003 0.2827253937721252 0.5267757773399353 <_> <_> <_>8 12 3 8 -1. <_>8 16 3 4 2. 0 0.0381368584930897 0.5074741244316101 0.1023615971207619 <_> <_> <_>8 14 5 3 -1. <_>8 15 5 1 3. 0 -2.8168049175292253e-003 0.6169006824493408 0.4359692931175232 <_> <_> <_>7 14 4 3 -1. <_>7 15 4 1 3. 0 8.1303603947162628e-003 0.4524433016777039 0.7606095075607300 <_> <_> <_>11 4 3 2 -1. <_>12 4 1 2 3. 0 6.0056019574403763e-003 0.5240408778190613 0.1859712004661560 <_> <_> <_>3 15 14 4 -1. <_>3 15 7 2 2. <_>10 17 7 2 2. 0 0.0191393196582794 0.5209379196166992 0.2332071959972382 <_> <_> <_>2 2 16 4 -1. <_>10 2 8 2 2. <_>2 4 8 2 2. 0 0.0164457596838474 0.5450702905654907 0.3264234960079193 <_> <_> <_>0 8 6 12 -1. <_>3 8 3 12 2. 0 -0.0373568907380104 0.6999046802520752 0.4533241987228394 <_> <_> <_>5 7 10 2 -1. <_>5 7 5 2 2. 0 -0.0197279006242752 0.2653664946556091 0.5412809848785400 <_> <_> <_>9 7 2 5 -1. <_>10 7 1 5 2. 0 6.6972579807043076e-003 0.4480566084384918 0.7138652205467224 <_> <_> <_>13 7 6 4 -1. <_>16 7 3 2 2. <_>13 9 3 2 2. 0 7.4457528535276651e-004 0.4231350123882294 0.5471320152282715 <_> <_> <_>0 13 8 2 -1. <_>0 14 8 1 2. 0 1.1790640419349074e-003 0.5341702103614807 0.3130455017089844 <_> <_> <_>13 7 6 4 -1. <_>16 7 3 2 2. <_>13 9 3 2 2. 0 0.0349806100130081 0.5118659734725952 0.3430530130863190 <_> <_> <_>1 7 6 4 -1. <_>1 7 3 2 2. <_>4 9 3 2 2. 0 5.6859792675822973e-004 0.3532187044620514 0.5468639731407166 <_> <_> <_>12 6 1 12 -1. <_>12 12 1 6 2. 0 -0.0113406497985125 0.2842353880405426 0.5348700881004334 <_> <_> <_>9 5 2 6 -1. <_>10 5 1 6 2. 0 -6.6228108480572701e-003 0.6883640289306641 0.4492664933204651 <_> <_> <_>14 12 2 3 -1. <_>14 13 2 1 3. 0 -8.0160330981016159e-003 0.1709893941879273 0.5224308967590332 <_> <_> <_>4 12 2 3 -1. <_>4 13 2 1 3. 0 1.4206819469109178e-003 0.5290846228599548 0.2993383109569550 <_> <_> <_>8 12 4 3 -1. <_>8 13 4 1 3. 0 -2.7801711112260818e-003 0.6498854160308838 0.4460499882698059 <_> <_> <_>5 2 2 4 -1. <_>5 2 1 2 2. <_>6 4 1 2 2. 0 -1.4747589593753219e-003 0.3260438144207001 0.5388113260269165 <_> <_> <_>5 5 11 3 -1. <_>5 6 11 1 3. 0 -0.0238303393125534 0.7528941035270691 0.4801219999790192 <_> <_> <_>7 6 4 12 -1. <_>7 12 4 6 2. 0 6.9369790144264698e-003 0.5335165858268738 0.3261427879333496 <_> <_> <_>12 13 8 5 -1. <_>12 13 4 5 2. 0 8.2806255668401718e-003 0.4580394029617310 0.5737829804420471 <_> <_> <_>7 6 1 12 -1. <_>7 12 1 6 2. 0 -0.0104395002126694 0.2592320144176483 0.5233827829360962 34.5541114807128910 8 -1 <_> <_> <_> <_>1 2 6 3 -1. <_>4 2 3 3 2. 0 7.2006587870419025e-003 0.3258886039257050 0.6849808096885681 <_> <_> <_>9 5 6 10 -1. <_>12 5 3 5 2. <_>9 10 3 5 2. 0 -2.8593589086085558e-003 0.5838881134986877 0.2537829875946045 <_> <_> <_>5 5 8 12 -1. <_>5 5 4 6 2. <_>9 11 4 6 2. 0 6.8580528022721410e-004 0.5708081722259522 0.2812424004077911 <_> <_> <_>0 7 20 6 -1. <_>0 9 20 2 3. 0 7.9580191522836685e-003 0.2501051127910614 0.5544260740280151 <_> <_> <_>4 2 2 2 -1. <_>4 3 2 1 2. 0 -1.2124150525778532e-003 0.2385368049144745 0.5433350205421448 <_> <_> <_>4 18 12 2 -1. <_>8 18 4 2 3. 0 7.9426132142543793e-003 0.3955070972442627 0.6220757961273193 <_> <_> <_>7 4 4 16 -1. <_>7 12 4 8 2. 0 2.4630590341985226e-003 0.5639708042144775 0.2992357909679413 <_> <_> <_>7 6 7 8 -1. <_>7 10 7 4 2. 0 -6.0396599583327770e-003 0.2186512947082520 0.5411676764488220 <_> <_> <_>6 3 3 1 -1. <_>7 3 1 1 3. 0 -1.2988339876756072e-003 0.2350706011056900 0.5364584922790527 <_> <_> <_>11 15 2 4 -1. <_>11 17 2 2 2. 0 2.2299369447864592e-004 0.3804112970829010 0.5729606151580811 <_> <_> <_>3 5 4 8 -1. <_>3 9 4 4 2. 0 1.4654280385002494e-003 0.2510167956352234 0.5258268713951111 <_> <_> <_>7 1 6 12 -1. <_>7 7 6 6 2. 0 -8.1210042117163539e-004 0.5992823839187622 0.3851158916950226 <_> <_> <_>4 6 6 2 -1. <_>6 6 2 2 3. 0 -1.3836020370945334e-003 0.5681396126747131 0.3636586964130402 <_> <_> <_>16 4 4 6 -1. <_>16 6 4 2 3. 0 -0.0279364492744207 0.1491317003965378 0.5377560257911682 <_> <_> <_>3 3 5 2 -1. <_>3 4 5 1 2. 0 -4.6919551095925272e-004 0.3692429959774017 0.5572484731674194 <_> <_> <_>9 11 2 3 -1. <_>9 12 2 1 3. 0 -4.9829659983515739e-003 0.6758509278297424 0.4532504081726074 <_> <_> <_>2 16 4 2 -1. <_>2 17 4 1 2. 0 1.8815309740602970e-003 0.5368022918701172 0.2932539880275726 <_> <_> <_>7 13 6 6 -1. <_>10 13 3 3 2. <_>7 16 3 3 2. 0 -0.0190675500780344 0.1649377048015595 0.5330067276954651 <_> <_> <_>7 0 3 4 -1. <_>8 0 1 4 3. 0 -4.6906559728085995e-003 0.1963925957679749 0.5119361877441406 <_> <_> <_>8 15 4 3 -1. <_>8 16 4 1 3. 0 5.9777139686048031e-003 0.4671171903610230 0.7008398175239563 <_> <_> <_>0 4 4 6 -1. <_>0 6 4 2 3. 0 -0.0333031304180622 0.1155416965484619 0.5104162096977234 <_> <_> <_>5 6 12 3 -1. <_>9 6 4 3 3. 0 0.0907441079616547 0.5149660110473633 0.1306173056364059 <_> <_> <_>7 6 6 14 -1. <_>9 6 2 14 3. 0 9.3555898638442159e-004 0.3605481088161469 0.5439859032630920 <_> <_> <_>9 7 3 3 -1. <_>10 7 1 3 3. 0 0.0149016501381993 0.4886212050914764 0.7687569856643677 <_> <_> <_>6 12 2 4 -1. <_>6 14 2 2 2. 0 6.1594118596985936e-004 0.5356813073158264 0.3240939080715179 <_> <_> <_>10 12 7 6 -1. <_>10 14 7 2 3. 0 -0.0506709888577461 0.1848621964454651 0.5230404138565064 <_> <_> <_>1 0 15 2 -1. <_>1 1 15 1 2. 0 6.8665749859064817e-004 0.3840579986572266 0.5517945885658264 <_> <_> <_>14 0 6 6 -1. <_>14 0 3 6 2. 0 8.3712432533502579e-003 0.4288564026355743 0.6131753921508789 <_> <_> <_>5 3 3 1 -1. <_>6 3 1 1 3. 0 -1.2953069526702166e-003 0.2913674116134644 0.5280737876892090 <_> <_> <_>14 0 6 6 -1. <_>14 0 3 6 2. 0 -0.0419416800141335 0.7554799914360046 0.4856030941009522 <_> <_> <_>0 3 20 10 -1. <_>0 8 20 5 2. 0 -0.0235293805599213 0.2838279902935028 0.5256081223487854 <_> <_> <_>14 0 6 6 -1. <_>14 0 3 6 2. 0 0.0408574491739273 0.4870935082435608 0.6277297139167786 <_> <_> <_>0 0 6 6 -1. <_>3 0 3 6 2. 0 -0.0254068691283464 0.7099707722663879 0.4575029015541077 <_> <_> <_>19 15 1 2 -1. <_>19 16 1 1 2. 0 -4.1415440500713885e-004 0.4030886888504028 0.5469412207603455 <_> <_> <_>0 2 4 8 -1. <_>2 2 2 8 2. 0 0.0218241196125746 0.4502024054527283 0.6768701076507568 <_> <_> <_>2 1 18 4 -1. <_>11 1 9 2 2. <_>2 3 9 2 2. 0 0.0141140399500728 0.5442860722541809 0.3791700005531311 <_> <_> <_>8 12 1 2 -1. <_>8 13 1 1 2. 0 6.7214590671937913e-005 0.4200463891029358 0.5873476266860962 <_> <_> <_>5 2 10 6 -1. <_>10 2 5 3 2. <_>5 5 5 3 2. 0 -7.9417638480663300e-003 0.3792561888694763 0.5585265755653381 <_> <_> <_>9 7 2 4 -1. <_>10 7 1 4 2. 0 -7.2144409641623497e-003 0.7253103852272034 0.4603548943996429 <_> <_> <_>9 7 3 3 -1. <_>10 7 1 3 3. 0 2.5817339774221182e-003 0.4693301916122437 0.5900238752365112 <_> <_> <_>4 5 12 8 -1. <_>8 5 4 8 3. 0 0.1340931951999664 0.5149213075637817 0.1808844953775406 <_> <_> <_>15 15 4 3 -1. <_>15 16 4 1 3. 0 2.2962710354477167e-003 0.5399743914604187 0.3717867136001587 <_> <_> <_>8 18 3 1 -1. <_>9 18 1 1 3. 0 -2.1575849968940020e-003 0.2408495992422104 0.5148863792419434 <_> <_> <_>9 13 4 3 -1. <_>9 14 4 1 3. 0 -4.9196188338100910e-003 0.6573588252067566 0.4738740026950836 <_> <_> <_>7 13 4 3 -1. <_>7 14 4 1 3. 0 1.6267469618469477e-003 0.4192821979522705 0.6303114295005798 <_> <_> <_>19 15 1 2 -1. <_>19 16 1 1 2. 0 3.3413388882763684e-004 0.5540298223495483 0.3702101111412048 <_> <_> <_>0 15 8 4 -1. <_>0 17 8 2 2. 0 -0.0266980808228254 0.1710917949676514 0.5101410746574402 <_> <_> <_>9 3 6 4 -1. <_>11 3 2 4 3. 0 -0.0305618792772293 0.1904218047857285 0.5168793797492981 <_> <_> <_>8 14 4 3 -1. <_>8 15 4 1 3. 0 2.8511548880487680e-003 0.4447506964206696 0.6313853859901428 <_> <_> <_>3 14 14 6 -1. <_>3 16 14 2 3. 0 -0.0362114794552326 0.2490727007389069 0.5377349257469177 <_> <_> <_>6 3 6 6 -1. <_>6 6 6 3 2. 0 -2.4115189444273710e-003 0.5381243228912354 0.3664236962795258 <_> <_> <_>5 11 10 6 -1. <_>5 14 10 3 2. 0 -7.7253201743587852e-004 0.5530232191085815 0.3541550040245056 <_> <_> <_>3 10 3 4 -1. <_>4 10 1 4 3. 0 2.9481729143299162e-004 0.4132699072360992 0.5667243003845215 <_> <_> <_>13 9 2 2 -1. <_>13 9 1 2 2. 0 -6.2334560789167881e-003 0.0987872332334518 0.5198668837547302 <_> <_> <_>5 3 6 4 -1. <_>7 3 2 4 3. 0 -0.0262747295200825 0.0911274924874306 0.5028107166290283 <_> <_> <_>9 7 3 3 -1. <_>10 7 1 3 3. 0 5.3212260827422142e-003 0.4726648926734924 0.6222720742225647 <_> <_> <_>2 12 2 3 -1. <_>2 13 2 1 3. 0 -4.1129058226943016e-003 0.2157457023859024 0.5137804746627808 <_> <_> <_>9 8 3 12 -1. <_>9 12 3 4 3. 0 3.2457809429615736e-003 0.5410770773887634 0.3721776902675629 <_> <_> <_>3 14 4 6 -1. <_>3 14 2 3 2. <_>5 17 2 3 2. 0 -0.0163597092032433 0.7787874937057495 0.4685291945934296 <_> <_> <_>16 15 2 2 -1. <_>16 16 2 1 2. 0 3.2166109303943813e-004 0.5478987097740173 0.4240373969078064 <_> <_> <_>2 15 2 2 -1. <_>2 16 2 1 2. 0 6.4452440710738301e-004 0.5330560803413391 0.3501324951648712 <_> <_> <_>8 12 4 3 -1. <_>8 13 4 1 3. 0 -7.8909732401371002e-003 0.6923521161079407 0.4726569056510925 <_> <_> <_>0 7 20 1 -1. <_>10 7 10 1 2. 0 0.0483362115919590 0.5055900216102600 0.0757492035627365 <_> <_> <_>7 6 8 3 -1. <_>7 6 4 3 2. 0 -7.5178127735853195e-004 0.3783741891384125 0.5538573861122131 <_> <_> <_>5 7 8 2 -1. <_>9 7 4 2 2. 0 -2.4953910615295172e-003 0.3081651031970978 0.5359612107276917 <_> <_> <_>9 7 3 5 -1. <_>10 7 1 5 3. 0 -2.2385010961443186e-003 0.6633958816528320 0.4649342894554138 <_> <_> <_>8 7 3 5 -1. <_>9 7 1 5 3. 0 -1.7988430336117744e-003 0.6596844792366028 0.4347187876701355 <_> <_> <_>11 1 3 5 -1. <_>12 1 1 5 3. 0 8.7860915809869766e-003 0.5231832861900330 0.2315579950809479 <_> <_> <_>6 2 3 6 -1. <_>7 2 1 6 3. 0 3.6715380847454071e-003 0.5204250216484070 0.2977376878261566 <_> <_> <_>14 14 6 5 -1. <_>14 14 3 5 2. 0 -0.0353364497423172 0.7238878011703491 0.4861505031585693 <_> <_> <_>9 8 2 2 -1. <_>9 9 2 1 2. 0 -6.9189240457490087e-004 0.3105022013187408 0.5229824781417847 <_> <_> <_>10 7 1 3 -1. <_>10 8 1 1 3. 0 -3.3946109469980001e-003 0.3138968050479889 0.5210173726081848 <_> <_> <_>6 6 2 2 -1. <_>6 6 1 1 2. <_>7 7 1 1 2. 0 9.8569283727556467e-004 0.4536580145359039 0.6585097908973694 <_> <_> <_>2 11 18 4 -1. <_>11 11 9 2 2. <_>2 13 9 2 2. 0 -0.0501631014049053 0.1804454028606415 0.5198916792869568 <_> <_> <_>6 6 2 2 -1. <_>6 6 1 1 2. <_>7 7 1 1 2. 0 -2.2367259953171015e-003 0.7255702018737793 0.4651359021663666 <_> <_> <_>0 15 20 2 -1. <_>0 16 20 1 2. 0 7.4326287722215056e-004 0.4412921071052551 0.5898545980453491 <_> <_> <_>4 14 2 3 -1. <_>4 15 2 1 3. 0 -9.3485182151198387e-004 0.3500052988529205 0.5366017818450928 <_> <_> <_>8 14 4 3 -1. <_>8 15 4 1 3. 0 0.0174979399889708 0.4912194907665253 0.8315284848213196 <_> <_> <_>8 7 2 3 -1. <_>8 8 2 1 3. 0 -1.5200000489130616e-003 0.3570275902748108 0.5370560288429260 <_> <_> <_>9 10 2 3 -1. <_>9 11 2 1 3. 0 7.8003940870985389e-004 0.4353772103786469 0.5967335104942322 39.1072883605957030 9 -1 <_> <_> <_> <_>5 4 10 4 -1. <_>5 6 10 2 2. 0 -9.9945552647113800e-003 0.6162583231925964 0.3054533004760742 <_> <_> <_>9 7 6 4 -1. <_>12 7 3 2 2. <_>9 9 3 2 2. 0 -1.1085229925811291e-003 0.5818294882774353 0.3155578076839447 <_> <_> <_>4 7 3 6 -1. <_>4 9 3 2 3. 0 1.0364380432292819e-003 0.2552052140235901 0.5692911744117737 <_> <_> <_>11 15 4 4 -1. <_>13 15 2 2 2. <_>11 17 2 2 2. 0 6.8211311008781195e-004 0.3685089945793152 0.5934931039810181 <_> <_> <_>7 8 4 2 -1. <_>7 9 4 1 2. 0 -6.8057340104132891e-004 0.2332392036914825 0.5474792122840881 <_> <_> <_>13 1 4 3 -1. <_>13 1 2 3 2. 0 2.6068789884448051e-004 0.3257457017898560 0.5667545795440674 <_> <_> <_>5 15 4 4 -1. <_>5 15 2 2 2. <_>7 17 2 2 2. 0 5.1607372006401420e-004 0.3744716942310333 0.5845472812652588 <_> <_> <_>9 5 4 7 -1. <_>9 5 2 7 2. 0 8.5007521556690335e-004 0.3420371115207672 0.5522807240486145 <_> <_> <_>5 6 8 3 -1. <_>9 6 4 3 2. 0 -1.8607829697430134e-003 0.2804419994354248 0.5375424027442932 <_> <_> <_>9 9 2 2 -1. <_>9 10 2 1 2. 0 -1.5033970121294260e-003 0.2579050958156586 0.5498952269554138 <_> <_> <_>7 15 5 3 -1. <_>7 16 5 1 3. 0 2.3478909861296415e-003 0.4175156056880951 0.6313710808753967 <_> <_> <_>11 10 4 3 -1. <_>11 10 2 3 2. 0 -2.8880240279249847e-004 0.5865169763565064 0.4052666127681732 <_> <_> <_>6 9 8 10 -1. <_>6 14 8 5 2. 0 8.9405477046966553e-003 0.5211141109466553 0.2318654060363770 <_> <_> <_>10 11 6 2 -1. <_>10 11 3 2 2. 0 -0.0193277392536402 0.2753432989120483 0.5241525769233704 <_> <_> <_>4 11 6 2 -1. <_>7 11 3 2 2. 0 -2.0202060113660991e-004 0.5722978711128235 0.3677195906639099 <_> <_> <_>11 3 8 1 -1. <_>11 3 4 1 2. 0 2.1179069299250841e-003 0.4466108083724976 0.5542430877685547 <_> <_> <_>6 3 3 2 -1. <_>7 3 1 2 3. 0 -1.7743760254234076e-003 0.2813253104686737 0.5300959944725037 <_> <_> <_>14 5 6 5 -1. <_>14 5 3 5 2. 0 4.2234458960592747e-003 0.4399709999561310 0.5795428156852722 <_> <_> <_>7 5 2 12 -1. <_>7 11 2 6 2. 0 -0.0143752200528979 0.2981117963790894 0.5292059183120728 <_> <_> <_>8 11 4 3 -1. <_>8 12 4 1 3. 0 -0.0153491804376245 0.7705215215682983 0.4748171865940094 <_> <_> <_>4 1 2 3 -1. <_>5 1 1 3 2. 0 1.5152279956964776e-005 0.3718844056129456 0.5576897263526917 <_> <_> <_>18 3 2 6 -1. <_>18 5 2 2 3. 0 -9.1293919831514359e-003 0.3615196049213409 0.5286766886711121 <_> <_> <_>0 3 2 6 -1. <_>0 5 2 2 3. 0 2.2512159775942564e-003 0.5364704728126526 0.3486298024654388 <_> <_> <_>9 12 2 3 -1. <_>9 13 2 1 3. 0 -4.9696918576955795e-003 0.6927651762962341 0.4676836133003235 <_> <_> <_>7 13 4 3 -1. <_>7 14 4 1 3. 0 -0.0128290103748441 0.7712153792381287 0.4660735130310059 <_> <_> <_>18 0 2 6 -1. <_>18 2 2 2 3. 0 -9.3660065904259682e-003 0.3374983966350555 0.5351287722587585 <_> <_> <_>0 0 2 6 -1. <_>0 2 2 2 3. 0 3.2452319283038378e-003 0.5325189828872681 0.3289610147476196 <_> <_> <_>8 14 6 3 -1. <_>8 15 6 1 3. 0 -0.0117235602810979 0.6837652921676636 0.4754300117492676 <_> <_> <_>7 4 2 4 -1. <_>8 4 1 4 2. 0 2.9257940695970319e-005 0.3572087883949280 0.5360502004623413 <_> <_> <_>8 5 4 6 -1. <_>8 7 4 2 3. 0 -2.2244219508138485e-005 0.5541427135467529 0.3552064001560211 <_> <_> <_>6 4 2 2 -1. <_>7 4 1 2 2. 0 5.0881509669125080e-003 0.5070844292640686 0.1256462037563324 <_> <_> <_>3 14 14 4 -1. <_>10 14 7 2 2. <_>3 16 7 2 2. 0 0.0274296794086695 0.5269560217857361 0.1625818014144898 <_> <_> <_>6 15 6 2 -1. <_>6 15 3 1 2. <_>9 16 3 1 2. 0 -6.4142867922782898e-003 0.7145588994026184 0.4584197103977203 <_> <_> <_>14 15 6 2 -1. <_>14 16 6 1 2. 0 3.3479959238320589e-003 0.5398612022399902 0.3494696915149689 <_> <_> <_>2 12 12 8 -1. <_>2 16 12 4 2. 0 -0.0826354920864105 0.2439192980527878 0.5160226225852966 <_> <_> <_>7 7 7 2 -1. <_>7 8 7 1 2. 0 1.0261740535497665e-003 0.3886891901493073 0.5767908096313477 <_> <_> <_>0 2 18 2 -1. <_>0 3 18 1 2. 0 -1.6307090409100056e-003 0.3389458060264587 0.5347700715065002 <_> <_> <_>9 6 2 5 -1. <_>9 6 1 5 2. 0 2.4546680506318808e-003 0.4601413905620575 0.6387246847152710 <_> <_> <_>7 5 3 8 -1. <_>8 5 1 8 3. 0 -9.9476519972085953e-004 0.5769879221916199 0.4120396077632904 <_> <_> <_>9 6 3 4 -1. <_>10 6 1 4 3. 0 0.0154091902077198 0.4878709018230438 0.7089822292327881 <_> <_> <_>4 13 3 2 -1. <_>4 14 3 1 2. 0 1.1784400558099151e-003 0.5263553261756897 0.2895244956016541 <_> <_> <_>9 4 6 3 -1. <_>11 4 2 3 3. 0 -0.0277019198983908 0.1498828977346420 0.5219606757164002 <_> <_> <_>5 4 6 3 -1. <_>7 4 2 3 3. 0 -0.0295053999871016 0.0248933192342520 0.4999816119670868 <_> <_> <_>14 11 5 2 -1. <_>14 12 5 1 2. 0 4.5159430010244250e-004 0.5464622974395752 0.4029662907123566 <_> <_> <_>1 2 6 9 -1. <_>3 2 2 9 3. 0 7.1772639639675617e-003 0.4271056950092316 0.5866296887397766 <_> <_> <_>14 6 6 13 -1. <_>14 6 3 13 2. 0 -0.0741820484399796 0.6874179244041443 0.4919027984142304 <_> <_> <_>3 6 14 8 -1. <_>3 6 7 4 2. <_>10 10 7 4 2. 0 -0.0172541607171297 0.3370676040649414 0.5348739027976990 <_> <_> <_>16 0 4 11 -1. <_>16 0 2 11 2. 0 0.0148515598848462 0.4626792967319489 0.6129904985427856 <_> <_> <_>3 4 12 12 -1. <_>3 4 6 6 2. <_>9 10 6 6 2. 0 0.0100020002573729 0.5346122980117798 0.3423453867435455 <_> <_> <_>11 4 5 3 -1. <_>11 5 5 1 3. 0 2.0138120744377375e-003 0.4643830060958862 0.5824304223060608 <_> <_> <_>4 11 4 2 -1. <_>4 12 4 1 2. 0 1.5135470312088728e-003 0.5196396112442017 0.2856149971485138 <_> <_> <_>10 7 2 2 -1. <_>10 7 1 2 2. 0 3.1381431035697460e-003 0.4838162958621979 0.5958529710769653 <_> <_> <_>8 7 2 2 -1. <_>9 7 1 2 2. 0 -5.1450440660119057e-003 0.8920302987098694 0.4741412103176117 <_> <_> <_>9 17 3 2 -1. <_>10 17 1 2 3. 0 -4.4736708514392376e-003 0.2033942937850952 0.5337278842926025 <_> <_> <_>5 6 3 3 -1. <_>5 7 3 1 3. 0 1.9628470763564110e-003 0.4571633934974670 0.6725863218307495 <_> <_> <_>10 0 3 3 -1. <_>11 0 1 3 3. 0 5.4260450415313244e-003 0.5271108150482178 0.2845670878887177 <_> <_> <_>5 6 6 2 -1. <_>5 6 3 1 2. <_>8 7 3 1 2. 0 4.9611460417509079e-004 0.4138312935829163 0.5718597769737244 <_> <_> <_>12 16 4 3 -1. <_>12 17 4 1 3. 0 9.3728788197040558e-003 0.5225151181221008 0.2804847061634064 <_> <_> <_>3 12 3 2 -1. <_>3 13 3 1 2. 0 6.0500897234305739e-004 0.5236768722534180 0.3314523994922638 <_> <_> <_>9 12 3 2 -1. <_>9 13 3 1 2. 0 5.6792551185935736e-004 0.4531059861183167 0.6276971101760864 <_> <_> <_>1 11 16 4 -1. <_>1 11 8 2 2. <_>9 13 8 2 2. 0 0.0246443394571543 0.5130851864814758 0.2017143964767456 <_> <_> <_>12 4 3 3 -1. <_>12 5 3 1 3. 0 -0.0102904504165053 0.7786595225334168 0.4876641035079956 <_> <_> <_>4 4 5 3 -1. <_>4 5 5 1 3. 0 2.0629419013857841e-003 0.4288598895072937 0.5881264209747315 <_> <_> <_>12 16 4 3 -1. <_>12 17 4 1 3. 0 -5.0519481301307678e-003 0.3523977994918823 0.5286008715629578 <_> <_> <_>5 4 3 3 -1. <_>5 5 3 1 3. 0 -5.7692620903253555e-003 0.6841086149215698 0.4588094055652618 <_> <_> <_>9 0 2 2 -1. <_>9 1 2 1 2. 0 -4.5789941214025021e-004 0.3565520048141480 0.5485978126525879 <_> <_> <_>8 9 4 2 -1. <_>8 10 4 1 2. 0 -7.5918837683275342e-004 0.3368793129920960 0.5254197120666504 <_> <_> <_>8 8 4 3 -1. <_>8 9 4 1 3. 0 -1.7737259622663260e-003 0.3422161042690277 0.5454015135765076 <_> <_> <_>0 13 6 3 -1. <_>2 13 2 3 3. 0 -8.5610467940568924e-003 0.6533612012863159 0.4485856890678406 <_> <_> <_>16 14 3 2 -1. <_>16 15 3 1 2. 0 1.7277270089834929e-003 0.5307580232620239 0.3925352990627289 <_> <_> <_>1 18 18 2 -1. <_>7 18 6 2 3. 0 -0.0281996093690395 0.6857458949089050 0.4588584005832672 <_> <_> <_>16 14 3 2 -1. <_>16 15 3 1 2. 0 -1.7781109781935811e-003 0.4037851095199585 0.5369856953620911 <_> <_> <_>1 14 3 2 -1. <_>1 15 3 1 2. 0 3.3177141449414194e-004 0.5399798750877380 0.3705750107765198 <_> <_> <_>7 14 6 3 -1. <_>7 15 6 1 3. 0 2.6385399978607893e-003 0.4665437042713165 0.6452730894088745 <_> <_> <_>5 14 8 3 -1. <_>5 15 8 1 3. 0 -2.1183069329708815e-003 0.5914781093597412 0.4064677059650421 <_> <_> <_>10 6 4 14 -1. <_>10 6 2 14 2. 0 -0.0147732896730304 0.3642038106918335 0.5294762849807739 <_> <_> <_>6 6 4 14 -1. <_>8 6 2 14 2. 0 -0.0168154407292604 0.2664231956005096 0.5144972801208496 <_> <_> <_>13 5 2 3 -1. <_>13 6 2 1 3. 0 -6.3370140269398689e-003 0.6779531240463257 0.4852097928524017 <_> <_> <_>7 16 6 1 -1. <_>9 16 2 1 3. 0 -4.4560048991115764e-005 0.5613964796066284 0.4153054058551788 <_> <_> <_>9 12 3 3 -1. <_>9 13 3 1 3. 0 -1.0240620467811823e-003 0.5964478254318237 0.4566304087638855 <_> <_> <_>7 0 3 3 -1. <_>8 0 1 3 3. 0 -2.3161689750850201e-003 0.2976115047931671 0.5188159942626953 <_> <_> <_>4 0 16 18 -1. <_>4 9 16 9 2. 0 0.5321757197380066 0.5187839269638062 0.2202631980180740 <_> <_> <_>1 1 16 14 -1. <_>1 8 16 7 2. 0 -0.1664305031299591 0.1866022944450378 0.5060343146324158 <_> <_> <_>3 9 15 4 -1. <_>8 9 5 4 3. 0 0.1125352978706360 0.5212125182151794 0.1185022965073586 <_> <_> <_>6 12 7 3 -1. <_>6 13 7 1 3. 0 9.3046864494681358e-003 0.4589937031269074 0.6826149225234985 <_> <_> <_>14 15 2 3 -1. <_>14 16 2 1 3. 0 -4.6255099587142467e-003 0.3079940974712372 0.5225008726119995 <_> <_> <_>2 3 16 14 -1. <_>2 3 8 7 2. <_>10 10 8 7 2. 0 -0.1111646965146065 0.2101044058799744 0.5080801844596863 <_> <_> <_>16 2 4 18 -1. <_>18 2 2 9 2. <_>16 11 2 9 2. 0 -0.0108884396031499 0.5765355229377747 0.4790464043617249 <_> <_> <_>4 15 2 3 -1. <_>4 16 2 1 3. 0 5.8564301580190659e-003 0.5065100193023682 0.1563598960638046 <_> <_> <_>16 2 4 18 -1. <_>18 2 2 9 2. <_>16 11 2 9 2. 0 0.0548543892800808 0.4966914951801300 0.7230510711669922 <_> <_> <_>1 1 8 3 -1. <_>1 2 8 1 3. 0 -0.0111973397433758 0.2194979041814804 0.5098798274993897 <_> <_> <_>8 11 4 3 -1. <_>8 12 4 1 3. 0 4.4069071300327778e-003 0.4778401851654053 0.6770902872085571 <_> <_> <_>5 11 5 9 -1. <_>5 14 5 3 3. 0 -0.0636652931571007 0.1936362981796265 0.5081024169921875 <_> <_> <_>16 0 4 11 -1. <_>16 0 2 11 2. 0 -9.8081491887569427e-003 0.5999063253402710 0.4810341000556946 <_> <_> <_>7 0 6 1 -1. <_>9 0 2 1 3. 0 -2.1717099007219076e-003 0.3338333964347839 0.5235472917556763 <_> <_> <_>16 3 3 7 -1. <_>17 3 1 7 3. 0 -0.0133155202493072 0.6617069840431213 0.4919213056564331 <_> <_> <_>1 3 3 7 -1. <_>2 3 1 7 3. 0 2.5442079640924931e-003 0.4488744139671326 0.6082184910774231 <_> <_> <_>7 8 6 12 -1. <_>7 12 6 4 3. 0 0.0120378397405148 0.5409392118453980 0.3292432129383087 <_> <_> <_>0 0 4 11 -1. <_>2 0 2 11 2. 0 -0.0207010507583618 0.6819120049476624 0.4594995975494385 <_> <_> <_>14 0 6 20 -1. <_>14 0 3 20 2. 0 0.0276082791388035 0.4630792140960693 0.5767282843589783 <_> <_> <_>0 3 1 2 -1. <_>0 4 1 1 2. 0 1.2370620388537645e-003 0.5165379047393799 0.2635016143321991 <_> <_> <_>5 5 10 8 -1. <_>10 5 5 4 2. <_>5 9 5 4 2. 0 -0.0376693382859230 0.2536393105983734 0.5278980135917664 <_> <_> <_>4 7 12 4 -1. <_>4 7 6 2 2. <_>10 9 6 2 2. 0 -1.8057259730994701e-003 0.3985156118869782 0.5517500042915344 50.6104812622070310 10 -1 <_> <_> <_> <_>2 1 6 4 -1. <_>5 1 3 4 2. 0 4.4299028813838959e-003 0.2891018092632294 0.6335226297378540 <_> <_> <_>9 7 6 4 -1. <_>12 7 3 2 2. <_>9 9 3 2 2. 0 -2.3813319858163595e-003 0.6211789250373840 0.3477487862110138 <_> <_> <_>5 6 2 6 -1. <_>5 9 2 3 2. 0 2.2915711160749197e-003 0.2254412025213242 0.5582118034362793 <_> <_> <_>9 16 6 4 -1. <_>12 16 3 2 2. <_>9 18 3 2 2. 0 9.9457940086722374e-004 0.3711710870265961 0.5930070877075195 <_> <_> <_>9 4 2 12 -1. <_>9 10 2 6 2. 0 7.7164667891338468e-004 0.5651720166206360 0.3347995877265930 <_> <_> <_>7 1 6 18 -1. <_>9 1 2 18 3. 0 -1.1386410333216190e-003 0.3069126009941101 0.5508630871772766 <_> <_> <_>4 12 12 2 -1. <_>8 12 4 2 3. 0 -1.6403039626311511e-004 0.5762827992439270 0.3699047863483429 <_> <_> <_>8 8 6 2 -1. <_>8 9 6 1 2. 0 2.9793529392918572e-005 0.2644244134426117 0.5437911152839661 <_> <_> <_>8 0 3 6 -1. <_>9 0 1 6 3. 0 8.5774902254343033e-003 0.5051138997077942 0.1795724928379059 <_> <_> <_>11 18 3 2 -1. <_>11 19 3 1 2. 0 -2.6032689493149519e-004 0.5826969146728516 0.4446826875209808 <_> <_> <_>1 1 17 4 -1. <_>1 3 17 2 2. 0 -6.1404630541801453e-003 0.3113852143287659 0.5346971750259399 <_> <_> <_>11 8 4 12 -1. <_>11 8 2 12 2. 0 -0.0230869501829147 0.3277946114540100 0.5331197977066040 <_> <_> <_>8 14 4 3 -1. <_>8 15 4 1 3. 0 -0.0142436502501369 0.7381709814071655 0.4588063061237335 <_> <_> <_>12 3 2 17 -1. <_>12 3 1 17 2. 0 0.0194871295243502 0.5256630778312683 0.2274471968412399 <_> <_> <_>4 7 6 1 -1. <_>6 7 2 1 3. 0 -9.6681108698248863e-004 0.5511230826377869 0.3815006911754608 <_> <_> <_>18 3 2 3 -1. <_>18 4 2 1 3. 0 3.1474709976464510e-003 0.5425636768341065 0.2543726861476898 <_> <_> <_>8 4 3 4 -1. <_>8 6 3 2 2. 0 -1.8026070029009134e-004 0.5380191802978516 0.3406304121017456 <_> <_> <_>4 5 12 10 -1. <_>4 10 12 5 2. 0 -6.0266260989010334e-003 0.3035801947116852 0.5420572161674500 <_> <_> <_>5 18 4 2 -1. <_>7 18 2 2 2. 0 4.4462960795499384e-004 0.3990997076034546 0.5660110116004944 <_> <_> <_>17 2 3 6 -1. <_>17 4 3 2 3. 0 2.2609760053455830e-003 0.5562806725502014 0.3940688073635101 <_> <_> <_>7 7 6 6 -1. <_>9 7 2 6 3. 0 0.0511330589652061 0.4609653949737549 0.7118561863899231 <_> <_> <_>17 2 3 6 -1. <_>17 4 3 2 3. 0 -0.0177863091230392 0.2316166013479233 0.5322144031524658 <_> <_> <_>8 0 3 4 -1. <_>9 0 1 4 3. 0 -4.9679628573358059e-003 0.2330771982669830 0.5122029185295105 <_> <_> <_>9 14 2 3 -1. <_>9 15 2 1 3. 0 2.0667689386755228e-003 0.4657444059848785 0.6455488204956055 <_> <_> <_>0 12 6 3 -1. <_>0 13 6 1 3. 0 7.4413768015801907e-003 0.5154392123222351 0.2361633926630020 <_> <_> <_>8 14 4 3 -1. <_>8 15 4 1 3. 0 -3.6277279723435640e-003 0.6219773292541504 0.4476661086082459 <_> <_> <_>3 12 2 3 -1. <_>3 13 2 1 3. 0 -5.3530759178102016e-003 0.1837355047464371 0.5102208256721497 <_> <_> <_>5 6 12 7 -1. <_>9 6 4 7 3. 0 0.1453091949224472 0.5145987272262573 0.1535930931568146 <_> <_> <_>0 2 3 6 -1. <_>0 4 3 2 3. 0 2.4394490756094456e-003 0.5343660116195679 0.3624661862850189 <_> <_> <_>14 6 1 3 -1. <_>14 7 1 1 3. 0 -3.1283390708267689e-003 0.6215007901191711 0.4845592081546783 <_> <_> <_>2 0 3 14 -1. <_>3 0 1 14 3. 0 1.7940260004252195e-003 0.4299261868000031 0.5824198126792908 <_> <_> <_>12 14 5 6 -1. <_>12 16 5 2 3. 0 0.0362538211047649 0.5260334014892578 0.1439467966556549 <_> <_> <_>4 14 5 6 -1. <_>4 16 5 2 3. 0 -5.1746722310781479e-003 0.3506538867950440 0.5287045240402222 <_> <_> <_>11 10 2 2 -1. <_>12 10 1 1 2. <_>11 11 1 1 2. 0 6.5383297624066472e-004 0.4809640944004059 0.6122040152549744 <_> <_> <_>5 0 3 14 -1. <_>6 0 1 14 3. 0 -0.0264802295714617 0.1139362007379532 0.5045586228370667 <_> <_> <_>10 15 2 3 -1. <_>10 16 2 1 3. 0 -3.0440660193562508e-003 0.6352095007896423 0.4794734120368958 <_> <_> <_>0 2 2 3 -1. <_>0 3 2 1 3. 0 3.6993520334362984e-003 0.5131118297576904 0.2498510926961899 <_> <_> <_>5 11 12 6 -1. <_>5 14 12 3 2. 0 -3.6762931267730892e-004 0.5421394705772400 0.3709532022476196 <_> <_> <_>6 11 3 9 -1. <_>6 14 3 3 3. 0 -0.0413822606205940 0.1894959956407547 0.5081691741943359 <_> <_> <_>11 10 2 2 -1. <_>12 10 1 1 2. <_>11 11 1 1 2. 0 -1.0532729793339968e-003 0.6454367041587830 0.4783608913421631 <_> <_> <_>5 6 1 3 -1. <_>5 7 1 1 3. 0 -2.1648600231856108e-003 0.6215031147003174 0.4499826133251190 <_> <_> <_>4 9 13 3 -1. <_>4 10 13 1 3. 0 -5.6747748749330640e-004 0.3712610900402069 0.5419334769248962 <_> <_> <_>1 7 15 6 -1. <_>6 7 5 6 3. 0 0.1737584024667740 0.5023643970489502 0.1215742006897926 <_> <_> <_>4 5 12 6 -1. <_>8 5 4 6 3. 0 -2.9049699660390615e-003 0.3240267932415009 0.5381883978843689 <_> <_> <_>8 10 4 3 -1. <_>8 11 4 1 3. 0 1.2299539521336555e-003 0.4165507853031158 0.5703486204147339 <_> <_> <_>15 14 1 3 -1. <_>15 15 1 1 3. 0 -5.4329237900674343e-004 0.3854042887687683 0.5547549128532410 <_> <_> <_>1 11 5 3 -1. <_>1 12 5 1 3. 0 -8.3297258242964745e-003 0.2204494029283524 0.5097082853317261 <_> <_> <_>7 1 7 12 -1. <_>7 7 7 6 2. 0 -1.0417630255687982e-004 0.5607066154479981 0.4303036034107208 <_> <_> <_>0 1 6 10 -1. <_>0 1 3 5 2. <_>3 6 3 5 2. 0 0.0312047004699707 0.4621657133102417 0.6982004046440125 <_> <_> <_>16 1 4 3 -1. <_>16 2 4 1 3. 0 7.8943502157926559e-003 0.5269594192504883 0.2269068062305450 <_> <_> <_>5 5 2 3 -1. <_>5 6 2 1 3. 0 -4.3645310215651989e-003 0.6359223127365112 0.4537956118583679 <_> <_> <_>12 2 3 5 -1. <_>13 2 1 5 3. 0 7.6793059706687927e-003 0.5274767875671387 0.2740483880043030 <_> <_> <_>0 3 4 6 -1. <_>0 5 4 2 3. 0 -0.0254311393946409 0.2038519978523254 0.5071732997894287 <_> <_> <_>8 12 4 2 -1. <_>8 13 4 1 2. 0 8.2000601105391979e-004 0.4587455093860626 0.6119868159294128 <_> <_> <_>8 18 3 1 -1. <_>9 18 1 1 3. 0 2.9284600168466568e-003 0.5071274042129517 0.2028204947710037 <_> <_> <_>11 10 2 2 -1. <_>12 10 1 1 2. <_>11 11 1 1 2. 0 4.5256470912136137e-005 0.4812104105949402 0.5430821776390076 <_> <_> <_>7 10 2 2 -1. <_>7 10 1 1 2. <_>8 11 1 1 2. 0 1.3158309739083052e-003 0.4625813961029053 0.6779323220252991 <_> <_> <_>11 11 4 4 -1. <_>11 13 4 2 2. 0 1.5870389761403203e-003 0.5386291742324829 0.3431465029716492 <_> <_> <_>8 12 3 8 -1. <_>9 12 1 8 3. 0 -0.0215396601706743 0.0259425006806850 0.5003222823143005 <_> <_> <_>13 0 6 3 -1. <_>13 1 6 1 3. 0 0.0143344802781940 0.5202844738960266 0.1590632945299149 <_> <_> <_>8 8 3 4 -1. <_>9 8 1 4 3. 0 -8.3881383761763573e-003 0.7282481193542481 0.4648044109344482 <_> <_> <_>5 7 10 10 -1. <_>10 7 5 5 2. <_>5 12 5 5 2. 0 9.1906841844320297e-003 0.5562356710433960 0.3923191130161285 <_> <_> <_>3 18 8 2 -1. <_>3 18 4 1 2. <_>7 19 4 1 2. 0 -5.8453059755265713e-003 0.6803392767906189 0.4629127979278565 <_> <_> <_>10 2 6 8 -1. <_>12 2 2 8 3. 0 -0.0547077991068363 0.2561671137809753 0.5206125974655151 <_> <_> <_>4 2 6 8 -1. <_>6 2 2 8 3. 0 9.1142775490880013e-003 0.5189620256423950 0.3053877055644989 <_> <_> <_>11 0 3 7 -1. <_>12 0 1 7 3. 0 -0.0155750000849366 0.1295074969530106 0.5169094800949097 <_> <_> <_>7 11 2 1 -1. <_>8 11 1 1 2. 0 -1.2050600344082341e-004 0.5735098123550415 0.4230825006961823 <_> <_> <_>15 14 1 3 -1. <_>15 15 1 1 3. 0 1.2273970060050488e-003 0.5289878249168396 0.4079791903495789 <_> <_> <_>7 15 2 2 -1. <_>7 15 1 1 2. <_>8 16 1 1 2. 0 -1.2186600361019373e-003 0.6575639843940735 0.4574409127235413 <_> <_> <_>15 14 1 3 -1. <_>15 15 1 1 3. 0 -3.3256649039685726e-003 0.3628047108650208 0.5195019841194153 <_> <_> <_>6 0 3 7 -1. <_>7 0 1 7 3. 0 -0.0132883097976446 0.1284265965223312 0.5043488740921021 <_> <_> <_>18 1 2 7 -1. <_>18 1 1 7 2. 0 -3.3839771058410406e-003 0.6292240023612976 0.4757505953311920 <_> <_> <_>2 0 8 20 -1. <_>2 10 8 10 2. 0 -0.2195422053337097 0.1487731933593750 0.5065013766288757 <_> <_> <_>3 0 15 6 -1. <_>3 2 15 2 3. 0 4.9111708067357540e-003 0.4256102144718170 0.5665838718414307 <_> <_> <_>4 3 12 2 -1. <_>4 4 12 1 2. 0 -1.8744950648397207e-004 0.4004144072532654 0.5586857199668884 <_> <_> <_>16 0 4 5 -1. <_>16 0 2 5 2. 0 -5.2178641781210899e-003 0.6009116172790527 0.4812706112861633 <_> <_> <_>7 0 3 4 -1. <_>8 0 1 4 3. 0 -1.1111519997939467e-003 0.3514933884143829 0.5287089943885803 <_> <_> <_>16 0 4 5 -1. <_>16 0 2 5 2. 0 4.4036400504410267e-003 0.4642275869846344 0.5924085974693298 <_> <_> <_>1 7 6 13 -1. <_>3 7 2 13 3. 0 0.1229949966073036 0.5025529265403748 0.0691524818539619 <_> <_> <_>16 0 4 5 -1. <_>16 0 2 5 2. 0 -0.0123135102912784 0.5884591937065125 0.4934012889862061 <_> <_> <_>0 0 4 5 -1. <_>2 0 2 5 2. 0 4.1471039876341820e-003 0.4372239112854004 0.5893477797508240 <_> <_> <_>14 12 3 6 -1. <_>14 14 3 2 3. 0 -3.5502649843692780e-003 0.4327551126480103 0.5396270155906677 <_> <_> <_>3 12 3 6 -1. <_>3 14 3 2 3. 0 -0.0192242693156004 0.1913134008646011 0.5068330764770508 <_> <_> <_>16 1 4 3 -1. <_>16 2 4 1 3. 0 1.4395059552043676e-003 0.5308178067207336 0.4243533015251160 <_> <_> <_>8 7 2 10 -1. <_>8 7 1 5 2. <_>9 12 1 5 2. 0 -6.7751999013125896e-003 0.6365395784378052 0.4540086090564728 <_> <_> <_>11 11 4 4 -1. <_>11 13 4 2 2. 0 7.0119630545377731e-003 0.5189834237098694 0.3026199936866760 <_> <_> <_>0 1 4 3 -1. <_>0 2 4 1 3. 0 5.4014651104807854e-003 0.5105062127113342 0.2557682991027832 <_> <_> <_>13 4 1 3 -1. <_>13 5 1 1 3. 0 9.0274988906458020e-004 0.4696914851665497 0.5861827731132507 <_> <_> <_>7 15 3 5 -1. <_>8 15 1 5 3. 0 0.0114744501188397 0.5053645968437195 0.1527177989482880 <_> <_> <_>9 7 3 5 -1. <_>10 7 1 5 3. 0 -6.7023430019617081e-003 0.6508980989456177 0.4890604019165039 <_> <_> <_>8 7 3 5 -1. <_>9 7 1 5 3. 0 -2.0462959073483944e-003 0.6241816878318787 0.4514600038528442 <_> <_> <_>10 6 4 14 -1. <_>10 6 2 14 2. 0 -9.9951568990945816e-003 0.3432781100273132 0.5400953888893127 <_> <_> <_>0 5 5 6 -1. <_>0 7 5 2 3. 0 -0.0357007086277008 0.1878059059381485 0.5074077844619751 <_> <_> <_>9 5 6 4 -1. <_>9 5 3 4 2. 0 4.5584561303257942e-004 0.3805277049541473 0.5402569770812988 <_> <_> <_>0 0 18 10 -1. <_>6 0 6 10 3. 0 -0.0542606003582478 0.6843714714050293 0.4595097005367279 <_> <_> <_>10 6 4 14 -1. <_>10 6 2 14 2. 0 6.0600461438298225e-003 0.5502905249595642 0.4500527977943420 <_> <_> <_>6 6 4 14 -1. <_>8 6 2 14 2. 0 -6.4791832119226456e-003 0.3368858098983765 0.5310757160186768 <_> <_> <_>13 4 1 3 -1. <_>13 5 1 1 3. 0 -1.4939469983801246e-003 0.6487640142440796 0.4756175875663757 <_> <_> <_>5 1 2 3 -1. <_>6 1 1 3 2. 0 1.4610530342906713e-005 0.4034579098224640 0.5451064109802246 <_> <_> <_>18 1 2 18 -1. <_>19 1 1 9 2. <_>18 10 1 9 2. 0 -7.2321938350796700e-003 0.6386873722076416 0.4824739992618561 <_> <_> <_>2 1 4 3 -1. <_>2 2 4 1 3. 0 -4.0645818226039410e-003 0.2986421883106232 0.5157335996627808 <_> <_> <_>18 1 2 18 -1. <_>19 1 1 9 2. <_>18 10 1 9 2. 0 0.0304630808532238 0.5022199749946594 0.7159956097602844 <_> <_> <_>1 14 4 6 -1. <_>1 14 2 3 2. <_>3 17 2 3 2. 0 -8.0544911324977875e-003 0.6492452025413513 0.4619275033473969 <_> <_> <_>10 11 7 6 -1. <_>10 13 7 2 3. 0 0.0395051389932632 0.5150570869445801 0.2450613975524902 <_> <_> <_>0 10 6 10 -1. <_>0 10 3 5 2. <_>3 15 3 5 2. 0 8.4530208259820938e-003 0.4573669135570526 0.6394037008285523 <_> <_> <_>11 0 3 4 -1. <_>12 0 1 4 3. 0 -1.1688120430335402e-003 0.3865512013435364 0.5483661293983460 <_> <_> <_>5 10 5 6 -1. <_>5 13 5 3 2. 0 2.8070670086890459e-003 0.5128579139709473 0.2701480090618134 <_> <_> <_>14 6 1 8 -1. <_>14 10 1 4 2. 0 4.7365209320560098e-004 0.4051581919193268 0.5387461185455322 <_> <_> <_>1 7 18 6 -1. <_>1 7 9 3 2. <_>10 10 9 3 2. 0 0.0117410803213716 0.5295950174331665 0.3719413876533508 <_> <_> <_>9 7 2 2 -1. <_>9 7 1 2 2. 0 3.1833238899707794e-003 0.4789406955242157 0.6895126104354858 <_> <_> <_>5 9 4 5 -1. <_>7 9 2 5 2. 0 7.0241501089185476e-004 0.5384489297866821 0.3918080925941467 54.6200714111328130 11 -1 <_> <_> <_> <_>7 6 6 3 -1. <_>9 6 2 3 3. 0 0.0170599296689034 0.3948527872562408 0.7142534852027893 <_> <_> <_>1 0 18 4 -1. <_>7 0 6 4 3. 0 0.0218408405780792 0.3370316028594971 0.6090016961097717 <_> <_> <_>7 15 2 4 -1. <_>7 17 2 2 2. 0 2.4520049919374287e-004 0.3500576019287109 0.5987902283668518 <_> <_> <_>1 0 19 9 -1. <_>1 3 19 3 3. 0 8.3272606134414673e-003 0.3267528116703033 0.5697240829467773 <_> <_> <_>3 7 3 6 -1. <_>3 9 3 2 3. 0 5.7148298947140574e-004 0.3044599890708923 0.5531656742095947 <_> <_> <_>13 7 4 4 -1. <_>15 7 2 2 2. <_>13 9 2 2 2. 0 6.7373987985774875e-004 0.3650012016296387 0.5672631263732910 <_> <_> <_>3 7 4 4 -1. <_>3 7 2 2 2. <_>5 9 2 2 2. 0 3.4681590477703139e-005 0.3313541114330292 0.5388727188110352 <_> <_> <_>9 6 10 8 -1. <_>9 10 10 4 2. 0 -5.8563398197293282e-003 0.2697942852973938 0.5498778820037842 <_> <_> <_>3 8 14 12 -1. <_>3 14 14 6 2. 0 8.5102273151278496e-003 0.5269358158111572 0.2762879133224487 <_> <_> <_>6 5 10 12 -1. <_>11 5 5 6 2. <_>6 11 5 6 2. 0 -0.0698172077536583 0.2909603118896484 0.5259246826171875 <_> <_> <_>9 11 2 3 -1. <_>9 12 2 1 3. 0 -8.6113670840859413e-004 0.5892577171325684 0.4073697924613953 <_> <_> <_>9 5 6 5 -1. <_>9 5 3 5 2. 0 9.7149249631911516e-004 0.3523564040660858 0.5415862202644348 <_> <_> <_>9 4 2 4 -1. <_>9 6 2 2 2. 0 -1.4727490452060010e-005 0.5423017740249634 0.3503156006336212 <_> <_> <_>9 5 6 5 -1. <_>9 5 3 5 2. 0 0.0484202913939953 0.5193945765495300 0.3411195874214172 <_> <_> <_>5 5 6 5 -1. <_>8 5 3 5 2. 0 1.3257140526548028e-003 0.3157769143581390 0.5335376262664795 <_> <_> <_>11 2 6 1 -1. <_>13 2 2 1 3. 0 1.4922149603080470e-005 0.4451299905776978 0.5536553859710693 <_> <_> <_>3 2 6 1 -1. <_>5 2 2 1 3. 0 -2.7173398993909359e-003 0.3031741976737976 0.5248088836669922 <_> <_> <_>13 5 2 3 -1. <_>13 6 2 1 3. 0 2.9219500720500946e-003 0.4781453013420105 0.6606041789054871 <_> <_> <_>0 10 1 4 -1. <_>0 12 1 2 2. 0 -1.9804988987743855e-003 0.3186308145523071 0.5287625193595886 <_> <_> <_>13 5 2 3 -1. <_>13 6 2 1 3. 0 -4.0012109093368053e-003 0.6413596868515015 0.4749928116798401 <_> <_> <_>8 18 3 2 -1. <_>9 18 1 2 3. 0 -4.3491991236805916e-003 0.1507498025894165 0.5098996758460999 <_> <_> <_>6 15 9 2 -1. <_>6 16 9 1 2. 0 1.3490889687091112e-003 0.4316158890724182 0.5881167054176331 <_> <_> <_>8 14 4 3 -1. <_>8 15 4 1 3. 0 0.0185970701277256 0.4735553860664368 0.9089794158935547 <_> <_> <_>18 4 2 4 -1. <_>18 6 2 2 2. 0 -1.8562379991635680e-003 0.3553189039230347 0.5577837228775024 <_> <_> <_>5 5 2 3 -1. <_>5 6 2 1 3. 0 2.2940430790185928e-003 0.4500094950199127 0.6580877900123596 <_> <_> <_>15 16 3 2 -1. <_>15 17 3 1 2. 0 2.9982850537635386e-004 0.5629242062568665 0.3975878953933716 <_> <_> <_>0 0 3 9 -1. <_>0 3 3 3 3. 0 3.5455459728837013e-003 0.5381547212600708 0.3605485856533051 <_> <_> <_>9 7 3 3 -1. <_>9 8 3 1 3. 0 9.6104722470045090e-003 0.5255997180938721 0.1796745955944061 <_> <_> <_>8 7 3 3 -1. <_>8 8 3 1 3. 0 -6.2783220782876015e-003 0.2272856980562210 0.5114030241966248 <_> <_> <_>9 5 2 6 -1. <_>9 5 1 6 2. 0 3.4598479978740215e-003 0.4626308083534241 0.6608219146728516 <_> <_> <_>8 6 3 4 -1. <_>9 6 1 4 3. 0 -1.3112019514665008e-003 0.6317539811134338 0.4436857998371124 <_> <_> <_>7 6 8 12 -1. <_>11 6 4 6 2. <_>7 12 4 6 2. 0 2.6876179035753012e-003 0.5421109795570374 0.4054022133350372 <_> <_> <_>5 6 8 12 -1. <_>5 6 4 6 2. <_>9 12 4 6 2. 0 3.9118169806897640e-003 0.5358477830886841 0.3273454904556274 <_> <_> <_>12 4 3 3 -1. <_>12 5 3 1 3. 0 -0.0142064504325390 0.7793576717376709 0.4975781142711639 <_> <_> <_>2 16 3 2 -1. <_>2 17 3 1 2. 0 7.1705528534948826e-004 0.5297319889068604 0.3560903966426849 <_> <_> <_>12 4 3 3 -1. <_>12 5 3 1 3. 0 1.6635019565001130e-003 0.4678094089031220 0.5816481709480286 <_> <_> <_>2 12 6 6 -1. <_>2 14 6 2 3. 0 3.3686188980937004e-003 0.5276734232902527 0.3446420133113861 <_> <_> <_>7 13 6 3 -1. <_>7 14 6 1 3. 0 0.0127995302900672 0.4834679961204529 0.7472159266471863 <_> <_> <_>6 14 6 3 -1. <_>6 15 6 1 3. 0 3.3901201095432043e-003 0.4511859118938446 0.6401721239089966 <_> <_> <_>14 15 5 3 -1. <_>14 16 5 1 3. 0 4.7070779837667942e-003 0.5335658788681030 0.3555220961570740 <_> <_> <_>5 4 3 3 -1. <_>5 5 3 1 3. 0 1.4819339849054813e-003 0.4250707030296326 0.5772724151611328 <_> <_> <_>14 15 5 3 -1. <_>14 16 5 1 3. 0 -6.9995759986341000e-003 0.3003320097923279 0.5292900204658508 <_> <_> <_>5 3 6 2 -1. <_>7 3 2 2 3. 0 0.0159390103071928 0.5067319273948669 0.1675581932067871 <_> <_> <_>8 15 4 3 -1. <_>8 16 4 1 3. 0 7.6377349905669689e-003 0.4795069992542267 0.7085601091384888 <_> <_> <_>1 15 5 3 -1. <_>1 16 5 1 3. 0 6.7334040068089962e-003 0.5133113265037537 0.2162470072507858 <_> <_> <_>8 13 4 6 -1. <_>10 13 2 3 2. <_>8 16 2 3 2. 0 -0.0128588099032640 0.1938841938972473 0.5251371860504150 <_> <_> <_>7 8 3 3 -1. <_>8 8 1 3 3. 0 -6.2270800117403269e-004 0.5686538219451904 0.4197868108749390 <_> <_> <_>12 0 5 4 -1. <_>12 2 5 2 2. 0 -5.2651681471616030e-004 0.4224168956279755 0.5429695844650269 <_> <_> <_>0 2 20 2 -1. <_>0 2 10 1 2. <_>10 3 10 1 2. 0 0.0110750999301672 0.5113775134086609 0.2514517903327942 <_> <_> <_>1 0 18 4 -1. <_>7 0 6 4 3. 0 -0.0367282517254353 0.7194662094116211 0.4849618971347809 <_> <_> <_>4 3 6 1 -1. <_>6 3 2 1 3. 0 -2.8207109426148236e-004 0.3840261995792389 0.5394446253776550 <_> <_> <_>4 18 13 2 -1. <_>4 19 13 1 2. 0 -2.7489690110087395e-003 0.5937088727951050 0.4569182097911835 <_> <_> <_>2 10 3 6 -1. <_>2 12 3 2 3. 0 0.0100475195795298 0.5138576030731201 0.2802298069000244 <_> <_> <_>14 12 6 8 -1. <_>17 12 3 4 2. <_>14 16 3 4 2. 0 -8.1497840583324432e-003 0.6090037226676941 0.4636121094226837 <_> <_> <_>4 13 10 6 -1. <_>4 13 5 3 2. <_>9 16 5 3 2. 0 -6.8833888508379459e-003 0.3458611071109772 0.5254660248756409 <_> <_> <_>14 12 1 2 -1. <_>14 13 1 1 2. 0 -1.4039360394235700e-005 0.5693104267120361 0.4082083106040955 <_> <_> <_>8 13 4 3 -1. <_>8 14 4 1 3. 0 1.5498419525101781e-003 0.4350537061691284 0.5806517004966736 <_> <_> <_>14 12 2 2 -1. <_>14 13 2 1 2. 0 -6.7841499112546444e-003 0.1468873023986816 0.5182775259017944 <_> <_> <_>4 12 2 2 -1. <_>4 13 2 1 2. 0 2.1705629478674382e-004 0.5293524265289307 0.3456174135208130 <_> <_> <_>8 12 9 2 -1. <_>8 13 9 1 2. 0 3.1198898795992136e-004 0.4652450978755951 0.5942413806915283 <_> <_> <_>9 14 2 3 -1. <_>9 15 2 1 3. 0 5.4507530294358730e-003 0.4653508961200714 0.7024846076965332 <_> <_> <_>11 10 3 6 -1. <_>11 13 3 3 2. 0 -2.5818689027801156e-004 0.5497295260429382 0.3768967092037201 <_> <_> <_>5 6 9 12 -1. <_>5 12 9 6 2. 0 -0.0174425393342972 0.3919087946414948 0.5457497835159302 <_> <_> <_>11 10 3 6 -1. <_>11 13 3 3 2. 0 -0.0453435294330120 0.1631357073783875 0.5154908895492554 <_> <_> <_>6 10 3 6 -1. <_>6 13 3 3 2. 0 1.9190689781680703e-003 0.5145897865295410 0.2791895866394043 <_> <_> <_>5 4 11 3 -1. <_>5 5 11 1 3. 0 -6.0177869163453579e-003 0.6517636179924011 0.4756332933902741 <_> <_> <_>7 1 5 10 -1. <_>7 6 5 5 2. 0 -4.0720738470554352e-003 0.5514652729034424 0.4092685878276825 <_> <_> <_>2 8 18 2 -1. <_>2 9 18 1 2. 0 3.9855059003457427e-004 0.3165240883827210 0.5285550951957703 <_> <_> <_>7 17 5 3 -1. <_>7 18 5 1 3. 0 -6.5418570302426815e-003 0.6853377819061279 0.4652808904647827 <_> <_> <_>5 9 12 1 -1. <_>9 9 4 1 3. 0 3.4845089539885521e-003 0.5484588146209717 0.4502759873867035 <_> <_> <_>0 14 6 6 -1. <_>0 14 3 3 2. <_>3 17 3 3 2. 0 -0.0136967804282904 0.6395779848098755 0.4572555124759674 <_> <_> <_>5 9 12 1 -1. <_>9 9 4 1 3. 0 -0.0173471402376890 0.2751072943210602 0.5181614756584168 <_> <_> <_>3 9 12 1 -1. <_>7 9 4 1 3. 0 -4.0885428898036480e-003 0.3325636088848114 0.5194984078407288 <_> <_> <_>14 10 6 7 -1. <_>14 10 3 7 2. 0 -9.4687901437282562e-003 0.5942280888557434 0.4851819872856140 <_> <_> <_>1 0 16 2 -1. <_>1 1 16 1 2. 0 1.7084840219467878e-003 0.4167110919952393 0.5519806146621704 <_> <_> <_>10 9 10 9 -1. <_>10 12 10 3 3. 0 9.4809094443917274e-003 0.5433894991874695 0.4208514988422394 <_> <_> <_>0 1 10 2 -1. <_>5 1 5 2 2. 0 -4.7389650717377663e-003 0.6407189965248108 0.4560655057430267 <_> <_> <_>17 3 2 3 -1. <_>17 4 2 1 3. 0 6.5761050209403038e-003 0.5214555263519287 0.2258227020502091 <_> <_> <_>1 3 2 3 -1. <_>1 4 2 1 3. 0 -2.1690549328923225e-003 0.3151527941226959 0.5156704783439636 <_> <_> <_>9 7 3 6 -1. <_>10 7 1 6 3. 0 0.0146601703017950 0.4870837032794952 0.6689941287040710 <_> <_> <_>6 5 4 3 -1. <_>8 5 2 3 2. 0 1.7231999663636088e-004 0.3569748997688294 0.5251078009605408 <_> <_> <_>7 5 6 6 -1. <_>9 5 2 6 3. 0 -0.0218037609010935 0.8825920820236206 0.4966329932212830 <_> <_> <_>3 4 12 12 -1. <_>3 4 6 6 2. <_>9 10 6 6 2. 0 -0.0947361066937447 0.1446162015199661 0.5061113834381104 <_> <_> <_>9 2 6 15 -1. <_>11 2 2 15 3. 0 5.5825551971793175e-003 0.5396478772163391 0.4238066077232361 <_> <_> <_>2 2 6 17 -1. <_>4 2 2 17 3. 0 1.9517090404406190e-003 0.4170410931110382 0.5497786998748779 <_> <_> <_>14 10 6 7 -1. <_>14 10 3 7 2. 0 0.0121499001979828 0.4698367118835449 0.5664274096488953 <_> <_> <_>0 10 6 7 -1. <_>3 10 3 7 2. 0 -7.5169620104134083e-003 0.6267772912979126 0.4463135898113251 <_> <_> <_>9 2 6 15 -1. <_>11 2 2 15 3. 0 -0.0716679096221924 0.3097011148929596 0.5221003293991089 <_> <_> <_>5 2 6 15 -1. <_>7 2 2 15 3. 0 -0.0882924199104309 0.0811238884925842 0.5006365180015564 <_> <_> <_>17 9 3 6 -1. <_>17 11 3 2 3. 0 0.0310630798339844 0.5155503749847412 0.1282255947589874 <_> <_> <_>6 7 6 6 -1. <_>8 7 2 6 3. 0 0.0466218404471874 0.4699777960777283 0.7363960742950440 <_> <_> <_>1 10 18 6 -1. <_>10 10 9 3 2. <_>1 13 9 3 2. 0 -0.0121894897893071 0.3920530080795288 0.5518996715545654 <_> <_> <_>0 9 10 9 -1. <_>0 12 10 3 3. 0 0.0130161102861166 0.5260658264160156 0.3685136139392853 <_> <_> <_>8 15 4 3 -1. <_>8 16 4 1 3. 0 -3.4952899441123009e-003 0.6339294910430908 0.4716280996799469 <_> <_> <_>5 12 3 4 -1. <_>5 14 3 2 2. 0 -4.4015039748046547e-005 0.5333027243614197 0.3776184916496277 <_> <_> <_>3 3 16 12 -1. <_>3 9 16 6 2. 0 -0.1096649020910263 0.1765342056751251 0.5198346972465515 <_> <_> <_>1 1 12 12 -1. <_>1 1 6 6 2. <_>7 7 6 6 2. 0 -9.0279558207839727e-004 0.5324159860610962 0.3838908076286316 <_> <_> <_>10 4 2 4 -1. <_>11 4 1 2 2. <_>10 6 1 2 2. 0 7.1126641705632210e-004 0.4647929966449738 0.5755224227905273 <_> <_> <_>0 9 10 2 -1. <_>0 9 5 1 2. <_>5 10 5 1 2. 0 -3.1250279862433672e-003 0.3236708939075470 0.5166770815849304 <_> <_> <_>9 11 3 3 -1. <_>9 12 3 1 3. 0 2.4144679773598909e-003 0.4787439107894898 0.6459717750549316 <_> <_> <_>3 12 9 2 -1. <_>3 13 9 1 2. 0 4.4391240226104856e-004 0.4409308135509491 0.6010255813598633 <_> <_> <_>9 9 2 2 -1. <_>9 10 2 1 2. 0 -2.2611189342569560e-004 0.4038113951683044 0.5493255853652954 50.1697311401367190 12 -1 <_> <_> <_> <_>3 4 13 6 -1. <_>3 6 13 2 3. 0 -0.0469012893736362 0.6600171923637390 0.3743801116943359 <_> <_> <_>9 7 6 4 -1. <_>12 7 3 2 2. <_>9 9 3 2 2. 0 -1.4568349579349160e-003 0.5783991217613220 0.3437797129154205 <_> <_> <_>1 0 6 8 -1. <_>4 0 3 8 2. 0 5.5598369799554348e-003 0.3622266948223114 0.5908216238021851 <_> <_> <_>9 5 2 12 -1. <_>9 11 2 6 2. 0 7.3170487303286791e-004 0.5500419139862061 0.2873558104038239 <_> <_> <_>4 4 3 10 -1. <_>4 9 3 5 2. 0 1.3318009441718459e-003 0.2673169970512390 0.5431019067764282 <_> <_> <_>6 17 8 3 -1. <_>6 18 8 1 3. 0 2.4347059661522508e-004 0.3855027854442596 0.5741388797760010 <_> <_> <_>0 5 10 6 -1. <_>0 7 10 2 3. 0 -3.0512469820678234e-003 0.5503209829330444 0.3462845087051392 <_> <_> <_>13 2 3 2 -1. <_>13 3 3 1 2. 0 -6.8657199153676629e-004 0.3291221857070923 0.5429509282112122 <_> <_> <_>7 5 4 5 -1. <_>9 5 2 5 2. 0 1.4668200165033340e-003 0.3588382005691528 0.5351811051368713 <_> <_> <_>12 14 3 6 -1. <_>12 16 3 2 3. 0 3.2021870720200241e-004 0.4296841919422150 0.5700234174728394 <_> <_> <_>1 11 8 2 -1. <_>1 12 8 1 2. 0 7.4122188379988074e-004 0.5282164812088013 0.3366870880126953 <_> <_> <_>7 13 6 3 -1. <_>7 14 6 1 3. 0 3.8330298848450184e-003 0.4559567868709564 0.6257336139678955 <_> <_> <_>0 5 3 6 -1. <_>0 7 3 2 3. 0 -0.0154564399272203 0.2350116968154907 0.5129452943801880 <_> <_> <_>13 2 3 2 -1. <_>13 3 3 1 2. 0 2.6796779129654169e-003 0.5329415202140808 0.4155062139034271 <_> <_> <_>4 14 4 6 -1. <_>4 14 2 3 2. <_>6 17 2 3 2. 0 2.8296569362282753e-003 0.4273087978363037 0.5804538130760193 <_> <_> <_>13 2 3 2 -1. <_>13 3 3 1 2. 0 -3.9444249123334885e-003 0.2912611961364746 0.5202686190605164 <_> <_> <_>8 2 4 12 -1. <_>8 6 4 4 3. 0 2.7179559692740440e-003 0.5307688117027283 0.3585677146911621 <_> <_> <_>14 0 6 8 -1. <_>17 0 3 4 2. <_>14 4 3 4 2. 0 5.9077627956867218e-003 0.4703775048255920 0.5941585898399353 <_> <_> <_>7 17 3 2 -1. <_>8 17 1 2 3. 0 -4.2240349575877190e-003 0.2141567021608353 0.5088796019554138 <_> <_> <_>8 12 4 2 -1. <_>8 13 4 1 2. 0 4.0725888684391975e-003 0.4766413867473602 0.6841061115264893 <_> <_> <_>6 0 8 12 -1. <_>6 0 4 6 2. <_>10 6 4 6 2. 0 0.0101495301350951 0.5360798835754395 0.3748497068881989 <_> <_> <_>14 0 2 10 -1. <_>15 0 1 5 2. <_>14 5 1 5 2. 0 -1.8864999583456665e-004 0.5720130205154419 0.3853805065155029 <_> <_> <_>5 3 8 6 -1. <_>5 3 4 3 2. <_>9 6 4 3 2. 0 -4.8864358104765415e-003 0.3693122863769531 0.5340958833694458 <_> <_> <_>14 0 6 10 -1. <_>17 0 3 5 2. <_>14 5 3 5 2. 0 0.0261584799736738 0.4962374866008759 0.6059989929199219 <_> <_> <_>9 14 1 2 -1. <_>9 15 1 1 2. 0 4.8560759751126170e-004 0.4438945949077606 0.6012468934059143 <_> <_> <_>15 10 4 3 -1. <_>15 11 4 1 3. 0 0.0112687097862363 0.5244250297546387 0.1840388029813767 <_> <_> <_>8 14 2 3 -1. <_>8 15 2 1 3. 0 -2.8114619199186563e-003 0.6060283780097961 0.4409897029399872 <_> <_> <_>3 13 14 4 -1. <_>10 13 7 2 2. <_>3 15 7 2 2. 0 -5.6112729944288731e-003 0.3891170918941498 0.5589237213134766 <_> <_> <_>1 10 4 3 -1. <_>1 11 4 1 3. 0 8.5680093616247177e-003 0.5069345831871033 0.2062619030475617 <_> <_> <_>9 11 6 1 -1. <_>11 11 2 1 3. 0 -3.8172779022715986e-004 0.5882201790809631 0.4192610979080200 <_> <_> <_>5 11 6 1 -1. <_>7 11 2 1 3. 0 -1.7680290329735726e-004 0.5533605813980103 0.4003368914127350 <_> <_> <_>3 5 16 15 -1. <_>3 10 16 5 3. 0 6.5112537704408169e-003 0.3310146927833557 0.5444191098213196 <_> <_> <_>6 12 4 2 -1. <_>8 12 2 2 2. 0 -6.5948683186434209e-005 0.5433831810951233 0.3944905996322632 <_> <_> <_>4 4 12 10 -1. <_>10 4 6 5 2. <_>4 9 6 5 2. 0 6.9939051754772663e-003 0.5600358247756958 0.4192714095115662 <_> <_> <_>8 6 3 4 -1. <_>9 6 1 4 3. 0 -4.6744439750909805e-003 0.6685466766357422 0.4604960978031158 <_> <_> <_>8 12 4 8 -1. <_>10 12 2 4 2. <_>8 16 2 4 2. 0 0.0115898502990603 0.5357121229171753 0.2926830053329468 <_> <_> <_>8 14 4 3 -1. <_>8 15 4 1 3. 0 0.0130078401416540 0.4679817855358124 0.7307463288307190 <_> <_> <_>12 2 3 2 -1. <_>13 2 1 2 3. 0 -1.1008579749614000e-003 0.3937501013278961 0.5415065288543701 <_> <_> <_>8 15 3 2 -1. <_>8 16 3 1 2. 0 6.0472649056464434e-004 0.4242376089096069 0.5604041218757629 <_> <_> <_>6 0 9 14 -1. <_>9 0 3 14 3. 0 -0.0144948400557041 0.3631210029125214 0.5293182730674744 <_> <_> <_>9 6 2 3 -1. <_>10 6 1 3 2. 0 -5.3056948818266392e-003 0.6860452294349670 0.4621821045875549 <_> <_> <_>10 8 2 3 -1. <_>10 9 2 1 3. 0 -8.1829127157106996e-004 0.3944096863269806 0.5420439243316650 <_> <_> <_>0 9 4 6 -1. <_>0 11 4 2 3. 0 -0.0190775208175182 0.1962621957063675 0.5037891864776611 <_> <_> <_>6 0 8 2 -1. <_>6 1 8 1 2. 0 3.5549470339901745e-004 0.4086259007453919 0.5613973140716553 <_> <_> <_>6 14 7 3 -1. <_>6 15 7 1 3. 0 1.9679730758070946e-003 0.4489121139049530 0.5926123261451721 <_> <_> <_>8 10 8 9 -1. <_>8 13 8 3 3. 0 6.9189141504466534e-003 0.5335925817489624 0.3728385865688324 <_> <_> <_>5 2 3 2 -1. <_>6 2 1 2 3. 0 2.9872779268771410e-003 0.5111321210861206 0.2975643873214722 <_> <_> <_>14 1 6 8 -1. <_>17 1 3 4 2. <_>14 5 3 4 2. 0 -6.2264618463814259e-003 0.5541489720344544 0.4824537932872772 <_> <_> <_>0 1 6 8 -1. <_>0 1 3 4 2. <_>3 5 3 4 2. 0 0.0133533002808690 0.4586423933506012 0.6414797902107239 <_> <_> <_>1 2 18 6 -1. <_>10 2 9 3 2. <_>1 5 9 3 2. 0 0.0335052385926247 0.5392425060272217 0.3429994881153107 <_> <_> <_>9 3 2 1 -1. <_>10 3 1 1 2. 0 -2.5294460356235504e-003 0.1703713983297348 0.5013315081596375 <_> <_> <_>13 2 4 6 -1. <_>15 2 2 3 2. <_>13 5 2 3 2. 0 -1.2801629491150379e-003 0.5305461883544922 0.4697405099868774 <_> <_> <_>5 4 3 3 -1. <_>5 5 3 1 3. 0 7.0687388069927692e-003 0.4615545868873596 0.6436504721641541 <_> <_> <_>13 5 1 3 -1. <_>13 6 1 1 3. 0 9.6880499040707946e-004 0.4833599030971527 0.6043894290924072 <_> <_> <_>2 16 5 3 -1. <_>2 17 5 1 3. 0 3.9647659286856651e-003 0.5187637209892273 0.3231816887855530 <_> <_> <_>13 2 4 6 -1. <_>15 2 2 3 2. <_>13 5 2 3 2. 0 -0.0220577307045460 0.4079256951808929 0.5200980901718140 <_> <_> <_>3 2 4 6 -1. <_>3 2 2 3 2. <_>5 5 2 3 2. 0 -6.6906312713399529e-004 0.5331609249114990 0.3815600872039795 <_> <_> <_>13 5 1 2 -1. <_>13 6 1 1 2. 0 -6.7009328631684184e-004 0.5655422210693359 0.4688901901245117 <_> <_> <_>5 5 2 2 -1. <_>5 6 2 1 2. 0 7.4284552829340100e-004 0.4534381031990051 0.6287400126457214 <_> <_> <_>13 9 2 2 -1. <_>13 9 1 2 2. 0 2.2227810695767403e-003 0.5350633263587952 0.3303655982017517 <_> <_> <_>5 9 2 2 -1. <_>6 9 1 2 2. 0 -5.4130521602928638e-003 0.1113687008619309 0.5005434751510620 <_> <_> <_>13 17 3 2 -1. <_>13 18 3 1 2. 0 -1.4520040167553816e-005 0.5628737807273865 0.4325133860111237 <_> <_> <_>6 16 4 4 -1. <_>6 16 2 2 2. <_>8 18 2 2 2. 0 2.3369169502984732e-004 0.4165835082530975 0.5447791218757629 <_> <_> <_>9 16 2 3 -1. <_>9 17 2 1 3. 0 4.2894547805190086e-003 0.4860391020774841 0.6778649091720581 <_> <_> <_>0 13 9 6 -1. <_>0 15 9 2 3. 0 5.9103150852024555e-003 0.5262305140495300 0.3612113893032074 <_> <_> <_>9 14 2 6 -1. <_>9 17 2 3 2. 0 0.0129005396738648 0.5319377183914185 0.3250288069248200 <_> <_> <_>9 15 2 3 -1. <_>9 16 2 1 3. 0 4.6982979401946068e-003 0.4618245065212250 0.6665925979614258 <_> <_> <_>1 10 18 6 -1. <_>1 12 18 2 3. 0 0.0104398597031832 0.5505670905113220 0.3883604109287262 <_> <_> <_>8 11 4 2 -1. <_>8 12 4 1 2. 0 3.0443191062659025e-003 0.4697853028774262 0.7301844954490662 <_> <_> <_>7 9 6 2 -1. <_>7 10 6 1 2. 0 -6.1593751888722181e-004 0.3830839097499847 0.5464984178543091 <_> <_> <_>8 8 2 3 -1. <_>8 9 2 1 3. 0 -3.4247159492224455e-003 0.2566300034523010 0.5089530944824219 <_> <_> <_>17 5 3 4 -1. <_>18 5 1 4 3. 0 -9.3538565561175346e-003 0.6469966173171997 0.4940795898437500 <_> <_> <_>1 19 18 1 -1. <_>7 19 6 1 3. 0 0.0523389987647533 0.4745982885360718 0.7878770828247070 <_> <_> <_>9 0 3 2 -1. <_>10 0 1 2 3. 0 3.5765620414167643e-003 0.5306664705276489 0.2748498022556305 <_> <_> <_>1 8 1 6 -1. <_>1 10 1 2 3. 0 7.1555317845195532e-004 0.5413125753402710 0.4041908979415894 <_> <_> <_>12 17 8 3 -1. <_>12 17 4 3 2. 0 -0.0105166798457503 0.6158512234687805 0.4815283119678497 <_> <_> <_>0 5 3 4 -1. <_>1 5 1 4 3. 0 7.7347927726805210e-003 0.4695805907249451 0.7028980851173401 <_> <_> <_>9 7 2 3 -1. <_>9 8 2 1 3. 0 -4.3226778507232666e-003 0.2849566042423248 0.5304684042930603 <_> <_> <_>7 11 2 2 -1. <_>7 11 1 1 2. <_>8 12 1 1 2. 0 -2.5534399319440126e-003 0.7056984901428223 0.4688892066478729 <_> <_> <_>11 3 2 5 -1. <_>11 3 1 5 2. 0 1.0268510231981054e-004 0.3902932107448578 0.5573464035987854 <_> <_> <_>7 3 2 5 -1. <_>8 3 1 5 2. 0 7.1395188570022583e-006 0.3684231936931610 0.5263987779617310 <_> <_> <_>15 13 2 3 -1. <_>15 14 2 1 3. 0 -1.6711989883333445e-003 0.3849175870418549 0.5387271046638489 <_> <_> <_>5 6 2 3 -1. <_>5 7 2 1 3. 0 4.9260449595749378e-003 0.4729771912097931 0.7447251081466675 <_> <_> <_>4 19 15 1 -1. <_>9 19 5 1 3. 0 4.3908702209591866e-003 0.4809181094169617 0.5591921806335449 <_> <_> <_>1 19 15 1 -1. <_>6 19 5 1 3. 0 -0.0177936293184757 0.6903678178787231 0.4676927030086517 <_> <_> <_>15 13 2 3 -1. <_>15 14 2 1 3. 0 2.0469669252634048e-003 0.5370690226554871 0.3308162093162537 <_> <_> <_>5 0 4 15 -1. <_>7 0 2 15 2. 0 0.0298914890736341 0.5139865279197693 0.3309059143066406 <_> <_> <_>9 6 2 5 -1. <_>9 6 1 5 2. 0 1.5494900289922953e-003 0.4660237133502960 0.6078342795372009 <_> <_> <_>9 5 2 7 -1. <_>10 5 1 7 2. 0 1.4956969534978271e-003 0.4404835999011993 0.5863919854164124 <_> <_> <_>16 11 3 3 -1. <_>16 12 3 1 3. 0 9.5885928021743894e-004 0.5435971021652222 0.4208523035049439 <_> <_> <_>1 11 3 3 -1. <_>1 12 3 1 3. 0 4.9643701640889049e-004 0.5370578169822693 0.4000622034072876 <_> <_> <_>6 6 8 3 -1. <_>6 7 8 1 3. 0 -2.7280810754746199e-003 0.5659412741661072 0.4259642958641052 <_> <_> <_>0 15 6 2 -1. <_>0 16 6 1 2. 0 2.3026480339467525e-003 0.5161657929420471 0.3350869119167328 <_> <_> <_>1 0 18 6 -1. <_>7 0 6 6 3. 0 0.2515163123607636 0.4869661927223206 0.7147309780120850 <_> <_> <_>6 0 3 4 -1. <_>7 0 1 4 3. 0 -4.6328022144734859e-003 0.2727448940277100 0.5083789825439453 <_> <_> <_>14 10 4 10 -1. <_>16 10 2 5 2. <_>14 15 2 5 2. 0 -0.0404344908893108 0.6851438879966736 0.5021767020225525 <_> <_> <_>3 2 3 2 -1. <_>4 2 1 2 3. 0 1.4972220014897175e-005 0.4284465014934540 0.5522555112838745 <_> <_> <_>11 2 2 2 -1. <_>11 3 2 1 2. 0 -2.4050309730228037e-004 0.4226118922233582 0.5390074849128723 <_> <_> <_>2 10 4 10 -1. <_>2 10 2 5 2. <_>4 15 2 5 2. 0 0.0236578397452831 0.4744631946086884 0.7504366040229797 <_> <_> <_>0 13 20 6 -1. <_>10 13 10 3 2. <_>0 16 10 3 2. 0 -8.1449104472994804e-003 0.4245058894157410 0.5538362860679627 <_> <_> <_>0 5 2 15 -1. <_>1 5 1 15 2. 0 -3.6992130335420370e-003 0.5952357053756714 0.4529713094234467 <_> <_> <_>1 7 18 4 -1. <_>10 7 9 2 2. <_>1 9 9 2 2. 0 -6.7718601785600185e-003 0.4137794077396393 0.5473399758338928 <_> <_> <_>0 0 2 17 -1. <_>1 0 1 17 2. 0 4.2669530957937241e-003 0.4484114944934845 0.5797994136810303 <_> <_> <_>2 6 16 6 -1. <_>10 6 8 3 2. <_>2 9 8 3 2. 0 1.7791989957913756e-003 0.5624858736991882 0.4432444870471954 <_> <_> <_>8 14 1 3 -1. <_>8 15 1 1 3. 0 1.6774770338088274e-003 0.4637751877307892 0.6364241838455200 <_> <_> <_>8 15 4 2 -1. <_>8 16 4 1 2. 0 1.1732629500329494e-003 0.4544503092765808 0.5914415717124939 <_> <_> <_>5 2 8 2 -1. <_>5 2 4 1 2. <_>9 3 4 1 2. 0 8.6998171173036098e-004 0.5334752798080444 0.3885917961597443 <_> <_> <_>6 11 8 6 -1. <_>6 14 8 3 2. 0 7.6378340600058436e-004 0.5398585200309753 0.3744941949844360 <_> <_> <_>9 13 2 2 -1. <_>9 14 2 1 2. 0 1.5684569370932877e-004 0.4317873120307922 0.5614616274833679 <_> <_> <_>18 4 2 6 -1. <_>18 6 2 2 3. 0 -0.0215113703161478 0.1785925030708313 0.5185542702674866 <_> <_> <_>9 12 2 2 -1. <_>9 13 2 1 2. 0 1.3081369979772717e-004 0.4342499077320099 0.5682849884033203 <_> <_> <_>18 4 2 6 -1. <_>18 6 2 2 3. 0 0.0219920407980680 0.5161716938018799 0.2379394024610519 <_> <_> <_>9 13 1 3 -1. <_>9 14 1 1 3. 0 -8.0136500764638186e-004 0.5986763238906860 0.4466426968574524 <_> <_> <_>18 4 2 6 -1. <_>18 6 2 2 3. 0 -8.2736099138855934e-003 0.4108217954635620 0.5251057147979736 <_> <_> <_>0 4 2 6 -1. <_>0 6 2 2 3. 0 3.6831789184361696e-003 0.5173814296722412 0.3397518098354340 <_> <_> <_>9 12 3 3 -1. <_>9 13 3 1 3. 0 -7.9525681212544441e-003 0.6888983249664307 0.4845924079418182 <_> <_> <_>3 13 2 3 -1. <_>3 14 2 1 3. 0 1.5382299898192286e-003 0.5178567171096802 0.3454113900661469 <_> <_> <_>13 13 4 3 -1. <_>13 14 4 1 3. 0 -0.0140435304492712 0.1678421050310135 0.5188667774200440 <_> <_> <_>5 4 3 3 -1. <_>5 5 3 1 3. 0 1.4315890148282051e-003 0.4368256926536560 0.5655773878097534 <_> <_> <_>5 2 10 6 -1. <_>5 4 10 2 3. 0 -0.0340142287313938 0.7802296280860901 0.4959217011928558 <_> <_> <_>3 13 4 3 -1. <_>3 14 4 1 3. 0 -0.0120272999629378 0.1585101038217545 0.5032231807708740 <_> <_> <_>3 7 15 5 -1. <_>8 7 5 5 3. 0 0.1331661939620972 0.5163304805755615 0.2755128145217896 <_> <_> <_>3 7 12 2 -1. <_>7 7 4 2 3. 0 -1.5221949433907866e-003 0.3728317916393280 0.5214552283287048 <_> <_> <_>10 3 3 9 -1. <_>11 3 1 9 3. 0 -9.3929271679371595e-004 0.5838379263877869 0.4511165022850037 <_> <_> <_>8 6 4 6 -1. <_>10 6 2 6 2. 0 0.0277197398245335 0.4728286862373352 0.7331544756889343 <_> <_> <_>9 7 4 3 -1. <_>9 8 4 1 3. 0 3.1030150130391121e-003 0.5302202105522156 0.4101563096046448 <_> <_> <_>0 9 4 9 -1. <_>2 9 2 9 2. 0 0.0778612196445465 0.4998334050178528 0.1272961944341660 <_> <_> <_>9 13 3 5 -1. <_>10 13 1 5 3. 0 -0.0158549398183823 0.0508333593606949 0.5165656208992004 <_> <_> <_>7 7 6 3 -1. <_>9 7 2 3 3. 0 -4.9725300632417202e-003 0.6798133850097656 0.4684231877326965 <_> <_> <_>9 7 3 5 -1. <_>10 7 1 5 3. 0 -9.7676506265997887e-004 0.6010771989822388 0.4788931906223297 <_> <_> <_>5 7 8 2 -1. <_>9 7 4 2 2. 0 -2.4647710379213095e-003 0.3393397927284241 0.5220503807067871 <_> <_> <_>5 9 12 2 -1. <_>9 9 4 2 3. 0 -6.7937700077891350e-003 0.4365136921405792 0.5239663124084473 <_> <_> <_>5 6 10 3 -1. <_>10 6 5 3 2. 0 0.0326080210506916 0.5052723884582520 0.2425214946269989 <_> <_> <_>10 12 3 1 -1. <_>11 12 1 1 3. 0 -5.8514421107247472e-004 0.5733973979949951 0.4758574068546295 <_> <_> <_>0 1 11 15 -1. <_>0 6 11 5 3. 0 -0.0296326000243425 0.3892289102077484 0.5263597965240479 66.6691207885742190 13 -1 <_> <_> <_> <_>1 0 18 6 -1. <_>7 0 6 6 3. 0 0.0465508513152599 0.3276950120925903 0.6240522861480713 <_> <_> <_>7 7 6 1 -1. <_>9 7 2 1 3. 0 7.9537127166986465e-003 0.4256485104560852 0.6942939162254334 <_> <_> <_>5 16 6 4 -1. <_>5 16 3 2 2. <_>8 18 3 2 2. 0 6.8221561377868056e-004 0.3711487054824829 0.5900732874870300 <_> <_> <_>6 5 9 8 -1. <_>6 9 9 4 2. 0 -1.9348249770700932e-004 0.2041133940219879 0.5300545096397400 <_> <_> <_>5 10 2 6 -1. <_>5 13 2 3 2. 0 -2.6710508973337710e-004 0.5416126251220703 0.3103179037570953 <_> <_> <_>7 6 8 10 -1. <_>11 6 4 5 2. <_>7 11 4 5 2. 0 2.7818060480058193e-003 0.5277832746505737 0.3467069864273071 <_> <_> <_>5 6 8 10 -1. <_>5 6 4 5 2. <_>9 11 4 5 2. 0 -4.6779078547842801e-004 0.5308231115341187 0.3294492065906525 <_> <_> <_>9 5 2 2 -1. <_>9 6 2 1 2. 0 -3.0335160772665404e-005 0.5773872733116150 0.3852097094058991 <_> <_> <_>5 12 8 2 -1. <_>5 13 8 1 2. 0 7.8038009814918041e-004 0.4317438900470734 0.6150057911872864 <_> <_> <_>10 2 8 2 -1. <_>10 3 8 1 2. 0 -4.2553851380944252e-003 0.2933903932571411 0.5324292778968811 <_> <_> <_>4 0 2 10 -1. <_>4 0 1 5 2. <_>5 5 1 5 2. 0 -2.4735610350035131e-004 0.5468844771385193 0.3843030035495758 <_> <_> <_>9 10 2 2 -1. <_>9 11 2 1 2. 0 -1.4724259381182492e-004 0.4281542897224426 0.5755587220191956 <_> <_> <_>2 8 15 3 -1. <_>2 9 15 1 3. 0 1.1864770203828812e-003 0.3747301101684570 0.5471466183662415 <_> <_> <_>8 13 4 3 -1. <_>8 14 4 1 3. 0 2.3936580400913954e-003 0.4537783861160278 0.6111528873443604 <_> <_> <_>7 2 3 2 -1. <_>8 2 1 2 3. 0 -1.5390539774671197e-003 0.2971341907978058 0.5189538002014160 <_> <_> <_>7 13 6 3 -1. <_>7 14 6 1 3. 0 -7.1968790143728256e-003 0.6699066758155823 0.4726476967334747 <_> <_> <_>9 9 2 2 -1. <_>9 10 2 1 2. 0 -4.1499789222143590e-004 0.3384954035282135 0.5260317921638489 <_> <_> <_>17 2 3 6 -1. <_>17 4 3 2 3. 0 4.4359830208122730e-003 0.5399122238159180 0.3920140862464905 <_> <_> <_>1 5 3 4 -1. <_>2 5 1 4 3. 0 2.6606200262904167e-003 0.4482578039169312 0.6119617819786072 <_> <_> <_>14 8 4 6 -1. <_>14 10 4 2 3. 0 -1.5287200221791863e-003 0.3711237907409668 0.5340266227722168 <_> <_> <_>1 4 3 8 -1. <_>2 4 1 8 3. 0 -4.7397250309586525e-003 0.6031088232994080 0.4455145001411438 <_> <_> <_>8 13 4 6 -1. <_>8 16 4 3 2. 0 -0.0148291299119592 0.2838754057884216 0.5341861844062805 <_> <_> <_>3 14 2 2 -1. <_>3 15 2 1 2. 0 9.2275557108223438e-004 0.5209547281265259 0.3361653983592987 <_> <_> <_>14 8 4 6 -1. <_>14 10 4 2 3. 0 0.0835298076272011 0.5119969844818115 0.0811644494533539 <_> <_> <_>2 8 4 6 -1. <_>2 10 4 2 3. 0 -7.5633148662745953e-004 0.3317120075225830 0.5189831256866455 <_> <_> <_>10 14 1 6 -1. <_>10 17 1 3 2. 0 9.8403859883546829e-003 0.5247598290443420 0.2334959059953690 <_> <_> <_>7 5 3 6 -1. <_>8 5 1 6 3. 0 -1.5953830443322659e-003 0.5750094056129456 0.4295622110366821 <_> <_> <_>11 2 2 6 -1. <_>12 2 1 3 2. <_>11 5 1 3 2. 0 3.4766020689858124e-005 0.4342445135116577 0.5564029216766357 <_> <_> <_>6 6 6 5 -1. <_>8 6 2 5 3. 0 0.0298629105091095 0.4579147100448608 0.6579188108444214 <_> <_> <_>17 1 3 6 -1. <_>17 3 3 2 3. 0 0.0113255903124809 0.5274311900138855 0.3673888146877289 <_> <_> <_>8 7 3 5 -1. <_>9 7 1 5 3. 0 -8.7828645482659340e-003 0.7100368738174439 0.4642167091369629 <_> <_> <_>9 18 3 2 -1. <_>10 18 1 2 3. 0 4.3639959767460823e-003 0.5279216170310974 0.2705877125263214 <_> <_> <_>8 18 3 2 -1. <_>9 18 1 2 3. 0 4.1804728098213673e-003 0.5072525143623352 0.2449083030223846 <_> <_> <_>12 3 5 2 -1. <_>12 4 5 1 2. 0 -4.5668511302210391e-004 0.4283105134963989 0.5548691153526306 <_> <_> <_>7 1 5 12 -1. <_>7 7 5 6 2. 0 -3.7140368949621916e-003 0.5519387722015381 0.4103653132915497 <_> <_> <_>1 0 18 4 -1. <_>7 0 6 4 3. 0 -0.0253042895346880 0.6867002248764038 0.4869889020919800 <_> <_> <_>4 2 2 2 -1. <_>4 3 2 1 2. 0 -3.4454080741852522e-004 0.3728874027729034 0.5287693142890930 <_> <_> <_>11 14 4 2 -1. <_>13 14 2 1 2. <_>11 15 2 1 2. 0 -8.3935231668874621e-004 0.6060152053833008 0.4616062045097351 <_> <_> <_>0 2 3 6 -1. <_>0 4 3 2 3. 0 0.0172800496220589 0.5049635767936707 0.1819823980331421 <_> <_> <_>9 7 2 3 -1. <_>9 8 2 1 3. 0 -6.3595077954232693e-003 0.1631239950656891 0.5232778787612915 <_> <_> <_>5 5 1 3 -1. <_>5 6 1 1 3. 0 1.0298109846189618e-003 0.4463278055191040 0.6176549196243286 <_> <_> <_>10 10 6 1 -1. <_>10 10 3 1 2. 0 1.0117109632119536e-003 0.5473384857177734 0.4300698935985565 <_> <_> <_>4 10 6 1 -1. <_>7 10 3 1 2. 0 -0.0103088002651930 0.1166985034942627 0.5000867247581482 <_> <_> <_>9 17 3 3 -1. <_>9 18 3 1 3. 0 5.4682018235325813e-003 0.4769287109375000 0.6719213724136353 <_> <_> <_>4 14 1 3 -1. <_>4 15 1 1 3. 0 -9.1696460731327534e-004 0.3471089899539948 0.5178164839744568 <_> <_> <_>12 5 3 3 -1. <_>12 6 3 1 3. 0 2.3922820109874010e-003 0.4785236120223999 0.6216310858726502 <_> <_> <_>4 5 12 3 -1. <_>4 6 12 1 3. 0 -7.5573818758130074e-003 0.5814796090126038 0.4410085082054138 <_> <_> <_>9 8 2 3 -1. <_>9 9 2 1 3. 0 -7.7024032361805439e-004 0.3878000080585480 0.5465722084045410 <_> <_> <_>4 9 3 3 -1. <_>5 9 1 3 3. 0 -8.7125990539789200e-003 0.1660051047801971 0.4995836019515991 <_> <_> <_>6 0 9 17 -1. <_>9 0 3 17 3. 0 -0.0103063201531768 0.4093391001224518 0.5274233818054199 <_> <_> <_>9 12 1 3 -1. <_>9 13 1 1 3. 0 -2.0940979011356831e-003 0.6206194758415222 0.4572280049324036 <_> <_> <_>9 5 2 15 -1. <_>9 10 2 5 3. 0 6.8099051713943481e-003 0.5567759275436401 0.4155600070953369 <_> <_> <_>8 14 2 3 -1. <_>8 15 2 1 3. 0 -1.0746059706434608e-003 0.5638927817344666 0.4353024959564209 <_> <_> <_>10 14 1 3 -1. <_>10 15 1 1 3. 0 2.1550289820879698e-003 0.4826265871524811 0.6749758124351502 <_> <_> <_>7 1 6 5 -1. <_>9 1 2 5 3. 0 0.0317423194646835 0.5048379898071289 0.1883248984813690 <_> <_> <_>0 0 20 2 -1. <_>0 0 10 2 2. 0 -0.0783827230334282 0.2369548976421356 0.5260158181190491 <_> <_> <_>2 13 5 3 -1. <_>2 14 5 1 3. 0 5.7415119372308254e-003 0.5048828721046448 0.2776469886302948 <_> <_> <_>9 11 2 3 -1. <_>9 12 2 1 3. 0 -2.9014600440859795e-003 0.6238604784011841 0.4693317115306854 <_> <_> <_>2 5 9 15 -1. <_>2 10 9 5 3. 0 -2.6427931152284145e-003 0.3314141929149628 0.5169777274131775 <_> <_> <_>5 0 12 10 -1. <_>11 0 6 5 2. <_>5 5 6 5 2. 0 -0.1094966009259224 0.2380045056343079 0.5183441042900085 <_> <_> <_>5 1 2 3 -1. <_>6 1 1 3 2. 0 7.4075913289561868e-005 0.4069635868072510 0.5362150073051453 <_> <_> <_>10 7 6 1 -1. <_>12 7 2 1 3. 0 -5.0593802006915212e-004 0.5506706237792969 0.4374594092369080 <_> <_> <_>3 1 2 10 -1. <_>3 1 1 5 2. <_>4 6 1 5 2. 0 -8.2131777890026569e-004 0.5525709986686707 0.4209375977516174 <_> <_> <_>13 7 2 1 -1. <_>13 7 1 1 2. 0 -6.0276539443293586e-005 0.5455474853515625 0.4748266041278839 <_> <_> <_>4 13 4 6 -1. <_>4 15 4 2 3. 0 6.8065142259001732e-003 0.5157995820045471 0.3424577116966248 <_> <_> <_>13 7 2 1 -1. <_>13 7 1 1 2. 0 1.7202789895236492e-003 0.5013207793235779 0.6331263780593872 <_> <_> <_>5 7 2 1 -1. <_>6 7 1 1 2. 0 -1.3016929733566940e-004 0.5539718270301819 0.4226869940757752 <_> <_> <_>2 12 18 4 -1. <_>11 12 9 2 2. <_>2 14 9 2 2. 0 -4.8016388900578022e-003 0.4425095021724701 0.5430780053138733 <_> <_> <_>5 7 2 2 -1. <_>5 7 1 1 2. <_>6 8 1 1 2. 0 -2.5399310979992151e-003 0.7145782113075256 0.4697605073451996 <_> <_> <_>16 3 4 2 -1. <_>16 4 4 1 2. 0 -1.4278929447755218e-003 0.4070445001125336 0.5399605035781860 <_> <_> <_>0 2 2 18 -1. <_>0 2 1 9 2. <_>1 11 1 9 2. 0 -0.0251425504684448 0.7884690761566162 0.4747352004051209 <_> <_> <_>1 2 18 4 -1. <_>10 2 9 2 2. <_>1 4 9 2 2. 0 -3.8899609353393316e-003 0.4296191930770874 0.5577110052108765 <_> <_> <_>9 14 1 3 -1. <_>9 15 1 1 3. 0 4.3947459198534489e-003 0.4693162143230438 0.7023944258689880 <_> <_> <_>2 12 18 4 -1. <_>11 12 9 2 2. <_>2 14 9 2 2. 0 0.0246784202754498 0.5242322087287903 0.3812510073184967 <_> <_> <_>0 12 18 4 -1. <_>0 12 9 2 2. <_>9 14 9 2 2. 0 0.0380476787686348 0.5011739730834961 0.1687828004360199 <_> <_> <_>11 4 5 3 -1. <_>11 5 5 1 3. 0 7.9424865543842316e-003 0.4828582108020783 0.6369568109512329 <_> <_> <_>6 4 7 3 -1. <_>6 5 7 1 3. 0 -1.5110049862414598e-003 0.5906485915184021 0.4487667977809906 <_> <_> <_>13 17 3 3 -1. <_>13 18 3 1 3. 0 6.4201741479337215e-003 0.5241097807884216 0.2990570068359375 <_> <_> <_>8 1 3 4 -1. <_>9 1 1 4 3. 0 -2.9802159406244755e-003 0.3041465878486633 0.5078489780426025 <_> <_> <_>11 4 2 4 -1. <_>11 4 1 4 2. 0 -7.4580078944563866e-004 0.4128139019012451 0.5256826281547546 <_> <_> <_>0 17 9 3 -1. <_>3 17 3 3 3. 0 -0.0104709500446916 0.5808395147323608 0.4494296014308929 <_> <_> <_>11 0 2 8 -1. <_>12 0 1 4 2. <_>11 4 1 4 2. 0 9.3369204550981522e-003 0.5246552824974060 0.2658948898315430 <_> <_> <_>0 8 6 12 -1. <_>0 8 3 6 2. <_>3 14 3 6 2. 0 0.0279369000345469 0.4674955010414124 0.7087256908416748 <_> <_> <_>10 7 4 12 -1. <_>10 13 4 6 2. 0 7.4277678504586220e-003 0.5409486889839172 0.3758518099784851 <_> <_> <_>5 3 8 14 -1. <_>5 10 8 7 2. 0 -0.0235845092684031 0.3758639991283417 0.5238550901412964 <_> <_> <_>14 10 6 1 -1. <_>14 10 3 1 2. 0 1.1452640173956752e-003 0.4329578876495361 0.5804247260093689 <_> <_> <_>0 4 10 4 -1. <_>0 6 10 2 2. 0 -4.3468660442158580e-004 0.5280618071556091 0.3873069882392883 <_> <_> <_>10 0 5 8 -1. <_>10 4 5 4 2. 0 0.0106485402211547 0.4902113080024719 0.5681251883506775 <_> <_> <_>8 1 4 8 -1. <_>8 1 2 4 2. <_>10 5 2 4 2. 0 -3.9418050437234342e-004 0.5570880174636841 0.4318251013755798 <_> <_> <_>9 11 6 1 -1. <_>11 11 2 1 3. 0 -1.3270479394122958e-004 0.5658439993858337 0.4343554973602295 <_> <_> <_>8 9 3 4 -1. <_>9 9 1 4 3. 0 -2.0125510636717081e-003 0.6056739091873169 0.4537523984909058 <_> <_> <_>18 4 2 6 -1. <_>18 6 2 2 3. 0 2.4854319635778666e-003 0.5390477180480957 0.4138010144233704 <_> <_> <_>8 8 3 4 -1. <_>9 8 1 4 3. 0 1.8237880431115627e-003 0.4354828894138336 0.5717188715934753 <_> <_> <_>7 1 13 3 -1. <_>7 2 13 1 3. 0 -0.0166566595435143 0.3010913133621216 0.5216122865676880 <_> <_> <_>7 13 6 1 -1. <_>9 13 2 1 3. 0 8.0349558265879750e-004 0.5300151109695435 0.3818396925926209 <_> <_> <_>12 11 3 6 -1. <_>12 13 3 2 3. 0 3.4170378930866718e-003 0.5328028798103333 0.4241400063037872 <_> <_> <_>5 11 6 1 -1. <_>7 11 2 1 3. 0 -3.6222729249857366e-004 0.5491728186607361 0.4186977148056030 <_> <_> <_>1 4 18 10 -1. <_>10 4 9 5 2. <_>1 9 9 5 2. 0 -0.1163002029061317 0.1440722048282623 0.5226451158523560 <_> <_> <_>8 6 4 9 -1. <_>8 9 4 3 3. 0 -0.0146950101479888 0.7747725248336792 0.4715717136859894 <_> <_> <_>8 6 4 3 -1. <_>8 7 4 1 3. 0 2.1972130052745342e-003 0.5355433821678162 0.3315644860267639 <_> <_> <_>8 7 3 3 -1. <_>9 7 1 3 3. 0 -4.6965209185145795e-004 0.5767235159873962 0.4458136856555939 <_> <_> <_>14 15 4 3 -1. <_>14 16 4 1 3. 0 6.5144998952746391e-003 0.5215674042701721 0.3647888898849487 <_> <_> <_>5 10 3 10 -1. <_>6 10 1 10 3. 0 0.0213000606745481 0.4994204938411713 0.1567950993776321 <_> <_> <_>8 15 4 3 -1. <_>8 16 4 1 3. 0 3.1881409231573343e-003 0.4742200076580048 0.6287270188331604 <_> <_> <_>0 8 1 6 -1. <_>0 10 1 2 3. 0 9.0019777417182922e-004 0.5347954034805298 0.3943752050399780 <_> <_> <_>10 15 1 3 -1. <_>10 16 1 1 3. 0 -5.1772277802228928e-003 0.6727191805839539 0.5013138055801392 <_> <_> <_>2 15 4 3 -1. <_>2 16 4 1 3. 0 -4.3764649890363216e-003 0.3106675148010254 0.5128793120384216 <_> <_> <_>18 3 2 8 -1. <_>19 3 1 4 2. <_>18 7 1 4 2. 0 2.6299960445612669e-003 0.4886310100555420 0.5755215883255005 <_> <_> <_>0 3 2 8 -1. <_>0 3 1 4 2. <_>1 7 1 4 2. 0 -2.0458688959479332e-003 0.6025794148445129 0.4558076858520508 <_> <_> <_>3 7 14 10 -1. <_>10 7 7 5 2. <_>3 12 7 5 2. 0 0.0694827064871788 0.5240747928619385 0.2185259014368057 <_> <_> <_>0 7 19 3 -1. <_>0 8 19 1 3. 0 0.0240489393472672 0.5011867284774780 0.2090622037649155 <_> <_> <_>12 6 3 3 -1. <_>12 7 3 1 3. 0 3.1095340382307768e-003 0.4866712093353272 0.7108548283576965 <_> <_> <_>0 6 1 3 -1. <_>0 7 1 1 3. 0 -1.2503260513767600e-003 0.3407891094684601 0.5156195163726807 <_> <_> <_>12 6 3 3 -1. <_>12 7 3 1 3. 0 -1.0281190043315291e-003 0.5575572252273560 0.4439432024955750 <_> <_> <_>5 6 3 3 -1. <_>5 7 3 1 3. 0 -8.8893622159957886e-003 0.6402000784873962 0.4620442092418671 <_> <_> <_>8 2 4 2 -1. <_>8 3 4 1 2. 0 -6.1094801640138030e-004 0.3766441941261292 0.5448899865150452 <_> <_> <_>6 3 4 12 -1. <_>8 3 2 12 2. 0 -5.7686357758939266e-003 0.3318648934364319 0.5133677124977112 <_> <_> <_>13 6 2 3 -1. <_>13 7 2 1 3. 0 1.8506490159779787e-003 0.4903570115566254 0.6406934857368469 <_> <_> <_>0 10 20 4 -1. <_>0 12 20 2 2. 0 -0.0997994691133499 0.1536051034927368 0.5015562176704407 <_> <_> <_>2 0 17 14 -1. <_>2 7 17 7 2. 0 -0.3512834906578064 0.0588231310248375 0.5174378752708435 <_> <_> <_>0 0 6 10 -1. <_>0 0 3 5 2. <_>3 5 3 5 2. 0 -0.0452445708215237 0.6961488723754883 0.4677872955799103 <_> <_> <_>14 6 6 4 -1. <_>14 6 3 4 2. 0 0.0714815780520439 0.5167986154556274 0.1038092970848084 <_> <_> <_>0 6 6 4 -1. <_>3 6 3 4 2. 0 2.1895780228078365e-003 0.4273078143596649 0.5532060861587524 <_> <_> <_>13 2 7 2 -1. <_>13 3 7 1 2. 0 -5.9242651332169771e-004 0.4638943970203400 0.5276389122009277 <_> <_> <_>0 2 7 2 -1. <_>0 3 7 1 2. 0 1.6788389766588807e-003 0.5301648974418640 0.3932034969329834 <_> <_> <_>6 11 14 2 -1. <_>13 11 7 1 2. <_>6 12 7 1 2. 0 -2.2163488902151585e-003 0.5630694031715393 0.4757033884525299 <_> <_> <_>8 5 2 2 -1. <_>8 5 1 1 2. <_>9 6 1 1 2. 0 1.1568699846975505e-004 0.4307535886764526 0.5535702705383301 <_> <_> <_>13 9 2 3 -1. <_>13 9 1 3 2. 0 -7.2017288766801357e-003 0.1444882005453110 0.5193064212799072 <_> <_> <_>1 1 3 12 -1. <_>2 1 1 12 3. 0 8.9081272017210722e-004 0.4384432137012482 0.5593621134757996 <_> <_> <_>17 4 1 3 -1. <_>17 5 1 1 3. 0 1.9605009583756328e-004 0.5340415835380554 0.4705956876277924 <_> <_> <_>2 4 1 3 -1. <_>2 5 1 1 3. 0 5.2022142335772514e-004 0.5213856101036072 0.3810079097747803 <_> <_> <_>14 5 1 3 -1. <_>14 6 1 1 3. 0 9.4588572392240167e-004 0.4769414961338043 0.6130738854408264 <_> <_> <_>7 16 2 3 -1. <_>7 17 2 1 3. 0 9.1698471806012094e-005 0.4245009124279022 0.5429363250732422 <_> <_> <_>8 13 4 6 -1. <_>10 13 2 3 2. <_>8 16 2 3 2. 0 2.1833200007677078e-003 0.5457730889320374 0.4191075861454010 <_> <_> <_>5 5 1 3 -1. <_>5 6 1 1 3. 0 -8.6039671441540122e-004 0.5764588713645935 0.4471659958362579 <_> <_> <_>16 0 4 20 -1. <_>16 0 2 20 2. 0 -0.0132362395524979 0.6372823119163513 0.4695009887218475 <_> <_> <_>5 1 2 6 -1. <_>5 1 1 3 2. <_>6 4 1 3 2. 0 4.3376701069064438e-004 0.5317873954772949 0.3945829868316650 67.6989212036132810 14 -1 <_> <_> <_> <_>5 4 10 4 -1. <_>5 6 10 2 2. 0 -0.0248471498489380 0.6555516719818115 0.3873311877250671 <_> <_> <_>15 2 4 12 -1. <_>15 2 2 12 2. 0 6.1348611488938332e-003 0.3748072087764740 0.5973997712135315 <_> <_> <_>7 6 4 12 -1. <_>7 12 4 6 2. 0 6.4498498104512691e-003 0.5425491929054260 0.2548811137676239 <_> <_> <_>14 5 1 8 -1. <_>14 9 1 4 2. 0 6.3491211039945483e-004 0.2462442070245743 0.5387253761291504 <_> <_> <_>1 4 14 10 -1. <_>1 4 7 5 2. <_>8 9 7 5 2. 0 1.4023890253156424e-003 0.5594322085380554 0.3528657853603363 <_> <_> <_>11 6 6 14 -1. <_>14 6 3 7 2. <_>11 13 3 7 2. 0 3.0044000595808029e-004 0.3958503901958466 0.5765938162803650 <_> <_> <_>3 6 6 14 -1. <_>3 6 3 7 2. <_>6 13 3 7 2. 0 1.0042409849120304e-004 0.3698996901512146 0.5534998178482056 <_> <_> <_>4 9 15 2 -1. <_>9 9 5 2 3. 0 -5.0841490738093853e-003 0.3711090981960297 0.5547800064086914 <_> <_> <_>7 14 6 3 -1. <_>7 15 6 1 3. 0 -0.0195372607558966 0.7492755055427551 0.4579297006130219 <_> <_> <_>6 3 14 4 -1. <_>13 3 7 2 2. <_>6 5 7 2 2. 0 -7.4532740654831287e-006 0.5649787187576294 0.3904069960117340 <_> <_> <_>1 9 15 2 -1. <_>6 9 5 2 3. 0 -3.6079459823668003e-003 0.3381088078022003 0.5267801284790039 <_> <_> <_>6 11 8 9 -1. <_>6 14 8 3 3. 0 2.0697501022368670e-003 0.5519291162490845 0.3714388906955719 <_> <_> <_>7 4 3 8 -1. <_>8 4 1 8 3. 0 -4.6463840408250690e-004 0.5608214735984802 0.4113566875457764 <_> <_> <_>14 6 2 6 -1. <_>14 9 2 3 2. 0 7.5490452582016587e-004 0.3559206128120422 0.5329356193542481 <_> <_> <_>5 7 6 4 -1. <_>5 7 3 2 2. <_>8 9 3 2 2. 0 -9.8322238773107529e-004 0.5414795875549316 0.3763205111026764 <_> <_> <_>1 1 18 19 -1. <_>7 1 6 19 3. 0 -0.0199406407773495 0.6347903013229370 0.4705299139022827 <_> <_> <_>1 2 6 5 -1. <_>4 2 3 5 2. 0 3.7680300883948803e-003 0.3913489878177643 0.5563716292381287 <_> <_> <_>12 17 6 2 -1. <_>12 18 6 1 2. 0 -9.4528505578637123e-003 0.2554892897605896 0.5215116739273071 <_> <_> <_>2 17 6 2 -1. <_>2 18 6 1 2. 0 2.9560849070549011e-003 0.5174679160118103 0.3063920140266419 <_> <_> <_>17 3 3 6 -1. <_>17 5 3 2 3. 0 9.1078737750649452e-003 0.5388448238372803 0.2885963022708893 <_> <_> <_>8 17 3 3 -1. <_>8 18 3 1 3. 0 1.8219229532405734e-003 0.4336043000221252 0.5852196812629700 <_> <_> <_>10 13 2 6 -1. <_>10 16 2 3 2. 0 0.0146887395530939 0.5287361741065979 0.2870005965232849 <_> <_> <_>7 13 6 3 -1. <_>7 14 6 1 3. 0 -0.0143879903480411 0.7019448876380920 0.4647370874881744 <_> <_> <_>17 3 3 6 -1. <_>17 5 3 2 3. 0 -0.0189866498112679 0.2986552119255066 0.5247011780738831 <_> <_> <_>8 13 2 3 -1. <_>8 14 2 1 3. 0 1.1527639580890536e-003 0.4323473870754242 0.5931661725044251 <_> <_> <_>9 3 6 2 -1. <_>11 3 2 2 3. 0 0.0109336702153087 0.5286864042282105 0.3130319118499756 <_> <_> <_>0 3 3 6 -1. <_>0 5 3 2 3. 0 -0.0149327302351594 0.2658419013023377 0.5084077119827271 <_> <_> <_>8 5 4 6 -1. <_>8 7 4 2 3. 0 -2.9970539617352188e-004 0.5463526844978333 0.3740724027156830 <_> <_> <_>5 5 3 2 -1. <_>5 6 3 1 2. 0 4.1677621193230152e-003 0.4703496992588043 0.7435721755027771 <_> <_> <_>10 1 3 4 -1. <_>11 1 1 4 3. 0 -6.3905320130288601e-003 0.2069258987903595 0.5280538201332092 <_> <_> <_>1 2 5 9 -1. <_>1 5 5 3 3. 0 4.5029609464108944e-003 0.5182648897171021 0.3483543097972870 <_> <_> <_>13 6 2 3 -1. <_>13 7 2 1 3. 0 -9.2040365561842918e-003 0.6803777217864990 0.4932360053062439 <_> <_> <_>0 6 14 3 -1. <_>7 6 7 3 2. 0 0.0813272595405579 0.5058398842811585 0.2253051996231079 <_> <_> <_>2 11 18 8 -1. <_>2 15 18 4 2. 0 -0.1507928073406220 0.2963424921035767 0.5264679789543152 <_> <_> <_>5 6 2 3 -1. <_>5 7 2 1 3. 0 3.3179009333252907e-003 0.4655495882034302 0.7072932124137878 <_> <_> <_>10 6 4 2 -1. <_>12 6 2 1 2. <_>10 7 2 1 2. 0 7.7402801252901554e-004 0.4780347943305969 0.5668237805366516 <_> <_> <_>6 6 4 2 -1. <_>6 6 2 1 2. <_>8 7 2 1 2. 0 6.8199541419744492e-004 0.4286996126174927 0.5722156763076782 <_> <_> <_>10 1 3 4 -1. <_>11 1 1 4 3. 0 5.3671570494771004e-003 0.5299307107925415 0.3114621937274933 <_> <_> <_>7 1 2 7 -1. <_>8 1 1 7 2. 0 9.7018666565418243e-005 0.3674638867378235 0.5269461870193481 <_> <_> <_>4 2 15 14 -1. <_>4 9 15 7 2. 0 -0.1253408938646317 0.2351492047309876 0.5245791077613831 <_> <_> <_>8 7 3 2 -1. <_>9 7 1 2 3. 0 -5.2516269497573376e-003 0.7115936875343323 0.4693767130374908 <_> <_> <_>2 3 18 4 -1. <_>11 3 9 2 2. <_>2 5 9 2 2. 0 -7.8342109918594360e-003 0.4462651014328003 0.5409085750579834 <_> <_> <_>9 7 2 2 -1. <_>10 7 1 2 2. 0 -1.1310069821774960e-003 0.5945618748664856 0.4417662024497986 <_> <_> <_>13 9 2 3 -1. <_>13 9 1 3 2. 0 1.7601120052859187e-003 0.5353249907493591 0.3973453044891357 <_> <_> <_>5 2 6 2 -1. <_>7 2 2 2 3. 0 -8.1581249833106995e-004 0.3760268092155457 0.5264726877212524 <_> <_> <_>9 5 2 7 -1. <_>9 5 1 7 2. 0 -3.8687589112669230e-003 0.6309912800788879 0.4749819934368134 <_> <_> <_>5 9 2 3 -1. <_>6 9 1 3 2. 0 1.5207129763439298e-003 0.5230181813240051 0.3361223936080933 <_> <_> <_>6 0 14 18 -1. <_>6 9 14 9 2. 0 0.5458673834800720 0.5167139768600464 0.1172635033726692 <_> <_> <_>2 16 6 3 -1. <_>2 17 6 1 3. 0 0.0156501904129982 0.4979439079761505 0.1393294930458069 <_> <_> <_>9 7 3 6 -1. <_>10 7 1 6 3. 0 -0.0117318602278829 0.7129650712013245 0.4921196103096008 <_> <_> <_>7 8 4 3 -1. <_>7 9 4 1 3. 0 -6.1765122227370739e-003 0.2288102954626083 0.5049701929092407 <_> <_> <_>7 12 6 3 -1. <_>7 13 6 1 3. 0 2.2457661107182503e-003 0.4632433950901032 0.6048725843429565 <_> <_> <_>9 12 2 3 -1. <_>9 13 2 1 3. 0 -5.1915869116783142e-003 0.6467421054840088 0.4602192938327789 <_> <_> <_>7 12 6 2 -1. <_>9 12 2 2 3. 0 -0.0238278806209564 0.1482000946998596 0.5226079225540161 <_> <_> <_>5 11 4 6 -1. <_>5 14 4 3 2. 0 1.0284580057486892e-003 0.5135489106178284 0.3375957012176514 <_> <_> <_>11 12 7 2 -1. <_>11 13 7 1 2. 0 -0.0100788502022624 0.2740561068058014 0.5303567051887512 <_> <_> <_>6 10 8 6 -1. <_>6 10 4 3 2. <_>10 13 4 3 2. 0 2.6168930344283581e-003 0.5332670807838440 0.3972454071044922 <_> <_> <_>11 10 3 4 -1. <_>11 12 3 2 2. 0 5.4385367548093200e-004 0.5365604162216187 0.4063411951065064 <_> <_> <_>9 16 2 3 -1. <_>9 17 2 1 3. 0 5.3510512225329876e-003 0.4653759002685547 0.6889045834541321 <_> <_> <_>13 3 1 9 -1. <_>13 6 1 3 3. 0 -1.5274790348485112e-003 0.5449501276016235 0.3624723851680756 <_> <_> <_>1 13 14 6 -1. <_>1 15 14 2 3. 0 -0.0806244164705276 0.1656087040901184 0.5000287294387817 <_> <_> <_>13 6 1 6 -1. <_>13 9 1 3 2. 0 0.0221920292824507 0.5132731199264526 0.2002808004617691 <_> <_> <_>0 4 3 8 -1. <_>1 4 1 8 3. 0 7.3100631125271320e-003 0.4617947936058044 0.6366536021232605 <_> <_> <_>18 0 2 18 -1. <_>18 0 1 18 2. 0 -6.4063072204589844e-003 0.5916250944137573 0.4867860972881317 <_> <_> <_>2 3 6 2 -1. <_>2 4 6 1 2. 0 -7.6415040530264378e-004 0.3888409137725830 0.5315797924995422 <_> <_> <_>9 0 8 6 -1. <_>9 2 8 2 3. 0 7.6734489994123578e-004 0.4159064888954163 0.5605279803276062 <_> <_> <_>6 6 1 6 -1. <_>6 9 1 3 2. 0 6.1474501853808761e-004 0.3089022040367127 0.5120148062705994 <_> <_> <_>14 8 6 3 -1. <_>14 9 6 1 3. 0 -5.0105270929634571e-003 0.3972199857234955 0.5207306146621704 <_> <_> <_>0 0 2 18 -1. <_>1 0 1 18 2. 0 -8.6909132078289986e-003 0.6257408261299133 0.4608575999736786 <_> <_> <_>1 18 18 2 -1. <_>10 18 9 1 2. <_>1 19 9 1 2. 0 -0.0163914598524570 0.2085209935903549 0.5242266058921814 <_> <_> <_>3 15 2 2 -1. <_>3 16 2 1 2. 0 4.0973909199237823e-004 0.5222427248954773 0.3780320882797241 <_> <_> <_>8 14 5 3 -1. <_>8 15 5 1 3. 0 -2.5242289993911982e-003 0.5803927183151245 0.4611890017986298 <_> <_> <_>8 14 2 3 -1. <_>8 15 2 1 3. 0 5.0945312250405550e-004 0.4401271939277649 0.5846015810966492 <_> <_> <_>12 3 3 3 -1. <_>13 3 1 3 3. 0 1.9656419754028320e-003 0.5322325229644775 0.4184590876102448 <_> <_> <_>7 5 6 2 -1. <_>9 5 2 2 3. 0 5.6298897834494710e-004 0.3741844892501831 0.5234565734863281 <_> <_> <_>15 5 5 2 -1. <_>15 6 5 1 2. 0 -6.7946797935292125e-004 0.4631041884422302 0.5356478095054627 <_> <_> <_>0 5 5 2 -1. <_>0 6 5 1 2. 0 7.2856349870562553e-003 0.5044670104980469 0.2377564013004303 <_> <_> <_>17 14 1 6 -1. <_>17 17 1 3 2. 0 -0.0174594894051552 0.7289121150970459 0.5050435066223145 <_> <_> <_>2 9 9 3 -1. <_>5 9 3 3 3. 0 -0.0254217498004436 0.6667134761810303 0.4678100049495697 <_> <_> <_>12 3 3 3 -1. <_>13 3 1 3 3. 0 -1.5647639520466328e-003 0.4391759037971497 0.5323626995086670 <_> <_> <_>0 0 4 18 -1. <_>2 0 2 18 2. 0 0.0114443600177765 0.4346440136432648 0.5680012106895447 <_> <_> <_>17 6 1 3 -1. <_>17 7 1 1 3. 0 -6.7352550104260445e-004 0.4477140903472900 0.5296812057495117 <_> <_> <_>2 14 1 6 -1. <_>2 17 1 3 2. 0 9.3194209039211273e-003 0.4740200042724609 0.7462607026100159 <_> <_> <_>19 8 1 2 -1. <_>19 9 1 1 2. 0 1.3328490604180843e-004 0.5365061759948731 0.4752134978771210 <_> <_> <_>5 3 3 3 -1. <_>6 3 1 3 3. 0 -7.8815799206495285e-003 0.1752219051122665 0.5015255212783814 <_> <_> <_>9 16 2 3 -1. <_>9 17 2 1 3. 0 -5.7985680177807808e-003 0.7271236777305603 0.4896200895309448 <_> <_> <_>2 6 1 3 -1. <_>2 7 1 1 3. 0 -3.8922499516047537e-004 0.4003908932209015 0.5344941020011902 <_> <_> <_>12 4 8 2 -1. <_>16 4 4 1 2. <_>12 5 4 1 2. 0 -1.9288610201328993e-003 0.5605612993240356 0.4803955852985382 <_> <_> <_>0 4 8 2 -1. <_>0 4 4 1 2. <_>4 5 4 1 2. 0 8.4214154630899429e-003 0.4753246903419495 0.7623608708381653 <_> <_> <_>2 16 18 4 -1. <_>2 18 18 2 2. 0 8.1655876711010933e-003 0.5393261909484863 0.4191643893718720 <_> <_> <_>7 15 2 4 -1. <_>7 17 2 2 2. 0 4.8280550981871784e-004 0.4240800142288208 0.5399821996688843 <_> <_> <_>4 0 14 3 -1. <_>4 1 14 1 3. 0 -2.7186630759388208e-003 0.4244599938392639 0.5424923896789551 <_> <_> <_>0 0 4 20 -1. <_>2 0 2 20 2. 0 -0.0125072300434113 0.5895841717720032 0.4550411105155945 <_> <_> <_>12 4 4 8 -1. <_>14 4 2 4 2. <_>12 8 2 4 2. 0 -0.0242865197360516 0.2647134959697723 0.5189179778099060 <_> <_> <_>6 7 2 2 -1. <_>6 7 1 1 2. <_>7 8 1 1 2. 0 -2.9676330741494894e-003 0.7347682714462280 0.4749749898910523 <_> <_> <_>10 6 2 3 -1. <_>10 7 2 1 3. 0 -0.0125289997085929 0.2756049931049347 0.5177599787712097 <_> <_> <_>8 7 3 2 -1. <_>8 8 3 1 2. 0 -1.0104000102728605e-003 0.3510560989379883 0.5144724249839783 <_> <_> <_>8 2 6 12 -1. <_>8 8 6 6 2. 0 -2.1348530426621437e-003 0.5637925863265991 0.4667319953441620 <_> <_> <_>4 0 11 12 -1. <_>4 4 11 4 3. 0 0.0195642597973347 0.4614573121070862 0.6137639880180359 <_> <_> <_>14 9 6 11 -1. <_>16 9 2 11 3. 0 -0.0971463471651077 0.2998378872871399 0.5193555951118469 <_> <_> <_>0 14 4 3 -1. <_>0 15 4 1 3. 0 4.5014568604528904e-003 0.5077884793281555 0.3045755922794342 <_> <_> <_>9 10 2 3 -1. <_>9 11 2 1 3. 0 6.3706971704959869e-003 0.4861018955707550 0.6887500882148743 <_> <_> <_>5 11 3 2 -1. <_>5 12 3 1 2. 0 -9.0721528977155685e-003 0.1673395931720734 0.5017563104629517 <_> <_> <_>9 15 3 3 -1. <_>10 15 1 3 3. 0 -5.3537208586931229e-003 0.2692756950855255 0.5242633223533630 <_> <_> <_>8 8 3 4 -1. <_>9 8 1 4 3. 0 -0.0109328404068947 0.7183864116668701 0.4736028909683228 <_> <_> <_>9 15 3 3 -1. <_>10 15 1 3 3. 0 8.2356072962284088e-003 0.5223966836929321 0.2389862984418869 <_> <_> <_>7 7 3 2 -1. <_>8 7 1 2 3. 0 -1.0038160253316164e-003 0.5719355940818787 0.4433943033218384 <_> <_> <_>2 10 16 4 -1. <_>10 10 8 2 2. <_>2 12 8 2 2. 0 4.0859128348529339e-003 0.5472841858863831 0.4148836135864258 <_> <_> <_>2 3 4 17 -1. <_>4 3 2 17 2. 0 0.1548541933298111 0.4973812103271484 0.0610615983605385 <_> <_> <_>15 13 2 7 -1. <_>15 13 1 7 2. 0 2.0897459762636572e-004 0.4709174036979675 0.5423889160156250 <_> <_> <_>2 2 6 1 -1. <_>5 2 3 1 2. 0 3.3316991175524890e-004 0.4089626967906952 0.5300992131233215 <_> <_> <_>5 2 12 4 -1. <_>9 2 4 4 3. 0 -0.0108134001493454 0.6104369759559631 0.4957334101200104 <_> <_> <_>6 0 8 12 -1. <_>6 0 4 6 2. <_>10 6 4 6 2. 0 0.0456560105085373 0.5069689154624939 0.2866660058498383 <_> <_> <_>13 7 2 2 -1. <_>14 7 1 1 2. <_>13 8 1 1 2. 0 1.2569549726322293e-003 0.4846917092800140 0.6318171024322510 <_> <_> <_>0 12 20 6 -1. <_>0 14 20 2 3. 0 -0.1201507002115250 0.0605261400341988 0.4980959892272949 <_> <_> <_>14 7 2 3 -1. <_>14 7 1 3 2. 0 -1.0533799650147557e-004 0.5363109707832336 0.4708042144775391 <_> <_> <_>0 8 9 12 -1. <_>3 8 3 12 3. 0 -0.2070319056510925 0.0596603304147720 0.4979098141193390 <_> <_> <_>3 0 16 2 -1. <_>3 0 8 2 2. 0 1.2909180077258497e-004 0.4712977111339569 0.5377997756004334 <_> <_> <_>6 15 3 3 -1. <_>6 16 3 1 3. 0 3.8818528992123902e-004 0.4363538026809692 0.5534191131591797 <_> <_> <_>8 15 6 3 -1. <_>8 16 6 1 3. 0 -2.9243610333651304e-003 0.5811185836791992 0.4825215935707092 <_> <_> <_>0 10 1 6 -1. <_>0 12 1 2 3. 0 8.3882332546636462e-004 0.5311700105667114 0.4038138985633850 <_> <_> <_>10 9 4 3 -1. <_>10 10 4 1 3. 0 -1.9061550265178084e-003 0.3770701885223389 0.5260015130043030 <_> <_> <_>9 15 2 3 -1. <_>9 16 2 1 3. 0 8.9514348655939102e-003 0.4766167998313904 0.7682183980941773 <_> <_> <_>5 7 10 1 -1. <_>5 7 5 1 2. 0 0.0130834598094225 0.5264462828636169 0.3062222003936768 <_> <_> <_>4 0 12 19 -1. <_>10 0 6 19 2. 0 -0.2115933001041412 0.6737198233604431 0.4695810079574585 <_> <_> <_>0 6 20 6 -1. <_>10 6 10 3 2. <_>0 9 10 3 2. 0 3.1493250280618668e-003 0.5644835233688355 0.4386953115463257 <_> <_> <_>3 6 2 2 -1. <_>3 6 1 1 2. <_>4 7 1 1 2. 0 3.9754100725986063e-004 0.4526061117649078 0.5895630121231079 <_> <_> <_>15 6 2 2 -1. <_>16 6 1 1 2. <_>15 7 1 1 2. 0 -1.3814480043947697e-003 0.6070582270622253 0.4942413866519928 <_> <_> <_>3 6 2 2 -1. <_>3 6 1 1 2. <_>4 7 1 1 2. 0 -5.8122188784182072e-004 0.5998213291168213 0.4508252143859863 <_> <_> <_>14 4 1 12 -1. <_>14 10 1 6 2. 0 -2.3905329871922731e-003 0.4205588996410370 0.5223848223686218 <_> <_> <_>2 5 16 10 -1. <_>2 5 8 5 2. <_>10 10 8 5 2. 0 0.0272689294070005 0.5206447243690491 0.3563301861286163 <_> <_> <_>9 17 3 2 -1. <_>10 17 1 2 3. 0 -3.7658358924090862e-003 0.3144704103469849 0.5218814015388489 <_> <_> <_>1 4 2 2 -1. <_>1 5 2 1 2. 0 -1.4903489500284195e-003 0.3380196094512940 0.5124437212944031 <_> <_> <_>5 0 15 5 -1. <_>10 0 5 5 3. 0 -0.0174282304942608 0.5829960703849793 0.4919725954532623 <_> <_> <_>0 0 15 5 -1. <_>5 0 5 5 3. 0 -0.0152780301868916 0.6163144707679749 0.4617887139320374 <_> <_> <_>11 2 2 17 -1. <_>11 2 1 17 2. 0 0.0319956094026566 0.5166357159614563 0.1712764054536820 <_> <_> <_>7 2 2 17 -1. <_>8 2 1 17 2. 0 -3.8256710395216942e-003 0.3408012092113495 0.5131387710571289 <_> <_> <_>15 11 2 9 -1. <_>15 11 1 9 2. 0 -8.5186436772346497e-003 0.6105518937110901 0.4997941851615906 <_> <_> <_>3 11 2 9 -1. <_>4 11 1 9 2. 0 9.0641621500253677e-004 0.4327270984649658 0.5582311153411865 <_> <_> <_>5 16 14 4 -1. <_>5 16 7 4 2. 0 0.0103448498994112 0.4855653047561646 0.5452420115470886 69.2298736572265630 15 -1 <_> <_> <_> <_>1 4 18 1 -1. <_>7 4 6 1 3. 0 7.8981826081871986e-003 0.3332524895668030 0.5946462154388428 <_> <_> <_>13 7 6 4 -1. <_>16 7 3 2 2. <_>13 9 3 2 2. 0 1.6170160379260778e-003 0.3490641117095947 0.5577868819236755 <_> <_> <_>9 8 2 12 -1. <_>9 12 2 4 3. 0 -5.5449741194024682e-004 0.5542566180229187 0.3291530013084412 <_> <_> <_>12 1 6 6 -1. <_>12 3 6 2 3. 0 1.5428980113938451e-003 0.3612579107284546 0.5545979142189026 <_> <_> <_>5 2 6 6 -1. <_>5 2 3 3 2. <_>8 5 3 3 2. 0 -1.0329450014978647e-003 0.3530139029026032 0.5576140284538269 <_> <_> <_>9 16 6 4 -1. <_>12 16 3 2 2. <_>9 18 3 2 2. 0 7.7698158565908670e-004 0.3916778862476349 0.5645321011543274 <_> <_> <_>1 2 18 3 -1. <_>7 2 6 3 3. 0 0.1432030051946640 0.4667482078075409 0.7023633122444153 <_> <_> <_>7 4 9 10 -1. <_>7 9 9 5 2. 0 -7.3866490274667740e-003 0.3073684871196747 0.5289257764816284 <_> <_> <_>5 9 4 4 -1. <_>7 9 2 4 2. 0 -6.2936742324382067e-004 0.5622118115425110 0.4037049114704132 <_> <_> <_>11 10 3 6 -1. <_>11 13 3 3 2. 0 7.8893528552725911e-004 0.5267661213874817 0.3557874858379364 <_> <_> <_>7 11 5 3 -1. <_>7 12 5 1 3. 0 -0.0122280502691865 0.6668320894241333 0.4625549912452698 <_> <_> <_>7 11 6 6 -1. <_>10 11 3 3 2. <_>7 14 3 3 2. 0 3.5420239437371492e-003 0.5521438121795654 0.3869673013687134 <_> <_> <_>0 0 10 9 -1. <_>0 3 10 3 3. 0 -1.0585320414975286e-003 0.3628678023815155 0.5320926904678345 <_> <_> <_>13 14 1 6 -1. <_>13 16 1 2 3. 0 1.4935660146875307e-005 0.4632444977760315 0.5363323092460632 <_> <_> <_>0 2 3 6 -1. <_>0 4 3 2 3. 0 5.2537708543241024e-003 0.5132231712341309 0.3265708982944489 <_> <_> <_>8 14 4 3 -1. <_>8 15 4 1 3. 0 -8.2338023930788040e-003 0.6693689823150635 0.4774140119552612 <_> <_> <_>6 14 1 6 -1. <_>6 16 1 2 3. 0 2.1866810129722580e-005 0.4053862094879150 0.5457931160926819 <_> <_> <_>9 15 2 3 -1. <_>9 16 2 1 3. 0 -3.8150229956954718e-003 0.6454995870590210 0.4793178141117096 <_> <_> <_>6 4 3 3 -1. <_>7 4 1 3 3. 0 1.1105879675596952e-003 0.5270407199859619 0.3529678881168366 <_> <_> <_>9 0 11 3 -1. <_>9 1 11 1 3. 0 -5.7707689702510834e-003 0.3803547024726868 0.5352957844734192 <_> <_> <_>0 6 20 3 -1. <_>0 7 20 1 3. 0 -3.0158339068293571e-003 0.5339403152465820 0.3887133002281189 <_> <_> <_>10 1 1 2 -1. <_>10 2 1 1 2. 0 -8.5453689098358154e-004 0.3564616143703461 0.5273603796958923 <_> <_> <_>9 6 2 6 -1. <_>10 6 1 6 2. 0 0.0110505102202296 0.4671907126903534 0.6849737763404846 <_> <_> <_>5 8 12 1 -1. <_>9 8 4 1 3. 0 0.0426058396697044 0.5151473283767700 0.0702200904488564 <_> <_> <_>3 8 12 1 -1. <_>7 8 4 1 3. 0 -3.0781750101596117e-003 0.3041661083698273 0.5152602195739746 <_> <_> <_>9 7 3 5 -1. <_>10 7 1 5 3. 0 -5.4815728217363358e-003 0.6430295705795288 0.4897229969501495 <_> <_> <_>3 9 6 2 -1. <_>6 9 3 2 2. 0 3.1881860923022032e-003 0.5307493209838867 0.3826209902763367 <_> <_> <_>12 9 3 3 -1. <_>12 10 3 1 3. 0 3.5947180003859103e-004 0.4650047123432159 0.5421904921531677 <_> <_> <_>7 0 6 1 -1. <_>9 0 2 1 3. 0 -4.0705031715333462e-003 0.2849679887294769 0.5079116225242615 <_> <_> <_>12 9 3 3 -1. <_>12 10 3 1 3. 0 -0.0145941702648997 0.2971645891666412 0.5128461718559265 <_> <_> <_>7 10 2 1 -1. <_>8 10 1 1 2. 0 -1.1947689927183092e-004 0.5631098151206970 0.4343082010746002 <_> <_> <_>6 4 9 13 -1. <_>9 4 3 13 3. 0 -6.9344649091362953e-004 0.4403578042984009 0.5359959006309509 <_> <_> <_>6 8 4 2 -1. <_>6 9 4 1 2. 0 1.4834799912932795e-005 0.3421008884906769 0.5164697766304016 <_> <_> <_>16 2 4 6 -1. <_>16 2 2 6 2. 0 9.0296985581517220e-003 0.4639343023300171 0.6114075183868408 <_> <_> <_>0 17 6 3 -1. <_>0 18 6 1 3. 0 -8.0640818923711777e-003 0.2820158898830414 0.5075494050979614 <_> <_> <_>10 10 3 10 -1. <_>10 15 3 5 2. 0 0.0260621197521687 0.5208905935287476 0.2688778042793274 <_> <_> <_>8 7 3 5 -1. <_>9 7 1 5 3. 0 0.0173146594315767 0.4663713872432709 0.6738539934158325 <_> <_> <_>10 4 4 3 -1. <_>10 4 2 3 2. 0 0.0226666405797005 0.5209349989891052 0.2212723940610886 <_> <_> <_>8 4 3 8 -1. <_>9 4 1 8 3. 0 -2.1965929772704840e-003 0.6063101291656494 0.4538190066814423 <_> <_> <_>6 6 9 13 -1. <_>9 6 3 13 3. 0 -9.5282476395368576e-003 0.4635204970836639 0.5247430801391602 <_> <_> <_>6 0 8 12 -1. <_>6 0 4 6 2. <_>10 6 4 6 2. 0 8.0943619832396507e-003 0.5289440155029297 0.3913882076740265 <_> <_> <_>14 2 6 8 -1. <_>16 2 2 8 3. 0 -0.0728773325681686 0.7752001881599426 0.4990234971046448 <_> <_> <_>6 0 3 6 -1. <_>7 0 1 6 3. 0 -6.9009521976113319e-003 0.2428039014339447 0.5048090219497681 <_> <_> <_>14 2 6 8 -1. <_>16 2 2 8 3. 0 -0.0113082397729158 0.5734364986419678 0.4842376112937927 <_> <_> <_>0 5 6 6 -1. <_>0 8 6 3 2. 0 0.0596132017672062 0.5029836297035217 0.2524977028369904 <_> <_> <_>9 12 6 2 -1. <_>12 12 3 1 2. <_>9 13 3 1 2. 0 -2.8624620754271746e-003 0.6073045134544373 0.4898459911346436 <_> <_> <_>8 17 3 2 -1. <_>9 17 1 2 3. 0 4.4781449250876904e-003 0.5015289187431335 0.2220316976308823 <_> <_> <_>11 6 2 2 -1. <_>12 6 1 1 2. <_>11 7 1 1 2. 0 -1.7513240454718471e-003 0.6614428758621216 0.4933868944644928 <_> <_> <_>1 9 18 2 -1. <_>7 9 6 2 3. 0 0.0401634201407433 0.5180878043174744 0.3741044998168945 <_> <_> <_>11 6 2 2 -1. <_>12 6 1 1 2. <_>11 7 1 1 2. 0 3.4768949262797832e-004 0.4720416963100433 0.5818032026290894 <_> <_> <_>3 4 12 8 -1. <_>7 4 4 8 3. 0 2.6551650371402502e-003 0.3805010914802551 0.5221335887908936 <_> <_> <_>13 11 5 3 -1. <_>13 12 5 1 3. 0 -8.7706279009580612e-003 0.2944166064262390 0.5231295228004456 <_> <_> <_>9 10 2 3 -1. <_>9 11 2 1 3. 0 -5.5122091434895992e-003 0.7346177101135254 0.4722816944122315 <_> <_> <_>14 7 2 3 -1. <_>14 7 1 3 2. 0 6.8672042107209563e-004 0.5452876091003418 0.4242413043975830 <_> <_> <_>5 4 1 3 -1. <_>5 5 1 1 3. 0 5.6019669864326715e-004 0.4398862123489380 0.5601285099983215 <_> <_> <_>13 4 2 3 -1. <_>13 5 2 1 3. 0 2.4143769405782223e-003 0.4741686880588532 0.6136621832847595 <_> <_> <_>5 4 2 3 -1. <_>5 5 2 1 3. 0 -1.5680900542065501e-003 0.6044552922248840 0.4516409933567047 <_> <_> <_>9 8 2 3 -1. <_>9 9 2 1 3. 0 -3.6827491130679846e-003 0.2452459037303925 0.5294982194900513 <_> <_> <_>8 9 2 2 -1. <_>8 10 2 1 2. 0 -2.9409190756268799e-004 0.3732838034629822 0.5251451134681702 <_> <_> <_>15 14 1 4 -1. <_>15 16 1 2 2. 0 4.2847759323194623e-004 0.5498809814453125 0.4065535068511963 <_> <_> <_>3 12 2 2 -1. <_>3 13 2 1 2. 0 -4.8817070201039314e-003 0.2139908969402313 0.4999957084655762 <_> <_> <_>12 15 2 2 -1. <_>13 15 1 1 2. <_>12 16 1 1 2. 0 2.7272020815871656e-004 0.4650287032127380 0.5813428759574890 <_> <_> <_>9 13 2 2 -1. <_>9 14 2 1 2. 0 2.0947199664078653e-004 0.4387486875057221 0.5572792887687683 <_> <_> <_>4 11 14 9 -1. <_>4 14 14 3 3. 0 0.0485011897981167 0.5244972705841065 0.3212889134883881 <_> <_> <_>7 13 4 3 -1. <_>7 14 4 1 3. 0 -4.5166411437094212e-003 0.6056813001632690 0.4545882046222687 <_> <_> <_>15 14 1 4 -1. <_>15 16 1 2 2. 0 -0.0122916800901294 0.2040929049253464 0.5152214169502258 <_> <_> <_>4 14 1 4 -1. <_>4 16 1 2 2. 0 4.8549679922871292e-004 0.5237604975700378 0.3739503026008606 <_> <_> <_>14 0 6 13 -1. <_>16 0 2 13 3. 0 0.0305560491979122 0.4960533976554871 0.5938246250152588 <_> <_> <_>4 1 2 12 -1. <_>4 1 1 6 2. <_>5 7 1 6 2. 0 -1.5105320198927075e-004 0.5351303815841675 0.4145204126834869 <_> <_> <_>11 14 6 6 -1. <_>14 14 3 3 2. <_>11 17 3 3 2. 0 2.4937440175563097e-003 0.4693366885185242 0.5514941215515137 <_> <_> <_>3 14 6 6 -1. <_>3 14 3 3 2. <_>6 17 3 3 2. 0 -0.0123821301385760 0.6791396737098694 0.4681667983531952 <_> <_> <_>14 17 3 2 -1. <_>14 18 3 1 2. 0 -5.1333461888134480e-003 0.3608739078044891 0.5229160189628601 <_> <_> <_>3 17 3 2 -1. <_>3 18 3 1 2. 0 5.1919277757406235e-004 0.5300073027610779 0.3633613884449005 <_> <_> <_>14 0 6 13 -1. <_>16 0 2 13 3. 0 0.1506042033433914 0.5157316923141480 0.2211782038211823 <_> <_> <_>0 0 6 13 -1. <_>2 0 2 13 3. 0 7.7144149690866470e-003 0.4410496950149536 0.5776609182357788 <_> <_> <_>10 10 7 6 -1. <_>10 12 7 2 3. 0 9.4443522393703461e-003 0.5401855111122131 0.3756650090217590 <_> <_> <_>6 15 2 2 -1. <_>6 15 1 1 2. <_>7 16 1 1 2. 0 2.5006249779835343e-004 0.4368270933628082 0.5607374906539917 <_> <_> <_>6 11 8 6 -1. <_>10 11 4 3 2. <_>6 14 4 3 2. 0 -3.3077150583267212e-003 0.4244799017906189 0.5518230795860291 <_> <_> <_>7 6 2 2 -1. <_>7 6 1 1 2. <_>8 7 1 1 2. 0 7.4048910755664110e-004 0.4496962130069733 0.5900576710700989 <_> <_> <_>2 2 16 6 -1. <_>10 2 8 3 2. <_>2 5 8 3 2. 0 0.0440920516848564 0.5293493270874023 0.3156355023384094 <_> <_> <_>5 4 3 3 -1. <_>5 5 3 1 3. 0 3.3639909233897924e-003 0.4483296871185303 0.5848662257194519 <_> <_> <_>11 7 3 10 -1. <_>11 12 3 5 2. 0 -3.9760079234838486e-003 0.4559507071971893 0.5483639240264893 <_> <_> <_>6 7 3 10 -1. <_>6 12 3 5 2. 0 2.7716930489987135e-003 0.5341786146163940 0.3792484104633331 <_> <_> <_>10 7 3 2 -1. <_>11 7 1 2 3. 0 -2.4123019829858094e-004 0.5667188763618469 0.4576973021030426 <_> <_> <_>8 12 4 2 -1. <_>8 13 4 1 2. 0 4.9425667384639382e-004 0.4421244859695435 0.5628787279129028 <_> <_> <_>10 1 1 3 -1. <_>10 2 1 1 3. 0 -3.8876468897797167e-004 0.4288370907306671 0.5391063094139099 <_> <_> <_>1 2 4 18 -1. <_>1 2 2 9 2. <_>3 11 2 9 2. 0 -0.0500488989055157 0.6899513006210327 0.4703742861747742 <_> <_> <_>12 4 4 12 -1. <_>12 10 4 6 2. 0 -0.0366354808211327 0.2217779010534287 0.5191826224327087 <_> <_> <_>0 0 1 6 -1. <_>0 2 1 2 3. 0 2.4273579474538565e-003 0.5136224031448364 0.3497397899627686 <_> <_> <_>9 11 2 3 -1. <_>9 12 2 1 3. 0 1.9558030180633068e-003 0.4826192855834961 0.6408380866050720 <_> <_> <_>8 7 4 3 -1. <_>8 8 4 1 3. 0 -1.7494610510766506e-003 0.3922835886478424 0.5272685289382935 <_> <_> <_>10 7 3 2 -1. <_>11 7 1 2 3. 0 0.0139550799503922 0.5078201889991760 0.8416504859924316 <_> <_> <_>7 7 3 2 -1. <_>8 7 1 2 3. 0 -2.1896739781368524e-004 0.5520489811897278 0.4314234852790833 <_> <_> <_>9 4 6 1 -1. <_>11 4 2 1 3. 0 -1.5131309628486633e-003 0.3934605121612549 0.5382571220397949 <_> <_> <_>8 7 2 3 -1. <_>9 7 1 3 2. 0 -4.3622800149023533e-003 0.7370628714561462 0.4736475944519043 <_> <_> <_>12 7 8 6 -1. <_>16 7 4 3 2. <_>12 10 4 3 2. 0 0.0651605874300003 0.5159279704093933 0.3281595110893250 <_> <_> <_>0 7 8 6 -1. <_>0 7 4 3 2. <_>4 10 4 3 2. 0 -2.3567399475723505e-003 0.3672826886177063 0.5172886252403259 <_> <_> <_>18 2 2 10 -1. <_>19 2 1 5 2. <_>18 7 1 5 2. 0 0.0151466596871614 0.5031493902206421 0.6687604188919067 <_> <_> <_>0 2 6 4 -1. <_>3 2 3 4 2. 0 -0.0228509604930878 0.6767519712448120 0.4709596931934357 <_> <_> <_>9 4 6 1 -1. <_>11 4 2 1 3. 0 4.8867650330066681e-003 0.5257998108863831 0.4059878885746002 <_> <_> <_>7 15 2 2 -1. <_>7 15 1 1 2. <_>8 16 1 1 2. 0 1.7619599821045995e-003 0.4696272909641266 0.6688278913497925 <_> <_> <_>11 13 1 6 -1. <_>11 16 1 3 2. 0 -1.2942519970238209e-003 0.4320712983608246 0.5344281792640686 <_> <_> <_>8 13 1 6 -1. <_>8 16 1 3 2. 0 0.0109299495816231 0.4997706115245819 0.1637486070394516 <_> <_> <_>14 3 2 1 -1. <_>14 3 1 1 2. 0 2.9958489903947338e-005 0.4282417893409729 0.5633224248886108 <_> <_> <_>8 15 2 3 -1. <_>8 16 2 1 3. 0 -6.5884361974895000e-003 0.6772121191024780 0.4700526893138886 <_> <_> <_>12 15 7 4 -1. <_>12 17 7 2 2. 0 3.2527779694646597e-003 0.5313397049903870 0.4536148905754089 <_> <_> <_>4 14 12 3 -1. <_>4 15 12 1 3. 0 -4.0435739792883396e-003 0.5660061836242676 0.4413388967514038 <_> <_> <_>10 3 3 2 -1. <_>11 3 1 2 3. 0 -1.2523540062829852e-003 0.3731913864612579 0.5356451869010925 <_> <_> <_>4 12 2 2 -1. <_>4 13 2 1 2. 0 1.9246719602961093e-004 0.5189986228942871 0.3738811016082764 <_> <_> <_>10 11 4 6 -1. <_>10 14 4 3 2. 0 -0.0385896712541580 0.2956373989582062 0.5188810825347900 <_> <_> <_>7 13 2 2 -1. <_>7 13 1 1 2. <_>8 14 1 1 2. 0 1.5489870565943420e-004 0.4347135126590729 0.5509533286094666 <_> <_> <_>4 11 14 4 -1. <_>11 11 7 2 2. <_>4 13 7 2 2. 0 -0.0337638482451439 0.3230330049991608 0.5195475816726685 <_> <_> <_>1 18 18 2 -1. <_>7 18 6 2 3. 0 -8.2657067105174065e-003 0.5975489020347595 0.4552114009857178 <_> <_> <_>11 18 2 2 -1. <_>12 18 1 1 2. <_>11 19 1 1 2. 0 1.4481440302915871e-005 0.4745678007602692 0.5497426986694336 <_> <_> <_>7 18 2 2 -1. <_>7 18 1 1 2. <_>8 19 1 1 2. 0 1.4951299817766994e-005 0.4324473142623901 0.5480644106864929 <_> <_> <_>12 18 8 2 -1. <_>12 19 8 1 2. 0 -0.0187417995184660 0.1580052971839905 0.5178533196449280 <_> <_> <_>7 14 6 2 -1. <_>7 15 6 1 2. 0 1.7572239739820361e-003 0.4517636895179749 0.5773764252662659 <_> <_> <_>8 12 4 8 -1. <_>10 12 2 4 2. <_>8 16 2 4 2. 0 -3.1391119118779898e-003 0.4149647951126099 0.5460842251777649 <_> <_> <_>4 9 3 3 -1. <_>4 10 3 1 3. 0 6.6656779381446540e-005 0.4039090871810913 0.5293084979057312 <_> <_> <_>7 10 6 2 -1. <_>9 10 2 2 3. 0 6.7743421532213688e-003 0.4767651855945587 0.6121956110000610 <_> <_> <_>5 0 4 15 -1. <_>7 0 2 15 2. 0 -7.3868161998689175e-003 0.3586258888244629 0.5187280774116516 <_> <_> <_>8 6 12 14 -1. <_>12 6 4 14 3. 0 0.0140409301966429 0.4712139964103699 0.5576155781745911 <_> <_> <_>5 16 3 3 -1. <_>5 17 3 1 3. 0 -5.5258329957723618e-003 0.2661027014255524 0.5039281249046326 <_> <_> <_>8 1 12 19 -1. <_>12 1 4 19 3. 0 0.3868423998355866 0.5144339799880981 0.2525899112224579 <_> <_> <_>3 0 3 2 -1. <_>3 1 3 1 2. 0 1.1459240340627730e-004 0.4284994900226593 0.5423371195793152 <_> <_> <_>10 12 4 5 -1. <_>10 12 2 5 2. 0 -0.0184675697237253 0.3885835111141205 0.5213062167167664 <_> <_> <_>6 12 4 5 -1. <_>8 12 2 5 2. 0 -4.5907011372037232e-004 0.5412563085556030 0.4235909879207611 <_> <_> <_>11 11 2 2 -1. <_>12 11 1 1 2. <_>11 12 1 1 2. 0 1.2527540093287826e-003 0.4899305105209351 0.6624091267585754 <_> <_> <_>0 2 3 6 -1. <_>0 4 3 2 3. 0 1.4910609461367130e-003 0.5286778211593628 0.4040051996707916 <_> <_> <_>11 11 2 2 -1. <_>12 11 1 1 2. <_>11 12 1 1 2. 0 -7.5435562757775187e-004 0.6032990217208862 0.4795120060443878 <_> <_> <_>7 6 4 10 -1. <_>7 11 4 5 2. 0 -6.9478838704526424e-003 0.4084401130676270 0.5373504161834717 <_> <_> <_>11 11 2 2 -1. <_>12 11 1 1 2. <_>11 12 1 1 2. 0 2.8092920547351241e-004 0.4846062958240509 0.5759382247924805 <_> <_> <_>2 13 5 2 -1. <_>2 14 5 1 2. 0 9.6073717577382922e-004 0.5164741277694702 0.3554979860782623 <_> <_> <_>11 11 2 2 -1. <_>12 11 1 1 2. <_>11 12 1 1 2. 0 -2.6883929967880249e-004 0.5677582025527954 0.4731765985488892 <_> <_> <_>7 11 2 2 -1. <_>7 11 1 1 2. <_>8 12 1 1 2. 0 2.1599370520561934e-003 0.4731487035751343 0.7070567011833191 <_> <_> <_>14 13 3 3 -1. <_>14 14 3 1 3. 0 5.6235301308333874e-003 0.5240243077278137 0.2781791985034943 <_> <_> <_>3 13 3 3 -1. <_>3 14 3 1 3. 0 -5.0243991427123547e-003 0.2837013900279999 0.5062304139137268 <_> <_> <_>9 14 2 3 -1. <_>9 15 2 1 3. 0 -9.7611639648675919e-003 0.7400717735290527 0.4934569001197815 <_> <_> <_>8 7 3 3 -1. <_>8 8 3 1 3. 0 4.1515100747346878e-003 0.5119131207466126 0.3407008051872253 <_> <_> <_>13 5 3 3 -1. <_>13 6 3 1 3. 0 6.2465080991387367e-003 0.4923788011074066 0.6579058766365051 <_> <_> <_>0 9 5 3 -1. <_>0 10 5 1 3. 0 -7.0597478188574314e-003 0.2434711009263992 0.5032842159271240 <_> <_> <_>13 5 3 3 -1. <_>13 6 3 1 3. 0 -2.0587709732353687e-003 0.5900310873985291 0.4695087075233460 <_> <_> <_>9 12 2 8 -1. <_>9 12 1 4 2. <_>10 16 1 4 2. 0 -2.4146060459315777e-003 0.3647317886352539 0.5189201831817627 <_> <_> <_>11 7 2 2 -1. <_>12 7 1 1 2. <_>11 8 1 1 2. 0 -1.4817609917372465e-003 0.6034948229789734 0.4940128028392792 <_> <_> <_>0 16 6 4 -1. <_>3 16 3 4 2. 0 -6.3016400672495365e-003 0.5818989872932434 0.4560427963733673 <_> <_> <_>10 6 2 3 -1. <_>10 7 2 1 3. 0 3.4763428848236799e-003 0.5217475891113281 0.3483993113040924 <_> <_> <_>9 5 2 6 -1. <_>9 7 2 2 3. 0 -0.0222508702427149 0.2360700070858002 0.5032082796096802 <_> <_> <_>12 15 8 4 -1. <_>12 15 4 4 2. 0 -0.0306125506758690 0.6499186754226685 0.4914919137954712 <_> <_> <_>0 14 8 6 -1. <_>4 14 4 6 2. 0 0.0130574796348810 0.4413323104381561 0.5683764219284058 <_> <_> <_>9 0 3 2 -1. <_>10 0 1 2 3. 0 -6.0095742810517550e-004 0.4359731078147888 0.5333483219146729 <_> <_> <_>4 15 4 2 -1. <_>6 15 2 2 2. 0 -4.1514250915497541e-004 0.5504062771797180 0.4326060116291046 <_> <_> <_>12 7 3 13 -1. <_>13 7 1 13 3. 0 -0.0137762902304530 0.4064112901687622 0.5201548933982849 <_> <_> <_>5 7 3 13 -1. <_>6 7 1 13 3. 0 -0.0322965085506439 0.0473519712686539 0.4977194964885712 <_> <_> <_>9 6 3 9 -1. <_>9 9 3 3 3. 0 0.0535569787025452 0.4881733059883118 0.6666939258575440 <_> <_> <_>4 4 7 12 -1. <_>4 10 7 6 2. 0 8.1889545544981956e-003 0.5400037169456482 0.4240820109844208 <_> <_> <_>12 12 2 2 -1. <_>13 12 1 1 2. <_>12 13 1 1 2. 0 2.1055320394225419e-004 0.4802047908306122 0.5563852787017822 <_> <_> <_>6 12 2 2 -1. <_>6 12 1 1 2. <_>7 13 1 1 2. 0 -2.4382730480283499e-003 0.7387793064117432 0.4773685038089752 <_> <_> <_>8 9 4 2 -1. <_>10 9 2 1 2. <_>8 10 2 1 2. 0 3.2835570164024830e-003 0.5288546085357666 0.3171291947364807 <_> <_> <_>3 6 2 2 -1. <_>3 6 1 1 2. <_>4 7 1 1 2. 0 2.3729570675641298e-003 0.4750812947750092 0.7060170769691467 <_> <_> <_>16 6 3 2 -1. <_>16 7 3 1 2. 0 -1.4541699783876538e-003 0.3811730146408081 0.5330739021301270 79.2490768432617190 16 -1 <_> <_> <_> <_>0 7 19 4 -1. <_>0 9 19 2 2. 0 0.0557552389800549 0.4019156992435455 0.6806036829948425 <_> <_> <_>10 2 10 1 -1. <_>10 2 5 1 2. 0 2.4730248842388391e-003 0.3351148962974548 0.5965719819068909 <_> <_> <_>9 4 2 12 -1. <_>9 10 2 6 2. 0 -3.5031698644161224e-004 0.5557708144187927 0.3482286930084229 <_> <_> <_>12 18 4 1 -1. <_>12 18 2 1 2. 0 5.4167630150914192e-004 0.4260858893394470 0.5693380832672119 <_> <_> <_>1 7 6 4 -1. <_>1 7 3 2 2. <_>4 9 3 2 2. 0 7.7193678589537740e-004 0.3494240045547485 0.5433688759803772 <_> <_> <_>12 0 6 13 -1. <_>14 0 2 13 3. 0 -1.5999219613149762e-003 0.4028499126434326 0.5484359264373779 <_> <_> <_>2 0 6 13 -1. <_>4 0 2 13 3. 0 -1.1832080053864047e-004 0.3806901872158051 0.5425465106964111 <_> <_> <_>10 5 8 8 -1. <_>10 9 8 4 2. 0 3.2909031142480671e-004 0.2620100080966950 0.5429521799087524 <_> <_> <_>8 3 2 5 -1. <_>9 3 1 5 2. 0 2.9518108931370080e-004 0.3799768984317780 0.5399264097213745 <_> <_> <_>8 4 9 1 -1. <_>11 4 3 1 3. 0 9.0466710389591753e-005 0.4433645009994507 0.5440226197242737 <_> <_> <_>3 4 9 1 -1. <_>6 4 3 1 3. 0 1.5007190086180344e-005 0.3719654977321625 0.5409119725227356 <_> <_> <_>1 0 18 10 -1. <_>7 0 6 10 3. 0 0.1393561065196991 0.5525395870208740 0.4479042887687683 <_> <_> <_>7 17 5 3 -1. <_>7 18 5 1 3. 0 1.6461990308016539e-003 0.4264501035213471 0.5772169828414917 <_> <_> <_>7 11 6 1 -1. <_>9 11 2 1 3. 0 4.9984431825578213e-004 0.4359526038169861 0.5685871243476868 <_> <_> <_>2 2 3 2 -1. <_>2 3 3 1 2. 0 -1.0971280280500650e-003 0.3390136957168579 0.5205408930778503 <_> <_> <_>8 12 4 2 -1. <_>8 13 4 1 2. 0 6.6919892560690641e-004 0.4557456076145172 0.5980659723281860 <_> <_> <_>6 10 3 6 -1. <_>6 13 3 3 2. 0 8.6471042595803738e-004 0.5134841203689575 0.2944033145904541 <_> <_> <_>11 4 2 4 -1. <_>11 4 1 4 2. 0 -2.7182599296793342e-004 0.3906578123569489 0.5377181172370911 <_> <_> <_>7 4 2 4 -1. <_>8 4 1 4 2. 0 3.0249499104684219e-005 0.3679609894752502 0.5225688815116882 <_> <_> <_>9 6 2 4 -1. <_>9 6 1 4 2. 0 -8.5225896909832954e-003 0.7293102145195007 0.4892365038394928 <_> <_> <_>6 13 8 3 -1. <_>6 14 8 1 3. 0 1.6705560265108943e-003 0.4345324933528900 0.5696138143539429 <_> <_> <_>9 15 3 4 -1. <_>10 15 1 4 3. 0 -7.1433838456869125e-003 0.2591280043125153 0.5225623846054077 <_> <_> <_>9 2 2 17 -1. <_>10 2 1 17 2. 0 -0.0163193698972464 0.6922279000282288 0.4651575982570648 <_> <_> <_>7 0 6 1 -1. <_>9 0 2 1 3. 0 4.8034260980784893e-003 0.5352262854576111 0.3286302983760834 <_> <_> <_>8 15 3 4 -1. <_>9 15 1 4 3. 0 -7.5421929359436035e-003 0.2040544003248215 0.5034546256065369 <_> <_> <_>7 13 7 3 -1. <_>7 14 7 1 3. 0 -0.0143631100654602 0.6804888844490051 0.4889059066772461 <_> <_> <_>8 16 3 3 -1. <_>9 16 1 3 3. 0 8.9063588529825211e-004 0.5310695767402649 0.3895480930805206 <_> <_> <_>6 2 8 10 -1. <_>6 7 8 5 2. 0 -4.4060191139578819e-003 0.5741562843322754 0.4372426867485046 <_> <_> <_>2 5 8 8 -1. <_>2 9 8 4 2. 0 -1.8862540309783071e-004 0.2831785976886749 0.5098205208778381 <_> <_> <_>14 16 2 2 -1. <_>14 17 2 1 2. 0 -3.7979281041771173e-003 0.3372507989406586 0.5246580243110657 <_> <_> <_>4 16 2 2 -1. <_>4 17 2 1 2. 0 1.4627049677073956e-004 0.5306674242019653 0.3911710083484650 <_> <_> <_>10 11 4 6 -1. <_>10 14 4 3 2. 0 -4.9164638767251745e-005 0.5462496280670166 0.3942720890045166 <_> <_> <_>6 11 4 6 -1. <_>6 14 4 3 2. 0 -0.0335825011134148 0.2157824039459229 0.5048211812973023 <_> <_> <_>10 14 1 3 -1. <_>10 15 1 1 3. 0 -3.5339309833943844e-003 0.6465312242507935 0.4872696995735169 <_> <_> <_>8 14 4 3 -1. <_>8 15 4 1 3. 0 5.0144111737608910e-003 0.4617668092250824 0.6248074769973755 <_> <_> <_>10 0 4 6 -1. <_>12 0 2 3 2. <_>10 3 2 3 2. 0 0.0188173707574606 0.5220689177513123 0.2000052034854889 <_> <_> <_>0 3 20 2 -1. <_>0 4 20 1 2. 0 -1.3434339780360460e-003 0.4014537930488586 0.5301619768142700 <_> <_> <_>12 0 8 2 -1. <_>16 0 4 1 2. <_>12 1 4 1 2. 0 1.7557960236445069e-003 0.4794039130210877 0.5653169751167297 <_> <_> <_>2 12 10 8 -1. <_>2 16 10 4 2. 0 -0.0956374630331993 0.2034195065498352 0.5006706714630127 <_> <_> <_>17 7 2 10 -1. <_>18 7 1 5 2. <_>17 12 1 5 2. 0 -0.0222412291914225 0.7672473192214966 0.5046340227127075 <_> <_> <_>1 7 2 10 -1. <_>1 7 1 5 2. <_>2 12 1 5 2. 0 -0.0155758196488023 0.7490342259407044 0.4755851030349731 <_> <_> <_>15 10 3 6 -1. <_>15 12 3 2 3. 0 5.3599118255078793e-003 0.5365303754806519 0.4004670977592468 <_> <_> <_>4 4 6 2 -1. <_>6 4 2 2 3. 0 -0.0217634998261929 0.0740154981613159 0.4964174926280975 <_> <_> <_>0 5 20 6 -1. <_>0 7 20 2 3. 0 -0.1656159013509750 0.2859103083610535 0.5218086242675781 <_> <_> <_>0 0 8 2 -1. <_>0 0 4 1 2. <_>4 1 4 1 2. 0 1.6461320046801120e-004 0.4191615879535675 0.5380793213844299 <_> <_> <_>1 0 18 4 -1. <_>7 0 6 4 3. 0 -8.9077502489089966e-003 0.6273192763328552 0.4877404868602753 <_> <_> <_>1 13 6 2 -1. <_>1 14 6 1 2. 0 8.6346449097618461e-004 0.5159940719604492 0.3671025931835175 <_> <_> <_>10 8 3 4 -1. <_>11 8 1 4 3. 0 -1.3751760125160217e-003 0.5884376764297485 0.4579083919525147 <_> <_> <_>6 1 6 1 -1. <_>8 1 2 1 3. 0 -1.4081239933148026e-003 0.3560509979724884 0.5139945149421692 <_> <_> <_>8 14 4 3 -1. <_>8 15 4 1 3. 0 -3.9342888630926609e-003 0.5994288921356201 0.4664272069931030 <_> <_> <_>1 6 18 2 -1. <_>10 6 9 2 2. 0 -0.0319669283926487 0.3345462083816528 0.5144183039665222 <_> <_> <_>15 11 1 2 -1. <_>15 12 1 1 2. 0 -1.5089280168467667e-005 0.5582656264305115 0.4414057135581970 <_> <_> <_>6 5 1 2 -1. <_>6 6 1 1 2. 0 5.1994470413774252e-004 0.4623680114746094 0.6168993711471558 <_> <_> <_>13 4 1 3 -1. <_>13 5 1 1 3. 0 -3.4220460802316666e-003 0.6557074785232544 0.4974805116653442 <_> <_> <_>2 15 1 2 -1. <_>2 16 1 1 2. 0 1.7723299970384687e-004 0.5269501805305481 0.3901908099651337 <_> <_> <_>12 4 4 3 -1. <_>12 5 4 1 3. 0 1.5716759953647852e-003 0.4633373022079468 0.5790457725524902 <_> <_> <_>0 0 7 3 -1. <_>0 1 7 1 3. 0 -8.9041329920291901e-003 0.2689608037471771 0.5053591132164002 <_> <_> <_>9 12 6 2 -1. <_>9 12 3 2 2. 0 4.0677518700249493e-004 0.5456603169441223 0.4329898953437805 <_> <_> <_>5 4 2 3 -1. <_>5 5 2 1 3. 0 6.7604780197143555e-003 0.4648993909358978 0.6689761877059937 <_> <_> <_>18 4 2 3 -1. <_>18 5 2 1 3. 0 2.9100088868290186e-003 0.5309703946113586 0.3377839922904968 <_> <_> <_>3 0 8 6 -1. <_>3 2 8 2 3. 0 1.3885459629818797e-003 0.4074738919734955 0.5349133014678955 <_> <_> <_>0 2 20 6 -1. <_>10 2 10 3 2. <_>0 5 10 3 2. 0 -0.0767642632126808 0.1992176026105881 0.5228242278099060 <_> <_> <_>4 7 2 4 -1. <_>5 7 1 4 2. 0 -2.2688310127705336e-004 0.5438501834869385 0.4253072142601013 <_> <_> <_>3 10 15 2 -1. <_>8 10 5 2 3. 0 -6.3094152137637138e-003 0.4259178936481476 0.5378909707069397 <_> <_> <_>3 0 12 11 -1. <_>9 0 6 11 2. 0 -0.1100727990269661 0.6904156804084778 0.4721749126911163 <_> <_> <_>13 0 2 6 -1. <_>13 0 1 6 2. 0 2.8619659133255482e-004 0.4524914920330048 0.5548306107521057 <_> <_> <_>0 19 2 1 -1. <_>1 19 1 1 2. 0 2.9425329557852820e-005 0.5370373725891113 0.4236463904380798 <_> <_> <_>16 10 4 10 -1. <_>18 10 2 5 2. <_>16 15 2 5 2. 0 -0.0248865708708763 0.6423557996749878 0.4969303905963898 <_> <_> <_>4 8 10 3 -1. <_>4 9 10 1 3. 0 0.0331488512456417 0.4988475143909454 0.1613811999559403 <_> <_> <_>14 12 3 3 -1. <_>14 13 3 1 3. 0 7.8491691965609789e-004 0.5416026115417481 0.4223009049892426 <_> <_> <_>0 10 4 10 -1. <_>0 10 2 5 2. <_>2 15 2 5 2. 0 4.7087189741432667e-003 0.4576328992843628 0.6027557849884033 <_> <_> <_>18 3 2 6 -1. <_>18 5 2 2 3. 0 2.4144479539245367e-003 0.5308973193168640 0.4422498941421509 <_> <_> <_>6 6 1 3 -1. <_>6 7 1 1 3. 0 1.9523180089890957e-003 0.4705634117126465 0.6663324832916260 <_> <_> <_>7 7 7 2 -1. <_>7 8 7 1 2. 0 1.3031980488449335e-003 0.4406126141548157 0.5526962280273438 <_> <_> <_>0 3 2 6 -1. <_>0 5 2 2 3. 0 4.4735497795045376e-003 0.5129023790359497 0.3301498889923096 <_> <_> <_>11 1 3 1 -1. <_>12 1 1 1 3. 0 -2.6652868837118149e-003 0.3135471045970917 0.5175036191940308 <_> <_> <_>5 0 2 6 -1. <_>6 0 1 6 2. 0 1.3666770246345550e-004 0.4119370877742767 0.5306876897811890 <_> <_> <_>1 1 18 14 -1. <_>7 1 6 14 3. 0 -0.0171264503151178 0.6177806258201599 0.4836578965187073 <_> <_> <_>4 6 8 3 -1. <_>8 6 4 3 2. 0 -2.6601430727168918e-004 0.3654330968856812 0.5169736742973328 <_> <_> <_>9 12 6 2 -1. <_>9 12 3 2 2. 0 -0.0229323804378510 0.3490915000438690 0.5163992047309876 <_> <_> <_>5 12 6 2 -1. <_>8 12 3 2 2. 0 2.3316550068557262e-003 0.5166299939155579 0.3709389865398407 <_> <_> <_>10 7 3 5 -1. <_>11 7 1 5 3. 0 0.0169256608933210 0.5014736056327820 0.8053988218307495 <_> <_> <_>7 7 3 5 -1. <_>8 7 1 5 3. 0 -8.9858826249837875e-003 0.6470788717269898 0.4657020866870880 <_> <_> <_>13 0 3 10 -1. <_>14 0 1 10 3. 0 -0.0118746999651194 0.3246378898620606 0.5258755087852478 <_> <_> <_>4 11 3 2 -1. <_>4 12 3 1 2. 0 1.9350569345988333e-004 0.5191941857337952 0.3839643895626068 <_> <_> <_>17 3 3 6 -1. <_>18 3 1 6 3. 0 5.8713490143418312e-003 0.4918133914470673 0.6187043190002441 <_> <_> <_>1 8 18 10 -1. <_>1 13 18 5 2. 0 -0.2483879029750824 0.1836802959442139 0.4988150000572205 <_> <_> <_>13 0 3 10 -1. <_>14 0 1 10 3. 0 0.0122560001909733 0.5227053761482239 0.3632029891014099 <_> <_> <_>9 14 2 3 -1. <_>9 15 2 1 3. 0 8.3990179700776935e-004 0.4490250051021576 0.5774148106575012 <_> <_> <_>16 3 3 7 -1. <_>17 3 1 7 3. 0 2.5407369248569012e-003 0.4804787039756775 0.5858299136161804 <_> <_> <_>4 0 3 10 -1. <_>5 0 1 10 3. 0 -0.0148224299773574 0.2521049976348877 0.5023537278175354 <_> <_> <_>16 3 3 7 -1. <_>17 3 1 7 3. 0 -5.7973959483206272e-003 0.5996695756912231 0.4853715002536774 <_> <_> <_>0 9 1 2 -1. <_>0 10 1 1 2. 0 7.2662148158997297e-004 0.5153716802597046 0.3671779930591583 <_> <_> <_>18 1 2 10 -1. <_>18 1 1 10 2. 0 -0.0172325801104307 0.6621719002723694 0.4994656145572662 <_> <_> <_>0 1 2 10 -1. <_>1 1 1 10 2. 0 7.8624086454510689e-003 0.4633395075798035 0.6256101727485657 <_> <_> <_>10 16 3 4 -1. <_>11 16 1 4 3. 0 -4.7343620099127293e-003 0.3615573048591614 0.5281885266304016 <_> <_> <_>2 8 3 3 -1. <_>3 8 1 3 3. 0 8.3048478700220585e-004 0.4442889094352722 0.5550957918167114 <_> <_> <_>11 0 2 6 -1. <_>12 0 1 3 2. <_>11 3 1 3 2. 0 7.6602199114859104e-003 0.5162935256958008 0.2613354921340942 <_> <_> <_>7 0 2 6 -1. <_>7 0 1 3 2. <_>8 3 1 3 2. 0 -4.1048377752304077e-003 0.2789632081985474 0.5019031763076782 <_> <_> <_>16 3 3 7 -1. <_>17 3 1 7 3. 0 4.8512578941881657e-003 0.4968984127044678 0.5661668181419373 <_> <_> <_>1 3 3 7 -1. <_>2 3 1 7 3. 0 9.9896453320980072e-004 0.4445607960224152 0.5551813244819641 <_> <_> <_>14 1 6 16 -1. <_>16 1 2 16 3. 0 -0.2702363133430481 0.0293882098048925 0.5151314139366150 <_> <_> <_>0 1 6 16 -1. <_>2 1 2 16 3. 0 -0.0130906803533435 0.5699399709701538 0.4447459876537323 <_> <_> <_>2 0 16 8 -1. <_>10 0 8 4 2. <_>2 4 8 4 2. 0 -9.4342790544033051e-003 0.4305466115474701 0.5487895011901856 <_> <_> <_>6 8 5 3 -1. <_>6 9 5 1 3. 0 -1.5482039889320731e-003 0.3680317103862763 0.5128080844879150 <_> <_> <_>9 7 3 3 -1. <_>10 7 1 3 3. 0 5.3746132180094719e-003 0.4838916957378388 0.6101555824279785 <_> <_> <_>8 8 4 3 -1. <_>8 9 4 1 3. 0 1.5786769799888134e-003 0.5325223207473755 0.4118548035621643 <_> <_> <_>9 6 2 4 -1. <_>9 6 1 4 2. 0 3.6856050137430429e-003 0.4810948073863983 0.6252303123474121 <_> <_> <_>0 7 15 1 -1. <_>5 7 5 1 3. 0 9.3887019902467728e-003 0.5200229883193970 0.3629410862922669 <_> <_> <_>8 2 7 9 -1. <_>8 5 7 3 3. 0 0.0127926301211119 0.4961709976196289 0.6738016009330750 <_> <_> <_>1 7 16 4 -1. <_>1 7 8 2 2. <_>9 9 8 2 2. 0 -3.3661040943115950e-003 0.4060279130935669 0.5283598899841309 <_> <_> <_>6 12 8 2 -1. <_>6 13 8 1 2. 0 3.9771420415490866e-004 0.4674113988876343 0.5900775194168091 <_> <_> <_>8 11 3 3 -1. <_>8 12 3 1 3. 0 1.4868030557408929e-003 0.4519116878509522 0.6082053780555725 <_> <_> <_>4 5 14 10 -1. <_>11 5 7 5 2. <_>4 10 7 5 2. 0 -0.0886867493391037 0.2807899117469788 0.5180991888046265 <_> <_> <_>4 12 3 2 -1. <_>4 13 3 1 2. 0 -7.4296112870797515e-005 0.5295584201812744 0.4087625145912170 <_> <_> <_>9 11 6 1 -1. <_>11 11 2 1 3. 0 -1.4932939848222304e-005 0.5461400151252747 0.4538542926311493 <_> <_> <_>4 9 7 6 -1. <_>4 11 7 2 3. 0 5.9162238612771034e-003 0.5329161286354065 0.4192134141921997 <_> <_> <_>7 10 6 3 -1. <_>7 11 6 1 3. 0 1.1141640134155750e-003 0.4512017965316773 0.5706217288970947 <_> <_> <_>9 11 2 2 -1. <_>9 12 2 1 2. 0 8.9249362645205110e-005 0.4577805995941162 0.5897638201713562 <_> <_> <_>0 5 20 6 -1. <_>0 7 20 2 3. 0 2.5319510605186224e-003 0.5299603939056397 0.3357639014720917 <_> <_> <_>6 4 6 1 -1. <_>8 4 2 1 3. 0 0.0124262003228068 0.4959059059619904 0.1346601992845535 <_> <_> <_>9 11 6 1 -1. <_>11 11 2 1 3. 0 0.0283357501029968 0.5117079019546509 6.1043637106195092e-004 <_> <_> <_>5 11 6 1 -1. <_>7 11 2 1 3. 0 6.6165882162749767e-003 0.4736349880695343 0.7011628150939941 <_> <_> <_>10 16 3 4 -1. <_>11 16 1 4 3. 0 8.0468766391277313e-003 0.5216417908668518 0.3282819986343384 <_> <_> <_>8 7 3 3 -1. <_>9 7 1 3 3. 0 -1.1193980462849140e-003 0.5809860825538635 0.4563739001750946 <_> <_> <_>2 12 16 8 -1. <_>2 16 16 4 2. 0 0.0132775902748108 0.5398362278938294 0.4103901088237763 <_> <_> <_>0 15 15 2 -1. <_>0 16 15 1 2. 0 4.8794739996083081e-004 0.4249286055564880 0.5410590767860413 <_> <_> <_>15 4 5 6 -1. <_>15 6 5 2 3. 0 0.0112431701272726 0.5269963741302490 0.3438215851783752 <_> <_> <_>9 5 2 4 -1. <_>10 5 1 4 2. 0 -8.9896668214350939e-004 0.5633075833320618 0.4456613063812256 <_> <_> <_>8 10 9 6 -1. <_>8 12 9 2 3. 0 6.6677159629762173e-003 0.5312889218330383 0.4362679123878479 <_> <_> <_>2 19 15 1 -1. <_>7 19 5 1 3. 0 0.0289472993463278 0.4701794981956482 0.6575797796249390 <_> <_> <_>10 16 3 4 -1. <_>11 16 1 4 3. 0 -0.0234000496566296 0. 0.5137398838996887 <_> <_> <_>0 15 20 4 -1. <_>0 17 20 2 2. 0 -0.0891170501708984 0.0237452797591686 0.4942430853843689 <_> <_> <_>10 16 3 4 -1. <_>11 16 1 4 3. 0 -0.0140546001493931 0.3127323091030121 0.5117511153221130 <_> <_> <_>7 16 3 4 -1. <_>8 16 1 4 3. 0 8.1239398568868637e-003 0.5009049177169800 0.2520025968551636 <_> <_> <_>9 16 3 3 -1. <_>9 17 3 1 3. 0 -4.9964650534093380e-003 0.6387143731117249 0.4927811920642853 <_> <_> <_>8 11 4 6 -1. <_>8 14 4 3 2. 0 3.1253970228135586e-003 0.5136849880218506 0.3680452108383179 <_> <_> <_>9 6 2 12 -1. <_>9 10 2 4 3. 0 6.7669642157852650e-003 0.5509843826293945 0.4363631904125214 <_> <_> <_>8 17 4 3 -1. <_>8 18 4 1 3. 0 -2.3711440153419971e-003 0.6162335276603699 0.4586946964263916 <_> <_> <_>9 18 8 2 -1. <_>13 18 4 1 2. <_>9 19 4 1 2. 0 -5.3522791713476181e-003 0.6185457706451416 0.4920490980148315 <_> <_> <_>1 18 8 2 -1. <_>1 19 8 1 2. 0 -0.0159688591957092 0.1382617950439453 0.4983252882957459 <_> <_> <_>13 5 6 15 -1. <_>15 5 2 15 3. 0 4.7676060348749161e-003 0.4688057899475098 0.5490046143531799 <_> <_> <_>9 8 2 2 -1. <_>9 9 2 1 2. 0 -2.4714691098779440e-003 0.2368514984846115 0.5003952980041504 <_> <_> <_>9 5 2 3 -1. <_>9 5 1 3 2. 0 -7.1033788844943047e-004 0.5856394171714783 0.4721533060073853 <_> <_> <_>1 5 6 15 -1. <_>3 5 2 15 3. 0 -0.1411755979061127 0.0869000628590584 0.4961591064929962 <_> <_> <_>4 1 14 8 -1. <_>11 1 7 4 2. <_>4 5 7 4 2. 0 0.1065180972218514 0.5138837099075317 0.1741005033254623 <_> <_> <_>2 4 4 16 -1. <_>2 4 2 8 2. <_>4 12 2 8 2. 0 -0.0527447499334812 0.7353636026382446 0.4772881865501404 <_> <_> <_>12 4 3 12 -1. <_>12 10 3 6 2. 0 -4.7431760467588902e-003 0.3884406089782715 0.5292701721191406 <_> <_> <_>4 5 10 12 -1. <_>4 5 5 6 2. <_>9 11 5 6 2. 0 9.9676765967160463e-004 0.5223492980003357 0.4003424048423767 <_> <_> <_>9 14 2 3 -1. <_>9 15 2 1 3. 0 8.0284131690859795e-003 0.4959106147289276 0.7212964296340942 <_> <_> <_>5 4 2 3 -1. <_>5 5 2 1 3. 0 8.6025858763605356e-004 0.4444884061813355 0.5538476109504700 <_> <_> <_>12 2 4 10 -1. <_>14 2 2 5 2. <_>12 7 2 5 2. 0 9.3191501218825579e-004 0.5398371219635010 0.4163244068622589 <_> <_> <_>6 4 7 3 -1. <_>6 5 7 1 3. 0 -2.5082060601562262e-003 0.5854265093803406 0.4562500119209290 <_> <_> <_>2 0 18 2 -1. <_>11 0 9 1 2. <_>2 1 9 1 2. 0 -2.1378761157393456e-003 0.4608069062232971 0.5280259251594544 <_> <_> <_>0 0 18 2 -1. <_>0 0 9 1 2. <_>9 1 9 1 2. 0 -2.1546049974858761e-003 0.3791126906871796 0.5255997180938721 <_> <_> <_>13 13 4 6 -1. <_>15 13 2 3 2. <_>13 16 2 3 2. 0 -7.6214009895920753e-003 0.5998609066009522 0.4952073991298676 <_> <_> <_>3 13 4 6 -1. <_>3 13 2 3 2. <_>5 16 2 3 2. 0 2.2055360022932291e-003 0.4484206140041351 0.5588530898094177 <_> <_> <_>10 12 2 6 -1. <_>10 15 2 3 2. 0 1.2586950324475765e-003 0.5450747013092041 0.4423840939998627 <_> <_> <_>5 9 10 10 -1. <_>5 9 5 5 2. <_>10 14 5 5 2. 0 -5.0926720723509789e-003 0.4118275046348572 0.5263035893440247 <_> <_> <_>11 4 4 2 -1. <_>13 4 2 1 2. <_>11 5 2 1 2. 0 -2.5095739401876926e-003 0.5787907838821411 0.4998494982719421 <_> <_> <_>7 12 6 8 -1. <_>10 12 3 8 2. 0 -0.0773275569081306 0.8397865891456604 0.4811120033264160 <_> <_> <_>12 2 4 10 -1. <_>14 2 2 5 2. <_>12 7 2 5 2. 0 -0.0414858199656010 0.2408611029386520 0.5176993012428284 <_> <_> <_>8 11 2 1 -1. <_>9 11 1 1 2. 0 1.0355669655837119e-004 0.4355360865592957 0.5417054295539856 <_> <_> <_>10 5 1 12 -1. <_>10 9 1 4 3. 0 1.3255809899419546e-003 0.5453971028327942 0.4894095063209534 <_> <_> <_>0 11 6 9 -1. <_>3 11 3 9 2. 0 -8.0598732456564903e-003 0.5771024227142334 0.4577918946743012 <_> <_> <_>12 2 4 10 -1. <_>14 2 2 5 2. <_>12 7 2 5 2. 0 0.0190586205571890 0.5169867873191834 0.3400475084781647 <_> <_> <_>4 2 4 10 -1. <_>4 2 2 5 2. <_>6 7 2 5 2. 0 -0.0350578911602497 0.2203243970870972 0.5000503063201904 <_> <_> <_>11 4 4 2 -1. <_>13 4 2 1 2. <_>11 5 2 1 2. 0 5.7296059094369411e-003 0.5043408274650574 0.6597570776939392 <_> <_> <_>0 14 6 3 -1. <_>0 15 6 1 3. 0 -0.0116483299061656 0.2186284959316254 0.4996652901172638 <_> <_> <_>11 4 4 2 -1. <_>13 4 2 1 2. <_>11 5 2 1 2. 0 1.4544479781761765e-003 0.5007681846618652 0.5503727793693543 <_> <_> <_>6 1 3 2 -1. <_>7 1 1 2 3. 0 -2.5030909455381334e-004 0.4129841029644013 0.5241670012474060 <_> <_> <_>11 4 4 2 -1. <_>13 4 2 1 2. <_>11 5 2 1 2. 0 -8.2907272735610604e-004 0.5412868261337280 0.4974496066570282 <_> <_> <_>5 4 4 2 -1. <_>5 4 2 1 2. <_>7 5 2 1 2. 0 1.0862209601327777e-003 0.4605529904365540 0.5879228711128235 <_> <_> <_>13 0 2 12 -1. <_>14 0 1 6 2. <_>13 6 1 6 2. 0 2.0000500080641359e-004 0.5278854966163635 0.4705209136009216 <_> <_> <_>6 0 3 10 -1. <_>7 0 1 10 3. 0 2.9212920926511288e-003 0.5129609704017639 0.3755536973476410 <_> <_> <_>3 0 17 8 -1. <_>3 4 17 4 2. 0 0.0253874007612467 0.4822691977024078 0.5790768265724182 <_> <_> <_>0 4 20 4 -1. <_>0 6 20 2 2. 0 -3.1968469265848398e-003 0.5248395204544067 0.3962840139865875 87.6960296630859380 17 -1 <_> <_> <_> <_>0 3 8 2 -1. <_>4 3 4 2 2. 0 5.8031738735735416e-003 0.3498983979225159 0.5961983203887940 <_> <_> <_>8 11 4 3 -1. <_>8 12 4 1 3. 0 -9.0003069490194321e-003 0.6816636919975281 0.4478552043437958 <_> <_> <_>5 7 6 4 -1. <_>5 7 3 2 2. <_>8 9 3 2 2. 0 -1.1549659539014101e-003 0.5585706233978272 0.3578251004219055 <_> <_> <_>8 3 4 9 -1. <_>8 6 4 3 3. 0 -1.1069850297644734e-003 0.5365036129951477 0.3050428032875061 <_> <_> <_>8 15 1 4 -1. <_>8 17 1 2 2. 0 1.0308309720130637e-004 0.3639095127582550 0.5344635844230652 <_> <_> <_>4 5 12 7 -1. <_>8 5 4 7 3. 0 -5.0984839908778667e-003 0.2859157025814056 0.5504264831542969 <_> <_> <_>4 2 4 10 -1. <_>4 2 2 5 2. <_>6 7 2 5 2. 0 8.2572200335562229e-004 0.5236523747444153 0.3476041853427887 <_> <_> <_>3 0 17 2 -1. <_>3 1 17 1 2. 0 9.9783325567841530e-003 0.4750322103500366 0.6219646930694580 <_> <_> <_>2 2 16 15 -1. <_>2 7 16 5 3. 0 -0.0374025292694569 0.3343375921249390 0.5278062820434570 <_> <_> <_>15 2 5 2 -1. <_>15 3 5 1 2. 0 4.8548257909715176e-003 0.5192180871963501 0.3700444102287293 <_> <_> <_>9 3 2 2 -1. <_>10 3 1 2 2. 0 -1.8664470408111811e-003 0.2929843962192535 0.5091944932937622 <_> <_> <_>4 5 16 15 -1. <_>4 10 16 5 3. 0 0.0168888904154301 0.3686845898628235 0.5431225895881653 <_> <_> <_>7 13 5 6 -1. <_>7 16 5 3 2. 0 -5.8372621424496174e-003 0.3632183969020844 0.5221335887908936 <_> <_> <_>10 7 3 2 -1. <_>11 7 1 2 3. 0 -1.4713739510625601e-003 0.5870683789253235 0.4700650870800018 <_> <_> <_>8 3 3 1 -1. <_>9 3 1 1 3. 0 -1.1522950371727347e-003 0.3195894956588745 0.5140954256057739 <_> <_> <_>9 16 3 3 -1. <_>9 17 3 1 3. 0 -4.2560300789773464e-003 0.6301859021186829 0.4814921021461487 <_> <_> <_>0 2 5 2 -1. <_>0 3 5 1 2. 0 -6.7378291860222816e-003 0.1977048069238663 0.5025808215141296 <_> <_> <_>12 5 4 3 -1. <_>12 6 4 1 3. 0 0.0113826701417565 0.4954132139682770 0.6867045760154724 <_> <_> <_>1 7 12 1 -1. <_>5 7 4 1 3. 0 5.1794708706438541e-003 0.5164427757263184 0.3350647985935211 <_> <_> <_>7 5 6 14 -1. <_>7 12 6 7 2. 0 -0.1174378991127014 0.2315246015787125 0.5234413743019104 <_> <_> <_>0 0 8 10 -1. <_>0 0 4 5 2. <_>4 5 4 5 2. 0 0.0287034492939711 0.4664297103881836 0.6722521185874939 <_> <_> <_>9 1 3 2 -1. <_>10 1 1 2 3. 0 4.8231030814349651e-003 0.5220875144004822 0.2723532915115356 <_> <_> <_>8 1 3 2 -1. <_>9 1 1 2 3. 0 2.6798530016094446e-003 0.5079277157783508 0.2906948924064636 <_> <_> <_>12 4 3 3 -1. <_>12 5 3 1 3. 0 8.0504082143306732e-003 0.4885950982570648 0.6395021080970764 <_> <_> <_>7 4 6 16 -1. <_>7 12 6 8 2. 0 4.8054959625005722e-003 0.5197256803512573 0.3656663894653320 <_> <_> <_>12 4 3 3 -1. <_>12 5 3 1 3. 0 -2.2420159075409174e-003 0.6153467893600464 0.4763701856136322 <_> <_> <_>2 3 2 6 -1. <_>2 5 2 2 3. 0 -0.0137577103450894 0.2637344896793366 0.5030903220176697 <_> <_> <_>14 2 6 9 -1. <_>14 5 6 3 3. 0 -0.1033829972147942 0.2287521958351135 0.5182461142539978 <_> <_> <_>5 4 3 3 -1. <_>5 5 3 1 3. 0 -9.4432085752487183e-003 0.6953303813934326 0.4694949090480804 <_> <_> <_>9 17 3 2 -1. <_>10 17 1 2 3. 0 8.0271181650459766e-004 0.5450655221939087 0.4268783926963806 <_> <_> <_>5 5 2 3 -1. <_>5 6 2 1 3. 0 -4.1945669800043106e-003 0.6091387867927551 0.4571642875671387 <_> <_> <_>13 11 3 6 -1. <_>13 13 3 2 3. 0 0.0109422104433179 0.5241063237190247 0.3284547030925751 <_> <_> <_>3 14 2 6 -1. <_>3 17 2 3 2. 0 -5.7841069065034389e-004 0.5387929081916809 0.4179368913173676 <_> <_> <_>14 3 6 2 -1. <_>14 4 6 1 2. 0 -2.0888620056211948e-003 0.4292691051959992 0.5301715731620789 <_> <_> <_>0 8 16 2 -1. <_>0 9 16 1 2. 0 3.2383969519287348e-003 0.3792347908020020 0.5220744013786316 <_> <_> <_>14 3 6 2 -1. <_>14 4 6 1 2. 0 4.9075027927756310e-003 0.5237283110618591 0.4126757979393005 <_> <_> <_>0 0 5 6 -1. <_>0 2 5 2 3. 0 -0.0322779417037964 0.1947655975818634 0.4994502067565918 <_> <_> <_>12 5 4 3 -1. <_>12 6 4 1 3. 0 -8.9711230248212814e-003 0.6011285185813904 0.4929032027721405 <_> <_> <_>4 11 3 6 -1. <_>4 13 3 2 3. 0 0.0153210898861289 0.5009753704071045 0.2039822041988373 <_> <_> <_>12 5 4 3 -1. <_>12 6 4 1 3. 0 2.0855569746345282e-003 0.4862189888954163 0.5721694827079773 <_> <_> <_>9 5 1 3 -1. <_>9 6 1 1 3. 0 5.0615021027624607e-003 0.5000218749046326 0.1801805943250656 <_> <_> <_>12 5 4 3 -1. <_>12 6 4 1 3. 0 -3.7174751050770283e-003 0.5530117154121399 0.4897592961788178 <_> <_> <_>6 6 8 12 -1. <_>6 12 8 6 2. 0 -0.0121705001220107 0.4178605973720551 0.5383723974227905 <_> <_> <_>12 5 4 3 -1. <_>12 6 4 1 3. 0 4.6248398721218109e-003 0.4997169971466065 0.5761327147483826 <_> <_> <_>5 12 9 2 -1. <_>8 12 3 2 3. 0 -2.1040429419372231e-004 0.5331807136535645 0.4097681045532227 <_> <_> <_>12 5 4 3 -1. <_>12 6 4 1 3. 0 -0.0146417804062366 0.5755925178527832 0.5051776170730591 <_> <_> <_>4 5 4 3 -1. <_>4 6 4 1 3. 0 3.3199489116668701e-003 0.4576976895332336 0.6031805872917175 <_> <_> <_>6 6 9 2 -1. <_>9 6 3 2 3. 0 3.7236879579722881e-003 0.4380396902561188 0.5415883064270020 <_> <_> <_>4 11 1 3 -1. <_>4 12 1 1 3. 0 8.2951161311939359e-004 0.5163031816482544 0.3702219128608704 <_> <_> <_>14 12 6 6 -1. <_>14 12 3 6 2. 0 -0.0114084901288152 0.6072946786880493 0.4862565100193024 <_> <_> <_>7 0 3 7 -1. <_>8 0 1 7 3. 0 -4.5320121571421623e-003 0.3292475938796997 0.5088962912559509 <_> <_> <_>9 8 3 3 -1. <_>10 8 1 3 3. 0 5.1276017911732197e-003 0.4829767942428589 0.6122708916664124 <_> <_> <_>8 8 3 3 -1. <_>9 8 1 3 3. 0 9.8583158105611801e-003 0.4660679996013641 0.6556177139282227 <_> <_> <_>5 10 11 3 -1. <_>5 11 11 1 3. 0 0.0369859188795090 0.5204849243164063 0.1690472066402435 <_> <_> <_>5 7 10 1 -1. <_>10 7 5 1 2. 0 4.6491161920130253e-003 0.5167322158813477 0.3725225031375885 <_> <_> <_>9 7 3 2 -1. <_>10 7 1 2 3. 0 -4.2664702050387859e-003 0.6406493186950684 0.4987342953681946 <_> <_> <_>8 7 3 2 -1. <_>9 7 1 2 3. 0 -4.7956590424291790e-004 0.5897293090820313 0.4464873969554901 <_> <_> <_>11 9 4 2 -1. <_>11 9 2 2 2. 0 3.6827160511165857e-003 0.5441560745239258 0.3472662866115570 <_> <_> <_>5 9 4 2 -1. <_>7 9 2 2 2. 0 -0.0100598800927401 0.2143162935972214 0.5004829764366150 <_> <_> <_>14 10 2 4 -1. <_>14 12 2 2 2. 0 -3.0361840617842972e-004 0.5386424064636231 0.4590323865413666 <_> <_> <_>7 7 3 2 -1. <_>8 7 1 2 3. 0 -1.4545479789376259e-003 0.5751184225082398 0.4497095048427582 <_> <_> <_>14 17 6 3 -1. <_>14 18 6 1 3. 0 1.6515209572389722e-003 0.5421937704086304 0.4238520860671997 <_> <_> <_>4 5 12 12 -1. <_>4 5 6 6 2. <_>10 11 6 6 2. 0 -7.8468639403581619e-003 0.4077920913696289 0.5258157253265381 <_> <_> <_>6 9 8 8 -1. <_>10 9 4 4 2. <_>6 13 4 4 2. 0 -5.1259850151836872e-003 0.4229275882244110 0.5479453206062317 <_> <_> <_>0 4 15 4 -1. <_>5 4 5 4 3. 0 -0.0368909612298012 0.6596375703811646 0.4674678146839142 <_> <_> <_>13 2 4 1 -1. <_>13 2 2 1 2. 0 2.4035639944486320e-004 0.4251135885715485 0.5573202967643738 <_> <_> <_>4 12 2 2 -1. <_>4 13 2 1 2. 0 -1.5150169929256663e-005 0.5259246826171875 0.4074114859104157 <_> <_> <_>8 13 4 3 -1. <_>8 14 4 1 3. 0 2.2108471021056175e-003 0.4671722948551178 0.5886352062225342 <_> <_> <_>9 13 2 3 -1. <_>9 14 2 1 3. 0 -1.1568620102480054e-003 0.5711066126823425 0.4487161934375763 <_> <_> <_>13 11 2 3 -1. <_>13 12 2 1 3. 0 4.9996292218565941e-003 0.5264198184013367 0.2898327112197876 <_> <_> <_>7 12 4 4 -1. <_>7 12 2 2 2. <_>9 14 2 2 2. 0 -1.4656189596280456e-003 0.3891738057136536 0.5197871923446655 <_> <_> <_>10 11 2 2 -1. <_>11 11 1 1 2. <_>10 12 1 1 2. 0 -1.1975039960816503e-003 0.5795872807502747 0.4927955865859985 <_> <_> <_>8 17 3 2 -1. <_>9 17 1 2 3. 0 -4.4954330660402775e-003 0.2377603054046631 0.5012555122375488 <_> <_> <_>10 11 2 2 -1. <_>11 11 1 1 2. <_>10 12 1 1 2. 0 1.4997160178609192e-004 0.4876626133918762 0.5617607831954956 <_> <_> <_>0 17 6 3 -1. <_>0 18 6 1 3. 0 2.6391509454697371e-003 0.5168088078498840 0.3765509128570557 <_> <_> <_>10 11 2 2 -1. <_>11 11 1 1 2. <_>10 12 1 1 2. 0 -2.9368131072260439e-004 0.5446649193763733 0.4874630868434906 <_> <_> <_>8 11 2 2 -1. <_>8 11 1 1 2. <_>9 12 1 1 2. 0 1.4211760135367513e-003 0.4687897861003876 0.6691331863403320 <_> <_> <_>12 5 8 4 -1. <_>12 5 4 4 2. 0 0.0794276371598244 0.5193443894386292 0.2732945978641510 <_> <_> <_>0 5 8 4 -1. <_>4 5 4 4 2. 0 0.0799375027418137 0.4971731007099152 0.1782083958387375 <_> <_> <_>13 2 4 1 -1. <_>13 2 2 1 2. 0 0.0110892597585917 0.5165994763374329 0.3209475874900818 <_> <_> <_>3 2 4 1 -1. <_>5 2 2 1 2. 0 1.6560709627810866e-004 0.4058471918106079 0.5307276248931885 <_> <_> <_>10 0 4 2 -1. <_>12 0 2 1 2. <_>10 1 2 1 2. 0 -5.3354292176663876e-003 0.3445056974887848 0.5158129930496216 <_> <_> <_>7 12 3 1 -1. <_>8 12 1 1 3. 0 1.1287260567769408e-003 0.4594863057136536 0.6075533032417297 <_> <_> <_>8 11 4 8 -1. <_>10 11 2 4 2. <_>8 15 2 4 2. 0 -0.0219692196696997 0.1680400967597961 0.5228595733642578 <_> <_> <_>9 9 2 2 -1. <_>9 10 2 1 2. 0 -2.1775320055894554e-004 0.3861596882343292 0.5215672850608826 <_> <_> <_>3 18 15 2 -1. <_>3 19 15 1 2. 0 2.0200149447191507e-004 0.5517979264259338 0.4363039135932922 <_> <_> <_>2 6 2 12 -1. <_>2 6 1 6 2. <_>3 12 1 6 2. 0 -0.0217331498861313 0.7999460101127625 0.4789851009845734 <_> <_> <_>9 8 2 3 -1. <_>9 9 2 1 3. 0 -8.4399932529777288e-004 0.4085975885391235 0.5374773144721985 <_> <_> <_>7 10 3 2 -1. <_>8 10 1 2 3. 0 -4.3895249837078154e-004 0.5470405220985413 0.4366143047809601 <_> <_> <_>11 11 3 1 -1. <_>12 11 1 1 3. 0 1.5092400135472417e-003 0.4988996982574463 0.5842149257659912 <_> <_> <_>6 11 3 1 -1. <_>7 11 1 1 3. 0 -3.5547839943319559e-003 0.6753690242767334 0.4721005856990814 <_> <_> <_>9 2 4 2 -1. <_>11 2 2 1 2. <_>9 3 2 1 2. 0 4.8191400128416717e-004 0.5415853857994080 0.4357109069824219 <_> <_> <_>4 12 2 3 -1. <_>4 13 2 1 3. 0 -6.0264398343861103e-003 0.2258509993553162 0.4991880953311920 <_> <_> <_>2 1 18 3 -1. <_>8 1 6 3 3. 0 -0.0116681400686502 0.6256554722785950 0.4927498996257782 <_> <_> <_>5 1 4 14 -1. <_>7 1 2 14 2. 0 -2.8718370012938976e-003 0.3947784900665283 0.5245801806449890 <_> <_> <_>8 16 12 3 -1. <_>8 16 6 3 2. 0 0.0170511696487665 0.4752511084079742 0.5794224143028259 <_> <_> <_>1 17 18 3 -1. <_>7 17 6 3 3. 0 -0.0133520802482963 0.6041104793548584 0.4544535875320435 <_> <_> <_>9 14 2 6 -1. <_>9 17 2 3 2. 0 -3.9301801007241011e-004 0.4258275926113129 0.5544905066490173 <_> <_> <_>9 12 1 8 -1. <_>9 16 1 4 2. 0 3.0483349692076445e-003 0.5233420133590698 0.3780272901058197 <_> <_> <_>9 14 2 3 -1. <_>9 15 2 1 3. 0 -4.3579288758337498e-003 0.6371889114379883 0.4838674068450928 <_> <_> <_>9 6 2 12 -1. <_>9 10 2 4 3. 0 5.6661018170416355e-003 0.5374705791473389 0.4163666069507599 <_> <_> <_>12 9 3 3 -1. <_>12 10 3 1 3. 0 6.0677339206449687e-005 0.4638795852661133 0.5311625003814697 <_> <_> <_>0 1 4 8 -1. <_>2 1 2 8 2. 0 0.0367381609976292 0.4688656032085419 0.6466524004936218 <_> <_> <_>9 1 6 2 -1. <_>12 1 3 1 2. <_>9 2 3 1 2. 0 8.6528137326240540e-003 0.5204318761825562 0.2188657969236374 <_> <_> <_>1 3 12 14 -1. <_>1 10 12 7 2. 0 -0.1537135988473892 0.1630371958017349 0.4958840012550354 <_> <_> <_>8 12 4 2 -1. <_>10 12 2 1 2. <_>8 13 2 1 2. 0 -4.1560421232134104e-004 0.5774459242820740 0.4696458876132965 <_> <_> <_>1 9 10 2 -1. <_>1 9 5 1 2. <_>6 10 5 1 2. 0 -1.2640169588848948e-003 0.3977175951004028 0.5217198133468628 <_> <_> <_>8 15 4 3 -1. <_>8 16 4 1 3. 0 -3.5473341122269630e-003 0.6046528220176697 0.4808315038681030 <_> <_> <_>6 8 8 3 -1. <_>6 9 8 1 3. 0 3.0019069527043030e-005 0.3996723890304565 0.5228201150894165 <_> <_> <_>9 15 5 3 -1. <_>9 16 5 1 3. 0 1.3113019522279501e-003 0.4712158143520355 0.5765997767448425 <_> <_> <_>8 7 4 3 -1. <_>8 8 4 1 3. 0 -1.3374709524214268e-003 0.4109584987163544 0.5253170132637024 <_> <_> <_>7 7 6 2 -1. <_>7 8 6 1 2. 0 0.0208767093718052 0.5202993750572205 0.1757981926202774 <_> <_> <_>5 7 8 2 -1. <_>5 7 4 1 2. <_>9 8 4 1 2. 0 -7.5497948564589024e-003 0.6566609740257263 0.4694975018501282 <_> <_> <_>12 9 3 3 -1. <_>12 10 3 1 3. 0 0.0241885501891375 0.5128673911094666 0.3370220959186554 <_> <_> <_>4 7 4 2 -1. <_>4 8 4 1 2. 0 -2.9358828905969858e-003 0.6580786705017090 0.4694541096687317 <_> <_> <_>14 2 6 9 -1. <_>14 5 6 3 3. 0 0.0575579293072224 0.5146445035934448 0.2775259912014008 <_> <_> <_>4 9 3 3 -1. <_>5 9 1 3 3. 0 -1.1343370424583554e-003 0.3836601972579956 0.5192667245864868 <_> <_> <_>12 9 3 3 -1. <_>12 10 3 1 3. 0 0.0168169997632504 0.5085592865943909 0.6177260875701904 <_> <_> <_>0 2 6 9 -1. <_>0 5 6 3 3. 0 5.0535178743302822e-003 0.5138763189315796 0.3684791922569275 <_> <_> <_>17 3 3 6 -1. <_>18 3 1 6 3. 0 -4.5874710194766521e-003 0.5989655256271362 0.4835202097892761 <_> <_> <_>0 3 3 6 -1. <_>1 3 1 6 3. 0 1.6882460331544280e-003 0.4509486854076386 0.5723056793212891 <_> <_> <_>17 14 1 2 -1. <_>17 15 1 1 2. 0 -1.6554000321775675e-003 0.3496770858764648 0.5243319272994995 <_> <_> <_>4 9 4 3 -1. <_>6 9 2 3 2. 0 -0.0193738006055355 0.1120536997914314 0.4968712925910950 <_> <_> <_>12 9 3 3 -1. <_>12 10 3 1 3. 0 0.0103744501248002 0.5148196816444397 0.4395213127136231 <_> <_> <_>5 9 3 3 -1. <_>5 10 3 1 3. 0 1.4973050565458834e-004 0.4084999859333038 0.5269886851310730 <_> <_> <_>9 5 6 8 -1. <_>12 5 3 4 2. <_>9 9 3 4 2. 0 -0.0429819300770760 0.6394104957580566 0.5018504261970520 <_> <_> <_>5 5 6 8 -1. <_>5 5 3 4 2. <_>8 9 3 4 2. 0 8.3065936341881752e-003 0.4707553982734680 0.6698353290557861 <_> <_> <_>16 1 4 6 -1. <_>16 4 4 3 2. 0 -4.1285790503025055e-003 0.4541369080543518 0.5323647260665894 <_> <_> <_>1 0 6 20 -1. <_>3 0 2 20 3. 0 1.7399420030415058e-003 0.4333961904048920 0.5439866185188294 <_> <_> <_>12 11 3 2 -1. <_>13 11 1 2 3. 0 1.1739750334527344e-004 0.4579687118530273 0.5543426275253296 <_> <_> <_>5 11 3 2 -1. <_>6 11 1 2 3. 0 1.8585780344437808e-004 0.4324643909931183 0.5426754951477051 <_> <_> <_>9 4 6 1 -1. <_>11 4 2 1 3. 0 5.5587692186236382e-003 0.5257220864295960 0.3550611138343811 <_> <_> <_>0 0 8 3 -1. <_>4 0 4 3 2. 0 -7.9851560294628143e-003 0.6043018102645874 0.4630635976791382 <_> <_> <_>15 0 2 5 -1. <_>15 0 1 5 2. 0 6.0594122624024749e-004 0.4598254859447479 0.5533195137977600 <_> <_> <_>4 1 3 2 -1. <_>5 1 1 2 3. 0 -2.2983040253166109e-004 0.4130752086639404 0.5322461128234863 <_> <_> <_>7 0 6 15 -1. <_>9 0 2 15 3. 0 4.3740210821852088e-004 0.4043039977550507 0.5409289002418518 <_> <_> <_>6 11 3 1 -1. <_>7 11 1 1 3. 0 2.9482020181603730e-004 0.4494963884353638 0.5628852248191834 <_> <_> <_>12 0 3 4 -1. <_>13 0 1 4 3. 0 0.0103126596659422 0.5177510976791382 0.2704316973686218 <_> <_> <_>5 4 6 1 -1. <_>7 4 2 1 3. 0 -7.7241109684109688e-003 0.1988019049167633 0.4980553984642029 <_> <_> <_>12 7 3 2 -1. <_>12 8 3 1 2. 0 -4.6797208487987518e-003 0.6644750237464905 0.5018296241760254 <_> <_> <_>0 1 4 6 -1. <_>0 4 4 3 2. 0 -5.0755459815263748e-003 0.3898304998874664 0.5185269117355347 <_> <_> <_>12 7 3 2 -1. <_>12 8 3 1 2. 0 2.2479740437120199e-003 0.4801808893680573 0.5660336017608643 <_> <_> <_>2 16 3 3 -1. <_>2 17 3 1 3. 0 8.3327008178457618e-004 0.5210919976234436 0.3957188129425049 <_> <_> <_>13 8 6 10 -1. <_>16 8 3 5 2. <_>13 13 3 5 2. 0 -0.0412793308496475 0.6154541969299316 0.5007054209709168 <_> <_> <_>0 9 5 2 -1. <_>0 10 5 1 2. 0 -5.0930189900100231e-004 0.3975942134857178 0.5228403806686401 <_> <_> <_>12 11 2 2 -1. <_>13 11 1 1 2. <_>12 12 1 1 2. 0 1.2568780221045017e-003 0.4979138076305389 0.5939183235168457 <_> <_> <_>3 15 3 3 -1. <_>3 16 3 1 3. 0 8.0048497766256332e-003 0.4984497129917145 0.1633366048336029 <_> <_> <_>12 7 3 2 -1. <_>12 8 3 1 2. 0 -1.1879300000146031e-003 0.5904964804649353 0.4942624866962433 <_> <_> <_>5 7 3 2 -1. <_>5 8 3 1 2. 0 6.1948952497914433e-004 0.4199557900428772 0.5328726172447205 <_> <_> <_>9 5 9 9 -1. <_>9 8 9 3 3. 0 6.6829859279096127e-003 0.5418602824211121 0.4905889034271240 <_> <_> <_>5 0 3 7 -1. <_>6 0 1 7 3. 0 -3.7062340416014194e-003 0.3725939095020294 0.5138000249862671 <_> <_> <_>5 2 12 5 -1. <_>9 2 4 5 3. 0 -0.0397394113242626 0.6478961110115051 0.5050346851348877 <_> <_> <_>6 11 2 2 -1. <_>6 11 1 1 2. <_>7 12 1 1 2. 0 1.4085009461268783e-003 0.4682339131832123 0.6377884149551392 <_> <_> <_>15 15 3 2 -1. <_>15 16 3 1 2. 0 3.9322688826359808e-004 0.5458530187606812 0.4150482118129730 <_> <_> <_>2 15 3 2 -1. <_>2 16 3 1 2. 0 -1.8979819724336267e-003 0.3690159916877747 0.5149704217910767 <_> <_> <_>14 12 6 8 -1. <_>17 12 3 4 2. <_>14 16 3 4 2. 0 -0.0139704402536154 0.6050562858581543 0.4811357855796814 <_> <_> <_>2 8 15 6 -1. <_>7 8 5 6 3. 0 -0.1010081991553307 0.2017080038785934 0.4992361962795258 <_> <_> <_>2 2 18 17 -1. <_>8 2 6 17 3. 0 -0.0173469204455614 0.5713148713111877 0.4899486005306244 <_> <_> <_>5 1 4 1 -1. <_>7 1 2 1 2. 0 1.5619759506080300e-004 0.4215388894081116 0.5392642021179199 <_> <_> <_>5 2 12 5 -1. <_>9 2 4 5 3. 0 0.1343892961740494 0.5136151909828186 0.3767612874507904 <_> <_> <_>3 2 12 5 -1. <_>7 2 4 5 3. 0 -0.0245822407305241 0.7027357816696167 0.4747906923294067 <_> <_> <_>4 9 12 4 -1. <_>10 9 6 2 2. <_>4 11 6 2 2. 0 -3.8553720805794001e-003 0.4317409098148346 0.5427716970443726 <_> <_> <_>5 15 6 2 -1. <_>5 15 3 1 2. <_>8 16 3 1 2. 0 -2.3165249731391668e-003 0.5942698717117310 0.4618647992610931 <_> <_> <_>10 14 2 3 -1. <_>10 15 2 1 3. 0 -4.8518120311200619e-003 0.6191568970680237 0.4884895086288452 <_> <_> <_>0 13 20 2 -1. <_>0 13 10 1 2. <_>10 14 10 1 2. 0 2.4699938949197531e-003 0.5256664752960205 0.4017199873924255 <_> <_> <_>4 9 12 8 -1. <_>10 9 6 4 2. <_>4 13 6 4 2. 0 0.0454969592392445 0.5237867832183838 0.2685773968696594 <_> <_> <_>8 13 3 6 -1. <_>8 16 3 3 2. 0 -0.0203195996582508 0.2130445986986160 0.4979738891124725 <_> <_> <_>10 12 2 2 -1. <_>10 13 2 1 2. 0 2.6994998916052282e-004 0.4814041852951050 0.5543122291564941 <_> <_> <_>9 12 2 2 -1. <_>9 12 1 1 2. <_>10 13 1 1 2. 0 -1.8232699949294329e-003 0.6482579708099365 0.4709989130496979 <_> <_> <_>4 11 14 4 -1. <_>11 11 7 2 2. <_>4 13 7 2 2. 0 -6.3015790656208992e-003 0.4581927955150604 0.5306236147880554 <_> <_> <_>8 5 4 2 -1. <_>8 6 4 1 2. 0 -2.4139499873854220e-004 0.5232086777687073 0.4051763117313385 <_> <_> <_>10 10 6 3 -1. <_>12 10 2 3 3. 0 -1.0330369696021080e-003 0.5556201934814453 0.4789193868637085 <_> <_> <_>2 14 1 2 -1. <_>2 15 1 1 2. 0 1.8041160365100950e-004 0.5229442715644836 0.4011810123920441 <_> <_> <_>13 8 6 12 -1. <_>16 8 3 6 2. <_>13 14 3 6 2. 0 -0.0614078603684902 0.6298682093620300 0.5010703206062317 <_> <_> <_>1 8 6 12 -1. <_>1 8 3 6 2. <_>4 14 3 6 2. 0 -0.0695439130067825 0.7228280901908875 0.4773184061050415 <_> <_> <_>10 0 6 10 -1. <_>12 0 2 10 3. 0 -0.0705426633358002 0.2269513010978699 0.5182529091835022 <_> <_> <_>5 11 8 4 -1. <_>5 11 4 2 2. <_>9 13 4 2 2. 0 2.4423799477517605e-003 0.5237097144126892 0.4098151028156281 <_> <_> <_>10 16 8 4 -1. <_>14 16 4 2 2. <_>10 18 4 2 2. 0 1.5494349645450711e-003 0.4773750901222229 0.5468043088912964 <_> <_> <_>7 7 6 6 -1. <_>9 7 2 6 3. 0 -0.0239142198115587 0.7146975994110107 0.4783824980258942 <_> <_> <_>10 2 4 10 -1. <_>10 2 2 10 2. 0 -0.0124536901712418 0.2635296881198883 0.5241122841835022 <_> <_> <_>6 1 4 9 -1. <_>8 1 2 9 2. 0 -2.0760179904755205e-004 0.3623757064342499 0.5113608837127686 <_> <_> <_>12 19 2 1 -1. <_>12 19 1 1 2. 0 2.9781080229440704e-005 0.4705932140350342 0.5432801842689514 90.2533493041992190 18 -1 <_> <_> <_> <_>1 2 4 9 -1. <_>3 2 2 9 2. 0 0.0117727499455214 0.3860518932342529 0.6421167254447937 <_> <_> <_>7 5 6 4 -1. <_>9 5 2 4 3. 0 0.0270375702530146 0.4385654926300049 0.6754038929939270 <_> <_> <_>9 4 2 4 -1. <_>9 6 2 2 2. 0 -3.6419500247575343e-005 0.5487101078033447 0.3423315882682800 <_> <_> <_>14 5 2 8 -1. <_>14 9 2 4 2. 0 1.9995409529656172e-003 0.3230532109737396 0.5400317907333374 <_> <_> <_>7 6 5 12 -1. <_>7 12 5 6 2. 0 4.5278300531208515e-003 0.5091639757156372 0.2935043871402741 <_> <_> <_>14 6 2 6 -1. <_>14 9 2 3 2. 0 4.7890920541249216e-004 0.4178153872489929 0.5344064235687256 <_> <_> <_>4 6 2 6 -1. <_>4 9 2 3 2. 0 1.1720920447260141e-003 0.2899182140827179 0.5132070779800415 <_> <_> <_>8 15 10 4 -1. <_>13 15 5 2 2. <_>8 17 5 2 2. 0 9.5305702416226268e-004 0.4280124902725220 0.5560845136642456 <_> <_> <_>6 18 2 2 -1. <_>7 18 1 2 2. 0 1.5099150004971307e-005 0.4044871926307678 0.5404760241508484 <_> <_> <_>11 3 6 2 -1. <_>11 4 6 1 2. 0 -6.0817901976406574e-004 0.4271768927574158 0.5503466129302979 <_> <_> <_>2 0 16 6 -1. <_>2 2 16 2 3. 0 3.3224520739167929e-003 0.3962723910808563 0.5369734764099121 <_> <_> <_>11 3 6 2 -1. <_>11 4 6 1 2. 0 -1.1037490330636501e-003 0.4727177917957306 0.5237749814987183 <_> <_> <_>4 11 10 3 -1. <_>4 12 10 1 3. 0 -1.4350269921123981e-003 0.5603008270263672 0.4223509132862091 <_> <_> <_>11 3 6 2 -1. <_>11 4 6 1 2. 0 2.0767399109899998e-003 0.5225917100906372 0.4732725918292999 <_> <_> <_>3 3 6 2 -1. <_>3 4 6 1 2. 0 -1.6412809782195836e-004 0.3999075889587402 0.5432739853858948 <_> <_> <_>16 0 4 7 -1. <_>16 0 2 7 2. 0 8.8302437216043472e-003 0.4678385853767395 0.6027327179908752 <_> <_> <_>0 14 9 6 -1. <_>0 16 9 2 3. 0 -0.0105520701035857 0.3493967056274414 0.5213974714279175 <_> <_> <_>9 16 3 3 -1. <_>9 17 3 1 3. 0 -2.2731600329279900e-003 0.6185818910598755 0.4749062955379486 <_> <_> <_>4 6 6 2 -1. <_>6 6 2 2 3. 0 -8.4786332445219159e-004 0.5285341143608093 0.3843482136726379 <_> <_> <_>15 11 1 3 -1. <_>15 12 1 1 3. 0 1.2081359745934606e-003 0.5360640883445740 0.3447335958480835 <_> <_> <_>5 5 2 3 -1. <_>5 6 2 1 3. 0 2.6512730401009321e-003 0.4558292031288147 0.6193962097167969 <_> <_> <_>10 9 2 2 -1. <_>10 10 2 1 2. 0 -1.1012479662895203e-003 0.3680230081081390 0.5327628254890442 <_> <_> <_>3 1 4 3 -1. <_>5 1 2 3 2. 0 4.9561518244445324e-004 0.3960595130920410 0.5274940729141235 <_> <_> <_>16 0 4 7 -1. <_>16 0 2 7 2. 0 -0.0439017713069916 0.7020444869995117 0.4992839097976685 <_> <_> <_>0 0 20 1 -1. <_>10 0 10 1 2. 0 0.0346903502941132 0.5049164295196533 0.2766602933406830 <_> <_> <_>15 11 1 3 -1. <_>15 12 1 1 3. 0 -2.7442190330475569e-003 0.2672632932662964 0.5274971127510071 <_> <_> <_>0 4 3 4 -1. <_>1 4 1 4 3. 0 3.3316588960587978e-003 0.4579482972621918 0.6001101732254028 <_> <_> <_>16 3 3 6 -1. <_>16 5 3 2 3. 0 -0.0200445707887411 0.3171594142913818 0.5235717892646790 <_> <_> <_>1 3 3 6 -1. <_>1 5 3 2 3. 0 1.3492030557245016e-003 0.5265362858772278 0.4034324884414673 <_> <_> <_>6 2 12 6 -1. <_>12 2 6 3 2. <_>6 5 6 3 2. 0 2.9702018946409225e-003 0.5332456827163696 0.4571984112262726 <_> <_> <_>8 10 4 3 -1. <_>8 11 4 1 3. 0 6.3039981760084629e-003 0.4593310952186585 0.6034635901451111 <_> <_> <_>4 2 14 6 -1. <_>11 2 7 3 2. <_>4 5 7 3 2. 0 -0.0129365902394056 0.4437963962554932 0.5372971296310425 <_> <_> <_>9 11 2 3 -1. <_>9 12 2 1 3. 0 4.0148729458451271e-003 0.4680323898792267 0.6437833905220032 <_> <_> <_>15 13 2 3 -1. <_>15 14 2 1 3. 0 -2.6401679497212172e-003 0.3709631860256195 0.5314332842826843 <_> <_> <_>8 12 4 3 -1. <_>8 13 4 1 3. 0 0.0139184398576617 0.4723555147647858 0.7130808830261231 <_> <_> <_>15 11 1 3 -1. <_>15 12 1 1 3. 0 -4.5087869511917233e-004 0.4492394030094147 0.5370404124259949 <_> <_> <_>7 13 5 2 -1. <_>7 14 5 1 2. 0 2.5384349282830954e-004 0.4406864047050476 0.5514402985572815 <_> <_> <_>7 12 6 3 -1. <_>7 13 6 1 3. 0 2.2710000630468130e-003 0.4682416915893555 0.5967984199523926 <_> <_> <_>5 11 4 4 -1. <_>5 13 4 2 2. 0 2.4120779708027840e-003 0.5079392194747925 0.3018598854541779 <_> <_> <_>11 4 3 3 -1. <_>12 4 1 3 3. 0 -3.6025670851813629e-005 0.5601037144660950 0.4471096992492676 <_> <_> <_>6 4 3 3 -1. <_>7 4 1 3 3. 0 -7.4905529618263245e-003 0.2207535058259964 0.4989944100379944 <_> <_> <_>16 5 3 6 -1. <_>17 5 1 6 3. 0 -0.0175131205469370 0.6531215906143189 0.5017648935317993 <_> <_> <_>3 6 12 7 -1. <_>7 6 4 7 3. 0 0.1428163051605225 0.4967963099479675 0.1482062041759491 <_> <_> <_>16 5 3 6 -1. <_>17 5 1 6 3. 0 5.5345268920063972e-003 0.4898946881294251 0.5954223871231079 <_> <_> <_>3 13 2 3 -1. <_>3 14 2 1 3. 0 -9.6323591424152255e-004 0.3927116990089417 0.5196074247360230 <_> <_> <_>16 5 3 6 -1. <_>17 5 1 6 3. 0 -2.0370010752230883e-003 0.5613325238227844 0.4884858131408691 <_> <_> <_>1 5 3 6 -1. <_>2 5 1 6 3. 0 1.6614829655736685e-003 0.4472880065441132 0.5578880906105042 <_> <_> <_>1 9 18 1 -1. <_>7 9 6 1 3. 0 -3.1188090797513723e-003 0.3840532898902893 0.5397477746009827 <_> <_> <_>0 9 8 7 -1. <_>4 9 4 7 2. 0 -6.4000617712736130e-003 0.5843983888626099 0.4533218145370483 <_> <_> <_>12 11 8 2 -1. <_>12 12 8 1 2. 0 3.1319601112045348e-004 0.5439221858978272 0.4234727919101715 <_> <_> <_>0 11 8 2 -1. <_>0 12 8 1 2. 0 -0.0182220991700888 0.1288464963436127 0.4958404898643494 <_> <_> <_>9 13 2 3 -1. <_>9 14 2 1 3. 0 8.7969247251749039e-003 0.4951297938823700 0.7153480052947998 <_> <_> <_>4 10 12 4 -1. <_>4 10 6 2 2. <_>10 12 6 2 2. 0 -4.2395070195198059e-003 0.3946599960327148 0.5194936990737915 <_> <_> <_>9 3 3 7 -1. <_>10 3 1 7 3. 0 9.7086271271109581e-003 0.4897503852844238 0.6064900159835815 <_> <_> <_>7 2 3 5 -1. <_>8 2 1 5 3. 0 -3.9934171363711357e-003 0.3245440125465393 0.5060828924179077 <_> <_> <_>9 12 4 6 -1. <_>11 12 2 3 2. <_>9 15 2 3 2. 0 -0.0167850591242313 0.1581953018903732 0.5203778743743897 <_> <_> <_>8 7 3 6 -1. <_>9 7 1 6 3. 0 0.0182720907032490 0.4680935144424439 0.6626979112625122 <_> <_> <_>15 4 4 2 -1. <_>15 5 4 1 2. 0 5.6872838176786900e-003 0.5211697816848755 0.3512184917926788 <_> <_> <_>8 7 3 3 -1. <_>9 7 1 3 3. 0 -1.0739039862528443e-003 0.5768386125564575 0.4529845118522644 <_> <_> <_>14 2 6 4 -1. <_>14 4 6 2 2. 0 -3.7093870341777802e-003 0.4507763087749481 0.5313581228256226 <_> <_> <_>7 16 6 1 -1. <_>9 16 2 1 3. 0 -2.1110709349159151e-004 0.5460820198059082 0.4333376884460449 <_> <_> <_>15 13 2 3 -1. <_>15 14 2 1 3. 0 1.0670139454305172e-003 0.5371856093406677 0.4078390896320343 <_> <_> <_>8 7 3 10 -1. <_>9 7 1 10 3. 0 3.5943021066486835e-003 0.4471287131309509 0.5643836259841919 <_> <_> <_>11 10 2 6 -1. <_>11 12 2 2 3. 0 -5.1776031032204628e-003 0.4499393105506897 0.5280330181121826 <_> <_> <_>6 10 4 1 -1. <_>8 10 2 1 2. 0 -2.5414369883947074e-004 0.5516173243522644 0.4407708048820496 <_> <_> <_>10 9 2 2 -1. <_>10 10 2 1 2. 0 6.3522560521960258e-003 0.5194190144538879 0.2465227991342545 <_> <_> <_>8 9 2 2 -1. <_>8 10 2 1 2. 0 -4.4205080484971404e-004 0.3830705881118774 0.5139682292938232 <_> <_> <_>12 7 2 2 -1. <_>13 7 1 1 2. <_>12 8 1 1 2. 0 7.4488727841526270e-004 0.4891090989112854 0.5974786877632141 <_> <_> <_>5 7 2 2 -1. <_>5 7 1 1 2. <_>6 8 1 1 2. 0 -3.5116379149258137e-003 0.7413681745529175 0.4768764972686768 <_> <_> <_>13 0 3 14 -1. <_>14 0 1 14 3. 0 -0.0125409103929996 0.3648819029331207 0.5252826809883118 <_> <_> <_>4 0 3 14 -1. <_>5 0 1 14 3. 0 9.4931852072477341e-003 0.5100492835044861 0.3629586994647980 <_> <_> <_>13 4 3 14 -1. <_>14 4 1 14 3. 0 0.0129611501470208 0.5232442021369934 0.4333561062812805 <_> <_> <_>9 14 2 3 -1. <_>9 15 2 1 3. 0 4.7209449112415314e-003 0.4648149013519287 0.6331052780151367 <_> <_> <_>8 14 4 3 -1. <_>8 15 4 1 3. 0 -2.3119079414755106e-003 0.5930309891700745 0.4531058073043823 <_> <_> <_>4 2 3 16 -1. <_>5 2 1 16 3. 0 -2.8262299019843340e-003 0.3870477974414825 0.5257101058959961 <_> <_> <_>7 2 8 10 -1. <_>7 7 8 5 2. 0 -1.4311339473351836e-003 0.5522503256797791 0.4561854898929596 <_> <_> <_>6 14 7 3 -1. <_>6 15 7 1 3. 0 1.9378310535103083e-003 0.4546220898628235 0.5736966729164124 <_> <_> <_>9 2 10 12 -1. <_>14 2 5 6 2. <_>9 8 5 6 2. 0 2.6343559147790074e-004 0.5345739126205444 0.4571875035762787 <_> <_> <_>6 7 8 2 -1. <_>6 8 8 1 2. 0 7.8257522545754910e-004 0.3967815935611725 0.5220187902450562 <_> <_> <_>8 13 4 6 -1. <_>8 16 4 3 2. 0 -0.0195504408329725 0.2829642891883850 0.5243508219718933 <_> <_> <_>6 6 1 3 -1. <_>6 7 1 1 3. 0 4.3914958951063454e-004 0.4590066969394684 0.5899090170860291 <_> <_> <_>16 2 4 6 -1. <_>16 4 4 2 3. 0 0.0214520003646612 0.5231410861015320 0.2855378985404968 <_> <_> <_>6 6 4 2 -1. <_>6 6 2 1 2. <_>8 7 2 1 2. 0 5.8973580598831177e-004 0.4397256970405579 0.5506421923637390 <_> <_> <_>16 2 4 6 -1. <_>16 4 4 2 3. 0 -0.0261576101183891 0.3135079145431519 0.5189175009727478 <_> <_> <_>0 2 4 6 -1. <_>0 4 4 2 3. 0 -0.0139598604291677 0.3213272988796234 0.5040717720985413 <_> <_> <_>9 6 2 6 -1. <_>9 6 1 6 2. 0 -6.3699018210172653e-003 0.6387544870376587 0.4849506914615631 <_> <_> <_>3 4 6 10 -1. <_>3 9 6 5 2. 0 -8.5613820701837540e-003 0.2759132087230682 0.5032019019126892 <_> <_> <_>9 5 2 6 -1. <_>9 5 1 6 2. 0 9.6622901037335396e-004 0.4685640931129456 0.5834879279136658 <_> <_> <_>3 13 2 3 -1. <_>3 14 2 1 3. 0 7.6550268568098545e-004 0.5175207257270813 0.3896422088146210 <_> <_> <_>13 13 3 2 -1. <_>13 14 3 1 2. 0 -8.1833340227603912e-003 0.2069136947393417 0.5208122134208679 <_> <_> <_>2 16 10 4 -1. <_>2 16 5 2 2. <_>7 18 5 2 2. 0 -9.3976939097046852e-003 0.6134091019630432 0.4641222953796387 <_> <_> <_>5 6 10 6 -1. <_>10 6 5 3 2. <_>5 9 5 3 2. 0 4.8028980381786823e-003 0.5454108119010925 0.4395219981670380 <_> <_> <_>7 14 1 3 -1. <_>7 15 1 1 3. 0 -3.5680569708347321e-003 0.6344485282897949 0.4681093990802765 <_> <_> <_>14 16 6 3 -1. <_>14 17 6 1 3. 0 4.0733120404183865e-003 0.5292683243751526 0.4015620052814484 <_> <_> <_>5 4 3 3 -1. <_>5 5 3 1 3. 0 1.2568129459396005e-003 0.4392988085746765 0.5452824831008911 <_> <_> <_>7 4 10 3 -1. <_>7 5 10 1 3. 0 -2.9065010603517294e-003 0.5898832082748413 0.4863379895687103 <_> <_> <_>0 4 5 4 -1. <_>0 6 5 2 2. 0 -2.4409340694546700e-003 0.4069364964962006 0.5247421860694885 <_> <_> <_>13 11 3 9 -1. <_>13 14 3 3 3. 0 0.0248307008296251 0.5182725787162781 0.3682524859905243 <_> <_> <_>4 11 3 9 -1. <_>4 14 3 3 3. 0 -0.0488540083169937 0.1307577937841415 0.4961281120777130 <_> <_> <_>9 7 2 1 -1. <_>9 7 1 1 2. 0 -1.6110379947349429e-003 0.6421005725860596 0.4872662127017975 <_> <_> <_>5 0 6 17 -1. <_>7 0 2 17 3. 0 -0.0970094799995422 0.0477693490684032 0.4950988888740540 <_> <_> <_>10 3 6 3 -1. <_>10 3 3 3 2. 0 1.1209240183234215e-003 0.4616267085075378 0.5354745984077454 <_> <_> <_>2 2 15 4 -1. <_>7 2 5 4 3. 0 -1.3064090162515640e-003 0.6261854171752930 0.4638805985450745 <_> <_> <_>8 2 8 2 -1. <_>12 2 4 1 2. <_>8 3 4 1 2. 0 4.5771620352752507e-004 0.5384417772293091 0.4646640121936798 <_> <_> <_>8 1 3 6 -1. <_>8 3 3 2 3. 0 -6.3149951165542006e-004 0.3804047107696533 0.5130257010459900 <_> <_> <_>9 17 2 2 -1. <_>9 18 2 1 2. 0 1.4505970466416329e-004 0.4554310142993927 0.5664461851119995 <_> <_> <_>0 0 2 14 -1. <_>1 0 1 14 2. 0 -0.0164745505899191 0.6596958041191101 0.4715859889984131 <_> <_> <_>12 0 7 3 -1. <_>12 1 7 1 3. 0 0.0133695797994733 0.5195466279983521 0.3035964965820313 <_> <_> <_>1 14 1 2 -1. <_>1 15 1 1 2. 0 1.0271780047332868e-004 0.5229176282882690 0.4107066094875336 <_> <_> <_>14 12 2 8 -1. <_>15 12 1 4 2. <_>14 16 1 4 2. 0 -5.5311559699475765e-003 0.6352887749671936 0.4960907101631165 <_> <_> <_>1 0 7 3 -1. <_>1 1 7 1 3. 0 -2.6187049224972725e-003 0.3824546039104462 0.5140984058380127 <_> <_> <_>14 12 2 8 -1. <_>15 12 1 4 2. <_>14 16 1 4 2. 0 5.0834268331527710e-003 0.4950439929962158 0.6220818758010864 <_> <_> <_>6 0 8 12 -1. <_>6 0 4 6 2. <_>10 6 4 6 2. 0 0.0798181593418121 0.4952335953712463 0.1322475969791412 <_> <_> <_>6 1 8 9 -1. <_>6 4 8 3 3. 0 -0.0992265865206718 0.7542728781700134 0.5008416771888733 <_> <_> <_>5 2 2 2 -1. <_>5 3 2 1 2. 0 -6.5174017800018191e-004 0.3699302971363068 0.5130121111869812 <_> <_> <_>13 14 6 6 -1. <_>16 14 3 3 2. <_>13 17 3 3 2. 0 -0.0189968496561050 0.6689178943634033 0.4921202957630158 <_> <_> <_>0 17 20 2 -1. <_>0 17 10 1 2. <_>10 18 10 1 2. 0 0.0173468999564648 0.4983300864696503 0.1859198063611984 <_> <_> <_>10 3 2 6 -1. <_>11 3 1 3 2. <_>10 6 1 3 2. 0 5.5082101607695222e-004 0.4574424028396606 0.5522121787071228 <_> <_> <_>5 12 6 2 -1. <_>8 12 3 2 2. 0 2.0056050270795822e-003 0.5131744742393494 0.3856469988822937 <_> <_> <_>10 7 6 13 -1. <_>10 7 3 13 2. 0 -7.7688191086053848e-003 0.4361700117588043 0.5434309244155884 <_> <_> <_>5 15 10 5 -1. <_>10 15 5 5 2. 0 0.0508782789111137 0.4682720899581909 0.6840639710426331 <_> <_> <_>10 4 4 10 -1. <_>10 4 2 10 2. 0 -2.2901780903339386e-003 0.4329245090484619 0.5306099057197571 <_> <_> <_>5 7 2 1 -1. <_>6 7 1 1 2. 0 -1.5715380141045898e-004 0.5370057225227356 0.4378164112567902 <_> <_> <_>10 3 6 7 -1. <_>10 3 3 7 2. 0 0.1051924005150795 0.5137274265289307 0.0673614665865898 <_> <_> <_>4 3 6 7 -1. <_>7 3 3 7 2. 0 2.7198919560760260e-003 0.4112060964107513 0.5255665183067322 <_> <_> <_>1 7 18 5 -1. <_>7 7 6 5 3. 0 0.0483377799391747 0.5404623746871948 0.4438967108726502 <_> <_> <_>3 17 4 3 -1. <_>5 17 2 3 2. 0 9.5703761326149106e-004 0.4355969130992889 0.5399510860443115 <_> <_> <_>8 14 12 6 -1. <_>14 14 6 3 2. <_>8 17 6 3 2. 0 -0.0253712590783834 0.5995175242424011 0.5031024813652039 <_> <_> <_>0 13 20 4 -1. <_>0 13 10 2 2. <_>10 15 10 2 2. 0 0.0524579510092735 0.4950287938117981 0.1398351043462753 <_> <_> <_>4 5 14 2 -1. <_>11 5 7 1 2. <_>4 6 7 1 2. 0 -0.0123656298965216 0.6397299170494080 0.4964106082916260 <_> <_> <_>1 2 10 12 -1. <_>1 2 5 6 2. <_>6 8 5 6 2. 0 -0.1458971947431564 0.1001669988036156 0.4946322143077850 <_> <_> <_>6 1 14 3 -1. <_>6 2 14 1 3. 0 -0.0159086007624865 0.3312329947948456 0.5208340883255005 <_> <_> <_>8 16 2 3 -1. <_>8 17 2 1 3. 0 3.9486068999394774e-004 0.4406363964080811 0.5426102876663208 <_> <_> <_>9 17 3 2 -1. <_>10 17 1 2 3. 0 -5.2454001270234585e-003 0.2799589931964874 0.5189967155456543 <_> <_> <_>5 15 4 2 -1. <_>5 15 2 1 2. <_>7 16 2 1 2. 0 -5.0421799533069134e-003 0.6987580060958862 0.4752142131328583 <_> <_> <_>10 15 1 3 -1. <_>10 16 1 1 3. 0 2.9812189750373363e-003 0.4983288943767548 0.6307479739189148 <_> <_> <_>8 16 4 4 -1. <_>8 16 2 2 2. <_>10 18 2 2 2. 0 -7.2884308174252510e-003 0.2982333004474640 0.5026869773864746 <_> <_> <_>6 11 8 6 -1. <_>6 14 8 3 2. 0 1.5094350092113018e-003 0.5308442115783691 0.3832970857620239 <_> <_> <_>2 13 5 2 -1. <_>2 14 5 1 2. 0 -9.3340799212455750e-003 0.2037964016199112 0.4969817101955414 <_> <_> <_>13 14 6 6 -1. <_>16 14 3 3 2. <_>13 17 3 3 2. 0 0.0286671407520771 0.5025696754455566 0.6928027272224426 <_> <_> <_>1 9 18 4 -1. <_>7 9 6 4 3. 0 0.1701968014240265 0.4960052967071533 0.1476442962884903 <_> <_> <_>13 14 6 6 -1. <_>16 14 3 3 2. <_>13 17 3 3 2. 0 -3.2614478841423988e-003 0.5603063702583313 0.4826056063175201 <_> <_> <_>0 2 1 6 -1. <_>0 4 1 2 3. 0 5.5769277969375253e-004 0.5205562114715576 0.4129633009433746 <_> <_> <_>5 0 15 20 -1. <_>5 10 15 10 2. 0 0.3625833988189697 0.5221652984619141 0.3768612146377564 <_> <_> <_>1 14 6 6 -1. <_>1 14 3 3 2. <_>4 17 3 3 2. 0 -0.0116151301190257 0.6022682785987854 0.4637489914894104 <_> <_> <_>8 14 4 6 -1. <_>10 14 2 3 2. <_>8 17 2 3 2. 0 -4.0795197710394859e-003 0.4070447087287903 0.5337479114532471 <_> <_> <_>7 11 2 1 -1. <_>8 11 1 1 2. 0 5.7204300537705421e-004 0.4601835012435913 0.5900393128395081 <_> <_> <_>9 17 3 2 -1. <_>10 17 1 2 3. 0 6.7543348995968699e-004 0.5398252010345459 0.4345428943634033 <_> <_> <_>8 17 3 2 -1. <_>9 17 1 2 3. 0 6.3295697327703238e-004 0.5201563239097595 0.4051358997821808 <_> <_> <_>12 14 4 6 -1. <_>14 14 2 3 2. <_>12 17 2 3 2. 0 1.2435320531949401e-003 0.4642387926578522 0.5547441244125366 <_> <_> <_>4 14 4 6 -1. <_>4 14 2 3 2. <_>6 17 2 3 2. 0 -4.7363857738673687e-003 0.6198567152023315 0.4672552049160004 <_> <_> <_>13 14 2 6 -1. <_>14 14 1 3 2. <_>13 17 1 3 2. 0 -6.4658462069928646e-003 0.6837332844734192 0.5019000768661499 <_> <_> <_>5 14 2 6 -1. <_>5 14 1 3 2. <_>6 17 1 3 2. 0 3.5017321351915598e-004 0.4344803094863892 0.5363622903823853 <_> <_> <_>7 0 6 12 -1. <_>7 4 6 4 3. 0 1.5754920605104417e-004 0.4760079085826874 0.5732020735740662 <_> <_> <_>0 7 12 2 -1. <_>4 7 4 2 3. 0 9.9774366244673729e-003 0.5090985894203186 0.3635039925575256 <_> <_> <_>10 3 3 13 -1. <_>11 3 1 13 3. 0 -4.1464529931545258e-004 0.5570064783096314 0.4593802094459534 <_> <_> <_>7 3 3 13 -1. <_>8 3 1 13 3. 0 -3.5888899583369493e-004 0.5356845855712891 0.4339134991168976 <_> <_> <_>10 8 6 3 -1. <_>10 9 6 1 3. 0 4.0463250479660928e-004 0.4439803063869476 0.5436776876449585 <_> <_> <_>3 11 3 2 -1. <_>4 11 1 2 3. 0 -8.2184787606820464e-004 0.4042294919490814 0.5176299214363098 <_> <_> <_>13 12 6 8 -1. <_>16 12 3 4 2. <_>13 16 3 4 2. 0 5.9467419050633907e-003 0.4927651882171631 0.5633779764175415 <_> <_> <_>7 6 6 5 -1. <_>9 6 2 5 3. 0 -0.0217533893883228 0.8006293773651123 0.4800840914249420 <_> <_> <_>17 11 2 7 -1. <_>17 11 1 7 2. 0 -0.0145403798669577 0.3946054875850678 0.5182222723960877 <_> <_> <_>3 13 8 2 -1. <_>7 13 4 2 2. 0 -0.0405107699334621 0.0213249903172255 0.4935792982578278 <_> <_> <_>6 9 8 3 -1. <_>6 10 8 1 3. 0 -5.8458268176764250e-004 0.4012795984745026 0.5314025282859802 <_> <_> <_>4 3 4 3 -1. <_>4 4 4 1 3. 0 5.5151800625026226e-003 0.4642418920993805 0.5896260738372803 <_> <_> <_>11 3 4 3 -1. <_>11 4 4 1 3. 0 -6.0626221820712090e-003 0.6502159237861633 0.5016477704048157 <_> <_> <_>1 4 17 12 -1. <_>1 8 17 4 3. 0 0.0945358425378799 0.5264708995819092 0.4126827120780945 <_> <_> <_>11 3 4 3 -1. <_>11 4 4 1 3. 0 4.7315051779150963e-003 0.4879199862480164 0.5892447829246521 <_> <_> <_>4 8 6 3 -1. <_>4 9 6 1 3. 0 -5.2571471314877272e-004 0.3917280137538910 0.5189412832260132 <_> <_> <_>12 3 5 3 -1. <_>12 4 5 1 3. 0 -2.5464049540460110e-003 0.5837599039077759 0.4985705912113190 <_> <_> <_>1 11 2 7 -1. <_>2 11 1 7 2. 0 -0.0260756891220808 0.1261983960866928 0.4955821931362152 <_> <_> <_>15 12 2 8 -1. <_>16 12 1 4 2. <_>15 16 1 4 2. 0 -5.4779709316790104e-003 0.5722513794898987 0.5010265707969666 <_> <_> <_>4 8 11 3 -1. <_>4 9 11 1 3. 0 5.1337741315364838e-003 0.5273262262344360 0.4226376116275787 <_> <_> <_>9 13 6 2 -1. <_>12 13 3 1 2. <_>9 14 3 1 2. 0 4.7944980906322598e-004 0.4450066983699799 0.5819587111473084 <_> <_> <_>6 13 4 3 -1. <_>6 14 4 1 3. 0 -2.1114079281687737e-003 0.5757653117179871 0.4511714875698090 <_> <_> <_>9 12 3 3 -1. <_>10 12 1 3 3. 0 -0.0131799904629588 0.1884381026029587 0.5160734057426453 <_> <_> <_>5 3 3 3 -1. <_>5 4 3 1 3. 0 -4.7968099825084209e-003 0.6589789986610413 0.4736118912696838 <_> <_> <_>9 4 2 3 -1. <_>9 5 2 1 3. 0 6.7483168095350266e-003 0.5259429812431335 0.3356395065784454 <_> <_> <_>0 2 16 3 -1. <_>0 3 16 1 3. 0 1.4623369788751006e-003 0.5355271100997925 0.4264092147350311 <_> <_> <_>15 12 2 8 -1. <_>16 12 1 4 2. <_>15 16 1 4 2. 0 4.7645159065723419e-003 0.5034406781196594 0.5786827802658081 <_> <_> <_>3 12 2 8 -1. <_>3 12 1 4 2. <_>4 16 1 4 2. 0 6.8066660314798355e-003 0.4756605029106140 0.6677829027175903 <_> <_> <_>14 13 3 6 -1. <_>14 15 3 2 3. 0 3.6608621012419462e-003 0.5369611978530884 0.4311546981334686 <_> <_> <_>3 13 3 6 -1. <_>3 15 3 2 3. 0 0.0214496403932571 0.4968641996383667 0.1888816058635712 <_> <_> <_>6 5 10 2 -1. <_>11 5 5 1 2. <_>6 6 5 1 2. 0 4.1678901761770248e-003 0.4930733144283295 0.5815368890762329 <_> <_> <_>2 14 14 6 -1. <_>2 17 14 3 2. 0 8.6467564105987549e-003 0.5205205082893372 0.4132595062255859 <_> <_> <_>10 14 1 3 -1. <_>10 15 1 1 3. 0 -3.6114078829996288e-004 0.5483555197715759 0.4800927937030792 <_> <_> <_>4 16 2 2 -1. <_>4 16 1 1 2. <_>5 17 1 1 2. 0 1.0808729566633701e-003 0.4689902067184448 0.6041421294212341 <_> <_> <_>10 6 2 3 -1. <_>10 7 2 1 3. 0 5.7719959877431393e-003 0.5171142220497131 0.3053277134895325 <_> <_> <_>0 17 20 2 -1. <_>0 17 10 1 2. <_>10 18 10 1 2. 0 1.5720770461484790e-003 0.5219978094100952 0.4178803861141205 <_> <_> <_>13 6 1 3 -1. <_>13 7 1 1 3. 0 -1.9307859474793077e-003 0.5860369801521301 0.4812920093536377 <_> <_> <_>8 13 3 2 -1. <_>9 13 1 2 3. 0 -7.8926272690296173e-003 0.1749276965856552 0.4971733987331390 <_> <_> <_>12 2 3 3 -1. <_>13 2 1 3 3. 0 -2.2224679123610258e-003 0.4342589080333710 0.5212848186492920 <_> <_> <_>3 18 2 2 -1. <_>3 18 1 1 2. <_>4 19 1 1 2. 0 1.9011989934369922e-003 0.4765186905860901 0.6892055273056030 <_> <_> <_>9 16 3 4 -1. <_>10 16 1 4 3. 0 2.7576119173318148e-003 0.5262191295623779 0.4337486028671265 <_> <_> <_>6 6 1 3 -1. <_>6 7 1 1 3. 0 5.1787449046969414e-003 0.4804069101810455 0.7843729257583618 <_> <_> <_>13 1 5 2 -1. <_>13 2 5 1 2. 0 -9.0273341629654169e-004 0.4120846986770630 0.5353423953056335 <_> <_> <_>7 14 6 2 -1. <_>7 14 3 1 2. <_>10 15 3 1 2. 0 5.1797959022223949e-003 0.4740372896194458 0.6425960063934326 <_> <_> <_>11 3 3 4 -1. <_>12 3 1 4 3. 0 -0.0101140001788735 0.2468792051076889 0.5175017714500427 <_> <_> <_>1 13 12 6 -1. <_>5 13 4 6 3. 0 -0.0186170600354671 0.5756294131278992 0.4628978967666626 <_> <_> <_>14 11 5 2 -1. <_>14 12 5 1 2. 0 5.9225959703326225e-003 0.5169625878334045 0.3214271068572998 <_> <_> <_>2 15 14 4 -1. <_>2 15 7 2 2. <_>9 17 7 2 2. 0 -6.2945079989731312e-003 0.3872014880180359 0.5141636729240418 <_> <_> <_>3 7 14 2 -1. <_>10 7 7 1 2. <_>3 8 7 1 2. 0 6.5353019163012505e-003 0.4853048920631409 0.6310489773750305 <_> <_> <_>1 11 4 2 -1. <_>1 12 4 1 2. 0 1.0878399480134249e-003 0.5117315053939819 0.3723258972167969 <_> <_> <_>14 0 6 14 -1. <_>16 0 2 14 3. 0 -0.0225422400981188 0.5692740082740784 0.4887112975120544 <_> <_> <_>4 11 1 3 -1. <_>4 12 1 1 3. 0 -3.0065660830587149e-003 0.2556012868881226 0.5003992915153503 <_> <_> <_>14 0 6 14 -1. <_>16 0 2 14 3. 0 7.4741272255778313e-003 0.4810872972011566 0.5675926804542542 <_> <_> <_>1 10 3 7 -1. <_>2 10 1 7 3. 0 0.0261623207479715 0.4971194863319397 0.1777237057685852 <_> <_> <_>8 12 9 2 -1. <_>8 13 9 1 2. 0 9.4352738233283162e-004 0.4940010905265808 0.5491250753402710 <_> <_> <_>0 6 20 1 -1. <_>10 6 10 1 2. 0 0.0333632417023182 0.5007612109184265 0.2790724039077759 <_> <_> <_>8 4 4 4 -1. <_>8 4 2 4 2. 0 -0.0151186501607299 0.7059578895568848 0.4973031878471375 <_> <_> <_>0 0 2 2 -1. <_>0 1 2 1 2. 0 9.8648946732282639e-004 0.5128620266914368 0.3776761889457703 104.7491989135742200 19 -1 <_> <_> <_> <_>5 3 10 9 -1. <_>5 6 10 3 3. 0 -0.0951507985591888 0.6470757126808167 0.4017286896705627 <_> <_> <_>15 2 4 10 -1. <_>15 2 2 10 2. 0 6.2702340073883533e-003 0.3999822139739990 0.5746449232101440 <_> <_> <_>8 2 2 7 -1. <_>9 2 1 7 2. 0 3.0018089455552399e-004 0.3558770120143890 0.5538809895515442 <_> <_> <_>7 4 12 1 -1. <_>11 4 4 1 3. 0 1.1757409665733576e-003 0.4256534874439240 0.5382617712020874 <_> <_> <_>3 4 9 1 -1. <_>6 4 3 1 3. 0 4.4235268433112651e-005 0.3682908117771149 0.5589926838874817 <_> <_> <_>15 10 1 4 -1. <_>15 12 1 2 2. 0 -2.9936920327600092e-005 0.5452470183372498 0.4020367860794067 <_> <_> <_>4 10 6 4 -1. <_>7 10 3 4 2. 0 3.0073199886828661e-003 0.5239058136940002 0.3317843973636627 <_> <_> <_>15 9 1 6 -1. <_>15 12 1 3 2. 0 -0.0105138896033168 0.4320689141750336 0.5307983756065369 <_> <_> <_>7 17 6 3 -1. <_>7 18 6 1 3. 0 8.3476826548576355e-003 0.4504637122154236 0.6453298926353455 <_> <_> <_>14 3 2 16 -1. <_>15 3 1 8 2. <_>14 11 1 8 2. 0 -3.1492270063608885e-003 0.4313425123691559 0.5370525121688843 <_> <_> <_>4 9 1 6 -1. <_>4 12 1 3 2. 0 -1.4435649973165710e-005 0.5326603055000305 0.3817971944808960 <_> <_> <_>12 1 5 2 -1. <_>12 2 5 1 2. 0 -4.2855090578086674e-004 0.4305163919925690 0.5382009744644165 <_> <_> <_>6 18 4 2 -1. <_>6 18 2 1 2. <_>8 19 2 1 2. 0 1.5062429883982986e-004 0.4235970973968506 0.5544965267181397 <_> <_> <_>2 4 16 10 -1. <_>10 4 8 5 2. <_>2 9 8 5 2. 0 0.0715598315000534 0.5303059816360474 0.2678802907466888 <_> <_> <_>6 5 1 10 -1. <_>6 10 1 5 2. 0 8.4095180500298738e-004 0.3557108938694000 0.5205433964729309 <_> <_> <_>4 8 15 2 -1. <_>9 8 5 2 3. 0 0.0629865005612373 0.5225362777709961 0.2861376106739044 <_> <_> <_>1 8 15 2 -1. <_>6 8 5 2 3. 0 -3.3798629883676767e-003 0.3624185919761658 0.5201697945594788 <_> <_> <_>9 5 3 6 -1. <_>9 7 3 2 3. 0 -1.1810739670181647e-004 0.5474476814270020 0.3959893882274628 <_> <_> <_>5 7 8 2 -1. <_>9 7 4 2 2. 0 -5.4505601292476058e-004 0.3740422129631043 0.5215715765953064 <_> <_> <_>9 11 2 3 -1. <_>9 12 2 1 3. 0 -1.8454910023137927e-003 0.5893052220344544 0.4584448933601379 <_> <_> <_>1 0 16 3 -1. <_>1 1 16 1 3. 0 -4.3832371011376381e-004 0.4084582030773163 0.5385351181030273 <_> <_> <_>11 2 7 2 -1. <_>11 3 7 1 2. 0 -2.4000830017030239e-003 0.3777455091476440 0.5293580293655396 <_> <_> <_>5 1 10 18 -1. <_>5 7 10 6 3. 0 -0.0987957417964935 0.2963612079620361 0.5070089101791382 <_> <_> <_>17 4 3 2 -1. <_>18 4 1 2 3. 0 3.1798239797353745e-003 0.4877632856369019 0.6726443767547607 <_> <_> <_>8 13 1 3 -1. <_>8 14 1 1 3. 0 3.2406419632025063e-004 0.4366911053657532 0.5561109781265259 <_> <_> <_>3 14 14 6 -1. <_>3 16 14 2 3. 0 -0.0325472503900528 0.3128157854080200 0.5308616161346436 <_> <_> <_>0 2 3 4 -1. <_>1 2 1 4 3. 0 -7.7561130747199059e-003 0.6560224890708923 0.4639872014522553 <_> <_> <_>12 1 5 2 -1. <_>12 2 5 1 2. 0 0.0160272493958473 0.5172680020332336 0.3141897916793823 <_> <_> <_>3 1 5 2 -1. <_>3 2 5 1 2. 0 7.1002350523485802e-006 0.4084446132183075 0.5336294770240784 <_> <_> <_>10 13 2 3 -1. <_>10 14 2 1 3. 0 7.3422808200120926e-003 0.4966922104358673 0.6603465080261231 <_> <_> <_>8 13 2 3 -1. <_>8 14 2 1 3. 0 -1.6970280557870865e-003 0.5908237099647522 0.4500182867050171 <_> <_> <_>14 12 2 3 -1. <_>14 13 2 1 3. 0 2.4118260480463505e-003 0.5315160751342773 0.3599720895290375 <_> <_> <_>7 2 2 3 -1. <_>7 3 2 1 3. 0 -5.5300937965512276e-003 0.2334040999412537 0.4996814131736755 <_> <_> <_>5 6 10 4 -1. <_>10 6 5 2 2. <_>5 8 5 2 2. 0 -2.6478730142116547e-003 0.5880935788154602 0.4684734046459198 <_> <_> <_>9 13 1 6 -1. <_>9 16 1 3 2. 0 0.0112956296652555 0.4983777105808258 0.1884590983390808 <_> <_> <_>10 12 2 2 -1. <_>11 12 1 1 2. <_>10 13 1 1 2. 0 -6.6952878842130303e-004 0.5872138142585754 0.4799019992351532 <_> <_> <_>4 12 2 3 -1. <_>4 13 2 1 3. 0 1.4410680159926414e-003 0.5131189227104187 0.3501011133193970 <_> <_> <_>14 4 6 6 -1. <_>14 6 6 2 3. 0 2.4637870956212282e-003 0.5339372158050537 0.4117639064788818 <_> <_> <_>8 17 2 3 -1. <_>8 18 2 1 3. 0 3.3114518737420440e-004 0.4313383102416992 0.5398246049880981 <_> <_> <_>16 4 4 6 -1. <_>16 6 4 2 3. 0 -0.0335572697222233 0.2675336897373200 0.5179154872894287 <_> <_> <_>0 4 4 6 -1. <_>0 6 4 2 3. 0 0.0185394193977118 0.4973869919776917 0.2317177057266235 <_> <_> <_>14 6 2 3 -1. <_>14 6 1 3 2. 0 -2.9698139405809343e-004 0.5529708266258240 0.4643664062023163 <_> <_> <_>4 9 8 1 -1. <_>8 9 4 1 2. 0 -4.5577259152196348e-004 0.5629584193229675 0.4469191133975983 <_> <_> <_>8 12 4 3 -1. <_>8 13 4 1 3. 0 -0.0101589802652597 0.6706212759017944 0.4925918877124786 <_> <_> <_>5 12 10 6 -1. <_>5 14 10 2 3. 0 -2.2413829356082715e-005 0.5239421725273132 0.3912901878356934 <_> <_> <_>11 12 1 2 -1. <_>11 13 1 1 2. 0 7.2034963523037732e-005 0.4799438118934631 0.5501788854598999 <_> <_> <_>8 15 4 2 -1. <_>8 16 4 1 2. 0 -6.9267209619283676e-003 0.6930009722709656 0.4698084890842438 <_> <_> <_>6 9 8 8 -1. <_>10 9 4 4 2. <_>6 13 4 4 2. 0 -7.6997838914394379e-003 0.4099623858928680 0.5480883121490479 <_> <_> <_>7 12 4 6 -1. <_>7 12 2 3 2. <_>9 15 2 3 2. 0 -7.3130549862980843e-003 0.3283475935459137 0.5057886242866516 <_> <_> <_>10 11 3 1 -1. <_>11 11 1 1 3. 0 1.9650589674711227e-003 0.4978047013282776 0.6398249864578247 <_> <_> <_>9 7 2 10 -1. <_>9 7 1 5 2. <_>10 12 1 5 2. 0 7.1647600270807743e-003 0.4661160111427307 0.6222137212753296 <_> <_> <_>8 0 6 6 -1. <_>10 0 2 6 3. 0 -0.0240786392241716 0.2334644943475723 0.5222162008285523 <_> <_> <_>3 11 2 6 -1. <_>3 13 2 2 3. 0 -0.0210279691964388 0.1183653995394707 0.4938226044178009 <_> <_> <_>16 12 1 2 -1. <_>16 13 1 1 2. 0 3.6017020465806127e-004 0.5325019955635071 0.4116711020469666 <_> <_> <_>1 14 6 6 -1. <_>1 14 3 3 2. <_>4 17 3 3 2. 0 -0.0172197297215462 0.6278762221336365 0.4664269089698792 <_> <_> <_>13 1 3 6 -1. <_>14 1 1 6 3. 0 -7.8672142699360847e-003 0.3403415083885193 0.5249736905097961 <_> <_> <_>8 8 2 2 -1. <_>8 9 2 1 2. 0 -4.4777389848604798e-004 0.3610411882400513 0.5086259245872498 <_> <_> <_>9 9 3 3 -1. <_>10 9 1 3 3. 0 5.5486010387539864e-003 0.4884265959262848 0.6203498244285584 <_> <_> <_>8 7 3 3 -1. <_>8 8 3 1 3. 0 -6.9461148232221603e-003 0.2625930011272430 0.5011097192764282 <_> <_> <_>14 0 2 3 -1. <_>14 0 1 3 2. 0 1.3569870498031378e-004 0.4340794980525971 0.5628312230110169 <_> <_> <_>1 0 18 9 -1. <_>7 0 6 9 3. 0 -0.0458802506327629 0.6507998704910278 0.4696274995803833 <_> <_> <_>11 5 4 15 -1. <_>11 5 2 15 2. 0 -0.0215825606137514 0.3826502859592438 0.5287616848945618 <_> <_> <_>5 5 4 15 -1. <_>7 5 2 15 2. 0 -0.0202095396816731 0.3233368098735809 0.5074477195739746 <_> <_> <_>14 0 2 3 -1. <_>14 0 1 3 2. 0 5.8496710844337940e-003 0.5177603960037231 0.4489670991897583 <_> <_> <_>4 0 2 3 -1. <_>5 0 1 3 2. 0 -5.7476379879517481e-005 0.4020850956439972 0.5246363878250122 <_> <_> <_>11 12 2 2 -1. <_>12 12 1 1 2. <_>11 13 1 1 2. 0 -1.1513100471347570e-003 0.6315072178840637 0.4905154109001160 <_> <_> <_>7 12 2 2 -1. <_>7 12 1 1 2. <_>8 13 1 1 2. 0 1.9862831104546785e-003 0.4702459871768951 0.6497151255607605 <_> <_> <_>12 0 3 4 -1. <_>13 0 1 4 3. 0 -5.2719512023031712e-003 0.3650383949279785 0.5227652788162231 <_> <_> <_>4 11 3 3 -1. <_>4 12 3 1 3. 0 1.2662699446082115e-003 0.5166100859642029 0.3877618014812470 <_> <_> <_>12 7 4 2 -1. <_>12 8 4 1 2. 0 -6.2919440679252148e-003 0.7375894188880920 0.5023847818374634 <_> <_> <_>8 10 3 2 -1. <_>9 10 1 2 3. 0 6.7360111279413104e-004 0.4423226118087769 0.5495585799217224 <_> <_> <_>9 9 3 2 -1. <_>10 9 1 2 3. 0 -1.0523450328037143e-003 0.5976396203041077 0.4859583079814911 <_> <_> <_>8 9 3 2 -1. <_>9 9 1 2 3. 0 -4.4216238893568516e-004 0.5955939292907715 0.4398930966854096 <_> <_> <_>12 0 3 4 -1. <_>13 0 1 4 3. 0 1.1747940443456173e-003 0.5349888205528259 0.4605058133602142 <_> <_> <_>5 0 3 4 -1. <_>6 0 1 4 3. 0 5.2457437850534916e-003 0.5049191117286682 0.2941577136516571 <_> <_> <_>4 14 12 4 -1. <_>10 14 6 2 2. <_>4 16 6 2 2. 0 -0.0245397202670574 0.2550177872180939 0.5218586921691895 <_> <_> <_>8 13 2 3 -1. <_>8 14 2 1 3. 0 7.3793041519820690e-004 0.4424861073493958 0.5490816235542297 <_> <_> <_>10 10 3 8 -1. <_>10 14 3 4 2. 0 1.4233799884095788e-003 0.5319514274597168 0.4081355929374695 <_> <_> <_>8 10 4 8 -1. <_>8 10 2 4 2. <_>10 14 2 4 2. 0 -2.4149110540747643e-003 0.4087659120559692 0.5238950252532959 <_> <_> <_>10 8 3 1 -1. <_>11 8 1 1 3. 0 -1.2165299849584699e-003 0.5674579143524170 0.4908052980899811 <_> <_> <_>9 12 1 6 -1. <_>9 15 1 3 2. 0 -1.2438809499144554e-003 0.4129425883293152 0.5256118178367615 <_> <_> <_>10 8 3 1 -1. <_>11 8 1 1 3. 0 6.1942739412188530e-003 0.5060194134712219 0.7313653230667114 <_> <_> <_>7 8 3 1 -1. <_>8 8 1 1 3. 0 -1.6607169527560472e-003 0.5979632139205933 0.4596369862556458 <_> <_> <_>5 2 15 14 -1. <_>5 9 15 7 2. 0 -0.0273162592202425 0.4174365103244782 0.5308842062950134 <_> <_> <_>2 1 2 10 -1. <_>2 1 1 5 2. <_>3 6 1 5 2. 0 -1.5845570014789701e-003 0.5615804791450501 0.4519486129283905 <_> <_> <_>14 14 2 3 -1. <_>14 15 2 1 3. 0 -1.5514739789068699e-003 0.4076187014579773 0.5360785126686096 <_> <_> <_>2 7 3 3 -1. <_>3 7 1 3 3. 0 3.8446558755822480e-004 0.4347293972969055 0.5430442094802856 <_> <_> <_>17 4 3 3 -1. <_>17 5 3 1 3. 0 -0.0146722598001361 0.1659304946660996 0.5146093964576721 <_> <_> <_>0 4 3 3 -1. <_>0 5 3 1 3. 0 8.1608882173895836e-003 0.4961819052696228 0.1884745955467224 <_> <_> <_>13 5 6 2 -1. <_>16 5 3 1 2. <_>13 6 3 1 2. 0 1.1121659772470593e-003 0.4868263900279999 0.6093816161155701 <_> <_> <_>4 19 12 1 -1. <_>8 19 4 1 3. 0 -7.2603770531713963e-003 0.6284325122833252 0.4690375924110413 <_> <_> <_>12 12 2 4 -1. <_>12 14 2 2 2. 0 -2.4046430189628154e-004 0.5575000047683716 0.4046044051647186 <_> <_> <_>3 15 1 3 -1. <_>3 16 1 1 3. 0 -2.3348190006799996e-004 0.4115762114524841 0.5252848267555237 <_> <_> <_>11 16 6 4 -1. <_>11 16 3 4 2. 0 5.5736480280756950e-003 0.4730072915554047 0.5690100789070129 <_> <_> <_>2 10 3 10 -1. <_>3 10 1 10 3. 0 0.0306237693876028 0.4971886873245239 0.1740095019340515 <_> <_> <_>12 8 2 4 -1. <_>12 8 1 4 2. 0 9.2074798885732889e-004 0.5372117757797241 0.4354872107505798 <_> <_> <_>6 8 2 4 -1. <_>7 8 1 4 2. 0 -4.3550739064812660e-005 0.5366883873939514 0.4347316920757294 <_> <_> <_>10 14 2 3 -1. <_>10 14 1 3 2. 0 -6.6452710889279842e-003 0.3435518145561218 0.5160533189773560 <_> <_> <_>5 1 10 3 -1. <_>10 1 5 3 2. 0 0.0432219989597797 0.4766792058944702 0.7293652892112732 <_> <_> <_>10 7 3 2 -1. <_>11 7 1 2 3. 0 2.2331769578158855e-003 0.5029315948486328 0.5633171200752258 <_> <_> <_>5 6 9 2 -1. <_>8 6 3 2 3. 0 3.1829739455133677e-003 0.4016092121601105 0.5192136764526367 <_> <_> <_>9 8 2 2 -1. <_>9 9 2 1 2. 0 -1.8027749320026487e-004 0.4088315963745117 0.5417919754981995 <_> <_> <_>2 11 16 6 -1. <_>2 11 8 3 2. <_>10 14 8 3 2. 0 -5.2934689447283745e-003 0.4075677096843720 0.5243561863899231 <_> <_> <_>12 7 2 2 -1. <_>13 7 1 1 2. <_>12 8 1 1 2. 0 1.2750959722325206e-003 0.4913282990455627 0.6387010812759399 <_> <_> <_>9 5 2 3 -1. <_>9 6 2 1 3. 0 4.3385322205722332e-003 0.5031672120094299 0.2947346866130829 <_> <_> <_>9 7 3 2 -1. <_>10 7 1 2 3. 0 8.5250744596123695e-003 0.4949789047241211 0.6308869123458862 <_> <_> <_>5 1 8 12 -1. <_>5 7 8 6 2. 0 -9.4266352243721485e-004 0.5328366756439209 0.4285649955272675 <_> <_> <_>13 5 2 2 -1. <_>13 6 2 1 2. 0 1.3609660090878606e-003 0.4991525113582611 0.5941501259803772 <_> <_> <_>5 5 2 2 -1. <_>5 6 2 1 2. 0 4.4782509212382138e-004 0.4573504030704498 0.5854480862617493 <_> <_> <_>12 4 3 3 -1. <_>12 5 3 1 3. 0 1.3360050506889820e-003 0.4604358971118927 0.5849052071571350 <_> <_> <_>4 14 2 3 -1. <_>4 15 2 1 3. 0 -6.0967548051849008e-004 0.3969388902187347 0.5229423046112061 <_> <_> <_>12 4 3 3 -1. <_>12 5 3 1 3. 0 -2.3656780831515789e-003 0.5808320045471191 0.4898357093334198 <_> <_> <_>5 4 3 3 -1. <_>5 5 3 1 3. 0 1.0734340175986290e-003 0.4351210892200470 0.5470039248466492 <_> <_> <_>9 14 2 6 -1. <_>10 14 1 3 2. <_>9 17 1 3 2. 0 2.1923359017819166e-003 0.5355060100555420 0.3842903971672058 <_> <_> <_>8 14 3 2 -1. <_>9 14 1 2 3. 0 5.4968618787825108e-003 0.5018138885498047 0.2827191948890686 <_> <_> <_>9 5 6 6 -1. <_>11 5 2 6 3. 0 -0.0753688216209412 0.1225076019763947 0.5148826837539673 <_> <_> <_>5 5 6 6 -1. <_>7 5 2 6 3. 0 0.0251344703137875 0.4731766879558563 0.7025446295738220 <_> <_> <_>13 13 1 2 -1. <_>13 14 1 1 2. 0 -2.9358599931583740e-005 0.5430532097816467 0.4656086862087250 <_> <_> <_>0 2 10 2 -1. <_>0 3 10 1 2. 0 -5.8355910005047917e-004 0.4031040072441101 0.5190119743347168 <_> <_> <_>13 13 1 2 -1. <_>13 14 1 1 2. 0 -2.6639450807124376e-003 0.4308126866817474 0.5161771178245544 <_> <_> <_>5 7 2 2 -1. <_>5 7 1 1 2. <_>6 8 1 1 2. 0 -1.3804089976474643e-003 0.6219829916954041 0.4695515930652618 <_> <_> <_>13 5 2 7 -1. <_>13 5 1 7 2. 0 1.2313219485804439e-003 0.5379363894462585 0.4425831139087677 <_> <_> <_>6 13 1 2 -1. <_>6 14 1 1 2. 0 -1.4644179827882908e-005 0.5281640291213989 0.4222503006458283 <_> <_> <_>11 0 3 7 -1. <_>12 0 1 7 3. 0 -0.0128188095986843 0.2582092881202698 0.5179932713508606 <_> <_> <_>0 3 2 16 -1. <_>0 3 1 8 2. <_>1 11 1 8 2. 0 0.0228521898388863 0.4778693020343781 0.7609264254570007 <_> <_> <_>11 0 3 7 -1. <_>12 0 1 7 3. 0 8.2305970136076212e-004 0.5340992212295532 0.4671724140644074 <_> <_> <_>6 0 3 7 -1. <_>7 0 1 7 3. 0 0.0127701200544834 0.4965761005878449 0.1472366005182266 <_> <_> <_>11 16 8 4 -1. <_>11 16 4 4 2. 0 -0.0500515103340149 0.6414994001388550 0.5016592144966126 <_> <_> <_>1 16 8 4 -1. <_>5 16 4 4 2. 0 0.0157752707600594 0.4522320032119751 0.5685362219810486 <_> <_> <_>13 5 2 7 -1. <_>13 5 1 7 2. 0 -0.0185016207396984 0.2764748930931091 0.5137959122657776 <_> <_> <_>5 5 2 7 -1. <_>6 5 1 7 2. 0 2.4626250378787518e-003 0.5141941905021668 0.3795408010482788 <_> <_> <_>18 6 2 14 -1. <_>18 13 2 7 2. 0 0.0629161670804024 0.5060648918151856 0.6580433845520020 <_> <_> <_>6 10 3 4 -1. <_>6 12 3 2 2. 0 -2.1648500478477217e-005 0.5195388197898865 0.4019886851310730 <_> <_> <_>14 7 1 2 -1. <_>14 8 1 1 2. 0 2.1180990152060986e-003 0.4962365031242371 0.5954458713531494 <_> <_> <_>0 1 18 6 -1. <_>0 1 9 3 2. <_>9 4 9 3 2. 0 -0.0166348908096552 0.3757933080196381 0.5175446867942810 <_> <_> <_>14 7 1 2 -1. <_>14 8 1 1 2. 0 -2.8899470344185829e-003 0.6624013781547546 0.5057178735733032 <_> <_> <_>0 6 2 14 -1. <_>0 13 2 7 2. 0 0.0767832621932030 0.4795796871185303 0.8047714829444885 <_> <_> <_>17 0 3 12 -1. <_>18 0 1 12 3. 0 3.9170677773654461e-003 0.4937882125377655 0.5719941854476929 <_> <_> <_>0 6 18 3 -1. <_>0 7 18 1 3. 0 -0.0726706013083458 0.0538945607841015 0.4943903982639313 <_> <_> <_>6 0 14 16 -1. <_>6 8 14 8 2. 0 0.5403950214385986 0.5129774212837219 0.1143338978290558 <_> <_> <_>0 0 3 12 -1. <_>1 0 1 12 3. 0 2.9510019812732935e-003 0.4528343975543976 0.5698574185371399 <_> <_> <_>13 0 3 7 -1. <_>14 0 1 7 3. 0 3.4508369863033295e-003 0.5357726812362671 0.4218730926513672 <_> <_> <_>5 7 1 2 -1. <_>5 8 1 1 2. 0 -4.2077939724549651e-004 0.5916172862052918 0.4637925922870636 <_> <_> <_>14 4 6 6 -1. <_>14 6 6 2 3. 0 3.3051050268113613e-003 0.5273385047912598 0.4382042884826660 <_> <_> <_>5 7 7 2 -1. <_>5 8 7 1 2. 0 4.7735060798004270e-004 0.4046528041362763 0.5181884765625000 <_> <_> <_>8 6 6 9 -1. <_>8 9 6 3 3. 0 -0.0259285103529692 0.7452235817909241 0.5089386105537415 <_> <_> <_>5 4 6 1 -1. <_>7 4 2 1 3. 0 -2.9729790985584259e-003 0.3295435905456543 0.5058795213699341 <_> <_> <_>13 0 6 4 -1. <_>16 0 3 2 2. <_>13 2 3 2 2. 0 5.8508329093456268e-003 0.4857144057750702 0.5793024897575378 <_> <_> <_>1 2 18 12 -1. <_>1 6 18 4 3. 0 -0.0459675192832947 0.4312731027603149 0.5380653142929077 <_> <_> <_>3 2 17 12 -1. <_>3 6 17 4 3. 0 0.1558596044778824 0.5196170210838318 0.1684713959693909 <_> <_> <_>5 14 7 3 -1. <_>5 15 7 1 3. 0 0.0151648297905922 0.4735757112503052 0.6735026836395264 <_> <_> <_>10 14 1 3 -1. <_>10 15 1 1 3. 0 -1.0604249546304345e-003 0.5822926759719849 0.4775702953338623 <_> <_> <_>3 14 3 3 -1. <_>3 15 3 1 3. 0 6.6476291976869106e-003 0.4999198913574219 0.2319535017013550 <_> <_> <_>14 4 6 6 -1. <_>14 6 6 2 3. 0 -0.0122311301529408 0.4750893115997315 0.5262982249259949 <_> <_> <_>0 4 6 6 -1. <_>0 6 6 2 3. 0 5.6528882123529911e-003 0.5069767832756043 0.3561818897724152 <_> <_> <_>12 5 4 3 -1. <_>12 6 4 1 3. 0 1.2977829901501536e-003 0.4875693917274475 0.5619062781333923 <_> <_> <_>4 5 4 3 -1. <_>4 6 4 1 3. 0 0.0107815898954868 0.4750770032405853 0.6782308220863342 <_> <_> <_>18 0 2 6 -1. <_>18 2 2 2 3. 0 2.8654779307544231e-003 0.5305461883544922 0.4290736019611359 <_> <_> <_>8 1 4 9 -1. <_>10 1 2 9 2. 0 2.8663428965955973e-003 0.4518479108810425 0.5539351105690002 <_> <_> <_>6 6 8 2 -1. <_>6 6 4 2 2. 0 -5.1983320154249668e-003 0.4149119853973389 0.5434188842773438 <_> <_> <_>6 5 4 2 -1. <_>6 5 2 1 2. <_>8 6 2 1 2. 0 5.3739990107715130e-003 0.4717896878719330 0.6507657170295715 <_> <_> <_>10 5 2 3 -1. <_>10 6 2 1 3. 0 -0.0146415298804641 0.2172164022922516 0.5161777138710022 <_> <_> <_>9 5 1 3 -1. <_>9 6 1 1 3. 0 -1.5042580344015732e-005 0.5337383747100830 0.4298836886882782 <_> <_> <_>9 10 2 2 -1. <_>9 11 2 1 2. 0 -1.1875660129589960e-004 0.4604594111442566 0.5582447052001953 <_> <_> <_>0 8 4 3 -1. <_>0 9 4 1 3. 0 0.0169955305755138 0.4945895075798035 0.0738800764083862 <_> <_> <_>6 0 8 6 -1. <_>6 3 8 3 2. 0 -0.0350959412753582 0.7005509138107300 0.4977591037750244 <_> <_> <_>1 0 6 4 -1. <_>1 0 3 2 2. <_>4 2 3 2 2. 0 2.4217350874096155e-003 0.4466265141963959 0.5477694272994995 <_> <_> <_>13 0 3 7 -1. <_>14 0 1 7 3. 0 -9.6340337768197060e-004 0.4714098870754242 0.5313338041305542 <_> <_> <_>9 16 2 2 -1. <_>9 17 2 1 2. 0 1.6391130338888615e-004 0.4331546127796173 0.5342242121696472 <_> <_> <_>11 4 6 10 -1. <_>11 9 6 5 2. 0 -0.0211414601653814 0.2644700109958649 0.5204498767852783 <_> <_> <_>0 10 19 2 -1. <_>0 11 19 1 2. 0 8.7775202700868249e-004 0.5208349823951721 0.4152742922306061 <_> <_> <_>9 5 8 9 -1. <_>9 8 8 3 3. 0 -0.0279439203441143 0.6344125270843506 0.5018811821937561 <_> <_> <_>4 0 3 7 -1. <_>5 0 1 7 3. 0 6.7297378554940224e-003 0.5050438046455383 0.3500863909721375 <_> <_> <_>8 6 4 12 -1. <_>10 6 2 6 2. <_>8 12 2 6 2. 0 0.0232810396701097 0.4966318011283875 0.6968677043914795 <_> <_> <_>0 2 6 4 -1. <_>0 4 6 2 2. 0 -0.0116449799388647 0.3300260007381439 0.5049629807472229 <_> <_> <_>8 15 4 3 -1. <_>8 16 4 1 3. 0 0.0157643090933561 0.4991598129272461 0.7321153879165649 <_> <_> <_>8 0 3 7 -1. <_>9 0 1 7 3. 0 -1.3611479662358761e-003 0.3911735117435455 0.5160670876502991 <_> <_> <_>9 5 3 4 -1. <_>10 5 1 4 3. 0 -8.1522337859496474e-004 0.5628911256790161 0.4949719011783600 <_> <_> <_>8 5 3 4 -1. <_>9 5 1 4 3. 0 -6.0066272271797061e-004 0.5853595137596130 0.4550595879554749 <_> <_> <_>7 6 6 1 -1. <_>9 6 2 1 3. 0 4.9715518252924085e-004 0.4271470010280609 0.5443599224090576 <_> <_> <_>7 14 4 4 -1. <_>7 14 2 2 2. <_>9 16 2 2 2. 0 2.3475370835512877e-003 0.5143110752105713 0.3887656927108765 <_> <_> <_>13 14 4 6 -1. <_>15 14 2 3 2. <_>13 17 2 3 2. 0 -8.9261569082736969e-003 0.6044502258300781 0.4971720874309540 <_> <_> <_>7 8 1 8 -1. <_>7 12 1 4 2. 0 -0.0139199104160070 0.2583160996437073 0.5000367760658264 <_> <_> <_>16 0 2 8 -1. <_>17 0 1 4 2. <_>16 4 1 4 2. 0 1.0209949687123299e-003 0.4857374131679535 0.5560358166694641 <_> <_> <_>2 0 2 8 -1. <_>2 0 1 4 2. <_>3 4 1 4 2. 0 -2.7441629208624363e-003 0.5936884880065918 0.4645777046680450 <_> <_> <_>6 1 14 3 -1. <_>6 2 14 1 3. 0 -0.0162001308053732 0.3163014948368073 0.5193495154380798 <_> <_> <_>7 9 3 10 -1. <_>7 14 3 5 2. 0 4.3331980705261230e-003 0.5061224102973938 0.3458878993988037 <_> <_> <_>9 14 2 2 -1. <_>9 15 2 1 2. 0 5.8497930876910686e-004 0.4779017865657806 0.5870177745819092 <_> <_> <_>7 7 6 8 -1. <_>7 11 6 4 2. 0 -2.2466450463980436e-003 0.4297851026058197 0.5374773144721985 <_> <_> <_>9 7 3 6 -1. <_>9 10 3 3 2. 0 2.3146099410951138e-003 0.5438671708106995 0.4640969932079315 <_> <_> <_>7 13 3 3 -1. <_>7 14 3 1 3. 0 8.7679121643304825e-003 0.4726893007755280 0.6771789789199829 <_> <_> <_>9 9 2 2 -1. <_>9 10 2 1 2. 0 -2.2448020172305405e-004 0.4229173064231873 0.5428048968315125 <_> <_> <_>0 1 18 2 -1. <_>6 1 6 2 3. 0 -7.4336021207273006e-003 0.6098880767822266 0.4683673977851868 <_> <_> <_>7 1 6 14 -1. <_>7 8 6 7 2. 0 -2.3189240600913763e-003 0.5689436793327332 0.4424242079257965 <_> <_> <_>1 9 18 1 -1. <_>7 9 6 1 3. 0 -2.1042178850620985e-003 0.3762221038341522 0.5187087059020996 <_> <_> <_>9 7 2 2 -1. <_>9 7 1 2 2. 0 4.6034841216169298e-004 0.4699405133724213 0.5771207213401794 <_> <_> <_>9 3 2 9 -1. <_>10 3 1 9 2. 0 1.0547629790380597e-003 0.4465216994285584 0.5601701736450195 <_> <_> <_>18 14 2 3 -1. <_>18 15 2 1 3. 0 8.7148818420246243e-004 0.5449805259704590 0.3914709091186523 <_> <_> <_>7 11 3 1 -1. <_>8 11 1 1 3. 0 3.3364820410497487e-004 0.4564009010791779 0.5645738840103149 <_> <_> <_>10 8 3 4 -1. <_>11 8 1 4 3. 0 -1.4853250468149781e-003 0.5747377872467041 0.4692778885364533 <_> <_> <_>7 14 3 6 -1. <_>8 14 1 6 3. 0 3.0251620337367058e-003 0.5166196823120117 0.3762814104557037 <_> <_> <_>10 8 3 4 -1. <_>11 8 1 4 3. 0 5.0280741415917873e-003 0.5002111792564392 0.6151527166366577 <_> <_> <_>7 8 3 4 -1. <_>8 8 1 4 3. 0 -5.8164511574432254e-004 0.5394598245620728 0.4390751123428345 <_> <_> <_>7 9 6 9 -1. <_>7 12 6 3 3. 0 0.0451415292918682 0.5188326835632324 0.2063035964965820 <_> <_> <_>0 14 2 3 -1. <_>0 15 2 1 3. 0 -1.0795620037242770e-003 0.3904685080051422 0.5137907266616821 <_> <_> <_>11 12 1 2 -1. <_>11 13 1 1 2. 0 1.5995999274309725e-004 0.4895322918891907 0.5427504181861877 <_> <_> <_>4 3 8 3 -1. <_>8 3 4 3 2. 0 -0.0193592701107264 0.6975228786468506 0.4773507118225098 <_> <_> <_>0 4 20 6 -1. <_>0 4 10 6 2. 0 0.2072550952434540 0.5233635902404785 0.3034991919994354 <_> <_> <_>9 14 1 3 -1. <_>9 15 1 1 3. 0 -4.1953290929086506e-004 0.5419396758079529 0.4460186064243317 <_> <_> <_>8 14 4 3 -1. <_>8 15 4 1 3. 0 2.2582069505006075e-003 0.4815764129161835 0.6027408838272095 <_> <_> <_>0 15 14 4 -1. <_>0 17 14 2 2. 0 -6.7811207845807076e-003 0.3980278968811035 0.5183305740356445 <_> <_> <_>1 14 18 6 -1. <_>1 17 18 3 2. 0 0.0111543098464608 0.5431231856346130 0.4188759922981262 <_> <_> <_>0 0 10 6 -1. <_>0 0 5 3 2. <_>5 3 5 3 2. 0 0.0431624315679073 0.4738228023052216 0.6522961258888245 105.7611007690429700 20 -1 ================================================ FILE: examples/hello.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" ) func main() { robot := gobot.NewRobot( func() { gobot.Every(500*time.Millisecond, func() { fmt.Println("Greetings human") }) }, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/hello_api.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "html" "net/http" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/api" ) func main() { manager := gobot.NewManager() a := api.NewAPI(manager) a.AddHandler(func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hello, %q \n", html.EscapeString(r.URL.Path)) }) a.Debug() a.Start() manager.AddCommand("custom_gobot_command", func(params map[string]interface{}) interface{} { return "This command is attached to the mcp!" }) hello := manager.AddRobot(gobot.NewRobot("hello")) hello.AddCommand("hi_there", func(params map[string]interface{}) interface{} { return fmt.Sprintf("This command is attached to the robot %v", hello.Name) }) if err := manager.Start(); err != nil { panic(err) } } ================================================ FILE: examples/hello_api_auth.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "html" "net/http" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/api" ) func main() { manager := gobot.NewManager() a := api.NewAPI(manager) a.AddHandler(api.BasicAuth("gort", "klatuu")) a.Debug() a.AddHandler(func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hello, %q \n", html.EscapeString(r.URL.Path)) }) a.Start() manager.AddCommand("custom_gobot_command", func(params map[string]interface{}) interface{} { return "This command is attached to the mcp!" }) hello := manager.AddRobot(gobot.NewRobot("hello")) hello.AddCommand("hi_there", func(params map[string]interface{}) interface{} { return fmt.Sprintf("This command is attached to the robot %v", hello.Name) }) if err := manager.Start(); err != nil { panic(err) } } ================================================ FILE: examples/hello_api_custom.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "net/http" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/api" ) func main() { manager := gobot.NewManager() a := api.NewAPI(manager) // creates routes/handlers for the custom API a.Get("/", func(res http.ResponseWriter, req *http.Request) { if _, err := res.Write([]byte("OK")); err != nil { fmt.Println(err) } }) a.Get("/api/hello", func(res http.ResponseWriter, req *http.Request) { msg := fmt.Sprintf("This command is attached to the robot %v", manager.Robot("hello").Name) if _, err := res.Write([]byte(msg)); err != nil { fmt.Println(err) } }) // starts the API without the default C2PIO API and Robeaux web interface. a.StartWithoutDefaults() manager.AddRobot(gobot.NewRobot("hello")) if err := manager.Start(); err != nil { panic(err) } } ================================================ FILE: examples/hello_api_video.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "net/http" "os" "github.com/hybridgroup/mjpeg" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/api" "gocv.io/x/gocv" ) var ( deviceID int err error webcam *gocv.VideoCapture stream *mjpeg.Stream ) func main() { // parse args deviceID := os.Args[1] manager := gobot.NewManager() a := api.NewAPI(manager) // add the standard C3PIO API routes manually. a.AddC3PIORoutes() // starts the API without the default C2PIO API and Robeaux web interface. // However, the C3PIO API was added manually using a.AddC3PIORoutes() which // means the REST API will be available, but not the web interface. a.StartWithoutDefaults() hello := manager.AddRobot(gobot.NewRobot("hello")) hello.AddCommand("hi_there", func(params map[string]interface{}) interface{} { return fmt.Sprintf("This command is attached to the robot %v", hello.Name) }) // open webcam webcam, err = gocv.OpenVideoCapture(deviceID) if err != nil { fmt.Printf("Error opening capture device: %v\n", deviceID) return } defer webcam.Close() // create the mjpeg stream stream = mjpeg.NewStream() http.Handle("/video", stream) // start capturing go mjpegCapture() if err := manager.Start(); err != nil { panic(err) } } func mjpegCapture() { img := gocv.NewMat() defer img.Close() for { if ok := webcam.Read(&img); !ok { fmt.Printf("Device closed: %v\n", deviceID) return } if img.Empty() { continue } buf, _ := gocv.IMEncode(".jpg", img) stream.UpdateJPEG(buf) } } ================================================ FILE: examples/holystone_hs200.go ================================================ //go:build example // +build example // // Do not build by default. /* How to run go run examples/holystone_hs200.go */ package main import ( "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/holystone/hs200" ) func main() { drone := hs200.NewDriver("172.16.10.1:8888", "172.16.10.1:8080") work := func() { drone.TakeOff() gobot.After(5*time.Second, func() { drone.Land() }) } robot := gobot.NewRobot("hs200", []gobot.Connection{}, []gobot.Device{drone}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/jetson-nano_blink.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/jetson" ) func main() { r := jetson.NewAdaptor() led := gpio.NewLedDriver(r, "40") work := func() { gobot.Every(1*time.Second, func() { if err := led.Toggle(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("blinkBot", []gobot.Connection{r}, []gobot.Device{led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/jetson-nano_servo.go ================================================ //go:build example // +build example // // Do not build by default. //nolint:gosec // ok here package main // // before to run // 1. check Jetson io pwm pin configure `sudo /opt/nvidia/jetson-io/jetson-io.py` // 2. if end pin configure, reboot Jetson nano. // 3. run gobot import ( "fmt" "log" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/jetson" ) func main() { jetsonAdaptor := jetson.NewAdaptor() servo := gpio.NewServoDriver(jetsonAdaptor, "32") counter := 0 flg := true work := func() { gobot.Every(100*time.Millisecond, func() { log.Println("Turning", counter) if err := servo.Move(uint8(counter)); err != nil { fmt.Println(err) } switch counter { case 140: flg = false case 30: flg = true } if flg { counter = counter + 1 } else { counter = counter - 1 } }) } robot := gobot.NewRobot("Jetsonservo", []gobot.Connection{jetsonAdaptor}, []gobot.Device{servo}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/joule_blink.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/intel-iot/joule" ) func main() { e := joule.NewAdaptor() led := gpio.NewLedDriver(e, "GP100") work := func() { gobot.Every(1*time.Second, func() { if err := led.Toggle(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("blinkBot", []gobot.Connection{e}, []gobot.Device{led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/joule_blinkm.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/intel-iot/joule" ) func main() { e := joule.NewAdaptor() blinkm := i2c.NewBlinkMDriver(e, i2c.WithBus(0), i2c.WithAddress(0x09)) work := func() { gobot.Every(1*time.Second, func() { r := byte(gobot.Rand(255)) g := byte(gobot.Rand(255)) b := byte(gobot.Rand(255)) if err := blinkm.Rgb(r, g, b); err != nil { fmt.Println(err) } color, err := blinkm.Color() if err != nil { fmt.Println(err) } fmt.Printf("color %v\n", color) }) } robot := gobot.NewRobot("blinkmBot", []gobot.Connection{e}, []gobot.Device{blinkm}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/joule_grove_lcd.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/intel-iot/joule" ) func main() { board := joule.NewAdaptor() screen := i2c.NewGroveLcdDriver(board) work := func() { if err := screen.Write("hello"); err != nil { fmt.Println(err) } if err := screen.SetRGB(255, 0, 0); err != nil { fmt.Println(err) } gobot.After(5*time.Second, func() { if err := screen.Clear(); err != nil { fmt.Println(err) } if err := screen.Home(); err != nil { fmt.Println(err) } if err := screen.SetRGB(0, 255, 0); err != nil { fmt.Println(err) } // set a custom character in the first position if err := screen.SetCustomChar(0, i2c.CustomLCDChars["smiley"]); err != nil { fmt.Println(err) } // add the custom character at the end of the string if err := screen.Write("goodbye\nhave a nice day " + string(byte(0))); err != nil { fmt.Println(err) } gobot.Every(500*time.Millisecond, func() { if err := screen.Scroll(false); err != nil { fmt.Println(err) } }) }) if err := screen.Home(); err != nil { fmt.Println(err) } time.Sleep(1 * time.Second) if err := screen.SetRGB(0, 0, 255); err != nil { fmt.Println(err) } } robot := gobot.NewRobot("screenBot", []gobot.Connection{board}, []gobot.Device{screen}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/joule_grove_rotary_sensor.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/intel-iot/joule" ) func main() { board := joule.NewAdaptor() ads1015 := i2c.NewADS1015Driver(board) sensor := aio.NewGroveRotaryDriver(ads1015, "0", aio.WithSensorCyclicRead(500*time.Millisecond)) work := func() { _ = sensor.On(aio.Data, func(data interface{}) { fmt.Println("sensor", data) }) } robot := gobot.NewRobot("sensorBot", []gobot.Connection{board}, []gobot.Device{ads1015, sensor}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/joule_led_brightness.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/intel-iot/joule" ) func main() { e := joule.NewAdaptor() led := gpio.NewLedDriver(e, "J12_26") work := func() { brightness := uint8(0) fadeAmount := uint8(15) gobot.Every(100*time.Millisecond, func() { if err := led.Brightness(brightness); err != nil { fmt.Println(err) } brightness = brightness + fadeAmount if brightness == 0 || brightness == 255 { fadeAmount = -fadeAmount } }) } robot := gobot.NewRobot("pwmBot", []gobot.Connection{e}, []gobot.Device{led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/joule_led_brightness_with_analog_input.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/intel-iot/joule" ) func main() { e := joule.NewAdaptor() ads1015 := i2c.NewADS1015Driver(e) sensor := aio.NewAnalogSensorDriver(ads1015, "0", aio.WithSensorCyclicRead(500*time.Millisecond)) led := gpio.NewLedDriver(e, "J12_26") work := func() { _ = sensor.On(aio.Data, func(data interface{}) { brightness := uint8(gobot.ToScale(gobot.FromScale(float64(data.(int)), 0, 1023), 0, 255)) fmt.Println("sensor", data) fmt.Println("brightness", brightness) if err := led.Brightness(brightness); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("sensorBot", []gobot.Connection{e}, []gobot.Device{ads1015, sensor, led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/joule_leds.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/intel-iot/joule" ) func main() { e := joule.NewAdaptor() led0 := gpio.NewLedDriver(e, "GP100") led1 := gpio.NewLedDriver(e, "GP101") led2 := gpio.NewLedDriver(e, "GP102") led3 := gpio.NewLedDriver(e, "GP103") work := func() { if err := led0.Off(); err != nil { fmt.Println(err) } if err := led1.Off(); err != nil { fmt.Println(err) } if err := led2.Off(); err != nil { fmt.Println(err) } if err := led3.Off(); err != nil { fmt.Println(err) } gobot.Every(1*time.Second, func() { if err := led0.Toggle(); err != nil { fmt.Println(err) } }) gobot.Every(2*time.Second, func() { if err := led1.Toggle(); err != nil { fmt.Println(err) } }) gobot.Every(4*time.Second, func() { if err := led2.Toggle(); err != nil { fmt.Println(err) } }) gobot.Every(8*time.Second, func() { if err := led3.Toggle(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("blinkBot", []gobot.Connection{e}, []gobot.Device{led0, led1, led2, led3}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/joystick_ps3.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/joystick" ) func main() { joystickAdaptor := joystick.NewAdaptor("0") stick := joystick.NewDriver(joystickAdaptor, joystick.Dualshock3) work := func() { // buttons _ = stick.On(joystick.SquarePress, func(data interface{}) { fmt.Println("square_press") }) _ = stick.On(joystick.SquareRelease, func(data interface{}) { fmt.Println("square_release") }) _ = stick.On(joystick.TrianglePress, func(data interface{}) { fmt.Println("triangle_press") }) _ = stick.On(joystick.TriangleRelease, func(data interface{}) { fmt.Println("triangle_release") }) _ = stick.On(joystick.CirclePress, func(data interface{}) { fmt.Println("circle_press") }) _ = stick.On(joystick.CircleRelease, func(data interface{}) { fmt.Println("circle_release") }) _ = stick.On(joystick.XPress, func(data interface{}) { fmt.Println("x_press") }) _ = stick.On(joystick.XRelease, func(data interface{}) { fmt.Println("x_release") }) _ = stick.On(joystick.StartPress, func(data interface{}) { fmt.Println("start_press") }) _ = stick.On(joystick.StartRelease, func(data interface{}) { fmt.Println("start_release") }) _ = stick.On(joystick.SelectPress, func(data interface{}) { fmt.Println("select_press") }) _ = stick.On(joystick.SelectRelease, func(data interface{}) { fmt.Println("select_release") }) _ = stick.On(joystick.HomePress, func(data interface{}) { fmt.Println("home_press") }) _ = stick.On(joystick.HomeRelease, func(data interface{}) { fmt.Println("home_release") }) _ = stick.On(joystick.RightPress, func(data interface{}) { fmt.Println("right_press") }) _ = stick.On(joystick.RightRelease, func(data interface{}) { fmt.Println("right_release") }) _ = stick.On(joystick.LeftPress, func(data interface{}) { fmt.Println("left_press") }) _ = stick.On(joystick.LeftRelease, func(data interface{}) { fmt.Println("left_release") }) _ = stick.On(joystick.UpPress, func(data interface{}) { fmt.Println("up_press") }) _ = stick.On(joystick.UpRelease, func(data interface{}) { fmt.Println("up_release") }) _ = stick.On(joystick.DownPress, func(data interface{}) { fmt.Println("down_press") }) _ = stick.On(joystick.DownRelease, func(data interface{}) { fmt.Println("down_release") }) // joysticks _ = stick.On(joystick.LeftX, func(data interface{}) { fmt.Println("left_x", data) }) _ = stick.On(joystick.LeftY, func(data interface{}) { fmt.Println("left_y", data) }) _ = stick.On(joystick.RightX, func(data interface{}) { fmt.Println("right_x", data) }) _ = stick.On(joystick.RightY, func(data interface{}) { fmt.Println("right_y", data) }) // triggers _ = stick.On(joystick.R1Press, func(data interface{}) { fmt.Println("R1Press", data) }) _ = stick.On(joystick.R1Release, func(data interface{}) { fmt.Println("R1Release", data) }) _ = stick.On(joystick.R2Press, func(data interface{}) { fmt.Println("R2Press", data) }) _ = stick.On(joystick.R2Release, func(data interface{}) { fmt.Println("R2Release", data) }) _ = stick.On(joystick.L1Press, func(data interface{}) { fmt.Println("L1Press", data) }) _ = stick.On(joystick.L1Release, func(data interface{}) { fmt.Println("L1Release", data) }) _ = stick.On(joystick.L2Press, func(data interface{}) { fmt.Println("L2Press", data) }) _ = stick.On(joystick.L2Release, func(data interface{}) { fmt.Println("L2Release", data) }) } robot := gobot.NewRobot("joystickBot", []gobot.Connection{joystickAdaptor}, []gobot.Device{stick}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/joystick_ps4.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/joystick" ) func main() { joystickAdaptor := joystick.NewAdaptor("0") stick := joystick.NewDriver(joystickAdaptor, joystick.Dualshock4) work := func() { _ = stick.On(joystick.SquarePress, func(data interface{}) { fmt.Println("square_press") }) _ = stick.On(joystick.SquareRelease, func(data interface{}) { fmt.Println("square_release") }) _ = stick.On(joystick.TrianglePress, func(data interface{}) { fmt.Println("triangle_press") }) _ = stick.On(joystick.TriangleRelease, func(data interface{}) { fmt.Println("triangle_release") }) _ = stick.On(joystick.CirclePress, func(data interface{}) { fmt.Println("circle_press") }) _ = stick.On(joystick.CircleRelease, func(data interface{}) { fmt.Println("circle_release") }) _ = stick.On(joystick.XPress, func(data interface{}) { fmt.Println("x_press") }) _ = stick.On(joystick.XRelease, func(data interface{}) { fmt.Println("x_release") }) _ = stick.On(joystick.HomePress, func(data interface{}) { fmt.Println("home_press") }) _ = stick.On(joystick.HomeRelease, func(data interface{}) { fmt.Println("home_release") }) _ = stick.On(joystick.SharePress, func(data interface{}) { fmt.Println("share_press") }) _ = stick.On(joystick.ShareRelease, func(data interface{}) { fmt.Println("share_release") }) _ = stick.On(joystick.OptionsPress, func(data interface{}) { fmt.Println("options_press") }) _ = stick.On(joystick.OptionsRelease, func(data interface{}) { fmt.Println("options_release") }) _ = stick.On(joystick.L1Press, func(data interface{}) { fmt.Println("l1_press") }) _ = stick.On(joystick.L1Release, func(data interface{}) { fmt.Println("l1_release") }) _ = stick.On(joystick.L2Press, func(data interface{}) { fmt.Println("l2_press") }) _ = stick.On(joystick.L2Release, func(data interface{}) { fmt.Println("l2_release") }) _ = stick.On(joystick.R1Press, func(data interface{}) { fmt.Println("r1_press") }) _ = stick.On(joystick.R1Release, func(data interface{}) { fmt.Println("r1_release") }) _ = stick.On(joystick.R2Press, func(data interface{}) { fmt.Println("r2_press") }) _ = stick.On(joystick.R2Release, func(data interface{}) { fmt.Println("r2_release") }) _ = stick.On(joystick.UpPress, func(data interface{}) { fmt.Println("up_press") }) _ = stick.On(joystick.UpRelease, func(data interface{}) { fmt.Println("up_release") }) _ = stick.On(joystick.DownPress, func(data interface{}) { fmt.Println("down_press") }) _ = stick.On(joystick.DownRelease, func(data interface{}) { fmt.Println("down_release") }) _ = stick.On(joystick.RightPress, func(data interface{}) { fmt.Println("right_press") }) _ = stick.On(joystick.RightRelease, func(data interface{}) { fmt.Println("right_release") }) _ = stick.On(joystick.LeftPress, func(data interface{}) { fmt.Println("left_press") }) _ = stick.On(joystick.LeftRelease, func(data interface{}) { fmt.Println("left_release") }) _ = stick.On(joystick.LeftX, func(data interface{}) { fmt.Println("left_x", data) }) _ = stick.On(joystick.LeftY, func(data interface{}) { fmt.Println("left_y", data) }) _ = stick.On(joystick.RightX, func(data interface{}) { fmt.Println("right_x", data) }) _ = stick.On(joystick.RightY, func(data interface{}) { fmt.Println("right_y", data) }) _ = stick.On(joystick.L2, func(data interface{}) { fmt.Println("L2", data) }) _ = stick.On(joystick.R2, func(data interface{}) { fmt.Println("R2", data) }) } robot := gobot.NewRobot("joystickBot", []gobot.Connection{joystickAdaptor}, []gobot.Device{stick}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/joystick_ps5.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/joystick" ) func main() { joystickAdaptor := joystick.NewAdaptor("0") stick := joystick.NewDriver(joystickAdaptor, joystick.Dualsense) work := func() { _ = stick.On(joystick.SquarePress, func(data interface{}) { fmt.Println("square_press") }) _ = stick.On(joystick.SquareRelease, func(data interface{}) { fmt.Println("square_release") }) _ = stick.On(joystick.TrianglePress, func(data interface{}) { fmt.Println("triangle_press") }) _ = stick.On(joystick.TriangleRelease, func(data interface{}) { fmt.Println("triangle_release") }) _ = stick.On(joystick.CirclePress, func(data interface{}) { fmt.Println("circle_press") }) _ = stick.On(joystick.CircleRelease, func(data interface{}) { fmt.Println("circle_release") }) _ = stick.On(joystick.XPress, func(data interface{}) { fmt.Println("x_press") }) _ = stick.On(joystick.XRelease, func(data interface{}) { fmt.Println("x_release") }) _ = stick.On(joystick.HomePress, func(data interface{}) { fmt.Println("home_press") }) _ = stick.On(joystick.HomeRelease, func(data interface{}) { fmt.Println("home_release") }) _ = stick.On(joystick.CreatePress, func(data interface{}) { fmt.Println("create_press") }) _ = stick.On(joystick.CreateRelease, func(data interface{}) { fmt.Println("create_release") }) _ = stick.On(joystick.OptionsPress, func(data interface{}) { fmt.Println("options_press") }) _ = stick.On(joystick.OptionsRelease, func(data interface{}) { fmt.Println("options_release") }) _ = stick.On(joystick.L1Press, func(data interface{}) { fmt.Println("l1_press") }) _ = stick.On(joystick.L1Release, func(data interface{}) { fmt.Println("l1_release") }) _ = stick.On(joystick.R1Press, func(data interface{}) { fmt.Println("r1_press") }) _ = stick.On(joystick.R1Release, func(data interface{}) { fmt.Println("r1_release") }) _ = stick.On(joystick.PSPress, func(data interface{}) { fmt.Println("ps_press") }) _ = stick.On(joystick.PSRelease, func(data interface{}) { fmt.Println("ps_release") }) _ = stick.On(joystick.TrackpadPress, func(data interface{}) { fmt.Println("trackpad_press") }) _ = stick.On(joystick.TrackpadRelease, func(data interface{}) { fmt.Println("trackpad_release") }) _ = stick.On(joystick.UpPress, func(data interface{}) { fmt.Println("up_press") }) _ = stick.On(joystick.UpRelease, func(data interface{}) { fmt.Println("up_release") }) _ = stick.On(joystick.DownPress, func(data interface{}) { fmt.Println("down_press") }) _ = stick.On(joystick.DownRelease, func(data interface{}) { fmt.Println("down_release") }) _ = stick.On(joystick.RightPress, func(data interface{}) { fmt.Println("right_press") }) _ = stick.On(joystick.RightRelease, func(data interface{}) { fmt.Println("right_release") }) _ = stick.On(joystick.LeftPress, func(data interface{}) { fmt.Println("left_press") }) _ = stick.On(joystick.LeftRelease, func(data interface{}) { fmt.Println("left_release") }) // _ = stick.On(joystick.LeftX, func(data interface{}) { // fmt.Println("left_x", data) // }) // _ = stick.On(joystick.LeftY, func(data interface{}) { // fmt.Println("left_y", data) // }) // _ = stick.On(joystick.RightX, func(data interface{}) { // fmt.Println("right_x", data) // }) // _ = stick.On(joystick.RightY, func(data interface{}) { // fmt.Println("right_y", data) // }) // _ = stick.On(joystick.L2, func(data interface{}) { // fmt.Println("L2", data) // }) // _ = stick.On(joystick.R2, func(data interface{}) { // fmt.Println("R2", data) // }) } robot := gobot.NewRobot("joystickBot", []gobot.Connection{joystickAdaptor}, []gobot.Device{stick}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/joystick_xbox360.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/joystick" ) func main() { joystickAdaptor := joystick.NewAdaptor("0") stick := joystick.NewDriver(joystickAdaptor, joystick.Xbox360) work := func() { _ = stick.On(joystick.APress, func(data interface{}) { fmt.Println("a_press") }) _ = stick.On(joystick.ARelease, func(data interface{}) { fmt.Println("a_release") }) _ = stick.On(joystick.BPress, func(data interface{}) { fmt.Println("b_press") }) _ = stick.On(joystick.BRelease, func(data interface{}) { fmt.Println("b_release") }) _ = stick.On(joystick.UpPress, func(data interface{}) { fmt.Println("up", data) }) _ = stick.On(joystick.DownPress, func(data interface{}) { fmt.Println("down", data) }) _ = stick.On(joystick.LeftPress, func(data interface{}) { fmt.Println("left", data) }) _ = stick.On(joystick.RightPress, func(data interface{}) { fmt.Println("right", data) }) _ = stick.On(joystick.LeftX, func(data interface{}) { fmt.Println("left_x", data) }) _ = stick.On(joystick.LeftY, func(data interface{}) { fmt.Println("left_y", data) }) _ = stick.On(joystick.RightX, func(data interface{}) { fmt.Println("right_x", data) }) _ = stick.On(joystick.RightY, func(data interface{}) { fmt.Println("right_y", data) }) } robot := gobot.NewRobot("joystickBot", []gobot.Connection{joystickAdaptor}, []gobot.Device{stick}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/joystick_xbox360_rock_band_drums.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/joystick" ) func main() { joystickAdaptor := joystick.NewAdaptor("0") stick := joystick.NewDriver(joystickAdaptor, joystick.Xbox360RockBandDrums) work := func() { _ = stick.On(joystick.RedPress, func(data interface{}) { fmt.Println("red_press") }) _ = stick.On(joystick.RedRelease, func(data interface{}) { fmt.Println("red_release") }) _ = stick.On(joystick.YellowPress, func(data interface{}) { fmt.Println("yellow_press") }) _ = stick.On(joystick.YellowRelease, func(data interface{}) { fmt.Println("yellow_release") }) _ = stick.On(joystick.BluePress, func(data interface{}) { fmt.Println("blue_press") }) _ = stick.On(joystick.BlueRelease, func(data interface{}) { fmt.Println("blue_release") }) _ = stick.On(joystick.GreenPress, func(data interface{}) { fmt.Println("green_press") }) _ = stick.On(joystick.GreenRelease, func(data interface{}) { fmt.Println("blue_release") }) _ = stick.On(joystick.PedalPress, func(data interface{}) { fmt.Println("pedal_press") }) _ = stick.On(joystick.PedalRelease, func(data interface{}) { fmt.Println("pedal_release") }) _ = stick.On(joystick.UpPress, func(data interface{}) { fmt.Println("up", data) }) _ = stick.On(joystick.DownPress, func(data interface{}) { fmt.Println("down", data) }) _ = stick.On(joystick.LeftPress, func(data interface{}) { fmt.Println("left", data) }) _ = stick.On(joystick.RightPress, func(data interface{}) { fmt.Println("right", data) }) } robot := gobot.NewRobot("joystickBot", []gobot.Connection{joystickAdaptor}, []gobot.Device{stick}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/joystick_xboxone.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/joystick" ) func main() { joystickAdaptor := joystick.NewAdaptor("0") joystick := joystick.NewDriver(joystickAdaptor, joystick.XboxOne) work := func() { // start button _ = joystick.On(joystick.Event("start_press"), func(data interface{}) { fmt.Println("start_press") }) _ = joystick.On(joystick.Event("start_release"), func(data interface{}) { fmt.Println("start_release") }) // back button _ = joystick.On(joystick.Event("back_press"), func(data interface{}) { fmt.Println("back_press") }) _ = joystick.On(joystick.Event("back_release"), func(data interface{}) { fmt.Println("back_release") }) // a button _ = joystick.On(joystick.Event("a_press"), func(data interface{}) { fmt.Println("a_press") }) _ = joystick.On(joystick.Event("a_release"), func(data interface{}) { fmt.Println("a_release") }) // b button _ = joystick.On(joystick.Event("b_press"), func(data interface{}) { fmt.Println("b_press") }) _ = joystick.On(joystick.Event("b_release"), func(data interface{}) { fmt.Println("b_release") }) // x button _ = joystick.On(joystick.Event("x_press"), func(data interface{}) { fmt.Println("x_press") }) _ = joystick.On(joystick.Event("x_release"), func(data interface{}) { fmt.Println("x_release") }) // y button _ = joystick.On(joystick.Event("y_press"), func(data interface{}) { fmt.Println("y_press") }) _ = joystick.On(joystick.Event("y_release"), func(data interface{}) { fmt.Println("y_release") }) // up dpad _ = joystick.On(joystick.Event("up_press"), func(data interface{}) { fmt.Println("up_press", data) }) _ = joystick.On(joystick.Event("up_release"), func(data interface{}) { fmt.Println("up_release", data) }) // down dpad _ = joystick.On(joystick.Event("down_press"), func(data interface{}) { fmt.Println("down_press") }) _ = joystick.On(joystick.Event("down_release"), func(data interface{}) { fmt.Println("down_release") }) // left dpad _ = joystick.On(joystick.Event("left_press"), func(data interface{}) { fmt.Println("left_press") }) _ = joystick.On(joystick.Event("left_release"), func(data interface{}) { fmt.Println("left_release") }) // right dpad _ = joystick.On(joystick.Event("right_press"), func(data interface{}) { fmt.Println("right_press") }) _ = joystick.On(joystick.Event("right_release"), func(data interface{}) { fmt.Println("right_release") }) // rt trigger _ = joystick.On(joystick.Event("rt"), func(data interface{}) { fmt.Println("rt", data) }) // lt trigger _ = joystick.On(joystick.Event("lt"), func(data interface{}) { fmt.Println("lt", data) }) // lb button _ = joystick.On(joystick.Event("lb_press"), func(data interface{}) { fmt.Println("lb_press") }) _ = joystick.On(joystick.Event("lb_release"), func(data interface{}) { fmt.Println("lb_release") }) // rb button _ = joystick.On(joystick.Event("rb_press"), func(data interface{}) { fmt.Println("rb_press") }) _ = joystick.On(joystick.Event("rb_release"), func(data interface{}) { fmt.Println("rb_release") }) // rx stick _ = joystick.On(joystick.Event("right_x"), func(data interface{}) { fmt.Println("right_x", data) }) // ry stick _ = joystick.On(joystick.Event("right_y"), func(data interface{}) { fmt.Println("right_y", data) }) // right_stick button _ = joystick.On(joystick.Event("right_stick_press"), func(data interface{}) { fmt.Println("right_stick_press") }) _ = joystick.On(joystick.Event("right_stick_release"), func(data interface{}) { fmt.Println("right_stick_release") }) // lx stick _ = joystick.On(joystick.Event("left_x"), func(data interface{}) { fmt.Println("left_x", data) }) // ly stick _ = joystick.On(joystick.Event("left_y"), func(data interface{}) { fmt.Println("left_y", data) }) // left_stick button _ = joystick.On(joystick.Event("left_stick_press"), func(data interface{}) { fmt.Println("left_stick_press") }) _ = joystick.On(joystick.Event("left_stick_release"), func(data interface{}) { fmt.Println("left_stick_release") }) } robot := gobot.NewRobot("joystickBot", []gobot.Connection{joystickAdaptor}, []gobot.Device{joystick}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/keyboard.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/keyboard" ) func main() { keys := keyboard.NewDriver() work := func() { _ = keys.On(keyboard.Key, func(data interface{}) { key := data.(keyboard.KeyEvent) if key.Key == keyboard.A { fmt.Println("A pressed!") } else { fmt.Println("keyboard event!", key, key.Char) } }) } robot := gobot.NewRobot("keyboardbot", []gobot.Connection{}, []gobot.Device{keys}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/keyboard_mqtt.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/keyboard" "gobot.io/x/gobot/v2/platforms/mqtt" ) func main() { keys := keyboard.NewDriver() mqttAdaptor := mqtt.NewAdaptor("tcp://iot.eclipse.org:1883", "conductor") work := func() { _ = keys.On(keyboard.Key, func(data interface{}) { key := data.(keyboard.KeyEvent) switch key.Key { case keyboard.ArrowUp: mqttAdaptor.Publish("rover/frente", []byte{}) case keyboard.ArrowRight: mqttAdaptor.Publish("rover/derecha", []byte{}) case keyboard.ArrowDown: mqttAdaptor.Publish("rover/atras", []byte{}) case keyboard.ArrowLeft: mqttAdaptor.Publish("rover/izquierda", []byte{}) } }) } robot := gobot.NewRobot("keyboardbot", []gobot.Connection{mqttAdaptor}, []gobot.Device{keys}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/leap_motion.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/leap" ) func main() { leapMotionAdaptor := leap.NewAdaptor("127.0.0.1:6437") l := leap.NewDriver(leapMotionAdaptor) work := func() { _ = l.On(leap.MessageEvent, func(data interface{}) { fmt.Println(data.(leap.Frame)) }) } robot := gobot.NewRobot("leapBot", []gobot.Connection{leapMotionAdaptor}, []gobot.Device{l}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/leap_motion_gestures.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/leap" ) func main() { leapMotionAdaptor := leap.NewAdaptor("127.0.0.1:6437") l := leap.NewDriver(leapMotionAdaptor) work := func() { _ = l.On(leap.GestureEvent, func(data interface{}) { printGesture(data.(leap.Gesture)) }) } robot := gobot.NewRobot("leapBot", []gobot.Connection{leapMotionAdaptor}, []gobot.Device{l}, work, ) if err := robot.Start(); err != nil { panic(err) } } func printGesture(gesture leap.Gesture) { fmt.Println("Gesture", gesture) } ================================================ FILE: examples/leap_motion_hands.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/leap" ) func main() { leapMotionAdaptor := leap.NewAdaptor("127.0.0.1:6437") l := leap.NewDriver(leapMotionAdaptor) work := func() { _ = l.On(leap.HandEvent, func(data interface{}) { printHand(data.(leap.Hand)) }) } robot := gobot.NewRobot("leapBot", []gobot.Connection{leapMotionAdaptor}, []gobot.Device{l}, work, ) if err := robot.Start(); err != nil { panic(err) } } func printHand(hand leap.Hand) { fmt.Println("Hand", hand) } ================================================ FILE: examples/leap_servos.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/firmata" "gobot.io/x/gobot/v2/platforms/leap" ) // Video: https://www.youtube.com/watch?v=ayNMyUfdAqc func main() { firmataAdaptor := firmata.NewAdaptor("/dev/tty.usbmodem1451") servo1 := gpio.NewServoDriver(firmataAdaptor, "3") servo2 := gpio.NewServoDriver(firmataAdaptor, "4") servo3 := gpio.NewServoDriver(firmataAdaptor, "5") servo4 := gpio.NewServoDriver(firmataAdaptor, "6") servo5 := gpio.NewServoDriver(firmataAdaptor, "7") leapMotionAdaptor := leap.NewAdaptor("127.0.0.1:6437") l := leap.NewDriver(leapMotionAdaptor) work := func() { fist := false _ = l.On(leap.MessageEvent, func(data interface{}) { handIsOpen := len(data.(leap.Frame).Pointables) > 0 if handIsOpen && fist { if err := servo1.Move(0); err != nil { fmt.Println(err) } if err := servo2.Move(0); err != nil { fmt.Println(err) } if err := servo3.Move(0); err != nil { fmt.Println(err) } if err := servo4.Move(0); err != nil { fmt.Println(err) } if err := servo5.Move(0); err != nil { fmt.Println(err) } fist = false } else if !handIsOpen && !fist { if err := servo1.Move(120); err != nil { fmt.Println(err) } if err := servo2.Move(120); err != nil { fmt.Println(err) } if err := servo3.Move(120); err != nil { fmt.Println(err) } if err := servo4.Move(120); err != nil { fmt.Println(err) } if err := servo5.Move(120); err != nil { fmt.Println(err) } fist = true } }) } robot := gobot.NewRobot("servoBot", []gobot.Connection{firmataAdaptor, leapMotionAdaptor}, []gobot.Device{servo1, servo2, servo3, servo4, servo5, l}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/leap_sphero.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "math" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/serial/sphero" "gobot.io/x/gobot/v2/platforms/leap" "gobot.io/x/gobot/v2/platforms/serialport" ) func main() { leapAdaptor := leap.NewAdaptor("127.0.0.1:6437") spheroAdaptor := serialport.NewAdaptor("/dev/tty.Sphero-YBW-RN-SPP") leapDriver := leap.NewDriver(leapAdaptor) spheroDriver := sphero.NewSpheroDriver(spheroAdaptor) work := func() { _ = leapDriver.On(leap.MessageEvent, func(data interface{}) { hands := data.(leap.Frame).Hands if len(hands) > 0 { x := math.Abs(hands[0].Direction[0]) y := math.Abs(hands[0].Direction[1]) z := math.Abs(hands[0].Direction[2]) spheroDriver.SetRGB(scale(x), scale(y), scale(z)) } }) } robot := gobot.NewRobot("leapBot", []gobot.Connection{leapAdaptor, spheroAdaptor}, []gobot.Device{leapDriver, spheroDriver}, work, ) if err := robot.Start(); err != nil { panic(err) } } func scale(position float64) uint8 { return uint8(gobot.ToScale(gobot.FromScale(position, 0, 1), 0, 255)) } ================================================ FILE: examples/mavlink.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/mavlink" common "gobot.io/x/gobot/v2/platforms/mavlink/common" ) func main() { adaptor := mavlink.NewAdaptor("/dev/ttyACM0") iris := mavlink.NewDriver(adaptor) work := func() { _ = iris.Once(mavlink.PacketEvent, func(data interface{}) { packet := data.(*common.MAVLinkPacket) dataStream := common.NewRequestDataStream(100, packet.SystemID, packet.ComponentID, 4, 1, ) if err := iris.SendPacket( common.CraftMAVLinkPacket(packet.SystemID, packet.ComponentID, dataStream)); err != nil { fmt.Println(err) } }) _ = iris.On(mavlink.MessageEvent, func(data interface{}) { if data.(common.MAVLinkMessage).Id() == 30 { message := data.(*common.Attitude) fmt.Println("Attitude") fmt.Println("TIME_BOOT_MS", message.TIME_BOOT_MS) fmt.Println("ROLL", message.ROLL) fmt.Println("PITCH", message.PITCH) fmt.Println("YAW", message.YAW) fmt.Println("ROLLSPEED", message.ROLLSPEED) fmt.Println("PITCHSPEED", message.PITCHSPEED) fmt.Println("YAWSPEED", message.YAWSPEED) fmt.Println("") } }) } robot := gobot.NewRobot("mavBot", []gobot.Connection{adaptor}, []gobot.Device{iris}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/metal_button.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/intel-iot/edison" ) func main() { e := edison.NewAdaptor() if err := e.Connect(); err != nil { fmt.Println(err) } led := gpio.NewLedDriver(e, "13") if err := led.Start(); err != nil { fmt.Println(err) } if err := led.Off(); err != nil { fmt.Println(err) } button := gpio.NewButtonDriver(e, "5") if err := button.Start(); err != nil { fmt.Println(err) } buttonEvents := button.Subscribe() for event := range buttonEvents { fmt.Println("Event:", event.Name, event.Data) if event.Name == gpio.ButtonPush { if err := led.Toggle(); err != nil { fmt.Println(err) } } } } ================================================ FILE: examples/mqtt_driver_ping.go ================================================ //go:build example // +build example // // Do not build by default. // TO RUN: // // go run ./examples/mqtt_driver_ping.go // // EXAMPLE: // // go run ./examples/mqtt_driver_ping.go ssl://iot.eclipse.org:8883 package main import ( "fmt" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/mqtt" ) func main() { mqttAdaptor := mqtt.NewAdaptor(os.Args[1], "pinger") mqttAdaptor.SetAutoReconnect(true) holaDriver := mqtt.NewDriver(mqttAdaptor, "hola") helloDriver := mqtt.NewDriver(mqttAdaptor, "hello") work := func() { _ = helloDriver.On(mqtt.Data, func(data interface{}) { fmt.Println("hello") }) _ = holaDriver.On(mqtt.Data, func(data interface{}) { fmt.Println("hola") }) data := []byte("o") gobot.Every(1*time.Second, func() { helloDriver.Publish(data) }) gobot.Every(5*time.Second, func() { holaDriver.Publish(data) }) } robot := gobot.NewRobot("mqttBot", []gobot.Connection{mqttAdaptor}, []gobot.Device{helloDriver, holaDriver}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/mqtt_firmata_blink.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/firmata" "gobot.io/x/gobot/v2/platforms/mqtt" ) func main() { mqttAdaptor := mqtt.NewAdaptor("tcp://test.mosquitto.org:1883", "blinker") firmataAdaptor := firmata.NewAdaptor("/dev/ttyACM0") led := gpio.NewLedDriver(firmataAdaptor, "13") work := func() { _ = mqttAdaptor.On("lights/on", func(msg mqtt.Message) { if err := led.On(); err != nil { fmt.Println(err) } }) _ = mqttAdaptor.On("lights/off", func(msg mqtt.Message) { if err := led.Off(); err != nil { fmt.Println(err) } }) data := []byte("") gobot.Every(1*time.Second, func() { mqttAdaptor.Publish("lights/on", data) }) gobot.Every(2*time.Second, func() { mqttAdaptor.Publish("lights/off", data) }) } robot := gobot.NewRobot("mqttBot", []gobot.Connection{mqttAdaptor, firmataAdaptor}, []gobot.Device{led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/mqtt_ping.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/mqtt" ) func main() { mqttAdaptor := mqtt.NewAdaptor("tcp://test.mosquitto.org:1883", "pinger") work := func() { _ = mqttAdaptor.On("hello", func(msg mqtt.Message) { fmt.Println("hello") }) _ = mqttAdaptor.On("hola", func(msg mqtt.Message) { fmt.Println("hola") }) data := []byte("o") gobot.Every(1*time.Second, func() { mqttAdaptor.Publish("hello", data) }) gobot.Every(5*time.Second, func() { mqttAdaptor.Publish("hola", data) }) } robot := gobot.NewRobot("mqttBot", []gobot.Connection{mqttAdaptor}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/nanopct6_direct_pin.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/adaptors" "gobot.io/x/gobot/v2/platforms/friendlyelec/nanopct6" ) // Wiring // PWR : 1, 17 (+3.3V, VCC), 2, 4 (+5V), 6, 9, 14, 20, 25, 30, 34, 39 (GND) // GPIO : header pin 36 is input, pin 37 used as normal output, pin 38 used as inverted output // Button: the input pin is wired with a button to GND, the internal pull up resistor is used // LED's: the output pins are wired to the cathode of the LED, the anode is wired with a resistor (70-130Ohm for 20mA) // to VCC // Expected behavior: always one LED is on, the other in opposite state, if button is pressed for >2 seconds the state // changes func main() { const ( inPinNum = "36" outPinNum = "37" outPinInvertedNum = "38" debounceTime = 2 * time.Second ) // note: WithGpiosOpenDrain() is optional, if using WithGpiosOpenSource() the LED's will not light up board := nanopct6.NewAdaptor(adaptors.WithGpiosActiveLow(outPinInvertedNum), adaptors.WithGpiosOpenDrain(outPinNum, outPinInvertedNum), adaptors.WithGpiosPullUp(inPinNum), adaptors.WithGpioDebounce(inPinNum, debounceTime)) inPin := gpio.NewDirectPinDriver(board, inPinNum) outPin := gpio.NewDirectPinDriver(board, outPinNum) outPinInverted := gpio.NewDirectPinDriver(board, outPinInvertedNum) work := func() { level := byte(1) gobot.Every(500*time.Millisecond, func() { read, err := inPin.DigitalRead() fmt.Printf("pin %s state is %d\n", inPinNum, read) if err != nil { fmt.Println(err) if level == 1 { level = 0 } else { level = 1 } } else { level = byte(read) } err = outPin.DigitalWrite(level) fmt.Printf("pin %s is now %d\n", outPinNum, level) if err != nil { fmt.Println(err) } err = outPinInverted.DigitalWrite(level) fmt.Printf("pin %s is now not %d\n", outPinInvertedNum, level) if err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("pinBot", []gobot.Connection{board}, []gobot.Device{inPin, outPin, outPinInverted}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/nanopct6_ds18b20.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "log" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/onewire" "gobot.io/x/gobot/v2/platforms/friendlyelec/nanopct6" ) // Preparation: see /gobot/system/ONEWIRE.md // // Wiring: // PWR : 1, 17 (+3.3V, VCC), 6, 9, 14, 20, 25, 30, 34, 39 (GND) // 1-wire : 16 (DQ) - resistor to VCC, ~1.5kOhm ... 5kOhm // DS18B20: 1 (GND), 2 (DQ), 3 (VDD, +3 ... 5.5V) for local power mode func main() { adaptor := nanopct6.NewAdaptor() // resolution change not supported by all devices temp0 := onewire.NewDS18B20Driver(adaptor, 0xde5e710a6461, onewire.WithResolution(12)) temp1 := onewire.NewDS18B20Driver(adaptor, 0x1e40710a6461, onewire.WithFahrenheit(), onewire.WithConversionTime(500)) work := func() { time0, err := temp0.ConversionTime() if err != nil { log.Printf("Err CT0: %v\n", err) } res0, err := temp0.Resolution() if err != nil { log.Printf("Err R0: %v\n", err) } log.Printf("Conversion time @%d bit for Temp 0: %d ms\n", res0, time0) time1, err := temp1.ConversionTime() if err != nil { log.Printf("Err CT1: %v\n", err) } res1, err := temp1.Resolution() if err != nil { log.Printf("Err R1: %v\n", err) } log.Printf("Conversion time @%d bit for Temp 0: %d ms\n", res1, time1) gobot.Every(10*(time.Duration(time0))*time.Millisecond, func() { t0, err := temp0.Temperature() if err != nil { log.Printf("Err Temp 0: %v\n", err) } fmt.Printf("Temp 0: %2.1f °C\n", t0) }) gobot.Every(10*(time.Duration(time1))*time.Millisecond, func() { t1, err := temp1.Temperature() if err != nil { log.Printf("Err Temp 1: %v\n", err) } fmt.Printf("Temp 1: %2.3f °F\n", t1) }) } robot := gobot.NewRobot("onewireBot", []gobot.Connection{adaptor}, []gobot.Device{temp0, temp1}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/nanopct6_servo.go ================================================ //go:build example // +build example // Do not build by default. package main import ( "fmt" "log" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/adaptors" "gobot.io/x/gobot/v2/platforms/friendlyelec/nanopct6" ) // Wiring // PWR: 1, 17 (+3.3V, VCC), 2, 4 (+5V), 6, 9, 14, 20, 25, 30, 34, 39 (GND) // PWM: header pin 11 (pwm14-m0), 13 (pwm15-m0), 29 (pwm12-m0), 31 (pwm13-m0), 35 (pwm10-m0) // Servo SG90: red (+5V), brown (GND), orange (PWM) func main() { const ( pwmPin = "35" wait = 3 * time.Second fiftyHzNanos = 20 * 1000 * 1000 // 50Hz = 0.02 sec = 20 ms ) // usually a frequency of 50Hz is used for servos, most servos have 0.5 ms..2.5 ms for 0-180°, // however the mapping can be changed with options: adaptor := nanopct6.NewAdaptor( adaptors.WithPWMDefaultPeriodForPin(pwmPin, fiftyHzNanos), adaptors.WithPWMServoDutyCycleRangeForPin(pwmPin, 500*time.Microsecond, 2500*time.Microsecond), adaptors.WithPWMServoAngleRangeForPin(pwmPin, 0, 180), ) servo := gpio.NewServoDriver(adaptor, pwmPin) work := func() { fmt.Printf("first move to minimal position for %s...\n", wait) if err := servo.ToMin(); err != nil { log.Println(err) } time.Sleep(wait) fmt.Printf("second move to center position for %s...\n", wait) if err := servo.ToCenter(); err != nil { log.Println(err) } time.Sleep(wait) fmt.Printf("third move to maximal position for %s...\n", wait) if err := servo.ToMax(); err != nil { log.Println(err) } time.Sleep(wait) fmt.Println("finally move 0-180° (or what your servo do for the new mapping) and back forever...") angle := 0 fadeAmount := 45 gobot.Every(time.Second, func() { if err := servo.Move(byte(angle)); err != nil { log.Println(err) } angle = angle + fadeAmount if angle < 0 || angle > 180 { if angle < 0 { angle = 0 } if angle > 180 { angle = 180 } // change direction and recalculate fadeAmount = -fadeAmount angle = angle + fadeAmount } }) } robot := gobot.NewRobot("motorBot", []gobot.Connection{adaptor}, []gobot.Device{servo}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/nanopct6_thermalzone.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "log" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" "gobot.io/x/gobot/v2/platforms/friendlyelec/nanopct6" ) // Wiring: no wiring needed func main() { adaptor := nanopct6.NewAdaptor() therm0 := aio.NewThermalZoneDriver(adaptor, "soc_thermal") therm1 := aio.NewThermalZoneDriver(adaptor, "npu_thermal", aio.WithFahrenheit()) work := func() { gobot.Every(500*time.Millisecond, func() { t0, err := therm0.Read() if err != nil { log.Println(err) } t1, err := therm1.Read() if err != nil { log.Println(err) } fmt.Printf("SOC: %2.3f °C, NPU: %2.3f °F\n", t0, t1) }) } robot := gobot.NewRobot("thermalBot", []gobot.Connection{adaptor}, []gobot.Device{therm0, therm1}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/nanopct6_yl40.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "log" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/friendlyelec/nanopct6" ) func main() { // Wiring // PWR : 1, 17 (+3.3V, VCC), 6, 9, 14, 20, 25, 30, 34, 39 (GND) // I2C8: 3 (SDA), 5 (SCL) // YL-40 module: wire AOUT --> AIN2 for this example, set all jumpers for temp, LDR and variable resistor // // Note: temperature measurement is often buggy, because sensor is not properly grounded // fix it by soldering a small bridge to the adjacent ground pin of brightness sensor board := nanopct6.NewAdaptor() yl := i2c.NewYL40Driver(board, i2c.WithBus(8)) work := func() { // the LED light is visible above ~1.7V writeVal, _ := yl.AOUT() gobot.Every(1000*time.Millisecond, func() { if err := yl.Write(writeVal); err != nil { fmt.Println(err) } else { log.Printf(" %.1f V written", writeVal) writeVal = writeVal + 0.1 if writeVal > 3.3 { writeVal = 0 } } if brightness, err := yl.ReadBrightness(); err != nil { fmt.Println(err) } else { log.Printf("Brightness: %.0f [0..1000]", brightness) } if temperature, err := yl.ReadTemperature(); err != nil { fmt.Println(err) } else { log.Printf("Temperature: %.1f °C", temperature) } if ain2, err := yl.ReadAIN2(); err != nil { fmt.Println(err) } else { log.Printf("Read back AOUT: %.1f [0..3.3]", ain2) } if potiState, err := yl.ReadPotentiometer(); err != nil { fmt.Println(err) } else { log.Printf("Resistor: %.0f %% [-100..+100]", potiState) } }) } robot := gobot.NewRobot("yl40Bot", []gobot.Connection{board}, []gobot.Device{yl}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/nanopi_button.go ================================================ //go:build example // +build example // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/adaptors" "gobot.io/x/gobot/v2/platforms/friendlyelec/nanopi" ) // PWR NanoPi: 1, 17 (+3.3V, VCC); 2, 4 (+5V, VDD); 6, 9, 14, 20 (GND) // GPIO NanoPi: header pin 22 is input, pin 7 is normal output // Button: the input pin is wired with a button to GND, the internal pull up resistor is used // LED: the output pin is wired to the cathode of a LED, the anode is wired with a resistor (70-130Ohm for 20mA) to VCC // Expected behavior: LED is initially on, if button is pressed and released, the state changes func main() { const ( buttonPin = "22" ledPin = "7" ) a := nanopi.NewNeoAdaptor(adaptors.WithGpiosPullUp(buttonPin)) button := gpio.NewButtonDriver(a, buttonPin, gpio.WithButtonPollInterval(50*time.Millisecond)) led := gpio.NewLedDriver(a, ledPin) if err := led.On(); err != nil { fmt.Println(err) } work := func() { if err := button.On(gpio.Error, func(err interface{}) { fmt.Println("an error occurred:", err) }); err != nil { panic(err) } if err := button.On(gpio.ButtonPush, func(interface{}) { fmt.Println("button pressed") if err := led.On(); err != nil { fmt.Println(err) } }); err != nil { panic(err) } if err := button.On(gpio.ButtonRelease, func(interface{}) { fmt.Println("button released") if err := led.Off(); err != nil { fmt.Println(err) } }); err != nil { panic(err) } } robot := gobot.NewRobot("buttonBot", []gobot.Connection{a}, []gobot.Device{button, led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/nanopi_direct_pin.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/adaptors" "gobot.io/x/gobot/v2/platforms/friendlyelec/nanopi" ) // Wiring // PWR NanoPi: 1, 17 (+3.3V, VCC); 2, 4 (+5V, VDD); 6, 9, 14, 20 (GND) // GPIO NanoPi: header pin 22 is input, pin 23 is normal output, pin 24 is inverted output // Button: the input pin is wired with a button to GND, the internal pull up resistor is used // LED's: the output pins are wired to the cathode of the LED, the anode is wired with a resistor (70-130Ohm for 20mA) // to VCC // Expected behavior: always one LED is on, the other in opposite state, if button is pressed for >2 seconds the state // changes func main() { const ( inPinNum = "22" // 7, 8, 10, 11, 12, 13, 15, 16, 18, 22 outPinNum = "23" outPinInvertedNum = "24" debounceTime = 2 * time.Second ) // note: WithGpiosOpenDrain() is optional, if using WithGpiosOpenSource() the LED's will not light up board := nanopi.NewNeoAdaptor(adaptors.WithGpiosActiveLow(outPinInvertedNum), adaptors.WithGpiosOpenDrain(outPinNum, outPinInvertedNum), adaptors.WithGpiosPullUp(inPinNum), adaptors.WithGpioDebounce(inPinNum, debounceTime)) inPin := gpio.NewDirectPinDriver(board, inPinNum) outPin := gpio.NewDirectPinDriver(board, outPinNum) outPinInverted := gpio.NewDirectPinDriver(board, outPinInvertedNum) work := func() { level := byte(1) gobot.Every(500*time.Millisecond, func() { read, err := inPin.DigitalRead() fmt.Printf("pin %s state is %d\n", inPinNum, read) if err != nil { fmt.Println(err) if level == 1 { level = 0 } else { level = 1 } } else { level = byte(read) } err = outPin.DigitalWrite(level) fmt.Printf("pin %s is now %d\n", outPinNum, level) if err != nil { fmt.Println(err) } err = outPinInverted.DigitalWrite(level) fmt.Printf("pin %s is now not %d\n", outPinInvertedNum, level) if err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("pinBot", []gobot.Connection{board}, []gobot.Device{inPin, outPin, outPinInverted}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/nanopi_direct_pin_event.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/friendlyelec/nanopi" "gobot.io/x/gobot/v2/system" ) const ( inPinNum = "22" // 7, 8, 10, 11, 12, 13, 15, 16, 18, 22 outPinNum = "23" outPinInvertedNum = "24" debounceTime = 2 * time.Second ) var ( outPin gobot.DigitalPinner outPinInverted gobot.DigitalPinner ) // Wiring // PWR NanoPi: 1, 17 (+3.3V, VCC); 2, 4 (+5V, VDD); 6, 9, 14, 20 (GND) // GPIO NanoPi: header pin 22 is input, pin 23 is normal output, pin 24 is inverted output // Button: the input pin is wired with a button to GND, the internal pull up resistor is used // LED's: the output pins are wired to the cathode of a LED, the anode is wired with a resistor (70-130Ohm for 20mA) // to VCC // Expected behavior: always one LED is on, the other in opposite state, if button is pressed for >2 seconds the state // changes func main() { board := nanopi.NewNeoAdaptor() work := func() { inPin, err := board.DigitalPin(inPinNum) if err != nil { fmt.Println(err) } if err := inPin.ApplyOptions(system.WithPinDirectionInput(), system.WithPinPullUp(), system.WithPinDebounce(debounceTime), system.WithPinEventOnBothEdges(buttonEventHandler)); err != nil { fmt.Println(err) } // note: WithPinOpenDrain() is optional, if using WithPinOpenSource() the LED's will not light up outPin, err = board.DigitalPin(outPinNum) if err != nil { fmt.Println(err) } if err := outPin.ApplyOptions(system.WithPinDirectionOutput(1), system.WithPinOpenDrain()); err != nil { fmt.Println(err) } outPinInverted, err = board.DigitalPin(outPinInvertedNum) if err != nil { fmt.Println(err) } if err := outPinInverted.ApplyOptions(system.WithPinActiveLow(), system.WithPinDirectionOutput(1), system.WithPinOpenDrain()); err != nil { fmt.Println(err) } fmt.Printf("\nPlease press and hold the button for at least %s\n", debounceTime) } robot := gobot.NewRobot("pinEdgeBot", []gobot.Connection{board}, []gobot.Device{}, work, ) if err := robot.Start(); err != nil { panic(err) } } func buttonEventHandler(offset int, t time.Duration, et string, sn uint32, lsn uint32) { fmt.Printf("%s: %s detected on line %d with total sequence %d and line sequence %d\n", t, et, offset, sn, lsn) level := 1 if et == "falling edge" { level = 0 } if outPin != nil { err := outPin.Write(level) fmt.Printf("pin %s is now %d\n", outPinNum, level) if err != nil { fmt.Println(err) } } if outPinInverted != nil { err := outPinInverted.Write(level) fmt.Printf("pin %s is now not %d\n", outPinInvertedNum, level) if err != nil { fmt.Println(err) } } } ================================================ FILE: examples/nanopi_led_brightness.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/friendlyelec/nanopi" ) // Wiring // PWR NanoPi: 1, 17 (+3.3V, VCC); 2, 4 (+5V, VDD); 6, 9, 14, 20 (GND) // GPIO NanoPi: the fourth header pin at inner USB side, count from USB side, is the PWM output // LED: the PWM output is NOT able to drive a 20mA LED with full brightness (custom driver or low current LED is needed) // Expected behavior: the LED fades in and out func main() { r := nanopi.NewNeoAdaptor() led := gpio.NewLedDriver(r, "PWM") work := func() { brightness := uint8(0) fadeAmount := uint8(15) gobot.Every(100*time.Millisecond, func() { if err := led.Brightness(brightness); err != nil { fmt.Println(err) } brightness = brightness + fadeAmount if brightness == 0 || brightness == 255 { fadeAmount = -fadeAmount } }) } robot := gobot.NewRobot("pwmBot", []gobot.Connection{r}, []gobot.Device{led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/nanopi_pca9533.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/friendlyelec/nanopi" ) // Wiring // PWR NanoPi: 1, 17 (+3.3V, VCC); 2, 4 (+5V, VDD); 6, 9, 14, 20 (GND) // I2C0 NanoPi: 3 (SDA), 5 (SCL) // PCA9533: 8 (VDD, +2.3..5.5V), 4 (VSS, GND), 7 (SDA), 6 (SCL) // LED pins: 1 (LED0), 2 (LED1), 3 (LED2), 5 (LED3) // LED's directly driven with pull-up resistors to VDD, e.g. 180 Ohm // I2C addresses: 0x62 (PCA9533/01), 0x63 (PCA9533/02) func main() { board := nanopi.NewNeoAdaptor() pca := i2c.NewPCA953xDriver(board, i2c.WithAddress(0x63)) led := uint8(0) // index of LED wVal := uint8(1) // start with LED is "off" rVal := uint8(0) work := func() { // LED 2 with 5 Hz 1:1, LED 3 with 1 Hz 1:10 initialize(pca, 5, 1) gobot.Every(2000*time.Millisecond, func() { fmt.Printf("set LED%d output to %d", led, wVal) err := pca.WriteGPIO(led, wVal) if err != nil { fmt.Println("errW:", err) } rVal, err = pca.ReadGPIO(led) if err != nil { fmt.Println("errR:", err) } if rVal == 0 { fmt.Printf(" - LED%d is ON\n", led) } else { fmt.Printf(" - LED%d is OFF\n", led) } led = led + 1 if led > 1 { led = 0 if wVal == 1 { wVal = 0 } else { wVal = 1 } } }) } robot := gobot.NewRobot("ledI2c", []gobot.Connection{board}, []gobot.Device{pca}, work, ) if err := robot.Start(); err != nil { panic(err) } } func initialize(pca *i2c.PCA953xDriver, led2FrequHz float32, led3FrequHz float32) { // prepare PWM0 err := pca.WriteFrequency(0, led2FrequHz) if err != nil { fmt.Println("errWF0:", err) } frq, err := pca.ReadFrequency(0) if err != nil { fmt.Println("errRF0:", err) } fmt.Println("get Frq0:", frq) err = pca.WriteDutyCyclePercent(0, 50) if err != nil { fmt.Println("errWD0:", err) } dc, err := pca.ReadDutyCyclePercent(0) if err != nil { fmt.Println("errRD0:", err) } fmt.Println("get dc0:", dc) // prepare PWM1 err = pca.WriteFrequency(1, led3FrequHz) if err != nil { fmt.Println("errWF1:", err) } frq, err = pca.ReadFrequency(1) if err != nil { fmt.Println("errRF1:", err) } fmt.Println("get Frq1:", frq) err = pca.WriteDutyCyclePercent(1, 10) if err != nil { fmt.Println("errWD1:", err) } dc, err = pca.ReadDutyCyclePercent(1) if err != nil { fmt.Println("errRD1:", err) } fmt.Println("get dc1:", dc) // LED 2 fmt.Println("set LED: 2 to: pwm0") err = pca.SetLED(2, i2c.PCA953xModePwm0) if err != nil { fmt.Println("errW:", err) } fmt.Println("set LED: 3 to: pwm1") err = pca.SetLED(3, i2c.PCA953xModePwm1) if err != nil { fmt.Println("errW:", err) } } ================================================ FILE: examples/nats.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/nats" ) func main() { natsAdaptor := nats.NewAdaptorWithAuth("localhost:4222", 1234, "user", "pass") work := func() { natsAdaptor.On("hello", func(msg nats.Message) { fmt.Println("hello") }) natsAdaptor.On("hola", func(msg nats.Message) { fmt.Println("hola") }) data := []byte("o") gobot.Every(1*time.Second, func() { natsAdaptor.Publish("hello", data) }) gobot.Every(5*time.Second, func() { natsAdaptor.Publish("hola", data) }) } robot := gobot.NewRobot("natsBot", []gobot.Connection{natsAdaptor}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/nats_driver_ping.go ================================================ //go:build example // +build example // // Do not build by default. // TO RUN: // // go run ./examples/nats_driver_ping.go // // EXAMPLE: // // go run ./examples/nats_driver_ping.go tls://nats.demo.io:4443 package main import ( "fmt" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/nats" ) func main() { natsAdaptor := nats.NewAdaptor(os.Args[1], 1234) holaDriver := nats.NewDriver(natsAdaptor, "hola") helloDriver := nats.NewDriver(natsAdaptor, "hello") work := func() { _ = helloDriver.On(nats.Data, func(msg nats.Message) { fmt.Println("hello") }) _ = holaDriver.On(nats.Data, func(msg nats.Message) { fmt.Println("hola") }) data := []byte("o") gobot.Every(1*time.Second, func() { helloDriver.Publish(data) }) gobot.Every(5*time.Second, func() { holaDriver.Publish(data) }) } robot := gobot.NewRobot("natsBot", []gobot.Connection{natsAdaptor}, []gobot.Device{helloDriver, holaDriver}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/opencv_face_detect.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "path" "runtime" "sync/atomic" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/opencv" "gocv.io/x/gocv" ) var img atomic.Value func main() { _, currentfile, _, _ := runtime.Caller(0) cascade := path.Join(path.Dir(currentfile), "haarcascade_frontalface_alt.xml") window := opencv.NewWindowDriver() camera := opencv.NewCameraDriver(1) work := func() { mat := gocv.NewMat() img.Store(mat) camera.On(opencv.Frame, func(data interface{}) { i := data.(gocv.Mat) img.Store(i) }) gobot.Every(10*time.Millisecond, func() { i := img.Load().(gocv.Mat) if i.Empty() { return } faces := opencv.DetectObjects(cascade, i) opencv.DrawRectangles(i, faces, 0, 255, 0, 5) window.ShowImage(i) window.WaitKey(1) }) } robot := gobot.NewRobot("faceBot", []gobot.Connection{}, []gobot.Device{window, camera}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/opencv_window.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/opencv" "gocv.io/x/gocv" ) func main() { window := opencv.NewWindowDriver() camera := opencv.NewCameraDriver(0) work := func() { camera.On(opencv.Frame, func(data interface{}) { img := data.(gocv.Mat) window.ShowImage(img) window.WaitKey(1) }) } robot := gobot.NewRobot("cameraBot", []gobot.Device{window, camera}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/orangepi5pro_direct_pin.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/adaptors" "gobot.io/x/gobot/v2/platforms/orangepi/orangepi5pro" ) // Wiring // PWR : 1, 17 (+3.3V, VCC), 2, 4 (+5V), 6, 9, 14, 20, 25, 30, 34, 39 (GND) // GPIO : header pin 32 is input, pin 38 used as normal output, pin 40 used as inverted output // Button: the input pin is wired with a button to GND, the internal pull up resistor is used // LED's: the output pins are wired to the cathode of the LED, the anode is wired with a resistor (70-130Ohm for 20mA) // to VCC // Expected behavior: always one LED is on, the other in opposite state, if button is pressed for >2 seconds the state // changes func main() { const ( inPinNum = "32" outPinNum = "38" outPinInvertedNum = "40" debounceTime = 2 * time.Second ) // note: WithGpiosOpenDrain() is optional, if using WithGpiosOpenSource() the LED's will not light up board := orangepi5pro.NewAdaptor(adaptors.WithGpiosActiveLow(outPinInvertedNum), adaptors.WithGpiosOpenDrain(outPinNum, outPinInvertedNum), adaptors.WithGpiosPullUp(inPinNum), adaptors.WithGpioDebounce(inPinNum, debounceTime)) inPin := gpio.NewDirectPinDriver(board, inPinNum) outPin := gpio.NewDirectPinDriver(board, outPinNum) outPinInverted := gpio.NewDirectPinDriver(board, outPinInvertedNum) work := func() { level := byte(1) gobot.Every(500*time.Millisecond, func() { read, err := inPin.DigitalRead() fmt.Printf("pin %s state is %d\n", inPinNum, read) if err != nil { fmt.Println(err) if level == 1 { level = 0 } else { level = 1 } } else { level = byte(read) } err = outPin.DigitalWrite(level) fmt.Printf("pin %s is now %d\n", outPinNum, level) if err != nil { fmt.Println(err) } err = outPinInverted.DigitalWrite(level) fmt.Printf("pin %s is now not %d\n", outPinInvertedNum, level) if err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("pinBot", []gobot.Connection{board}, []gobot.Device{inPin, outPin, outPinInverted}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/orangepi5pro_servo.go ================================================ //go:build example // +build example // Do not build by default. package main import ( "fmt" "log" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/adaptors" "gobot.io/x/gobot/v2/platforms/orangepi/orangepi5pro" ) // Wiring // PWR: 1, 17 (+3.3V, VCC), 2, 4 (+5V), 6, 9, 14, 20, 25, 30, 34, 39 (GND) // PWM: 7(pwm13-m2), 11(pwm14-m1), 12(pwm3-m3), 13(pwm15-m1), 27(pwm0-m2), 28(pwm1-m2), 32(pwm14-m2), 33(pwm15-m3) // Servo SG90: red (+5V), brown (GND), orange (PWM) func main() { const ( pwmPin = "7" wait = 3 * time.Second fiftyHzNanos = 20 * 1000 * 1000 // 50Hz = 0.02 sec = 20 ms ) // usually a frequency of 50Hz is used for servos, most servos have 0.5 ms..2.5 ms for 0-180°, // however the mapping can be changed with options: adaptor := orangepi5pro.NewAdaptor( adaptors.WithPWMDefaultPeriodForPin(pwmPin, fiftyHzNanos), adaptors.WithPWMServoDutyCycleRangeForPin(pwmPin, 500*time.Microsecond, 2500*time.Microsecond), adaptors.WithPWMServoAngleRangeForPin(pwmPin, 0, 180), ) servo := gpio.NewServoDriver(adaptor, pwmPin) work := func() { fmt.Printf("first move to minimal position for %s...\n", wait) if err := servo.ToMin(); err != nil { log.Println(err) } time.Sleep(wait) fmt.Printf("second move to center position for %s...\n", wait) if err := servo.ToCenter(); err != nil { log.Println(err) } time.Sleep(wait) fmt.Printf("third move to maximal position for %s...\n", wait) if err := servo.ToMax(); err != nil { log.Println(err) } time.Sleep(wait) fmt.Println("finally move 0-180° (or what your servo do for the new mapping) and back forever...") angle := 0 fadeAmount := 45 gobot.Every(time.Second, func() { if err := servo.Move(byte(angle)); err != nil { log.Println(err) } angle = angle + fadeAmount if angle < 0 || angle > 180 { if angle < 0 { angle = 0 } if angle > 180 { angle = 180 } // change direction and recalculate fadeAmount = -fadeAmount angle = angle + fadeAmount } }) } robot := gobot.NewRobot("motorBot", []gobot.Connection{adaptor}, []gobot.Device{servo}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/orangepi5pro_thermalzone.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "log" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" "gobot.io/x/gobot/v2/platforms/orangepi/orangepi5pro" ) // Wiring: no wiring needed func main() { adaptor := orangepi5pro.NewAdaptor() therm0 := aio.NewThermalZoneDriver(adaptor, "soc_thermal") therm1 := aio.NewThermalZoneDriver(adaptor, "npu_thermal", aio.WithFahrenheit()) work := func() { gobot.Every(500*time.Millisecond, func() { t0, err := therm0.Read() if err != nil { log.Println(err) } t1, err := therm1.Read() if err != nil { log.Println(err) } fmt.Printf("SOC: %2.3f °C, NPU: %2.3f °F\n", t0, t1) }) } robot := gobot.NewRobot("thermalBot", []gobot.Connection{adaptor}, []gobot.Device{therm0, therm1}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/particle_api.go ================================================ //go:build example // +build example // // Do not build by default. /* To run this example, pass the device ID as first param, and the access token as the second param: go run examples/particle_api.go mydevice myaccesstoken */ package main import ( "fmt" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/api" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/particle" ) func main() { manager := gobot.NewManager() api.NewAPI(manager).Start() core := particle.NewAdaptor(os.Args[1], os.Args[2]) led := gpio.NewLedDriver(core, "D7") work := func() { gobot.Every(1*time.Second, func() { if err := led.Toggle(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("spark", []gobot.Connection{core}, []gobot.Device{led}, work, ) manager.AddRobot(robot) if err := manager.Start(); err != nil { panic(err) } } ================================================ FILE: examples/particle_blink.go ================================================ //go:build example // +build example // // Do not build by default. /* To run this example, pass the device ID as first param, and the access token as the second param: go run examples/particle_blink.go mydevice myaccesstoken */ package main import ( "fmt" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/particle" ) func main() { core := particle.NewAdaptor(os.Args[1], os.Args[2]) led := gpio.NewLedDriver(core, "D7") work := func() { gobot.Every(1*time.Second, func() { if err := led.Toggle(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("spark", []gobot.Connection{core}, []gobot.Device{led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/particle_button.go ================================================ //go:build example // +build example // // Do not build by default. /* To run this example, pass the device ID as first param, and the access token as the second param: go run examples/particle_button.go mydevice myaccesstoken */ package main import ( "fmt" "os" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/particle" ) func main() { core := particle.NewAdaptor(os.Args[1], os.Args[2]) led := gpio.NewLedDriver(core, "D7") button := gpio.NewButtonDriver(core, "D5") work := func() { _ = button.On(button.Event("push"), func(data interface{}) { if err := led.On(); err != nil { fmt.Println(err) } }) _ = button.On(button.Event("release"), func(data interface{}) { if err := led.Off(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("spark", []gobot.Connection{core}, []gobot.Device{button, led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/particle_events.go ================================================ //go:build example // +build example // // Do not build by default. /* To run this example, pass the device ID as first param, and the access token as the second param: go run examples/particle_events.go mydevice myaccesstoken */ package main import ( "fmt" "os" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/particle" ) func main() { core := particle.NewAdaptor(os.Args[1], os.Args[2]) work := func() { if stream, err := core.EventStream("all", ""); err != nil { fmt.Println(err) } else { // TODO: some other way to handle this fmt.Println(stream) } } robot := gobot.NewRobot("spark", []gobot.Connection{core}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/particle_function.go ================================================ //go:build example // +build example // // Do not build by default. /* To run this example, pass the device ID as first param, and the access token as the second param: go run examples/particle_function.go mydevice myaccesstoken */ package main import ( "fmt" "os" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/particle" ) func main() { core := particle.NewAdaptor(os.Args[1], os.Args[2]) work := func() { if result, err := core.Function("brew", "202,230"); err != nil { fmt.Println(err) } else { fmt.Println("result from \"brew\":", result) } } robot := gobot.NewRobot("spark", []gobot.Connection{core}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/particle_led_brightness.go ================================================ //go:build example // +build example // // Do not build by default. /* To run this example, pass the device ID as first param, and the access token as the second param: go run examples/particle_led_brightness.go mydevice myaccesstoken */ package main import ( "fmt" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/particle" ) func main() { core := particle.NewAdaptor(os.Args[1], os.Args[2]) led := gpio.NewLedDriver(core, "A1") work := func() { brightness := uint8(0) fadeAmount := uint8(25) gobot.Every(500*time.Millisecond, func() { if err := led.Brightness(brightness); err != nil { fmt.Println(err) } brightness = brightness + fadeAmount if brightness == 0 || brightness == 255 { fadeAmount = -fadeAmount } }) } robot := gobot.NewRobot("spark", []gobot.Connection{core}, []gobot.Device{led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/particle_variable.go ================================================ //go:build example // +build example // // Do not build by default. /* To run this example, pass the device ID as first param, and the access token as the second param: go run examples/particle_variable.go mydevice myaccesstoken */ package main import ( "fmt" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/particle" ) func main() { core := particle.NewAdaptor(os.Args[1], os.Args[2]) work := func() { gobot.Every(1*time.Second, func() { if temp, err := core.Variable("temperature"); err != nil { fmt.Println(err) } else { fmt.Println("result from \"temperature\" is:", temp) } }) } robot := gobot.NewRobot("spark", []gobot.Connection{core}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/pebble.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/api" "gobot.io/x/gobot/v2/platforms/pebble" ) func main() { manager := gobot.NewManager() api := api.NewAPI(manager) api.Port = "8080" api.Start() pebbleAdaptor := pebble.NewAdaptor() pebbleDriver := pebble.NewDriver(pebbleAdaptor) work := func() { pebbleDriver.SendNotification("Hello Pebble!") _ = pebbleDriver.On(pebbleDriver.Event("button"), func(data interface{}) { fmt.Println("Button pushed: " + data.(string)) }) _ = pebbleDriver.On(pebbleDriver.Event("tap"), func(data interface{}) { fmt.Println("Tap event detected") }) } robot := gobot.NewRobot("pebble", []gobot.Connection{pebbleAdaptor}, []gobot.Device{pebbleDriver}, work, ) manager.AddRobot(robot) if err := manager.Start(); err != nil { panic(err) } } ================================================ FILE: examples/pebble_accelerometer.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/api" "gobot.io/x/gobot/v2/platforms/pebble" ) func main() { manager := gobot.NewManager() a := api.NewAPI(manager) a.Port = "8080" a.Start() pebbleAdaptor := pebble.NewAdaptor() pebbleDriver := pebble.NewDriver(pebbleAdaptor) work := func() { _ = pebbleDriver.On(pebbleDriver.Event("accel"), func(data interface{}) { fmt.Println(data.(string)) }) } robot := gobot.NewRobot("pebble", []gobot.Connection{pebbleAdaptor}, []gobot.Device{pebbleDriver}, work, ) manager.AddRobot(robot) if err := manager.Start(); err != nil { panic(err) } } ================================================ FILE: examples/raspi_adafruit2327_servo.go ================================================ //go:build example // +build example // // Do not build by default. //nolint:gosec // ok here package main import ( "fmt" "log" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/raspi" ) const ( // Min pulse length out of 4096 servoMin = 150 // Max pulse length out of 4096 servoMax = 700 // Limiting the max this servo can rotate (in deg) maxDegree = 180 // Number of degrees to increase per call degIncrease = 10 yawDeg = 90 ) func main() { r := raspi.NewAdaptor() // Changing from the default 0x40 address because this configuration involves // a Servo HAT stacked on top of a DC/Stepper Motor HAT on top of the Pi. stackedHatAddr := 0x41 adaFruit := i2c.NewAdafruit2327Driver(r, i2c.WithAddress(stackedHatAddr)) work := func() { gobot.Every(5*time.Second, func() { if err := adafruitServoMotorRunner(adaFruit); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("adaFruitBot", []gobot.Connection{r}, []gobot.Device{adaFruit}, work, ) if err := robot.Start(); err != nil { panic(err) } } func adafruitServoMotorRunner(a *i2c.Adafruit2327Driver) error { log.Printf("Servo Motor Run Loop...\n") var channel byte = 1 deg := 90 // Do not need to set this every run loop freq := 60.0 if err := a.SetServoMotorFreq(freq); err != nil { return err } // start in the middle of the 180-deg range pulse := degree2pulse(deg) if err := a.SetServoMotorPulse(channel, 0, pulse); err != nil { return err } // INCR pulse = degree2pulse(deg + degIncrease) if err := a.SetServoMotorPulse(channel, 0, pulse); err != nil { return err } time.Sleep(2000 * time.Millisecond) // DECR pulse = degree2pulse(deg - degIncrease) if err := a.SetServoMotorPulse(channel, 0, pulse); err != nil { return err } return nil } func degree2pulse(deg int) int32 { pulse := servoMin pulse += ((servoMax - servoMin) / maxDegree) * deg return int32(pulse) } ================================================ FILE: examples/raspi_adafruit2348_dcmotor.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "log" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/raspi" ) func main() { r := raspi.NewAdaptor() // we use the default address 0x60 for DC/Stepper Motor HAT on top of the Pi adaFruit := i2c.NewAdafruit2348Driver(r) work := func() { gobot.Every(5*time.Second, func() { dcMotor := 2 // 0-based if err := adafruitDCMotorRunner(adaFruit, dcMotor); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("adaFruitBot", []gobot.Connection{r}, []gobot.Device{adaFruit}, work, ) if err := robot.Start(); err != nil { panic(err) } } func adafruitDCMotorRunner(a *i2c.Adafruit2348Driver, dcMotor int) error { log.Printf("DC Motor Run Loop...\n") // set the speed: var speed int32 = 255 // 255 = full speed! if err := a.SetDCMotorSpeed(dcMotor, speed); err != nil { return err } // run FORWARD if err := a.RunDCMotor(dcMotor, i2c.Adafruit2348Forward); err != nil { return err } // Sleep and RELEASE time.Sleep(2000 * time.Millisecond) if err := a.RunDCMotor(dcMotor, i2c.Adafruit2348Release); err != nil { return err } // run BACKWARD if err := a.RunDCMotor(dcMotor, i2c.Adafruit2348Backward); err != nil { return err } // Sleep and RELEASE time.Sleep(2000 * time.Millisecond) if err := a.RunDCMotor(dcMotor, i2c.Adafruit2348Release); err != nil { return err } return nil } ================================================ FILE: examples/raspi_adafruit2348_stepper.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "log" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/raspi" ) func main() { r := raspi.NewAdaptor() // we use the default address 0x60 for DC/Stepper Motor HAT on top of the Pi adaFruit := i2c.NewAdafruit2348Driver(r) work := func() { gobot.Every(5*time.Second, func() { motor := 0 // 0-based if err := adafruitStepperMotorRunner(adaFruit, motor); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("adaFruitBot", []gobot.Connection{r}, []gobot.Device{adaFruit}, work, ) if err := robot.Start(); err != nil { panic(err) } } func adafruitStepperMotorRunner(a *i2c.Adafruit2348Driver, motor int) error { log.Printf("Stepper Motor Run Loop...\n") // set the speed state: speed := 30 // rpm style := i2c.Adafruit2348Double steps := 20 if err := a.SetStepperMotorSpeed(motor, speed); err != nil { return err } if err := a.Step(motor, steps, i2c.Adafruit2348Forward, style); err != nil { return err } if err := a.Step(motor, steps, i2c.Adafruit2348Backward, style); err != nil { return err } return nil } ================================================ FILE: examples/raspi_ads1015.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/raspi" ) func main() { a := raspi.NewAdaptor() // Use the gain to be able to read values of at least 5V (for all channels) ads1015 := i2c.NewADS1015Driver(a, i2c.WithADS1x15BestGainForVoltage(5.0)) work := func() { gobot.Every(100*time.Millisecond, func() { v, _ := ads1015.ReadWithDefaults(0) fmt.Println("A0", v) }) } robot := gobot.NewRobot("ads1015bot", []gobot.Connection{a}, []gobot.Device{ads1015}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/raspi_blink.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/raspi" ) func main() { r := raspi.NewAdaptor() led := gpio.NewLedDriver(r, "7") work := func() { gobot.Every(1*time.Second, func() { if err := led.Toggle(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("blinkBot", []gobot.Connection{r}, []gobot.Device{led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/raspi_blinkm.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/raspi" ) func main() { r := raspi.NewAdaptor() blinkm := i2c.NewBlinkMDriver(r) work := func() { gobot.Every(1*time.Second, func() { r := byte(gobot.Rand(255)) g := byte(gobot.Rand(255)) b := byte(gobot.Rand(255)) if err := blinkm.Rgb(r, g, b); err != nil { fmt.Println(err) } color, err := blinkm.Color() if err != nil { fmt.Println(err) } fmt.Printf("color %v\n", color) }) } robot := gobot.NewRobot("blinkmBot", []gobot.Connection{r}, []gobot.Device{blinkm}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/raspi_button.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/raspi" ) func main() { r := raspi.NewAdaptor() button := gpio.NewButtonDriver(r, "11") led := gpio.NewLedDriver(r, "7") work := func() { _ = button.On(gpio.ButtonPush, func(data interface{}) { fmt.Println("button pressed") if err := led.On(); err != nil { fmt.Println(err) } }) _ = button.On(gpio.ButtonRelease, func(data interface{}) { fmt.Println("button released") if err := led.Off(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("buttonBot", []gobot.Connection{r}, []gobot.Device{button, led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/raspi_ccs811.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/raspi" ) func CCS811BootData(a *i2c.CCS811Driver) { v, err := a.GetHardwareVersion() if err != nil { fmt.Println(err.Error()) } fmt.Printf("Hardare Version %#x\n", v) d, err := a.GetFirmwareBootVersion() if err != nil { fmt.Println(err.Error()) } fmt.Printf("Boot Version %#x\n", d) d, err = a.GetFirmwareAppVersion() if err != nil { fmt.Println(err.Error()) } fmt.Printf("App Version %#x\n\n", d) } func main() { r := raspi.NewAdaptor() ccs811Driver := i2c.NewCCS811Driver(r) work := func() { CCS811BootData(ccs811Driver) gobot.Every(1*time.Second, func() { s, err := ccs811Driver.GetStatus() if err != nil { fmt.Printf("Error fetching data from the status register: %+v\n", err.Error()) } fmt.Printf("Status %+v \n", s) hd, err := ccs811Driver.HasData() if err != nil { fmt.Printf("Error fetching data from the status register: %+v\n", err.Error()) } if hd { ec02, tv0C, _ := ccs811Driver.GetGasData() fmt.Printf("Gas Data - eco2: %+v, tvoc: %+v \n", ec02, tv0C) temp, _ := ccs811Driver.GetTemperature() fmt.Printf("Temperature %+v \n\n", temp) } else { fmt.Println("New data is not available") } }) } robot := gobot.NewRobot("adaFruitBot", []gobot.Connection{r}, []gobot.Device{ccs811Driver}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/raspi_direct_pin.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/adaptors" "gobot.io/x/gobot/v2/platforms/raspi" ) // Wiring // PWR Raspi: 1 (+3.3V, VCC), 2(+5V), 6, 9, 14, 20 (GND) // GPIO Raspi: header pin 21 (GPIO9) is input, pin 24 (GPIO8) is normal output, pin 26 (GPIO7) is inverted output // Button: the input pin is wired with a button to GND, the internal pull up resistor is used // LED's: the output pins are wired to the cathode of a LED, the anode is wired with a resistor (70-130Ohm for 20mA) // to VCC // Expected behavior: always one LED is on, the other in opposite state, if button is pressed for >2 seconds the state // changes func main() { const ( inPinNum = "21" outPinNum = "24" outPinInvertedNum = "26" ) // note: WithGpiosOpenDrain() is optional, if using WithGpiosOpenSource() the LED's will not light up board := raspi.NewAdaptor(adaptors.WithGpiosActiveLow(outPinInvertedNum), adaptors.WithGpiosOpenDrain(outPinNum, outPinInvertedNum), adaptors.WithGpiosPullUp(inPinNum), adaptors.WithGpioDebounce(inPinNum, 2*time.Second)) inPin := gpio.NewDirectPinDriver(board, inPinNum) outPin := gpio.NewDirectPinDriver(board, outPinNum) outPinInverted := gpio.NewDirectPinDriver(board, outPinInvertedNum) work := func() { level := byte(1) gobot.Every(500*time.Millisecond, func() { read, err := inPin.DigitalRead() fmt.Printf("pin %s state is %d\n", inPinNum, read) if err != nil { fmt.Println(err) } else { level = byte(read) } err = outPin.DigitalWrite(level) fmt.Printf("pin %s is now %d\n", outPinNum, level) if err != nil { fmt.Println(err) } err = outPinInverted.DigitalWrite(level) fmt.Printf("pin %s is now not %d\n", outPinInvertedNum, level) if err != nil { fmt.Println(err) } if level == 1 { level = 0 } else { level = 1 } }) } robot := gobot.NewRobot("pinBot", []gobot.Connection{board}, []gobot.Device{inPin, outPin, outPinInverted}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/raspi_direct_pin_event.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/raspi" "gobot.io/x/gobot/v2/system" ) const ( inPinNum = "21" outPinNum = "24" outPinInvertedNum = "26" debounceTime = 2 * time.Second ) var ( outPin gobot.DigitalPinner outPinInverted gobot.DigitalPinner ) // Wiring // PWR Raspi: 1 (+3.3V, VCC), 2(+5V), 6, 9, 14, 20 (GND) // GPIO Raspi: header pin 21 (GPIO9) is input, pin 24 (GPIO8) is normal output, pin 26 (GPIO7) is inverted output // Button: the input pin is wired with a button to GND, the internal pull up resistor is used // LED's: the output pins are wired to the cathode of a LED, the anode is wired with a resistor (70-130Ohm for 20mA) // to VCC // Expected behavior: always one LED is on, the other in opposite state, if button is pressed for >2 seconds the state // changes func main() { board := raspi.NewAdaptor() work := func() { inPin, err := board.DigitalPin(inPinNum) if err != nil { fmt.Println(err) } if err := inPin.ApplyOptions(system.WithPinDirectionInput(), system.WithPinPullUp(), system.WithPinDebounce(debounceTime), system.WithPinEventOnBothEdges(buttonEventHandler)); err != nil { fmt.Println(err) } // note: WithPinOpenDrain() is optional, if using WithPinOpenSource() the LED's will not light up outPin, err = board.DigitalPin(outPinNum) if err != nil { fmt.Println(err) } if err := outPin.ApplyOptions(system.WithPinDirectionOutput(1), system.WithPinOpenDrain()); err != nil { fmt.Println(err) } outPinInverted, err = board.DigitalPin(outPinInvertedNum) if err != nil { fmt.Println(err) } if err := outPinInverted.ApplyOptions(system.WithPinActiveLow(), system.WithPinDirectionOutput(1), system.WithPinOpenDrain()); err != nil { fmt.Println(err) } fmt.Printf("\nPlease press and hold the button for at least %s\n", debounceTime) } robot := gobot.NewRobot("pinEdgeBot", []gobot.Connection{board}, []gobot.Device{}, work, ) if err := robot.Start(); err != nil { panic(err) } } func buttonEventHandler(offset int, t time.Duration, et string, sn uint32, lsn uint32) { fmt.Printf("%s: %s detected on line %d with total sequence %d and line sequence %d\n", t, et, offset, sn, lsn) level := 1 if et == "falling edge" { level = 0 } err := outPin.Write(level) fmt.Printf("pin %s is now %d\n", outPinNum, level) if err != nil { fmt.Println(err) } err = outPinInverted.Write(level) fmt.Printf("pin %s is now not %d\n", outPinInvertedNum, level) if err != nil { fmt.Println(err) } } ================================================ FILE: examples/raspi_generic.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "reflect" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/raspi" ) // Wiring // PWR Raspi: 1 (+3.3V, VCC), 6, 9, 14, 20 (GND) // I2C1 Raspi: 3 (SDA), 5 (SCL) // PCA9501: 20 (VDD, +2.5..3.6V), 10 (VSS, GND), 19 (SDA), 18 (SCL) // HW address pins: 1 (A0), 2 (A1), 3 (A2), 12 (A3), 11 (A4), 9 (A5) func main() { const ( defaultAddress = 0x7F // with open address pins (internal pull-up) myAddress = 0x44 // needs to be adjusted for your configuration eepromAddr = uint8(0x02) dataLen = 7 write = true read = true ) board := raspi.NewAdaptor() drv := i2c.NewGenericDriver(board, "PCA9501-EEPROM", defaultAddress, i2c.WithAddress(myAddress)) var valWr uint8 = 0x09 var err error wData := make([]byte, dataLen) rData := make([]byte, dataLen) work := func() { gobot.Every(500*time.Millisecond, func() { // write "dataLen" values, starting by EEPROM address valWr++ if write { for i := range wData { wData[i] = byte(i) + valWr } err = drv.WriteBlockData(eepromAddr, wData) if err != nil { fmt.Println("err write:", err) } else if read != write { fmt.Printf("EEPROM addr: %d, wr: %v\n", eepromAddr, wData) } } // write process needs some time, so wait at least 5ms before read a value // when decreasing to much, the check below will fail time.Sleep(10 * time.Millisecond) if read { err = drv.ReadBlockData(eepromAddr, rData) if err != nil { fmt.Println("err read:", err) } else if read != write { fmt.Printf("EEPROM addr: %d, rd: %v\n", eepromAddr, rData) } } // compare read and write if read && write { if reflect.DeepEqual(wData, rData) { fmt.Printf("EEPROM addr: %d equal: %v\n", eepromAddr, rData) } else { fmt.Printf("EEPROM addr: %d wr: %v differ rd: %v\n", eepromAddr, wData, rData) } } }) } robot := gobot.NewRobot("genericDriverI2c", []gobot.Connection{board}, []gobot.Device{drv}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/raspi_grove_pi_blink.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/raspi" ) func main() { r := raspi.NewAdaptor() gp := i2c.NewGrovePiDriver(r) led := gpio.NewLedDriver(gp, "D2") work := func() { gobot.Every(1*time.Second, func() { if err := led.Toggle(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("blinkBot", []gobot.Connection{r}, []gobot.Device{gp, led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/raspi_grove_pi_button.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/raspi" ) func main() { r := raspi.NewAdaptor() gp := i2c.NewGrovePiDriver(r) button := gpio.NewButtonDriver(gp, "D3", gpio.WithButtonPollInterval(50*time.Millisecond)) led := gpio.NewLedDriver(gp, "D2") work := func() { _ = button.On(gpio.ButtonPush, func(data interface{}) { fmt.Println("button pressed") if err := led.On(); err != nil { fmt.Println(err) } }) _ = button.On(gpio.ButtonRelease, func(data interface{}) { fmt.Println("button released") if err := led.Off(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("buttonBot", []gobot.Connection{r}, []gobot.Device{gp, button, led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/raspi_grove_pi_dht.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/raspi" ) const ( dhtPin = "4" dhtModel = 1 // white DHT22, 0 for the blue DHT11 delayMillisec = 10 ) func main() { r := raspi.NewAdaptor() gp := i2c.NewGrovePiDriver(r) work := func() { gobot.Every(1*time.Second, func() { if temp, hum, err := gp.DHTRead(dhtPin, dhtModel, delayMillisec); err != nil { fmt.Println(err) } else { fmt.Println("Temperature [°C]", temp) fmt.Println("rel. Humidity [%]", hum) } }) } robot := gobot.NewRobot("dhtBot", []gobot.Connection{r}, []gobot.Device{gp}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/raspi_grove_pi_rotary.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/raspi" ) func main() { board := raspi.NewAdaptor() gp := i2c.NewGrovePiDriver(board) sensor := aio.NewGroveRotaryDriver(gp, "A1", aio.WithSensorCyclicRead(500*time.Millisecond)) work := func() { _ = sensor.On(aio.Data, func(data interface{}) { fmt.Println("sensor", data) }) } robot := gobot.NewRobot("sensorBot", []gobot.Connection{board}, []gobot.Device{gp, sensor}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/raspi_grove_pi_ultrasonic.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/raspi" ) const ( ultrasonicPin = "4" delayMillisec = 10 ) func main() { r := raspi.NewAdaptor() gp := i2c.NewGrovePiDriver(r) work := func() { gobot.Every(1*time.Second, func() { if val, err := gp.UltrasonicRead(ultrasonicPin, delayMillisec); err != nil { fmt.Println(err) } else { fmt.Println("Distance [cm]", val) } }) } robot := gobot.NewRobot("ultrasonicBot", []gobot.Connection{r}, []gobot.Device{gp}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/raspi_grove_rotary_sensor.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/raspi" ) func main() { board := raspi.NewAdaptor() ads1015 := i2c.NewADS1015Driver(board) sensor := aio.NewGroveRotaryDriver(ads1015, "0", aio.WithSensorCyclicRead(500*time.Millisecond)) work := func() { _ = sensor.On(aio.Data, func(data interface{}) { fmt.Println("sensor", data) }) } robot := gobot.NewRobot("sensorBot", []gobot.Connection{board}, []gobot.Device{ads1015, sensor}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/raspi_hcsr04.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "log" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/raspi" ) func main() { const ( triggerOutput = "11" echoInput = "13" ) // this is mandatory for systems with defunct edge detection, although the "cdev" is used with an newer Kernel // keep in mind, that this cause more inaccurate measurements const pollEdgeDetection = true opts := []interface{}{} if pollEdgeDetection { opts = append(opts, gpio.WithHCSR04UseEdgePolling()) } a := raspi.NewAdaptor() hcsr04 := gpio.NewHCSR04Driver(a, triggerOutput, echoInput, opts...) work := func() { if pollEdgeDetection { fmt.Println("Please note that measurements are CPU consuming and will be more inaccurate with this setting.") fmt.Println("After startup the system is under load and the measurement is very inaccurate, so wait a bit...") time.Sleep(2000 * time.Millisecond) } if err := hcsr04.StartDistanceMonitor(); err != nil { log.Fatal(err) } // first single shot if v, err := hcsr04.MeasureDistance(); err != nil { log.Fatal(err) } else { fmt.Printf("first single shot done: %5.3f m\n", v) } ticker := gobot.Every(1*time.Second, func() { fmt.Printf("continuous measurement: %5.3f m\n", hcsr04.Distance()) }) gobot.After(5*time.Second, func() { if err := hcsr04.StopDistanceMonitor(); err != nil { log.Fatal(err) } ticker.Stop() }) gobot.After(7*time.Second, func() { // second single shot if v, err := hcsr04.MeasureDistance(); err != nil { log.Fatal(err) } else { fmt.Printf("second single shot done: %5.3f m\n", v) } // cleanup if err := hcsr04.Halt(); err != nil { log.Println(err) } if err := a.Finalize(); err != nil { log.Println(err) } os.Exit(0) }) } robot := gobot.NewRobot("distanceBot", []gobot.Connection{a}, []gobot.Device{hcsr04}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/raspi_hmc5883l.go ================================================ //go:build example // +build example // // Do not build by default. /* How to run go run examples/raspi_hmc5883l.go */ package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/raspi" ) func main() { raspi := raspi.NewAdaptor() hmc5883l := i2c.NewHMC5883LDriver(raspi) work := func() { gobot.Every(200*time.Millisecond, func() { // get heading in radians, to convert to degrees multiply by 180/math.Pi heading, _ := hmc5883l.Heading() fmt.Println("Heading", heading) // read the data in Gauss x, y, z, _ := hmc5883l.Read() fmt.Println(x, y, z) }) } robot := gobot.NewRobot("hmc5883LBot", []gobot.Connection{raspi}, []gobot.Device{hmc5883l}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/raspi_ina3221.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/raspi" ) func main() { r := raspi.NewAdaptor() ina := i2c.NewINA3221Driver(r) work := func() { gobot.Every(5*time.Second, func() { for _, ch := range []i2c.INA3221Channel{i2c.INA3221Channel1, i2c.INA3221Channel2, i2c.INA3221Channel3} { val, err := ina.GetBusVoltage(ch) if err != nil { fmt.Printf("INA3221Channel %v Bus Voltage error: %v\n", ch, err) } fmt.Printf("INA3221Channel %v Bus Voltage: %fV\n", ch, val) val, err = ina.GetShuntVoltage(ch) if err != nil { fmt.Printf("INA3221Channel %v Shunt Voltage error: %v\n", ch, err) } fmt.Printf("INA3221Channel %v Shunt Voltage: %fV\n", ch, val) val, err = ina.GetCurrent(ch) if err != nil { fmt.Printf("INA3221Channel %v Current error: %v\n", ch, err) } fmt.Printf("INA3221Channel %v Current: %fmA\n", ch, val) val, err = ina.GetLoadVoltage(ch) if err != nil { fmt.Printf("INA3221Channel %v Load Voltage error: %v\n", ch, err) } fmt.Printf("INA3221Channel %v Load Voltage: %fV\n", ch, val) } }) } robot := gobot.NewRobot("INA3221 Robot", []gobot.Connection{r}, []gobot.Device{ina}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/raspi_led_brightness.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/raspi" ) func main() { r := raspi.NewAdaptor() led := gpio.NewLedDriver(r, "pwm0") work := func() { brightness := uint8(0) fadeAmount := uint8(15) gobot.Every(100*time.Millisecond, func() { if err := led.Brightness(brightness); err != nil { fmt.Println(err) } brightness = brightness + fadeAmount if brightness == 0 || brightness == 255 { fadeAmount = -fadeAmount } }) } robot := gobot.NewRobot("pwmBot", []gobot.Connection{r}, []gobot.Device{led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/raspi_mcp3008.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/spi" "gobot.io/x/gobot/v2/platforms/raspi" ) func main() { a := raspi.NewAdaptor() adc := spi.NewMCP3008Driver(a) work := func() { gobot.Every(100*time.Millisecond, func() { result, err := adc.Read(0) fmt.Println("A0", result, err) }) } robot := gobot.NewRobot("mcp3008bot", []gobot.Connection{a}, []gobot.Device{adc}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/raspi_pca9533.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/raspi" ) // Wiring // PWR Raspi: 1 (+3.3V, VCC), 6, 9, 14, 20 (GND) // I2C1 Raspi: 3 (SDA), 5 (SCL) // PCA9533: 8 (VDD, +2.3..5.5V), 4 (VSS, GND), 7 (SDA), 6 (SCL) // LED pins: 1 (LED0), 2 (LED1), 3 (LED2), 5 (LED3) // LED's directly driven with pull-up resistors to VDD, e.g. 180 Ohm // I2C addresses: 0x62 (PCA9533/01), 0x63 (PCA9533/02) func main() { board := raspi.NewAdaptor() pca := i2c.NewPCA953xDriver(board, i2c.WithAddress(0x63)) led := uint8(0) // index of LED wVal := uint8(1) // start with LED is "off" rVal := uint8(0) work := func() { // LED 2 with 5 Hz 1:1, LED 3 with 1 Hz 1:10 initialize(pca, 5, 1) gobot.Every(2000*time.Millisecond, func() { fmt.Printf("set LED%d output to %d", led, wVal) err := pca.WriteGPIO(led, wVal) if err != nil { fmt.Println("errW:", err) } rVal, err = pca.ReadGPIO(led) if err != nil { fmt.Println("errR:", err) } if rVal == 0 { fmt.Printf(" - LED%d is ON\n", led) } else { fmt.Printf(" - LED%d is OFF\n", led) } led = led + 1 if led > 1 { led = 0 if wVal == 1 { wVal = 0 } else { wVal = 1 } } }) } robot := gobot.NewRobot("ledI2c", []gobot.Connection{board}, []gobot.Device{pca}, work, ) if err := robot.Start(); err != nil { panic(err) } } func initialize(pca *i2c.PCA953xDriver, led2FrequHz float32, led3FrequHz float32) { // prepare PWM0 err := pca.WriteFrequency(0, led2FrequHz) if err != nil { fmt.Println("errWF0:", err) } frq, err := pca.ReadFrequency(0) if err != nil { fmt.Println("errRF0:", err) } fmt.Println("get Frq0:", frq) err = pca.WriteDutyCyclePercent(0, 50) if err != nil { fmt.Println("errWD0:", err) } dc, err := pca.ReadDutyCyclePercent(0) if err != nil { fmt.Println("errRD0:", err) } fmt.Println("get dc0:", dc) // prepare PWM1 err = pca.WriteFrequency(1, led3FrequHz) if err != nil { fmt.Println("errWF1:", err) } frq, err = pca.ReadFrequency(1) if err != nil { fmt.Println("errRF1:", err) } fmt.Println("get Frq1:", frq) err = pca.WriteDutyCyclePercent(1, 10) if err != nil { fmt.Println("errWD1:", err) } dc, err = pca.ReadDutyCyclePercent(1) if err != nil { fmt.Println("errRD1:", err) } fmt.Println("get dc1:", dc) // LED 2 fmt.Println("set LED: 2 to: pwm0") err = pca.SetLED(2, i2c.PCA953xModePwm0) if err != nil { fmt.Println("errW:", err) } fmt.Println("set LED: 3 to: pwm1") err = pca.SetLED(3, i2c.PCA953xModePwm1) if err != nil { fmt.Println("errW:", err) } } ================================================ FILE: examples/raspi_servo.go ================================================ //go:build example // +build example // Do not build by default. package main import ( "fmt" "log" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/adaptors" "gobot.io/x/gobot/v2/platforms/raspi" ) // Wiring // PWM Raspi: header pin 12 (GPIO18-PWM0), please refer to the README.md, located in the folder of raspi platform, on // how to activate the pwm support. // Servo: orange (PWM), black (GND), red (VCC) 4-6V (please read the manual of your device) func main() { const ( pwmPin = "pwm0" wait = 3 * time.Second fiftyHzNanos = 20 * 1000 * 1000 // 50Hz = 0.02 sec = 20 ms ) // usually a frequency of 50Hz is used for servos, most servos have 0.5 ms..2.5 ms for 0-180°, however the mapping // can be changed with options... // // for usage of pi-blaster driver just add the option "adaptors.WithPWMUsePiBlaster()" and use your pin number // instead of "pwm0" adaptor := raspi.NewAdaptor(adaptors.WithPWMDefaultPeriodForPin(pwmPin, fiftyHzNanos)) servo := gpio.NewServoDriver(adaptor, pwmPin) work := func() { fmt.Printf("first move to minimal position for %s...\n", wait) if err := servo.ToMin(); err != nil { log.Println(err) } time.Sleep(wait) fmt.Printf("second move to center position for %s...\n", wait) if err := servo.ToCenter(); err != nil { log.Println(err) } time.Sleep(wait) fmt.Printf("third move to maximal position for %s...\n", wait) if err := servo.ToMax(); err != nil { log.Println(err) } time.Sleep(wait) fmt.Println("finally move 0-180° (or what your servo do for the new mapping) and back forever...") angle := 0 fadeAmount := 45 gobot.Every(time.Second, func() { if err := servo.Move(byte(angle)); err != nil { log.Println(err) } angle = angle + fadeAmount if angle < 0 || angle > 180 { if angle < 0 { angle = 0 } if angle > 180 { angle = 180 } // change direction and recalculate fadeAmount = -fadeAmount angle = angle + fadeAmount } }) } robot := gobot.NewRobot("motorBot", []gobot.Connection{adaptor}, []gobot.Device{servo}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/raspi_sht2x.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/raspi" ) func main() { r := raspi.NewAdaptor() sht2x := i2c.NewSHT2xDriver(r) work := func() { gobot.Every(1*time.Second, func() { t, _ := sht2x.Temperature() fmt.Printf("Temperature: %v\n", t) h, _ := sht2x.Humidity() fmt.Printf("Humidity: %v\n", h) }) } robot := gobot.NewRobot("SHT2xbot", []gobot.Connection{r}, []gobot.Device{sht2x}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/raspi_sht3x.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/raspi" ) func main() { r := raspi.NewAdaptor() sht3x := i2c.NewSHT3xDriver(r) work := func() { sht3x.Units = "F" if err := sht3x.Start(); err != nil { fmt.Println(err) } sn, err := sht3x.SerialNumber() fmt.Printf("Serial Number: 0x%08x, err: %v\n", sn, err) gobot.Every(5*time.Second, func() { temp, rh, err := sht3x.Sample() fmt.Printf("Temp: %f F, Relative Humidity: %f, err: %v\n", temp, rh, err) }) } robot := gobot.NewRobot("SHT3xbot", []gobot.Connection{r}, []gobot.Device{sht3x}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/raspi_ssd1306.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/raspi" ) func main() { width := 128 height := 32 r := raspi.NewAdaptor() oled := i2c.NewSSD1306Driver(r, i2c.WithSSD1306DisplayWidth(width), i2c.WithSSD1306DisplayHeight(height)) stage := false work := func() { gobot.Every(1*time.Second, func() { oled.Clear() if stage { for x := 0; x < width; x += 5 { for y := 0; y < height; y++ { oled.Set(x, y, 1) } } } stage = !stage if err := oled.Display(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("ssd1306Robot", []gobot.Connection{r}, []gobot.Device{oled}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/raspi_ssd1306spi.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/spi" "gobot.io/x/gobot/v2/platforms/raspi" ) // this example only works for a 128x64 display // //nolint:lll // ok for example var gobotLogo = []byte{0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xe0, 0xb0, 0x90, 0xc8, 0x6e, 0x9a, 0xb6, 0xd, 0x3a, 0x15, 0xf7, 0xd, 0x59, 0x98, 0x94, 0xf4, 0xf4, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x7f, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x8f, 0x8f, 0xff, 0x97, 0xcf, 0x4f, 0xc3, 0x51, 0xc0, 0x41, 0xd1, 0x40, 0xa4, 0xc4, 0x50, 0xc0, 0x40, 0xd1, 0x87, 0xdf, 0x97, 0x77, 0x3f, 0x8f, 0x4f, 0xff, 0x9f, 0xbf, 0x9f, 0x9f, 0xff, 0xff, 0xff, 0x7f, 0x7f, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x3f, 0x37, 0x37, 0xef, 0xda, 0xbf, 0xef, 0x8e, 0x8d, 0xe7, 0xad, 0xfb, 0xaf, 0x1b, 0xdb, 0x29, 0x1f, 0x56, 0xcf, 0x1b, 0xcf, 0x9b, 0x55, 0x8f, 0xdd, 0x1a, 0xd7, 0x1e, 0xb5, 0x9b, 0xad, 0x17, 0xbd, 0xab, 0x15, 0xbf, 0x2d, 0x9a, 0xb7, 0x1d, 0xb7, 0x2d, 0x9a, 0xb7, 0x9e, 0x95, 0x9f, 0x55, 0x9b, 0x5d, 0x97, 0x5a, 0x8f, 0xda, 0xf, 0xda, 0x4f, 0x9a, 0x2e, 0x5a, 0xae, 0x14, 0xff, 0x67, 0xcf, 0x8b, 0x56, 0xdd, 0x74, 0xdd, 0x77, 0x57, 0x5f, 0x5f, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xfc, 0xfe, 0xff, 0xf2, 0xff, 0xfc, 0xef, 0xba, 0xef, 0xba, 0xed, 0xbf, 0xea, 0x5f, 0xfa, 0x56, 0xfe, 0xb4, 0xde, 0x74, 0xbe, 0xec, 0x5a, 0xfc, 0x55, 0xfc, 0xd5, 0xbc, 0x74, 0xad, 0x7c, 0xa9, 0xfc, 0xa5, 0xec, 0x9d, 0xc8, 0xcd, 0xac, 0x79, 0xd5, 0x7c, 0xb4, 0xdc, 0xb4, 0xdd, 0x74, 0xdd, 0xf4, 0xac, 0xfd, 0xaa, 0xfc, 0x56, 0xfc, 0xae, 0xfa, 0xad, 0xfe, 0xaa, 0x7f, 0xed, 0x5b, 0xfe, 0x55, 0xff, 0xff, 0xab, 0xaf, 0xf9, 0xf8, 0xfc, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x7f, 0x7f, 0x7f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x1f, 0x1f, 0x6e, 0xfb, 0x6e, 0xdb, 0x7e, 0xd5, 0x7f, 0xd5, 0x7f, 0xd5, 0xff, 0xaa, 0xff, 0x55, 0xff, 0x55, 0xff, 0x55, 0xff, 0xd6, 0xfd, 0xd7, 0x7d, 0xeb, 0xff, 0xaa, 0xff, 0xdb, 0x7f, 0xf5, 0xdf, 0x7b, 0xef, 0xfb, 0xed, 0xbf, 0xea, 0x7f, 0xea, 0xbf, 0xeb, 0xbe, 0xeb, 0x5e, 0xfb, 0x56, 0xff, 0x55, 0xff, 0xaa, 0xff, 0x56, 0xfd, 0x57, 0xfd, 0x57, 0xfd, 0x57, 0xfd, 0xb7, 0xb7, 0xda, 0x1a, 0x3f, 0x3f, 0x3f, 0x3f, 0x7f, 0x7f, 0x7f, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x7f, 0x7f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0xff, 0xff, 0xf, 0xf, 0xf, 0x1, 0x20, 0x8, 0x40, 0x10, 0x84, 0x0, 0xa8, 0x0, 0x2, 0xa8, 0x0, 0x2, 0xa8, 0x0, 0x42, 0xfd, 0x9f, 0x75, 0xdf, 0xb5, 0xdf, 0xb5, 0xff, 0xaa, 0x7f, 0x2a, 0x5f, 0x75, 0x3f, 0x6d, 0x7f, 0x5b, 0x7f, 0xf6, 0x3f, 0xed, 0x7f, 0xfb, 0xaf, 0x7e, 0xfb, 0x6f, 0xbd, 0xf7, 0x5f, 0xfd, 0x77, 0xde, 0x7f, 0xf5, 0x5f, 0x7f, 0xf5, 0x5f, 0xff, 0x35, 0xff, 0x57, 0x7d, 0x6f, 0x3d, 0x6b, 0x3f, 0x2a, 0xff, 0x55, 0xff, 0x95, 0x7f, 0x55, 0xff, 0x95, 0x6f, 0xa8, 0x40, 0x0, 0x2a, 0x0, 0x44, 0x10, 0x4, 0x40, 0x10, 0x84, 0x0, 0x28, 0x0, 0x20, 0x1, 0xf, 0x2f, 0x2f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0xff, 0x7, 0x7, 0x7, 0xa1, 0x0, 0x48, 0xa0, 0xd4, 0x30, 0xe8, 0x1a, 0x4, 0x18, 0x44, 0xc, 0x80, 0xe, 0x20, 0x84, 0x8c, 0x0, 0xcd, 0x8, 0x88, 0x92, 0x8, 0xa0, 0x2, 0x8, 0x42, 0xb0, 0x60, 0x9a, 0xf0, 0xc, 0x10, 0x4d, 0x8, 0x85, 0x24, 0x5, 0x48, 0x4, 0x84, 0x2c, 0x0, 0x8c, 0x19, 0x68, 0xb2, 0x48, 0xf1, 0x0, 0x44, 0x10, 0x0, 0x6c, 0xd8, 0x24, 0xfc, 0x80, 0x4c, 0x84, 0x48, 0x84, 0x4c, 0x80, 0x4c, 0x84, 0x48, 0xd4, 0x38, 0xe4, 0x18, 0x60, 0x4, 0x90, 0x2, 0x20, 0xc4, 0x31, 0xe8, 0x92, 0x78, 0x4, 0x19, 0x44, 0x9, 0x85, 0x25, 0x8, 0x85, 0x24, 0x4, 0x48, 0x5, 0x18, 0xb4, 0x49, 0xb0, 0xd4, 0x21, 0xcc, 0x0, 0x4c, 0x1, 0x8c, 0x24, 0x4, 0x88, 0x76, 0xa8, 0xdc, 0x30, 0x4e, 0x0, 0xc, 0x44, 0xc, 0x0, 0xc, 0x8, 0x62, 0x0, 0xa, 0x0, 0x10, 0x10, 0x80, 0xc0, 0xe0, 0xe2, 0x8, 0x0, 0x13, 0x6, 0x9, 0x27, 0xc, 0xc9, 0x18, 0x2, 0x58, 0x0, 0x9a, 0x10, 0x44, 0x18, 0x81, 0x18, 0x47, 0x18, 0x7, 0x4d, 0x2, 0x10, 0x4, 0x1, 0x13, 0x4, 0xb, 0x26, 0xd, 0xc8, 0x18, 0x82, 0x18, 0x10, 0x54, 0x1, 0x18, 0x40, 0x1a, 0x88, 0x98, 0xc6, 0x9, 0x27, 0xa, 0x85, 0x11, 0x40, 0xa, 0x20, 0x8b, 0x16, 0x49, 0x8e, 0x19, 0x80, 0x58, 0x82, 0x18, 0x81, 0x58, 0x8, 0x90, 0x89, 0xd8, 0x5, 0xe, 0x29, 0x7, 0x12, 0x4, 0x0, 0x68, 0x1, 0x87, 0xa0, 0xf, 0xa, 0xd4, 0x9, 0x18, 0x40, 0x1a, 0x0, 0x58, 0x2, 0x18, 0x40, 0x99, 0x4, 0x58, 0x6, 0x2b, 0x4, 0x13, 0x5, 0x80, 0x8, 0x2, 0x0, 0x28, 0x2, 0x40, 0x8, 0x97, 0xa, 0x9d, 0x53, 0x4, 0x0, 0x51, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80} func main() { raspiAdaptor := raspi.NewAdaptor() oled := spi.NewSSD1306Driver(raspiAdaptor) work := func() { _ = oled.Clear() if err := oled.SetBufferAndDisplay(gobotLogo); err != nil { fmt.Println(err) } } robot := gobot.NewRobot("ssd1360", []gobot.Connection{raspiAdaptor}, []gobot.Device{oled}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/raspi_stepper_move.go ================================================ //go:build example // +build example // // Do not build by default. //nolint:gosec // ok here package main import ( "log" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/raspi" ) func main() { const ( coilA1 = "7" coilA2 = "13" coilB1 = "11" coilB2 = "15" degPerStep = 1.875 countRot = 10 ) stepPerRevision := int(360.0 / degPerStep) r := raspi.NewAdaptor() stepper := gpio.NewStepperDriver(r, [4]string{coilA1, coilB1, coilA2, coilB2}, gpio.StepperModes.DualPhaseStepping, uint(stepPerRevision)) work := func() { defer func() { ec := 0 // set current to zero to prevent overheating if err := stepper.Sleep(); err != nil { ec = 1 log.Println("work done", err) } else { log.Println("work done") } os.Exit(ec) }() gobot.After(5*time.Second, func() { // this stops only the current movement and the next will start immediately (if any) // this means for the example, that the first rotation stops after ~5 rotations log.Println("asynchron stop after 5 sec.") if err := stepper.Stop(); err != nil { log.Println(err) } }) // one rotation per second if err := stepper.SetSpeed(60); err != nil { log.Println("set speed", err) } // Move forward N revolution if err := stepper.Move(stepPerRevision * countRot); err != nil { log.Println("move forward", err) } // Move backward N revolution if err := stepper.MoveDeg(-360 * countRot); err != nil { log.Println("move backward", err) } } robot := gobot.NewRobot("stepperBot", []gobot.Connection{r}, []gobot.Device{stepper}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/raspi_thermalzone.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "log" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" "gobot.io/x/gobot/v2/platforms/raspi" ) // Wiring: no wiring needed func main() { adaptor := raspi.NewAdaptor() therm0C := aio.NewThermalZoneDriver(adaptor, "thermal_zone0") therm0F := aio.NewThermalZoneDriver(adaptor, "thermal_zone0", aio.WithFahrenheit()) work := func() { gobot.Every(500*time.Millisecond, func() { t0C, err := therm0C.Read() if err != nil { log.Println(err) } t0F, err := therm0F.Read() if err != nil { log.Println(err) } fmt.Printf("Zone 0: %2.3f °C, %2.3f °F\n", t0C, t0F) }) } robot := gobot.NewRobot("thermalBot", []gobot.Connection{adaptor}, []gobot.Device{therm0C, therm0F}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/rock64_direct_pin.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/adaptors" "gobot.io/x/gobot/v2/platforms/pine64/rock64" ) // Wiring // PWR ROCK64: 1, P5_1 (+3.3V, VCC); 2, 4, P5_2 (+5V, VDD); 6, 9, 14, 20, P5_7, P5_8, P5_15, P5_16 (GND) // GPIO ROCK64: second header P5+BUS pin 3 is input, pin 4 is normal output, pin 5 is inverted output // Button: the input pin is wired with a button to GND, the internal pull up resistor is used // LED's: the output pins are wired to the cathode of the LED, the anode is wired with a resistor (70-130Ohm for 20mA) // to VCC // Expected behavior: always one LED is on, the other in opposite state, if button is pressed for >2 seconds the state // changes func main() { const ( inPinNum = "P5_3" outPinNum = "P5_4" outPinInvertedNum = "P5_5" debounceTime = 2 * time.Second ) // note: WithGpiosOpenDrain() is optional, if using WithGpiosOpenSource() the LED's will not light up board := rock64.NewAdaptor(adaptors.WithGpiosActiveLow(outPinInvertedNum), adaptors.WithGpiosOpenDrain(outPinNum, outPinInvertedNum), adaptors.WithGpiosPullUp(inPinNum), adaptors.WithGpioDebounce(inPinNum, debounceTime)) inPin := gpio.NewDirectPinDriver(board, inPinNum) outPin := gpio.NewDirectPinDriver(board, outPinNum) outPinInverted := gpio.NewDirectPinDriver(board, outPinInvertedNum) work := func() { level := byte(1) gobot.Every(500*time.Millisecond, func() { read, err := inPin.DigitalRead() fmt.Printf("pin %s state is %d\n", inPinNum, read) if err != nil { fmt.Println(err) if level == 1 { level = 0 } else { level = 1 } } else { level = byte(read) } err = outPin.DigitalWrite(level) fmt.Printf("pin %s is now %d\n", outPinNum, level) if err != nil { fmt.Println(err) } err = outPinInverted.DigitalWrite(level) fmt.Printf("pin %s is now not %d\n", outPinInvertedNum, level) if err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("pinBot", []gobot.Connection{board}, []gobot.Device{inPin, outPin, outPinInverted}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/rock64_yl40.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "log" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/pine64/rock64" ) func main() { // Wiring // PWR ROCK64: 1, P5_1 (+3.3V, VCC), 6, 9, 14, 20, P5_7, P5_8, P5_15, P5_16 (GND) // I2C0 ROCK64: 3 (SDA), 5 (SCL) // I2C1 ROCK64: 27 (SDA), 28 (SCL) // YL-40 module: wire AOUT --> AIN2 for this example // // Note: temperature measurement is often buggy, because sensor is not properly grounded // fix it by soldering a small bridge to the adjacent ground pin of brightness sensor board := rock64.NewAdaptor() yl := i2c.NewYL40Driver(board, i2c.WithBus(1)) work := func() { // the LED light is visible above ~1.7V writeVal, _ := yl.AOUT() gobot.Every(1000*time.Millisecond, func() { if err := yl.Write(writeVal); err != nil { fmt.Println(err) } else { log.Printf(" %.1f V written", writeVal) writeVal = writeVal + 0.1 if writeVal > 3.3 { writeVal = 0 } } if brightness, err := yl.ReadBrightness(); err != nil { fmt.Println(err) } else { log.Printf("Brightness: %.0f [0..1000]", brightness) } if temperature, err := yl.ReadTemperature(); err != nil { fmt.Println(err) } else { log.Printf("Temperature: %.1f °C", temperature) } if ain2, err := yl.ReadAIN2(); err != nil { fmt.Println(err) } else { log.Printf("Read back AOUT: %.1f [0..3.3]", ain2) } if potiState, err := yl.ReadPotentiometer(); err != nil { fmt.Println(err) } else { log.Printf("Resistor: %.0f %% [-100..+100]", potiState) } }) } robot := gobot.NewRobot("yl40Bot", []gobot.Connection{board}, []gobot.Device{yl}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/serialport_megapi_motor.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/serial/megapi" "gobot.io/x/gobot/v2/platforms/serialport" ) func main() { // use "/dev/ttyUSB0" if connecting with USB cable // use "/dev/ttyAMA0" on devices older than Raspberry Pi 3 Model B adaptor := serialport.NewAdaptor("/dev/ttyS0", serialport.WithName("MegaPi")) motor := megapi.NewMotorDriver(adaptor, 1) work := func() { speed := int16(0) fadeAmount := int16(30) gobot.Every(100*time.Millisecond, func() { if err := motor.Speed(speed); err != nil { fmt.Println(err) } speed = speed + fadeAmount if speed == 0 || speed == 300 { fadeAmount = -fadeAmount } }) } robot := gobot.NewRobot("megaPiBot", []gobot.Connection{adaptor}, []gobot.Device{motor}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/serialport_mindwave.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/serial/neurosky" "gobot.io/x/gobot/v2/platforms/serialport" ) func main() { adaptor := serialport.NewAdaptor("/dev/rfcomm0", serialport.WithName("Neurosky"), serialport.WithBaudRate(57600)) neuro := neurosky.NewMindWaveDriver(adaptor) work := func() { _ = neuro.On(neuro.Event("extended"), func(data interface{}) { fmt.Println("Extended", data) }) _ = neuro.On(neuro.Event("signal"), func(data interface{}) { fmt.Println("Signal", data) }) _ = neuro.On(neuro.Event("attention"), func(data interface{}) { fmt.Println("Attention", data) }) _ = neuro.On(neuro.Event("meditation"), func(data interface{}) { fmt.Println("Meditation", data) }) _ = neuro.On(neuro.Event("blink"), func(data interface{}) { fmt.Println("Blink", data) }) _ = neuro.On(neuro.Event("wave"), func(data interface{}) { fmt.Println("Wave", data) }) _ = neuro.On(neuro.Event("eeg"), func(data interface{}) { eeg := data.(neurosky.MindWaveEEGData) fmt.Println("Delta", eeg.Delta) fmt.Println("Theta", eeg.Theta) fmt.Println("LoAlpha", eeg.LoAlpha) fmt.Println("HiAlpha", eeg.HiAlpha) fmt.Println("LoBeta", eeg.LoBeta) fmt.Println("HiBeta", eeg.HiBeta) fmt.Println("LoGamma", eeg.LoGamma) fmt.Println("MidGamma", eeg.MidGamma) fmt.Printf("\n\n") }) } robot := gobot.NewRobot("brainBot", []gobot.Connection{adaptor}, []gobot.Device{neuro}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/serialport_sphero.go ================================================ //go:build example // +build example // // Do not build by default. //nolint:gosec // ok here package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/common/spherocommon" "gobot.io/x/gobot/v2/drivers/serial/sphero" "gobot.io/x/gobot/v2/platforms/serialport" ) func main() { adaptor := serialport.NewAdaptor("/dev/rfcomm0") spheroDriver := sphero.NewSpheroDriver(adaptor) work := func() { spheroDriver.SetDataStreaming(spherocommon.DefaultDataStreamingConfig()) _ = spheroDriver.On(spherocommon.CollisionEvent, func(data interface{}) { fmt.Printf("Collision! %+v\n", data) }) _ = spheroDriver.On(spherocommon.SensorDataEvent, func(data interface{}) { fmt.Printf("Streaming Data! %+v\n", data) }) gobot.Every(3*time.Second, func() { spheroDriver.Roll(30, uint16(gobot.Rand(360))) }) gobot.Every(1*time.Second, func() { r := uint8(gobot.Rand(255)) g := uint8(gobot.Rand(255)) b := uint8(gobot.Rand(255)) spheroDriver.SetRGB(r, g, b) }) } robot := gobot.NewRobot("sphero", []gobot.Connection{adaptor}, []gobot.Device{spheroDriver}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/serialport_sphero_api.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/api" "gobot.io/x/gobot/v2/drivers/serial/sphero" "gobot.io/x/gobot/v2/platforms/serialport" ) func main() { manager := gobot.NewManager() api.NewAPI(manager).Start() spheros := map[string]string{ "Sphero-BPO": "/dev/rfcomm0", } for name, port := range spheros { spheroAdaptor := serialport.NewAdaptor(port) spheroDriver := sphero.NewSpheroDriver(spheroAdaptor) work := func() { spheroDriver.SetRGB(uint8(255), uint8(0), uint8(0)) } robot := gobot.NewRobot(name, []gobot.Connection{spheroAdaptor}, []gobot.Device{spheroDriver}, work, ) robot.AddCommand("turn_blue", func(params map[string]interface{}) interface{} { spheroDriver.SetRGB(uint8(0), uint8(0), uint8(255)) return nil }) manager.AddRobot(robot) } if err := manager.Start(); err != nil { panic(err) } } ================================================ FILE: examples/serialport_sphero_calibration.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/api" "gobot.io/x/gobot/v2/drivers/serial/sphero" "gobot.io/x/gobot/v2/platforms/keyboard" "gobot.io/x/gobot/v2/platforms/serialport" ) func main() { manager := gobot.NewManager() a := api.NewAPI(manager) a.Start() ballConn := serialport.NewAdaptor("/dev/rfcomm0") ball := sphero.NewSpheroDriver(ballConn) keys := keyboard.NewDriver() calibrating := false work := func() { _ = keys.On(keyboard.Key, func(data interface{}) { key := data.(keyboard.KeyEvent) switch key.Key { case keyboard.ArrowUp: if calibrating { break } ball.Roll(100, 0) case keyboard.ArrowDown: if calibrating { break } ball.Roll(100, 100) case keyboard.ArrowLeft: ball.Roll(100, 270) case keyboard.ArrowRight: ball.Roll(100, 90) case keyboard.Spacebar: if calibrating { ball.FinishCalibration() } else { ball.StartCalibration() } calibrating = !calibrating } }) } robot := gobot.NewRobot("sphero-calibration", []gobot.Connection{ballConn}, []gobot.Device{ball, keys}, work, ) manager.AddRobot(robot) if err := manager.Start(); err != nil { panic(err) } } ================================================ FILE: examples/serialport_sphero_conways.go ================================================ //go:build example // +build example // // Do not build by default. //nolint:gosec // ok here package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/common/spherocommon" "gobot.io/x/gobot/v2/drivers/serial" "gobot.io/x/gobot/v2/drivers/serial/sphero" "gobot.io/x/gobot/v2/platforms/serialport" ) type conway struct { alive bool age int contacts int cell *sphero.SpheroDriver } func main() { manager := gobot.NewManager() spheros := []string{ "/dev/rfcomm0", "/dev/rfcomm1", "/dev/rfcomm2", } for _, port := range spheros { spheroAdaptor := serialport.NewAdaptor(port) cell := sphero.NewSpheroDriver(spheroAdaptor, serial.WithName("Sphero"+port)) work := func() { conway := new(conway) conway.cell = cell conway.birth() _ = cell.On(spherocommon.CollisionEvent, func(data interface{}) { conway.contact() }) gobot.Every(3*time.Second, func() { if conway.alive { conway.movement() } }) gobot.Every(10*time.Second, func() { if conway.alive { conway.birthday() } }) } robot := gobot.NewRobot("conway", []gobot.Connection{spheroAdaptor}, []gobot.Device{cell}, work, ) manager.AddRobot(robot) } if err := manager.Start(); err != nil { panic(err) } } func (c *conway) resetContacts() { c.contacts = 0 } func (c *conway) contact() { c.contacts++ } func (c *conway) rebirth() { fmt.Println("Welcome back", c.cell.Name(), "!") c.life() } func (c *conway) birth() { c.resetContacts() c.age = 0 c.life() c.movement() } func (c *conway) life() { c.cell.SetRGB(0, 255, 0) c.alive = true } func (c *conway) death() { fmt.Println(c.cell.Name(), "died :(") c.alive = false c.cell.SetRGB(255, 0, 0) c.cell.Stop() } func (c *conway) enoughContacts() bool { if c.contacts >= 2 && c.contacts < 7 { return true } return false } func (c *conway) birthday() { c.age++ fmt.Println("Happy birthday", c.cell.Name(), "you are", c.age, "and had", c.contacts, "contacts.") if c.enoughContacts() { if !c.alive { c.rebirth() } } else { c.death() } c.resetContacts() } func (c *conway) movement() { if c.alive { c.cell.Roll(100, uint16(gobot.Rand(360))) } } ================================================ FILE: examples/serialport_sphero_dpad.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/api" "gobot.io/x/gobot/v2/drivers/serial/sphero" "gobot.io/x/gobot/v2/platforms/serialport" ) func main() { manager := gobot.NewManager() a := api.NewAPI(manager) a.Start() conn := serialport.NewAdaptor("/dev/rfcomm0") ball := sphero.NewSpheroDriver(conn) robot := gobot.NewRobot("sphero-dpad", []gobot.Connection{conn}, []gobot.Device{ball}, ) robot.AddCommand("move", func(params map[string]interface{}) interface{} { direction := params["direction"].(string) switch direction { case "up": ball.Roll(100, 0) case "down": ball.Roll(100, 180) case "left": ball.Roll(100, 270) case "right": ball.Roll(100, 90) } time.Sleep(2 * time.Second) ball.Stop() return "ok" }) manager.AddRobot(robot) if err := manager.Start(); err != nil { panic(err) } } ================================================ FILE: examples/serialport_sphero_master.go ================================================ //go:build example // +build example // // Do not build by default. //nolint:gosec // ok here package main import ( "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/serial/sphero" "gobot.io/x/gobot/v2/platforms/serialport" ) func main() { manager := gobot.NewManager() spheros := map[string]string{ "Sphero-BPO": "/dev/rfcomm0", } for name, port := range spheros { spheroAdaptor := serialport.NewAdaptor(port) spheroDriver := sphero.NewSpheroDriver(spheroAdaptor) work := func() { spheroDriver.SetRGB(uint8(255), uint8(0), uint8(0)) } robot := gobot.NewRobot(name, []gobot.Connection{spheroAdaptor}, []gobot.Device{spheroDriver}, work, ) manager.AddRobot(robot) } robot := gobot.NewRobot("", func() { gobot.Every(1*time.Second, func() { sphero := manager.Robot("Sphero-BPO").Device("sphero").(*sphero.SpheroDriver) sphero.SetRGB(uint8(gobot.Rand(255)), uint8(gobot.Rand(255)), uint8(gobot.Rand(255)), ) }) }, ) manager.AddRobot(robot) if err := manager.Start(); err != nil { panic(err) } } ================================================ FILE: examples/serialport_sphero_multiple.go ================================================ //go:build example // +build example // // Do not build by default. //nolint:gosec // ok here package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/api" "gobot.io/x/gobot/v2/drivers/common/spherocommon" "gobot.io/x/gobot/v2/drivers/serial" "gobot.io/x/gobot/v2/drivers/serial/sphero" "gobot.io/x/gobot/v2/platforms/serialport" ) func NewSwarmBot(port string) *gobot.Robot { spheroAdaptor := serialport.NewAdaptor(port) spheroDriver := sphero.NewSpheroDriver(spheroAdaptor, serial.WithName("Sphero"+port)) work := func() { spheroDriver.Stop() _ = spheroDriver.On(spherocommon.CollisionEvent, func(data interface{}) { fmt.Println("Collision Detected!") }) gobot.Every(1*time.Second, func() { spheroDriver.Roll(100, uint16(gobot.Rand(360))) }) gobot.Every(3*time.Second, func() { spheroDriver.SetRGB(uint8(gobot.Rand(255)), uint8(gobot.Rand(255)), uint8(gobot.Rand(255)), ) }) } robot := gobot.NewRobot("sphero", []gobot.Connection{spheroAdaptor}, []gobot.Device{spheroDriver}, work, ) return robot } func main() { manager := gobot.NewManager() api.NewAPI(manager).Start() spheros := []string{ "/dev/rfcomm0", "/dev/rfcomm1", "/dev/rfcomm2", "/dev/rfcomm3", } for _, port := range spheros { manager.AddRobot(NewSwarmBot(port)) } if err := manager.Start(); err != nil { panic(err) } } ================================================ FILE: examples/square.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/api" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/intel-iot/edison" ) func main() { manager := gobot.NewManager() a := api.NewAPI(manager) a.Start() board := edison.NewAdaptor() red := gpio.NewLedDriver(board, "3") green := gpio.NewLedDriver(board, "5") blue := gpio.NewLedDriver(board, "6") button := gpio.NewButtonDriver(board, "7") enabled := true work := func() { if err := red.Brightness(0xff); err != nil { fmt.Println(err) } if err := green.Brightness(0x00); err != nil { fmt.Println(err) } if err := blue.Brightness(0x00); err != nil { fmt.Println(err) } flash := false on := true gobot.Every(250*time.Millisecond, func() { if enabled { if flash { if on { if err := red.Brightness(0x00); err != nil { fmt.Println(err) } if err := green.Brightness(0xff); err != nil { fmt.Println(err) } if err := blue.Brightness(0x00); err != nil { fmt.Println(err) } on = false } else { if err := red.Brightness(0xff); err != nil { fmt.Println(err) } if err := green.Brightness(0x00); err != nil { fmt.Println(err) } if err := blue.Brightness(0x00); err != nil { fmt.Println(err) } on = true } } } }) _ = button.On(gpio.ButtonPush, func(data interface{}) { flash = true }) _ = button.On(gpio.ButtonRelease, func(data interface{}) { flash = false if err := red.Brightness(0x00); err != nil { fmt.Println(err) } if err := green.Brightness(0x00); err != nil { fmt.Println(err) } if err := blue.Brightness(0xff); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot( "square of fire", []gobot.Connection{board}, []gobot.Device{red, green, blue, button}, work, ) robot.AddCommand("enable", func(params map[string]interface{}) interface{} { enabled = !enabled return enabled }) manager.AddRobot(robot) if err := manager.Start(); err != nil { panic(err) } } ================================================ FILE: examples/square_fire.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/api" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/intel-iot/edison" ) func main() { manager := gobot.NewManager() a := api.NewAPI(manager) a.Start() board := edison.NewAdaptor() red := gpio.NewLedDriver(board, "3") green := gpio.NewLedDriver(board, "5") blue := gpio.NewLedDriver(board, "6") button := gpio.NewButtonDriver(board, "7") enabled := true work := func() { if err := red.Brightness(0xff); err != nil { fmt.Println(err) } if err := green.Brightness(0x00); err != nil { fmt.Println(err) } if err := blue.Brightness(0x00); err != nil { fmt.Println(err) } flash := false on := true gobot.Every(50*time.Millisecond, func() { if enabled { if flash { if on { if err := red.Brightness(0x00); err != nil { fmt.Println(err) } if err := green.Brightness(0xff); err != nil { fmt.Println(err) } if err := blue.Brightness(0x00); err != nil { fmt.Println(err) } on = false } else { if err := red.Brightness(0x00); err != nil { fmt.Println(err) } if err := green.Brightness(0x00); err != nil { fmt.Println(err) } if err := blue.Brightness(0xff); err != nil { fmt.Println(err) } on = true } } } }) _ = button.On(gpio.ButtonPush, func(data interface{}) { flash = true }) _ = button.On(gpio.ButtonRelease, func(data interface{}) { flash = false if err := red.Brightness(0x00); err != nil { fmt.Println(err) } if err := green.Brightness(0x00); err != nil { fmt.Println(err) } if err := blue.Brightness(0xff); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot( "square of fire", []gobot.Connection{board}, []gobot.Device{red, green, blue, button}, work, ) robot.AddCommand("enable", func(params map[string]interface{}) interface{} { enabled = !enabled return enabled }) manager.AddRobot(robot) if err := manager.Start(); err != nil { panic(err) } } ================================================ FILE: examples/tello.go ================================================ //go:build example // +build example // // Do not build by default. /* How to run: Connect to the drone's Wi-Fi network from your computer. It will be named something like "TELLO-XXXXXX". Once you are connected you can run the Gobot code on your computer to control the drone. go run examples/tello.go */ package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/dji/tello" ) func main() { drone := tello.NewDriver("8888") work := func() { if err := drone.TakeOff(); err != nil { fmt.Println(err) } gobot.After(5*time.Second, func() { if err := drone.Land(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("tello", []gobot.Connection{}, []gobot.Device{drone}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/tello_facetracker.go ================================================ //go:build example // +build example // // Do not build by default. /* You must have ffmpeg and OpenCV installed in order to run this code. It will connect to the Tello and then open a window using OpenCV showing the streaming video. How to run go run examples/tello_facetracker.go ~/Downloads/res10_300x300_ssd_iter_140000.caffemodel ~/Development/opencv/samples/dnn/face_detector/deploy.prototxt You can find download the weight via https://github.com/opencv/opencv_3rdparty/raw/dnn_samples_face_detector_20170830/res10_300x300_ssd_iter_140000.caffemodel And you can find protofile in OpenCV samples directory */ package main import ( "fmt" "image" "image/color" "io" "math" "os" "os/exec" "strconv" "sync/atomic" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/dji/tello" "gobot.io/x/gobot/v2/platforms/joystick" "gocv.io/x/gocv" ) type pair struct { x float64 y float64 } const ( frameX = 400 frameY = 300 frameSize = frameX * frameY * 3 offset = 32767.0 ) var ( // ffmpeg command to decode video stream from drone ffmpeg = exec.Command("ffmpeg", "-hwaccel", "auto", "-hwaccel_device", "opencl", "-i", "pipe:0", "-nostats", "-flags", "low_delay", "-probesize", "32", "-fflags", "nobuffer+fastseek+flush_packets", "-analyzeduration", "0", "-af", "aresample=async=1:min_comp=0.1:first_pts=0", "-pix_fmt", "bgr24", "-s", strconv.Itoa(frameX)+"x"+strconv.Itoa(frameY), "-f", "rawvideo", "pipe:1") ffmpegIn, _ = ffmpeg.StdinPipe() ffmpegOut, _ = ffmpeg.StdoutPipe() // gocv window = gocv.NewWindow("Tello") net *gocv.Net green = color.RGBA{0, 255, 0, 0} // tracking tracking = false detected = false detectSize = false distTolerance = 0.05 * dist(0, 0, frameX, frameY) refDistance float64 left, top, right, bottom float64 // drone drone = tello.NewDriver("8890") flightData *tello.FlightData // joystick joyAdaptor = joystick.NewAdaptor("0") stick = joystick.NewDriver(joyAdaptor, "dualshock4") leftX, leftY, rightX, rightY atomic.Value ) func init() { leftX.Store(float64(0.0)) leftY.Store(float64(0.0)) rightX.Store(float64(0.0)) rightY.Store(float64(0.0)) // process drone events in separate goroutine for concurrency go func() { handleJoystick() if err := ffmpeg.Start(); err != nil { fmt.Println(err) return } _ = drone.On(tello.FlightDataEvent, func(data interface{}) { // TODO: protect flight data from race condition flightData = data.(*tello.FlightData) }) _ = drone.On(tello.ConnectedEvent, func(data interface{}) { fmt.Println("Connected") if err := drone.StartVideo(); err != nil { fmt.Println(err) } if err := drone.SetVideoEncoderRate(tello.VideoBitRateAuto); err != nil { fmt.Println(err) } if err := drone.SetExposure(0); err != nil { fmt.Println(err) } gobot.Every(100*time.Millisecond, func() { if err := drone.StartVideo(); err != nil { fmt.Println(err) } }) }) _ = drone.On(tello.VideoFrameEvent, func(data interface{}) { pkt := data.([]byte) if _, err := ffmpegIn.Write(pkt); err != nil { fmt.Println(err) } }) robot := gobot.NewRobot("tello", []gobot.Connection{joyAdaptor}, []gobot.Device{drone, stick}, ) err := robot.Start() if err != nil { fmt.Println(err) } }() } func main() { if len(os.Args) < 5 { fmt.Println("How to run:\ngo run facetracker.go [model] [config] ([backend] [device])") return } model := os.Args[1] config := os.Args[2] backend := gocv.NetBackendDefault if len(os.Args) > 3 { backend = gocv.ParseNetBackend(os.Args[3]) } target := gocv.NetTargetCPU if len(os.Args) > 4 { target = gocv.ParseNetTarget(os.Args[4]) } n := gocv.ReadNet(model, config) if n.Empty() { fmt.Printf("Error reading network model from : %v %v\n", model, config) return } net = &n defer net.Close() net.SetPreferableBackend(gocv.NetBackendType(backend)) net.SetPreferableTarget(gocv.NetTargetType(target)) for { // get next frame from stream buf := make([]byte, frameSize) if _, err := io.ReadFull(ffmpegOut, buf); err != nil { fmt.Println(err) continue } img, _ := gocv.NewMatFromBytes(frameY, frameX, gocv.MatTypeCV8UC3, buf) if img.Empty() { continue } trackFace(&img) window.IMShow(img) if window.WaitKey(10) >= 0 { break } } } func trackFace(frame *gocv.Mat) { W := float64(frame.Cols()) H := float64(frame.Rows()) blob := gocv.BlobFromImage(*frame, 1.0, image.Pt(300, 300), gocv.NewScalar(104, 177, 123, 0), false, false) defer blob.Close() net.SetInput(blob, "data") detBlob := net.Forward("detection_out") defer detBlob.Close() detections := gocv.GetBlobChannel(detBlob, 0, 0) defer detections.Close() for r := 0; r < detections.Rows(); r++ { confidence := detections.GetFloatAt(r, 2) if confidence < 0.5 { continue } left = float64(detections.GetFloatAt(r, 3)) * W top = float64(detections.GetFloatAt(r, 4)) * H right = float64(detections.GetFloatAt(r, 5)) * W bottom = float64(detections.GetFloatAt(r, 6)) * H left = math.Min(math.Max(0.0, left), W-1.0) right = math.Min(math.Max(0.0, right), W-1.0) bottom = math.Min(math.Max(0.0, bottom), H-1.0) top = math.Min(math.Max(0.0, top), H-1.0) detected = true rect := image.Rect(int(left), int(top), int(right), int(bottom)) gocv.Rectangle(frame, rect, green, 3) } if !tracking || !detected { return } if detectSize { detectSize = false refDistance = dist(left, top, right, bottom) } distance := dist(left, top, right, bottom) // x axis switch { case right < W/2: drone.CounterClockwise(50) case left > W/2: drone.Clockwise(50) default: drone.Clockwise(0) } // y axis switch { case top < H/10: drone.Up(25) case bottom > H-H/10: drone.Down(25) default: drone.Up(0) } // z axis switch { case distance < refDistance-distTolerance: drone.Forward(20) case distance > refDistance+distTolerance: drone.Backward(20) default: drone.Forward(0) } } func dist(x1, y1, x2, y2 float64) float64 { return math.Sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1)) } func handleJoystick() { _ = stick.On(joystick.CirclePress, func(data interface{}) { drone.Forward(0) drone.Up(0) drone.Clockwise(0) tracking = !tracking if tracking { detectSize = true println("tracking") } else { detectSize = false println("not tracking") } }) _ = stick.On(joystick.SquarePress, func(data interface{}) { fmt.Println("battery:", flightData.BatteryPercentage) }) _ = stick.On(joystick.TrianglePress, func(data interface{}) { drone.TakeOff() println("Takeoff") }) _ = stick.On(joystick.XPress, func(data interface{}) { drone.Land() println("Land") }) _ = stick.On(joystick.LeftX, func(data interface{}) { val := float64(data.(int16)) leftX.Store(val) }) _ = stick.On(joystick.LeftY, func(data interface{}) { val := float64(data.(int16)) leftY.Store(val) }) _ = stick.On(joystick.RightX, func(data interface{}) { val := float64(data.(int16)) rightX.Store(val) }) _ = stick.On(joystick.RightY, func(data interface{}) { val := float64(data.(int16)) rightY.Store(val) }) gobot.Every(50*time.Millisecond, func() { rightStick := getRightStick() switch { case rightStick.y < -10: if err := drone.Forward(tello.ValidatePitch(rightStick.y, offset)); err != nil { fmt.Println(err) } case rightStick.y > 10: if err := drone.Backward(tello.ValidatePitch(rightStick.y, offset)); err != nil { fmt.Println(err) } default: if err := drone.Forward(0); err != nil { fmt.Println(err) } } switch { case rightStick.x > 10: if err := drone.Right(tello.ValidatePitch(rightStick.x, offset)); err != nil { fmt.Println(err) } case rightStick.x < -10: if err := drone.Left(tello.ValidatePitch(rightStick.x, offset)); err != nil { fmt.Println(err) } default: if err := drone.Right(0); err != nil { fmt.Println(err) } } }) gobot.Every(50*time.Millisecond, func() { leftStick := getLeftStick() switch { case leftStick.y < -10: if err := drone.Up(tello.ValidatePitch(leftStick.y, offset)); err != nil { fmt.Println(err) } case leftStick.y > 10: if err := drone.Down(tello.ValidatePitch(leftStick.y, offset)); err != nil { fmt.Println(err) } default: if err := drone.Up(0); err != nil { fmt.Println(err) } } switch { case leftStick.x > 20: if err := drone.Clockwise(tello.ValidatePitch(leftStick.x, offset)); err != nil { fmt.Println(err) } case leftStick.x < -20: if err := drone.CounterClockwise(tello.ValidatePitch(leftStick.x, offset)); err != nil { fmt.Println(err) } default: if err := drone.Clockwise(0); err != nil { fmt.Println(err) } } }) } func getLeftStick() pair { s := pair{x: 0, y: 0} s.x = leftX.Load().(float64) s.y = leftY.Load().(float64) return s } func getRightStick() pair { s := pair{x: 0, y: 0} s.x = rightX.Load().(float64) s.y = rightY.Load().(float64) return s } ================================================ FILE: examples/tello_keyboard.go ================================================ //go:build example // +build example // // Do not build by default. /* How to run: Connect to the drone's Wi-Fi network from your computer. It will be named something like "TELLO-XXXXXX". Once you are connected you can run the Gobot code on your computer to control the drone. go run examples/tello_keyboard.go */ package main import ( "fmt" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/dji/tello" "gobot.io/x/gobot/v2/platforms/keyboard" ) func resetDronePostion(drone *tello.Driver) { if err := drone.Forward(0); err != nil { fmt.Println(err) } if err := drone.Backward(0); err != nil { fmt.Println(err) } if err := drone.Up(0); err != nil { fmt.Println(err) } if err := drone.Down(0); err != nil { fmt.Println(err) } if err := drone.Left(0); err != nil { fmt.Println(err) } if err := drone.Right(0); err != nil { fmt.Println(err) } if err := drone.Clockwise(0); err != nil { fmt.Println(err) } } func main() { drone := tello.NewDriver("8888") keys := keyboard.NewDriver() _ = keys.On(keyboard.Key, func(data interface{}) { key := data.(keyboard.KeyEvent) switch key.Key { case keyboard.A: fmt.Println(key.Char) if err := drone.Clockwise(-25); err != nil { fmt.Println(err) } case keyboard.D: fmt.Println(key.Char) if err := drone.Clockwise(25); err != nil { fmt.Println(err) } case keyboard.W: fmt.Println(key.Char) if err := drone.Forward(20); err != nil { fmt.Println(err) } case keyboard.S: fmt.Println(key.Char) if err := drone.Backward(20); err != nil { fmt.Println(err) } case keyboard.K: fmt.Println(key.Char) if err := drone.Down(20); err != nil { fmt.Println(err) } case keyboard.J: fmt.Println(key.Char) if err := drone.Up(20); err != nil { fmt.Println(err) } case keyboard.Q: fmt.Println(key.Char) if err := drone.Land(); err != nil { fmt.Println(err) } case keyboard.P: fmt.Println(key.Char) if err := drone.TakeOff(); err != nil { fmt.Println(err) } case keyboard.ArrowUp: fmt.Println(key.Char) if err := drone.FrontFlip(); err != nil { fmt.Println(err) } case keyboard.ArrowDown: fmt.Println(key.Char) if err := drone.BackFlip(); err != nil { fmt.Println(err) } case keyboard.ArrowLeft: fmt.Println(key.Char) if err := drone.LeftFlip(); err != nil { fmt.Println(err) } case keyboard.ArrowRight: fmt.Println(key.Char) if err := drone.RightFlip(); err != nil { fmt.Println(err) } case keyboard.Escape: resetDronePostion(drone) } }) var flightData *tello.FlightData work := func() { _ = drone.On(tello.FlightDataEvent, func(data interface{}) { flightData = data.(*tello.FlightData) fmt.Println("Height:", flightData.Height) }) } robot := gobot.NewRobot("tello", []gobot.Connection{}, []gobot.Device{keys, drone}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/tello_opencv.go ================================================ //go:build example // +build example // // Do not build by default. /* You must have ffmpeg and OpenCV installed in order to run this code. It will connect to the Tello and then open a window using OpenCV showing the streaming video. How to run go run examples/tello_opencv.go */ package main import ( "fmt" "io" "os/exec" "strconv" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/dji/tello" "gocv.io/x/gocv" ) const ( frameX = 960 frameY = 720 frameSize = frameX * frameY * 3 ) func main() { drone := tello.NewDriver("8890") window := gocv.NewWindow("Tello") ffmpeg := exec.Command("ffmpeg", "-hwaccel", "auto", "-hwaccel_device", "opencl", "-i", "pipe:0", "-pix_fmt", "bgr24", "-s", strconv.Itoa(frameX)+"x"+strconv.Itoa(frameY), "-f", "rawvideo", "pipe:1") ffmpegIn, _ := ffmpeg.StdinPipe() ffmpegOut, _ := ffmpeg.StdoutPipe() work := func() { if err := ffmpeg.Start(); err != nil { fmt.Println(err) return } _ = drone.On(tello.ConnectedEvent, func(data interface{}) { fmt.Println("Connected") if err := drone.StartVideo(); err != nil { fmt.Println(err) } if err := drone.SetVideoEncoderRate(tello.VideoBitRateAuto); err != nil { fmt.Println(err) } if err := drone.SetExposure(0); err != nil { fmt.Println(err) } gobot.Every(100*time.Millisecond, func() { if err := drone.StartVideo(); err != nil { fmt.Println(err) } }) }) _ = drone.On(tello.VideoFrameEvent, func(data interface{}) { pkt := data.([]byte) if _, err := ffmpegIn.Write(pkt); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("tello", []gobot.Connection{}, []gobot.Device{drone}, work, ) // calling Start(false) lets the Start routine return immediately without an additional blocking goroutine robot.Start(false) // now handle video frames from ffmpeg stream in main thread, to be macOS/Windows friendly for { buf := make([]byte, frameSize) if _, err := io.ReadFull(ffmpegOut, buf); err != nil { fmt.Println(err) continue } img, _ := gocv.NewMatFromBytes(frameY, frameX, gocv.MatTypeCV8UC3, buf) if img.Empty() { continue } window.IMShow(img) if window.WaitKey(1) >= 0 { break } } } ================================================ FILE: examples/tello_ps3.go ================================================ //go:build example // +build example // // Do not build by default. /* How to setup You must be using a PS3 or compatible controller, along with a DJI Tello drone to run this example. You run the Go program on your computer and communicate wirelessly via WiFi with the Tello. How to run go run examples/tello_ps3.go */ package main import ( "fmt" "sync/atomic" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/dji/tello" "gobot.io/x/gobot/v2/platforms/joystick" ) type pair struct { x float64 y float64 } var leftX, leftY, rightX, rightY atomic.Value const offset = 32767.0 func main() { joystickAdaptor := joystick.NewAdaptor("0") stick := joystick.NewDriver(joystickAdaptor, "dualshock3") drone := tello.NewDriver("8888") work := func() { leftX.Store(float64(0.0)) leftY.Store(float64(0.0)) rightX.Store(float64(0.0)) rightY.Store(float64(0.0)) _ = stick.On(joystick.TrianglePress, func(data interface{}) { if err := drone.TakeOff(); err != nil { fmt.Println(err) } }) _ = stick.On(joystick.XPress, func(data interface{}) { if err := drone.Land(); err != nil { fmt.Println(err) } }) _ = stick.On(joystick.UpPress, func(data interface{}) { fmt.Println("FrontFlip") if err := drone.FrontFlip(); err != nil { fmt.Println(err) } }) _ = stick.On(joystick.DownPress, func(data interface{}) { fmt.Println("BackFlip") if err := drone.BackFlip(); err != nil { fmt.Println(err) } }) _ = stick.On(joystick.RightPress, func(data interface{}) { fmt.Println("RightFlip") if err := drone.RightFlip(); err != nil { fmt.Println(err) } }) _ = stick.On(joystick.LeftPress, func(data interface{}) { fmt.Println("LeftFlip") if err := drone.LeftFlip(); err != nil { fmt.Println(err) } }) _ = stick.On(joystick.LeftX, func(data interface{}) { val := float64(data.(int)) leftX.Store(val) }) _ = stick.On(joystick.LeftY, func(data interface{}) { val := float64(data.(int)) leftY.Store(val) }) _ = stick.On(joystick.RightX, func(data interface{}) { val := float64(data.(int)) rightX.Store(val) }) _ = stick.On(joystick.RightY, func(data interface{}) { val := float64(data.(int)) rightY.Store(val) }) gobot.Every(50*time.Millisecond, func() { rightStick := getRightStick() switch { case rightStick.y < -10: if err := drone.Forward(tello.ValidatePitch(rightStick.y, offset)); err != nil { fmt.Println(err) } case rightStick.y > 10: if err := drone.Backward(tello.ValidatePitch(rightStick.y, offset)); err != nil { fmt.Println(err) } default: if err := drone.Forward(0); err != nil { fmt.Println(err) } } switch { case rightStick.x > 10: if err := drone.Right(tello.ValidatePitch(rightStick.x, offset)); err != nil { fmt.Println(err) } case rightStick.x < -10: if err := drone.Left(tello.ValidatePitch(rightStick.x, offset)); err != nil { fmt.Println(err) } default: if err := drone.Right(0); err != nil { fmt.Println(err) } } }) gobot.Every(50*time.Millisecond, func() { leftStick := getLeftStick() switch { case leftStick.y < -10: if err := drone.Up(tello.ValidatePitch(leftStick.y, offset)); err != nil { fmt.Println(err) } case leftStick.y > 10: if err := drone.Down(tello.ValidatePitch(leftStick.y, offset)); err != nil { fmt.Println(err) } default: if err := drone.Up(0); err != nil { fmt.Println(err) } } switch { case leftStick.x > 20: if err := drone.Clockwise(tello.ValidatePitch(leftStick.x, offset)); err != nil { fmt.Println(err) } case leftStick.x < -20: if err := drone.CounterClockwise(tello.ValidatePitch(leftStick.x, offset)); err != nil { fmt.Println(err) } default: if err := drone.Clockwise(0); err != nil { fmt.Println(err) } } }) } robot := gobot.NewRobot("tello", []gobot.Connection{joystickAdaptor}, []gobot.Device{stick, drone}, work, ) if err := robot.Start(); err != nil { panic(err) } } func getLeftStick() pair { s := pair{x: 0, y: 0} s.x = leftX.Load().(float64) s.y = leftY.Load().(float64) return s } func getRightStick() pair { s := pair{x: 0, y: 0} s.x = rightX.Load().(float64) s.y = rightY.Load().(float64) return s } ================================================ FILE: examples/tello_video.go ================================================ //go:build example // +build example // // Do not build by default. /* You must have MPlayer (https://mplayerhq.hu) installed in order to run this code. it will connect to the Tello and then open a window using MPlayer showing the streaming video. How to run go run examples/tello_video.go */ package main import ( "fmt" "os/exec" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/dji/tello" ) func main() { drone := tello.NewDriver("8890") mplayer := exec.Command("mplayer", "-fps", "60", "-") mplayerIn, _ := mplayer.StdinPipe() if err := mplayer.Start(); err != nil { fmt.Println(err) return } work := func() { _ = drone.On(tello.ConnectedEvent, func(data interface{}) { fmt.Println("Connected") if err := drone.StartVideo(); err != nil { fmt.Println(err) } if err := drone.SetVideoEncoderRate(tello.VideoBitRateAuto); err != nil { fmt.Println(err) } gobot.Every(100*time.Millisecond, func() { if err := drone.StartVideo(); err != nil { fmt.Println(err) } }) }) _ = drone.On(tello.VideoFrameEvent, func(data interface{}) { pkt := data.([]byte) if _, err := mplayerIn.Write(pkt); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("tello", []gobot.Connection{}, []gobot.Device{drone}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/tinkerboard2_direct_pin_bin_counter.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/adaptors" "gobot.io/x/gobot/v2/platforms/asus/tinkerboard2" ) // Wiring // PWR Tinkerboard-2: 1 (+3.3V, VCC), 2(+5V), 6, 9, 14, 20 (GND) // GPIO Tinkerboard-2: header pins 3, 5, 7, 11 used as inverted output // LED's: the output pins are wired to the cathode of a LED, the anode is wired with a resistor (70-130Ohm for 20mA) // to +3.3V (use >150Ohm if connected to +5V) // Expected behavior: the 4 LED's on normal output counts up binary func main() { const ( outPinBit0Num = "3" outPinBit1Num = "5" outPinBit2Num = "7" outPinBit3Num = "11" ) board := tinkerboard2.NewAdaptor(adaptors.WithGpiosActiveLow(outPinBit0Num, outPinBit1Num, outPinBit2Num, outPinBit3Num)) outPinB0 := gpio.NewDirectPinDriver(board, outPinBit0Num) outPinB1 := gpio.NewDirectPinDriver(board, outPinBit1Num) outPinB2 := gpio.NewDirectPinDriver(board, outPinBit2Num) outPinB3 := gpio.NewDirectPinDriver(board, outPinBit3Num) work := func() { value := byte(0) gobot.Every(500*time.Millisecond, func() { b0 := value & 0x01 b1 := (value & 0x02) / 0x02 b2 := (value & 0x04) / 0x04 b3 := (value & 0x08) / 0x08 if err := outPinB0.DigitalWrite(b0); err != nil { fmt.Println(err) } else { fmt.Printf("pin %s is now %d\n", outPinBit0Num, b0) } if err := outPinB1.DigitalWrite(b1); err != nil { fmt.Println(err) } else { fmt.Printf("pin %s is now %d\n", outPinBit1Num, b1) } if err := outPinB2.DigitalWrite(b2); err != nil { fmt.Println(err) } else { fmt.Printf("pin %s is now %d\n", outPinBit2Num, b2) } if err := outPinB3.DigitalWrite(b3); err != nil { fmt.Println(err) } else { fmt.Printf("pin %s is now %d\n", outPinBit3Num, b3) } value++ if value > 15 { value = 0 } }) } robot := gobot.NewRobot("pinBot", []gobot.Connection{board}, []gobot.Device{outPinB0, outPinB1, outPinB2, outPinB3}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/tinkerboard2_yl40.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "log" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/asus/tinkerboard2" ) func main() { // Wiring // PWR Tinkerboard 2: 1 (+3.3V, VCC), 6, 9, 14, 20 (GND) // I2C1 Tinkerboard 2: 27 (SDA), 28 (SCL) // YL-40 module: wire AOUT --> AIN2 for this example, set all jumpers for temp, LDR and variable resistor // // Note: temperature measurement is often buggy, because sensor is not properly grounded // fix it by soldering a small bridge to the adjacent ground pin of brightness sensor board := tinkerboard2.NewAdaptor() yl := i2c.NewYL40Driver(board, i2c.WithBus(7)) work := func() { // the LED light is visible above ~1.7V writeVal, _ := yl.AOUT() gobot.Every(1000*time.Millisecond, func() { if err := yl.Write(writeVal); err != nil { fmt.Println(err) } else { log.Printf(" %.1f V written", writeVal) writeVal = writeVal + 0.1 if writeVal > 3.3 { writeVal = 0 } } if brightness, err := yl.ReadBrightness(); err != nil { fmt.Println(err) } else { log.Printf("Brightness: %.0f [0..1000]", brightness) } if temperature, err := yl.ReadTemperature(); err != nil { fmt.Println(err) } else { log.Printf("Temperature: %.1f °C", temperature) } if ain2, err := yl.ReadAIN2(); err != nil { fmt.Println(err) } else { log.Printf("Read back AOUT: %.1f [0..3.3]", ain2) } if potiState, err := yl.ReadPotentiometer(); err != nil { fmt.Println(err) } else { log.Printf("Resistor: %.0f %% [-100..+100]", potiState) } }) } robot := gobot.NewRobot("yl40Bot", []gobot.Connection{board}, []gobot.Device{yl}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/tinkerboard_adafruit1109_lcd_keys.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/asus/tinkerboard" ) // Wiring // PWR Tinkerboard: 1 (+3.3V, VCC), 2 (+5V), 6, 9, 14, 20 (GND) // I2C1 Tinkerboard: 3 (SDA), 5 (SCL) // PLATE: connected via pin header (pin 1..26) func main() { board := tinkerboard.NewAdaptor() ada := i2c.NewAdafruit1109Driver(board, i2c.WithBus(1)) work := func() { // set a custom character smiley := [8]byte{0, 0, 10, 0, 0, 17, 14, 0} if err := ada.CreateChar(0, smiley); err != nil { fmt.Println(err) } if err := ada.Clear(); err != nil { fmt.Println(err) } if err := ada.SetRGB(true, false, false); err != nil { fmt.Println(err) } if err := ada.Write(" Hello from \n Tinker Board "); err != nil { fmt.Println(err) } // add the custom character at the end of the string if err := ada.Write(string(byte(0))); err != nil { fmt.Println(err) } // after 1 sec. activate rotation direction := 1 gobot.After(1*time.Second, func() { if err := ada.SetRGB(false, true, false); err != nil { fmt.Println(err) } gobot.Every(400*time.Millisecond, func() { if direction == 1 { if err := ada.ScrollLeft(); err != nil { fmt.Println(err) } } if direction == 2 { if err := ada.ScrollRight(); err != nil { fmt.Println(err) } } }) }) // after 7 sec. activate play with the buttons gobot.After(7*time.Second, func() { direction = 0 time.Sleep(1 * time.Second) if err := ada.LeftToRight(); err != nil { fmt.Println(err) } if err := ada.Clear(); err != nil { fmt.Println(err) } if err := ada.SetRGB(false, false, true); err != nil { fmt.Println(err) } if err := ada.Write("Try the buttons!"); err != nil { fmt.Println(err) } gobot.Every(500*time.Millisecond, func() { if val, err := ada.SelectButton(); err != nil { fmt.Println(err) } else if val != 0 { if err := ada.Clear(); err != nil { fmt.Println(err) } if err := ada.Write("-Select Button-\nclear the screen"); err != nil { fmt.Println(err) } if err := ada.Blink(false); err != nil { fmt.Println(err) } direction = 0 } if val, err := ada.UpButton(); err != nil { fmt.Println(err) } else if val != 0 { if err := ada.Clear(); err != nil { fmt.Println(err) } if err := ada.Write(" -Up Button- \nset RGB to white"); err != nil { fmt.Println(err) } if err := ada.Blink(false); err != nil { fmt.Println(err) } if err := ada.SetRGB(true, true, true); err != nil { fmt.Println(err) } direction = 0 } if val, err := ada.DownButton(); err != nil { fmt.Println(err) } else if val != 0 { if err := ada.Clear(); err != nil { fmt.Println(err) } if err := ada.Write(" -Down Button- \nset blink on"); err != nil { fmt.Println(err) } if err := ada.Blink(true); err != nil { fmt.Println(err) } direction = 0 } if val, err := ada.LeftButton(); err != nil { fmt.Println(err) } else if val != 0 { if err := ada.Clear(); err != nil { fmt.Println(err) } if err := ada.Write(" -Left Button- \nrotate left"); err != nil { fmt.Println(err) } if err := ada.Blink(false); err != nil { fmt.Println(err) } direction = 1 } if val, err := ada.RightButton(); err != nil { fmt.Println(err) } else if val != 0 { if err := ada.Clear(); err != nil { fmt.Println(err) } if err := ada.Write(" -Right Button- \nrotate right"); err != nil { fmt.Println(err) } if err := ada.Blink(false); err != nil { fmt.Println(err) } direction = 2 } }) }) } robot := gobot.NewRobot("adaBot", []gobot.Connection{board}, []gobot.Device{ada}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/tinkerboard_ads1115.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/asus/tinkerboard" ) // Wiring // PWR Tinkerboard: 1 (+3.3V, VCC), 2(+5V), 6, 9, 14, 20 (GND) // I2C1 Tinkerboard: 3 (SDA-ws), 5 (SCL-gn) // ADS1115 plate: VDD (2.0..5.5V), GND, SDL, SDA, A0..A3 (input voltage 0..5V) func main() { const voltage = 5.0 // we will be able to read values of at least 5V (for all channels) a := tinkerboard.NewAdaptor() ads1115 := i2c.NewADS1115Driver(a, i2c.WithADS1x15BestGainForVoltage(voltage)) work := func() { var a0, a1, a2, a3 float64 var err error gobot.Every(2*time.Second, func() { a0, err = ads1115.ReadWithDefaults(0) if err != nil { fmt.Println(err) } else { fmt.Println("A0", a0) } a1, err = ads1115.ReadWithDefaults(1) if err != nil { fmt.Println(err) } else { fmt.Println("A1", a1) } a2, err = ads1115.ReadWithDefaults(2) if err != nil { fmt.Println(err) } else { fmt.Println("A2", a2) } a3, err = ads1115.ReadWithDefaults(3) if err != nil { fmt.Println(err) } else { fmt.Println("A3", a3) } if v, err := ads1115.ReadDifferenceWithDefaults(0); err != nil { fmt.Println(err) } else { fmt.Printf("A0-A1 %f, (e: %f)\n", v, v-(a0-a1)) } if v, err := ads1115.ReadDifferenceWithDefaults(1); err != nil { fmt.Println(err) } else { fmt.Printf("A0-A3 %f, (e: %f)\n", v, v-(a0-a3)) } if v, err := ads1115.ReadDifferenceWithDefaults(2); err != nil { fmt.Println(err) } else { fmt.Printf("A1-A3 %f, (e: %f)\n", v, v-(a1-a3)) } if v, err := ads1115.ReadDifferenceWithDefaults(3); err != nil { fmt.Println(err) } else { fmt.Printf("A2-A3 %f, (e: %f)\n", v, v-(a2-a3)) } fmt.Println("-------------") }) } robot := gobot.NewRobot("ads1115bot", []gobot.Connection{a}, []gobot.Device{ads1115}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/tinkerboard_adxl345.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/asus/tinkerboard" ) // Wiring // PWR Tinkerboard: 1 (+3.3V, VCC), 2(+5V), 6, 9, 14, 20 (GND) // I2C1 Tinkerboard: 3 (SDA-ws), 5 (SCL-gn) // ADXL345 plate: VCC, GND, SDL, SDA func main() { a := tinkerboard.NewAdaptor() adxl := i2c.NewADXL345Driver(a) work := func() { gobot.Every(1000*time.Millisecond, func() { if x, y, z, err := adxl.XYZ(); err != nil { fmt.Println(err) } else { fmt.Printf("x: %.7f | y: %.7f | z: %.7f \n", x, y, z) } }) } robot := gobot.NewRobot("mpBot", []gobot.Connection{a}, []gobot.Device{adxl}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/tinkerboard_blink.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/asus/tinkerboard" ) func main() { r := tinkerboard.NewAdaptor() led := gpio.NewLedDriver(r, "7") work := func() { gobot.Every(1*time.Second, func() { if err := led.Toggle(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("blinkBot", []gobot.Connection{r}, []gobot.Device{led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/tinkerboard_bme280.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/asus/tinkerboard" ) // Wiring // PWR Tinkerboard: 1 (+3.3V, VCC), 2(+5V), 6, 9, 14, 20 (GND) // I2C1 Tinkerboard: 3 (SDA-ws), 5 (SCL-gn) // BME280 plate: VIN (2.5..5V), GND, SDL, SDA, SDO to GND func main() { a := tinkerboard.NewAdaptor() bme280 := i2c.NewBME280Driver(a, i2c.WithAddress(0x76), i2c.WithBME280PressureOversampling(0x05), i2c.WithBME280TemperatureOversampling(0x02), i2c.WithBME280HumidityOversampling(0x01), i2c.WithBME280IIRFilter(0x05)) work := func() { gobot.Every(2*time.Second, func() { t, e := bme280.Temperature() fmt.Println("Temperature [°C]", t) if e != nil { fmt.Println(e) } p, e := bme280.Pressure() fmt.Println("Pressure [Pa]", p) // 100hPa = 1Pa if e != nil { fmt.Println(e) } a, e := bme280.Altitude() fmt.Println("Altitude [m]", a) if e != nil { fmt.Println(e) } h, e := bme280.Humidity() fmt.Println("Humidity [%]", h) if e != nil { fmt.Println(e) } fmt.Println("-------------") }) } robot := gobot.NewRobot("bme280bot", []gobot.Connection{a}, []gobot.Device{bme280}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/tinkerboard_bmp280.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/asus/tinkerboard" ) // Wiring // PWR Tinkerboard: 1 (+3.3V, VCC), 2(+5V), 6, 9, 14, 20 (GND) // I2C1 Tinkerboard: 3 (SDA-ws), 5 (SCL-gn) // BMP280 plate: VIN (2.5..5V), GND, SDL, SDA, SDO to GND func main() { a := tinkerboard.NewAdaptor() bmp280 := i2c.NewBMP280Driver(a, i2c.WithAddress(0x76), i2c.WithBME280PressureOversampling(0x05), i2c.WithBME280TemperatureOversampling(0x02), i2c.WithBME280IIRFilter(0x05)) work := func() { gobot.Every(2*time.Second, func() { t, e := bmp280.Temperature() fmt.Println("Temperature [°C]", t) if e != nil { fmt.Println(e) } p, e := bmp280.Pressure() fmt.Println("Pressure [Pa]", p) // 100hPa = 1Pa if e != nil { fmt.Println(e) } a, e := bmp280.Altitude() fmt.Println("Altitude [m]", a) if e != nil { fmt.Println(e) } fmt.Println("-------------") }) } robot := gobot.NewRobot("bmp280bot", []gobot.Connection{a}, []gobot.Device{bmp280}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/tinkerboard_button.go ================================================ //go:build example // +build example // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/asus/tinkerboard" ) // Wiring // PWR Tinkerboard: 1 (+3.3V, VCC), 2(+5V), 6, 9, 14, 20 (GND) // GPIO Tinkerboard: header pin 22 is input, pin 7 is normal output // Button: the input pin is wired with a button to GND, an external pull up resistor is needed (e.g. 1K) // LED: the output pin is wired to the cathode of a LED, the anode is wired with a resistor (70-130Ohm for 20mA) to VCC // Expected behavior: LED is initially on, if button is pressed and released, the state changes func main() { const ( buttonPin = "22" ledPin = "7" ) a := tinkerboard.NewAdaptor() button := gpio.NewButtonDriver(a, buttonPin, gpio.WithButtonPollInterval(100*time.Millisecond)) led := gpio.NewLedDriver(a, ledPin) if err := led.On(); err != nil { fmt.Println(err) } work := func() { if err := button.On(gpio.Error, func(err interface{}) { fmt.Println("an error occurred:", err) }); err != nil { panic(err) } if err := button.On(gpio.ButtonPush, func(interface{}) { fmt.Println("button pressed") if err := led.On(); err != nil { fmt.Println(err) } }); err != nil { panic(err) } if err := button.On(gpio.ButtonRelease, func(interface{}) { fmt.Println("button released") if err := led.Off(); err != nil { fmt.Println(err) } }); err != nil { panic(err) } } robot := gobot.NewRobot("buttonBot", []gobot.Connection{a}, []gobot.Device{button, led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/tinkerboard_direct_pin.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/adaptors" "gobot.io/x/gobot/v2/platforms/asus/tinkerboard" ) // Wiring // PWR Tinkerboard: 1 (+3.3V, VCC), 2(+5V), 6, 9, 14, 20 (GND) // GPIO Tinkerboard: header pin 21 is input, pin 24 used as normal output, pin 26 used as inverted output // Button: the input pin is wired with a button to GND, an external pull up resistor is needed (e.g. 1K) // LED's: the output pins are wired to the cathode of a LED, the anode is wired with a resistor (70-130Ohm for 20mA) // to VCC // Expected behavior: always one LED is on, the other in opposite state, on button press the state changes func main() { const ( inPinNum = "21" outPinNum = "24" outPinInvertedNum = "26" ) board := tinkerboard.NewAdaptor(adaptors.WithGpiosActiveLow(outPinInvertedNum)) inPin := gpio.NewDirectPinDriver(board, inPinNum) outPin := gpio.NewDirectPinDriver(board, outPinNum) outPinInverted := gpio.NewDirectPinDriver(board, outPinInvertedNum) work := func() { level := byte(1) gobot.Every(500*time.Millisecond, func() { read, err := inPin.DigitalRead() fmt.Printf("pin %s state is %d\n", inPinNum, read) if err != nil { fmt.Println(err) } else { level = byte(read) } err = outPin.DigitalWrite(level) fmt.Printf("pin %s is now %d\n", outPinNum, level) if err != nil { fmt.Println(err) } err = outPinInverted.DigitalWrite(level) fmt.Printf("pin %s is now not %d\n", outPinInvertedNum, level) if err != nil { fmt.Println(err) } if level == 1 { level = 0 } else { level = 1 } }) } robot := gobot.NewRobot("pinBot", []gobot.Connection{board}, []gobot.Device{inPin, outPin, outPinInverted}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/tinkerboard_ds18b20.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "log" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/onewire" "gobot.io/x/gobot/v2/platforms/asus/tinkerboard" ) // Preparation: see /gobot/system/ONEWIRE.md and /gobot/platforms/asus/tinkerboard/README.md // // Wiring: // PWR Tinkerboard: 1 (+3.3V, VCC), 6, 9, 14, 20 (GND) // 1-wire Tinkerboard: 7 (DQ) - resistor to VCC, ~1.5kOhm ... 5kOhm // DS18B20: 1 (GND), 2 (DQ), 3 (VDD, +3 ... 5.5V) for local power mode func main() { adaptor := tinkerboard.NewAdaptor() // resolution change not supported by all devices temp0 := onewire.NewDS18B20Driver(adaptor, 0x072261452f18, onewire.WithResolution(10)) temp1 := onewire.NewDS18B20Driver(adaptor, 0x1465421f64ff, onewire.WithFahrenheit(), onewire.WithConversionTime(500)) work := func() { time0, err := temp0.ConversionTime() if err != nil { log.Printf("Err CT0: %v\n", err) } res0, err := temp0.Resolution() if err != nil { log.Printf("Err R0: %v\n", err) } log.Printf("Conversion time @%d bit for Temp 0: %d ms\n", res0, time0) time1, err := temp1.ConversionTime() if err != nil { log.Printf("Err CT1: %v\n", err) } res1, err := temp1.Resolution() if err != nil { log.Printf("Err R1: %v\n", err) } log.Printf("Conversion time @%d bit for Temp 0: %d ms\n", res1, time1) gobot.Every(10*(time.Duration(time0))*time.Millisecond, func() { t0, err := temp0.Temperature() if err != nil { log.Printf("Err Temp 0: %v\n", err) } fmt.Printf("Temp 0: %2.1f °C\n", t0) }) gobot.Every(10*(time.Duration(time1))*time.Millisecond, func() { t1, err := temp1.Temperature() if err != nil { log.Printf("Err Temp 1: %v\n", err) } fmt.Printf("Temp 1: %2.3f °F\n", t1) }) } robot := gobot.NewRobot("onewireBot", []gobot.Connection{adaptor}, []gobot.Device{temp0, temp1}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/tinkerboard_generic.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "reflect" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/asus/tinkerboard" ) // Attention! Possibly this will not work, because the current kernel of Tinker-OS 4.4.194 (2021-10-06) needs the // workaround for bad timing to emulate a PCA9501 EEPROM random read (switch on the flag below in this case). // The armbian image with kernel 5.15.74-rockchip (2022-10-18) is known to work. // // Wiring // PWR Tinkerboard: 1 (+3.3V, VCC), 6, 9, 14, 20 (GND) // I2C1 Tinkerboard: 3 (SDA), 5 (SCL) // PCA9501: 20 (VDD, +2.5..3.6V), 10 (VSS, GND), 19 (SDA), 18 (SCL) // HW address pins: 1 (A0), 2 (A1), 3 (A2), 12 (A3), 11 (A4), 9 (A5) func main() { const ( defaultAddress = 0x7F // with open address pins (internal pull-up) myAddress = 0x44 // needs to be adjusted for your configuration workaroundBadTiming = false eepromAddr = uint8(0x02) dataLen = 7 write = true read = true ) board := tinkerboard.NewAdaptor() drv := i2c.NewGenericDriver(board, "PCA9501-EEPROM", defaultAddress, i2c.WithAddress(myAddress)) var valWr uint8 = 0x09 var err error wData := make([]byte, dataLen) rData := make([]byte, dataLen) work := func() { gobot.Every(500*time.Millisecond, func() { // write "dataLen" values, starting by EEPROM address valWr++ if write { for i := range wData { wData[i] = byte(i) + valWr } err = drv.WriteBlockData(eepromAddr, wData) if err != nil { fmt.Println("err write:", err) } else if read != write { fmt.Printf("EEPROM addr: %d, wr: %v\n", eepromAddr, wData) } } // write process needs some time, so wait at least 5ms before read a value // when decreasing to much, the check below will fail time.Sleep(10 * time.Millisecond) if read { if workaroundBadTiming { err = readBlockDataBadTiming(drv, eepromAddr, rData) } else { err = drv.ReadBlockData(eepromAddr, rData) } if err != nil { fmt.Println("err read:", err) } else if read != write { fmt.Printf("EEPROM addr: %d, rd: %v\n", eepromAddr, rData) } } // compare read and write if read && write { if reflect.DeepEqual(wData, rData) { fmt.Printf("EEPROM addr: %d equal: %v\n", eepromAddr, rData) } else { fmt.Printf("EEPROM addr: %d wr: %v differ rd: %v\n", eepromAddr, wData, rData) } } }) } robot := gobot.NewRobot("genericDriverI2c", []gobot.Connection{board}, []gobot.Device{drv}, work, ) if err := robot.Start(); err != nil { panic(err) } } // workaround for some boards (e.g. tinkerboard), because Read*Data not working together with PCA9501, // caused by bad timing func readBlockDataBadTiming(drv *i2c.GenericDriver, reg uint8, data []byte) error { // set a value to the dummy address if err := drv.WriteByteData(reg-1, 0x00); err != nil { return err } // write process needs some time, so wait at least 5ms before read a value // when decreasing to much, the check below will fail time.Sleep(20 * time.Millisecond) return drv.Read(data) } ================================================ FILE: examples/tinkerboard_grove_lcd.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/asus/tinkerboard" ) func main() { board := tinkerboard.NewAdaptor() screen := i2c.NewGroveLcdDriver(board) work := func() { if err := screen.Write("Hello from"); err != nil { fmt.Println(err) } if err := screen.SetRGB(255, 0, 0); err != nil { fmt.Println(err) } gobot.After(5*time.Second, func() { if err := screen.Clear(); err != nil { fmt.Println(err) } if err := screen.Home(); err != nil { fmt.Println(err) } if err := screen.SetRGB(0, 255, 0); err != nil { fmt.Println(err) } // set a custom character in the first position if err := screen.SetCustomChar(0, i2c.CustomLCDChars["smiley"]); err != nil { fmt.Println(err) } // add the custom character at the end of the string if err := screen.Write("\nTinker Board " + string(byte(0))); err != nil { fmt.Println(err) } gobot.Every(500*time.Millisecond, func() { if err := screen.Scroll(false); err != nil { fmt.Println(err) } }) }) if err := screen.Home(); err != nil { fmt.Println(err) } time.Sleep(1 * time.Second) if err := screen.SetRGB(0, 0, 255); err != nil { fmt.Println(err) } } robot := gobot.NewRobot("screenBot", []gobot.Connection{board}, []gobot.Device{screen}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/tinkerboard_hcsr04.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "log" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/asus/tinkerboard" ) // Wiring // PWR Tinkerboard: 2(+5V), 6, 9, 14, 20 (GND) // GPIO Tinkerboard: header pin 7 is the trigger output, pin 22 used as echo input // HC-SR04: the power is wired to +5V and GND of tinkerboard, the same for trigger output and the echo input pin func main() { const ( triggerOutput = "7" echoInput = "22" ) // this is mandatory for systems with defunct edge detection, although the "cdev" is used with an newer Kernel // keep in mind, that this cause more inaccurate measurements const pollEdgeDetection = true opts := []interface{}{} if pollEdgeDetection { opts = append(opts, gpio.WithHCSR04UseEdgePolling()) } a := tinkerboard.NewAdaptor() hcsr04 := gpio.NewHCSR04Driver(a, triggerOutput, echoInput, opts...) work := func() { if pollEdgeDetection { fmt.Println("Please note that measurements are CPU consuming and will be more inaccurate with this setting.") fmt.Println("After startup the system is under load and the measurement is very inaccurate, so wait a bit...") time.Sleep(2000 * time.Millisecond) } if err := hcsr04.StartDistanceMonitor(); err != nil { log.Fatal(err) } // first single shot if v, err := hcsr04.MeasureDistance(); err != nil { log.Fatal(err) } else { fmt.Printf("first single shot done: %5.3f m\n", v) } ticker := gobot.Every(1*time.Second, func() { fmt.Printf("continuous measurement: %5.3f m\n", hcsr04.Distance()) }) gobot.After(5*time.Second, func() { if err := hcsr04.StopDistanceMonitor(); err != nil { log.Fatal(err) } ticker.Stop() }) gobot.After(7*time.Second, func() { // second single shot if v, err := hcsr04.MeasureDistance(); err != nil { log.Fatal(err) } else { fmt.Printf("second single shot done: %5.3f m\n", v) } // cleanup if err := hcsr04.Halt(); err != nil { log.Println(err) } if err := a.Finalize(); err != nil { log.Println(err) } os.Exit(0) }) } robot := gobot.NewRobot("distanceBot", []gobot.Connection{a}, []gobot.Device{hcsr04}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/tinkerboard_hmc5883l.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "log" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/asus/tinkerboard" ) // Wiring // PWR Tinkerboard: 1 (+3.3V, VCC), 6, 9, 14, 20 (GND) // I2C1 Tinkerboard: 3 (SDA), 5 (SCL) // HMC5883L plate: VCC, GND, SDL, SDA func main() { a := tinkerboard.NewAdaptor() hmc := i2c.NewHMC5883LDriver(a) work := func() { var x, y, z, h float64 var err error gobot.Every(1000*time.Millisecond, func() { if x, y, z, err = hmc.Read(); err != nil { fmt.Println(err) } else { log.Printf("Xn: %f, Yn: %f, Zn: %f", x, y, z) } if h, err = hmc.Heading(); err != nil { fmt.Println(err) } else { log.Printf("Heading: %.1f", h) } }) } robot := gobot.NewRobot("hcBot", []gobot.Connection{a}, []gobot.Device{hmc}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/tinkerboard_mfcrc522gpio.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/spi" "gobot.io/x/gobot/v2/platforms/adaptors" "gobot.io/x/gobot/v2/platforms/asus/tinkerboard" ) // Wiring // PWR Tinkerboard: 1 (+3.3V, VCC), 2(+5V), 6, 9, 14, 20 (GND) // GPIO-SPI Tinkerboard (same as SPI2): 23 (CLK), 19 (TXD), 21 (RXD), 24 (CSN0) // MFRC522 plate: VCC, GND, SCK (CLK), SDO (->TXD), SDI (->RXD), NCS/SDA (CSN0/CSN1?) const ( sclk = "23" ncs = "24" sdo = "19" sdi = "21" speedHz = 5000 // more than 15kHz is not possible with GPIO's, so we choose 5kHz ) func main() { a := tinkerboard.NewAdaptor(adaptors.WithSpiGpioAccess(sclk, ncs, sdo, sdi)) d := spi.NewMFRC522Driver(a, spi.WithSpeed(speedHz)) wasCardDetected := false const textToCard = "Hello RFID user!\nHey, we use GPIO's for SPI." work := func() { if err := d.PrintReaderVersion(); err != nil { fmt.Println("get version err:", err) } gobot.Every(2*time.Second, func() { if !wasCardDetected { fmt.Println("\n+++ poll for card +++") if err := d.IsCardPresent(); err != nil { fmt.Println("no card found") } else { fmt.Println("\n+++ write card +++") err := d.WriteText(textToCard) if err != nil { fmt.Println("write err:", err) } wasCardDetected = true } } else { fmt.Println("\n+++ read card +++") text, err := d.ReadText() if err != nil { fmt.Println("read err:", err) wasCardDetected = false } else { fmt.Printf("-- start text --\n%s\n-- end text --\n", text) } } }) } robot := gobot.NewRobot("gpioSpiBot", []gobot.Connection{a}, []gobot.Device{d}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/tinkerboard_mfcrc522spi.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/spi" "gobot.io/x/gobot/v2/platforms/asus/tinkerboard" ) // Wiring // PWR Tinkerboard: 1 (+3.3V, VCC), 2(+5V), 6, 9, 14, 20 (GND) // SPI0 Tinkerboard (not working with armbian): 11 (CLK), 13 (TXD), 15 (RXD), 29 (CSN0), 31 (CSN1, n.c.) // SPI2 Tinkerboard: 23 (CLK), 19 (TXD), 21 (RXD), 24 (CSN0), 26 (CSN1, n.c.) // MFRC522 plate: VCC, GND, SCK (CLK), SDO (->TXD), SDI (->RXD), NCS/SDA (CSN0/CSN1?) func main() { a := tinkerboard.NewAdaptor() d := spi.NewMFRC522Driver(a, spi.WithBusNumber(2)) wasCardDetected := false const textToCard = "Hello RFID user!\nThis text was written to card." work := func() { if err := d.PrintReaderVersion(); err != nil { fmt.Println("get version err:", err) } gobot.Every(2*time.Second, func() { if !wasCardDetected { fmt.Println("\n+++ poll for card +++") if err := d.IsCardPresent(); err != nil { fmt.Println("no card found") } else { fmt.Println("\n+++ write card +++") err := d.WriteText(textToCard) if err != nil { fmt.Println("write err:", err) } wasCardDetected = true } } else { fmt.Println("\n+++ read card +++") text, err := d.ReadText() if err != nil { fmt.Println("read err:", err) wasCardDetected = false } else { fmt.Printf("-- start text --\n%s\n-- end text --\n", text) } } }) } robot := gobot.NewRobot("spiBot", []gobot.Connection{a}, []gobot.Device{d}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/tinkerboard_motor.go ================================================ //go:build example // +build example // Do not build by default. package main import ( "fmt" "log" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/asus/tinkerboard" ) // Wiring // PWR Tinkerboard: 1 (+3.3V, VCC), 2(+5V), 6, 9, 14, 20 (GND) // PWM Tinkerboard: header pin 33 (PWM2) or pin 32 (PWM3) // Please decouple the PWM pin with an amplifier, e.g. a simple MOSFET (IRLZ34N, IRF530 etc.), a half H-bridge or // just use a LED for the first tests. func main() { adaptor := tinkerboard.NewAdaptor() motor := gpio.NewMotorDriver(adaptor, "32", gpio.WithMotorAnalog()) // gpio.WithMotorAnalog() is optional here work := func() { fmt.Println("first try full speed for 5 seconds...") if err := motor.On(); err != nil { log.Println(err) } time.Sleep(5 * time.Second) fmt.Println("second switch off for 5 seconds...") if err := motor.Off(); err != nil { log.Println(err) } time.Sleep(5 * time.Second) fmt.Println("finally fade in and out forever...") speed := byte(0) fadeAmount := byte(15) gobot.Every(100*time.Millisecond, func() { if err := motor.SetSpeed(speed); err != nil { log.Println(err) } speed = speed + fadeAmount if speed == 0 || speed == 255 { fadeAmount = -fadeAmount } }) } robot := gobot.NewRobot("motorBot", []gobot.Connection{adaptor}, []gobot.Device{motor}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/tinkerboard_mpl115a2.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/asus/tinkerboard" ) // Wiring // PWR Tinkerboard: 1 (+3.3V, VCC), 2(+5V), 6, 9, 14, 20 (GND) // I2C1 Tinkerboard: 3 (SDA-ws), 5 (SCL-gn) // MPL115A2 plate: VDD (2.375..5.5V), GND, SDL, SDA func main() { board := tinkerboard.NewAdaptor() mpl115a2 := i2c.NewMPL115A2Driver(board) work := func() { gobot.Every(2*time.Second, func() { if press, err := mpl115a2.Pressure(); err != nil { fmt.Println(err) } else { fmt.Println("Pressure [kPa]", press) } if temp, err := mpl115a2.Temperature(); err != nil { fmt.Println(err) } else { fmt.Println("Temperature [°C]", temp) } fmt.Println("-------------") }) } robot := gobot.NewRobot("mpl115Bot", []gobot.Connection{board}, []gobot.Device{mpl115a2}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/tinkerboard_mpu6050.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/asus/tinkerboard" ) // Wiring // PWR Tinkerboard: 1 (+3.3V, VCC), 2(+5V), 6, 9, 14, 20 (GND) // I2C1 Tinkerboard: 3 (SDA-ws), 5 (SCL-gn) // MPU6050 plate: VCC, GND, SDL, SDA func main() { a := tinkerboard.NewAdaptor() mpu6050 := i2c.NewMPU6050Driver(a) work := func() { var err error gobot.Every(1000*time.Millisecond, func() { if err = mpu6050.GetData(); err != nil { fmt.Println(err) } else { fmt.Printf("Acc: %v Gyr: %v Temp: %v\n", mpu6050.Accelerometer, mpu6050.Gyroscope, mpu6050.Temperature) } }) } robot := gobot.NewRobot("mpBot", []gobot.Connection{a}, []gobot.Device{mpu6050}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/tinkerboard_pca9533.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/asus/tinkerboard" ) // Wiring // PWR Tinkerboard: 1 (+3.3V, VCC), 6, 9, 14, 20 (GND) // I2C1 Tinkerboard: 3 (SDA), 5 (SCL) // PCA9533: 8 (VDD, +2.3..5.5V), 4 (VSS, GND), 7 (SDA), 6 (SCL) // LED pins: 1 (LED0), 2 (LED1), 3 (LED2), 5 (LED3) // LED's directly driven with pull-up resistors to VDD, e.g. 180 Ohm // I2C addresses: 0x62 (PCA9533/01), 0x63 (PCA9533/02) func main() { board := tinkerboard.NewAdaptor() pca := i2c.NewPCA953xDriver(board, i2c.WithAddress(0x63)) led := uint8(0) // index of LED wVal := uint8(1) // start with LED is "off" rVal := uint8(0) work := func() { // LED 2 with 2 Hz 1:1, LED 3 with 5 Hz 1:10 initialize(pca, 2, 5) gobot.Every(2000*time.Millisecond, func() { fmt.Printf("set LED%d output to %d", led, wVal) err := pca.WriteGPIO(led, wVal) if err != nil { fmt.Println("errW:", err) } rVal, err = pca.ReadGPIO(led) if err != nil { fmt.Println("errR:", err) } if rVal == 0 { fmt.Printf(" - LED%d is ON\n", led) } else { fmt.Printf(" - LED%d is OFF\n", led) } led = led + 1 if led > 1 { led = 0 if wVal == 1 { wVal = 0 } else { wVal = 1 } } }) } robot := gobot.NewRobot("ledI2c", []gobot.Connection{board}, []gobot.Device{pca}, work, ) if err := robot.Start(); err != nil { panic(err) } } func initialize(pca *i2c.PCA953xDriver, led2FrequHz float32, led3FrequHz float32) { // prepare PWM0 err := pca.WriteFrequency(0, led2FrequHz) if err != nil { fmt.Println("errWF0:", err) } frq, err := pca.ReadFrequency(0) if err != nil { fmt.Println("errRF0:", err) } fmt.Println("get Frq0:", frq) err = pca.WriteDutyCyclePercent(0, 50) if err != nil { fmt.Println("errWD0:", err) } dc, err := pca.ReadDutyCyclePercent(0) if err != nil { fmt.Println("errRD0:", err) } fmt.Println("get dc0:", dc) // prepare PWM1 err = pca.WriteFrequency(1, led3FrequHz) if err != nil { fmt.Println("errWF1:", err) } frq, err = pca.ReadFrequency(1) if err != nil { fmt.Println("errRF1:", err) } fmt.Println("get Frq1:", frq) err = pca.WriteDutyCyclePercent(1, 10) if err != nil { fmt.Println("errWD1:", err) } dc, err = pca.ReadDutyCyclePercent(1) if err != nil { fmt.Println("errRD1:", err) } fmt.Println("get dc1:", dc) // LED 2 fmt.Println("set LED: 2 to: pwm0") err = pca.SetLED(2, i2c.PCA953xModePwm0) if err != nil { fmt.Println("errW:", err) } fmt.Println("set LED: 3 to: pwm1") err = pca.SetLED(3, i2c.PCA953xModePwm1) if err != nil { fmt.Println("errW:", err) } } ================================================ FILE: examples/tinkerboard_pcf8583_clock.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "log" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/asus/tinkerboard" ) // Wiring // PWR Tinkerboard: 1(+3.3V, VCC), 6,9,14,20(GND) // I2C1 Tinkerboard: 3(SDA), 5(SCL) // PCF8583 DIP package: 1(OSCI,50Hz), 2(OSCO,nc), 3(A0-GND), 4(VSS,GND), 5(SDA), 6(SCL), 7(/INT,nc), 8(VDD,+3.3V) func main() { board := tinkerboard.NewAdaptor() pcf := i2c.NewPCF8583Driver(board, i2c.WithBus(1), i2c.WithPCF8583Mode(i2c.PCF8583CtrlModeClock50)) work := func() { currentTime := time.Now() log.Println(currentTime) if err := pcf.WriteTime(currentTime); err != nil { fmt.Println(err) } gobot.Every(10*time.Second, func() { if val, err := pcf.ReadTime(); err != nil { fmt.Println(err) } else { log.Printf("read Time: %v", val) } ramVal, err := pcf.ReadRAM(uint8(0)) if err != nil { fmt.Println(err) } else { log.Printf("read RAM: %v", ramVal) ramVal++ } if err := pcf.WriteRAM(uint8(0), ramVal); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("pcfBot", []gobot.Connection{board}, []gobot.Device{pcf}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/tinkerboard_pcf8583_counter.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "log" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/asus/tinkerboard" ) // Wiring // PWR Tinkerboard: 1(+3.3V,VCC), 6,9,14,20(GND) // I2C1 Tinkerboard: 3(SDA), 5(SCL) // PCF8583 DIP package: 1(OSCI,event), 2(OSCO,nc), 3(A0-GND), 4(VSS,GND), 5(SDA), 6(SCL), 7(/INT,nc), 8(VDD,+3.3V) // Note: event can be created by e.g. an debounced button func main() { board := tinkerboard.NewAdaptor() pcf := i2c.NewPCF8583Driver(board, i2c.WithBus(1), i2c.WithPCF8583Mode(i2c.PCF8583CtrlModeCounter)) work := func() { lastCnt := int32(1234) if err := pcf.WriteCounter(lastCnt); err != nil { fmt.Println(err) } gobot.Every(1000*time.Millisecond, func() { if val, err := pcf.ReadCounter(); err != nil { fmt.Println(err) } else { log.Printf("read Counter: %d, diff [Hz]: %d", val, val-lastCnt) lastCnt = val } ramVal, err := pcf.ReadRAM(uint8(0)) if err != nil { fmt.Println(err) } else { log.Printf("read RAM: %d", ramVal) ramVal++ } if err := pcf.WriteRAM(uint8(0), ramVal); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("pcfBot", []gobot.Connection{board}, []gobot.Device{pcf}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/tinkerboard_pcf8591.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "log" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/asus/tinkerboard" ) func main() { // This driver was tested with Tinkerboard and this board with temperature & brightness sensor: // https://www.makershop.de/download/YL_40_PCF8591.pdf // // Wiring // PWR Tinkerboard: 1 (+3.3V, VCC), 6, 9, 14, 20 (GND) // I2C1 Tinkerboard: 3 (SDA), 5 (SCL) // PCF8591 plate: wire AOUT --> AIN2 for this example board := tinkerboard.NewAdaptor() pcf := i2c.NewPCF8591Driver(board, i2c.WithBus(1)) aout := aio.NewAnalogActuatorDriver(pcf, "AOUT") aout.SetScaler(aio.AnalogActuatorLinearScaler(0, 3.3, 0, 255)) var val int var err error // brightness sensor, high brightness - low raw value descLight := "s.0" // temperature sensor, high temperature - low raw value // sometimes buggy, because not properly grounded descTemp := "s.1" // wired to AOUT descAIN2 := "s.2" // adjustable resistor, turn clockwise will lower the raw value descResi := "s.3" // the LED light is visible above ~1.7V, this means ~127 (half of 3.3V) writeVal := 1.7 work := func() { gobot.Every(1000*time.Millisecond, func() { if err := aout.Write(writeVal); err != nil { fmt.Println(err) } else { log.Printf("Write AOUT: %.1f V [0..3.3]", writeVal) writeVal = writeVal + 0.1 if writeVal > 3.3 { writeVal = 0 } } if val, err = pcf.AnalogRead(descLight); err != nil { fmt.Println(err) } else { log.Printf("Brightness (%s): %d [255..0]", descLight, val) } if val, err = pcf.AnalogRead(descTemp); err != nil { fmt.Println(err) } else { log.Printf("Temperature (%s): %d [255..0]", descTemp, val) } if val, err = pcf.AnalogRead(descAIN2); err != nil { fmt.Println(err) } else { log.Printf("Read AOUT (%s): %d [0..255]", descAIN2, val) } if val, err = pcf.AnalogRead(descResi); err != nil { fmt.Println(err) } else { log.Printf("Resistor (%s): %d [255..0]", descResi, val) } }) } robot := gobot.NewRobot("pcfBot", []gobot.Connection{board}, []gobot.Device{pcf}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/tinkerboard_thermalzone.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "log" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" "gobot.io/x/gobot/v2/platforms/asus/tinkerboard" ) // Wiring: no wiring needed func main() { adaptor := tinkerboard.NewAdaptor() therm0 := aio.NewThermalZoneDriver(adaptor, "thermal_zone0") therm1 := aio.NewThermalZoneDriver(adaptor, "thermal_zone1", aio.WithFahrenheit()) work := func() { gobot.Every(500*time.Millisecond, func() { t0, err := therm0.Read() if err != nil { log.Println(err) } t1, err := therm1.Read() if err != nil { log.Println(err) } fmt.Printf("Zone 0: %2.3f °C, Zone 1: %2.3f °F\n", t0, t1) }) } robot := gobot.NewRobot("thermalBot", []gobot.Connection{adaptor}, []gobot.Device{therm0, therm1}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/up2_lcd.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/upboard/up2" ) func main() { board := up2.NewAdaptor() screen := i2c.NewGroveLcdDriver(board) work := func() { if err := screen.Write("hello"); err != nil { fmt.Println(err) } if err := screen.SetRGB(255, 0, 0); err != nil { fmt.Println(err) } gobot.After(5*time.Second, func() { if err := screen.Clear(); err != nil { fmt.Println(err) } if err := screen.Home(); err != nil { fmt.Println(err) } if err := screen.SetRGB(0, 255, 0); err != nil { fmt.Println(err) } // set a custom character in the first position if err := screen.SetCustomChar(0, i2c.CustomLCDChars["smiley"]); err != nil { fmt.Println(err) } // add the custom character at the end of the string if err := screen.Write("goodbye\nhave a nice day " + string(byte(0))); err != nil { fmt.Println(err) } gobot.Every(500*time.Millisecond, func() { if err := screen.Scroll(false); err != nil { fmt.Println(err) } }) }) if err := screen.Home(); err != nil { fmt.Println(err) } time.Sleep(1 * time.Second) if err := screen.SetRGB(0, 0, 255); err != nil { fmt.Println(err) } } robot := gobot.NewRobot("screenBot", []gobot.Connection{board}, []gobot.Device{screen}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/up2_leds.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/upboard/up2" ) func main() { b := up2.NewAdaptor() red := gpio.NewLedDriver(b, up2.LEDRed) blue := gpio.NewLedDriver(b, up2.LEDBlue) green := gpio.NewLedDriver(b, up2.LEDGreen) yellow := gpio.NewLedDriver(b, up2.LEDYellow) work := func() { if err := red.Off(); err != nil { fmt.Println(err) } if err := blue.Off(); err != nil { fmt.Println(err) } if err := green.Off(); err != nil { fmt.Println(err) } if err := yellow.Off(); err != nil { fmt.Println(err) } gobot.Every(1*time.Second, func() { if err := red.Toggle(); err != nil { fmt.Println(err) } }) gobot.Every(2*time.Second, func() { if err := green.Toggle(); err != nil { fmt.Println(err) } }) gobot.Every(4*time.Second, func() { if err := yellow.Toggle(); err != nil { fmt.Println(err) } }) gobot.Every(8*time.Second, func() { if err := blue.Toggle(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("blinkBot", []gobot.Connection{b}, []gobot.Device{red, blue, green, yellow}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/wifi_firmata_analog_input.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" "gobot.io/x/gobot/v2/platforms/firmata" ) func main() { firmataAdaptor := firmata.NewTCPAdaptor(os.Args[1]) sensor := aio.NewAnalogSensorDriver(firmataAdaptor, "A0", aio.WithSensorCyclicRead(500*time.Millisecond)) work := func() { _ = sensor.On(aio.Data, func(data interface{}) { brightness := uint8( gobot.ToScale(gobot.FromScale(float64(data.(int)), 0, 1024), 0, 255), ) fmt.Println("sensor", data) fmt.Println("brightness", brightness) }) } robot := gobot.NewRobot("sensorBot", []gobot.Connection{firmataAdaptor}, []gobot.Device{sensor}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/wifi_firmata_blink.go ================================================ //go:build example // +build example // // Do not build by default. /* How to setup You must be using a WiFi-connected microcontroller, that has been flashed with the WifiFirmata sketch. You then run the go program on your computer, and communicate wirelessly with the microcontroller. How to run Pass the IP address/port as first param: go run examples/wifi_firmata_blink.go 192.168.0.39:3030 */ package main import ( "fmt" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/firmata" ) func main() { firmataAdaptor := firmata.NewTCPAdaptor(os.Args[1]) led := gpio.NewLedDriver(firmataAdaptor, "2") work := func() { gobot.Every(1*time.Second, func() { if err := led.Toggle(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("bot", []gobot.Connection{firmataAdaptor}, []gobot.Device{led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/zero_analog.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "log" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" "gobot.io/x/gobot/v2/platforms/radxa/zero" ) // Wiring: // PWR : 1, 17 (+3.3V, VCC), 2, 4 (+5V), 6, 9, 14, 20, 25, 30, 34, 39 (GND) // ADC (max. 1.8V): header pin 15 is input for channel 1, pin 26 is input for channel 2 func main() { const ( inPin0 = "15_mean" inPin1 = "26" inVoltageScale = 0.439453125 // see README.md of the platform ) scaler := aio.AnalogSensorLinearScaler(0, 4095, 0, 1.8) adaptor := zero.NewAdaptor() ana0 := aio.NewAnalogSensorDriver(adaptor, inPin0, aio.WithSensorScaler(scaler)) ana1 := aio.NewAnalogSensorDriver(adaptor, inPin1) work := func() { gobot.Every(500*time.Millisecond, func() { v0, err := ana0.Read() if err != nil { log.Println(err) } v1, err := ana1.Read() if err != nil { log.Println(err) } fmt.Printf("%s: %1.3f V, %s: %2.0f (%4.0f mV)\n", inPin0, v0, inPin1, v1, v1*inVoltageScale) }) } robot := gobot.NewRobot("adcBot", []gobot.Connection{adaptor}, []gobot.Device{ana0, ana1}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/zero_direct_pin.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/adaptors" "gobot.io/x/gobot/v2/platforms/radxa/zero" ) // Wiring // PWR : 1, 17 (+3.3V, VCC), 2, 4 (+5V), 6, 9, 14, 20, 25, 30, 34, 39 (GND) // GPIO : header pin 24 is input, pin 32 used as normal output, pin 36 used as inverted output // Button: the input pin is wired with a button to GND, the internal pull up resistor is used // LED's: the output pins are wired to the cathode of the LED, the anode is wired with a resistor (70-130Ohm for 20mA) // to VCC // Expected behavior: always one LED is on, the other in opposite state, if button is pressed the state changes func main() { const ( inPinNum = "24" outPinNum = "32" outPinInvertedNum = "36" ) // note: WithGpiosOpenDrain() is optional, if using WithGpiosOpenSource() the LED's will not light up board := zero.NewAdaptor(adaptors.WithGpiosActiveLow(outPinInvertedNum), adaptors.WithGpiosOpenDrain(outPinNum, outPinInvertedNum), adaptors.WithGpiosPullUp(inPinNum)) inPin := gpio.NewDirectPinDriver(board, inPinNum) outPin := gpio.NewDirectPinDriver(board, outPinNum) outPinInverted := gpio.NewDirectPinDriver(board, outPinInvertedNum) work := func() { level := byte(1) gobot.Every(500*time.Millisecond, func() { read, err := inPin.DigitalRead() fmt.Printf("pin %s state is %d\n", inPinNum, read) if err != nil { fmt.Println(err) if level == 1 { level = 0 } else { level = 1 } } else { level = byte(read) } err = outPin.DigitalWrite(level) fmt.Printf("pin %s is now %d\n", outPinNum, level) if err != nil { fmt.Println(err) } err = outPinInverted.DigitalWrite(level) fmt.Printf("pin %s is now not %d\n", outPinInvertedNum, level) if err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("pinBot", []gobot.Connection{board}, []gobot.Device{inPin, outPin, outPinInverted}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/zero_servo.go ================================================ //go:build example // +build example // Do not build by default. package main import ( "fmt" "log" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/adaptors" "gobot.io/x/gobot/v2/platforms/radxa/zero" ) // Wiring // PWR: 1, 17 (+3.3V, VCC), 2, 4 (+5V), 6, 9, 14, 20, 25, 30, 34, 39 (GND) // PWM: header pin 18 (PWM_C), 40 (PWMAO_A) // Servo SG90: red (+5V), brown (GND), orange (PWM) func main() { const ( pwmPin = "18" wait = 3 * time.Second fiftyHzNanos = 20 * 1000 * 1000 // 50Hz = 0.02 sec = 20 ms ) // usually a frequency of 50Hz is used for servos, most servos have 0.5 ms..2.5 ms for 0-180°, // however the mapping can be changed with options: adaptor := zero.NewAdaptor( adaptors.WithPWMDefaultPeriodForPin(pwmPin, fiftyHzNanos), adaptors.WithPWMServoDutyCycleRangeForPin(pwmPin, 500*time.Microsecond, 2500*time.Microsecond), adaptors.WithPWMServoAngleRangeForPin(pwmPin, 0, 180), ) servo := gpio.NewServoDriver(adaptor, pwmPin) work := func() { fmt.Printf("first move to minimal position for %s...\n", wait) if err := servo.ToMin(); err != nil { log.Println(err) } time.Sleep(wait) fmt.Printf("second move to center position for %s...\n", wait) if err := servo.ToCenter(); err != nil { log.Println(err) } time.Sleep(wait) fmt.Printf("third move to maximal position for %s...\n", wait) if err := servo.ToMax(); err != nil { log.Println(err) } time.Sleep(wait) fmt.Println("finally move 0-180° (or what your servo do for the new mapping) and back forever...") angle := 0 fadeAmount := 45 gobot.Every(time.Second, func() { if err := servo.Move(byte(angle)); err != nil { log.Println(err) } angle = angle + fadeAmount if angle < 0 || angle > 180 { if angle < 0 { angle = 0 } if angle > 180 { angle = 180 } // change direction and recalculate fadeAmount = -fadeAmount angle = angle + fadeAmount } }) } robot := gobot.NewRobot("motorBot", []gobot.Connection{adaptor}, []gobot.Device{servo}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: examples/zero_yl40.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "log" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/radxa/zero" ) func main() { // Wiring // PWR : 1, 17 (+3.3V, VCC), 6, 9, 14, 20, 25, 30, 34, 39 (GND) // I2C3: 3 (SDA), 5 (SCL), I2C1: 24/16 (SDA), 23/13 (SCL), I2C4: 7 (SDA), 11 (SCL) // YL-40 module: wire AOUT --> AIN2 for this example // // Note: temperature measurement is often buggy, because sensor is not properly grounded // fix it by soldering a small bridge to the adjacent ground pin of brightness sensor board := zero.NewAdaptor() yl := i2c.NewYL40Driver(board, i2c.WithBus(3)) work := func() { // the LED light is visible above ~1.7V writeVal, _ := yl.AOUT() gobot.Every(1000*time.Millisecond, func() { if err := yl.Write(writeVal); err != nil { fmt.Println(err) } else { log.Printf(" %.1f V written", writeVal) writeVal = writeVal + 0.1 if writeVal > 3.3 { writeVal = 0 } } if brightness, err := yl.ReadBrightness(); err != nil { fmt.Println(err) } else { log.Printf("Brightness: %.0f [0..1000]", brightness) } if temperature, err := yl.ReadTemperature(); err != nil { fmt.Println(err) } else { log.Printf("Temperature: %.1f °C", temperature) } if ain2, err := yl.ReadAIN2(); err != nil { fmt.Println(err) } else { log.Printf("Read back AOUT: %.1f [0..3.3]", ain2) } if potiState, err := yl.ReadPotentiometer(); err != nil { fmt.Println(err) } else { log.Printf("Resistor: %.0f %% [-100..+100]", potiState) } }) } robot := gobot.NewRobot("yl40Bot", []gobot.Connection{board}, []gobot.Device{yl}, work, ) if err := robot.Start(); err != nil { panic(err) } } ================================================ FILE: go.mod ================================================ module gobot.io/x/gobot/v2 go 1.24.0 toolchain go1.24.6 require ( github.com/0xcafed00d/joystick v1.0.1 github.com/bmizerany/pat v0.0.0-20210406213842-e4b6760bdd6f github.com/donovanhide/eventsource v0.0.0-20210830082556-c59027999da0 github.com/eclipse/paho.mqtt.golang v1.5.1 github.com/gofrs/uuid v4.4.0+incompatible github.com/hashicorp/go-multierror v1.1.1 github.com/hybridgroup/go-ardrone v0.0.0-20140402002621-b9750d8d7b78 github.com/hybridgroup/mjpeg v0.0.0-20140228234708-4680f319790e github.com/nats-io/nats.go v1.47.0 github.com/nsf/termbox-go v1.1.1 github.com/sigurn/crc8 v0.0.0-20220107193325-2243fe600f9f github.com/stretchr/testify v1.11.1 github.com/warthog618/go-gpiocdev v0.9.1 go.bug.st/serial v1.6.4 gocv.io/x/gocv v0.42.0 golang.org/x/net v0.46.0 golang.org/x/sys v0.37.0 periph.io/x/conn/v3 v3.7.2 periph.io/x/host/v3 v3.8.5 tinygo.org/x/bluetooth v0.13.0 ) require ( github.com/creack/goselect v0.1.3 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/klauspost/compress v1.18.0 // indirect github.com/mattn/go-runewidth v0.0.9 // indirect github.com/nats-io/nkeys v0.4.11 // indirect github.com/nats-io/nuid v1.0.1 // indirect github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/saltosystems/winrt-go v0.0.0-20241223121953-98e32661f6ff // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/soypat/cyw43439 v0.0.0-20250505012923-830110c8f4af // indirect github.com/soypat/seqs v0.0.0-20250630134107-01c3f05666ba // indirect github.com/tinygo-org/cbgo v0.0.4 // indirect github.com/tinygo-org/pio v0.2.0 // indirect golang.org/x/crypto v0.43.0 // indirect golang.org/x/exp v0.0.0-20251017212417-90e834f514db // indirect golang.org/x/sync v0.17.0 // indirect gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) ================================================ FILE: go.sum ================================================ github.com/0xcafed00d/joystick v1.0.1 h1:r4p2cRp4MHJWu1gArhGtumbkPxmr3tcOUTFqybEhplM= github.com/0xcafed00d/joystick v1.0.1/go.mod h1:gzszjNgzP6jtCAeSdC9OqPVO5rO7TJuaw4P7eAjNzx8= github.com/bmizerany/pat v0.0.0-20210406213842-e4b6760bdd6f h1:gOO/tNZMjjvTKZWpY7YnXC72ULNLErRtp94LountVE8= github.com/bmizerany/pat v0.0.0-20210406213842-e4b6760bdd6f/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c= github.com/creack/goselect v0.1.3 h1:MaGNMclRo7P2Jl21hBpR1Cn33ITSbKP6E49RtfblLKc= github.com/creack/goselect v0.1.3/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/donovanhide/eventsource v0.0.0-20210830082556-c59027999da0 h1:C7t6eeMaEQVy6e8CarIhscYQlNmw5e3G36y7l7Y21Ao= github.com/donovanhide/eventsource v0.0.0-20210830082556-c59027999da0/go.mod h1:56wL82FO0bfMU5RvfXoIwSOP2ggqqxT+tAfNEIyxuHw= github.com/eclipse/paho.mqtt.golang v1.5.1 h1:/VSOv3oDLlpqR2Epjn1Q7b2bSTplJIeV2ISgCl2W7nE= github.com/eclipse/paho.mqtt.golang v1.5.1/go.mod h1:1/yJCneuyOoCOzKSsOTUc0AJfpsItBGWvYpBLimhArU= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hybridgroup/go-ardrone v0.0.0-20140402002621-b9750d8d7b78 h1:7of6LJZ4LF9AvF4bTiMr2I72KxodBf1BXrSD9Tz0lWU= github.com/hybridgroup/go-ardrone v0.0.0-20140402002621-b9750d8d7b78/go.mod h1:YllNbhGM1UEcySxCv1BWK5lre7QLmJJ+O0ADUOo2nbc= github.com/hybridgroup/mjpeg v0.0.0-20140228234708-4680f319790e h1:xCcwD5FOXul+j1dn8xD16nbrhJkkum/Cn+jTd/u1LhY= github.com/hybridgroup/mjpeg v0.0.0-20140228234708-4680f319790e/go.mod h1:eagM805MRKrioHYuU7iKLUyFPVKqVV6um5DAvCkUtXs= github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/nats-io/nats.go v1.47.0 h1:YQdADw6J/UfGUd2Oy6tn4Hq6YHxCaJrVKayxxFqYrgM= github.com/nats-io/nats.go v1.47.0/go.mod h1:iRWIPokVIFbVijxuMQq4y9ttaBTMe0SFdlZfMDd+33g= github.com/nats-io/nkeys v0.4.11 h1:q44qGV008kYd9W1b1nEBkNzvnWxtRSQ7A8BoqRrcfa0= github.com/nats-io/nkeys v0.4.11/go.mod h1:szDimtgmfOi9n25JpfIdGw12tZFYXqhGxjhVxsatHVE= github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nsf/termbox-go v1.1.1 h1:nksUPLCb73Q++DwbYUBEglYBRPZyoXJdrj5L+TkjyZY= github.com/nsf/termbox-go v1.1.1/go.mod h1:T0cTdVuOwf7pHQNtfhnEbzHbcNyCEcVU4YPpouCbVxo= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/saltosystems/winrt-go v0.0.0-20241223121953-98e32661f6ff h1:cCYo/NzsEvK9MedoaqkVY8kCp4g1QMyKOYlA/uJwO7g= github.com/saltosystems/winrt-go v0.0.0-20241223121953-98e32661f6ff/go.mod h1:CIltaIm7qaANUIvzr0Vmz71lmQMAIbGJ7cvgzX7FMfA= github.com/sigurn/crc8 v0.0.0-20220107193325-2243fe600f9f h1:1R9KdKjCNSd7F8iGTxIpoID9prlYH8nuNYKt0XvweHA= github.com/sigurn/crc8 v0.0.0-20220107193325-2243fe600f9f/go.mod h1:vQhwQ4meQEDfahT5kd61wLAF5AAeh5ZPLVI4JJ/tYo8= github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/soypat/cyw43439 v0.0.0-20250505012923-830110c8f4af h1:ZfFq94aH/BCSWWKd9RPUgdHOdgGKCnfl2VdvU9UksTA= github.com/soypat/cyw43439 v0.0.0-20250505012923-830110c8f4af/go.mod h1:MUaGO5m6X7xrkHrPDmnaxCEcuCCFN/0ZFh9oie+exbU= github.com/soypat/seqs v0.0.0-20250630134107-01c3f05666ba h1:NaIxs8iRVTAGBY4xiCy1Jqex3mIPodyLHppYvxUjJEk= github.com/soypat/seqs v0.0.0-20250630134107-01c3f05666ba/go.mod h1:oCVCNGCHMKoBj97Zp9znLbQ1nHxpkmOY9X+UAGzOxc8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/tinygo-org/cbgo v0.0.4 h1:3D76CRYbH03Rudi8sEgs/YO0x3JIMdyq8jlQtk/44fU= github.com/tinygo-org/cbgo v0.0.4/go.mod h1:7+HgWIHd4nbAz0ESjGlJ1/v9LDU1Ox8MGzP9mah/fLk= github.com/tinygo-org/pio v0.2.0 h1:vo3xa6xDZ2rVtxrks/KcTZHF3qq4lyWOntvEvl2pOhU= github.com/tinygo-org/pio v0.2.0/go.mod h1:LU7Dw00NJ+N86QkeTGjMLNkYcEYMor6wTDpTCu0EaH8= github.com/warthog618/go-gpiocdev v0.9.1 h1:pwHPaqjJfhCipIQl78V+O3l9OKHivdRDdmgXYbmhuCI= github.com/warthog618/go-gpiocdev v0.9.1/go.mod h1:dN3e3t/S2aSNC+hgigGE/dBW8jE1ONk9bDSEYfoPyl8= github.com/warthog618/go-gpiosim v0.1.1 h1:MRAEv+T+itmw+3GeIGpQJBfanUVyg0l3JCTwHtwdre4= github.com/warthog618/go-gpiosim v0.1.1/go.mod h1:YXsnB+I9jdCMY4YAlMSRrlts25ltjmuIsrnoUrBLdqU= go.bug.st/serial v1.6.4 h1:7FmqNPgVp3pu2Jz5PoPtbZ9jJO5gnEnZIvnI1lzve8A= go.bug.st/serial v1.6.4/go.mod h1:nofMJxTeNVny/m6+KaafC6vJGj3miwQZ6vW4BZUGJPI= gocv.io/x/gocv v0.42.0 h1:AAsrFJH2aIsQHukkCovWqj0MCGZleQpVyf5gNVRXjQI= gocv.io/x/gocv v0.42.0/go.mod h1:zYdWMj29WAEznM3Y8NsU3A0TRq/wR/cy75jeUypThqU= golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04= golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0= golang.org/x/exp v0.0.0-20251017212417-90e834f514db h1:by6IehL4BH5k3e3SJmcoNbOobMey2SLpAF79iPOEBvw= golang.org/x/exp v0.0.0-20251017212417-90e834f514db/go.mod h1:j/pmGrbnkbPtQfxEe5D0VQhZC6qKbfKifgD0oM7sR70= golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= periph.io/x/conn/v3 v3.7.2 h1:qt9dE6XGP5ljbFnCKRJ9OOCoiOyBGlw7JZgoi72zZ1s= periph.io/x/conn/v3 v3.7.2/go.mod h1:Ao0b4sFRo4QOx6c1tROJU1fLJN1hUIYggjOrkIVnpGg= periph.io/x/host/v3 v3.8.5 h1:g4g5xE1XZtDiGl1UAJaUur1aT7uNiFLMkyMEiZ7IHII= periph.io/x/host/v3 v3.8.5/go.mod h1:hPq8dISZIc+UNfWoRj+bPH3XEBQqJPdFdx218W92mdc= tinygo.org/x/bluetooth v0.13.0 h1:3pkTMcfqv71HoAxG4DBTm2n+1bm6Nqqz8eoHjSW9+5g= tinygo.org/x/bluetooth v0.13.0/go.mod h1:YnyJRVX09i+wkFeHpXut0b+qHq+T2WwKBRRiF/scANA= ================================================ FILE: helpers_test.go ================================================ package gobot import "os" type NullReadWriteCloser struct{} func (NullReadWriteCloser) Write(p []byte) (int, error) { return len(p), nil } func (NullReadWriteCloser) Read(b []byte) (int, error) { return len(b), nil } func (NullReadWriteCloser) Close() error { return nil } type testDriver struct { Commander name string pin string connection Connection } var ( testDriverStart = func() error { return nil } testDriverHalt = func() error { return nil } ) func (t *testDriver) Start() error { return testDriverStart() } func (t *testDriver) Halt() error { return testDriverHalt() } func (t *testDriver) Name() string { return t.name } func (t *testDriver) SetName(n string) { t.name = n } func (t *testDriver) Pin() string { return t.pin } func (t *testDriver) Connection() Connection { return t.connection } func newTestDriver(adaptor *testAdaptor, name string, pin string) *testDriver { t := &testDriver{ name: name, connection: adaptor, pin: pin, Commander: NewCommander(), } t.AddCommand("DriverCommand", func(params map[string]interface{}) interface{} { return nil }) return t } type testAdaptor struct { name string port string } var ( testAdaptorConnect = func() error { return nil } testAdaptorFinalize = func() error { return nil } ) func (t *testAdaptor) Finalize() error { return testAdaptorFinalize() } func (t *testAdaptor) Connect() error { return testAdaptorConnect() } func (t *testAdaptor) Name() string { return t.name } func (t *testAdaptor) SetName(n string) { t.name = n } func (t *testAdaptor) Port() string { return t.port } func newTestAdaptor(name string, port string) *testAdaptor { //nolint:unparam // keep for tests return &testAdaptor{ name: name, port: port, } } func newTestRobot(name string) *Robot { adaptor1 := newTestAdaptor("Connection1", "/dev/null") adaptor2 := newTestAdaptor("Connection2", "/dev/null") adaptor3 := newTestAdaptor("", "/dev/null") driver1 := newTestDriver(adaptor1, "Device1", "0") driver2 := newTestDriver(adaptor2, "Device2", "2") driver3 := newTestDriver(adaptor3, "", "1") work := func() {} r := NewRobot(name, []Connection{adaptor1, adaptor2, adaptor3}, []Device{driver1, driver2, driver3}, work, ) r.AddCommand("RobotCommand", func(params map[string]interface{}) interface{} { return nil }) r.trap = func(c chan os.Signal) { c <- os.Interrupt } return r } ================================================ FILE: manager.go ================================================ package gobot import ( "os" "os/signal" "sync/atomic" ) // JSONManager is a JSON representation of a Gobot Manager. type JSONManager struct { Robots []*JSONRobot `json:"robots"` Commands []string `json:"commands"` } // NewJSONManager returns a JSONManager given a Gobot Manager. func NewJSONManager(gobot *Manager) *JSONManager { jsonGobot := &JSONManager{ Robots: []*JSONRobot{}, Commands: []string{}, } for command := range gobot.Commands() { jsonGobot.Commands = append(jsonGobot.Commands, command) } gobot.robots.Each(func(r *Robot) { jsonGobot.Robots = append(jsonGobot.Robots, NewJSONRobot(r)) }) return jsonGobot } // Manager is the main type of your Gobot application and contains a collection of // Robots, API commands that apply to the Manager, and Events that apply to the Manager. type Manager struct { Commander Eventer robots *Robots trap func(chan os.Signal) AutoRun bool running atomic.Value } // NewManager returns a new Gobot Manager func NewManager() *Manager { m := &Manager{ robots: &Robots{}, trap: func(c chan os.Signal) { signal.Notify(c, os.Interrupt) }, AutoRun: true, Commander: NewCommander(), Eventer: NewEventer(), } m.running.Store(false) return m } // Start calls the Start method on each robot in its collection of robots. On // error, call Stop to ensure that all robots are returned to a sane, stopped // state. func (g *Manager) Start() error { if err := g.robots.Start(!g.AutoRun); err != nil { return err } g.running.Store(true) if !g.AutoRun { return nil } c := make(chan os.Signal, 1) g.trap(c) // waiting for interrupt coming on the channel <-c // Stop calls the Stop method on each robot in its collection of robots. return g.Stop() } // Stop calls the Stop method on each robot in its collection of robots. func (g *Manager) Stop() error { err := g.robots.Stop() g.running.Store(false) return err } // Running returns if the Manager is currently started or not func (g *Manager) Running() bool { return g.running.Load().(bool) //nolint:forcetypeassert // no error return value, so there is no better way } // Robots returns all robots associated with this Gobot Manager. func (g *Manager) Robots() *Robots { return g.robots } // AddRobot adds a new robot to the internal collection of robots. Returns the // added robot func (g *Manager) AddRobot(r *Robot) *Robot { *g.robots = append(*g.robots, r) return r } // Robot returns a robot given name. Returns nil if the Robot does not exist. func (g *Manager) Robot(name string) *Robot { for _, robot := range *g.Robots() { if robot.Name == name { return robot } } return nil } ================================================ FILE: manager_test.go ================================================ package gobot import ( "errors" "fmt" "log" "os" "testing" "time" multierror "github.com/hashicorp/go-multierror" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func initTestManager() *Manager { log.SetOutput(&NullReadWriteCloser{}) g := NewManager() g.trap = func(c chan os.Signal) { c <- os.Interrupt } g.AddRobot(newTestRobot("Robot1")) g.AddRobot(newTestRobot("Robot2")) g.AddRobot(newTestRobot("")) return g } func initTestManager1Robot() *Manager { log.SetOutput(&NullReadWriteCloser{}) g := NewManager() g.trap = func(c chan os.Signal) { c <- os.Interrupt } g.AddRobot(newTestRobot("Robot99")) return g } func TestNullReadWriteCloser(t *testing.T) { n := &NullReadWriteCloser{} i, _ := n.Write([]byte{1, 2, 3}) assert.Equal(t, 3, i) i, _ = n.Read(make([]byte, 10)) assert.Equal(t, 10, i) require.NoError(t, n.Close()) } func TestManagerRobot(t *testing.T) { g := initTestManager() assert.Equal(t, "Robot1", g.Robot("Robot1").Name) assert.Equal(t, (*Robot)(nil), g.Robot("Robot4")) assert.Equal(t, (Device)(nil), g.Robot("Robot4").Device("Device1")) assert.Equal(t, (Connection)(nil), g.Robot("Robot4").Connection("Connection1")) assert.Equal(t, (Device)(nil), g.Robot("Robot1").Device("Device4")) assert.Equal(t, "Device1", g.Robot("Robot1").Device("Device1").Name()) assert.Equal(t, 3, g.Robot("Robot1").Devices().Len()) assert.Equal(t, (Connection)(nil), g.Robot("Robot1").Connection("Connection4")) assert.Equal(t, 3, g.Robot("Robot1").Connections().Len()) } func TestManagerToJSON(t *testing.T) { g := initTestManager() g.AddCommand("test_function", func(params map[string]interface{}) interface{} { return nil }) json := NewJSONManager(g) assert.Len(t, json.Robots, g.Robots().Len()) assert.Len(t, json.Commands, len(g.Commands())) } func TestManagerStart(t *testing.T) { g := initTestManager() require.NoError(t, g.Start()) require.NoError(t, g.Stop()) assert.False(t, g.Running()) } func TestManagerStartAutoRun(t *testing.T) { g := NewManager() g.AddRobot(newTestRobot("Robot99")) go func() { _ = g.Start() }() time.Sleep(10 * time.Millisecond) assert.True(t, g.Running()) // stop it require.NoError(t, g.Stop()) assert.False(t, g.Running()) } func TestManagerStartDriverErrors(t *testing.T) { // arrange g := initTestManager1Robot() var ec int es := [4]error{ nil, errors.New("driver start error 1"), errors.New("driver start error 2"), errors.New("driver start error 3"), } testDriverStart = func() error { ec++ return es[ec] } defer func() { testDriverStart = func() error { return nil } }() var want error want = multierror.Append(want, fmt.Errorf("'Device1' start error: %w", es[1])) want = multierror.Append(want, fmt.Errorf("'Device2' start error: %w", es[2])) want = multierror.Append(want, fmt.Errorf("'' start error: %w", es[3])) // act & assert assert.Equal(t, want, g.Start()) require.NoError(t, g.Stop()) } func TestManagerHaltFromRobotDriverErrors(t *testing.T) { // arrange g := initTestManager1Robot() es := [4]error{ nil, errors.New("driver halt error 1"), errors.New("driver halt error 2"), errors.New("driver halt error 3"), } var ec int testDriverHalt = func() error { ec++ return es[ec] } defer func() { testDriverHalt = func() error { return nil } }() var want error want = multierror.Append(want, fmt.Errorf("'Device1' halt error: %w", es[1])) want = multierror.Append(want, fmt.Errorf("'Device2' halt error: %w", es[2])) want = multierror.Append(want, fmt.Errorf("'' halt error: %w", es[3])) // act & assert assert.Equal(t, want, g.Start()) } func TestManagerStartRobotAdaptorErrors(t *testing.T) { // arrange g := initTestManager1Robot() es := [4]error{ nil, errors.New("adaptor start error 1"), errors.New("adaptor start error 2"), errors.New("adaptor start error 3"), } var ec int testAdaptorConnect = func() error { ec++ return es[ec] } defer func() { testAdaptorConnect = func() error { return nil } }() var want error want = multierror.Append(want, fmt.Errorf("'Connection1' connect error: %w", es[1])) want = multierror.Append(want, fmt.Errorf("'Connection2' connect error: %w", es[2])) want = multierror.Append(want, fmt.Errorf("'' connect error: %w", es[3])) // act & assert assert.Equal(t, want, g.Start()) require.NoError(t, g.Stop()) } func TestManagerFinalizeErrors(t *testing.T) { // arrange g := initTestManager1Robot() es := [4]error{ nil, errors.New("adaptor finalize error 1"), errors.New("adaptor finalize error 2"), errors.New("adaptor finalize error 3"), } var ec int testAdaptorFinalize = func() error { ec++ return fmt.Errorf("adaptor finalize error %d", ec) } defer func() { testAdaptorFinalize = func() error { return nil } }() var want error want = multierror.Append(want, fmt.Errorf("'Connection1' finalize error: %w", es[1])) want = multierror.Append(want, fmt.Errorf("'Connection2' finalize error: %w", es[2])) want = multierror.Append(want, fmt.Errorf("'' finalize error: %w", es[3])) // act & assert assert.Equal(t, want, g.Start()) } ================================================ FILE: platforms/adaptors/analogpinsadaptor.go ================================================ package adaptors import ( "fmt" "sync" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/system" ) type analogPinTranslator func(pin string) (path string, w bool, readBufLen uint16, err error) // analogPinsConfiguration contains all changeable attributes of the adaptor. type analogPinsConfiguration struct { debug bool } // AnalogPinsAdaptor is a adaptor for analog pins, normally used for composition in platforms. // It is also usable for general sysfs access. type AnalogPinsAdaptor struct { sys *system.Accesser analogPinsCfg *analogPinsConfiguration translate analogPinTranslator pins map[string]gobot.AnalogPinner mutex sync.Mutex } // NewAnalogPinsAdaptor provides the access to analog pins of the board. Usually sysfs system drivers are used. // The translator is used to adapt the pin header naming, which is given by user, to the internal file name // nomenclature. This varies by each platform. // // Options: // // "WithAnalogPinDebug" func NewAnalogPinsAdaptor( sys *system.Accesser, t analogPinTranslator, opts ...AnalogPinsOptionApplier, ) *AnalogPinsAdaptor { a := AnalogPinsAdaptor{ sys: sys, analogPinsCfg: &analogPinsConfiguration{}, translate: t, } for _, o := range opts { o.apply(a.analogPinsCfg) } sys.AddAnalogSupport() return &a } // WithAnalogPinDebug can be used to switch on debugging for analog pins implementation. func WithAnalogPinDebug() analogPinsDebugOption { return analogPinsDebugOption(true) } // Connect prepare new connection to analog pins. func (a *AnalogPinsAdaptor) Connect() error { a.mutex.Lock() defer a.mutex.Unlock() if a.pins != nil { return fmt.Errorf("analog pin adaptor already connected, please call Finalize() for re-connect") } a.pins = make(map[string]gobot.AnalogPinner) a.debuglnf("connect the analog pins adaptor done") return nil } // Finalize closes connection to analog pins func (a *AnalogPinsAdaptor) Finalize() error { a.mutex.Lock() defer a.mutex.Unlock() // nothing to do at the moment, because the file access for each pin will be closed immediately after read/write a.pins = nil a.debuglnf("finalize the analog pins adaptor done") return nil } // AnalogRead returns an analog value from specified pin or identifier, defined by the translation function. func (a *AnalogPinsAdaptor) AnalogRead(id string) (int, error) { a.mutex.Lock() defer a.mutex.Unlock() pin, err := a.analogPin(id) if err != nil { return 0, err } return pin.Read() } // AnalogWrite writes an analog value to the specified pin or identifier, defined by the translation function. func (a *AnalogPinsAdaptor) AnalogWrite(id string, val int) error { a.mutex.Lock() defer a.mutex.Unlock() pin, err := a.analogPin(id) if err != nil { return err } return pin.Write(val) } // analogPin initializes the pin for analog access and returns matched pin for specified identifier. func (a *AnalogPinsAdaptor) analogPin(id string) (gobot.AnalogPinner, error) { if a.pins == nil { return nil, fmt.Errorf("not connected for pin %s", id) } pin := a.pins[id] if pin == nil { path, w, readBufLen, err := a.translate(id) if err != nil { return nil, err } pin = a.sys.NewAnalogPin(path, w, readBufLen) a.pins[id] = pin } return pin, nil } func (a *AnalogPinsAdaptor) debuglnf(format string, p ...interface{}) { gobot.Debuglnf(a.analogPinsCfg.debug, format, p...) } ================================================ FILE: platforms/adaptors/analogpinsadaptor_test.go ================================================ //nolint:nonamedreturns // ok for tests package adaptors import ( "fmt" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/system" ) const ( analogReadPath = "/sys/bus/iio/devices/iio:device0/in_voltage0_raw" analogWritePath = "/sys/devices/platform/ff680020.pwm/pwm/pwmchip3/export" analogReadWritePath = "/sys/devices/platform/ff680020.pwm/pwm/pwmchip3/pwm44/period" analogReadWriteStringPath = "/sys/devices/platform/ff680020.pwm/pwm/pwmchip3/pwm44/polarity" ) var analogMockPaths = []string{ analogReadPath, analogWritePath, analogReadWritePath, analogReadWriteStringPath, } func initTestAnalogPinsAdaptorWithMockedFilesystem(mockPaths []string) (*AnalogPinsAdaptor, *system.MockFilesystem) { sys := system.NewAccesser() fs := sys.UseMockFilesystem(mockPaths) a := NewAnalogPinsAdaptor(sys, testAnalogPinTranslator) fs.Files[analogReadPath].Contents = "54321" fs.Files[analogWritePath].Contents = "0" fs.Files[analogReadWritePath].Contents = "30000" fs.Files[analogReadWriteStringPath].Contents = "inverted" if err := a.Connect(); err != nil { panic(err) } return a, fs } func testAnalogPinTranslator(id string) (string, bool, uint16, error) { switch id { case "read": return analogReadPath, false, 10, nil case "write": return analogWritePath, true, 0, nil case "read/write": return analogReadWritePath, true, 12, nil case "read/write_string": return analogReadWriteStringPath, true, 13, nil } return "", false, 0, fmt.Errorf("'%s' is not a valid id of an analog pin", id) } func TestAnalogPinsConnect(t *testing.T) { translate := func(id string) (path string, w bool, bufLen uint16, err error) { return } a := NewAnalogPinsAdaptor(system.NewAccesser(), translate) assert.Equal(t, (map[string]gobot.AnalogPinner)(nil), a.pins) err := a.AnalogWrite("write", 1) require.ErrorContains(t, err, "not connected") err = a.Connect() require.NoError(t, err) assert.NotEqual(t, (map[string]gobot.AnalogPinner)(nil), a.pins) assert.Empty(t, a.pins) } func TestAnalogPinsFinalize(t *testing.T) { // arrange sys := system.NewAccesser() fs := sys.UseMockFilesystem(analogMockPaths) a := NewAnalogPinsAdaptor(sys, testAnalogPinTranslator) fs.Files[analogReadPath].Contents = "0" // assert that finalize before connect is working require.NoError(t, a.Finalize()) // arrange require.NoError(t, a.Connect()) require.NoError(t, a.AnalogWrite("write", 1)) assert.Len(t, a.pins, 1) // act err := a.Finalize() // assert require.NoError(t, err) assert.Empty(t, a.pins) // assert that finalize after finalize is working require.NoError(t, a.Finalize()) // arrange missing file require.NoError(t, a.Connect()) require.NoError(t, a.AnalogWrite("write", 2)) delete(fs.Files, analogWritePath) err = a.Finalize() require.NoError(t, err) // because there is currently no access on finalize // arrange write error require.NoError(t, a.Connect()) require.NoError(t, a.AnalogWrite("read/write_string", 5)) fs.WithWriteError = true err = a.Finalize() require.NoError(t, err) // because there is currently no access on finalize } func TestAnalogPinsReConnect(t *testing.T) { // arrange a, _ := initTestAnalogPinsAdaptorWithMockedFilesystem(analogMockPaths) require.NoError(t, a.AnalogWrite("read/write_string", 1)) assert.Len(t, a.pins, 1) require.NoError(t, a.Finalize()) // act err := a.Connect() // assert require.NoError(t, err) assert.NotNil(t, a.pins) assert.Empty(t, a.pins) } func TestAnalogWrite(t *testing.T) { tests := map[string]struct { pin string simulateWriteErr bool simulateReadErr bool wantValW string wantValRW string wantValRWS string wantErr string }{ "write_w_pin": { pin: "write", wantValW: "100", wantValRW: "30000", wantValRWS: "inverted", }, "write_rw_pin": { pin: "read/write_string", wantValW: "0", wantValRW: "30000", wantValRWS: "100", }, "ok_on_read_error": { pin: "read/write_string", simulateReadErr: true, wantValW: "0", wantValRW: "30000", wantValRWS: "100", }, "error_write_error": { pin: "read/write_string", simulateWriteErr: true, wantValW: "0", wantValRW: "30000", wantValRWS: "inverted", wantErr: "write error", }, "error_notexist": { pin: "notexist", wantValW: "0", wantValRW: "30000", wantValRWS: "inverted", wantErr: "'notexist' is not a valid id of an analog pin", }, "error_write_not_allowed": { pin: "read", wantValW: "0", wantValRW: "30000", wantValRWS: "inverted", wantErr: "the pin '/sys/bus/iio/devices/iio:device0/in_voltage0_raw' is not allowed to write (val: 100)", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange a, fs := initTestAnalogPinsAdaptorWithMockedFilesystem(analogMockPaths) fs.WithWriteError = tc.simulateWriteErr fs.WithReadError = tc.simulateReadErr // act err := a.AnalogWrite(tc.pin, 100) // assert if tc.wantErr != "" { require.EqualError(t, err, tc.wantErr) } else { require.NoError(t, err) } assert.Equal(t, "54321", fs.Files[analogReadPath].Contents) assert.Equal(t, tc.wantValW, fs.Files[analogWritePath].Contents) assert.Equal(t, tc.wantValRW, fs.Files[analogReadWritePath].Contents) assert.Equal(t, tc.wantValRWS, fs.Files[analogReadWriteStringPath].Contents) }) } } func TestAnalogRead(t *testing.T) { tests := map[string]struct { pin string simulateReadErr bool simulateWriteErr bool wantVal int wantErr string }{ "read_r_pin": { pin: "read", wantVal: 54321, }, "read_rw_pin": { pin: "read/write", wantVal: 30000, }, "ok_on_write_error": { pin: "read", simulateWriteErr: true, wantVal: 54321, }, "error_read_error": { pin: "read", simulateReadErr: true, wantErr: "read error", }, "error_notexist": { pin: "notexist", wantErr: "'notexist' is not a valid id of an analog pin", }, "error_invalid_syntax": { pin: "read/write_string", wantErr: "strconv.Atoi: parsing \"inverted\": invalid syntax", }, "error_read_not_allowed": { pin: "write", wantErr: "the pin '/sys/devices/platform/ff680020.pwm/pwm/pwmchip3/export' is not allowed to read", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange a, fs := initTestAnalogPinsAdaptorWithMockedFilesystem(analogMockPaths) fs.WithReadError = tc.simulateReadErr fs.WithWriteError = tc.simulateWriteErr // act got, err := a.AnalogRead(tc.pin) // assert if tc.wantErr != "" { require.EqualError(t, err, tc.wantErr) } else { require.NoError(t, err) } assert.Equal(t, tc.wantVal, got) }) } } ================================================ FILE: platforms/adaptors/analogpinsadaptoroptions.go ================================================ package adaptors // AnalogPinsOptionApplier is the interface for analog pins adaptor options. This provides the possibility for change // the platform behavior by the user when creating the platform, e.g. by "NewAdaptor()". // The interface needs to be implemented by each configurable option type. type AnalogPinsOptionApplier interface { apply(cfg *analogPinsConfiguration) } // analogPinsDebugOption is the type to switch on analog pins related debug messages. type analogPinsDebugOption bool func (o analogPinsDebugOption) String() string { return "switch on debugging for analog pins option" } func (o analogPinsDebugOption) apply(cfg *analogPinsConfiguration) { cfg.debug = bool(o) } ================================================ FILE: platforms/adaptors/analogpinsadaptoroptions_test.go ================================================ package adaptors import ( "testing" "github.com/stretchr/testify/assert" "gobot.io/x/gobot/v2/system" ) func TestWithAnalogPinDebug(t *testing.T) { // This is a general test, that options are applied in constructor. Further tests for options // can also be done by call of "WithOption(val).apply(cfg)". // arrange & act a := NewAnalogPinsAdaptor(system.NewAccesser(), nil, WithAnalogPinDebug()) // assert assert.True(t, a.analogPinsCfg.debug) } ================================================ FILE: platforms/adaptors/analogpintranslator.go ================================================ package adaptors import ( "fmt" "gobot.io/x/gobot/v2/system" ) type AnalogPinDefinition struct { Path string W bool // writable ReadBufLen uint16 // readable if buffer > 0 } type AnalogPinDefinitions map[string]AnalogPinDefinition type AnalogPinTranslator struct { sys *system.Accesser pinDefinitions AnalogPinDefinitions } // NewAnalogPinTranslator creates a new instance of a translator for analog pins, suitable for the most cases. func NewAnalogPinTranslator(sys *system.Accesser, pinDefinitions AnalogPinDefinitions) *AnalogPinTranslator { return &AnalogPinTranslator{sys: sys, pinDefinitions: pinDefinitions} } // Translate returns the sysfs path for the given id. func (pt *AnalogPinTranslator) Translate(id string) (string, bool, uint16, error) { pinInfo, ok := pt.pinDefinitions[id] if !ok { return "", false, 0, fmt.Errorf("'%s' is not a valid id for an analog pin", id) } path := pinInfo.Path info, err := pt.sys.Stat(path) if err != nil { return "", false, 0, fmt.Errorf("error (%v) on access '%s'", err, path) } if info.IsDir() { return "", false, 0, fmt.Errorf("the item '%s' is a directory, which is not expected", path) } return path, pinInfo.W, pinInfo.ReadBufLen, nil } ================================================ FILE: platforms/adaptors/analogpintranslator_test.go ================================================ package adaptors import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2/system" ) func TestNewAnalogPinTranslator(t *testing.T) { // arrange sys := &system.Accesser{} pinDef := AnalogPinDefinitions{} // act pt := NewAnalogPinTranslator(sys, pinDef) // assert assert.IsType(t, &AnalogPinTranslator{}, pt) assert.Equal(t, sys, pt.sys) assert.Equal(t, pinDef, pt.pinDefinitions) } func TestAnalogPinTranslatorTranslate(t *testing.T) { pinDefinitions := AnalogPinDefinitions{ "thermal_zone0": {Path: "/sys/class/thermal/thermal_zone0/temp", W: false, ReadBufLen: 7}, "thermal_zone1": {Path: "/sys/class/thermal/thermal_zone1/temp", W: false, ReadBufLen: 7}, } mockedPaths := []string{ "/sys/class/thermal/thermal_zone0/temp", "/sys/class/thermal/thermal_zone1/temp", } tests := map[string]struct { id string wantPath string wantBufLen uint16 wantErr string }{ "translate_thermal_zone0": { id: "thermal_zone0", wantPath: "/sys/class/thermal/thermal_zone0/temp", wantBufLen: 7, }, "translate_thermal_zone1": { id: "thermal_zone1", wantPath: "/sys/class/thermal/thermal_zone1/temp", wantBufLen: 7, }, "unknown_id": { id: "99", wantErr: "'99' is not a valid id for an analog pin", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange sys := system.NewAccesser() _ = sys.UseMockFilesystem(mockedPaths) pt := NewAnalogPinTranslator(sys, pinDefinitions) // act path, w, buf, err := pt.Translate(tc.id) // assert if tc.wantErr != "" { require.EqualError(t, err, tc.wantErr) } else { require.NoError(t, err) } assert.Equal(t, tc.wantPath, path) assert.False(t, w) assert.Equal(t, tc.wantBufLen, buf) }) } } ================================================ FILE: platforms/adaptors/busnumbervalidator.go ================================================ package adaptors import "fmt" type BusNumberValidator struct { validNumbers []int } // NewBusNumberValidator creates a new instance for a bus number validator, used for I2C and SPI. func NewBusNumberValidator(validNumbers []int) *BusNumberValidator { return &BusNumberValidator{validNumbers: validNumbers} } func (bnv *BusNumberValidator) Validate(busNr int) error { for _, validNumber := range bnv.validNumbers { if validNumber == busNr { return nil } } return fmt.Errorf("bus number %d out of range %v", busNr, bnv.validNumbers) } ================================================ FILE: platforms/adaptors/busnumbervalidator_test.go ================================================ package adaptors import ( "fmt" "testing" "github.com/stretchr/testify/assert" ) func TestNewBusNumberValidator(t *testing.T) { // arrange validNums := []int{5, 8} // act bnv := NewBusNumberValidator(validNums) // assert assert.IsType(t, &BusNumberValidator{}, bnv) assert.Equal(t, validNums, bnv.validNumbers) } func TestBusNumberValidatorValidate(t *testing.T) { tests := map[string]struct { validNumbers []int busNr int wantErr error }{ "number_negative_error": { validNumbers: []int{0, 1, 2, 3, 4}, busNr: -1, wantErr: fmt.Errorf("bus number -1 out of range [0 1 2 3 4]"), }, "number_0_ok": { validNumbers: []int{0, 1, 2, 3, 4}, busNr: 0, }, "number_1_ok": { validNumbers: []int{0, 1, 2, 3, 4}, busNr: 1, }, "number_2_ok": { validNumbers: []int{0, 1, 2, 3, 4}, busNr: 2, }, "number_3_ok": { validNumbers: []int{0, 1, 2, 3, 4}, busNr: 3, }, "number_4_ok": { validNumbers: []int{0, 1, 2, 3, 4}, busNr: 4, }, "number_5_error": { validNumbers: []int{0, 1, 2, 3, 4}, busNr: 5, wantErr: fmt.Errorf("bus number 5 out of range [0 1 2 3 4]"), }, "number_negative_error_0_2": { validNumbers: []int{0, 2}, busNr: -1, wantErr: fmt.Errorf("bus number -1 out of range [0 2]"), }, "number_0_ok_0_2": { validNumbers: []int{0, 2}, busNr: 0, }, "number_1_error_0_2": { validNumbers: []int{0, 2}, busNr: 1, wantErr: fmt.Errorf("bus number 1 out of range [0 2]"), }, "number_2_ok_0_2": { validNumbers: []int{0, 2}, busNr: 2, }, "number_3_error_0_2": { validNumbers: []int{0, 2}, busNr: 3, wantErr: fmt.Errorf("bus number 3 out of range [0 2]"), }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange bnv := NewBusNumberValidator(tc.validNumbers) // act err := bnv.Validate(tc.busNr) // assert assert.Equal(t, tc.wantErr, err) }) } } ================================================ FILE: platforms/adaptors/digitalpinsadaptor.go ================================================ package adaptors import ( "fmt" "sync" "time" "github.com/hashicorp/go-multierror" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/system" ) type ( digitalPinTranslator func(pin string) (chip string, line int, err error) digitalPinInitializer func(gobot.DigitalPinner) error ) // digitalPinsConfiguration contains all changeable attributes of the adaptor. type digitalPinsConfiguration struct { debug bool initialize digitalPinInitializer systemOptions []system.AccesserOptionApplier pinOptions map[string][]func(gobot.DigitalPinOptioner) bool } // DigitalPinsAdaptor is a adaptor for digital pins, normally used for composition in platforms. type DigitalPinsAdaptor struct { sys *system.Accesser digitalPinsCfg *digitalPinsConfiguration translate digitalPinTranslator pins map[string]gobot.DigitalPinner mutex sync.Mutex } // NewDigitalPinsAdaptor provides the access to digital pins of the board. It supports sysfs and cdev system drivers. // This is decided by the given accesser. The translator is used to adapt the pin header naming, which is given by user, // to the internal file name or chip/line nomenclature. This varies by each platform. If for some reasons the default // initializer is not suitable, it can be given by the option "WithDigitalPinInitializer()". This is especially needed, // if some values needs to be adjusted after the pin was created but before the pin is exported. func NewDigitalPinsAdaptor( sys *system.Accesser, t digitalPinTranslator, opts ...DigitalPinsOptionApplier, ) *DigitalPinsAdaptor { a := DigitalPinsAdaptor{ sys: sys, digitalPinsCfg: &digitalPinsConfiguration{ initialize: func(pin gobot.DigitalPinner) error { return pin.Export() }, pinOptions: make(map[string][]func(gobot.DigitalPinOptioner) bool), }, translate: t, } for _, o := range opts { o.apply(a.digitalPinsCfg) } a.sys.AddDigitalPinSupport(a.digitalPinsCfg.systemOptions...) return &a } // WithDigitalPinDebug can be used to switch on debugging for digital pins implementation. func WithDigitalPinDebug() digitalPinsDebugOption { return digitalPinsDebugOption(true) } // WithDigitalPinInitializer can be used to substitute the default initializer. func WithDigitalPinInitializer(pc digitalPinInitializer) digitalPinsInitializeOption { return digitalPinsInitializeOption(pc) } // WithGpioCdevAccess can be used to change the default legacy sysfs implementation to the character device Kernel ABI, // provided by the go-gpiocdev package. func WithGpioCdevAccess() digitalPinsSystemSysfsOption { return digitalPinsSystemSysfsOption(false) } // WithGpioSysfsAccess can be used to change the default character device implementation, provided by the go-gpiocdev // package, to the legacy sysfs Kernel ABI. func WithGpioSysfsAccess() digitalPinsSystemSysfsOption { return digitalPinsSystemSysfsOption(true) } // WithGpiosActiveLow prepares the given pins for inverse reaction on next initialize. // This is working for inputs and outputs. func WithGpiosActiveLow(pin string, otherPins ...string) digitalPinsActiveLowOption { pins := append([]string{pin}, otherPins...) return digitalPinsActiveLowOption(pins) } // WithGpiosPullDown prepares the given pins to be pulled down (high impedance to GND) on next initialize. // This is working for inputs and outputs since Kernel 5.5, but will be ignored with sysfs ABI. func WithGpiosPullDown(pin string, otherPins ...string) digitalPinsPullDownOption { pins := append([]string{pin}, otherPins...) return digitalPinsPullDownOption(pins) } // WithGpiosPullUp prepares the given pins to be pulled up (high impedance to VDD) on next initialize. // This is working for inputs and outputs since Kernel 5.5, but will be ignored with sysfs ABI. func WithGpiosPullUp(pin string, otherPins ...string) digitalPinsPullUpOption { pins := append([]string{pin}, otherPins...) return digitalPinsPullUpOption(pins) } // WithGpiosOpenDrain prepares the given output pins to be driven with open drain/collector on next initialize. // This will be ignored for inputs or with sysfs ABI. func WithGpiosOpenDrain(pin string, otherPins ...string) digitalPinsOpenDrainOption { pins := append([]string{pin}, otherPins...) return digitalPinsOpenDrainOption(pins) } // WithGpiosOpenSource prepares the given output pins to be driven with open source/emitter on next initialize. // This will be ignored for inputs or with sysfs ABI. func WithGpiosOpenSource(pin string, otherPins ...string) digitalPinsOpenSourceOption { pins := append([]string{pin}, otherPins...) return digitalPinsOpenSourceOption(pins) } // WithGpioDebounce prepares the given input pin to be debounced on next initialize. // This is working for inputs since Kernel 5.10, but will be ignored for outputs or with sysfs ABI. func WithGpioDebounce(pin string, period time.Duration) digitalPinsDebounceOption { return digitalPinsDebounceOption{id: pin, period: period} } // WithGpioEventOnFallingEdge prepares the given input pin to be generate an event on falling edge. // This is working for inputs since Kernel 5.10, but will be ignored for outputs or with sysfs ABI. func WithGpioEventOnFallingEdge(pin string, handler func(lineOffset int, timestamp time.Duration, detectedEdge string, seqno uint32, lseqno uint32), ) digitalPinsEventOnFallingEdgeOption { return digitalPinsEventOnFallingEdgeOption{id: pin, handler: handler} } // WithGpioEventOnRisingEdge prepares the given input pin to be generate an event on rising edge. // This is working for inputs since Kernel 5.10, but will be ignored for outputs or with sysfs ABI. func WithGpioEventOnRisingEdge(pin string, handler func(lineOffset int, timestamp time.Duration, detectedEdge string, seqno uint32, lseqno uint32), ) digitalPinsEventOnRisingEdgeOption { return digitalPinsEventOnRisingEdgeOption{id: pin, handler: handler} } // WithGpioEventOnBothEdges prepares the given input pin to be generate an event on rising and falling edges. // This is working for inputs since Kernel 5.10, but will be ignored for outputs or with sysfs ABI. func WithGpioEventOnBothEdges(pin string, handler func(lineOffset int, timestamp time.Duration, detectedEdge string, seqno uint32, lseqno uint32), ) digitalPinsEventOnBothEdgesOption { return digitalPinsEventOnBothEdgesOption{id: pin, handler: handler} } // WithGpioPollForEdgeDetection prepares the given input pin to use a discrete input pin polling function together with // edge detection. func WithGpioPollForEdgeDetection( pin string, pollInterval time.Duration, pollQuitChan chan struct{}, ) digitalPinsPollForEdgeDetectionOption { return digitalPinsPollForEdgeDetectionOption{id: pin, pollInterval: pollInterval, pollQuitChan: pollQuitChan} } // Connect prepare new connection to digital pins. func (a *DigitalPinsAdaptor) Connect() error { a.mutex.Lock() defer a.mutex.Unlock() if a.pins != nil { return fmt.Errorf("digital pin adaptor already connected, please call Finalize() for re-connect") } a.pins = make(map[string]gobot.DigitalPinner) a.debuglnf("connect the digital pins adaptor done") return nil } // Finalize closes connection to digital pins func (a *DigitalPinsAdaptor) Finalize() error { a.mutex.Lock() defer a.mutex.Unlock() a.debuglnf("finalize the digital pins adaptor with %d pins...", len(a.pins)) var err error for id, pin := range a.pins { if pin != nil { e := pin.Unexport() if e != nil { err = multierror.Append(err, e) } a.debuglnf("finalize the digital pin '%s' done with error: %v", id, e) } } a.pins = nil a.debuglnf("finalize the digital pins adaptor done with error: %v", err) return err } // DigitalPin returns a digital pin. If the pin is initially acquired, it is an input. // Pin direction and other options can be changed afterwards by pin.ApplyOptions() at any time. func (a *DigitalPinsAdaptor) DigitalPin(id string) (gobot.DigitalPinner, error) { a.mutex.Lock() defer a.mutex.Unlock() return a.digitalPin(id) } // DigitalRead reads digital value from pin func (a *DigitalPinsAdaptor) DigitalRead(id string) (int, error) { a.mutex.Lock() defer a.mutex.Unlock() pin, err := a.digitalPin(id, system.WithPinDirectionInput()) if err != nil { return 0, err } return pin.Read() } // DigitalWrite writes digital value to specified pin func (a *DigitalPinsAdaptor) DigitalWrite(id string, val byte) error { a.mutex.Lock() defer a.mutex.Unlock() pin, err := a.digitalPin(id, system.WithPinDirectionOutput(int(val))) if err != nil { return err } return pin.Write(int(val)) } func (a *DigitalPinsAdaptor) digitalPin( id string, opts ...func(gobot.DigitalPinOptioner) bool, ) (gobot.DigitalPinner, error) { if a.pins == nil { return nil, fmt.Errorf("not connected for pin %s", id) } o := append(a.digitalPinsCfg.pinOptions[id], opts...) pin := a.pins[id] if pin == nil { chip, line, err := a.translate(id) if err != nil { return nil, err } pin = a.sys.NewDigitalPin(chip, line, o...) if err = a.digitalPinsCfg.initialize(pin); err != nil { return nil, err } a.pins[id] = pin } else { if err := pin.ApplyOptions(o...); err != nil { return nil, err } } return pin, nil } func (a *DigitalPinsAdaptor) debuglnf(format string, p ...interface{}) { gobot.Debuglnf(a.digitalPinsCfg.debug, format, p...) } ================================================ FILE: platforms/adaptors/digitalpinsadaptor_test.go ================================================ //nolint:nonamedreturns // ok for tests package adaptors import ( "fmt" "runtime" "strconv" "sync" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/system" ) // make sure that this adaptor fulfills all the required interfaces var ( _ gobot.DigitalPinnerProvider = (*DigitalPinsAdaptor)(nil) _ gpio.DigitalReader = (*DigitalPinsAdaptor)(nil) _ gpio.DigitalWriter = (*DigitalPinsAdaptor)(nil) ) func initTestConnectedDigitalPinsAdaptorWithMockedFilesystem( mockPaths []string, ) (*DigitalPinsAdaptor, *system.MockFilesystem) { a, fs := initTestDigitalPinsAdaptorWithMockedFilesystem(mockPaths) if err := a.Connect(); err != nil { panic(err) } return a, fs } func initTestDigitalPinsAdaptorWithMockedFilesystem(mockPaths []string) (*DigitalPinsAdaptor, *system.MockFilesystem) { sys := system.NewAccesser(system.WithDigitalPinSysfsAccess()) fs := sys.UseMockFilesystem(mockPaths) a := NewDigitalPinsAdaptor(sys, testDigitalPinTranslator) return a, fs } func testDigitalPinTranslator(pin string) (string, int, error) { line, err := strconv.Atoi(pin) if err != nil { return "", 0, fmt.Errorf("not a valid pin") } line = line + 11 // just for tests return "", line, err } func TestNewDigitalPinsAdaptor(t *testing.T) { // arrange translate := func(string) (string, int, error) { return "", 0, nil } sys := system.NewAccesser() // arrange for cdev needed sys.UseMockFilesystem([]string{"/dev/gpiochip"}) // act a := NewDigitalPinsAdaptor(sys, translate) // assert assert.IsType(t, &DigitalPinsAdaptor{}, a) assert.NotNil(t, a.sys) assert.NotNil(t, a.digitalPinsCfg) assert.NotNil(t, a.translate) assert.Nil(t, a.pins) // will be created on connect assert.True(t, a.sys.HasDigitalPinCdevAccess()) } func TestDigitalPinsConnect(t *testing.T) { translate := func(pin string) (chip string, line int, err error) { return } sys := system.NewAccesser(system.WithDigitalPinSysfsAccess()) a := NewDigitalPinsAdaptor(sys, translate) assert.Equal(t, (map[string]gobot.DigitalPinner)(nil), a.pins) _, err := a.DigitalRead("13") require.ErrorContains(t, err, "not connected for pin 13") err = a.DigitalWrite("7", 1) require.ErrorContains(t, err, "not connected for pin 7") err = a.Connect() require.NoError(t, err) assert.NotEqual(t, (map[string]gobot.DigitalPinner)(nil), a.pins) assert.Empty(t, a.pins) } func TestDigitalPinsFinalize(t *testing.T) { // arrange mockedPaths := []string{ "/sys/class/gpio/export", "/sys/class/gpio/unexport", "/sys/class/gpio/gpio14/direction", "/sys/class/gpio/gpio14/value", } sys := system.NewAccesser(system.WithDigitalPinSysfsAccess()) fs := sys.UseMockFilesystem(mockedPaths) a := NewDigitalPinsAdaptor(sys, testDigitalPinTranslator) // assert that finalize before connect is working require.NoError(t, a.Finalize()) // arrange require.NoError(t, a.Connect()) require.NoError(t, a.DigitalWrite("3", 1)) assert.Len(t, a.pins, 1) // act err := a.Finalize() // assert require.NoError(t, err) assert.Empty(t, a.pins) // assert that finalize after finalize is working require.NoError(t, a.Finalize()) // arrange missing sysfs file require.NoError(t, a.Connect()) require.NoError(t, a.DigitalWrite("3", 2)) delete(fs.Files, "/sys/class/gpio/unexport") err = a.Finalize() require.ErrorContains(t, err, "/sys/class/gpio/unexport: no such file") } func TestDigitalPinsReConnect(t *testing.T) { // arrange mockedPaths := []string{ "/sys/class/gpio/export", "/sys/class/gpio/unexport", "/sys/class/gpio/gpio15/direction", "/sys/class/gpio/gpio15/value", } a, _ := initTestConnectedDigitalPinsAdaptorWithMockedFilesystem(mockedPaths) require.NoError(t, a.DigitalWrite("4", 1)) assert.Len(t, a.pins, 1) require.NoError(t, a.Finalize()) // act err := a.Connect() // assert require.NoError(t, err) assert.NotNil(t, a.pins) assert.Empty(t, a.pins) } func TestDigitalIO(t *testing.T) { mockedPaths := []string{ "/sys/class/gpio/export", "/sys/class/gpio/unexport", "/sys/class/gpio/gpio25/value", "/sys/class/gpio/gpio25/direction", } a, _ := initTestConnectedDigitalPinsAdaptorWithMockedFilesystem(mockedPaths) err := a.DigitalWrite("14", 1) require.NoError(t, err) i, err := a.DigitalRead("14") require.NoError(t, err) assert.Equal(t, 1, i) } func TestDigitalRead(t *testing.T) { // arrange mockedPaths := []string{ "/sys/class/gpio/export", "/sys/class/gpio/unexport", "/sys/class/gpio/gpio24/value", "/sys/class/gpio/gpio24/direction", } a, fs := initTestConnectedDigitalPinsAdaptorWithMockedFilesystem(mockedPaths) fs.Files["/sys/class/gpio/gpio24/value"].Contents = "1" // assert read correct value without error i, err := a.DigitalRead("13") require.NoError(t, err) assert.Equal(t, 1, i) // assert error bubbling for read errors fs.WithReadError = true _, err = a.DigitalRead("13") require.ErrorContains(t, err, "read error") // assert error bubbling for write errors fs.WithWriteError = true _, err = a.DigitalRead("7") require.ErrorContains(t, err, "write error") } func TestDigitalPinConcurrency(t *testing.T) { oldProcs := runtime.GOMAXPROCS(0) runtime.GOMAXPROCS(8) defer runtime.GOMAXPROCS(oldProcs) translate := func(pin string) (string, int, error) { line, err := strconv.Atoi(pin); return "", line, err } sys := system.NewAccesser(system.WithDigitalPinSysfsAccess()) for retry := 0; retry < 20; retry++ { a := NewDigitalPinsAdaptor(sys, translate) _ = a.Connect() var wg sync.WaitGroup for i := 0; i < 20; i++ { wg.Add(1) pinAsString := strconv.Itoa(i) go func(pin string) { defer wg.Done() _, _ = a.DigitalPin(pin) }(pinAsString) } wg.Wait() } } ================================================ FILE: platforms/adaptors/digitalpinsadaptoroptions.go ================================================ package adaptors import ( "time" "gobot.io/x/gobot/v2/system" ) // DigitalPinsOptionApplier is the interface for digital adaptors options. This provides the possibility for change the // platform behavior by the user when creating the platform, e.g. by "NewAdaptor()". // The interface needs to be implemented by each configurable option type. type DigitalPinsOptionApplier interface { apply(cfg *digitalPinsConfiguration) } // digitalPinsDebugOption is the type to switch on digital pin related debug messages. type digitalPinsDebugOption bool // digitalPinInitializeOption is the type for applying another than the default initializer type digitalPinsInitializeOption digitalPinInitializer // digitalPinsSystemSysfsOption is the type to change the default character device implementation to the legacy // sysfs Kernel ABI type digitalPinsSystemSysfsOption bool // digitalPinsActiveLowOption is the type to prepare the given pins for inverse reaction on next initialize type digitalPinsActiveLowOption []string // digitalPinsPullDownOption is the type to prepare the given pins to be pulled down (high impedance to GND) // on next initialize type digitalPinsPullDownOption []string // digitalPinsPullUpOption is the type to prepare the given pins to be pulled up (high impedance to VDD) // on next initialize type digitalPinsPullUpOption []string // digitalPinsOpenDrainOption is the type to prepare the given output pins to be driven with open drain/collector // on next initialize type digitalPinsOpenDrainOption []string // digitalPinsOpenSourceOption is the type to prepares the given output pins to be driven with open source/emitter // on next initialize type digitalPinsOpenSourceOption []string // digitalPinsDebounceOption is the type to prepare the given input pin to be debounced on next initialize type digitalPinsDebounceOption struct { id string period time.Duration } // digitalPinsEventOnFallingEdgeOption is the type to prepare the given input pin to be generate an event // on falling edge type digitalPinsEventOnFallingEdgeOption struct { id string handler func(int, time.Duration, string, uint32, uint32) } // digitalPinsEventOnRisingEdgeOption is the type to prepare the given input pin to be generate an event // on rising edge type digitalPinsEventOnRisingEdgeOption struct { id string handler func(int, time.Duration, string, uint32, uint32) } // digitalPinsEventOnBothEdgesOption is the type to prepare the given input pin to be generate an event // on rising and falling edges type digitalPinsEventOnBothEdgesOption struct { id string handler func(int, time.Duration, string, uint32, uint32) } // digitalPinsPollForEdgeDetectionOption is the type to prepare the given input pin to use a discrete input pin polling // function together with edge detection. type digitalPinsPollForEdgeDetectionOption struct { id string pollInterval time.Duration pollQuitChan chan struct{} } func (o digitalPinsDebugOption) String() string { return "switch on debugging for digital pins option" } func (o digitalPinsInitializeOption) String() string { return "pin initializer option for digital IO's" } func (o digitalPinsSystemSysfsOption) String() string { return "use sysfs vs. cdev system access option for digital pins" } func (o digitalPinsActiveLowOption) String() string { return "digital pins set to active low option" } func (o digitalPinsPullDownOption) String() string { return "digital pins set to pull down option" } func (o digitalPinsPullUpOption) String() string { return "digital pins set to pull up option" } func (o digitalPinsOpenDrainOption) String() string { return "digital pins set to open drain option" } func (o digitalPinsOpenSourceOption) String() string { return "digital pins set to open source option" } func (o digitalPinsDebounceOption) String() string { return "set debounce time for digital pin option" } func (o digitalPinsEventOnFallingEdgeOption) String() string { return "set event on falling edge for digital pin option" } func (o digitalPinsEventOnRisingEdgeOption) String() string { return "set event on rising edge for digital pin option" } func (o digitalPinsEventOnBothEdgesOption) String() string { return "set event on rising and falling edge for digital pin option" } func (o digitalPinsPollForEdgeDetectionOption) String() string { return "discrete polling function for edge detection on digital pin option" } func (o digitalPinsDebugOption) apply(cfg *digitalPinsConfiguration) { cfg.debug = bool(o) cfg.systemOptions = append(cfg.systemOptions, system.WithDigitalPinDebug()) } func (o digitalPinsInitializeOption) apply(cfg *digitalPinsConfiguration) { cfg.initialize = digitalPinInitializer(o) } func (o digitalPinsSystemSysfsOption) apply(cfg *digitalPinsConfiguration) { useSysFs := bool(o) if useSysFs { cfg.systemOptions = append(cfg.systemOptions, system.WithDigitalPinSysfsAccess()) } else { cfg.systemOptions = append(cfg.systemOptions, system.WithDigitalPinCdevAccess()) } } func (o digitalPinsActiveLowOption) apply(cfg *digitalPinsConfiguration) { for _, pin := range o { cfg.pinOptions[pin] = append(cfg.pinOptions[pin], system.WithPinActiveLow()) } } func (o digitalPinsPullDownOption) apply(cfg *digitalPinsConfiguration) { for _, pin := range o { cfg.pinOptions[pin] = append(cfg.pinOptions[pin], system.WithPinPullDown()) } } func (o digitalPinsPullUpOption) apply(cfg *digitalPinsConfiguration) { for _, pin := range o { cfg.pinOptions[pin] = append(cfg.pinOptions[pin], system.WithPinPullUp()) } } func (o digitalPinsOpenDrainOption) apply(cfg *digitalPinsConfiguration) { for _, pin := range o { cfg.pinOptions[pin] = append(cfg.pinOptions[pin], system.WithPinOpenDrain()) } } func (o digitalPinsOpenSourceOption) apply(cfg *digitalPinsConfiguration) { for _, pin := range o { cfg.pinOptions[pin] = append(cfg.pinOptions[pin], system.WithPinOpenSource()) } } func (o digitalPinsDebounceOption) apply(cfg *digitalPinsConfiguration) { cfg.pinOptions[o.id] = append(cfg.pinOptions[o.id], system.WithPinDebounce(o.period)) } func (o digitalPinsEventOnFallingEdgeOption) apply(cfg *digitalPinsConfiguration) { cfg.pinOptions[o.id] = append(cfg.pinOptions[o.id], system.WithPinEventOnFallingEdge(o.handler)) } func (o digitalPinsEventOnRisingEdgeOption) apply(cfg *digitalPinsConfiguration) { cfg.pinOptions[o.id] = append(cfg.pinOptions[o.id], system.WithPinEventOnRisingEdge(o.handler)) } func (o digitalPinsEventOnBothEdgesOption) apply(cfg *digitalPinsConfiguration) { cfg.pinOptions[o.id] = append(cfg.pinOptions[o.id], system.WithPinEventOnBothEdges(o.handler)) } func (o digitalPinsPollForEdgeDetectionOption) apply(cfg *digitalPinsConfiguration) { cfg.pinOptions[o.id] = append(cfg.pinOptions[o.id], system.WithPinPollForEdgeDetection(o.pollInterval, o.pollQuitChan)) } ================================================ FILE: platforms/adaptors/digitalpinsadaptoroptions_test.go ================================================ package adaptors import ( "fmt" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/system" ) func TestDigitalPinsWithGpiosActiveLow(t *testing.T) { // This is a general test, that options are applied in constructor. Further tests for options // can also be done by call of "WithOption(val).apply(cfg)". // arrange & act a := NewDigitalPinsAdaptor(system.NewAccesser(), nil, WithGpiosActiveLow("1", "12", "33")) // assert assert.Len(t, a.digitalPinsCfg.pinOptions, 3) } func TestWithDigitalPinDebug(t *testing.T) { // arrange cfg := &digitalPinsConfiguration{debug: false} // act WithDigitalPinDebug().apply(cfg) // assert assert.True(t, cfg.debug) } func TestDigitalPinsWithDigitalPinInitializer(t *testing.T) { // arrange const ( pinNo = "1" translatedPinNo = "12" ) a := NewDigitalPinsAdaptor(system.NewAccesser(), testDigitalPinTranslator) require.NoError(t, a.Connect()) dpa := a.sys.UseMockDigitalPinAccess() pin, err := a.DigitalPin(pinNo) require.NoError(t, err) require.Equal(t, 1, dpa.Exported("", translatedPinNo)) // original initializer called on DigitalPin() require.NoError(t, a.digitalPinsCfg.initialize(pin)) require.Equal(t, 2, dpa.Exported("", translatedPinNo)) var called bool anotherInitializer := func(pin gobot.DigitalPinner) error { called = true return nil } WithDigitalPinInitializer(anotherInitializer).apply(a.digitalPinsCfg) // act require.NoError(t, a.digitalPinsCfg.initialize(pin)) // assert assert.Equal(t, 2, dpa.Exported("", translatedPinNo)) assert.True(t, called) } func TestDigitalPinsWithSysfsAccess(t *testing.T) { // arrange a := NewDigitalPinsAdaptor(system.NewAccesser(), nil, WithGpioSysfsAccess()) // assert assert.True(t, a.sys.HasDigitalPinSysfsAccess()) } func TestDigitalPinsWithCdevAccess(t *testing.T) { // arrange sys := system.NewAccesser(system.WithDigitalPinSysfsAccess()) sys.UseMockFilesystem([]string{"/dev/gpiochip0"}) a := NewDigitalPinsAdaptor(sys, nil, WithGpioCdevAccess()) // assert assert.True(t, a.sys.HasDigitalPinCdevAccess()) } func TestDigitalReadWithGpiosActiveLow(t *testing.T) { // arrange mockedPaths := []string{ "/sys/class/gpio/export", "/sys/class/gpio/unexport", "/sys/class/gpio/gpio25/value", "/sys/class/gpio/gpio25/direction", "/sys/class/gpio/gpio25/active_low", "/sys/class/gpio/gpio26/value", "/sys/class/gpio/gpio26/direction", } a, fs := initTestDigitalPinsAdaptorWithMockedFilesystem(mockedPaths) // arrange files for for pin 14 fs.Files["/sys/class/gpio/gpio25/value"].Contents = "1" fs.Files["/sys/class/gpio/gpio25/active_low"].Contents = "5" // arrange value file and config for pin 15 fs.Files["/sys/class/gpio/gpio26/value"].Contents = "0" WithGpiosActiveLow("14").apply(a.digitalPinsCfg) require.NoError(t, a.Connect()) // creates a new pin without inverted logic if _, err := a.DigitalRead("15"); err != nil { panic(err) } // assert for untouched content of pin 14 assert.Equal(t, "5", fs.Files["/sys/class/gpio/gpio25/active_low"].Contents) // arrange direction file and config for pin 15 fs.Add("/sys/class/gpio/gpio26/active_low") fs.Files["/sys/class/gpio/gpio26/active_low"].Contents = "6" WithGpiosActiveLow("15").apply(a.digitalPinsCfg) require.NoError(t, a.Finalize()) require.NoError(t, a.Connect()) // act got1, err1 := a.DigitalRead("14") // for a new pin got2, err2 := a.DigitalRead("15") // for an existing pin (calls ApplyOptions()) // assert require.NoError(t, err1) require.NoError(t, err2) assert.Equal(t, 1, got1) // there is no mechanism to negate mocked values assert.Equal(t, 0, got2) assert.Equal(t, "1", fs.Files["/sys/class/gpio/gpio25/active_low"].Contents) assert.Equal(t, "1", fs.Files["/sys/class/gpio/gpio26/active_low"].Contents) } func TestDigitalWriteWithOptions(t *testing.T) { // arrange mockedPaths := []string{ "/sys/class/gpio/export", "/sys/class/gpio/unexport", "/sys/class/gpio/gpio18/value", "/sys/class/gpio/gpio18/direction", } a, fs := initTestDigitalPinsAdaptorWithMockedFilesystem(mockedPaths) // assert write correct value without error and just ignore unsupported options WithGpiosPullUp("7").apply(a.digitalPinsCfg) WithGpiosOpenDrain("7").apply(a.digitalPinsCfg) WithGpioEventOnFallingEdge("7", gpioTestEventHandler).apply(a.digitalPinsCfg) WithGpioPollForEdgeDetection("7", 0, nil).apply(a.digitalPinsCfg) require.NoError(t, a.Connect()) err := a.DigitalWrite("7", 1) require.NoError(t, err) assert.Equal(t, "1", fs.Files["/sys/class/gpio/gpio18/value"].Contents) // assert second write to same pin without error and just ignore unsupported options WithGpiosPullDown("7").apply(a.digitalPinsCfg) WithGpiosOpenSource("7").apply(a.digitalPinsCfg) WithGpioDebounce("7", 2*time.Second).apply(a.digitalPinsCfg) WithGpioEventOnRisingEdge("7", gpioTestEventHandler).apply(a.digitalPinsCfg) require.NoError(t, a.Finalize()) require.NoError(t, a.Connect()) err = a.DigitalWrite("7", 1) require.NoError(t, err) // assert third write to same pin without error WithGpioEventOnBothEdges("7", gpioTestEventHandler).apply(a.digitalPinsCfg) require.NoError(t, a.Finalize()) require.NoError(t, a.Connect()) err = a.DigitalWrite("7", 1) require.NoError(t, err) // assert error on bad id require.ErrorContains(t, a.DigitalWrite("notexist", 1), "not a valid pin") // assert error bubbling fs.WithWriteError = true err = a.DigitalWrite("7", 0) require.ErrorContains(t, err, "write error") } func TestDigitalWriteWithGpiosActiveLow(t *testing.T) { // arrange mockedPaths := []string{ "/sys/class/gpio/export", "/sys/class/gpio/unexport", "/sys/class/gpio/gpio19/value", "/sys/class/gpio/gpio19/direction", "/sys/class/gpio/gpio19/active_low", } a, fs := initTestDigitalPinsAdaptorWithMockedFilesystem(mockedPaths) fs.Files["/sys/class/gpio/gpio19/active_low"].Contents = "5" WithGpiosActiveLow("8").apply(a.digitalPinsCfg) require.NoError(t, a.Connect()) // act err := a.DigitalWrite("8", 2) // assert require.NoError(t, err) assert.Equal(t, "2", fs.Files["/sys/class/gpio/gpio19/value"].Contents) assert.Equal(t, "1", fs.Files["/sys/class/gpio/gpio19/active_low"].Contents) } func gpioTestEventHandler(o int, t time.Duration, et string, sn uint32, lsn uint32) { // the handler should never execute, because used in outputs and not supported by sysfs panic(fmt.Sprintf("event handler was called (%d, %d) unexpected for line %d with '%s' at %s!", sn, lsn, o, t, et)) } ================================================ FILE: platforms/adaptors/digitalpintranslator.go ================================================ package adaptors import ( "fmt" "gobot.io/x/gobot/v2/system" ) type CdevPin struct { Chip uint8 Line uint8 } type DigitalPinDefinition struct { Sysfs int Cdev CdevPin } type DigitalPinDefinitions map[string]DigitalPinDefinition type DigitalPinTranslator struct { sys *system.Accesser pinDefinitions DigitalPinDefinitions } // NewDigitalPinTranslator creates a new instance of a translator for digital GPIO pins, suitable for the most cases. func NewDigitalPinTranslator(sys *system.Accesser, pinDefinitions DigitalPinDefinitions) *DigitalPinTranslator { return &DigitalPinTranslator{sys: sys, pinDefinitions: pinDefinitions} } // Translate returns the chip and the line or for legacy sysfs usage the pin number from the given id. func (pt *DigitalPinTranslator) Translate(id string) (string, int, error) { pindef, ok := pt.pinDefinitions[id] if !ok { return "", -1, fmt.Errorf("'%s' is not a valid id for a digital pin", id) } if pt.sys.HasDigitalPinSysfsAccess() { return "", pindef.Sysfs, nil } chip := fmt.Sprintf("gpiochip%d", pindef.Cdev.Chip) line := int(pindef.Cdev.Line) return chip, line, nil } ================================================ FILE: platforms/adaptors/digitalpintranslator_test.go ================================================ package adaptors import ( "fmt" "testing" "github.com/stretchr/testify/assert" "gobot.io/x/gobot/v2/system" ) func TestNewDigitalPinTranslator(t *testing.T) { // arrange sys := &system.Accesser{} pinDef := DigitalPinDefinitions{} // act pt := NewDigitalPinTranslator(sys, pinDef) // assert assert.IsType(t, &DigitalPinTranslator{}, pt) assert.Equal(t, sys, pt.sys) assert.Equal(t, pinDef, pt.pinDefinitions) } func TestDigitalPinTranslatorTranslate(t *testing.T) { pinDefinitions := DigitalPinDefinitions{ "7": {Sysfs: 17, Cdev: CdevPin{Chip: 0, Line: 17}}, "22": {Sysfs: 171, Cdev: CdevPin{Chip: 5, Line: 19}}, "5": {Sysfs: 253, Cdev: CdevPin{Chip: 8, Line: 5}}, } tests := map[string]struct { access system.AccesserOptionApplier pin string wantChip string wantLine int wantErr error }{ "cdev_ok_7": { pin: "7", wantChip: "gpiochip0", wantLine: 17, }, "cdev_ok_22": { pin: "22", wantChip: "gpiochip5", wantLine: 19, }, "cdev_ok_5": { pin: "5", wantChip: "gpiochip8", wantLine: 5, }, "sysfs_ok_7": { access: system.WithDigitalPinSysfsAccess(), pin: "7", wantChip: "", wantLine: 17, }, "sysfs_ok_22": { access: system.WithDigitalPinSysfsAccess(), pin: "22", wantChip: "", wantLine: 171, }, "sysfs_ok_5": { access: system.WithDigitalPinSysfsAccess(), pin: "5", wantChip: "", wantLine: 253, }, "unknown_pin": { pin: "99", wantChip: "", wantLine: -1, wantErr: fmt.Errorf("'99' is not a valid id for a digital pin"), }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange sys := system.NewAccesser() // arrange for cdev needed sys.UseMockFilesystem([]string{"/dev/gpiochip"}) sys.AddDigitalPinSupport(tc.access) pt := NewDigitalPinTranslator(sys, pinDefinitions) // act chip, line, err := pt.Translate(tc.pin) // assert assert.Equal(t, tc.wantErr, err) assert.Equal(t, tc.wantChip, chip) assert.Equal(t, tc.wantLine, line) }) } } ================================================ FILE: platforms/adaptors/i2cbusadaptor.go ================================================ package adaptors import ( "fmt" "sync" multierror "github.com/hashicorp/go-multierror" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/system" ) type i2cBusNumberValidator func(busNumber int) error // i2cBusConfiguration contains all changeable attributes of the adaptor. type i2cBusConfiguration struct { debug bool } // I2cBusAdaptor is a adaptor for i2c bus, normally used for composition in platforms. type I2cBusAdaptor struct { sys *system.Accesser i2cBusCfg *i2cBusConfiguration validateNumber i2cBusNumberValidator defaultBusNumber int mutex sync.Mutex buses map[int]gobot.I2cSystemDevicer } // NewI2cBusAdaptor provides the access to i2c buses of the board. The validator is used to check the bus number, // which is given by user, to the abilities of the board. // // Options: // // "WithI2cDebug" func NewI2cBusAdaptor( sys *system.Accesser, v i2cBusNumberValidator, defaultBusNr int, opts ...I2CBusOptionApplier, ) *I2cBusAdaptor { a := I2cBusAdaptor{ sys: sys, i2cBusCfg: &i2cBusConfiguration{}, validateNumber: v, defaultBusNumber: defaultBusNr, } for _, o := range opts { o.apply(a.i2cBusCfg) } sys.AddI2CSupport() return &a } // WithI2cDebug can be used to switch on debugging for I2C implementation. func WithI2cDebug() i2cBusDebugOption { return i2cBusDebugOption(true) } // Connect prepares the connection to i2c buses. func (a *I2cBusAdaptor) Connect() error { a.mutex.Lock() defer a.mutex.Unlock() if a.buses != nil { return fmt.Errorf("I2C bus adaptor already connected, please call Finalize() for re-connect") } a.buses = make(map[int]gobot.I2cSystemDevicer) a.debuglnf("connect the I2C bus adaptor done") return nil } // Finalize closes all i2c buses. func (a *I2cBusAdaptor) Finalize() error { a.mutex.Lock() defer a.mutex.Unlock() a.debuglnf("finalize the I2C bus adaptor for %d buses...", len(a.buses)) var err error for busNum, bus := range a.buses { if bus != nil { e := bus.Close() if e != nil { err = multierror.Append(err, e) } a.debuglnf("I2C bus %d closed with error: %v", busNum, e) } } a.buses = nil a.debuglnf("finalize the I2C bus adaptor done with error: %v", err) return err } // GetI2cConnection returns a connection to a device on a specified i2c bus func (a *I2cBusAdaptor) GetI2cConnection(address int, busNum int) (i2c.Connection, error) { a.mutex.Lock() defer a.mutex.Unlock() if a.buses == nil { return nil, fmt.Errorf("not connected") } bus := a.buses[busNum] if bus == nil { err := a.validateNumber(busNum) if err != nil { return nil, err } bus, err = a.sys.NewI2cDevice(fmt.Sprintf("/dev/i2c-%d", busNum)) if err != nil { return nil, err } a.buses[busNum] = bus } return i2c.NewConnection(bus, address), nil } // DefaultI2cBus returns the default i2c bus number for this platform. func (a *I2cBusAdaptor) DefaultI2cBus() int { return a.defaultBusNumber } func (a *I2cBusAdaptor) debuglnf(format string, p ...interface{}) { gobot.Debuglnf(a.i2cBusCfg.debug, format, p...) } ================================================ FILE: platforms/adaptors/i2cbusadaptor_test.go ================================================ package adaptors import ( "fmt" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/system" ) // make sure that this Adaptor fulfills all the required interfaces var _ i2c.Connector = (*I2cBusAdaptor)(nil) const i2cBus1 = "/dev/i2c-1" func initTestI2cAdaptorWithMockedFilesystem(mockPaths []string) (*I2cBusAdaptor, *system.MockFilesystem) { validator := func(busNr int) error { if busNr > 1 { return fmt.Errorf("%d not valid", busNr) } return nil } a := NewI2cBusAdaptor(system.NewAccesser(), validator, 1) a.sys.UseMockSyscall() fs := a.sys.UseMockFilesystem(mockPaths) if err := a.Connect(); err != nil { panic(err) } return a, fs } func TestI2cWorkflow(t *testing.T) { a, _ := initTestI2cAdaptorWithMockedFilesystem([]string{i2cBus1}) assert.Empty(t, a.buses) con, err := a.GetI2cConnection(0xff, 1) require.NoError(t, err) assert.Len(t, a.buses, 1) _, err = con.Write([]byte{0x00, 0x01}) require.NoError(t, err) data := []byte{42, 42} _, err = con.Read(data) require.NoError(t, err) assert.Equal(t, []byte{0x00, 0x01}, data) require.NoError(t, a.Finalize()) assert.Empty(t, a.buses) } func TestI2cGetI2cConnection(t *testing.T) { // arrange a, _ := initTestI2cAdaptorWithMockedFilesystem([]string{i2cBus1}) // assert working connection c1, e1 := a.GetI2cConnection(0xff, 1) require.NoError(t, e1) assert.NotNil(t, c1) assert.Len(t, a.buses, 1) // assert invalid bus gets error c2, e2 := a.GetI2cConnection(0x01, 99) require.ErrorContains(t, e2, "99 not valid") assert.Nil(t, c2) assert.Len(t, a.buses, 1) // assert unconnected gets error require.NoError(t, a.Finalize()) c3, e3 := a.GetI2cConnection(0x01, 99) require.ErrorContains(t, e3, "not connected") assert.Nil(t, c3) assert.Empty(t, a.buses) } func TestI2cFinalize(t *testing.T) { // arrange a, fs := initTestI2cAdaptorWithMockedFilesystem([]string{i2cBus1}) // assert that finalize before connect is working require.NoError(t, a.Finalize()) // arrange require.NoError(t, a.Connect()) _, _ = a.GetI2cConnection(0xaf, 1) assert.Len(t, a.buses, 1) // assert that Finalize after GetI2cConnection is working and clean up require.NoError(t, a.Finalize()) assert.Empty(t, a.buses) // assert that finalize after finalize is working require.NoError(t, a.Finalize()) // assert that close error is recognized require.NoError(t, a.Connect()) con, _ := a.GetI2cConnection(0xbf, 1) assert.Len(t, a.buses, 1) _, _ = con.Write([]byte{0xbf}) fs.WithCloseError = true err := a.Finalize() require.ErrorContains(t, err, "close error") } func TestI2cReConnect(t *testing.T) { // arrange a, _ := initTestI2cAdaptorWithMockedFilesystem([]string{i2cBus1}) require.NoError(t, a.Finalize()) // act require.NoError(t, a.Connect()) // assert assert.NotNil(t, a.buses) assert.Empty(t, a.buses) } func TestI2cGetDefaultBus(t *testing.T) { a := NewI2cBusAdaptor(system.NewAccesser(), nil, 2) assert.Equal(t, 2, a.DefaultI2cBus()) } ================================================ FILE: platforms/adaptors/i2cbusadaptoroptions.go ================================================ package adaptors // I2CBusOptionApplier is the interface for I2C bus adaptors options. This provides the possibility for change the // platform behavior by the user when creating the platform, e.g. by "NewAdaptor()". // The interface needs to be implemented by each configurable option type. type I2CBusOptionApplier interface { apply(cfg *i2cBusConfiguration) } // i2cBusDebugOption is the type to switch on I2C related debug messages. type i2cBusDebugOption bool func (o i2cBusDebugOption) String() string { return "switch on debugging for I2C option" } func (o i2cBusDebugOption) apply(cfg *i2cBusConfiguration) { cfg.debug = bool(o) } ================================================ FILE: platforms/adaptors/i2cbusadaptoroptions_test.go ================================================ package adaptors import ( "testing" "github.com/stretchr/testify/assert" "gobot.io/x/gobot/v2/system" ) func TestWithI2cDebug(t *testing.T) { // This is a general test, that options are applied in constructor. Further tests for options // can also be done by call of "WithOption(val).apply(cfg)". // arrange & act a := NewI2cBusAdaptor(system.NewAccesser(), nil, 0, WithI2cDebug()) // assert assert.True(t, a.i2cBusCfg.debug) } ================================================ FILE: platforms/adaptors/onewirebusadaptor.go ================================================ package adaptors import ( "fmt" "sync" multierror "github.com/hashicorp/go-multierror" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/onewire" "gobot.io/x/gobot/v2/system" ) // oneWireBusConfiguration contains all changeable attributes of the adaptor. type oneWireBusConfiguration struct { debug bool } // OneWireBusAdaptor is a adaptor for the 1-wire bus, normally used for composition in platforms. // note: currently only one controller is supported by most platforms, but it would be possible to activate more, // see https://forums.raspberrypi.com/viewtopic.php?t=65137 // // Options: // // "WithOneWireDebug" type OneWireBusAdaptor struct { sys *system.Accesser oneWireBusCfg *oneWireBusConfiguration mutex *sync.Mutex connections map[string]onewire.Connection } // NewOneWireBusAdaptor provides the access to 1-wire devices of the board. func NewOneWireBusAdaptor(sys *system.Accesser, opts ...OneWireBusOptionApplier) *OneWireBusAdaptor { a := OneWireBusAdaptor{ sys: sys, oneWireBusCfg: &oneWireBusConfiguration{}, mutex: &sync.Mutex{}, } for _, o := range opts { o.apply(a.oneWireBusCfg) } sys.AddOneWireSupport() return &a } // WithOneWireDebug can be used to switch on debugging for 1-wire implementation. func WithOneWireDebug() oneWireBusDebugOption { return oneWireBusDebugOption(true) } // Connect prepares the connection to 1-wire devices. func (a *OneWireBusAdaptor) Connect() error { a.mutex.Lock() defer a.mutex.Unlock() if a.connections != nil { return fmt.Errorf("1-wire bus adaptor already connected, please call Finalize() for re-connect") } a.connections = make(map[string]onewire.Connection) a.debuglnf("connect the 1-wire bus adaptor done") return nil } // Finalize closes all 1-wire connections. func (a *OneWireBusAdaptor) Finalize() error { a.mutex.Lock() defer a.mutex.Unlock() a.debuglnf("finalize the 1-wire bus adaptor for %d buses...", len(a.connections)) var err error for id, con := range a.connections { if con != nil { e := con.Close() if e != nil { err = multierror.Append(err, e) } a.debuglnf("1-wire bus %s closed with error: %v", id, e) } } a.connections = nil a.debuglnf("finalize the 1-wire bus adaptor done with error: %v", err) return err } // GetOneWireConnection returns a 1-wire connection to a device with the given family code and serial number. func (a *OneWireBusAdaptor) GetOneWireConnection(familyCode byte, serialNumber uint64) (onewire.Connection, error) { a.mutex.Lock() defer a.mutex.Unlock() if a.connections == nil { return nil, fmt.Errorf("not connected") } id := fmt.Sprintf("%d_%d", familyCode, serialNumber) con := a.connections[id] if con == nil { var err error dev, err := a.sys.NewOneWireDevice(familyCode, serialNumber) if err != nil { return nil, err } con = onewire.NewConnection(dev) a.connections[id] = con } return con, nil } func (a *OneWireBusAdaptor) debuglnf(format string, p ...interface{}) { gobot.Debuglnf(a.oneWireBusCfg.debug, format, p...) } ================================================ FILE: platforms/adaptors/onewirebusadaptor_test.go ================================================ package adaptors import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2/system" ) func initTestOneWireAdaptor() *OneWireBusAdaptor { a := NewOneWireBusAdaptor(system.NewAccesser()) if err := a.Connect(); err != nil { panic(err) } return a } func TestNewOneWireBusAdaptor(t *testing.T) { // arrange sys := system.NewAccesser() // act a := NewOneWireBusAdaptor(sys) // assert assert.IsType(t, &OneWireBusAdaptor{}, a) assert.NotNil(t, a.mutex) assert.Nil(t, a.connections) } func TestOneWireGetOneWireConnection(t *testing.T) { // arrange const ( familyCode = 28 serialNumber = 123456789 ) a := initTestOneWireAdaptor() // assert working connection c1, e1 := a.GetOneWireConnection(familyCode, serialNumber) require.NoError(t, e1) assert.NotNil(t, c1) assert.Len(t, a.connections, 1) // assert unconnected gets error require.NoError(t, a.Finalize()) c2, e2 := a.GetOneWireConnection(familyCode, serialNumber+1) require.ErrorContains(t, e2, "not connected") assert.Nil(t, c2) assert.Empty(t, a.connections) } func TestOneWireFinalize(t *testing.T) { // arrange a := initTestOneWireAdaptor() // assert that finalize before connect is working require.NoError(t, a.Finalize()) // arrange require.NoError(t, a.Connect()) _, _ = a.GetOneWireConnection(28, 54321) assert.Len(t, a.connections, 1) // assert that Finalize after GetOneWireConnection is working and clean up require.NoError(t, a.Finalize()) assert.Empty(t, a.connections) // assert that finalize after finalize is working require.NoError(t, a.Finalize()) } func TestOneWireReConnect(t *testing.T) { // arrange a := initTestOneWireAdaptor() require.NoError(t, a.Finalize()) // act require.NoError(t, a.Connect()) // assert assert.NotNil(t, a.connections) assert.Empty(t, a.connections) } ================================================ FILE: platforms/adaptors/onewirebusadaptoroptions.go ================================================ package adaptors // OneWireBusOptionApplier is the interface for 1-wire bus adaptors options. This provides the possibility for change // the platform behavior by the user when creating the platform, e.g. by "NewAdaptor()". // The interface needs to be implemented by each configurable option type. type OneWireBusOptionApplier interface { apply(cfg *oneWireBusConfiguration) } // oneWireBusDebugOption is the type to switch on 1-wire related debug messages. type oneWireBusDebugOption bool func (o oneWireBusDebugOption) String() string { return "switch on debugging for 1-wire option" } func (o oneWireBusDebugOption) apply(cfg *oneWireBusConfiguration) { cfg.debug = bool(o) } ================================================ FILE: platforms/adaptors/onewirebusadaptoroptions_test.go ================================================ package adaptors import ( "testing" "github.com/stretchr/testify/assert" "gobot.io/x/gobot/v2/system" ) func TestWithOneWireDebug(t *testing.T) { // This is a general test, that options are applied in constructor. Further tests for options // can also be done by call of "WithOption(val).apply(cfg)". // arrange & act a := NewOneWireBusAdaptor(system.NewAccesser(), WithOneWireDebug()) // assert assert.True(t, a.oneWireBusCfg.debug) } ================================================ FILE: platforms/adaptors/piblasterpwm_pin.go ================================================ package adaptors import ( "fmt" "os" "strconv" "gobot.io/x/gobot/v2/system" ) const ( piBlasterPath = "/dev/pi-blaster" piBlasterMinDutyNano = 10000 // 10 us ) // piBlasterPWMPin is the Raspberry Pi implementation of the PWMPinner interface. // It uses Pi Blaster. type piBlasterPWMPin struct { sys *system.Accesser pin string dc uint32 period uint32 } // newPiBlasterPWMPin returns a new PWM pin for pi-blaster access. func newPiBlasterPWMPin(sys *system.Accesser, pinNo int) *piBlasterPWMPin { return &piBlasterPWMPin{ sys: sys, pin: strconv.Itoa(pinNo), } } // Export exports the pin for use by the Raspberry Pi func (p *piBlasterPWMPin) Export() error { return nil } // Unexport releases the pin from the operating system func (p *piBlasterPWMPin) Unexport() error { return p.writeValue(fmt.Sprintf("release %v\n", p.pin)) } // Enabled returns always true for "enabled" func (p *piBlasterPWMPin) Enabled() (bool, error) { return true, nil } // SetEnabled do nothing for PiBlaster func (p *piBlasterPWMPin) SetEnabled(e bool) error { return nil } // Polarity returns always true for "normal" func (p *piBlasterPWMPin) Polarity() (bool, error) { return true, nil } // SetPolarity does not do anything when using PiBlaster func (p *piBlasterPWMPin) SetPolarity(bool) error { return nil } // Period returns the cached PWM period for pin func (p *piBlasterPWMPin) Period() (uint32, error) { return p.period, nil } // SetPeriod uses PiBlaster setting and cannot be changed. We allow setting once here to define a base period for // ServoWrite(). see https://github.com/sarfata/pi-blaster#how-to-adjust-the-frequency-and-the-resolution-of-the-pwm func (p *piBlasterPWMPin) SetPeriod(period uint32) error { if p.period != 0 { return fmt.Errorf("the period of PWM pins needs to be set to '%d' in pi-blaster source code", period) } p.period = period return nil } // DutyCycle returns the duty cycle for the pin func (p *piBlasterPWMPin) DutyCycle() (uint32, error) { return p.dc, nil } // SetDutyCycle writes the duty cycle to the pin func (p *piBlasterPWMPin) SetDutyCycle(dutyNanos uint32) error { if p.period == 0 { return fmt.Errorf("pi-blaster PWM pin period not set while try to set duty cycle to '%d'", dutyNanos) } if dutyNanos > p.period { return fmt.Errorf("the duty cycle (%d) exceeds period (%d) for pi-blaster", dutyNanos, p.period) } // never go below minimum allowed duty for pi blaster unless the duty equals to 0 if dutyNanos < piBlasterMinDutyNano && dutyNanos != 0 { dutyNanos = piBlasterMinDutyNano fmt.Printf("duty cycle value limited to '%d' ns for pi-blaster", dutyNanos) } duty := float64(dutyNanos) / float64(p.period) if err := p.writeValue(fmt.Sprintf("%v=%v\n", p.pin, duty)); err != nil { return err } p.dc = dutyNanos return nil } func (p *piBlasterPWMPin) writeValue(data string) error { fi, err := p.sys.OpenFile(piBlasterPath, os.O_WRONLY|os.O_APPEND, 0o644) defer fi.Close() //nolint:staticcheck // for historical reasons if err != nil { return err } _, err = fi.WriteString(data) return err } ================================================ FILE: platforms/adaptors/piblasterpwm_pin_test.go ================================================ package adaptors import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/system" ) var _ gobot.PWMPinner = (*piBlasterPWMPin)(nil) func TestPiBlasterPWMPin(t *testing.T) { // arrange const path = "/dev/pi-blaster" a := system.NewAccesser() a.UseMockFilesystem([]string{path}) pin := newPiBlasterPWMPin(a, 1) // act & assert: activate pin for usage require.NoError(t, pin.Export()) require.NoError(t, pin.SetEnabled(true)) // act & assert: get and set polarity val, err := pin.Polarity() require.NoError(t, err) assert.True(t, val) require.NoError(t, pin.SetPolarity(false)) polarity, err := pin.Polarity() assert.True(t, polarity) require.NoError(t, err) // act & assert: get and set period period, err := pin.Period() require.NoError(t, err) assert.Equal(t, uint32(0), period) require.NoError(t, pin.SetPeriod(20000000)) period, err = pin.Period() require.NoError(t, err) assert.Equal(t, uint32(20000000), period) err = pin.SetPeriod(10000000) require.EqualError(t, err, "the period of PWM pins needs to be set to '10000000' in pi-blaster source code") // act & assert: cleanup require.NoError(t, pin.Unexport()) } func TestPiBlasterPWMPin_DutyCycle(t *testing.T) { // arrange const path = "/dev/pi-blaster" a := system.NewAccesser() a.UseMockFilesystem([]string{path}) pin := newPiBlasterPWMPin(a, 1) // act & assert: activate pin for usage require.NoError(t, pin.Export()) require.NoError(t, pin.SetEnabled(true)) // act & assert zero dc, err := pin.DutyCycle() require.NoError(t, err) assert.Equal(t, uint32(0), dc) // act & assert error without period set, the value remains zero err = pin.SetDutyCycle(10000) require.EqualError(t, err, "pi-blaster PWM pin period not set while try to set duty cycle to '10000'") dc, err = pin.DutyCycle() require.NoError(t, err) assert.Equal(t, uint32(0), dc) // arrange, act & assert a value pin.period = 20000000 require.NoError(t, pin.SetDutyCycle(10000)) dc, err = pin.DutyCycle() require.NoError(t, err) assert.Equal(t, uint32(10000), dc) // act & assert error on over limit, the value remains err = pin.SetDutyCycle(20000001) require.EqualError(t, err, "the duty cycle (20000001) exceeds period (20000000) for pi-blaster") dc, err = pin.DutyCycle() require.NoError(t, err) assert.Equal(t, uint32(10000), dc) // act & assert: cleanup require.NoError(t, pin.Unexport()) } ================================================ FILE: platforms/adaptors/pwmpinsadaptor.go ================================================ package adaptors import ( "fmt" "log" "sync" "time" multierror "github.com/hashicorp/go-multierror" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/system" ) // note for period in nano seconds: // 100000000ns = 100ms = 10Hz, 10000000ns = 10ms = 100Hz, 1000000ns = 1ms = 1kHz, // 100000ns = 100us = 10kHz, 10000ns = 10us = 100kHz, 1000ns = 1us = 1MHz, // 100ns = 10MHz, 10ns = 100MHz, 1ns = 1GHz const pwmPeriodDefault = 10000000 // 10 ms = 100 Hz // 50Hz = 0.02 sec = 20 ms const fiftyHzNanos = 20 * 1000 * 1000 type ( pwmPinTranslator func(pin string) (path string, channel int, err error) pwmPinInitializer func(id string, pin gobot.PWMPinner) error ) type pwmPinServoScale struct { minDegree, maxDegree float64 minDuty, maxDuty time.Duration } // pwmPinsConfiguration contains all changeable attributes of the adaptor. type pwmPinsConfiguration struct { debug bool initialize pwmPinInitializer usePiBlasterPin bool periodDefault uint32 periodMinimum uint32 dutyRateMinimum float64 // is the minimal relation of duty/period (except 0.0) polarityNormalIdentifier string polarityInvertedIdentifier string adjustDutyOnSetPeriod bool pinsDefaultPeriod map[string]uint32 // the key is the pin id pinsServoScale map[string]pwmPinServoScale // the key is the pin id } // PWMPinsAdaptor is a adaptor for PWM pins, normally used for composition in platforms. type PWMPinsAdaptor struct { sys *system.Accesser translate pwmPinTranslator pwmPinsCfg *pwmPinsConfiguration pins map[string]gobot.PWMPinner mutex sync.Mutex } // NewPWMPinsAdaptor provides the access to PWM pins of the board. It uses sysfs system drivers. The translator is used // to adapt the pin header naming, which is given by user, to the internal file name nomenclature. This varies by each // platform. If for some reasons the default initializer is not suitable, it can be given by the option // "WithPWMPinInitializer()". // // Further options: // // "WithPWMPinDebug" // "WithPWMDefaultPeriod" // "WithPWMPolarityInvertedIdentifier" // "WithPWMNoDutyCycleAdjustment" // "WithPWMDefaultPeriodForPin" // "WithPWMServoDutyCycleRangeForPin" // "WithPWMServoAngleRangeForPin" func NewPWMPinsAdaptor(sys *system.Accesser, t pwmPinTranslator, opts ...PwmPinsOptionApplier) *PWMPinsAdaptor { a := PWMPinsAdaptor{ sys: sys, translate: t, pwmPinsCfg: &pwmPinsConfiguration{ periodDefault: pwmPeriodDefault, pinsDefaultPeriod: make(map[string]uint32), pinsServoScale: make(map[string]pwmPinServoScale), polarityNormalIdentifier: "normal", polarityInvertedIdentifier: "inversed", adjustDutyOnSetPeriod: true, }, } a.pwmPinsCfg.initialize = a.getDefaultInitializer() for _, o := range opts { o.apply(a.pwmPinsCfg) } sys.AddPWMSupport() return &a } // WithPWMPinDebug can be used to switch on debugging for PWM-pins implementation. func WithPWMPinDebug() pwmPinsDebugOption { return pwmPinsDebugOption(true) } // WithPWMPinInitializer substitute the default initializer. func WithPWMPinInitializer(pc pwmPinInitializer) pwmPinsInitializeOption { return pwmPinsInitializeOption(pc) } // WithPWMUsePiBlaster substitute the default sysfs-implementation for PWM-pins by the implementation for pi-blaster. func WithPWMUsePiBlaster() pwmPinsUsePiBlasterPinOption { return pwmPinsUsePiBlasterPinOption(true) } // WithPWMDefaultPeriod substitute the default period of 10 ms (100 Hz) for all created pins. func WithPWMDefaultPeriod(periodNanoSec uint32) pwmPinsPeriodDefaultOption { return pwmPinsPeriodDefaultOption(periodNanoSec) } // WithPWMMinimumPeriod substitute the default minimum period limit of 0 nanoseconds. func WithPWMMinimumPeriod(periodNanoSec uint32) pwmPinsPeriodMinimumOption { return pwmPinsPeriodMinimumOption(periodNanoSec) } // WithPWMMinimumDutyRate substitute the default minimum duty rate of 1/period. The given limit only come into effect, // if the rate is > 0, because a rate of 0.0 is always allowed. func WithPWMMinimumDutyRate(dutyRate float64) pwmPinsDutyRateMinimumOption { return pwmPinsDutyRateMinimumOption(dutyRate) } // WithPWMPolarityInvertedIdentifier use the given identifier, which will replace the default "inversed". func WithPWMPolarityInvertedIdentifier(identifier string) pwmPinsPolarityInvertedIdentifierOption { return pwmPinsPolarityInvertedIdentifierOption(identifier) } // WithPWMNoDutyCycleAdjustment switch off the automatic adjustment of duty cycle on setting the period. func WithPWMNoDutyCycleAdjustment() pwmPinsAdjustDutyOnSetPeriodOption { return pwmPinsAdjustDutyOnSetPeriodOption(false) } // WithPWMDefaultPeriodForPin substitute the default period of 10 ms (100 Hz) for the given pin. // This option also overrides a default period given by the WithPWMDefaultPeriod() option. // This is often needed for servo applications, where the default period is 50Hz (20.000.000 ns). func WithPWMDefaultPeriodForPin(pin string, periodNanoSec uint32) pwmPinsDefaultPeriodForPinOption { o := pwmPinsDefaultPeriodForPinOption{id: pin, period: periodNanoSec} return o } // WithPWMServoDutyCycleRangeForPin set new values for range of duty cycle for servo calls, which replaces the default // 0.5-2.5 ms range. The given duration values will be internally converted to nanoseconds. func WithPWMServoDutyCycleRangeForPin(pin string, minimum, maximum time.Duration) pwmPinsServoDutyScaleForPinOption { return pwmPinsServoDutyScaleForPinOption{id: pin, min: minimum, max: maximum} } // WithPWMServoAngleRangeForPin set new values for range of angle for servo calls, which replaces // the default 0.0-180.0° range. func WithPWMServoAngleRangeForPin(pin string, minimum, maximum float64) pwmPinsServoAngleScaleForPinOption { return pwmPinsServoAngleScaleForPinOption{id: pin, minDegree: minimum, maxDegree: maximum} } // Connect prepare new connection to PWM pins. func (a *PWMPinsAdaptor) Connect() error { a.mutex.Lock() defer a.mutex.Unlock() if a.pins != nil { return fmt.Errorf("PWM pins adaptor already connected, please call Finalize() for re-connect") } a.pins = make(map[string]gobot.PWMPinner) if a.pwmPinsCfg.dutyRateMinimum == 0 && a.pwmPinsCfg.periodDefault > 0 { a.pwmPinsCfg.dutyRateMinimum = 1 / float64(a.pwmPinsCfg.periodDefault) } a.debuglnf("connect the PWM pins adaptor done") return nil } // Finalize closes connection to PWM pins. func (a *PWMPinsAdaptor) Finalize() error { a.mutex.Lock() defer a.mutex.Unlock() a.debuglnf("finalize the pwm pins adaptor with %d pins...", len(a.pins)) var err error for id, pin := range a.pins { if pin != nil { if e := pin.SetEnabled(false); e != nil { a.debuglnf("PWM pin '%s' disabled on finalize with error: %v", id, e) err = multierror.Append(err, e) } if e := pin.Unexport(); e != nil { a.debuglnf("PWM pin '%s' unexport on finalize with error: %v", id, e) err = multierror.Append(err, e) } } } a.pins = nil a.debuglnf("finalize the PWM pins adaptor done with error: %v", err) return err } // PwmWrite writes a PWM signal to the specified pin. The given value is between 0 and 255. func (a *PWMPinsAdaptor) PwmWrite(id string, val byte) error { a.mutex.Lock() defer a.mutex.Unlock() pin, err := a.pwmPin(id) if err != nil { return err } periodNanos, err := pin.Period() if err != nil { return err } dutyNanos := float64(periodNanos) * gobot.FromScale(float64(val), 0, 255.0) if err := a.validateDutyCycle(id, dutyNanos, float64(periodNanos)); err != nil { return err } return pin.SetDutyCycle(uint32(dutyNanos)) } // ServoWrite writes a servo signal to the specified pin. The given angle is between 0 and 180°. func (a *PWMPinsAdaptor) ServoWrite(id string, angle byte) error { a.mutex.Lock() defer a.mutex.Unlock() pin, err := a.pwmPin(id) if err != nil { return err } periodNanos, err := pin.Period() if err != nil { return err } if periodNanos != fiftyHzNanos { log.Printf("WARNING: the PWM acts with a period of %d, but should use %d (50Hz) for servos\n", periodNanos, fiftyHzNanos) } scale, ok := a.pwmPinsCfg.pinsServoScale[id] if !ok { return fmt.Errorf("no scaler found for servo pin '%s'", id) } dutyNanos := gobot.ToScale(gobot.FromScale(float64(angle), scale.minDegree, scale.maxDegree), float64(scale.minDuty), float64(scale.maxDuty)) if err := a.validateDutyCycle(id, dutyNanos, float64(periodNanos)); err != nil { return err } return pin.SetDutyCycle(uint32(dutyNanos)) } // SetPeriod adjusts the period of the specified PWM pin immediately. // If duty cycle is already set, also this value will be adjusted in the same ratio. func (a *PWMPinsAdaptor) SetPeriod(id string, period uint32) error { a.mutex.Lock() defer a.mutex.Unlock() pin, err := a.pwmPin(id) if err != nil { return err } return setPeriod(pin, period, a.pwmPinsCfg.adjustDutyOnSetPeriod) } // PWMPin initializes the pin for PWM and returns matched pwmPin for specified pin number. // It implements the PWMPinnerProvider interface. func (a *PWMPinsAdaptor) PWMPin(id string) (gobot.PWMPinner, error) { a.mutex.Lock() defer a.mutex.Unlock() return a.pwmPin(id) } func (a *PWMPinsAdaptor) getDefaultInitializer() func(string, gobot.PWMPinner) error { return func(id string, pin gobot.PWMPinner) error { if err := pin.Export(); err != nil { return err } // Make sure PWM is disabled before change anything (period needs to be >0 for this check) if period, _ := pin.Period(); period > 0 { if err := pin.SetEnabled(false); err != nil { return err } } // looking for a pin specific period defaultPeriod, ok := a.pwmPinsCfg.pinsDefaultPeriod[id] if !ok { defaultPeriod = a.pwmPinsCfg.periodDefault } if err := setPeriod(pin, defaultPeriod, a.pwmPinsCfg.adjustDutyOnSetPeriod); err != nil { return err } // ensure servo scaler is present // // usually for the most servos (at 50Hz) for 180° (SG90, AD002) // 0.5 ms => 0 (1/40 part of period at 50Hz) // 1.5 ms => 90 // 2.5 ms => 180 (1/8 part of period at 50Hz) scale, ok := a.pwmPinsCfg.pinsServoScale[id] if !ok { scale = pwmPinServoScale{ minDegree: 0, maxDegree: 180, } } if scale.minDuty == 0 { scale.minDuty = time.Duration(defaultPeriod / 40) } if scale.maxDuty == 0 { scale.maxDuty = time.Duration(defaultPeriod / 8) } a.pwmPinsCfg.pinsServoScale[id] = scale // period needs to be set >1 before all next statements if err := pin.SetPolarity(true); err != nil { return err } return pin.SetEnabled(true) } } func (a *PWMPinsAdaptor) pwmPin(id string) (gobot.PWMPinner, error) { if a.pins == nil { return nil, fmt.Errorf("not connected") } pin := a.pins[id] if pin == nil { path, channel, err := a.translate(id) if err != nil { return nil, err } if a.pwmPinsCfg.usePiBlasterPin { pin = newPiBlasterPWMPin(a.sys, channel) } else { pin = a.sys.NewPWMPin(path, channel, a.pwmPinsCfg.polarityNormalIdentifier, a.pwmPinsCfg.polarityInvertedIdentifier) } if err := a.pwmPinsCfg.initialize(id, pin); err != nil { return nil, err } a.pins[id] = pin } return pin, nil } func (a *PWMPinsAdaptor) validateDutyCycle(id string, dutyNanos, periodNanos float64) error { if periodNanos == 0 { return nil } if dutyNanos > periodNanos { return fmt.Errorf("duty cycle (%d) exceeds period (%d) for PWM pin id '%s'", uint32(dutyNanos), uint32(periodNanos), id) } if dutyNanos == 0 { return nil } rate := dutyNanos / periodNanos if rate < a.pwmPinsCfg.dutyRateMinimum { return fmt.Errorf("duty rate (%.8f) is lower than allowed (%.8f) for PWM pin id '%s'", rate, a.pwmPinsCfg.dutyRateMinimum, id) } return nil } func (a *PWMPinsAdaptor) debuglnf(format string, p ...interface{}) { gobot.Debuglnf(a.pwmPinsCfg.debug, format, p...) } // setPeriod adjusts the PWM period of the given pin. If duty cycle is already set and this feature is not suppressed, // also this value will be adjusted in the same ratio. The order of writing the values must be observed, otherwise an // error occur "write error: Invalid argument". func setPeriod(pin gobot.PWMPinner, period uint32, adjustDuty bool) error { errorBase := fmt.Sprintf("setPeriod(%v, %d) failed", pin, period) var oldDuty uint32 var err error if adjustDuty { if oldDuty, err = pin.DutyCycle(); err != nil { return fmt.Errorf("%s with '%v'", errorBase, err) } } if oldDuty == 0 { if err := pin.SetPeriod(period); err != nil { return fmt.Errorf("%s with '%v'", errorBase, err) } } else { // adjust duty cycle in the same ratio oldPeriod, err := pin.Period() if err != nil { return fmt.Errorf("%s with '%v'", errorBase, err) } //nolint:gosec // TODO: fix later duty := uint32(uint64(oldDuty) * uint64(period) / uint64(oldPeriod)) // the order depends on value (duty must not be bigger than period in any situation) if duty > oldPeriod { if err := pin.SetPeriod(period); err != nil { return fmt.Errorf("%s with '%v'", errorBase, err) } if err := pin.SetDutyCycle(duty); err != nil { return fmt.Errorf("%s with '%v'", errorBase, err) } } else { if err := pin.SetDutyCycle(duty); err != nil { return fmt.Errorf("%s with '%v'", errorBase, err) } if err := pin.SetPeriod(period); err != nil { return fmt.Errorf("%s with '%v'", errorBase, err) } } } return nil } ================================================ FILE: platforms/adaptors/pwmpinsadaptor_test.go ================================================ //nolint:nonamedreturns // ok for tests package adaptors import ( "errors" "fmt" "runtime" "strconv" "sync" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/system" ) const ( pwmDir = "/sys/devices/platform/ff680020.pwm/pwm/pwmchip3/" //nolint:gosec // false positive pwmPwm44Dir = pwmDir + "pwm44/" pwmPwm47Dir = pwmDir + "pwm47/" pwmExportPath = pwmDir + "export" pwmUnexportPath = pwmDir + "unexport" pwm44EnablePath = pwmPwm44Dir + "enable" pwm44PeriodPath = pwmPwm44Dir + "period" pwm44DutyCyclePath = pwmPwm44Dir + "duty_cycle" pwm44PolarityPath = pwmPwm44Dir + "polarity" pwm47EnablePath = pwmPwm47Dir + "enable" pwm47PeriodPath = pwmPwm47Dir + "period" pwm47DutyCyclePath = pwmPwm47Dir + "duty_cycle" pwm47PolarityPath = pwmPwm47Dir + "polarity" ) var pwmMockPaths = []string{ pwmExportPath, pwmUnexportPath, pwm44EnablePath, pwm44PeriodPath, pwm44DutyCyclePath, pwm44PolarityPath, pwm47EnablePath, pwm47PeriodPath, pwm47DutyCyclePath, pwm47PolarityPath, } // make sure that this PWMPinsAdaptor fulfills all the required interfaces var ( _ gobot.PWMPinnerProvider = (*PWMPinsAdaptor)(nil) _ gpio.PwmWriter = (*PWMPinsAdaptor)(nil) _ gpio.ServoWriter = (*PWMPinsAdaptor)(nil) ) func initTestPWMPinsAdaptorWithMockedFilesystem(mockPaths []string) (*PWMPinsAdaptor, *system.MockFilesystem) { sys := system.NewAccesser() fs := sys.UseMockFilesystem(mockPaths) a := NewPWMPinsAdaptor(sys, testPWMPinTranslator) fs.Files[pwm44EnablePath].Contents = "0" fs.Files[pwm44PeriodPath].Contents = "0" fs.Files[pwm44DutyCyclePath].Contents = "0" fs.Files[pwm44PolarityPath].Contents = a.pwmPinsCfg.polarityInvertedIdentifier if err := a.Connect(); err != nil { panic(err) } return a, fs } func testPWMPinTranslator(id string) (string, int, error) { channel, err := strconv.Atoi(id) if err != nil { return "", -1, fmt.Errorf("'%s' is not a valid id of a PWM pin", id) } channel = channel + 11 // just for tests, 33=>pwm0, 36=>pwm3 return pwmDir, channel, err } func TestNewPWMPinsAdaptor(t *testing.T) { // arrange translate := func(pin string) (chip string, line int, err error) { return } // act a := NewPWMPinsAdaptor(system.NewAccesser(), translate) // assert assert.Equal(t, uint32(pwmPeriodDefault), a.pwmPinsCfg.periodDefault) assert.Equal(t, "normal", a.pwmPinsCfg.polarityNormalIdentifier) assert.Equal(t, "inversed", a.pwmPinsCfg.polarityInvertedIdentifier) assert.True(t, a.pwmPinsCfg.adjustDutyOnSetPeriod) } func TestPWMPinsConnect(t *testing.T) { translate := func(pin string) (chip string, line int, err error) { return } a := NewPWMPinsAdaptor(system.NewAccesser(), translate) assert.Equal(t, (map[string]gobot.PWMPinner)(nil), a.pins) err := a.PwmWrite("33", 1) require.ErrorContains(t, err, "not connected") err = a.Connect() require.NoError(t, err) assert.NotEqual(t, (map[string]gobot.PWMPinner)(nil), a.pins) assert.Empty(t, a.pins) } func TestPWMPinsFinalize(t *testing.T) { // arrange sys := system.NewAccesser() fs := sys.UseMockFilesystem(pwmMockPaths) a := NewPWMPinsAdaptor(sys, testPWMPinTranslator) fs.Files[pwm44PeriodPath].Contents = "0" fs.Files[pwm44DutyCyclePath].Contents = "0" // assert that finalize before connect is working require.NoError(t, a.Finalize()) // arrange require.NoError(t, a.Connect()) require.NoError(t, a.PwmWrite("33", 1)) assert.Len(t, a.pins, 1) // act err := a.Finalize() // assert require.NoError(t, err) assert.Empty(t, a.pins) // assert that finalize after finalize is working require.NoError(t, a.Finalize()) // arrange missing sysfs file require.NoError(t, a.Connect()) require.NoError(t, a.PwmWrite("33", 2)) delete(fs.Files, pwmUnexportPath) err = a.Finalize() require.ErrorContains(t, err, pwmUnexportPath+": no such file") // arrange write error require.NoError(t, a.Connect()) require.NoError(t, a.PwmWrite("33", 2)) fs.WithWriteError = true err = a.Finalize() require.ErrorContains(t, err, "write error") } func TestPWMPinsReConnect(t *testing.T) { // arrange a, _ := initTestPWMPinsAdaptorWithMockedFilesystem(pwmMockPaths) require.NoError(t, a.PwmWrite("33", 1)) assert.Len(t, a.pins, 1) require.NoError(t, a.Finalize()) // act err := a.Connect() // assert require.NoError(t, err) assert.NotNil(t, a.pins) assert.Empty(t, a.pins) } func TestPWMPinsCache(t *testing.T) { // arrange a, _ := initTestPWMPinsAdaptorWithMockedFilesystem(pwmMockPaths) // act firstSysPin, err := a.PWMPin("33") require.NoError(t, err) secondSysPin, err := a.PWMPin("33") require.NoError(t, err) otherSysPin, err := a.PWMPin("36") require.NoError(t, err) // assert assert.Equal(t, secondSysPin, firstSysPin) assert.NotEqual(t, otherSysPin, firstSysPin) } func TestPwmWrite(t *testing.T) { tests := map[string]struct { pin string value byte minimumRate float64 simulateWriteErr bool simulateReadErr bool wantExport string wantEnable string wantPeriod string wantDutyCycle string wantErr string }{ "write_max": { pin: "33", value: 255, wantExport: "44", wantEnable: "1", wantPeriod: "10000000", wantDutyCycle: "10000000", }, "write_nearmax": { pin: "33", value: 254, wantExport: "44", wantEnable: "1", wantPeriod: "10000000", wantDutyCycle: "9960784", }, "write_mid": { pin: "33", value: 100, wantExport: "44", wantEnable: "1", wantPeriod: "10000000", wantDutyCycle: "3921568", }, "write_near min": { pin: "33", value: 1, wantExport: "44", wantEnable: "1", wantPeriod: "10000000", wantDutyCycle: "39215", }, "write_min": { pin: "33", value: 0, minimumRate: 0.05, wantExport: "44", wantEnable: "1", wantPeriod: "10000000", wantDutyCycle: "0", }, "error_min_rate": { pin: "33", value: 1, minimumRate: 0.05, wantExport: "44", wantEnable: "1", wantPeriod: "10000000", wantDutyCycle: "0", wantErr: "is lower than allowed (0.05", }, "error_non_existent_pin": { pin: "notexist", wantEnable: "0", wantPeriod: "0", wantDutyCycle: "0", wantErr: "'notexist' is not a valid id of a PWM pin", }, "error_write_error": { pin: "33", value: 10, simulateWriteErr: true, wantEnable: "0", wantPeriod: "0", wantDutyCycle: "0", wantErr: "write error", }, "error_read_error": { pin: "33", value: 11, simulateReadErr: true, wantExport: "44", wantEnable: "0", wantPeriod: "0", wantDutyCycle: "0", wantErr: "read error", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange a, fs := initTestPWMPinsAdaptorWithMockedFilesystem(pwmMockPaths) if tc.minimumRate > 0 { a.pwmPinsCfg.dutyRateMinimum = tc.minimumRate } fs.WithWriteError = tc.simulateWriteErr fs.WithReadError = tc.simulateReadErr // act err := a.PwmWrite(tc.pin, tc.value) // assert assert.Equal(t, tc.wantExport, fs.Files[pwmExportPath].Contents) assert.Equal(t, tc.wantEnable, fs.Files[pwm44EnablePath].Contents) assert.Equal(t, tc.wantPeriod, fs.Files[pwm44PeriodPath].Contents) assert.Equal(t, tc.wantDutyCycle, fs.Files[pwm44DutyCyclePath].Contents) if tc.wantErr != "" { require.ErrorContains(t, err, tc.wantErr) } else { require.NoError(t, err) assert.Equal(t, "normal", fs.Files[pwm44PolarityPath].Contents) } }) } } func TestServoWrite(t *testing.T) { a, fs := initTestPWMPinsAdaptorWithMockedFilesystem(pwmMockPaths) err := a.ServoWrite("33", 0) require.NoError(t, err) assert.Equal(t, "44", fs.Files[pwmExportPath].Contents) assert.Equal(t, "1", fs.Files[pwm44EnablePath].Contents) //nolint:perfsprint // ok here assert.Equal(t, fmt.Sprintf("%d", a.pwmPinsCfg.periodDefault), fs.Files[pwm44PeriodPath].Contents) assert.Equal(t, "250000", fs.Files[pwm44DutyCyclePath].Contents) assert.Equal(t, "normal", fs.Files[pwm44PolarityPath].Contents) err = a.ServoWrite("33", 180) require.NoError(t, err) assert.Equal(t, "1250000", fs.Files[pwm44DutyCyclePath].Contents) err = a.ServoWrite("notexist", 42) require.ErrorContains(t, err, "'notexist' is not a valid id of a PWM pin") fs.WithWriteError = true err = a.ServoWrite("33", 100) require.ErrorContains(t, err, "write error") fs.WithWriteError = false fs.WithReadError = true err = a.ServoWrite("33", 100) require.ErrorContains(t, err, "read error") fs.WithReadError = false delete(a.pwmPinsCfg.pinsServoScale, "33") err = a.ServoWrite("33", 42) require.EqualError(t, err, "no scaler found for servo pin '33'") } func TestSetPeriod(t *testing.T) { // arrange a, fs := initTestPWMPinsAdaptorWithMockedFilesystem(pwmMockPaths) newPeriod := uint32(2550000) // act err := a.SetPeriod("33", newPeriod) // assert require.NoError(t, err) assert.Equal(t, "44", fs.Files[pwmExportPath].Contents) assert.Equal(t, "1", fs.Files[pwm44EnablePath].Contents) assert.Equal(t, fmt.Sprintf("%d", newPeriod), fs.Files[pwm44PeriodPath].Contents) //nolint:perfsprint // ok here assert.Equal(t, "0", fs.Files[pwm44DutyCyclePath].Contents) assert.Equal(t, "normal", fs.Files[pwm44PolarityPath].Contents) // arrange test for automatic adjustment of duty cycle to lower value err = a.PwmWrite("33", 127) // 127 is a little bit smaller than 50% of period require.NoError(t, err) assert.Equal(t, strconv.Itoa(1270000), fs.Files[pwm44DutyCyclePath].Contents) newPeriod = newPeriod / 10 // act err = a.SetPeriod("33", newPeriod) // assert require.NoError(t, err) assert.Equal(t, strconv.Itoa(127000), fs.Files[pwm44DutyCyclePath].Contents) // arrange test for automatic adjustment of duty cycle to higher value newPeriod = newPeriod * 20 // act err = a.SetPeriod("33", newPeriod) // assert require.NoError(t, err) assert.Equal(t, strconv.Itoa(2540000), fs.Files[pwm44DutyCyclePath].Contents) // act err = a.SetPeriod("not_exist", newPeriod) // assert require.ErrorContains(t, err, "'not_exist' is not a valid id of a PWM pin") } func Test_PWMPin(t *testing.T) { translateErr := "translator_error" translator := func(string) (string, int, error) { return pwmDir, 44, nil } tests := map[string]struct { mockPaths []string period string dutyCycle string translate func(string) (string, int, error) pin string wantErr string }{ "pin_ok": { mockPaths: []string{pwmExportPath, pwm44EnablePath, pwm44PeriodPath, pwm44DutyCyclePath, pwm44PolarityPath}, period: "0", dutyCycle: "0", translate: translator, pin: "33", }, "init_export_error": { mockPaths: []string{}, translate: translator, pin: "33", wantErr: "Export() failed for id 44 with : " + "/sys/devices/platform/ff680020.pwm/pwm/pwmchip3/export: no such file", }, "init_setenabled_error": { mockPaths: []string{pwmExportPath, pwm44PeriodPath}, period: "1000", translate: translator, pin: "33", wantErr: "SetEnabled(false) failed for id 44 with : " + "/sys/devices/platform/ff680020.pwm/pwm/pwmchip3/pwm44/enable: no such file", }, "init_setperiod_dutycycle_no_error": { mockPaths: []string{pwmExportPath, pwm44EnablePath, pwm44PeriodPath, pwm44DutyCyclePath, pwm44PolarityPath}, period: "0", dutyCycle: "0", translate: translator, pin: "33", }, "init_setperiod_error": { mockPaths: []string{pwmExportPath, pwm44EnablePath, pwm44DutyCyclePath}, dutyCycle: "0", translate: translator, pin: "33", wantErr: "SetPeriod(10000000) failed for id 44 with : " + "/sys/devices/platform/ff680020.pwm/pwm/pwmchip3/pwm44/period: no such file", }, "init_setpolarity_error": { mockPaths: []string{pwmExportPath, pwm44EnablePath, pwm44PeriodPath, pwm44DutyCyclePath}, period: "0", dutyCycle: "0", translate: translator, pin: "33", wantErr: "SetPolarity(normal) failed for id 44 with : " + "/sys/devices/platform/ff680020.pwm/pwm/pwmchip3/pwm44/polarity: no such file", }, "translate_error": { translate: func(string) (string, int, error) { return "", -1, errors.New(translateErr) }, wantErr: translateErr, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange sys := system.NewAccesser() fs := sys.UseMockFilesystem(tc.mockPaths) if tc.period != "" { fs.Files[pwm44PeriodPath].Contents = tc.period } if tc.dutyCycle != "" { fs.Files[pwm44DutyCyclePath].Contents = tc.dutyCycle } a := NewPWMPinsAdaptor(sys, tc.translate) if err := a.Connect(); err != nil { panic(err) } // act got, err := a.PWMPin(tc.pin) // assert if tc.wantErr == "" { require.NoError(t, err) assert.NotNil(t, got) } else { require.ErrorContains(t, err, tc.wantErr) assert.Nil(t, got) } }) } } func TestPWMPinConcurrency(t *testing.T) { oldProcs := runtime.GOMAXPROCS(0) runtime.GOMAXPROCS(8) defer runtime.GOMAXPROCS(oldProcs) translate := func(pin string) (string, int, error) { line, err := strconv.Atoi(pin); return "", line, err } sys := system.NewAccesser() for retry := 0; retry < 20; retry++ { a := NewPWMPinsAdaptor(sys, translate) require.NoError(t, a.Connect()) var wg sync.WaitGroup for i := 0; i < 20; i++ { wg.Add(1) pinAsString := strconv.Itoa(i) go func(pin string) { defer wg.Done() _, _ = a.PWMPin(pin) }(pinAsString) } wg.Wait() } } ================================================ FILE: platforms/adaptors/pwmpinsadaptoroptions.go ================================================ package adaptors import "time" // PwmPinsOptionApplier needs to be implemented by each configurable option type type PwmPinsOptionApplier interface { apply(cfg *pwmPinsConfiguration) } // pwmPinsDebugOption is the type to switch on PWM pins related debug messages. type pwmPinsDebugOption bool // pwmPinInitializeOption is the type for applying another than the default initializer. type pwmPinsInitializeOption pwmPinInitializer // pwmPinsUsePiBlasterPinOption is the type for applying the usage of the pi-blaster PWM pin implementation, which will // replace the default sysfs-implementation for PWM-pins. type pwmPinsUsePiBlasterPinOption bool // pwmPinPeriodDefaultOption is the type for applying another than the default period of 10 ms (100 Hz) for all // created pins. type pwmPinsPeriodDefaultOption uint32 // pwmPinsPeriodMinimumOption is the type for applying another than the default minimum period of "0". type pwmPinsPeriodMinimumOption uint32 // pwmPinsDutyRateMinimumOption is the type for applying another than the default minimum rate of 1/period. type pwmPinsDutyRateMinimumOption float64 // pwmPinPolarityInvertedIdentifierOption is the type for applying another identifier, which will replace the default // "inversed". type pwmPinsPolarityInvertedIdentifierOption string // pwmPinsAdjustDutyOnSetPeriodOption is the type for applying the automatic adjustment of duty cycle on setting // the period to on/off. type pwmPinsAdjustDutyOnSetPeriodOption bool // pwmPinsDefaultPeriodForPinOption is the type for applying another than the default period of 10 ms (100 Hz) only for // the given pin id. type pwmPinsDefaultPeriodForPinOption struct { id string period uint32 } // pwmPinsServoDutyScaleForPinOption is the type for applying another than the default 0.5-2.5 ms range of duty cycle // for servo calls on the specified pin id. type pwmPinsServoDutyScaleForPinOption struct { id string min time.Duration max time.Duration } // pwmPinsServoAngleScaleForPinOption is the type for applying another than the default 0.0-180.0° range of angle for // servo calls on the specified pin id. type pwmPinsServoAngleScaleForPinOption struct { id string minDegree float64 maxDegree float64 } func (o pwmPinsDebugOption) String() string { return "switch on debugging for pwm pins option" } func (o pwmPinsInitializeOption) String() string { return "pin initializer option for PWM's" } func (o pwmPinsUsePiBlasterPinOption) String() string { return "pi-blaster pin implementation option for PWM's" } func (o pwmPinsPeriodDefaultOption) String() string { return "default period option for PWM's" } func (o pwmPinsPeriodMinimumOption) String() string { return "minimum period option for PWM's" } func (o pwmPinsDutyRateMinimumOption) String() string { return "minimum duty rate option for PWM's" } func (o pwmPinsPolarityInvertedIdentifierOption) String() string { return "identifier for 'inversed' option for PWM's" } func (o pwmPinsAdjustDutyOnSetPeriodOption) String() string { return "adjust duty cycle on set period option for PWM's" } func (o pwmPinsDefaultPeriodForPinOption) String() string { return "default period for the pin option for PWM's" } func (o pwmPinsServoDutyScaleForPinOption) String() string { return "duty cycle min-max range for a servo pin option for PWM's" } func (o pwmPinsServoAngleScaleForPinOption) String() string { return "angle min-max range for a servo pin option for PWM's" } func (o pwmPinsDebugOption) apply(cfg *pwmPinsConfiguration) { cfg.debug = bool(o) } func (o pwmPinsInitializeOption) apply(cfg *pwmPinsConfiguration) { cfg.initialize = pwmPinInitializer(o) } func (o pwmPinsUsePiBlasterPinOption) apply(cfg *pwmPinsConfiguration) { cfg.usePiBlasterPin = bool(o) } func (o pwmPinsPeriodDefaultOption) apply(cfg *pwmPinsConfiguration) { cfg.periodDefault = uint32(o) } func (o pwmPinsPeriodMinimumOption) apply(cfg *pwmPinsConfiguration) { cfg.periodMinimum = uint32(o) } func (o pwmPinsDutyRateMinimumOption) apply(cfg *pwmPinsConfiguration) { cfg.dutyRateMinimum = float64(o) } func (o pwmPinsPolarityInvertedIdentifierOption) apply(cfg *pwmPinsConfiguration) { cfg.polarityInvertedIdentifier = string(o) } func (o pwmPinsAdjustDutyOnSetPeriodOption) apply(cfg *pwmPinsConfiguration) { cfg.adjustDutyOnSetPeriod = bool(o) } func (o pwmPinsDefaultPeriodForPinOption) apply(cfg *pwmPinsConfiguration) { cfg.pinsDefaultPeriod[o.id] = o.period } func (o pwmPinsServoDutyScaleForPinOption) apply(cfg *pwmPinsConfiguration) { scale, ok := cfg.pinsServoScale[o.id] if !ok { scale = pwmPinServoScale{minDegree: 0, maxDegree: 180} } scale.minDuty = o.min scale.maxDuty = o.max cfg.pinsServoScale[o.id] = scale } func (o pwmPinsServoAngleScaleForPinOption) apply(cfg *pwmPinsConfiguration) { scale, ok := cfg.pinsServoScale[o.id] if !ok { scale = pwmPinServoScale{} // default values for duty cycle will be set on initialize, if zero } scale.minDegree = o.minDegree scale.maxDegree = o.maxDegree cfg.pinsServoScale[o.id] = scale } ================================================ FILE: platforms/adaptors/pwmpinsadaptoroptions_test.go ================================================ //nolint:nonamedreturns // ok for tests package adaptors import ( "fmt" "testing" "github.com/stretchr/testify/assert" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/system" ) func TestWithPWMPinInitializer(t *testing.T) { // This is a general test, that options are applied by using the WithPWMPinInitializer() option. // All other configuration options can also be tested by With..(val).apply(cfg). // arrange wantErr := fmt.Errorf("new_initializer") newInitializer := func(string, gobot.PWMPinner) error { return wantErr } // act a := NewPWMPinsAdaptor(system.NewAccesser(), func(pin string) (c string, l int, e error) { return }, WithPWMPinInitializer(newInitializer)) // assert err := a.pwmPinsCfg.initialize("1", nil) assert.Equal(t, wantErr, err) } func TestWithPWMPinDebug(t *testing.T) { // arrange cfg := &pwmPinsConfiguration{debug: false} // act WithPWMPinDebug().apply(cfg) // assert assert.True(t, cfg.debug) } func TestWithPWMUsePiBlaster(t *testing.T) { // arrange cfg := &pwmPinsConfiguration{usePiBlasterPin: false} // act WithPWMUsePiBlaster().apply(cfg) // assert assert.True(t, cfg.usePiBlasterPin) } func TestWithPWMDefaultPeriod(t *testing.T) { // arrange const newPeriod = uint32(10) cfg := &pwmPinsConfiguration{periodDefault: 123} // act WithPWMDefaultPeriod(newPeriod).apply(cfg) // assert assert.Equal(t, newPeriod, cfg.periodDefault) } func TestWithPWMMinimumPeriod(t *testing.T) { // arrange const newMinPeriod = uint32(10) cfg := &pwmPinsConfiguration{periodMinimum: 23} // act WithPWMMinimumPeriod(newMinPeriod).apply(cfg) // assert assert.Equal(t, newMinPeriod, cfg.periodMinimum) } func TestWithPWMMinimumDutyRate(t *testing.T) { // arrange const newRate = 11.0 cfg := &pwmPinsConfiguration{dutyRateMinimum: 33} // act WithPWMMinimumDutyRate(newRate).apply(cfg) // assert assert.InDelta(t, newRate, cfg.dutyRateMinimum, 0.0) } func TestWithPWMPolarityInvertedIdentifier(t *testing.T) { // arrange const newPolarityIdent = "pwm_invers" cfg := &pwmPinsConfiguration{polarityInvertedIdentifier: "old_inverted"} // act WithPWMPolarityInvertedIdentifier(newPolarityIdent).apply(cfg) // assert assert.Equal(t, newPolarityIdent, cfg.polarityInvertedIdentifier) } func TestWithPWMNoDutyCycleAdjustment(t *testing.T) { // arrange cfg := &pwmPinsConfiguration{adjustDutyOnSetPeriod: true} // act WithPWMNoDutyCycleAdjustment().apply(cfg) // assert assert.False(t, cfg.adjustDutyOnSetPeriod) } func TestWithPWMDefaultPeriodForPin(t *testing.T) { // arrange const ( pin = "pin4test" newPeriod = 123456 ) cfg := &pwmPinsConfiguration{pinsDefaultPeriod: map[string]uint32{pin: 54321}} // act WithPWMDefaultPeriodForPin(pin, newPeriod).apply(cfg) // assert assert.Equal(t, uint32(newPeriod), cfg.pinsDefaultPeriod[pin]) } func TestWithPWMServoDutyCycleRangeForPin(t *testing.T) { const ( pin = "pin4test" newMin = 19 newMax = 99 ) tests := map[string]struct { scaleMap map[string]pwmPinServoScale wantScaleMap map[string]pwmPinServoScale }{ "empty_scale_map": { scaleMap: make(map[string]pwmPinServoScale), wantScaleMap: map[string]pwmPinServoScale{ pin: {minDuty: newMin, maxDuty: newMax, minDegree: 0, maxDegree: 180}, }, }, "scale_exists_for_set_pin": { scaleMap: map[string]pwmPinServoScale{ "other": {minDuty: 123, maxDuty: 234, minDegree: 11, maxDegree: 22}, pin: {minDuty: newMin - 2, maxDuty: newMax + 2, minDegree: 1, maxDegree: 2}, }, wantScaleMap: map[string]pwmPinServoScale{ "other": {minDuty: 123, maxDuty: 234, minDegree: 11, maxDegree: 22}, pin: {minDuty: newMin, maxDuty: newMax, minDegree: 1, maxDegree: 2}, }, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange cfg := &pwmPinsConfiguration{pinsServoScale: tc.scaleMap} // act WithPWMServoDutyCycleRangeForPin(pin, newMin, newMax).apply(cfg) // assert assert.Equal(t, tc.wantScaleMap, cfg.pinsServoScale) }) } } func TestWithPWMServoAngleRangeForPin(t *testing.T) { const ( pin = "pin4test" newMin = 30 newMax = 90 ) tests := map[string]struct { scaleMap map[string]pwmPinServoScale wantScaleMap map[string]pwmPinServoScale }{ "empty_scale_map": { scaleMap: make(map[string]pwmPinServoScale), wantScaleMap: map[string]pwmPinServoScale{ pin: {minDuty: 0.0, maxDuty: 0.0, minDegree: newMin, maxDegree: newMax}, }, }, "scale_exists_for_set_pin": { scaleMap: map[string]pwmPinServoScale{ "other": {minDuty: 123, maxDuty: 234, minDegree: 11, maxDegree: 22}, pin: {minDuty: 4, maxDuty: 5, minDegree: newMin - 2, maxDegree: newMax + 2}, }, wantScaleMap: map[string]pwmPinServoScale{ "other": {minDuty: 123, maxDuty: 234, minDegree: 11, maxDegree: 22}, pin: {minDuty: 4, maxDuty: 5, minDegree: newMin, maxDegree: newMax}, }, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange cfg := &pwmPinsConfiguration{pinsServoScale: tc.scaleMap} // act WithPWMServoAngleRangeForPin(pin, newMin, newMax).apply(cfg) // assert assert.Equal(t, tc.wantScaleMap, cfg.pinsServoScale) }) } } func TestStringer(t *testing.T) { assert.NotEmpty(t, pwmPinsInitializeOption(nil).String()) assert.NotEmpty(t, pwmPinsUsePiBlasterPinOption(true).String()) assert.NotEmpty(t, pwmPinsPeriodDefaultOption(1).String()) assert.NotEmpty(t, pwmPinsPeriodMinimumOption(1).String()) assert.NotEmpty(t, pwmPinsDutyRateMinimumOption(1).String()) assert.NotEmpty(t, pwmPinsPolarityInvertedIdentifierOption("1").String()) assert.NotEmpty(t, pwmPinsAdjustDutyOnSetPeriodOption(true).String()) assert.NotEmpty(t, pwmPinsDefaultPeriodForPinOption{}.String()) assert.NotEmpty(t, pwmPinsServoDutyScaleForPinOption{}.String()) assert.NotEmpty(t, pwmPinsServoAngleScaleForPinOption{}.String()) } ================================================ FILE: platforms/adaptors/pwmpintranslator.go ================================================ package adaptors import ( "fmt" "gobot.io/x/gobot/v2/system" ) type PWMPinDefinition struct { Dir string DirRegexp string Channel int } type PWMPinDefinitions map[string]PWMPinDefinition type PWMPinTranslator struct { sys *system.Accesser pinDefinitions PWMPinDefinitions } // NewPWMPinTranslator creates a new instance of a PWM pin translator, suitable for the most cases. func NewPWMPinTranslator(sys *system.Accesser, pinDefinitions PWMPinDefinitions) *PWMPinTranslator { return &PWMPinTranslator{sys: sys, pinDefinitions: pinDefinitions} } // Translate returns the sysfs path and channel for the given id. func (pt *PWMPinTranslator) Translate(id string) (string, int, error) { pinInfo, ok := pt.pinDefinitions[id] if !ok { return "", -1, fmt.Errorf("'%s' is not a valid id for a PWM pin", id) } path, err := pinInfo.FindPWMDir(pt.sys) if err != nil { return "", -1, err } return path, pinInfo.Channel, nil } func (p PWMPinDefinition) FindPWMDir(sys *system.Accesser) (string, error) { items, _ := sys.Find(p.Dir, p.DirRegexp) if len(items) == 0 { return "", fmt.Errorf("no path found for PWM directory pattern, '%s' in path '%s'. See README.md for activation", p.DirRegexp, p.Dir) } dir := items[0] info, err := sys.Stat(dir) if err != nil { return "", fmt.Errorf("error (%v) on access '%s'", err, dir) } if !info.IsDir() { return "", fmt.Errorf("the item '%s' is not a directory, which is not expected", dir) } return dir, nil } ================================================ FILE: platforms/adaptors/pwmpintranslator_test.go ================================================ package adaptors import ( "fmt" "testing" "github.com/stretchr/testify/assert" "gobot.io/x/gobot/v2/system" ) func TestNewPWMPinTranslator(t *testing.T) { // arrange sys := &system.Accesser{} pinDef := PWMPinDefinitions{} // act pt := NewPWMPinTranslator(sys, pinDef) // assert assert.IsType(t, &PWMPinTranslator{}, pt) assert.Equal(t, sys, pt.sys) assert.Equal(t, pinDef, pt.pinDefinitions) } func TestPWMPinTranslatorTranslate(t *testing.T) { pinDefinitions := PWMPinDefinitions{ "33": {Dir: "/sys/devices/platform/ff680020.pwm/pwm/", DirRegexp: "pwmchip[0|1|2]$", Channel: 0}, "32": {Dir: "/sys/devices/platform/ff680030.pwm/pwm/", DirRegexp: "pwmchip[0|1|2|3]$", Channel: 0}, } basePaths := []string{ "/sys/devices/platform/ff680020.pwm/pwm/", "/sys/devices/platform/ff680030.pwm/pwm/", } tests := map[string]struct { pin string chip string wantDir string wantChannel int wantErr error }{ "32_chip0": { pin: "32", chip: "pwmchip0", wantDir: "/sys/devices/platform/ff680030.pwm/pwm/pwmchip0", wantChannel: 0, }, "32_chip1": { pin: "32", chip: "pwmchip1", wantDir: "/sys/devices/platform/ff680030.pwm/pwm/pwmchip1", wantChannel: 0, }, "32_chip2": { pin: "32", chip: "pwmchip2", wantDir: "/sys/devices/platform/ff680030.pwm/pwm/pwmchip2", wantChannel: 0, }, "32_chip3": { pin: "32", chip: "pwmchip3", wantDir: "/sys/devices/platform/ff680030.pwm/pwm/pwmchip3", wantChannel: 0, }, "33_chip0": { pin: "33", chip: "pwmchip0", wantDir: "/sys/devices/platform/ff680020.pwm/pwm/pwmchip0", wantChannel: 0, }, "33_chip1": { pin: "33", chip: "pwmchip1", wantDir: "/sys/devices/platform/ff680020.pwm/pwm/pwmchip1", wantChannel: 0, }, "33_chip2": { pin: "33", chip: "pwmchip2", wantDir: "/sys/devices/platform/ff680020.pwm/pwm/pwmchip2", wantChannel: 0, }, "invalid_pin": { pin: "7", wantDir: "", wantChannel: -1, wantErr: fmt.Errorf("'7' is not a valid id for a PWM pin"), }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange mockedPaths := []string{} for _, base := range basePaths { mockedPaths = append(mockedPaths, base+tc.chip+"/") } sys := system.NewAccesser() _ = sys.UseMockFilesystem(mockedPaths) pt := NewPWMPinTranslator(sys, pinDefinitions) // act dir, channel, err := pt.Translate(tc.pin) // assert assert.Equal(t, tc.wantErr, err) assert.Equal(t, tc.wantDir, dir) assert.Equal(t, tc.wantChannel, channel) }) } } ================================================ FILE: platforms/adaptors/spibusadaptor.go ================================================ package adaptors import ( "fmt" "sync" multierror "github.com/hashicorp/go-multierror" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/spi" "gobot.io/x/gobot/v2/system" ) type spiBusNumberValidator func(busNumber int) error // spiBusConfiguration contains all changeable attributes of the adaptor. type spiBusConfiguration struct { debug bool spiGpioPinnerProvider gobot.DigitalPinnerProvider systemOptions []system.AccesserOptionApplier } // SpiBusAdaptor is a adaptor for SPI bus, normally used for composition in platforms. type SpiBusAdaptor struct { sys *system.Accesser validateBusNumber spiBusNumberValidator defaultBusNumber int defaultChipNumber int defaultMode int defaultBitCount int defaultMaxSpeed int64 // Hz spiBusCfg *spiBusConfiguration mutex sync.Mutex connections map[string]spi.Connection } // NewSpiBusAdaptor provides the access to SPI buses of the board. The validator is used to check the // bus number (given by user) to the abilities of the board. // // Options: // // "WithSpiDebug" // "WithSpiGpioAccess" func NewSpiBusAdaptor( sys *system.Accesser, v spiBusNumberValidator, busNum, chipNum, mode, bits int, maxSpeed int64, spiGpioPinnerProvider gobot.DigitalPinnerProvider, opts ...SpiBusOptionApplier, ) *SpiBusAdaptor { a := SpiBusAdaptor{ sys: sys, validateBusNumber: v, defaultBusNumber: busNum, defaultChipNumber: chipNum, defaultMode: mode, defaultBitCount: bits, defaultMaxSpeed: maxSpeed, spiBusCfg: &spiBusConfiguration{spiGpioPinnerProvider: spiGpioPinnerProvider}, } for _, o := range opts { o.apply(a.spiBusCfg) } sys.AddSPISupport(a.spiBusCfg.systemOptions...) return &a } // WithSpiDebug can be used to switch on debugging for SPI implementation. func WithSpiDebug() spiBusDebugOption { return spiBusDebugOption(true) } // WithSpiGpioAccess can be used to switch the default SPI implementation to GPIO usage. func WithSpiGpioAccess(sclkPin, ncsPin, sdoPin, sdiPin string) spiBusDigitalPinsForSystemSpiOption { o := spiBusDigitalPinsForSystemSpiOption{ sclkPin: sclkPin, ncsPin: ncsPin, sdoPin: sdoPin, sdiPin: sdiPin, } return o } // Connect prepares the connection to SPI buses. func (a *SpiBusAdaptor) Connect() error { a.mutex.Lock() defer a.mutex.Unlock() if a.connections != nil { return fmt.Errorf("SPI bus adaptor already connected, please call Finalize() for re-connect") } a.connections = make(map[string]spi.Connection) a.debuglnf("connect the SPI bus adaptor done") return nil } // Finalize closes all SPI connections. func (a *SpiBusAdaptor) Finalize() error { a.mutex.Lock() defer a.mutex.Unlock() a.debuglnf("finalize the SPI bus adaptor for %d buses...", len(a.connections)) var err error for id, con := range a.connections { if con != nil { e := con.Close() if e != nil { err = multierror.Append(err, e) } a.debuglnf("SPI bus '%s' closed with error: %v", id, e) } } a.connections = nil a.debuglnf("finalize the SPI bus adaptor done with error: %v", err) return err } // GetSpiConnection returns an spi connection to a device on a specified bus. // Valid bus numbers range between 0 and 65536, valid chip numbers are 0 ... 255. func (a *SpiBusAdaptor) GetSpiConnection(busNum, chipNum, mode, bits int, maxSpeed int64) (spi.Connection, error) { a.mutex.Lock() defer a.mutex.Unlock() a.debuglnf("get SPI connection") if a.connections == nil { return nil, fmt.Errorf("not connected") } id := fmt.Sprintf("%d_%d", busNum, chipNum) con := a.connections[id] if con == nil { if err := a.validateBusNumber(busNum); err != nil { return nil, err } var err error bus, err := a.sys.NewSpiDevice(busNum, chipNum, mode, bits, maxSpeed) if err != nil { return nil, err } con = spi.NewConnection(bus) a.connections[id] = con } return con, nil } // SpiDefaultBusNumber returns the default bus number for this platform. func (a *SpiBusAdaptor) SpiDefaultBusNumber() int { return a.defaultBusNumber } // SpiDefaultChipNumber returns the default chip number for this platform. func (a *SpiBusAdaptor) SpiDefaultChipNumber() int { return a.defaultChipNumber } // SpiDefaultMode returns the default SPI mode for this platform. func (a *SpiBusAdaptor) SpiDefaultMode() int { return a.defaultMode } // SpiDefaultBitCount returns the default number of bits used for this platform. func (a *SpiBusAdaptor) SpiDefaultBitCount() int { return a.defaultBitCount } // SpiDefaultMaxSpeed returns the default maximal speed for this platform. func (a *SpiBusAdaptor) SpiDefaultMaxSpeed() int64 { return a.defaultMaxSpeed } func (a *SpiBusAdaptor) debuglnf(format string, p ...interface{}) { gobot.Debuglnf(a.spiBusCfg.debug, format, p...) } ================================================ FILE: platforms/adaptors/spibusadaptor_test.go ================================================ package adaptors import ( "fmt" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2/drivers/spi" "gobot.io/x/gobot/v2/system" ) // make sure that this SpiBusAdaptor fulfills all the required interfaces var _ spi.Connector = (*SpiBusAdaptor)(nil) const spiTestAllowedBus = 15 func initTestSpiBusAdaptorWithMockedSpi() (*SpiBusAdaptor, *system.MockSpiAccess) { validator := func(busNr int) error { if busNr != spiTestAllowedBus { return fmt.Errorf("%d not valid", busNr) } return nil } sys := system.NewAccesser() // arrange for periphio needed sys.UseMockFilesystem([]string{"/dev/spidev"}) dpa := sys.UseMockDigitalPinAccess() a := NewSpiBusAdaptor(sys, validator, 1, 2, 3, 4, 5, dpa) spi := a.sys.UseMockSpi() if err := a.Connect(); err != nil { panic(err) } return a, spi } func TestNewSpiAdaptor(t *testing.T) { // arrange sys := system.NewAccesser() // arrange for periphio needed sys.UseMockFilesystem([]string{"/dev/spidev"}) dpa := sys.UseMockDigitalPinAccess() a := NewSpiBusAdaptor(sys, nil, 1, 2, 3, 4, 5, dpa) // act & assert assert.Equal(t, 1, a.SpiDefaultBusNumber()) assert.Equal(t, 2, a.SpiDefaultChipNumber()) assert.Equal(t, 3, a.SpiDefaultMode()) assert.Equal(t, 4, a.SpiDefaultBitCount()) assert.Equal(t, int64(5), a.SpiDefaultMaxSpeed()) _, err := a.GetSpiConnection(10, 0, 0, 8, 10000000) require.ErrorContains(t, err, "not connected") } func TestGetSpiConnection(t *testing.T) { // arrange const ( busNum = spiTestAllowedBus chipNum = 14 mode = 13 bits = 12 maxSpeed = int64(11) ) a, spi := initTestSpiBusAdaptorWithMockedSpi() assert.Empty(t, a.connections) // act con1, err1 := a.GetSpiConnection(busNum, chipNum, mode, bits, maxSpeed) // assert require.NoError(t, err1) assert.NotNil(t, con1) assert.Len(t, a.connections, 1) // assert cached connection con1a, err2 := a.GetSpiConnection(busNum, chipNum, mode, bits, maxSpeed) require.NoError(t, err2) assert.Equal(t, con1, con1a) assert.Len(t, a.connections, 1) // assert second connection con2, err3 := a.GetSpiConnection(busNum, chipNum+1, mode, bits, maxSpeed) require.NoError(t, err3) assert.NotNil(t, con2) assert.NotEqual(t, con1, con2) assert.Len(t, a.connections, 2) // assert bus validation error con, err := a.GetSpiConnection(busNum+1, chipNum, mode, bits, maxSpeed) require.ErrorContains(t, err, "16 not valid") assert.Nil(t, con) // assert create error spi.CreateError = true con, err = a.GetSpiConnection(busNum, chipNum+2, mode, bits, maxSpeed) require.ErrorContains(t, err, "error while create SPI connection in mock") assert.Nil(t, con) } func TestSpiFinalize(t *testing.T) { // arrange a, _ := initTestSpiBusAdaptorWithMockedSpi() _, e := a.GetSpiConnection(spiTestAllowedBus, 2, 3, 4, 5) require.NoError(t, e) assert.Len(t, a.connections, 1) // act err := a.Finalize() // assert require.NoError(t, err) assert.Empty(t, a.connections) } func TestSpiFinalizeWithError(t *testing.T) { // arrange a, spi := initTestSpiBusAdaptorWithMockedSpi() _, e := a.GetSpiConnection(spiTestAllowedBus, 2, 3, 4, 5) require.NoError(t, e) spi.SetCloseError(true) // act err := a.Finalize() // assert require.ErrorContains(t, err, "error while SPI close") } func TestSpiReConnect(t *testing.T) { // arrange a, _ := initTestSpiBusAdaptorWithMockedSpi() require.NoError(t, a.Finalize()) // act require.NoError(t, a.Connect()) // assert assert.NotNil(t, a.connections) assert.Empty(t, a.connections) } ================================================ FILE: platforms/adaptors/spibusadaptoroptions.go ================================================ package adaptors import "gobot.io/x/gobot/v2/system" // SpiBusOptionApplier is the interface for spi bus adaptor options. This provides the possibility for change the // platform behavior by the user when creating the platform, e.g. by "NewAdaptor()". // The interface needs to be implemented by each configurable option type. type SpiBusOptionApplier interface { apply(cfg *spiBusConfiguration) } // spiBusDebugOption is the type to switch on SPI related debug messages. type spiBusDebugOption bool // spiBusDigitalPinsForSystemSpiOption is the type to switch the default SPI implementation to GPIO usage type spiBusDigitalPinsForSystemSpiOption struct { sclkPin string ncsPin string sdoPin string sdiPin string } func (o spiBusDebugOption) String() string { return "switch on debugging for SPI option" } func (o spiBusDigitalPinsForSystemSpiOption) String() string { return "use digital pins for SPI option" } func (o spiBusDebugOption) apply(cfg *spiBusConfiguration) { cfg.debug = bool(o) cfg.systemOptions = append(cfg.systemOptions, system.WithSpiDebug()) } func (o spiBusDigitalPinsForSystemSpiOption) apply(cfg *spiBusConfiguration) { cfg.systemOptions = append(cfg.systemOptions, system.WithSpiGpioAccess(cfg.spiGpioPinnerProvider, o.sclkPin, o.ncsPin, o.sdoPin, o.sdiPin)) } ================================================ FILE: platforms/adaptors/spibusadaptoroptions_test.go ================================================ package adaptors import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2/system" ) func TestNewSpiBusAdaptorWithSpiGpioAccess(t *testing.T) { // arrange const ( sclkPin = "1" ncsPin = "2" sdoPin = "3" sdiPin = "4" sclkPinTranslated = "1" ncsPinTranslated = "2" sdoPinTranslated = "3" sdiPinTranslated = "4" ) sys := system.NewAccesser() dpa := sys.UseMockDigitalPinAccess() a := NewSpiBusAdaptor(sys, nil, 1, 2, 3, 4, 5, dpa, WithSpiGpioAccess(sclkPin, ncsPin, sdoPin, sdiPin)) // act require.NoError(t, a.Connect()) bus, err := a.sys.NewSpiDevice(0, 0, 0, 0, 1111) // assert require.NoError(t, err) assert.NotNil(t, bus) assert.True(t, a.sys.HasSpiGpioAccess()) assert.Equal(t, 1, dpa.AppliedOptions("", sclkPinTranslated)) assert.Equal(t, 1, dpa.AppliedOptions("", ncsPinTranslated)) assert.Equal(t, 1, dpa.AppliedOptions("", sdoPinTranslated)) assert.Equal(t, 0, dpa.AppliedOptions("", sdiPinTranslated)) // already input, so no option applied } func TestWithSpiDebug(t *testing.T) { // arrange cfg := &spiBusConfiguration{debug: false} // act WithSpiDebug().apply(cfg) // assert assert.True(t, cfg.debug) } ================================================ FILE: platforms/asus/tinkerboard/LICENSE ================================================ Copyright (c) 2014-2018 The Hybrid Group Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: platforms/asus/tinkerboard/README.md ================================================ # Tinker Board The ASUS Tinker Board is a single board SoC computer based on the Rockchip RK3288 processor. It has built-in GPIO, PWM, SPI, and I2C interfaces. For more info about the Tinker Board, go to [https://www.asus.com/uk/Single-Board-Computer/Tinker-Board/](https://www.asus.com/uk/Single-Board-Computer/Tinker-Board/). ## How to Install Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) Tested OS: * [Debian TinkerOS](https://github.com/TinkerBoard/debian_kernel/releases) * [armbian](https://www.armbian.com/tinkerboard/) with Debian or Ubuntu > The latest "Tinker Board Debian 10 V3.0.11" is official discontinued. Nevertheless it is tested with gobot. There > is a known i2c issue with the Kernel 4.4.194 if using block reads. armbian is known to work in this area. We recommend > to use "armbian bookworm minimal", because it is used for the latest development steps of gobot. ## Configuration steps for the OS ### System access and configuration basics Some configuration steps are needed to enable drivers and simplify the interaction with your Tinker Board. Once your Tinker Board has been configured, you do not need to do so again. Note that these configuration steps must be performed on the Tinker Board itself. The easiest is to login to the Tinker Board via SSH (option "-4" is used to force IPv4, which is needed for some versions of TinkerOS): ```sh ssh -4 @192.168.1.xxx # linaro@192.168.1.xxx ``` ### Enabling hardware drivers Not all drivers are enabled by default. You can have a look at the configuration file, to find out what is enabled at your system: ```sh cat /boot/armbianEnv.txt #/boot/config.txt ``` This file can be modified by "vi" or "nano", it is self explanatory: ```sh sudo vi /boot/armbianEnv.txt ``` Newer versions of OS provide an user interface for configuration with: ```sh sudo apt install armbian-config sudo armbian-config # tinker-config ``` After configuration was changed, an reboot is necessary. ```sh sudo reboot ``` ### Enabling GPIO pins #### Create a group "gpio" Create a Linux group named "gpio" by running the following command: ```sh sudo groupadd -f --system gpio ``` If you already have a "gpio" group, you can skip to the next step. #### Add the user to the new "gpio" group (TinkerOS only) Add the user to be a member of the Linux group named "gpio" by running the following command: ```sh sudo usermod -a -G gpio ``` If you already have added the "gpio" group, you can skip to the next step. #### Add a "udev" rules file for gpio (TinkerOS only) Create a new "udev" rules file for the GPIO on the Tinker Board by running the following command: ```sh sudo vi /etc/udev/rules.d/91-gpio.rules ``` And add the following contents to the file: ```txt SUBSYSTEM=="gpio", KERNEL=="gpiochip*", ACTION=="add", PROGRAM="/bin/sh -c 'chown root:gpio /sys/class/gpio/export /sys/class/gpio/unexport ; chmod 220 /sys/class/gpio/export /sys/class/gpio/unexport'" SUBSYSTEM=="gpio", KERNEL=="gpio*", ACTION=="add", PROGRAM="/bin/sh -c 'chown root:gpio /sys%p/active_low /sys%p/direction /sys%p/edge /sys%p/value ; chmod 660 /sys%p/active_low /sys%p/direction /sys%p/edge /sys%p/value'" ``` Press the "Esc" key, then press the ":" key and then the "q" key, and then press the "Enter" key. This should save your file. After rebooting your Tinker Board, you should be able to run your Gobot code that uses GPIO. ### Enabling I2C #### Create a group "i2c" If you already have a "i2c" group, you can skip to the next step. Create a Linux group named "i2c" by running the following command: ```sh sudo groupadd -f --system i2c ``` #### Add the user to the new "i2c" group If you already have added the "i2c" group, you can skip to the next step. Add the user to be a member of the Linux group named "i2c" by running the following command: ```sh sudo usermod -a -G gpio ``` #### Add a "udev" rules file for I2C (TinkerOS only) Create a new "udev" rules file for the I2C on the Tinker Board by running the following command: ```sh sudo vi /etc/udev/rules.d/92-i2c.rules ``` And add the following contents to the file: ```txt KERNEL=="i2c-0" , GROUP="i2c", MODE="0660" KERNEL=="i2c-[1-9]*", GROUP="i2c", MODE="0666" ``` Press the "Esc" key, then press the ":" key and then the "q" key, and then press the "Enter" key. This should save your file. After rebooting your Tinker Board, you should be able to run your Gobot code that uses I2C. ## How to Use The pin numbering used by your Gobot program should match the way your board is labeled right on the board itself. ```go r := tinkerboard.NewAdaptor() led := gpio.NewLedDriver(r, "7") ``` ## How to Connect ### Compiling Compile your Gobot program on your workstation like this: ```sh GOARM=7 GOARCH=arm GOOS=linux go build examples/tinkerboard_blink.go ``` Once you have compiled your code, you can upload your program and execute it on the Tinkerboard from your workstation using the `scp` and `ssh` commands like this: ```sh scp tinkerboard_blink @192.168.1.xxx:/home// ssh -t @192.168.1.xxx "./tinkerboard_blink" ``` ## Troubleshooting ### PWM #### Investigate state ```sh # ls -la /sys/class/pwm/ total 0 drwxr-xr-x 2 root root 0 Apr 24 14:11 . drwxr-xr-x 66 root root 0 Apr 24 14:09 .. lrwxrwxrwx 1 root root 0 Apr 24 14:09 pwmchip0 -> ../../devices/platform/ff680000.pwm/pwm/pwmchip0 ``` looking for one of the following items in the path: ff680000 => internally, not usable ff680010 => internally, not usable ff680020 => pwm2, pin33 ff680030 => pwm3, pin32 #### Activate When there is no pwm2, pwm3, this can be activated. Open the file /boot/config.txt and add lines/remove comment sign and adjust: intf:pwm2=on intf:pwm3=on Then save the file, close and reboot. After reboot check the state: ```sh # ls -la /sys/class/pwm/ total 0 drwxr-xr-x 2 root root 0 Apr 24 14:11 . drwxr-xr-x 66 root root 0 Apr 24 14:09 .. lrwxrwxrwx 1 root root 0 Apr 24 14:09 pwmchip0 -> ../../devices/platform/ff680000.pwm/pwm/pwmchip0 lrwxrwxrwx 1 root root 0 Apr 24 14:09 pwmchip1 -> ../../devices/platform/ff680010.pwm/pwm/pwmchip1 lrwxrwxrwx 1 root root 0 Apr 24 14:09 pwmchip2 -> ../../devices/platform/ff680030.pwm/pwm/pwmchip2 ``` #### Test For example only pwm3 was activated to use pin32. Connect an oscilloscope or at least a meter to the pin 32. switch to root user by "su -" investigate state: ```sh # ls -la /sys/class/pwm/pwmchip2/ total 0 drwxr-xr-x 3 root root 0 Apr 24 14:17 . drwxr-xr-x 3 root root 0 Apr 24 14:17 .. lrwxrwxrwx 1 root root 0 Apr 24 14:17 device -> ../../../ff680030.pwm --w------- 1 root root 4096 Apr 24 14:17 export -r--r--r-- 1 root root 4096 Apr 24 14:17 npwm drwxr-xr-x 2 root root 0 Apr 24 14:17 power lrwxrwxrwx 1 root root 0 Apr 24 14:17 subsystem -> ../../../../../class/pwm -rw-r--r-- 1 root root 4096 Apr 24 14:17 uevent --w------- 1 root root 4096 Apr 24 14:17 unexport ``` #### Creating pwm0 `echo 0 > /sys/class/pwm/pwmchip2/export` investigate result: ```sh # ls /sys/class/pwm/pwmchip2/ device export npwm power pwm0 subsystem uevent unexport # ls /sys/class/pwm/pwmchip2/pwm0/ capture duty_cycle enable period polarity power uevent # cat /sys/class/pwm/pwmchip2/pwm0/period 0 # cat /sys/class/pwm/pwmchip2/pwm0/duty_cycle 0 # cat /sys/class/pwm/pwmchip2/pwm0/enable 0 # cat /sys/class/pwm/pwmchip2/pwm0/polarity inversed ``` #### Initialization Note: Before writing the period all other write actions will cause an error "-bash: echo: write error: Invalid argument" ```sh echo 10000000 > /sys/class/pwm/pwmchip2/pwm0/period # this is a frequency divider for 1GHz (1000 will produce a frequency of 1MHz, 1000000 will cause a frequency of 1kHz, her we got 100Hz) echo "normal" > /sys/class/pwm/pwmchip2/pwm0/polarity echo 3000000 > /sys/class/pwm/pwmchip2/pwm0/duty_cycle # this means 30% echo 1 > /sys/class/pwm/pwmchip2/pwm0/enable ``` Now we should measure a value of around 1V with the meter, because the basis value is 3.3V and 30% leads to 1V. Try to inverse the sequence: `echo "inversed" > /sys/class/pwm/pwmchip2/pwm0/polarity` Now we should measure a value of around 2.3V with the meter, which is the difference of 1V to 3.3V. If we have attached an oscilloscope we can play around with the values for period and duty_cycle and see what happen. ================================================ FILE: platforms/asus/tinkerboard/adaptor.go ================================================ package tinkerboard import ( "fmt" "sync" multierror "github.com/hashicorp/go-multierror" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/adaptors" "gobot.io/x/gobot/v2/system" ) const ( defaultI2cBusNumber = 1 defaultSpiBusNumber = 0 defaultSpiChipNumber = 0 defaultSpiMode = 0 defaultSpiBitsNumber = 8 defaultSpiMaxSpeed = 500000 ) // Adaptor represents a Gobot Adaptor for the ASUS Tinker Board type Adaptor struct { *adaptors.AnalogPinsAdaptor *adaptors.DigitalPinsAdaptor *adaptors.PWMPinsAdaptor *adaptors.I2cBusAdaptor *adaptors.SpiBusAdaptor *adaptors.OneWireBusAdaptor name string sys *system.Accesser // used for unit tests only mutex *sync.Mutex } // NewAdaptor creates a Tinkerboard Adaptor // // Optional parameters: // // adaptors.WithGpioSysfsAccess(): use legacy sysfs driver instead of default character device driver // adaptors.WithSpiGpioAccess(sclk, ncs, sdo, sdi): use GPIO's instead of /dev/spidev#.# // adaptors.WithGpiosActiveLow(pin's): invert the pin behavior // adaptors.WithGpiosPullUp/Down(pin's): sets the internal pull resistor // // Further optional parameters for: // // AIO, see [adaptors.NewAnalogPinsAdaptor] // GPIO, see [adaptors.NewDigitalPinsAdaptor] // I2C, see [adaptors.NewI2cBusAdaptor] // 1-wire, see [adaptors.NewOneWireBusAdaptor] // PWM, see [adaptors.NewPWMPinsAdaptor] // SPI, see [adaptors.NewSpiBusAdaptor] // // note from RK3288 datasheet: "The pull direction (pullup or pulldown) for all of GPIOs are software-programmable", but // the latter is not working for any pin (armbian 22.08.7) func NewAdaptor(opts ...interface{}) *Adaptor { sys := system.NewAccesser() a := &Adaptor{ name: gobot.DefaultName("Tinker Board"), sys: sys, mutex: &sync.Mutex{}, } var analogPinsOpts []adaptors.AnalogPinsOptionApplier var digitalPinsOpts []adaptors.DigitalPinsOptionApplier var pwmPinsOpts []adaptors.PwmPinsOptionApplier var i2cBusOpts []adaptors.I2CBusOptionApplier var spiBusOpts []adaptors.SpiBusOptionApplier var oneWireBusOpts []adaptors.OneWireBusOptionApplier for _, opt := range opts { switch o := opt.(type) { case adaptors.AnalogPinsOptionApplier: analogPinsOpts = append(analogPinsOpts, o) case adaptors.DigitalPinsOptionApplier: digitalPinsOpts = append(digitalPinsOpts, o) case adaptors.PwmPinsOptionApplier: pwmPinsOpts = append(pwmPinsOpts, o) case adaptors.I2CBusOptionApplier: i2cBusOpts = append(i2cBusOpts, o) case adaptors.SpiBusOptionApplier: spiBusOpts = append(spiBusOpts, o) case adaptors.OneWireBusOptionApplier: oneWireBusOpts = append(oneWireBusOpts, o) default: panic(fmt.Sprintf("'%s' can not be applied on adaptor '%s'", opt, a.name)) } } analogPinTranslator := adaptors.NewAnalogPinTranslator(sys, analogPinDefinitions) digitalPinTranslator := adaptors.NewDigitalPinTranslator(sys, gpioPinDefinitions) pwmPinTranslator := adaptors.NewPWMPinTranslator(sys, pwmPinDefinitions) // Valid bus numbers are [0..4] which corresponds to /dev/i2c-0 through /dev/i2c-4. // We don't support "/dev/i2c-6 DesignWare HDMI". i2cBusNumberValidator := adaptors.NewBusNumberValidator([]int{0, 1, 2, 3, 4}) // Valid bus numbers are [0,2] which corresponds to /dev/spidev0.x, /dev/spidev2.x // x is the chip number <255 spiBusNumberValidator := adaptors.NewBusNumberValidator([]int{0, 2}) a.AnalogPinsAdaptor = adaptors.NewAnalogPinsAdaptor(sys, analogPinTranslator.Translate, analogPinsOpts...) a.DigitalPinsAdaptor = adaptors.NewDigitalPinsAdaptor(sys, digitalPinTranslator.Translate, digitalPinsOpts...) a.PWMPinsAdaptor = adaptors.NewPWMPinsAdaptor(sys, pwmPinTranslator.Translate, pwmPinsOpts...) a.I2cBusAdaptor = adaptors.NewI2cBusAdaptor(sys, i2cBusNumberValidator.Validate, defaultI2cBusNumber, i2cBusOpts...) a.SpiBusAdaptor = adaptors.NewSpiBusAdaptor(sys, spiBusNumberValidator.Validate, defaultSpiBusNumber, defaultSpiChipNumber, defaultSpiMode, defaultSpiBitsNumber, defaultSpiMaxSpeed, a.DigitalPinsAdaptor, spiBusOpts...) a.OneWireBusAdaptor = adaptors.NewOneWireBusAdaptor(sys, oneWireBusOpts...) return a } // Name returns the name of the Adaptor func (a *Adaptor) Name() string { return a.name } // SetName sets the name of the Adaptor func (a *Adaptor) SetName(n string) { a.name = n } // Connect create new connection to board and pins. func (a *Adaptor) Connect() error { a.mutex.Lock() defer a.mutex.Unlock() if err := a.OneWireBusAdaptor.Connect(); err != nil { return err } if err := a.SpiBusAdaptor.Connect(); err != nil { return err } if err := a.I2cBusAdaptor.Connect(); err != nil { return err } if err := a.AnalogPinsAdaptor.Connect(); err != nil { return err } if err := a.PWMPinsAdaptor.Connect(); err != nil { return err } return a.DigitalPinsAdaptor.Connect() } // Finalize closes connection to board, pins and bus func (a *Adaptor) Finalize() error { a.mutex.Lock() defer a.mutex.Unlock() err := a.DigitalPinsAdaptor.Finalize() if e := a.PWMPinsAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } if e := a.AnalogPinsAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } if e := a.I2cBusAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } if e := a.SpiBusAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } if e := a.OneWireBusAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } return err } ================================================ FILE: platforms/asus/tinkerboard/adaptor_test.go ================================================ package tinkerboard import ( "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/adaptors" "gobot.io/x/gobot/v2/system" ) const ( pwmDir = "/sys/devices/platform/ff680020.pwm/pwm/pwmchip2/" //nolint:gosec // false positive pwmPwmDir = pwmDir + "pwm0/" pwmExportPath = pwmDir + "export" pwmUnexportPath = pwmDir + "unexport" pwmEnablePath = pwmPwmDir + "enable" pwmPeriodPath = pwmPwmDir + "period" pwmDutyCyclePath = pwmPwmDir + "duty_cycle" pwmPolarityPath = pwmPwmDir + "polarity" pwmInvertedIdentifier = "inversed" ) var pwmMockPaths = []string{ pwmExportPath, pwmUnexportPath, pwmEnablePath, pwmPeriodPath, pwmDutyCyclePath, pwmPolarityPath, } // make sure that this Adaptor fulfills all the required interfaces var ( _ gobot.Adaptor = (*Adaptor)(nil) _ gobot.DigitalPinnerProvider = (*Adaptor)(nil) _ gobot.PWMPinnerProvider = (*Adaptor)(nil) _ gpio.DigitalReader = (*Adaptor)(nil) _ gpio.DigitalWriter = (*Adaptor)(nil) _ gpio.PwmWriter = (*Adaptor)(nil) _ gpio.ServoWriter = (*Adaptor)(nil) _ aio.AnalogReader = (*Adaptor)(nil) _ i2c.Connector = (*Adaptor)(nil) ) func preparePwmFs(fs *system.MockFilesystem) { fs.Files[pwmEnablePath].Contents = "0" fs.Files[pwmPeriodPath].Contents = "0" fs.Files[pwmDutyCyclePath].Contents = "0" fs.Files[pwmPolarityPath].Contents = pwmInvertedIdentifier } func initConnectedTestAdaptorWithMockedFilesystem(mockPaths []string) (*Adaptor, *system.MockFilesystem) { a := initConnectedTestAdaptor() fs := a.sys.UseMockFilesystem(mockPaths) return a, fs } func initConnectedTestAdaptor() *Adaptor { a := NewAdaptor() if err := a.Connect(); err != nil { panic(err) } return a } func TestNewAdaptor(t *testing.T) { // arrange & act a := NewAdaptor() // assert assert.IsType(t, &Adaptor{}, a) assert.True(t, strings.HasPrefix(a.Name(), "Tinker Board")) assert.NotNil(t, a.sys) assert.NotNil(t, a.mutex) assert.NotNil(t, a.AnalogPinsAdaptor) assert.NotNil(t, a.DigitalPinsAdaptor) assert.NotNil(t, a.PWMPinsAdaptor) assert.NotNil(t, a.I2cBusAdaptor) assert.NotNil(t, a.SpiBusAdaptor) assert.NotNil(t, a.OneWireBusAdaptor) assert.True(t, a.sys.HasDigitalPinCdevAccess()) // act & assert a.SetName("NewName") assert.Equal(t, "NewName", a.Name()) } func TestNewAdaptorWithOption(t *testing.T) { // arrange & act a := NewAdaptor(adaptors.WithGpiosActiveLow("1"), adaptors.WithGpioSysfsAccess()) // assert require.NoError(t, a.Connect()) assert.True(t, a.sys.HasDigitalPinSysfsAccess()) } func TestDigitalIO(t *testing.T) { // some basic tests, further tests are done in "digitalpinsadaptor.go" // arrange a := initConnectedTestAdaptor() dpa := a.sys.UseMockDigitalPinAccess() require.True(t, a.sys.HasDigitalPinCdevAccess()) // act & assert write err := a.DigitalWrite("7", 1) require.NoError(t, err) assert.Equal(t, []int{1}, dpa.Written("gpiochip0", "17")) // arrange, act & assert read dpa.UseValues("gpiochip5", "8", []int{3}) i, err := a.DigitalRead("10") require.NoError(t, err) assert.Equal(t, 3, i) // act and assert unknown pin require.ErrorContains(t, a.DigitalWrite("99", 1), "'99' is not a valid id for a digital pin") // act and assert finalize require.NoError(t, a.Finalize()) assert.Equal(t, 0, dpa.Exported("gpiochip0", "17")) assert.Equal(t, 0, dpa.Exported("gpiochip5", "8")) } func TestDigitalIOSysfs(t *testing.T) { // some basic tests, further tests are done in "digitalpinsadaptor.go" // arrange a := NewAdaptor(adaptors.WithGpioSysfsAccess()) require.NoError(t, a.Connect()) dpa := a.sys.UseMockDigitalPinAccess() require.True(t, a.sys.HasDigitalPinSysfsAccess()) // act & assert write err := a.DigitalWrite("7", 1) require.NoError(t, err) assert.Equal(t, []int{1}, dpa.Written("", "17")) // arrange, act & assert read dpa.UseValues("", "160", []int{4}) i, err := a.DigitalRead("10") require.NoError(t, err) assert.Equal(t, 4, i) // act and assert unknown pin require.ErrorContains(t, a.DigitalWrite("99", 1), "'99' is not a valid id for a digital pin") // act and assert finalize require.NoError(t, a.Finalize()) assert.Equal(t, 0, dpa.Exported("", "17")) assert.Equal(t, 0, dpa.Exported("", "160")) } func TestAnalogRead(t *testing.T) { mockPaths := []string{ "/sys/class/thermal/thermal_zone0/temp", } a, fs := initConnectedTestAdaptorWithMockedFilesystem(mockPaths) fs.Files["/sys/class/thermal/thermal_zone0/temp"].Contents = "567\n" got, err := a.AnalogRead("thermal_zone0") require.NoError(t, err) assert.Equal(t, 567, got) _, err = a.AnalogRead("thermal_zone10") require.ErrorContains(t, err, "'thermal_zone10' is not a valid id for an analog pin") fs.WithReadError = true _, err = a.AnalogRead("thermal_zone0") require.ErrorContains(t, err, "read error") fs.WithReadError = false require.NoError(t, a.Finalize()) } func TestFinalizeErrorAfterGPIO(t *testing.T) { // arrange a := initConnectedTestAdaptor() dpa := a.sys.UseMockDigitalPinAccess() require.True(t, a.sys.HasDigitalPinCdevAccess()) require.NoError(t, a.DigitalWrite("7", 1)) dpa.UseUnexportError("gpiochip0", "17") // act err := a.Finalize() // assert require.ErrorContains(t, err, "unexport error") } func TestFinalizeErrorAfterPWM(t *testing.T) { // indirect test for PWM.Finalize() is called for the adaptor // arrange a, fs := initConnectedTestAdaptorWithMockedFilesystem(pwmMockPaths) preparePwmFs(fs) require.NoError(t, a.PwmWrite("33", 1)) fs.WithWriteError = true // act err := a.Finalize() // assert require.ErrorContains(t, err, "write error") } func TestSpiDefaultValues(t *testing.T) { a := NewAdaptor() assert.Equal(t, 0, a.SpiDefaultBusNumber()) assert.Equal(t, 0, a.SpiDefaultChipNumber()) assert.Equal(t, 0, a.SpiDefaultMode()) assert.Equal(t, 8, a.SpiDefaultBitCount()) assert.Equal(t, int64(500000), a.SpiDefaultMaxSpeed()) } func TestI2cDefaultBus(t *testing.T) { a := NewAdaptor() assert.Equal(t, 1, a.DefaultI2cBus()) } func TestI2cFinalizeWithErrors(t *testing.T) { // arrange a := initConnectedTestAdaptor() a.sys.UseMockSyscall() fs := a.sys.UseMockFilesystem([]string{"/dev/i2c-4"}) con, err := a.GetI2cConnection(0xff, 4) require.NoError(t, err) _, err = con.Write([]byte{0xbf}) require.NoError(t, err) fs.WithCloseError = true // act err = a.Finalize() // assert require.ErrorContains(t, err, "close error") } ================================================ FILE: platforms/asus/tinkerboard/doc.go ================================================ /* Package tinkerboard contains the Gobot adaptor for the ASUS Tinker Board. For further information refer to tinkerboard README: https://github.com/hybridgroup/gobot/blob/release/platforms/asus/tinkerboard/README.md */ package tinkerboard // import "gobot.io/x/gobot/v2/platforms/asus/tinkerboard" ================================================ FILE: platforms/asus/tinkerboard/pinmap.go ================================================ package tinkerboard import "gobot.io/x/gobot/v2/platforms/adaptors" // notes for character device // pins: A=0+Nr, B=8+Nr, C=16+Nr // tested: armbian Linux, OK: work as input and output, IN: work only as input var gpioPinDefinitions = adaptors.DigitalPinDefinitions{ "7": {Sysfs: 17, Cdev: adaptors.CdevPin{Chip: 0, Line: 17}}, // GPIO0_C1_CLKOUT - OK "10": {Sysfs: 160, Cdev: adaptors.CdevPin{Chip: 5, Line: 8}}, // GPIO5_B0_UART1RX - IN, initial 1 "8": {Sysfs: 161, Cdev: adaptors.CdevPin{Chip: 5, Line: 9}}, // GPIO5_B1_UART1TX - NO, initial 1 "16": {Sysfs: 162, Cdev: adaptors.CdevPin{Chip: 5, Line: 10}}, // GPIO5_B2_UART1CTSN - NO, initial 0 "18": {Sysfs: 163, Cdev: adaptors.CdevPin{Chip: 5, Line: 11}}, // GPIO5_B3_UART1RTSN - NO, initial 0 "11": {Sysfs: 164, Cdev: adaptors.CdevPin{Chip: 5, Line: 12}}, // GPIO5_B4_SPI0CLK_UART4CTSN - NO, initial 0 "29": {Sysfs: 165, Cdev: adaptors.CdevPin{Chip: 5, Line: 13}}, // GPIO5_B5_SPI0CSN_UART4RTSN - NO, initial 0 "13": {Sysfs: 166, Cdev: adaptors.CdevPin{Chip: 5, Line: 14}}, // GPIO5_B6_SPI0_TXD_UART4TX - NO, initial 1 "15": {Sysfs: 167, Cdev: adaptors.CdevPin{Chip: 5, Line: 15}}, // GPIO5_B7_SPI0_RXD_UART4RX - IN, initial 1 "31": {Sysfs: 168, Cdev: adaptors.CdevPin{Chip: 5, Line: 16}}, // GPIO5_C0_SPI0CSN1 - OK if SPI0 off "22": {Sysfs: 171, Cdev: adaptors.CdevPin{Chip: 5, Line: 19}}, // GPIO5_C3 - OK "12": {Sysfs: 184, Cdev: adaptors.CdevPin{Chip: 6, Line: 0}}, // GPIO6_A0_PCM/I2S_CLK - NO, initial 1 "35": {Sysfs: 185, Cdev: adaptors.CdevPin{Chip: 6, Line: 1}}, // GPIO6_A1_PCM/I2S_FS - NO, initial 0 "38": {Sysfs: 187, Cdev: adaptors.CdevPin{Chip: 6, Line: 3}}, // GPIO6_A3_PCM/I2S_SDI - IN, initial 1 "40": {Sysfs: 188, Cdev: adaptors.CdevPin{Chip: 6, Line: 4}}, // GPIO6_A4_PCM/I2S_SDO - NO, initial 0 "36": {Sysfs: 223, Cdev: adaptors.CdevPin{Chip: 7, Line: 7}}, // GPIO7_A7_UART3RX - IN, initial 1 "37": {Sysfs: 224, Cdev: adaptors.CdevPin{Chip: 7, Line: 8}}, // GPIO7_B0_UART3TX - NO, initial 1 "27": {Sysfs: 233, Cdev: adaptors.CdevPin{Chip: 7, Line: 17}}, // GPIO7_C1_I2C4_SDA - OK if I2C4 off "28": {Sysfs: 234, Cdev: adaptors.CdevPin{Chip: 7, Line: 18}}, // GPIO7_C2_I2C_SCL - OK if I2C4 off "33": {Sysfs: 238, Cdev: adaptors.CdevPin{Chip: 7, Line: 22}}, // GPIO7_C6_UART2RX_PWM2 - IN, initial 1 "32": {Sysfs: 239, Cdev: adaptors.CdevPin{Chip: 7, Line: 23}}, // GPIO7_C7_UART2TX_PWM3 - NO, initial 1 "26": {Sysfs: 251, Cdev: adaptors.CdevPin{Chip: 8, Line: 3}}, // GPIO8_A3_SPI2CSN1 - OK if SPI2 off "3": {Sysfs: 252, Cdev: adaptors.CdevPin{Chip: 8, Line: 4}}, // GPIO8_A4_I2C1_SDA - OK if I2C1 off "5": {Sysfs: 253, Cdev: adaptors.CdevPin{Chip: 8, Line: 5}}, // GPIO8_A5_I2C1_SCL - OK if I2C1 off "23": {Sysfs: 254, Cdev: adaptors.CdevPin{Chip: 8, Line: 6}}, // GPIO8_A6_SPI2CLK - OK if SPI2 off "24": {Sysfs: 255, Cdev: adaptors.CdevPin{Chip: 8, Line: 7}}, // GPIO8_A7_SPI2CSN0 - OK if SPI2 off "21": {Sysfs: 256, Cdev: adaptors.CdevPin{Chip: 8, Line: 8}}, // GPIO8_B0_SPI2RXD - OK if SPI2 off "19": {Sysfs: 257, Cdev: adaptors.CdevPin{Chip: 8, Line: 9}}, // GPIO8_B1_SPI2TXD - OK if SPI2 off } var pwmPinDefinitions = adaptors.PWMPinDefinitions{ // GPIO7_C6_UART2RX_PWM2 "33": {Dir: "/sys/devices/platform/ff680020.pwm/pwm/", DirRegexp: "pwmchip[0|1|2]$", Channel: 0}, // GPIO7_C7_UART2TX_PWM3 "32": {Dir: "/sys/devices/platform/ff680030.pwm/pwm/", DirRegexp: "pwmchip[0|1|2|3]$", Channel: 0}, } var analogPinDefinitions = adaptors.AnalogPinDefinitions{ // +/-273.200 °C need >=7 characters to read: +/-273200 millidegree Celsius "thermal_zone0": {Path: "/sys/class/thermal/thermal_zone0/temp", W: false, ReadBufLen: 7}, "thermal_zone1": {Path: "/sys/class/thermal/thermal_zone1/temp", W: false, ReadBufLen: 7}, } ================================================ FILE: platforms/asus/tinkerboard2/README.md ================================================ # Tinker Board 2 The ASUS Tinker Board 2 is a single board SoC computer based on the Rockchip RK3399 processor (arm64). It has built-in GPIO, I2C, PWM, SPI, 1-Wire, MIPI CSI and MIPI DSI interfaces. For more info about the Tinker Board, go to [https://tinker-board.asus.com/series/tinker-board-2.html/](https://tinker-board.asus.com/series/tinker-board-2.html). ## How to Install Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) Tested OS: * [armbian](https://www.armbian.com/tinkerboard-2/) with Debian ### System access and configuration basics Use `sudo armbian-config` or see description for [Tinker Board](../README.md). ### Enabling hardware drivers See description for [Tinker Board](../README.md). ### Enabling GPIO pins See description for [Tinker Board](../README.md). ### Enabling I2C See description for [Tinker Board](../README.md). ## How to Use The pin numbering used by your Gobot program should match the way your board is labeled right on the board itself. ```go r := tinkerboard2.NewAdaptor() led := gpio.NewLedDriver(r, "7") ``` ## How to Connect ### Compiling Compile your Gobot program on your workstation like this: ```sh GOARCH=arm64 GOOS=linux go build -o output/ examples/tinkerboard2_yl40.go ``` Once you have compiled your code, you can upload your program and execute it on the Tinker Board 2 from your workstation using the `scp` and `ssh` commands like this: ```sh scp output/tinkerboard2_yl40 @192.168.1.xxx:~ ssh -t @192.168.1.xxx "./tinkerboard2_yl40" ``` ## Troubleshooting ### I2C The version "Armbian_community 25.2.0-trunk.124 bookworm" contains by default the overlay for i2c7 (header pins 27, 28) and i2c8 (connection on DSI_1, DSI_2). An overlay for i2c6 (header pins 3, 5) needs to be created manually based on one of the other overlays. ### PWM #### Investigate state ```sh # ls -la /sys/class/pwm/ ls -la /sys/class/pwm/ total 0 drwxr-xr-x 2 root root 0 Jan 18 2013 . drwxr-xr-x 77 root root 0 Jan 18 2013 .. lrwxrwxrwx 1 root root 0 Jan 18 2013 pwmchip0 -> ../../devices/platform/ff420020.pwm/pwm/pwmchip0 ``` looking for one of the following items in the path: ff420000 => pwm0, pin32 ff420010 => pwm1, pin33 ff420020 => pwm2, already activated, but internally, not usable ff420030 => pwm3, pin26 #### Activate The version "Armbian_community 25.2.0-trunk.124 bookworm" contains no overlay for pwm0, pwm1 or pwm3. This needs to be created based on another overlay, e.g. `rockchip-rk3568-hk-pwm1.dtbo`. After activation of your preferred pwmchip, proceed like described for [Tinker Board](../README). ================================================ FILE: platforms/asus/tinkerboard2/adaptor.go ================================================ package tinkerboard2 import ( "fmt" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/adaptors" "gobot.io/x/gobot/v2/platforms/asus/tinkerboard" "gobot.io/x/gobot/v2/system" ) const ( defaultI2cBusNumber = 7 // i2c-7 (header pins 27, 28) defaultSpiBusNumber = 1 // spidev1.x (header pins 19, 21, 23, 24) defaultSpiChipNumber = 0 defaultSpiMode = 0 defaultSpiBitsNumber = 8 defaultSpiMaxSpeed = 500000 ) type Tinkerboard2Adaptor struct { *tinkerboard.Adaptor sys *system.Accesser // used for unit tests only } // NewAdaptor creates a Tinkerboard-2 Adaptor // // Optional parameters: // // adaptors.WithGpioSysfsAccess(): use legacy sysfs driver instead of default character device driver // adaptors.WithSpiGpioAccess(sclk, ncs, sdo, sdi): use GPIO's instead of /dev/spidev#.# // adaptors.WithGpiosActiveLow(pin's): invert the pin behavior // adaptors.WithGpiosPullUp/Down(pin's): sets the internal pull resistor // // Further optional parameters for: // // GPIO, see [adaptors.NewDigitalPinsAdaptor] // I2C, see [adaptors.NewI2cBusAdaptor] // PWM, see [adaptors.NewPWMPinsAdaptor] // SPI, see [adaptors.NewSpiBusAdaptor] func NewAdaptor(opts ...interface{}) *Tinkerboard2Adaptor { sys := system.NewAccesser() a := Tinkerboard2Adaptor{ Adaptor: tinkerboard.NewAdaptor(opts...), sys: sys, } a.SetName(gobot.DefaultName("Tinker Board 2")) var digitalPinsOpts []adaptors.DigitalPinsOptionApplier var pwmPinsOpts []adaptors.PwmPinsOptionApplier var i2cBusOpts []adaptors.I2CBusOptionApplier var spiBusOpts []adaptors.SpiBusOptionApplier for _, opt := range opts { switch o := opt.(type) { case adaptors.DigitalPinsOptionApplier: digitalPinsOpts = append(digitalPinsOpts, o) case adaptors.PwmPinsOptionApplier: pwmPinsOpts = append(pwmPinsOpts, o) case adaptors.I2CBusOptionApplier: i2cBusOpts = append(i2cBusOpts, o) case adaptors.SpiBusOptionApplier: spiBusOpts = append(spiBusOpts, o) default: panic(fmt.Sprintf("'%s' can not be applied on adaptor '%s'", opt, a.Name())) } } // note: only adaptors different from tinkerboard needs to be re-assigned digitalPinTranslator := adaptors.NewDigitalPinTranslator(sys, gpioPinDefinitions) pwmPinTranslator := adaptors.NewPWMPinTranslator(sys, pwmPinDefinitions) // Valid bus numbers are [6..8] which corresponds to /dev/i2c-6 through /dev/i2c-8. // We don't support "/dev/i2c-0, /dev/i2c-3, /dev/i2c-4". i2cBusNumberValidator := adaptors.NewBusNumberValidator([]int{6, 7, 8}) spiBusNumberValidator := adaptors.NewBusNumberValidator([]int{1, 5}) a.DigitalPinsAdaptor = adaptors.NewDigitalPinsAdaptor(sys, digitalPinTranslator.Translate, digitalPinsOpts...) a.PWMPinsAdaptor = adaptors.NewPWMPinsAdaptor(sys, pwmPinTranslator.Translate, pwmPinsOpts...) a.I2cBusAdaptor = adaptors.NewI2cBusAdaptor(sys, i2cBusNumberValidator.Validate, defaultI2cBusNumber, i2cBusOpts...) a.SpiBusAdaptor = adaptors.NewSpiBusAdaptor(sys, spiBusNumberValidator.Validate, defaultSpiBusNumber, defaultSpiChipNumber, defaultSpiMode, defaultSpiBitsNumber, defaultSpiMaxSpeed, a.DigitalPinsAdaptor, spiBusOpts...) return &a } ================================================ FILE: platforms/asus/tinkerboard2/adaptor_test.go ================================================ package tinkerboard2 import ( "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2/platforms/adaptors" ) func TestNewAdaptor(t *testing.T) { // arrange & act a := NewAdaptor() // assert assert.IsType(t, &Tinkerboard2Adaptor{}, a) assert.True(t, strings.HasPrefix(a.Name(), "Tinker Board 2")) assert.NotNil(t, a.AnalogPinsAdaptor) assert.NotNil(t, a.DigitalPinsAdaptor) assert.NotNil(t, a.PWMPinsAdaptor) assert.NotNil(t, a.I2cBusAdaptor) assert.NotNil(t, a.SpiBusAdaptor) assert.True(t, a.sys.HasDigitalPinCdevAccess()) // act & assert a.SetName("NewName") assert.Equal(t, "NewName", a.Name()) } func TestNewAdaptorWithOption(t *testing.T) { // arrange & act a := NewAdaptor(adaptors.WithGpiosActiveLow("1"), adaptors.WithGpioSysfsAccess()) // assert require.NoError(t, a.Connect()) assert.True(t, a.sys.HasDigitalPinSysfsAccess()) } ================================================ FILE: platforms/asus/tinkerboard2/pinmap.go ================================================ package tinkerboard2 import "gobot.io/x/gobot/v2/platforms/adaptors" // notes for character device // pins: A=0+Nr, B=8+Nr, C=16+Nr, D=24+Nr // tested: armbian Linux, OK: work as input and output, IN: work only as input // MIPI ports itself not wired yet var gpioPinDefinitions = adaptors.DigitalPinDefinitions{ "26": {Sysfs: 6, Cdev: adaptors.CdevPin{Chip: 0, Line: 6}}, // GPIO0_A6_PWM3A_IR - OK, PWM OK "7": {Sysfs: 8, Cdev: adaptors.CdevPin{Chip: 0, Line: 8}}, // GPIO0_B0_TEST_CLKOUT2 - OK "21": {Sysfs: 39, Cdev: adaptors.CdevPin{Chip: 1, Line: 7}}, // GPIO1_A7_SPI1_RXD_UART4_RXD - OK "19": {Sysfs: 40, Cdev: adaptors.CdevPin{Chip: 1, Line: 8}}, // GPIO1_B0_SPI1_TXD_UART4_TXD - OK "23": {Sysfs: 41, Cdev: adaptors.CdevPin{Chip: 1, Line: 9}}, // GPIO1_B1_SPI1_CLK - OK "24": {Sysfs: 42, Cdev: adaptors.CdevPin{Chip: 1, Line: 10}}, // GPIO1_B2_SPI1_CSN - OK "DSI_1": {Sysfs: 48, Cdev: adaptors.CdevPin{Chip: 1, Line: 20}}, // GPIO1_C4_I2C8_SDA - ? "DSI_2": {Sysfs: 48, Cdev: adaptors.CdevPin{Chip: 1, Line: 21}}, // GPIO1_C5_I2C8_SCL - ? "27": {Sysfs: 71, Cdev: adaptors.CdevPin{Chip: 2, Line: 7}}, // GPIO2_A7_I2C7_SDA - OK "28": {Sysfs: 72, Cdev: adaptors.CdevPin{Chip: 2, Line: 8}}, // GPIO2_B0_I2C7_SCL - OK "3": {Sysfs: 73, Cdev: adaptors.CdevPin{Chip: 2, Line: 9}}, // GPIO2_B1_I2C6_SDA - OK "5": {Sysfs: 74, Cdev: adaptors.CdevPin{Chip: 2, Line: 10}}, // GPIO2_B2_I2C6_SCL - OK "CSI_3": {Sysfs: 75, Cdev: adaptors.CdevPin{Chip: 2, Line: 11}}, // GPIO2_B3_CSI_CLKOUT - ? "10": {Sysfs: 80, Cdev: adaptors.CdevPin{Chip: 2, Line: 16}}, // GPIO2_C0_UART0_RXD - OK "8": {Sysfs: 81, Cdev: adaptors.CdevPin{Chip: 2, Line: 17}}, // GPIO2_C1_UART0_TXD - OK "36": {Sysfs: 82, Cdev: adaptors.CdevPin{Chip: 2, Line: 18}}, // GPIO2_C2_UART0_CTSN - OK "11": {Sysfs: 83, Cdev: adaptors.CdevPin{Chip: 2, Line: 19}}, // GPIO2_C3_UART0_RTSN - OK "15": {Sysfs: 84, Cdev: adaptors.CdevPin{Chip: 2, Line: 20}}, // GPIO2_C4_SPI5_RX - OK "13": {Sysfs: 85, Cdev: adaptors.CdevPin{Chip: 2, Line: 21}}, // GPIO2_C5_SPI5_TX - OK "16": {Sysfs: 86, Cdev: adaptors.CdevPin{Chip: 2, Line: 22}}, // GPIO2_C6_SPI5_CLK - OK "18": {Sysfs: 87, Cdev: adaptors.CdevPin{Chip: 2, Line: 23}}, // GPIO2_C7_SPI5_CSN - OK "12": {Sysfs: 120, Cdev: adaptors.CdevPin{Chip: 3, Line: 24}}, // GPIO3_D0_I2S0_SCLK - OK "35": {Sysfs: 121, Cdev: adaptors.CdevPin{Chip: 3, Line: 25}}, // GPIO3_D1_I2S0_FS - OK (smooth digital behavior) "38": {Sysfs: 123, Cdev: adaptors.CdevPin{Chip: 3, Line: 27}}, // GPIO3_D3_I2S0_SDI0 - OK "22": {Sysfs: 124, Cdev: adaptors.CdevPin{Chip: 3, Line: 28}}, // GPIO3_D4_I2S0_SDO3 - OK "31": {Sysfs: 125, Cdev: adaptors.CdevPin{Chip: 3, Line: 29}}, // GPIO3_D5_I2S0_SDO2 - OK "29": {Sysfs: 126, Cdev: adaptors.CdevPin{Chip: 3, Line: 30}}, // GPIO3_D6_I2S0_SDO1 - OK "40": {Sysfs: 127, Cdev: adaptors.CdevPin{Chip: 3, Line: 31}}, // GPIO3_D7_I2S0_SDO0 - OK "CSI_1": {Sysfs: 128, Cdev: adaptors.CdevPin{Chip: 4, Line: 1}}, // GPIO4_A1_I2C1_SDA -? "CSI_2": {Sysfs: 129, Cdev: adaptors.CdevPin{Chip: 4, Line: 2}}, // GPIO4_A2_I2C1_SCL -? "CSI_4": {Sysfs: 130, Cdev: adaptors.CdevPin{Chip: 4, Line: 3}}, // GPIO4_A3_CSI_GPIO -? "32": {Sysfs: 146, Cdev: adaptors.CdevPin{Chip: 4, Line: 18}}, // GPIO4_C2_PWM0 - OK, PWM OK "J6_1": {Sysfs: 147, Cdev: adaptors.CdevPin{Chip: 4, Line: 19}}, // GPIO4_C3_UART2_RX -? "J6_2": {Sysfs: 148, Cdev: adaptors.CdevPin{Chip: 4, Line: 20}}, // GPIO4_C4_UART2_TX -? "37": {Sysfs: 149, Cdev: adaptors.CdevPin{Chip: 4, Line: 21}}, // GPIO4_C5_SPDIF_TX - OK "33": {Sysfs: 150, Cdev: adaptors.CdevPin{Chip: 4, Line: 22}}, // GPIO4_C6_PWM1 - OK, PWM OK } var pwmPinDefinitions = adaptors.PWMPinDefinitions{ // needs to be enabled by device tree (pwm0) "32": {Dir: "/sys/devices/platform/ff420000.pwm/pwm/", DirRegexp: "pwmchip[0|1|2|3]$", Channel: 0}, // needs to be enabled by device tree (pwm1) "33": {Dir: "/sys/devices/platform/ff420010.pwm/pwm/", DirRegexp: "pwmchip[0|1|2|3]$", Channel: 0}, // needs to be enabled by device tree (pwm3) "26": {Dir: "/sys/devices/platform/ff420030.pwm/pwm/", DirRegexp: "pwmchip[0|1|2|3]$", Channel: 0}, } // analog pins are the same as for tinkerboard ================================================ FILE: platforms/audio/LICENSE ================================================ Copyright (c) 2014-2018 The Hybrid Group Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: platforms/audio/audio_adaptor.go ================================================ // Package audio is based on aplay audio adaptor written by @colemanserious (https://github.com/colemanserious) package audio import ( "errors" "log" "os" "os/exec" "path" "gobot.io/x/gobot/v2" ) // Adaptor is gobot Adaptor connection to audio playback type Adaptor struct { name string } // NewAdaptor returns a new audio Adaptor func NewAdaptor() *Adaptor { return &Adaptor{name: gobot.DefaultName("Audio")} } // Name returns the Adaptor Name func (a *Adaptor) Name() string { return a.name } // SetName sets the Adaptor Name func (a *Adaptor) SetName(n string) { a.name = n } // Connect establishes a connection to the Audio adaptor func (a *Adaptor) Connect() error { return nil } // Finalize terminates the connection to the Audio adaptor func (a *Adaptor) Finalize() error { return nil } // Sound plays a sound and accepts: // // string: The filename of the audio to start playing func (a *Adaptor) Sound(fileName string) []error { var errorsList []error if fileName == "" { log.Println("Requires filename for audio file.") errorsList = append(errorsList, errors.New("requires filename for audio file")) return errorsList } _, err := os.Stat(fileName) if err != nil { log.Println(err) errorsList = append(errorsList, err) return errorsList } // command to play audio file based on file type commandName, err := CommandName(fileName) if err != nil { log.Println(err) errorsList = append(errorsList, err) return errorsList } err = RunCommand(commandName, fileName) if err != nil { log.Println(err) errorsList = append(errorsList, err) return errorsList } // Need to return to fulfill function sig, even though returning an empty return nil } // CommandName defines the playback command for a sound and accepts: // // string: The filename of the audio that needs playback func CommandName(fileName string) (string, error) { fileType := path.Ext(fileName) switch fileType { case ".mp3": return "mpg123", nil case ".wav": return "aplay", nil default: return "", errors.New("unknown filetype for audio file") } } var execCommand = exec.Command // RunCommand executes the playback command for a sound file and accepts: // // string: The audio command to be use for playback // string: The filename of the audio that needs playback func RunCommand(audioCommand string, filename string) error { cmd := execCommand(audioCommand, filename) err := cmd.Start() return err } ================================================ FILE: platforms/audio/audio_adaptor_test.go ================================================ // Based on aplay audio adaptor written by @colemanserious (https://github.com/colemanserious) package audio import ( "context" "os" "os/exec" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) var _ gobot.Adaptor = (*Adaptor)(nil) func TestAudioAdaptor(t *testing.T) { a := NewAdaptor() require.NoError(t, a.Connect()) require.NoError(t, a.Finalize()) } func TestAudioAdaptorName(t *testing.T) { a := NewAdaptor() assert.True(t, strings.HasPrefix(a.Name(), "Audio")) a.SetName("NewName") assert.Equal(t, "NewName", a.Name()) } func TestAudioAdaptorCommandsWav(t *testing.T) { cmd, _ := CommandName("whatever.wav") assert.Equal(t, "aplay", cmd) } func TestAudioAdaptorCommandsMp3(t *testing.T) { cmd, _ := CommandName("whatever.mp3") assert.Equal(t, "mpg123", cmd) } func TestAudioAdaptorCommandsUnknown(t *testing.T) { cmd, err := CommandName("whatever.unk") assert.NotEqual(t, "mpg123", cmd) require.ErrorContains(t, err, "unknown filetype for audio file") } func TestAudioAdaptorSoundWithNoFilename(t *testing.T) { a := NewAdaptor() errors := a.Sound("") require.ErrorContains(t, errors[0], "requires filename for audio file") } func TestAudioAdaptorSoundWithNonexistingFilename(t *testing.T) { a := NewAdaptor() errors := a.Sound("doesnotexist.mp3") require.ErrorContains(t, errors[0], "stat doesnotexist.mp3: no such file or directory") } func TestAudioAdaptorSoundWithValidMP3Filename(t *testing.T) { execCommand = myExecCommand a := NewAdaptor() defer func() { execCommand = exec.Command }() errors := a.Sound("../../examples/laser.mp3") assert.Empty(t, errors) } func myExecCommand(command string, args ...string) *exec.Cmd { cs := []string{"-test.run=TestHelperProcess", "--", command} cs = append(cs, args...) cmd := exec.CommandContext(context.Background(), os.Args[0], cs...) //nolint:gosec // ok for test cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"} return cmd } ================================================ FILE: platforms/audio/audio_driver.go ================================================ // Package audio is based on aplay audio adaptor written by @colemanserious (https://github.com/colemanserious) package audio import ( "time" "gobot.io/x/gobot/v2" ) // Driver is gobot software device for audio playback type Driver struct { gobot.Eventer gobot.Commander name string connection gobot.Connection interval time.Duration halt chan bool filename string } // NewDriver returns a new audio Driver. It accepts: // // *Adaptor: The audio adaptor to use for the driver // // string: The filename of the audio to start playing func NewDriver(a *Adaptor, filename string) *Driver { return &Driver{ name: gobot.DefaultName("Audio"), connection: a, interval: 500 * time.Millisecond, filename: filename, halt: make(chan bool), Eventer: gobot.NewEventer(), Commander: gobot.NewCommander(), } } // Name returns the Driver Name func (d *Driver) Name() string { return d.name } // SetName sets the Driver Name func (d *Driver) SetName(n string) { d.name = n } // Filename returns the file name for the driver to playback func (d *Driver) Filename() string { return d.filename } // Connection returns the Driver Connection func (d *Driver) Connection() gobot.Connection { return d.connection } // Sound plays back a sound file. It accepts: // // string: The filename of the audio to start playing func (d *Driver) Sound(fileName string) []error { //nolint:forcetypeassert // ok here return d.Connection().(*Adaptor).Sound(fileName) } // Play plays back the current sound file. func (d *Driver) Play() []error { return d.Sound(d.Filename()) } // Start starts the Driver func (d *Driver) Start() error { return nil } // Halt halts the Driver func (d *Driver) Halt() error { return nil } ================================================ FILE: platforms/audio/audio_driver_test.go ================================================ // Based on aplay audio adaptor written by @colemanserious (https://github.com/colemanserious) package audio import ( "os/exec" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) var _ gobot.Driver = (*Driver)(nil) func TestAudioDriver(t *testing.T) { d := NewDriver(NewAdaptor(), "../../examples/laser.mp3") assert.Equal(t, "../../examples/laser.mp3", d.Filename()) assert.NotNil(t, d.Connection()) require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestAudioDriverName(t *testing.T) { d := NewDriver(NewAdaptor(), "") assert.True(t, strings.HasPrefix(d.Name(), "Audio")) d.SetName("NewName") assert.Equal(t, "NewName", d.Name()) } func TestAudioDriverSoundWithNoFilename(t *testing.T) { d := NewDriver(NewAdaptor(), "") errors := d.Sound("") require.ErrorContains(t, errors[0], "requires filename for audio file") } func TestAudioDriverSoundWithDefaultFilename(t *testing.T) { execCommand = myExecCommand defer func() { execCommand = exec.Command }() d := NewDriver(NewAdaptor(), "../../examples/laser.mp3") errors := d.Play() assert.Empty(t, errors) } ================================================ FILE: platforms/audio/doc.go ================================================ /* Package audio provides the Gobot adaptor for audio. For more information refer to the README: https://github.com/hybridgroup/gobot/blob/release/platforms/audio/README.md */ package audio // import "gobot.io/x/gobot/v2/platforms/audio" ================================================ FILE: platforms/beagleboard/LICENSE ================================================ Copyright (c) 2013-2018 The Hybrid Group Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: platforms/beagleboard/README.md ================================================ # BeagleBoard devices The BeagleBone is an ARM based single board computer, with lots of GPIO, I2C, and analog interfaces built in. The Gobot adaptor for the BeagleBone supports all of the various BeagleBone boards such as the BeagleBone Black, SeeedStudio BeagleBone Green, SeeedStudio BeagleBone Green Wireless, and others that use the latest Debian and standard "Cape Manager" interfaces. For more info about the BeagleBone platform go to [http://beagleboard.org/getting-started](http://beagleboard.org/getting-started). In addition, there is an separate Adaptor for the PocketBeagle, a USB-key-fob sized computer. The PocketBeagle has a different pin layout and somewhat different capabilities. For more info about the PocketBeagle platform go to [http://beagleboard.org/pocket](http://beagleboard.org/pocket). ## How to Install We recommend updating to the latest Debian OS when using the BeagleBone. The current Gobot only supports 4.x versions of the OS. If you need support for older versions of the OS, you will need to use Gobot v1.4. You would normally install Go and Gobot on your workstation. Once installed, cross compile your program on your workstation, transfer the final executable to your BeagleBone, and run the program on the BeagleBone itself as documented here. ## How to Use The pin numbering used by your Gobot program should match the way your board is labeled right on the board itself. Gobot also has support for the four built-in LEDs, by referring to them as `usr0`, `usr1`, `usr2` and `usr3`. ```go package main import ( "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/beagleboard/beaglebone" ) func main() { beagleBoneAdaptor := beaglebone.NewAdaptor() led := gpio.NewLedDriver(beagleBoneAdaptor, "P9_12") work := func() { gobot.Every(1*time.Second, func() { if err := led.Toggle(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("blinkBot", []gobot.Connection{beagleBoneAdaptor}, []gobot.Device{led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ``` To use the PocketBeagle, use `pocketbeagle.NewAdaptor()` like this: ```go package main import ( "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/beagleboard/pocketbeagle" ) func main() { pocketBeagleAdaptor := pocketbeagle.NewAdaptor() led := gpio.NewLedDriver(pocketBeagleAdaptor, "P1_02") work := func() { gobot.Every(1*time.Second, func() { if err := led.Toggle(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("pocketBeagleBot", []gobot.Connection{pocketBeagleAdaptor}, []gobot.Device{led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ``` ## How to Connect ### Compiling Compile your Gobot program on your workstation like this: ```sh GOARM=7 GOARCH=arm GOOS=linux go build -o output/ examples/beaglebone_blink.go ``` Once you have compiled your code, you can you can upload your program and execute it on the BeagleBone from your workstation using the `scp` and `ssh` commands like this: ```sh scp output/beaglebone_blink debian@192.168.7.2:/home/debian/ ssh -t debian@192.168.7.2 "./beaglebone_blink" ``` In order to run the preceding commands, you must be running the official Debian Linux through the usb->ethernet connection, or be connected to the board using WiFi. You must also configure hardware settings as described below. ### Updating your board to the latest OS We recommend using your BeagleBone with the latest Debian OS. It is very easy to do this using the Etcher () utility program. First, download the latest BeagleBone OS from Now, use Etcher to create an SD card with the OS image you have downloaded. Once you have created the SD card, boot your BeagleBone using the new image as follows: - Insert SD card into your (powered-down) board, hold down the USER/BOOT button (if using Black) and apply power, either by the USB cable or 5V adapter. - If all you want to do it boot once from the SD card, it should now be booting. - If using BeagleBone Black and desire to write the image to your on-board eMMC, you'll need to follow the instructions at . When the flashing is complete, all 4 USRx LEDs will be steady on or off. The latest Debian flasher images automatically power down the board upon completion. This can take up to 45 minutes. Power-down your board, remove the SD card and apply power again to be complete. These instructions come from the Beagleboard web site's "Getting Started" page located here: ### Configure hardware settings Thanks to the BeagleBone team, the new "U-Boot Overlays" system for enabling hardware and the "cape-universal", the latest Debian OS should "just work" with any GPIO, PWM, I2C, or SPI pins. If you want to dig in and learn more about this check out: ### Upgrading from an older version Please note that if you are upgrading a board that has already run from an older version of Debian OS, you might need to clear out your older eMMC bootloader, otherwise the new U-Boot Overlays in the newer U-Boot may not get enabled. If so, login using SSH and run the following command on your BeagleBone board: `sudo dd if=/dev/zero of=/dev/mmcblk1 count=1 seek=1 bs=128k` Thanks to [@RobertCNelson](https://github.com/RobertCNelson) for the tip on the above. ================================================ FILE: platforms/beagleboard/beaglebone/adaptor.go ================================================ package beaglebone import ( "fmt" "os" "strconv" "strings" "sync" multierror "github.com/hashicorp/go-multierror" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/adaptors" "gobot.io/x/gobot/v2/system" ) const ( pwmPeriodDefault = 500000 // 0.5 ms = 2 kHz defaultI2cBusNumber = 2 defaultSpiBusNumber = 0 defaultSpiChipNumber = 0 defaultSpiMode = 0 defaultSpiBitsNumber = 8 defaultSpiMaxSpeed = 500000 ) // Adaptor is the gobot.Adaptor representation for the Beaglebone Black/Green type Adaptor struct { *adaptors.AnalogPinsAdaptor *adaptors.DigitalPinsAdaptor *adaptors.PWMPinsAdaptor *adaptors.I2cBusAdaptor *adaptors.SpiBusAdaptor name string sys *system.Accesser mutex *sync.Mutex usrLed string } // NewAdaptor returns a new Beaglebone Black/Green Adaptor // // Optional parameters: // // adaptors.WithGpioCdevAccess(): use character device driver instead of sysfs // adaptors.WithSpiGpioAccess(sclk, ncs, sdo, sdi): use GPIO's instead of /dev/spidev#.# // // Further optional parameters for: // // AIO, see [adaptors.NewAnalogPinsAdaptor] // GPIO, see [adaptors.NewDigitalPinsAdaptor] // I2C, see [adaptors.NewI2cBusAdaptor] // PWM, see [adaptors.NewPWMPinsAdaptor] // SPI, see [adaptors.NewSpiBusAdaptor] func NewAdaptor(opts ...interface{}) *Adaptor { sys := system.NewAccesser(system.WithDigitalPinSysfsAccess()) pwmPinTranslator := adaptors.NewPWMPinTranslator(sys, bbbPwmPinMap) a := &Adaptor{ name: gobot.DefaultName("BeagleboneBlack"), sys: sys, mutex: &sync.Mutex{}, usrLed: "/sys/class/leds/beaglebone:green:", } var analogPinsOpts []adaptors.AnalogPinsOptionApplier var digitalPinsOpts []adaptors.DigitalPinsOptionApplier pwmPinsOpts := []adaptors.PwmPinsOptionApplier{adaptors.WithPWMDefaultPeriod(pwmPeriodDefault)} var i2cBusOpts []adaptors.I2CBusOptionApplier var spiBusOpts []adaptors.SpiBusOptionApplier for _, opt := range opts { switch o := opt.(type) { case adaptors.AnalogPinsOptionApplier: analogPinsOpts = append(analogPinsOpts, o) case adaptors.DigitalPinsOptionApplier: digitalPinsOpts = append(digitalPinsOpts, o) case adaptors.PwmPinsOptionApplier: pwmPinsOpts = append(pwmPinsOpts, o) case adaptors.I2CBusOptionApplier: i2cBusOpts = append(i2cBusOpts, o) case adaptors.SpiBusOptionApplier: spiBusOpts = append(spiBusOpts, o) default: panic(fmt.Sprintf("'%s' can not be applied on adaptor '%s'", opt, a.name)) } } analogPinTranslator := adaptors.NewAnalogPinTranslator(sys, bbbAnalogPinMap) // Valid bus number is either 0 or 2 which corresponds to /dev/i2c-0 or /dev/i2c-2. i2cBusNumberValidator := adaptors.NewBusNumberValidator([]int{0, 2}) // Valid bus numbers are [0,1] which corresponds to /dev/spidev0.x through /dev/spidev1.x. // x is the chip number <255 spiBusNumberValidator := adaptors.NewBusNumberValidator([]int{0, 1}) a.AnalogPinsAdaptor = adaptors.NewAnalogPinsAdaptor(sys, analogPinTranslator.Translate, analogPinsOpts...) a.DigitalPinsAdaptor = adaptors.NewDigitalPinsAdaptor(sys, a.translateAndMuxDigitalPin, digitalPinsOpts...) a.PWMPinsAdaptor = adaptors.NewPWMPinsAdaptor(sys, a.getTranslateAndMuxPWMPinFunc(pwmPinTranslator.Translate), pwmPinsOpts...) a.I2cBusAdaptor = adaptors.NewI2cBusAdaptor(sys, i2cBusNumberValidator.Validate, defaultI2cBusNumber, i2cBusOpts...) a.SpiBusAdaptor = adaptors.NewSpiBusAdaptor(sys, spiBusNumberValidator.Validate, defaultSpiBusNumber, defaultSpiChipNumber, defaultSpiMode, defaultSpiBitsNumber, defaultSpiMaxSpeed, a.DigitalPinsAdaptor, spiBusOpts...) return a } // Name returns the Adaptor name func (a *Adaptor) Name() string { return a.name } // SetName sets the Adaptor name func (a *Adaptor) SetName(n string) { a.name = n } // Connect create new connection to board and pins. func (a *Adaptor) Connect() error { a.mutex.Lock() defer a.mutex.Unlock() if err := a.SpiBusAdaptor.Connect(); err != nil { return err } if err := a.I2cBusAdaptor.Connect(); err != nil { return err } if err := a.AnalogPinsAdaptor.Connect(); err != nil { return err } if err := a.PWMPinsAdaptor.Connect(); err != nil { return err } return a.DigitalPinsAdaptor.Connect() } // Finalize releases all i2c devices and exported analog, digital, pwm pins. func (a *Adaptor) Finalize() error { a.mutex.Lock() defer a.mutex.Unlock() err := a.DigitalPinsAdaptor.Finalize() if e := a.PWMPinsAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } if e := a.AnalogPinsAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } if e := a.I2cBusAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } if e := a.SpiBusAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } return err } // DigitalWrite writes a digital value to specified pin. // valid usr pin values are usr0, usr1, usr2 and usr3 func (a *Adaptor) DigitalWrite(id string, val byte) error { a.mutex.Lock() defer a.mutex.Unlock() if strings.Contains(id, "usr") { fi, e := a.sys.OpenFile(a.usrLed+id+"/brightness", os.O_WRONLY|os.O_APPEND, 0o666) defer fi.Close() //nolint:staticcheck // for historical reasons if e != nil { return e } _, err := fi.WriteString(strconv.Itoa(int(val))) return err } return a.DigitalPinsAdaptor.DigitalWrite(id, val) } // translatePin converts digital pin name to pin position func (a *Adaptor) translateAndMuxDigitalPin(id string) (string, int, error) { line, ok := bbbPinMap[id] if !ok { return "", -1, fmt.Errorf("'%s' is not a valid id for a digital pin", id) } // mux is done by id, not by line if err := a.muxPin(id, "gpio"); err != nil { return "", -1, err } return "", line, nil } func (a *Adaptor) getTranslateAndMuxPWMPinFunc( pwmPinTranslate func(id string) (string, int, error), ) func(id string) (string, int, error) { return func(id string) (string, int, error) { path, channel, err := pwmPinTranslate(id) if err != nil { return path, channel, err } if err := a.muxPin(id, "pwm"); err != nil { return "", -1, err } return path, channel, nil } } func (a *Adaptor) muxPin(pin, cmd string) error { path := fmt.Sprintf("/sys/devices/platform/ocp/ocp:%s_pinmux/state", pin) fi, e := a.sys.OpenFile(path, os.O_WRONLY, 0o666) defer fi.Close() //nolint:staticcheck // for historical reasons if e != nil { return e } _, e = fi.WriteString(cmd) return e } ================================================ FILE: platforms/beagleboard/beaglebone/adaptor_test.go ================================================ package beaglebone import ( "fmt" "strconv" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/drivers/spi" "gobot.io/x/gobot/v2/platforms/adaptors" "gobot.io/x/gobot/v2/system" ) // make sure that this Adaptor fulfills all the required interfaces var ( _ gobot.Adaptor = (*Adaptor)(nil) _ gobot.DigitalPinnerProvider = (*Adaptor)(nil) _ gobot.PWMPinnerProvider = (*Adaptor)(nil) _ gpio.DigitalReader = (*Adaptor)(nil) _ gpio.DigitalWriter = (*Adaptor)(nil) _ aio.AnalogReader = (*Adaptor)(nil) _ gpio.PwmWriter = (*Adaptor)(nil) _ gpio.ServoWriter = (*Adaptor)(nil) _ i2c.Connector = (*Adaptor)(nil) _ spi.Connector = (*Adaptor)(nil) ) func initConnectedTestAdaptorWithMockedFilesystem(mockPaths []string) (*Adaptor, *system.MockFilesystem) { a := NewAdaptor() fs := a.sys.UseMockFilesystem(mockPaths) if err := a.Connect(); err != nil { panic(err) } return a, fs } const ( pwmDir = "/sys/devices/platform/ocp/48300000.epwmss/48300200.pwm/pwm/" //nolint:gosec // false positive pwmChip0Dir = pwmDir + "pwmchip0/" pwmChip0ExportPath = pwmChip0Dir + "export" pwmChip0UnexportPath = pwmChip0Dir + "unexport" pwmChip0Pwm0Dir = pwmChip0Dir + "pwm0/" pwmChip0Pwm1Dir = pwmChip0Dir + "pwm1/" pwm0EnablePath = pwmChip0Pwm0Dir + "enable" pwm0PeriodPath = pwmChip0Pwm0Dir + "period" pwm0DutyCyclePath = pwmChip0Pwm0Dir + "duty_cycle" pwm0PolarityPath = pwmChip0Pwm0Dir + "polarity" pwm1EnablePath = pwmChip0Pwm1Dir + "enable" pwm1PeriodPath = pwmChip0Pwm1Dir + "period" pwm1DutyCyclePath = pwmChip0Pwm1Dir + "duty_cycle" pwm1PolarityPath = pwmChip0Pwm1Dir + "polarity" ) var pwmMockPaths = []string{ "/sys/devices/platform/ocp/ocp:P9_22_pinmux/state", "/sys/devices/platform/ocp/ocp:P9_21_pinmux/state", "/sys/bus/iio/devices/iio:device0/in_voltage1_raw", pwmChip0ExportPath, pwmChip0UnexportPath, pwm0EnablePath, pwm0PeriodPath, pwm0DutyCyclePath, pwm0PolarityPath, pwm1EnablePath, pwm1PeriodPath, pwm1DutyCyclePath, pwm1PolarityPath, } func TestNewAdaptor(t *testing.T) { // arrange & act a := NewAdaptor() // assert assert.IsType(t, &Adaptor{}, a) assert.True(t, strings.HasPrefix(a.Name(), "Beaglebone")) assert.NotNil(t, a.sys) assert.NotNil(t, a.mutex) assert.NotNil(t, a.AnalogPinsAdaptor) assert.NotNil(t, a.DigitalPinsAdaptor) assert.NotNil(t, a.PWMPinsAdaptor) assert.NotNil(t, a.I2cBusAdaptor) assert.NotNil(t, a.SpiBusAdaptor) assert.Equal(t, "/sys/class/leds/beaglebone:green:", a.usrLed) assert.True(t, a.sys.HasDigitalPinSysfsAccess()) // act & assert a.SetName("NewName") assert.Equal(t, "NewName", a.Name()) } func TestPWMWrite(t *testing.T) { // arrange a, fs := initConnectedTestAdaptorWithMockedFilesystem(pwmMockPaths) fs.Files[pwm1DutyCyclePath].Contents = "0" fs.Files[pwm1PeriodPath].Contents = "0" // act & assert wrong pin require.ErrorContains(t, a.PwmWrite("P9_99", 175), "'P9_99' is not a valid id for a PWM pin") // act & assert values _ = a.PwmWrite("P9_21", 175) assert.Equal(t, "500000", fs.Files[pwm1PeriodPath].Contents) assert.Equal(t, "343137", fs.Files[pwm1DutyCyclePath].Contents) require.NoError(t, a.Finalize()) } func TestServoWrite(t *testing.T) { // arrange: prepare 50Hz for servos const ( pin = "P9_21" fiftyHzNano = 20000000 ) a := NewAdaptor(adaptors.WithPWMDefaultPeriodForPin(pin, fiftyHzNano)) fs := a.sys.UseMockFilesystem(pwmMockPaths) require.NoError(t, a.Connect()) // act & assert for 0° (min default value) err := a.ServoWrite(pin, 0) require.NoError(t, err) assert.Equal(t, strconv.Itoa(fiftyHzNano), fs.Files[pwm1PeriodPath].Contents) assert.Equal(t, "500000", fs.Files[pwm1DutyCyclePath].Contents) // act & assert for 180° (max default value) err = a.ServoWrite(pin, 180) require.NoError(t, err) assert.Equal(t, strconv.Itoa(fiftyHzNano), fs.Files[pwm1PeriodPath].Contents) assert.Equal(t, "2500000", fs.Files[pwm1DutyCyclePath].Contents) // act & assert invalid pins err = a.ServoWrite("3", 120) require.ErrorContains(t, err, "'3' is not a valid id for a PWM pin") require.NoError(t, a.Finalize()) } func TestAnalogRead(t *testing.T) { mockPaths := []string{ "/sys/bus/iio/devices/iio:device0/in_voltage1_raw", } a, fs := initConnectedTestAdaptorWithMockedFilesystem(mockPaths) fs.Files["/sys/bus/iio/devices/iio:device0/in_voltage1_raw"].Contents = "567\n" i, err := a.AnalogRead("P9_40") assert.Equal(t, 567, i) require.NoError(t, err) _, err = a.AnalogRead("P9_99") require.ErrorContains(t, err, "not a valid id for an analog pin") fs.WithReadError = true _, err = a.AnalogRead("P9_40") require.ErrorContains(t, err, "read error") fs.WithReadError = false require.NoError(t, a.Finalize()) } func TestDigitalIO(t *testing.T) { mockPaths := []string{ "/sys/devices/platform/ocp/ocp:P8_07_pinmux/state", "/sys/devices/platform/ocp/ocp:P9_11_pinmux/state", "/sys/devices/platform/ocp/ocp:P9_12_pinmux/state", "/sys/class/leds/beaglebone:green:usr1/brightness", "/sys/class/gpio/export", "/sys/class/gpio/unexport", "/sys/class/gpio/gpio60/value", "/sys/class/gpio/gpio60/direction", "/sys/class/gpio/gpio66/value", "/sys/class/gpio/gpio66/direction", "/sys/class/gpio/gpio10/value", "/sys/class/gpio/gpio10/direction", "/sys/class/gpio/gpio30/value", "/sys/class/gpio/gpio30/direction", } a, fs := initConnectedTestAdaptorWithMockedFilesystem(mockPaths) // DigitalIO require.NoError(t, a.DigitalWrite("usr1", 1)) assert.Equal(t, "1", fs.Files["/sys/class/leds/beaglebone:green:usr1/brightness"].Contents, ) // no such LED err := a.DigitalWrite("usr10101", 1) require.ErrorContains(t, err, " : /sys/class/leds/beaglebone:green:usr10101/brightness: no such file") require.NoError(t, a.DigitalWrite("P9_12", 1)) assert.Equal(t, "1", fs.Files["/sys/class/gpio/gpio60/value"].Contents) require.ErrorContains(t, a.DigitalWrite("P9_99", 1), "'P9_99' is not a valid id for a digital pin") _, err = a.DigitalRead("P9_99") require.ErrorContains(t, err, "'P9_99' is not a valid id for a digital pin") fs.Files["/sys/class/gpio/gpio66/value"].Contents = "1" i, err := a.DigitalRead("P8_07") assert.Equal(t, 1, i) require.NoError(t, err) require.NoError(t, a.Finalize()) } func TestAnalogReadFileError(t *testing.T) { mockPaths := []string{ "/sys/devices/platform/whatever", } a, _ := initConnectedTestAdaptorWithMockedFilesystem(mockPaths) _, err := a.AnalogRead("P9_40") require.ErrorContains(t, err, "/sys/bus/iio/devices/iio:device0/in_voltage1_raw: no such file") } func TestDigitalPinDirectionFileError(t *testing.T) { mockPaths := []string{ "/sys/class/gpio/export", "/sys/class/gpio/gpio60/value", "/sys/devices/platform/ocp/ocp:P9_12_pinmux/state", } a, _ := initConnectedTestAdaptorWithMockedFilesystem(mockPaths) err := a.DigitalWrite("P9_12", 1) require.ErrorContains(t, err, "/sys/class/gpio/gpio60/direction: no such file") // no pin added after previous problem, so no pin to unexport in finalize err = a.Finalize() require.NoError(t, err) } func TestDigitalPinFinalizeFileError(t *testing.T) { mockPaths := []string{ "/sys/class/gpio/export", "/sys/class/gpio/gpio60/value", "/sys/class/gpio/gpio60/direction", "/sys/devices/platform/ocp/ocp:P9_12_pinmux/state", } a, _ := initConnectedTestAdaptorWithMockedFilesystem(mockPaths) err := a.DigitalWrite("P9_12", 1) require.NoError(t, err) err = a.Finalize() require.ErrorContains(t, err, "/sys/class/gpio/unexport: no such file") } func TestSpiDefaultValues(t *testing.T) { a := NewAdaptor() assert.Equal(t, 0, a.SpiDefaultBusNumber()) assert.Equal(t, 0, a.SpiDefaultChipNumber()) assert.Equal(t, 0, a.SpiDefaultMode()) assert.Equal(t, 8, a.SpiDefaultBitCount()) assert.Equal(t, int64(500000), a.SpiDefaultMaxSpeed()) } func TestI2cDefaultBus(t *testing.T) { a := NewAdaptor() assert.Equal(t, 2, a.DefaultI2cBus()) } func TestI2cFinalizeWithErrors(t *testing.T) { // arrange a := NewAdaptor() a.sys.UseMockSyscall() fs := a.sys.UseMockFilesystem([]string{"/dev/i2c-2"}) require.NoError(t, a.Connect()) con, err := a.GetI2cConnection(0xff, 2) require.NoError(t, err) _, err = con.Write([]byte{0xbf}) require.NoError(t, err) fs.WithCloseError = true // act err = a.Finalize() // assert require.ErrorContains(t, err, "close error") } func Test_translateAndMuxPWMPin(t *testing.T) { // arrange mockPaths := []string{ "/sys/devices/platform/ocp/48304000.epwmss/48304200.pwm/pwm/pwmchip4/", "/sys/devices/platform/ocp/48302000.epwmss/48302200.pwm/pwm/pwmchip2/", "/sys/devices/platform/ocp/48300000.epwmss/48300200.pwm/pwm/pwmchip0/", "/sys/devices/platform/ocp/48300000.epwmss/48300100.ecap/pwm/pwmchip0/", } a, fs := initConnectedTestAdaptorWithMockedFilesystem(mockPaths) tests := map[string]struct { wantDir string wantChannel int wantErr error }{ "P8_13": { wantDir: "/sys/devices/platform/ocp/48304000.epwmss/48304200.pwm/pwm/pwmchip4", wantChannel: 1, }, "P8_19": { wantDir: "/sys/devices/platform/ocp/48304000.epwmss/48304200.pwm/pwm/pwmchip4", wantChannel: 0, }, "P9_14": { wantDir: "/sys/devices/platform/ocp/48302000.epwmss/48302200.pwm/pwm/pwmchip2", wantChannel: 0, }, "P9_16": { wantDir: "/sys/devices/platform/ocp/48302000.epwmss/48302200.pwm/pwm/pwmchip2", wantChannel: 1, }, "P9_21": { wantDir: "/sys/devices/platform/ocp/48300000.epwmss/48300200.pwm/pwm/pwmchip0", wantChannel: 1, }, "P9_22": { wantDir: "/sys/devices/platform/ocp/48300000.epwmss/48300200.pwm/pwm/pwmchip0", wantChannel: 0, }, "P9_42": { wantDir: "/sys/devices/platform/ocp/48300000.epwmss/48300100.ecap/pwm/pwmchip0", wantChannel: 0, }, "P9_99": { wantDir: "", wantChannel: -1, wantErr: fmt.Errorf("'P9_99' is not a valid id for a PWM pin"), }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange muxPath := fmt.Sprintf("/sys/devices/platform/ocp/ocp:%s_pinmux/state", name) fs.Add(muxPath) pwmPinTranslator := adaptors.NewPWMPinTranslator(a.sys, bbbPwmPinMap) translateAndMuxPWMPin := a.getTranslateAndMuxPWMPinFunc(pwmPinTranslator.Translate) // act path, channel, err := translateAndMuxPWMPin(name) // assert assert.Equal(t, tc.wantErr, err) assert.Equal(t, tc.wantDir, path) assert.Equal(t, tc.wantChannel, channel) if tc.wantErr == nil { assert.Equal(t, "pwm", fs.Files[muxPath].Contents) } }) } } ================================================ FILE: platforms/beagleboard/beaglebone/pinmap.go ================================================ package beaglebone import "gobot.io/x/gobot/v2/platforms/adaptors" var bbbPinMap = map[string]int{ // P8_01 - P8_2 GND // P8_03 - P8_6 EMCC "P8_07": 66, "P8_08": 67, "P8_09": 69, "P8_10": 68, "P8_11": 45, "P8_12": 44, "P8_13": 23, "P8_14": 26, "P8_15": 47, "P8_16": 46, "P8_17": 27, "P8_18": 65, "P8_19": 22, // P8_20 - P8_25 EMCC "P8_26": 61, // P8_27 - P8_46 HDMI // P9_1 - P9_2 GND // P9_3 - P9_4 3V3 // P9_5 - P9_6 5V // P9_7 - P9_8 5V SYS // P9_9 PWR_BUT // P9_10 SYS_RESET "P9_11": 30, "P9_12": 60, "P9_13": 31, "P9_14": 50, "P9_15": 48, "P9_16": 51, "P9_17": 5, "P9_18": 4, // P9_19 I2C2 SCL // P9_20 I2C2 SDA "P9_21": 3, "P9_22": 2, "P9_23": 49, "P9_24": 15, "P9_25": 117, "P9_26": 14, "P9_27": 115, "P9_28": 113, "P9_29": 111, "P9_30": 112, "P9_31": 110, } var bbbPwmPinMap = adaptors.PWMPinDefinitions{ "P8_13": { Dir: "/sys/devices/platform/ocp/48304000.epwmss/48304200.pwm/pwm/", DirRegexp: "pwmchip[0-9]+$", Channel: 1, }, "P8_19": { Dir: "/sys/devices/platform/ocp/48304000.epwmss/48304200.pwm/pwm/", DirRegexp: "pwmchip[0-9]+$", Channel: 0, }, "P9_14": { Dir: "/sys/devices/platform/ocp/48302000.epwmss/48302200.pwm/pwm/", DirRegexp: "pwmchip[0-9]+$", Channel: 0, }, "P9_16": { Dir: "/sys/devices/platform/ocp/48302000.epwmss/48302200.pwm/pwm/", DirRegexp: "pwmchip[0-9]+$", Channel: 1, }, "P9_21": { Dir: "/sys/devices/platform/ocp/48300000.epwmss/48300200.pwm/pwm/", DirRegexp: "pwmchip[0-9]+$", Channel: 1, }, "P9_22": { Dir: "/sys/devices/platform/ocp/48300000.epwmss/48300200.pwm/pwm/", DirRegexp: "pwmchip[0-9]+$", Channel: 0, }, "P9_42": { Dir: "/sys/devices/platform/ocp/48300000.epwmss/48300100.ecap/pwm/", DirRegexp: "pwmchip[0-9]+$", Channel: 0, }, } var bbbAnalogPinMap = adaptors.AnalogPinDefinitions{ "P9_39": {Path: "/sys/bus/iio/devices/iio:device0/in_voltage0_raw", W: false, ReadBufLen: 1024}, "P9_40": {Path: "/sys/bus/iio/devices/iio:device0/in_voltage1_raw", W: false, ReadBufLen: 1024}, "P9_37": {Path: "/sys/bus/iio/devices/iio:device0/in_voltage2_raw", W: false, ReadBufLen: 1024}, "P9_38": {Path: "/sys/bus/iio/devices/iio:device0/in_voltage3_raw", W: false, ReadBufLen: 1024}, "P9_33": {Path: "/sys/bus/iio/devices/iio:device0/in_voltage4_raw", W: false, ReadBufLen: 1024}, "P9_36": {Path: "/sys/bus/iio/devices/iio:device0/in_voltage5_raw", W: false, ReadBufLen: 1024}, "P9_35": {Path: "/sys/bus/iio/devices/iio:device0/in_voltage6_raw", W: false, ReadBufLen: 1024}, } ================================================ FILE: platforms/beagleboard/doc.go ================================================ /* Package beagleboard provides the Gobot adaptor for the Beaglebone Black/Green, as well as a separate Adaptor for the PocketBeagle. Installing: Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) Example: package main import ( "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/beagleboard/beaglebone" ) func main() { beagleboneAdaptor := beaglebone.NewAdaptor() led := gpio.NewLedDriver(beagleboneAdaptor, "P9_12") work := func() { gobot.Every(1*time.Second, func() { if err := led.Toggle(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("blinkBot", []gobot.Connection{beagleboneAdaptor}, []gobot.Device{led}, work, ) if err := robot.Start(); err != nil { panic(err) } } For more information refer to the beaglebone README: https://github.com/hybridgroup/gobot/blob/release/platforms/beagleboard/README.md */ package beagleboard // import "gobot.io/x/gobot/v2/platforms/beagleboard" ================================================ FILE: platforms/beagleboard/pocketbeagle/adaptor.go ================================================ package pocketbeagle import ( "fmt" "os" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/adaptors" "gobot.io/x/gobot/v2/platforms/beagleboard/beaglebone" "gobot.io/x/gobot/v2/system" ) const pwmPeriodDefault = 500000 // 0.5 ms = 2 kHz // PocketBeagleAdaptor is the Gobot Adaptor for the PocketBeagle // For more information check out: // // http://beagleboard.org/pocket type PocketBeagleAdaptor struct { *beaglebone.Adaptor sys *system.Accesser } // NewAdaptor creates a new Adaptor for the PocketBeagle // tested with sysfs and cdev on "Linux BeagleBone 5.10.168-ti-r71" // // Optional parameters: // // adaptors.WithGpioCdevAccess(): use character device driver instead of sysfs // adaptors.WithSpiGpioAccess(sclk, ncs, sdo, sdi): use GPIO's instead of /dev/spidev#.# // adaptors.WithGpiosPullUp(pins): will be silently ignored (for some pins) // adaptors.WithGpioDebounce(inPinNum, debounceTime): is only supported for debounceTime < 8ms // // Further optional parameters for: // // AIO, see [adaptors.NewAnalogPinsAdaptor] // GPIO, see [adaptors.NewDigitalPinsAdaptor] // PWM, see [adaptors.NewPWMPinsAdaptor] func NewAdaptor(opts ...interface{}) *PocketBeagleAdaptor { sys := system.NewAccesser() a := PocketBeagleAdaptor{ Adaptor: beaglebone.NewAdaptor(opts...), sys: sys, } a.SetName(gobot.DefaultName("PocketBeagle")) var analogPinsOpts []adaptors.AnalogPinsOptionApplier var digitalPinsOpts []adaptors.DigitalPinsOptionApplier pwmPinsOpts := []adaptors.PwmPinsOptionApplier{adaptors.WithPWMDefaultPeriod(pwmPeriodDefault)} for _, opt := range opts { switch o := opt.(type) { case adaptors.AnalogPinsOptionApplier: analogPinsOpts = append(analogPinsOpts, o) case adaptors.DigitalPinsOptionApplier: digitalPinsOpts = append(digitalPinsOpts, o) case adaptors.PwmPinsOptionApplier: pwmPinsOpts = append(pwmPinsOpts, o) default: panic(fmt.Sprintf("'%s' can not be applied on adaptor '%s'", opt, a.Name())) } } analogPinTranslator := adaptors.NewAnalogPinTranslator(sys, analogPinMap) digitalPinTranslator := adaptors.NewDigitalPinTranslator(sys, gpioPinDefinitions) pwmPinTranslator := adaptors.NewPWMPinTranslator(sys, pwmPinMap) a.AnalogPinsAdaptor = adaptors.NewAnalogPinsAdaptor(sys, analogPinTranslator.Translate, analogPinsOpts...) a.DigitalPinsAdaptor = adaptors.NewDigitalPinsAdaptor(sys, a.getTranslateAndMuxDigitalPinFunc(digitalPinTranslator.Translate), digitalPinsOpts...) a.PWMPinsAdaptor = adaptors.NewPWMPinsAdaptor(sys, a.getTranslateAndMuxPWMPinFunc(pwmPinTranslator.Translate), pwmPinsOpts...) return &a } func (a *PocketBeagleAdaptor) getTranslateAndMuxDigitalPinFunc( digitalPinTranslate func(id string) (string, int, error), ) func(id string) (string, int, error) { return func(id string) (string, int, error) { if a.sys.HasDigitalPinSysfsAccess() { // mux is done by id, not by line if err := a.muxPin(id, "gpio"); err != nil { return "", -1, err } } return digitalPinTranslate(id) } } func (a *PocketBeagleAdaptor) getTranslateAndMuxPWMPinFunc( pwmPinTranslate func(id string) (string, int, error), ) func(id string) (string, int, error) { return func(id string) (string, int, error) { path, channel, err := pwmPinTranslate(id) if err != nil { return path, channel, err } if err := a.muxPin(id, "pwm"); err != nil { return "", -1, err } return path, channel, nil } } func (a *PocketBeagleAdaptor) muxPin(pin, cmd string) error { path := fmt.Sprintf("/sys/devices/platform/ocp/ocp:%s_pinmux/state", pin) fi, e := a.sys.OpenFile(path, os.O_WRONLY, 0o666) defer fi.Close() //nolint:staticcheck // for historical reasons if e != nil { return e } _, e = fi.WriteString(cmd) return e } ================================================ FILE: platforms/beagleboard/pocketbeagle/adaptor_test.go ================================================ package pocketbeagle import ( "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2/platforms/adaptors" ) func TestNewAdaptor(t *testing.T) { // arrange & act a := NewAdaptor() // assert assert.IsType(t, &PocketBeagleAdaptor{}, a) assert.True(t, strings.HasPrefix(a.Name(), "PocketBeagle")) assert.NotNil(t, a.sys) assert.NotNil(t, a.AnalogPinsAdaptor) assert.NotNil(t, a.DigitalPinsAdaptor) assert.NotNil(t, a.PWMPinsAdaptor) assert.NotNil(t, a.I2cBusAdaptor) assert.NotNil(t, a.SpiBusAdaptor) assert.True(t, a.sys.HasDigitalPinCdevAccess()) } func TestNewAdaptorWithOption(t *testing.T) { // arrange & act a := NewAdaptor(adaptors.WithGpioSysfsAccess()) // assert require.NoError(t, a.Connect()) assert.True(t, a.sys.HasDigitalPinSysfsAccess()) } func TestDigitalIO(t *testing.T) { // some basic tests, further tests are done in "digitalpinsadaptor.go" // arrange a := NewAdaptor() require.NoError(t, a.Connect()) dpa := a.sys.UseMockDigitalPinAccess() require.True(t, a.sys.HasDigitalPinCdevAccess()) // act & assert write err := a.DigitalWrite("P1_02", 1) require.NoError(t, err) assert.Equal(t, []int{1}, dpa.Written("gpiochip2", "23")) // arrange, act & assert read dpa.UseValues("gpiochip3", "19", []int{2}) i, err := a.DigitalRead("P2_34") require.NoError(t, err) assert.Equal(t, 2, i) // act and assert unknown pin require.ErrorContains(t, a.DigitalWrite("99", 1), "'99' is not a valid id for a digital pin") // act and assert finalize require.NoError(t, a.Finalize()) assert.Equal(t, 0, dpa.Exported("gpiochip2", "23")) assert.Equal(t, 0, dpa.Exported("gpiochip3", "19")) } ================================================ FILE: platforms/beagleboard/pocketbeagle/pinmap.go ================================================ package pocketbeagle import "gobot.io/x/gobot/v2/platforms/adaptors" // tested: am335x-debian-11.7-iot-armhf-2023-09-02-4gb, OK: work as input and output, IN: work only as input var gpioPinDefinitions = adaptors.DigitalPinDefinitions{ // gpiochip0 - 32 lines: // line 0: "NC" unused input active-high // line 1: "NC" unused input active-high "P1_08": {Sysfs: 2, Cdev: adaptors.CdevPin{Chip: 0, Line: 2}}, // P1.08_SPI0_CLK - ? "P1_10": {Sysfs: 3, Cdev: adaptors.CdevPin{Chip: 0, Line: 3}}, // P1.10_SPI0_MISO - ? "P1_12": {Sysfs: 4, Cdev: adaptors.CdevPin{Chip: 0, Line: 4}}, // P1.12_SPI0_MOSI - ? "P1_06": {Sysfs: 5, Cdev: adaptors.CdevPin{Chip: 0, Line: 5}}, // P1.06_SPI0_CS - ? // line 6: "[MMC0_CD]" "cd" input active-low [used] "P2_29": {Sysfs: 7, Cdev: adaptors.CdevPin{Chip: 0, Line: 7}}, // P2.29_SPI1_CLK - ? // line 8: "[SYSBOOT 12]" unused input active-high // line 9: "[SYSBOOT 13]" unused input active-high // line 10: "[SYSBOOT 14]" unused input active-high // line 11: "[SYSBOOT 15]" unused input active-high "P1_26": {Sysfs: 12, Cdev: adaptors.CdevPin{Chip: 0, Line: 12}}, // P1.26_I2C2_SDA - ? "P1_28": {Sysfs: 13, Cdev: adaptors.CdevPin{Chip: 0, Line: 13}}, // P1.28_I2C2_SCL - ? "P2_11": {Sysfs: 14, Cdev: adaptors.CdevPin{Chip: 0, Line: 14}}, // P2.11_I2C1_SDA - ? "P2_09": {Sysfs: 15, Cdev: adaptors.CdevPin{Chip: 0, Line: 15}}, // P2.09_I2C1_SCL - ? // line 16: "NC" unused input active-high // line 17: "NC" unused input active-high // line 18: "NC" unused input active-high "P2_31": {Sysfs: 19, Cdev: adaptors.CdevPin{Chip: 0, Line: 19}}, // P2.31_SPI1_CS - ? "P1_20": {Sysfs: 20, Cdev: adaptors.CdevPin{Chip: 0, Line: 20}}, // P1.20_PRU0.16 - ? // line 21: "NC" unused input active-high // line 22: "NC" unused input active-high "P2_03": {Sysfs: 23, Cdev: adaptors.CdevPin{Chip: 0, Line: 23}}, // P2.03 - ? // line 24: "NC" unused input active-high // line 25: "NC" unused input active-high "P1_34": {Sysfs: 26, Cdev: adaptors.CdevPin{Chip: 0, Line: 26}}, // P1.34 - ? "P2_19": {Sysfs: 27, Cdev: adaptors.CdevPin{Chip: 0, Line: 27}}, // P2.19 - ? // line 28: "NC" unused input active-high // line 29: "NC" unused input active-high "P2_05": {Sysfs: 30, Cdev: adaptors.CdevPin{Chip: 0, Line: 30}}, // P2.05_UART4_RX - ? "P2_07": {Sysfs: 31, Cdev: adaptors.CdevPin{Chip: 0, Line: 31}}, // P2.07_UART4_TX - ? // gpiochip1 - 32 lines: // line 0: "NC" unused input active-high // ... // line 7: "NC" unused input active-high "P2_27": {Sysfs: 40, Cdev: adaptors.CdevPin{Chip: 1, Line: 8}}, // P2.27_SPI1_MISO- ? "P2_25": {Sysfs: 41, Cdev: adaptors.CdevPin{Chip: 1, Line: 9}}, // P2.25_SPI1_MOSI - ? "P1_32": {Sysfs: 42, Cdev: adaptors.CdevPin{Chip: 1, Line: 10}}, // P1.32_UART0_RX - ? "P1_30": {Sysfs: 43, Cdev: adaptors.CdevPin{Chip: 1, Line: 11}}, // P1.30_UART0_TX - ? "P2_24": {Sysfs: 44, Cdev: adaptors.CdevPin{Chip: 1, Line: 12}}, // P2.24 - ? "P2_33": {Sysfs: 45, Cdev: adaptors.CdevPin{Chip: 1, Line: 13}}, // P2.33 - ? "P2_22": {Sysfs: 46, Cdev: adaptors.CdevPin{Chip: 1, Line: 14}}, // P2.22 - ? "P2_18": {Sysfs: 47, Cdev: adaptors.CdevPin{Chip: 1, Line: 15}}, // P2.18 - ? // line 16: "NC" unused input active-high // line 17: "NC" unused input active-high "P2_01": {Sysfs: 50, Cdev: adaptors.CdevPin{Chip: 1, Line: 18}}, // P2.01_PWM1A - ? // line 19: "NC" unused input active-high "P2_10": {Sysfs: 52, Cdev: adaptors.CdevPin{Chip: 1, Line: 20}}, // P2.10- ? "usr0": {Sysfs: -1, Cdev: adaptors.CdevPin{Chip: 1, Line: 21}}, // USR LED 0 (beaglebone:green:usr0) - ? "usr1": {Sysfs: -1, Cdev: adaptors.CdevPin{Chip: 1, Line: 22}}, // USR LED 1 (beaglebone:green:usr1) - ? "usr2": {Sysfs: -1, Cdev: adaptors.CdevPin{Chip: 1, Line: 23}}, // USR LED 2 (beaglebone:green:usr2) - ? "usr3": {Sysfs: -1, Cdev: adaptors.CdevPin{Chip: 1, Line: 24}}, // USR LED 3 (beaglebone:green:usr3) - ? "P2_06": {Sysfs: 57, Cdev: adaptors.CdevPin{Chip: 1, Line: 25}}, // P2.06 - ? "P2_04": {Sysfs: 58, Cdev: adaptors.CdevPin{Chip: 1, Line: 26}}, // P2.04 - ? "P2_02": {Sysfs: 59, Cdev: adaptors.CdevPin{Chip: 1, Line: 27}}, // P2.02 - ? "P2_08": {Sysfs: 60, Cdev: adaptors.CdevPin{Chip: 1, Line: 28}}, // P2.08 - ? // line 29: "NC" unused input active-high // line 30: "NC" unused input active-high // line 31: "NC" unused input active-high // gpiochip2 - 32 lines: "P2_20": {Sysfs: 64, Cdev: adaptors.CdevPin{Chip: 2, Line: 0}}, // P2.20 - ? "P2_17": {Sysfs: 65, Cdev: adaptors.CdevPin{Chip: 2, Line: 1}}, // P2.17 - ? // line 2: "NC" unused input active-high // line 3: "NC" unused input active-high // line 4: "NC" unused input active-high // line 5: "[EEPROM_WP]" unused input active-high // line 6: "[SYSBOOT 0]" unused input active-high // line 7: "[SYSBOOT 1]" unused input active-high // line 8: "[SYSBOOT 2]" unused input active-high // line 9: "[SYSBOOT 3]" unused input active-high // line 10: "[SYSBOOT 4]" unused input active-high // line 11: "[SYSBOOT 5]" unused input active-high // line 12: "[SYSBOOT 6]" unused input active-high // line 13: "[SYSBOOT 7]" unused input active-high // line 14: "[SYSBOOT 8]" unused input active-high // line 15: "[SYSBOOT 9]" unused input active-high // line 16: "[SYSBOOT 10]" unused input active-high // line 17: "[SYSBOOT 11]" unused input active-high // line 18: "NC" unused input active-high // ... // line 21: "NC" unused input active-high "P2_35": {Sysfs: 86, Cdev: adaptors.CdevPin{Chip: 2, Line: 22}}, // P2.35_AIN5 - ? "P1_02": {Sysfs: 87, Cdev: adaptors.CdevPin{Chip: 2, Line: 23}}, // P1.02_AIN6 - ? "P1_35": {Sysfs: 88, Cdev: adaptors.CdevPin{Chip: 2, Line: 24}}, // P1.35_PRU1.10 - ? "P1_04": {Sysfs: 89, Cdev: adaptors.CdevPin{Chip: 2, Line: 25}}, // P1.04_PRU1.11 - ? // line 26: "[MMC0_DAT3]" unused input active-high // line 27: "[MMC0_DAT2]" unused input active-high // line 28: "[MMC0_DAT1]" unused input active-high // line 29: "[MMC0_DAT0]" unused input active-high // line 30: "[MMC0_CLK]" unused input active-high // line 31: "[MMC0_CMD]" unused input active-high // gpiochip3 - 32 lines: // line 0: "NC" unused input active-high // ... // line 4: "NC" unused input active-high // line 13: "P1.03 [USB1]" unused input active-high "P1_36": {Sysfs: 110, Cdev: adaptors.CdevPin{Chip: 3, Line: 14}}, // P1.36_PWM0A - ? "P1_33": {Sysfs: 111, Cdev: adaptors.CdevPin{Chip: 3, Line: 15}}, // P1.33_PRU0.1 - ? "P2_32": {Sysfs: 112, Cdev: adaptors.CdevPin{Chip: 3, Line: 16}}, // P2.32_PRU0.2 - ? "P2_30": {Sysfs: 113, Cdev: adaptors.CdevPin{Chip: 3, Line: 17}}, // P2.30_PRU0.3 - ? "P1_31": {Sysfs: 114, Cdev: adaptors.CdevPin{Chip: 3, Line: 18}}, // P1.31_PRU0.4 - ? "P2_34": {Sysfs: 115, Cdev: adaptors.CdevPin{Chip: 3, Line: 19}}, // P2.34_PRU0.5 - ? "P2_28": {Sysfs: 116, Cdev: adaptors.CdevPin{Chip: 3, Line: 20}}, // P2.28_PRU0.6- ? "P1_29": {Sysfs: 117, Cdev: adaptors.CdevPin{Chip: 3, Line: 21}}, // P1.29_PRU0.7 - ? // line 22: "NC" unused input active-high // ... // line 31: "NC" unused input active-high // P1_01 - VIN; P1_03 - USB1-V_EN; P1_05 - USB1-VBUS; P1_07 - USB1-VIN; P1_09 - USB1-DN; P1_11 - USB1-DP; // P1_13 - USB1-ID; P1_14 - 3.3V; P1_15 - USB1-GND; P1_16 - GND; P1_16 - AIN-VREF-; P1_18 - AIN-VREF+; P1_19 - AIO0 // P1_21 - AIO1; P1_22 - GND; P1_23 - AIO2; P1_24 - VOUT-5V; P1_25 - AIO3; P1_27 - AIO4; P2_12 - PWR-BTN; P2_13 - VOUT // P2_14 - BAT-VIN; P2_15 - GND; P2_16 - BAT-TEMP; P2_21 - GND; P2_23 - 3.3V; P2_26 - NRST; P2_36 - AIO7 } var pwmPinMap = adaptors.PWMPinDefinitions{ "P1_33": {Dir: "/sys/devices/platform/ocp/48300000.epwmss/48300200.pwm/pwm/", DirRegexp: "pwmchip[0-9]+$", Channel: 1}, "P1_36": {Dir: "/sys/devices/platform/ocp/48300000.epwmss/48300200.pwm/pwm/", DirRegexp: "pwmchip[0-9]+$", Channel: 0}, "P2_1": {Dir: "/sys/devices/platform/ocp/48302000.epwmss/48302200.pwm/pwm/", DirRegexp: "pwmchip[0-9]+$", Channel: 0}, "P2_3": {Dir: "/sys/devices/platform/ocp/48304000.epwmss/48304200.pwm/pwm/", DirRegexp: "pwmchip[0-9]+$", Channel: 1}, } var analogPinMap = adaptors.AnalogPinDefinitions{ "P1_19": {Path: "/sys/bus/iio/devices/iio:device0/in_voltage0_raw", W: false, ReadBufLen: 1024}, "P1_21": {Path: "/sys/bus/iio/devices/iio:device0/in_voltage1_raw", W: false, ReadBufLen: 1024}, "P1_23": {Path: "/sys/bus/iio/devices/iio:device0/in_voltage2_raw", W: false, ReadBufLen: 1024}, "P1_25": {Path: "/sys/bus/iio/devices/iio:device0/in_voltage3_raw", W: false, ReadBufLen: 1024}, "P1_27": {Path: "/sys/bus/iio/devices/iio:device0/in_voltage4_raw", W: false, ReadBufLen: 1024}, "P2_36": {Path: "/sys/bus/iio/devices/iio:device0/in_voltage7_raw", W: false, ReadBufLen: 1024}, } ================================================ FILE: platforms/bleclient/LICENSE ================================================ Copyright (c) 2015-2018 The Hybrid Group Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: platforms/bleclient/README.md ================================================ # Bluetooth LE The Gobot BLE adaptor makes it easy to interact with Bluetooth LE aka Bluetooth 4.0 using Go. It is written using the [TinyGo Bluetooth](tinygo.org/x/bluetooth) package. Learn more about Bluetooth LE at Drivers for several BLE Services can be found in the according [driver folder](https://github.com/hybridgroup/gobot/tree/release/drivers/ble). ## How to Install Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) ### macOS You need to have XCode installed to be able to compile code that uses the Gobot BLE adaptor on macOS. This is because the `bluetooth` package uses a CGo based implementation. ### Ubuntu Everything should already just compile on most Linux systems. ### Windows You will need to have a GCC compiler such as [mingw-w64](https://github.com/mingw-w64/mingw-w64) installed in order to use BLE on Windows. ## How To Connect When using BLE a "peripheral" aka "server" is something you connect to such a a pulse meter. A "central" aka "client" is what does the connecting, such as your computer or mobile phone. You need to know the BLE ID of the peripheral you want to connect to. The Gobot BLE client adaptor also lets you connect to a peripheral by friendly name. ### Connect on Ubuntu On Linux the BLE code will need to run as a root user account. The easiest way to accomplish this is probably to use `go build` to build your program, and then to run the requesting executable using `sudo`. For example: go build examples/minidrone.go sudo ./minidrone AA:BB:CC:DD:EE ### Connect on Windows Hopefully coming soon... ## How to Use Here is an example that uses the BLE "Battery" service to retrieve the current change level of the peripheral device: ```go package main import ( "fmt" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble" "gobot.io/x/gobot/v2/platforms/bleclient" ) func main() { bleAdaptor := bleclient.NewAdaptor(os.Args[1]) battery := ble.NewBatteryDriver(bleAdaptor) work := func() { gobot.Every(5*time.Second, func() { level, err := battery.GetBatteryLevel() if err != nil { fmt.Println(err) } fmt.Println("Battery level:", level) }) } robot := gobot.NewRobot("bleBot", []gobot.Connection{bleAdaptor}, []gobot.Device{battery}, work, ) if err := robot.Start(); err != nil { panic(err) } } ``` ================================================ FILE: platforms/bleclient/ble_client_adaptor.go ================================================ package bleclient import ( "fmt" "log" "sync" "time" "tinygo.org/x/bluetooth" "gobot.io/x/gobot/v2" ) type configuration struct { scanTimeout time.Duration sleepAfterDisconnect time.Duration dropCharacteristicsOnDisconnect bool debug bool } // Adaptor represents a Client Connection to a BLE Peripheral type Adaptor struct { name string identifier string cfg *configuration btAdpt *btAdapter btDevice *btDevice characteristics map[string]bluetoothExtCharacteristicer connected bool rssi int btAdptCreator btAdptCreatorFunc mutex *sync.Mutex } // NewAdaptor returns a new Adaptor given an identifier. The identifier can be the address or the name. // // Supported options: // // "WithDebug" // "WithDropCharacteristicsOnDisconnect" // "WithScanTimeout" func NewAdaptor(identifier string, opts ...optionApplier) *Adaptor { cfg := configuration{ scanTimeout: 10 * time.Minute, sleepAfterDisconnect: 500 * time.Millisecond, } a := Adaptor{ name: gobot.DefaultName("BLEClient"), identifier: identifier, cfg: &cfg, characteristics: make(map[string]bluetoothExtCharacteristicer), btAdptCreator: newBtAdapter, mutex: &sync.Mutex{}, } for _, o := range opts { o.apply(a.cfg) } return &a } // WithDebug switch on some debug messages. func WithDebug() debugOption { return debugOption(true) } // WithWithDropCharacteristicsOnDisconnect leads to clean all discovered services from last connect command if a // disconnect command happen. Also all subscriptions will be cleaned. A new discover of services and characteristics is // done on next connect and the subscriptions needs to be done again afterwards by the caller. func WithDropCharacteristicsOnDisconnect() dropCharacteristicsOnDisconnect { return dropCharacteristicsOnDisconnect(true) } // WithScanTimeout substitute the default scan timeout of 10 min. func WithScanTimeout(timeout time.Duration) scanTimeoutOption { return scanTimeoutOption(timeout) } // WithSleepAfterDisconnect substitute the default sleep of 500 ms. func WithSleepAfterDisconnect(sleep time.Duration) sleepAfterDisconnectOption { return sleepAfterDisconnectOption(sleep) } // Name returns the name for the adaptor and after the connection is done, the name of the device func (a *Adaptor) Name() string { if a.btDevice != nil { return a.btDevice.name() } return a.name } // SetName sets the name for the adaptor func (a *Adaptor) SetName(n string) { a.name = n } // Address returns the Bluetooth LE address of the device if connected, otherwise the identifier func (a *Adaptor) Address() string { if a.btDevice != nil { return a.btDevice.address() } return a.identifier } // RSSI returns the Bluetooth LE RSSI value at the moment of connecting the adaptor func (a *Adaptor) RSSI() int { return a.rssi } // WithoutResponses sets if the adaptor should expect responses after // writing characteristics for this device (has no effect at the moment). func (a *Adaptor) WithoutResponses(bool) {} // Connect initiates a connection to the BLE peripheral. func (a *Adaptor) Connect() error { a.mutex.Lock() defer a.mutex.Unlock() if a.connected { return fmt.Errorf("%s is already connected", a.name) } var err error if a.cfg.debug { fmt.Println("[Connect]: enable adaptor...") } // for re-connect, the adapter is already known if a.btAdpt == nil { a.btAdpt = a.btAdptCreator(bluetooth.DefaultAdapter, a.cfg.debug) if err := a.btAdpt.enable(); err != nil { return fmt.Errorf("BT can't get adapter default: %v", err) } } if a.cfg.debug { fmt.Printf("[Connect]: scan %s for the identifier '%s'...\n", a.cfg.scanTimeout, a.identifier) } result, err := a.btAdpt.scan(a.identifier, a.cfg.scanTimeout) if err != nil { return fmt.Errorf("BT scan error: %v", err) } if a.cfg.debug { fmt.Printf("[Connect]: connect to peripheral device with address %s...\n", result.Address) } dev, err := a.btAdpt.connect(result.Address, result.LocalName()) if err != nil { return fmt.Errorf("BT connect error: %v", err) } a.rssi = int(result.RSSI) a.btDevice = dev if len(a.characteristics) == 0 { if a.cfg.debug { fmt.Println("[Connect]: get all services/characteristics...") } services, err := a.btDevice.discoverServices(nil) if err != nil { return fmt.Errorf("BT discover services/characteristics error: %v", err) } for _, service := range services { if a.cfg.debug { fmt.Printf("[Connect]: service found: %s\n", service) } chars, err := service.DiscoverCharacteristics(nil) if err != nil { log.Println(err) continue } for _, char := range chars { if a.cfg.debug { fmt.Printf("[Connect]: characteristic found: %s\n", char) } c := char // to prevent implicit memory aliasing in for loop, before go 1.22 a.characteristics[char.UUID().String()] = &c } } } if a.cfg.debug { fmt.Println("[Connect]: connected") } a.connected = true return nil } // Reconnect attempts to reconnect to the BLE peripheral. If it has an active connection // it will first close that connection and then establish a new connection. func (a *Adaptor) Reconnect() error { if a.connected { if err := a.Disconnect(); err != nil { return err } } return a.Connect() } // Disconnect terminates the connection to the BLE peripheral. func (a *Adaptor) Disconnect() error { if a.cfg.debug { fmt.Println("[Disconnect]: disconnect...") } if a.cfg.dropCharacteristicsOnDisconnect { if a.cfg.debug { fmt.Println("[Disconnect]: unsubscribe...") } for id, chara := range a.characteristics { if err := adjustNotificationsForCharacteristic(chara, nil); err != nil { fmt.Printf("[Disconnect]: error on unsubscribe characteristic %s: %v\n", id, err) } } if a.cfg.debug { fmt.Println("[Disconnect]: drop characteristics...") } a.characteristics = make(map[string]bluetoothExtCharacteristicer) } else if a.cfg.debug { fmt.Println("[Disconnect]: as configured, characteristics not dropped") } err := a.btDevice.disconnect() time.Sleep(a.cfg.sleepAfterDisconnect) a.connected = false if err != nil { return fmt.Errorf("BT disconnect error: %v", err) } if a.cfg.debug { fmt.Println("[Disconnect]: disconnected") } return nil } // Finalize finalizes the BLEAdaptor func (a *Adaptor) Finalize() error { return a.Disconnect() } // ReadCharacteristic returns bytes from the BLE device for the requested characteristic UUID. // The UUID can be given as 16-bit or 128-bit (with or without dashes) value. func (a *Adaptor) ReadCharacteristic(cUUID string) ([]byte, error) { if !a.connected { return nil, fmt.Errorf("cannot read from BLE device until connected") } cUUID, err := convertUUID(cUUID) if err != nil { return nil, err } if chara, ok := a.characteristics[cUUID]; ok { return readFromCharacteristic(chara) } return nil, fmt.Errorf("unknown characteristic: %s", cUUID) } // WriteCharacteristic writes bytes to the BLE device for the requested characteristic UUID. // The UUID can be given as 16-bit or 128-bit (with or without dashes) value. func (a *Adaptor) WriteCharacteristic(cUUID string, data []byte) error { if !a.connected { return fmt.Errorf("cannot write to BLE device until connected") } cUUID, err := convertUUID(cUUID) if err != nil { return err } if chara, ok := a.characteristics[cUUID]; ok { return writeToCharacteristicWithoutResponse(chara, data) } return fmt.Errorf("unknown characteristic: %s", cUUID) } // Subscribe subscribes to notifications from the BLE device for the requested characteristic UUID. // The UUID can be given as 16-bit or 128-bit (with or without dashes) value. func (a *Adaptor) Subscribe(cUUID string, f func(data []byte)) error { if !a.connected { return fmt.Errorf("cannot subscribe to BLE device until connected") } cUUID, err := convertUUID(cUUID) if err != nil { return err } if chara, ok := a.characteristics[cUUID]; ok { return adjustNotificationsForCharacteristic(chara, f) } return fmt.Errorf("unknown characteristic: %s", cUUID) } // Unsubscribe remove subscription to notifications from the BLE device for the requested characteristic UUID. // The UUID can be given as 16-bit or 128-bit (with or without dashes) value. func (a *Adaptor) Unsubscribe(cUUID string) error { if !a.connected { return fmt.Errorf("cannot unsubscribe from BLE device until connected") } cUUID, err := convertUUID(cUUID) if err != nil { return err } if chara, ok := a.characteristics[cUUID]; ok { return adjustNotificationsForCharacteristic(chara, nil) } return fmt.Errorf("unknown characteristic: %s", cUUID) } ================================================ FILE: platforms/bleclient/ble_client_adaptor_options.go ================================================ package bleclient import "time" // optionApplier needs to be implemented by each configurable option type type optionApplier interface { apply(cfg *configuration) } // dropCharacteristicsOnDisconnect is the type for applying drop feature. type dropCharacteristicsOnDisconnect bool // debugOption is the type for applying the debug switch on or off. type debugOption bool // scanTimeoutOption is the type for applying another timeout than the default 10 min. type scanTimeoutOption time.Duration // sleepAfterDisconnectOption is the type for applying another sleep time than the default 500 ms. type sleepAfterDisconnectOption time.Duration func (o dropCharacteristicsOnDisconnect) String() string { return "drop characteristics on disconnect option for BLE client adaptors" } func (o debugOption) String() string { return "debug option for BLE client adaptors" } func (o scanTimeoutOption) String() string { return "scan timeout option for BLE client adaptors" } func (o sleepAfterDisconnectOption) String() string { return "sleep after disconnect option for BLE client adaptors" } func (o dropCharacteristicsOnDisconnect) apply(cfg *configuration) { cfg.dropCharacteristicsOnDisconnect = bool(o) } func (o debugOption) apply(cfg *configuration) { cfg.debug = bool(o) } func (o scanTimeoutOption) apply(cfg *configuration) { cfg.scanTimeout = time.Duration(o) } func (o sleepAfterDisconnectOption) apply(cfg *configuration) { cfg.sleepAfterDisconnect = time.Duration(o) } ================================================ FILE: platforms/bleclient/ble_client_adaptor_options_test.go ================================================ package bleclient import ( "testing" "time" "github.com/stretchr/testify/assert" ) func TestWithDebug(t *testing.T) { // This is a general test, that options are applied by using the WithDebug() option. // All other configuration options can also be tested by With..(val).apply(cfg). // arrange & act a := NewAdaptor("address", WithDebug()) // assert assert.True(t, a.cfg.debug) } func TestWithDropCharacteristicsOnDisconnect(t *testing.T) { // arrange cfg := &configuration{dropCharacteristicsOnDisconnect: false} // act WithDropCharacteristicsOnDisconnect().apply(cfg) // assert assert.True(t, cfg.dropCharacteristicsOnDisconnect) } func TestWithScanTimeout(t *testing.T) { // arrange newTimeout := 2 * time.Second cfg := &configuration{scanTimeout: 10 * time.Second} // act WithScanTimeout(newTimeout).apply(cfg) // assert assert.Equal(t, newTimeout, cfg.scanTimeout) } func TestWithSleepAfterDisconnect(t *testing.T) { // arrange newSleep := 3 * time.Second cfg := &configuration{sleepAfterDisconnect: 10 * time.Second} // act WithSleepAfterDisconnect(newSleep).apply(cfg) // assert assert.Equal(t, newSleep, cfg.sleepAfterDisconnect) } ================================================ FILE: platforms/bleclient/ble_client_adaptor_test.go ================================================ package bleclient import ( "strings" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) var ( _ gobot.Adaptor = (*Adaptor)(nil) _ gobot.BLEConnector = (*Adaptor)(nil) ) func TestNewAdaptor(t *testing.T) { a := NewAdaptor("D7:99:5A:26:EC:38") assert.Equal(t, "D7:99:5A:26:EC:38", a.Address()) assert.True(t, strings.HasPrefix(a.Name(), "BLEClient")) } func TestName(t *testing.T) { a := NewAdaptor("D7:99:5A:26:EC:38") a.SetName("awesome") assert.Equal(t, "awesome", a.Name()) } func TestConnect(t *testing.T) { const ( scanTimeout = 5 * time.Millisecond deviceName = "hello" deviceAddress = "11:22:44:AA:BB:CC" rssi = 56 ) tests := map[string]struct { identifier string extAdapter *btTestAdapter simulateConnected bool simulateDiscoverServicesErr bool wantAddress string wantName string wantErr string }{ "connect_by_address": { identifier: deviceAddress, extAdapter: &btTestAdapter{ deviceAddress: deviceAddress, rssi: rssi, payload: &btTestPayload{name: deviceName}, }, wantAddress: deviceAddress, wantName: deviceName, }, "connect_by_name": { identifier: deviceName, extAdapter: &btTestAdapter{ deviceAddress: deviceAddress, rssi: rssi, payload: &btTestPayload{name: deviceName}, }, wantAddress: deviceAddress, wantName: deviceName, }, "error_already_connected": { extAdapter: &btTestAdapter{}, simulateConnected: true, wantName: "BLEClient", wantErr: "is already connected", }, "error_enable": { extAdapter: &btTestAdapter{ simulateEnableErr: true, }, wantName: "BLEClient", wantErr: "can't get adapter default: adapter enable error", }, "error_scan": { extAdapter: &btTestAdapter{ simulateScanErr: true, }, wantName: "BLEClient", wantErr: "scan error", }, "error_stop_scan": { extAdapter: &btTestAdapter{ deviceAddress: deviceAddress, payload: &btTestPayload{}, simulateStopScanErr: true, }, wantName: "BLEClient", wantErr: "stop scan error", }, "error_timeout_long_delay": { extAdapter: &btTestAdapter{ deviceAddress: deviceAddress, payload: &btTestPayload{}, scanDelay: 2 * scanTimeout, }, wantName: "BLEClient", wantErr: "scan timeout (5ms) elapsed", }, "error_timeout_bad_identifier": { identifier: "bad_identifier", extAdapter: &btTestAdapter{ deviceAddress: deviceAddress, payload: &btTestPayload{}, }, wantAddress: "bad_identifier", wantName: "BLEClient", wantErr: "scan timeout (5ms) elapsed", }, "error_connect": { extAdapter: &btTestAdapter{ deviceAddress: deviceAddress, payload: &btTestPayload{}, simulateConnectErr: true, }, wantName: "BLEClient", wantErr: "adapter connect error", }, "error_discovery_services": { identifier: "disco_err", extAdapter: &btTestAdapter{ deviceAddress: deviceAddress, payload: &btTestPayload{name: "disco_err"}, }, simulateDiscoverServicesErr: true, wantAddress: deviceAddress, wantName: "disco_err", wantErr: "device discover services error", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange a := NewAdaptor(tc.identifier) extDevice := btTestDevice{simulateDiscoverServicesErr: tc.simulateDiscoverServicesErr} btdc := func(_ bluetoothExtDevicer, address, name string) *btDevice { return &btDevice{extDevice: extDevice, devAddress: address, devName: name} } btac := func(bluetoothExtAdapterer, bool) *btAdapter { return &btAdapter{extAdapter: tc.extAdapter, btDeviceCreator: btdc} } a.btAdptCreator = btac a.cfg.scanTimeout = scanTimeout // to speed up test a.connected = tc.simulateConnected // act err := a.Connect() // assert if tc.wantErr == "" { require.NoError(t, err) assert.Equal(t, tc.wantName, a.Name()) assert.Equal(t, tc.wantAddress, a.Address()) assert.Equal(t, rssi, a.RSSI()) assert.True(t, a.connected) } else { require.ErrorContains(t, err, tc.wantErr) assert.Contains(t, a.Name(), tc.wantName) assert.Equal(t, tc.wantAddress, a.Address()) assert.Equal(t, tc.simulateConnected, a.connected) } }) } } func TestDisconnect(t *testing.T) { const ( scanTimeout = 5 * time.Millisecond deviceName = "hello" deviceAddress = "11:22:44:AA:BB:CC" ) tests := map[string]struct { connectBefore bool dropCharacteristics bool simulateDisconnectErr bool wantErr string }{ "disconnect_not_connectected": {}, "disconnect_connectected_before": { connectBefore: true, }, "disconnect_drop_charas": { connectBefore: true, dropCharacteristics: true, }, "error_disconnect": { simulateDisconnectErr: true, connectBefore: true, wantErr: "device disconnect error", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange a := NewAdaptor(deviceName) a.cfg.sleepAfterDisconnect = 0 // to speed up test a.cfg.dropCharacteristicsOnDisconnect = tc.dropCharacteristics var wantCharaLen int if tc.connectBefore { extDevice := btTestDevice{simulateDisconnectErr: tc.simulateDisconnectErr} btdc := func(_ bluetoothExtDevicer, address, name string) *btDevice { return &btDevice{extDevice: extDevice, devAddress: address, devName: name} } extAdapter := &btTestAdapter{ deviceAddress: deviceAddress, payload: &btTestPayload{name: deviceName}, } btac := func(bluetoothExtAdapterer, bool) *btAdapter { return &btAdapter{extAdapter: extAdapter, btDeviceCreator: btdc} } a.btAdptCreator = btac a.cfg.scanTimeout = scanTimeout // to speed up test require.NoError(t, a.Connect()) a.characteristics["charauuid"] = &btTestChara{} if !tc.dropCharacteristics { wantCharaLen = 1 } } // act err := a.Disconnect() // assert if tc.wantErr == "" { require.NoError(t, err) } else { require.ErrorContains(t, err, tc.wantErr) } assert.False(t, a.connected) require.NotNil(t, a.characteristics) assert.Len(t, a.characteristics, wantCharaLen) }) } } func TestReconnect(t *testing.T) { const ( scanTimeout = 5 * time.Millisecond deviceName = "hello" deviceAddress = "11:22:44:AA:BB:CC" rssi = 56 ) tests := map[string]struct { wasConnected bool dropCharacteristics bool simulateDisconnectErr bool simulateConnectErr bool wantErr string }{ "reconnect_not_connected": {}, "reconnect_was_connected": { wasConnected: true, }, "reconnect_drop_charas": { wasConnected: true, dropCharacteristics: true, }, "error_disconnect": { simulateDisconnectErr: true, wasConnected: true, wantErr: "device disconnect error", }, "error_connect": { simulateConnectErr: true, wasConnected: true, wantErr: "adapter connect error", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange a := NewAdaptor(deviceAddress) extDevice := btTestDevice{simulateDisconnectErr: tc.simulateDisconnectErr} btdc := func(_ bluetoothExtDevicer, address, name string) *btDevice { return &btDevice{extDevice: extDevice, devAddress: address, devName: name} } extAdapter := &btTestAdapter{ simulateConnectErr: tc.simulateConnectErr, deviceAddress: deviceAddress, rssi: rssi, payload: &btTestPayload{name: deviceName}, } a.btAdpt = &btAdapter{extAdapter: extAdapter, btDeviceCreator: btdc} a.cfg.scanTimeout = scanTimeout // to speed up test in case of errors a.cfg.sleepAfterDisconnect = 0 // to speed up test a.cfg.dropCharacteristicsOnDisconnect = tc.dropCharacteristics var wantCharaLen int if tc.wasConnected { a.btDevice = btdc(nil, "", "") a.connected = tc.wasConnected a.characteristics["charauuid"] = &btTestChara{} if !tc.dropCharacteristics { wantCharaLen = 1 } } // act err := a.Reconnect() // assert if tc.wantErr == "" { require.NoError(t, err) assert.Equal(t, rssi, a.RSSI()) assert.Len(t, a.characteristics, wantCharaLen) assert.True(t, a.connected) } else { require.ErrorContains(t, err, tc.wantErr) } }) } } func TestFinalize(t *testing.T) { // this also tests Disconnect() tests := map[string]struct { simulateDisconnectErr bool wantErr string }{ "disconnect": {}, "error_disconnect": { simulateDisconnectErr: true, wantErr: "device disconnect error", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange a := NewAdaptor("") a.cfg.sleepAfterDisconnect = 0 // to speed up test extDevice := btTestDevice{simulateDisconnectErr: tc.simulateDisconnectErr} a.btDevice = &btDevice{extDevice: extDevice} // act err := a.Finalize() // assert if tc.wantErr == "" { require.NoError(t, err) } else { require.ErrorContains(t, err, tc.wantErr) } assert.False(t, a.connected) }) } } func TestReadCharacteristic(t *testing.T) { const uuid = "00001234-0000-1000-8000-00805f9b34fb" tests := map[string]struct { inUUID string chara *btTestChara notConnected bool want []byte wantErr string }{ "read_ok": { inUUID: uuid, chara: &btTestChara{readData: []byte{1, 2, 3}}, want: []byte{1, 2, 3}, }, "error_not_connected": { notConnected: true, wantErr: "cannot read from BLE device until connected", }, "error_bad_chara": { inUUID: "gag1", wantErr: "'gag1' is not a valid 16-bit Bluetooth UUID", }, "error_unknown_chara": { inUUID: uuid, wantErr: "unknown characteristic: 00001234-0000-1000-8000-00805f9b34fb", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange a := NewAdaptor("") if tc.chara != nil { a.characteristics[uuid] = tc.chara } a.connected = !tc.notConnected // act got, err := a.ReadCharacteristic(tc.inUUID) // assert if tc.wantErr == "" { require.NoError(t, err) } else { require.ErrorContains(t, err, tc.wantErr) } assert.Equal(t, tc.want, got) }) } } func TestWriteCharacteristic(t *testing.T) { const uuid = "00004321-0000-1000-8000-00805f9b34fb" tests := map[string]struct { inUUID string inData []byte notConnected bool chara *btTestChara want []byte wantErr string }{ "write_ok": { inUUID: uuid, inData: []byte{3, 2, 1}, chara: &btTestChara{}, want: []byte{3, 2, 1}, }, "error_not_connected": { notConnected: true, wantErr: "cannot write to BLE device until connected", }, "error_bad_chara": { inUUID: "gag2", wantErr: "'gag2' is not a valid 16-bit Bluetooth UUID", }, "error_unknown_chara": { inUUID: uuid, wantErr: "unknown characteristic: 00004321-0000-1000-8000-00805f9b34fb", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange a := NewAdaptor("") if tc.chara != nil { a.characteristics[uuid] = tc.chara } a.connected = !tc.notConnected // act err := a.WriteCharacteristic(tc.inUUID, tc.inData) // assert if tc.wantErr == "" { require.NoError(t, err) assert.Equal(t, tc.want, tc.chara.writtenData) } else { require.ErrorContains(t, err, tc.wantErr) } }) } } func TestSubscribe(t *testing.T) { const uuid = "00004321-0000-1000-8000-00805f9b34fb" tests := map[string]struct { inUUID string notConnected bool chara *btTestChara want []byte wantErr string }{ "subscribe_ok": { inUUID: uuid, chara: &btTestChara{}, want: []byte{3, 4, 5}, }, "error_not_connected": { notConnected: true, wantErr: "cannot subscribe to BLE device until connected", }, "error_bad_chara": { inUUID: "gag2", wantErr: "'gag2' is not a valid 16-bit Bluetooth UUID", }, "error_unknown_chara": { inUUID: uuid, wantErr: "unknown characteristic: 00004321-0000-1000-8000-00805f9b34fb", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange a := NewAdaptor("") if tc.chara != nil { a.characteristics[uuid] = tc.chara } a.connected = !tc.notConnected var got []byte notificationFunc := func(data []byte) { got = append(got, data...) } // act err := a.Subscribe(tc.inUUID, notificationFunc) // assert if tc.wantErr == "" { require.NoError(t, err) tc.chara.notificationFunc([]byte{3, 4, 5}) } else { require.ErrorContains(t, err, tc.wantErr) } assert.Equal(t, tc.want, got) }) } } func TestUnsubscribe(t *testing.T) { const uuid = "00004321-0000-1000-8000-00805f9b34fb" tests := map[string]struct { inUUID string notConnected bool chara *btTestChara wantErr string }{ "unsubscribe_ok": { inUUID: uuid, chara: &btTestChara{notificationFunc: func([]byte) {}}, }, "error_not_connected": { notConnected: true, wantErr: "cannot unsubscribe from BLE device until connected", }, "error_bad_chara": { inUUID: "gag2", wantErr: "'gag2' is not a valid 16-bit Bluetooth UUID", }, "error_unknown_chara": { inUUID: uuid, wantErr: "unknown characteristic: 00004321-0000-1000-8000-00805f9b34fb", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange a := NewAdaptor("") if tc.chara != nil { a.characteristics[uuid] = tc.chara } a.connected = !tc.notConnected // act err := a.Unsubscribe(tc.inUUID) // assert if tc.wantErr == "" { require.NoError(t, err) require.NotNil(t, a.characteristics) require.NotNil(t, a.characteristics[uuid]) assert.Nil(t, tc.chara.notificationFunc) } else { require.ErrorContains(t, err, tc.wantErr) } }) } } ================================================ FILE: platforms/bleclient/btwrapper.go ================================================ package bleclient import ( "fmt" "time" "tinygo.org/x/bluetooth" ) // bluetoothExtDevicer is the interface usually implemented by bluetooth.Device type bluetoothExtDevicer interface { DiscoverServices(uuids []bluetooth.UUID) ([]bluetooth.DeviceService, error) Disconnect() error } // bluetoothExtAdapterer is the interface usually implemented by bluetooth.Adapter type bluetoothExtAdapterer interface { Enable() error Scan(callback func(*bluetooth.Adapter, bluetooth.ScanResult)) error StopScan() error Connect(address bluetooth.Address, params bluetooth.ConnectionParams) (bluetooth.Device, error) } type bluetoothExtCharacteristicer interface { Read(data []byte) (int, error) WriteWithoutResponse(p []byte) (n int, err error) EnableNotifications(callback func(buf []byte)) error } // btAdptCreatorFunc is just a convenience type, used in the BLE client to ensure testability type btAdptCreatorFunc func(bluetoothExtAdapterer, bool) *btAdapter // btAdapter is the wrapper for an external adapter implementation type btAdapter struct { extAdapter bluetoothExtAdapterer btDeviceCreator func(bluetoothExtDevicer, string, string) *btDevice debug bool } // newBtAdapter creates a new wrapper around the given external implementation func newBtAdapter(a bluetoothExtAdapterer, debug bool) *btAdapter { bta := btAdapter{ extAdapter: a, btDeviceCreator: newBtDevice, debug: debug, } return &bta } // Enable configures the BLE stack. It must be called before any Bluetooth-related calls (unless otherwise indicated). // It pass through the function of the external implementation. func (bta *btAdapter) enable() error { return bta.extAdapter.Enable() } // StopScan stops any in-progress scan. It can be called from within a Scan callback to stop the current scan. // If no scan is in progress, an error will be returned. func (bta *btAdapter) stopScan() error { return bta.extAdapter.StopScan() } // Connect starts a connection attempt to the given peripheral device address. // // On Linux and Windows, the IsRandom part of the address is ignored. func (bta *btAdapter) connect(address bluetooth.Address, devName string) (*btDevice, error) { extDev, err := bta.extAdapter.Connect(address, bluetooth.ConnectionParams{}) if err != nil { return nil, err } return bta.btDeviceCreator(extDev, address.String(), devName), nil } // Scan starts a BLE scan for the given identifier (address or name). func (bta *btAdapter) scan(identifier string, scanTimeout time.Duration) (*bluetooth.ScanResult, error) { resultChan := make(chan bluetooth.ScanResult, 1) errChan := make(chan error) go func() { callback := func(_ *bluetooth.Adapter, result bluetooth.ScanResult) { if bta.debug { fmt.Printf("[scan result]: address: '%s', rssi: %d, name: '%s', manufacturer: %v\n", result.Address, result.RSSI, result.LocalName(), result.ManufacturerData()) } if result.Address.String() == identifier || result.LocalName() == identifier { resultChan <- result } } err := bta.extAdapter.Scan(callback) if err != nil { errChan <- err } }() select { case result := <-resultChan: if err := bta.stopScan(); err != nil { return nil, fmt.Errorf("stop scan: %v", err) } return &result, nil case err := <-errChan: return nil, err case <-time.After(scanTimeout): _ = bta.stopScan() return nil, fmt.Errorf("scan timeout (%s) elapsed", scanTimeout) } } // btDevice is the wrapper for an external device implementation type btDevice struct { extDevice bluetoothExtDevicer devAddress string devName string } // newBtDevice creates a new wrapper around the given external implementation func newBtDevice(d bluetoothExtDevicer, address, name string) *btDevice { return &btDevice{extDevice: d, devAddress: address, devName: name} } func (btd *btDevice) name() string { return btd.devName } func (btd *btDevice) address() string { return btd.devAddress } func (btd *btDevice) discoverServices(uuids []bluetooth.UUID) ([]bluetooth.DeviceService, error) { return btd.extDevice.DiscoverServices(uuids) } // Disconnect from the BLE device. This method is non-blocking and does not wait until the connection is fully gone. func (btd *btDevice) disconnect() error { if btd != nil && btd.extDevice != nil { return btd.extDevice.Disconnect() } return nil } func readFromCharacteristic(chara bluetoothExtCharacteristicer) ([]byte, error) { buf := make([]byte, 255) n, err := chara.Read(buf) if err != nil { return nil, err } return buf[:n], nil } func writeToCharacteristicWithoutResponse(chara bluetoothExtCharacteristicer, data []byte) error { if _, err := chara.WriteWithoutResponse(data); err != nil { return err } return nil } func adjustNotificationsForCharacteristic(chara bluetoothExtCharacteristicer, f func(data []byte)) error { return chara.EnableNotifications(f) } ================================================ FILE: platforms/bleclient/doc.go ================================================ /* Package bleclient provides the Gobot client adaptor for Bluetooth LE. For more information refer to the README: https://github.com/hybridgroup/gobot/blob/release/platforms/bleclient/README.md */ package bleclient // import "gobot.io/x/gobot/v2/platforms/bleclient" ================================================ FILE: platforms/bleclient/helpers_test.go ================================================ package bleclient import ( "fmt" "time" "tinygo.org/x/bluetooth" ) type btTestAdapter struct { deviceAddress string rssi int16 scanDelay time.Duration payload *btTestPayload simulateEnableErr bool simulateScanErr bool simulateStopScanErr bool simulateConnectErr bool } func (bta *btTestAdapter) Enable() error { if bta.simulateEnableErr { return fmt.Errorf("adapter enable error") } return nil } func (bta *btTestAdapter) Scan(callback func(*bluetooth.Adapter, bluetooth.ScanResult)) error { if bta.simulateScanErr { return fmt.Errorf("adapter scan error") } devAddr, err := bluetooth.ParseMAC(bta.deviceAddress) if err != nil { // normally this error should not happen in test return err } time.Sleep(bta.scanDelay) a := bluetooth.Address{MACAddress: bluetooth.MACAddress{MAC: devAddr}} r := bluetooth.ScanResult{Address: a, RSSI: bta.rssi, AdvertisementPayload: bta.payload} callback(nil, r) return nil } func (bta *btTestAdapter) StopScan() error { if bta.simulateStopScanErr { return fmt.Errorf("adapter stop scan error") } return nil } func (bta *btTestAdapter) Connect(addr bluetooth.Address, _ bluetooth.ConnectionParams) (bluetooth.Device, error) { if bta.simulateConnectErr { return bluetooth.Device{}, fmt.Errorf("adapter connect error") } return bluetooth.Device{Address: addr}, nil } type btTestPayload struct { name string } func (ptp *btTestPayload) LocalName() string { return ptp.name } func (*btTestPayload) HasServiceUUID(bluetooth.UUID) bool { return true } func (*btTestPayload) ServiceUUIDs() []bluetooth.UUID { return nil } func (*btTestPayload) Bytes() []byte { return nil } func (*btTestPayload) ManufacturerData() []bluetooth.ManufacturerDataElement { return nil } func (*btTestPayload) ServiceData() []bluetooth.ServiceDataElement { return nil } type btTestDevice struct { simulateDiscoverServicesErr bool simulateDisconnectErr bool } func (btd btTestDevice) DiscoverServices(_ []bluetooth.UUID) ([]bluetooth.DeviceService, error) { if btd.simulateDiscoverServicesErr { return nil, fmt.Errorf("device discover services error") } // for this test we can not return any []bluetooth.DeviceService return nil, nil } func (btd btTestDevice) Disconnect() error { if btd.simulateDisconnectErr { return fmt.Errorf("device disconnect error") } return nil } // btTestChara implements bluetoothExtCharacteristicer type btTestChara struct { readData []byte writtenData []byte notificationFunc func(buf []byte) } func (btc *btTestChara) Read(data []byte) (int, error) { copy(data, btc.readData) return len(btc.readData), nil } func (btc *btTestChara) WriteWithoutResponse(data []byte) (int, error) { btc.writtenData = append(btc.writtenData, data...) return len(data), nil } func (btc *btTestChara) EnableNotifications(callback func(buf []byte)) error { btc.notificationFunc = callback return nil } ================================================ FILE: platforms/bleclient/uuid.go ================================================ package bleclient import ( "fmt" "strconv" "strings" "tinygo.org/x/bluetooth" ) // convertUUID creates a common 128 bit UUID xxxxyyyy-0000-1000-8000-00805f9b34fb from a short 16 bit UUID by replacing // the yyyy fields. If the given ID is still an arbitrary long one but without dashes, the dashes will be added. // Additionally some simple checks for the resulting UUID will be done. func convertUUID(cUUID string) (string, error) { var uuid string switch len(cUUID) { case 4: uid, err := strconv.ParseUint(cUUID, 16, 16) if err != nil { return "", fmt.Errorf("'%s' is not a valid 16-bit Bluetooth UUID: %v", cUUID, err) } return bluetooth.New16BitUUID(uint16(uid)).String(), nil case 32: // convert "22bb746f2bbd75542d6f726568705327" to "22bb746f-2bbd-7554-2d6f-726568705327" uuid = fmt.Sprintf("%s-%s-%s-%s-%s", cUUID[:8], cUUID[8:12], cUUID[12:16], cUUID[16:20], cUUID[20:]) case 36: uuid = cUUID } if uuid != "" { id := strings.ReplaceAll(uuid, "-", "") _, errHigh := strconv.ParseUint(id[:16], 16, 64) _, errLow := strconv.ParseUint(id[16:], 16, 64) if errHigh == nil && errLow == nil { return uuid, nil } } return "", fmt.Errorf("'%s' is not a valid 128-bit Bluetooth UUID", cUUID) } ================================================ FILE: platforms/bleclient/uuid_test.go ================================================ package bleclient import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func Test_convertUUID(t *testing.T) { tests := map[string]struct { input string want string wantErr string }{ "32_bit": { input: "12345678-4321-1234-4321-123456789abc", want: "12345678-4321-1234-4321-123456789abc", }, "16_bit": { input: "12f4", want: "000012f4-0000-1000-8000-00805f9b34fb", }, "32_bit_without_dashes": { input: "0123456789abcdef012345678abcdefc", want: "01234567-89ab-cdef-0123-45678abcdefc", }, "error_bad_chacters_16bit": { input: "123g", wantErr: "'123g' is not a valid 16-bit Bluetooth UUID", }, "error_bad_chacters_32bit": { input: "12345678-4321-1234-4321-123456789abg", wantErr: "'12345678-4321-1234-4321-123456789abg' is not a valid 128-bit Bluetooth UUID", }, "error_too_long": { input: "12345678-4321-1234-4321-123456789abcd", wantErr: "'12345678-4321-1234-4321-123456789abcd' is not a valid 128-bit Bluetooth UUID", }, "error_invalid": { input: "12345", wantErr: "'12345' is not a valid 128-bit Bluetooth UUID", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // act got, err := convertUUID(tc.input) // assert if tc.wantErr == "" { require.NoError(t, err) } else { require.ErrorContains(t, err, tc.wantErr) } assert.Equal(t, tc.want, got) }) } } ================================================ FILE: platforms/chip/LICENSE ================================================ Copyright (c) 2015-2018 The Hybrid Group Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: platforms/chip/README.md ================================================ # C.H.I.P. The [C.H.I.P.](http://www.getchip.com/) is a small, inexpensive ARM based single board computer, with many different IO interfaces available on the [pin headers](http://docs.getchip.com/#pin-headers). For documentation about the C.H.I.P. platform click [here](http://docs.getchip.com/). The [C.H.I.P. Pro](https://getchip.com/pages/chippro) is a version of C.H.I.P. intended for use in embedded product development. Here is info about the [C.H.I.P. Pro pin headers](https://docs.getchip.com/chip_pro.html#pin-descriptions). ## How to Install We recommend updating to the latest Debian OS when using the C.H.I.P., however Gobot should also support older versions of the OS, should your application require this. You would normally install Go and Gobot on your workstation. Once installed, cross compile your program on your workstation, transfer the final executable to your C.H.I.P and run the program on the C.H.I.P. itself as documented here. Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) ### PWM support Note that PWM might not be available in your kernel. In that case, you can install the required device tree overlay from the command line using [Gort](https://gobot.io/x/gort) CLI commands on the C.H.I.P device. Here are the steps: Install the required patched device tree compiler as described in the [C.H.I.P docs](https://docs.getchip.com/dip.html#make-a-dtbo-device-tree-overlay-blob): ```sh gort chip install dtc ``` Now, install the pwm overlay to activate pwm on the PWM0 pin: ```sh gort chip install pwm ``` Reboot the device to make sure the init script loads the overlay on boot. ## How to Use Please refer to one example for your platform, e.g. [chip_button.go](https://github.com/hybridgroup/gobot/blob/release/examples/chip_button.go). The pin numbering used by your Gobot program should match the way your board is labeled right on the board itself. If you want to use the C.H.I.P. Pro, use the `NewProAdaptor()` function like this: ```go chipProAdaptor := chip.NewProAdaptor() ``` ## How to Connect ### Compiling Compile your Gobot program on your workstation like this: ```bash GOARM=7 GOARCH=arm GOOS=linux go build examples/chip_button.go ``` Once you have compiled your code, you can you can upload your program and execute it on the C.H.I.P. from your workstation using the `scp` and `ssh` commands like this: ```bash scp chip_button root@192.168.1.xx: ssh -t root@192.168.1.xx "./chip_button" ``` ================================================ FILE: platforms/chip/chip_adaptor.go ================================================ package chip import ( "fmt" "os" "path/filepath" "strconv" "strings" "sync" multierror "github.com/hashicorp/go-multierror" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/adaptors" "gobot.io/x/gobot/v2/system" ) const ( defaultI2cBusNumber = 1 defaultSpiMaxSpeed = 5000 // 5kHz (more than 15kHz not possible with SPI over GPIO) ) // Valids pins are the XIO-P0 through XIO-P7 pins from the // extender (pins 13-20 on header 14), as well as the SoC pins // aka all the other pins. type sysfsPin struct { pin int pwmPin int } // Adaptor represents a Gobot Adaptor for a C.H.I.P. type Adaptor struct { *adaptors.DigitalPinsAdaptor *adaptors.PWMPinsAdaptor *adaptors.I2cBusAdaptor *adaptors.SpiBusAdaptor // for usage of "adaptors.WithSpiGpioAccess()" name string sys *system.Accesser // used for unit tests only mutex sync.Mutex pinMap map[string]sysfsPin } // NewAdaptor creates a C.H.I.P. Adaptor // // Optional parameters: // // adaptors.WithGpioCdevAccess(): use character device driver instead of sysfs // adaptors.WithSpiGpioAccess(sclk, ncs, sdo, sdi): use GPIO's instead of /dev/spidev#.# // // Further optional parameters for: // // GPIO, see [adaptors.NewDigitalPinsAdaptor] // I2C, see [adaptors.NewI2cBusAdaptor] // PWM, see [adaptors.NewPWMPinsAdaptor] // SPI, see [adaptors.NewSpiBusAdaptor] func NewAdaptor(opts ...interface{}) *Adaptor { sys := system.NewAccesser(system.WithDigitalPinSysfsAccess()) a := &Adaptor{ name: gobot.DefaultName("CHIP"), sys: sys, } a.pinMap = chipPins baseAddr, _ := getXIOBase() for i := 0; i < 8; i++ { pin := fmt.Sprintf("XIO-P%d", i) a.pinMap[pin] = sysfsPin{pin: baseAddr + i, pwmPin: -1} } var digitalPinsOpts []adaptors.DigitalPinsOptionApplier var pwmPinsOpts []adaptors.PwmPinsOptionApplier var i2cBusOpts []adaptors.I2CBusOptionApplier var spiBusOpts []adaptors.SpiBusOptionApplier for _, opt := range opts { switch o := opt.(type) { case adaptors.DigitalPinsOptionApplier: digitalPinsOpts = append(digitalPinsOpts, o) case adaptors.PwmPinsOptionApplier: pwmPinsOpts = append(pwmPinsOpts, o) case adaptors.I2CBusOptionApplier: i2cBusOpts = append(i2cBusOpts, o) case adaptors.SpiBusOptionApplier: spiBusOpts = append(spiBusOpts, o) default: panic(fmt.Sprintf("'%s' can not be applied on adaptor '%s'", opt, a.name)) } } // Valid bus numbers are [0..2] which corresponds to /dev/i2c-0 through /dev/i2c-2. i2cBusNumberValidator := adaptors.NewBusNumberValidator([]int{0, 1, 2}) a.DigitalPinsAdaptor = adaptors.NewDigitalPinsAdaptor(sys, a.translateDigitalPin, digitalPinsOpts...) a.PWMPinsAdaptor = adaptors.NewPWMPinsAdaptor(sys, a.translatePWMPin, pwmPinsOpts...) a.I2cBusAdaptor = adaptors.NewI2cBusAdaptor(sys, i2cBusNumberValidator.Validate, defaultI2cBusNumber, i2cBusOpts...) // SPI is only supported when "adaptors.WithSpiGpioAccess()" is given if len(spiBusOpts) > 0 { a.SpiBusAdaptor = adaptors.NewSpiBusAdaptor(sys, func(int) error { return nil }, 0, 0, 0, 0, defaultSpiMaxSpeed, a.DigitalPinsAdaptor, spiBusOpts...) } return a } // Name returns the name of the Adaptor func (a *Adaptor) Name() string { return a.name } // SetName sets the name of the Adaptor func (a *Adaptor) SetName(n string) { a.name = n } // Connect create new connection to board and pins. func (a *Adaptor) Connect() error { a.mutex.Lock() defer a.mutex.Unlock() if err := a.I2cBusAdaptor.Connect(); err != nil { return err } if err := a.PWMPinsAdaptor.Connect(); err != nil { return err } return a.DigitalPinsAdaptor.Connect() } // Finalize closes connection to board and pins func (a *Adaptor) Finalize() error { a.mutex.Lock() defer a.mutex.Unlock() err := a.DigitalPinsAdaptor.Finalize() if e := a.PWMPinsAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } if e := a.I2cBusAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } return err } func getXIOBase() (int, error) { // Default to original base from 4.3 kernel baseAddr := 408 const expanderID = "pcf8574a" labels, err := filepath.Glob("/sys/class/gpio/*/label") if err != nil { return baseAddr, err } for _, labelPath := range labels { label, err := os.ReadFile(labelPath) if err != nil { return baseAddr, err } if strings.HasPrefix(string(label), expanderID) { expanderPath, _ := filepath.Split(labelPath) basePath := filepath.Join(expanderPath, "base") base, err := os.ReadFile(basePath) if err != nil { return baseAddr, err } baseAddr, _ = strconv.Atoi(strings.TrimSpace(string(base))) break } } return baseAddr, nil } func (a *Adaptor) translateDigitalPin(id string) (string, int, error) { if val, ok := a.pinMap[id]; ok { return "", val.pin, nil } return "", -1, fmt.Errorf("'%s' is not a valid id for a digital pin", id) } func (a *Adaptor) translatePWMPin(id string) (string, int, error) { sysPin, ok := a.pinMap[id] if !ok { return "", -1, fmt.Errorf("'%s' is not a valid id for a pin", id) } if sysPin.pwmPin == -1 { return "", -1, fmt.Errorf("'%s' is not a valid id for a PWM pin", id) } return "/sys/class/pwm/pwmchip0", sysPin.pwmPin, nil } ================================================ FILE: platforms/chip/chip_adaptor_test.go ================================================ package chip import ( "fmt" "strconv" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/adaptors" "gobot.io/x/gobot/v2/system" ) // make sure that this Adaptor fulfills all the required interfaces var ( _ gobot.Adaptor = (*Adaptor)(nil) _ gobot.DigitalPinnerProvider = (*Adaptor)(nil) _ gobot.PWMPinnerProvider = (*Adaptor)(nil) _ gpio.DigitalReader = (*Adaptor)(nil) _ gpio.DigitalWriter = (*Adaptor)(nil) _ gpio.PwmWriter = (*Adaptor)(nil) _ gpio.ServoWriter = (*Adaptor)(nil) _ i2c.Connector = (*Adaptor)(nil) ) var mockPaths = []string{ "/sys/class/gpio/export", "/sys/class/gpio/unexport", "/sys/class/gpio/gpio50/value", "/sys/class/gpio/gpio50/direction", "/sys/class/gpio/gpio139/value", "/sys/class/gpio/gpio139/direction", "/sys/class/pwm/pwmchip0/export", "/sys/class/pwm/pwmchip0/unexport", "/sys/class/pwm/pwmchip0/pwm0/enable", "/sys/class/pwm/pwmchip0/pwm0/duty_cycle", "/sys/class/pwm/pwmchip0/pwm0/polarity", "/sys/class/pwm/pwmchip0/pwm0/period", } func initConnectedTestAdaptorWithMockedFilesystem() (*Adaptor, *system.MockFilesystem) { a := NewAdaptor() fs := a.sys.UseMockFilesystem(mockPaths) if err := a.Connect(); err != nil { panic(err) } return a, fs } func TestNewAdaptor(t *testing.T) { // arrange & act a := NewAdaptor() // assert assert.IsType(t, &Adaptor{}, a) assert.True(t, strings.HasPrefix(a.Name(), "CHIP")) assert.NotNil(t, a.sys) assert.NotNil(t, a.pinMap) assert.NotNil(t, a.DigitalPinsAdaptor) assert.NotNil(t, a.PWMPinsAdaptor) assert.NotNil(t, a.I2cBusAdaptor) assert.Nil(t, a.SpiBusAdaptor) assert.True(t, a.sys.HasDigitalPinSysfsAccess()) // act & assert a.SetName("NewName") assert.Equal(t, "NewName", a.Name()) } func TestNewAdaptorWithOption(t *testing.T) { // arrange & act a := NewAdaptor(adaptors.WithSpiGpioAccess("1", "2", "3", "4")) // assert assert.IsType(t, &Adaptor{}, a) assert.True(t, strings.HasPrefix(a.Name(), "CHIP")) assert.NotNil(t, a.sys) assert.NotNil(t, a.pinMap) assert.NotNil(t, a.DigitalPinsAdaptor) assert.NotNil(t, a.PWMPinsAdaptor) assert.NotNil(t, a.I2cBusAdaptor) assert.NotNil(t, a.SpiBusAdaptor) assert.True(t, a.sys.HasDigitalPinSysfsAccess()) } func TestFinalizeErrorAfterGPIO(t *testing.T) { a, fs := initConnectedTestAdaptorWithMockedFilesystem() require.NoError(t, a.DigitalWrite("CSID7", 1)) fs.WithWriteError = true err := a.Finalize() require.ErrorContains(t, err, "write error") } func TestFinalizeErrorAfterPWM(t *testing.T) { a, fs := initConnectedTestAdaptorWithMockedFilesystem() fs.Files["/sys/class/pwm/pwmchip0/pwm0/duty_cycle"].Contents = "0" fs.Files["/sys/class/pwm/pwmchip0/pwm0/period"].Contents = "0" require.NoError(t, a.PwmWrite("PWM0", 100)) fs.WithWriteError = true err := a.Finalize() require.ErrorContains(t, err, "write error") } func TestDigitalIO(t *testing.T) { a, fs := initConnectedTestAdaptorWithMockedFilesystem() require.NoError(t, a.DigitalWrite("CSID7", 1)) assert.Equal(t, "1", fs.Files["/sys/class/gpio/gpio139/value"].Contents) fs.Files["/sys/class/gpio/gpio50/value"].Contents = "1" i, _ := a.DigitalRead("TWI2-SDA") assert.Equal(t, 1, i) require.ErrorContains(t, a.DigitalWrite("XIO-P10", 1), "'XIO-P10' is not a valid id for a digital pin") require.NoError(t, a.Finalize()) } func TestPWMWrite(t *testing.T) { // arrange a, fs := initConnectedTestAdaptorWithMockedFilesystem() fs.Files["/sys/class/pwm/pwmchip0/pwm0/duty_cycle"].Contents = "0" fs.Files["/sys/class/pwm/pwmchip0/pwm0/period"].Contents = "0" // act err := a.PwmWrite("PWM0", 100) // assert require.NoError(t, err) assert.Equal(t, "0", fs.Files["/sys/class/pwm/pwmchip0/export"].Contents) assert.Equal(t, "1", fs.Files["/sys/class/pwm/pwmchip0/pwm0/enable"].Contents) assert.Equal(t, "3921568", fs.Files["/sys/class/pwm/pwmchip0/pwm0/duty_cycle"].Contents) assert.Equal(t, "10000000", fs.Files["/sys/class/pwm/pwmchip0/pwm0/period"].Contents) // pwmPeriodDefault assert.Equal(t, "normal", fs.Files["/sys/class/pwm/pwmchip0/pwm0/polarity"].Contents) require.NoError(t, a.Finalize()) } func TestServoWrite(t *testing.T) { // arrange: prepare 50Hz for servos const ( pin = "PWM0" fiftyHzNano = 20000000 ) a := NewAdaptor(adaptors.WithPWMDefaultPeriodForPin(pin, fiftyHzNano)) fs := a.sys.UseMockFilesystem(mockPaths) require.NoError(t, a.Connect()) fs.Files["/sys/class/pwm/pwmchip0/pwm0/duty_cycle"].Contents = "0" fs.Files["/sys/class/pwm/pwmchip0/pwm0/period"].Contents = "0" // act & assert for 0° (min default value) err := a.ServoWrite(pin, 0) require.NoError(t, err) assert.Equal(t, strconv.Itoa(fiftyHzNano), fs.Files["/sys/class/pwm/pwmchip0/pwm0/period"].Contents) assert.Equal(t, "500000", fs.Files["/sys/class/pwm/pwmchip0/pwm0/duty_cycle"].Contents) // act & assert for 180° (max default value) err = a.ServoWrite(pin, 180) require.NoError(t, err) assert.Equal(t, strconv.Itoa(fiftyHzNano), fs.Files["/sys/class/pwm/pwmchip0/pwm0/period"].Contents) assert.Equal(t, "2500000", fs.Files["/sys/class/pwm/pwmchip0/pwm0/duty_cycle"].Contents) require.NoError(t, a.Finalize()) } func TestI2cDefaultBus(t *testing.T) { a := NewAdaptor() assert.Equal(t, 1, a.DefaultI2cBus()) } func TestI2cFinalizeWithErrors(t *testing.T) { // arrange a := NewAdaptor() a.sys.UseMockSyscall() fs := a.sys.UseMockFilesystem([]string{"/dev/i2c-2"}) require.NoError(t, a.Connect()) con, err := a.GetI2cConnection(0xff, 2) require.NoError(t, err) _, err = con.Write([]byte{0xbf}) require.NoError(t, err) fs.WithCloseError = true // act err = a.Finalize() // assert require.ErrorContains(t, err, "close error") } func Test_translatePWMPin(t *testing.T) { tests := map[string]struct { usePro bool wantDir string wantChannel int wantErr error }{ "PWM0": { wantDir: "/sys/class/pwm/pwmchip0", wantChannel: 0, }, "PWM1": { usePro: true, wantDir: "/sys/class/pwm/pwmchip0", wantChannel: 1, }, "33_1": { wantDir: "", wantChannel: -1, wantErr: fmt.Errorf("'33_1' is not a valid id for a pin"), }, "AP-EINT3": { wantDir: "", wantChannel: -1, wantErr: fmt.Errorf("'AP-EINT3' is not a valid id for a PWM pin"), }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange var a *Adaptor if tc.usePro { a = NewProAdaptor() } else { a = NewAdaptor() } // act dir, channel, err := a.translatePWMPin(name) // assert assert.Equal(t, tc.wantErr, err) assert.Equal(t, tc.wantDir, dir) assert.Equal(t, tc.wantChannel, channel) }) } } ================================================ FILE: platforms/chip/chip_pinmap.go ================================================ package chip var chipPins = map[string]sysfsPin{ "PWM0": { pin: 34, pwmPin: 0, }, "AP-EINT3": { pin: 35, pwmPin: -1, }, "TWI1-SCK": { pin: 47, pwmPin: -1, }, "TWI1-SDA": { pin: 48, pwmPin: -1, }, "TWI2-SCK": { pin: 49, pwmPin: -1, }, "TWI2-SDA": { pin: 50, pwmPin: -1, }, "LCD-D2": { pin: 98, pwmPin: -1, }, "LCD-D3": { pin: 99, pwmPin: -1, }, "LCD-D4": { pin: 100, pwmPin: -1, }, "LCD-D5": { pin: 101, pwmPin: -1, }, "LCD-D6": { pin: 102, pwmPin: -1, }, "LCD-D7": { pin: 103, pwmPin: -1, }, "LCD-D10": { pin: 106, pwmPin: -1, }, "LCD-D11": { pin: 107, pwmPin: -1, }, "LCD-D12": { pin: 108, pwmPin: -1, }, "LCD-D13": { pin: 109, pwmPin: -1, }, "LCD-D14": { pin: 110, pwmPin: -1, }, "LCD-D15": { pin: 111, pwmPin: -1, }, "LCD-D18": { pin: 114, pwmPin: -1, }, "LCD-D19": { pin: 115, pwmPin: -1, }, "LCD-D20": { pin: 116, pwmPin: -1, }, "LCD-D21": { pin: 117, pwmPin: -1, }, "LCD-D22": { pin: 118, pwmPin: -1, }, "LCD-D23": { pin: 119, pwmPin: -1, }, "LCD-CLK": { pin: 120, pwmPin: -1, }, "LCD-DE": { pin: 121, pwmPin: -1, }, "LCD-HSYNC": { pin: 122, pwmPin: -1, }, "LCD-VSYNC": { pin: 123, pwmPin: -1, }, "CSIPCK": { pin: 128, pwmPin: -1, }, "CSICK": { pin: 129, pwmPin: -1, }, "CSIHSYNC": { pin: 130, pwmPin: -1, }, "CSIVSYNC": { pin: 131, pwmPin: -1, }, "CSID0": { pin: 132, pwmPin: -1, }, "CSID1": { pin: 133, pwmPin: -1, }, "CSID2": { pin: 134, pwmPin: -1, }, "CSID3": { pin: 135, pwmPin: -1, }, "CSID4": { pin: 136, pwmPin: -1, }, "CSID5": { pin: 137, pwmPin: -1, }, "CSID6": { pin: 138, pwmPin: -1, }, "CSID7": { pin: 139, pwmPin: -1, }, "AP-EINT1": { pin: 193, pwmPin: -1, }, "UART1-TX": { pin: 195, pwmPin: -1, }, "UART1-RX": { pin: 196, pwmPin: -1, }, } ================================================ FILE: platforms/chip/chippro_adaptor.go ================================================ package chip import "gobot.io/x/gobot/v2" // NewProAdaptor creates a C.H.I.P. Pro Adaptor func NewProAdaptor() *Adaptor { a := NewAdaptor() a.name = gobot.DefaultName("CHIP Pro") a.pinMap = chipProPins return a } ================================================ FILE: platforms/chip/chippro_adaptor_test.go ================================================ package chip import ( "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2/system" ) func initConnectedTestProAdaptorWithMockedFilesystem() (*Adaptor, *system.MockFilesystem) { a := NewProAdaptor() fs := a.sys.UseMockFilesystem(mockPaths) if err := a.Connect(); err != nil { panic(err) } return a, fs } func TestNewProAdaptor(t *testing.T) { a := NewProAdaptor() assert.True(t, strings.HasPrefix(a.Name(), "CHIP Pro")) assert.True(t, a.sys.HasDigitalPinSysfsAccess()) } func TestProDigitalIO(t *testing.T) { a, fs := initConnectedTestProAdaptorWithMockedFilesystem() require.NoError(t, a.DigitalWrite("CSID7", 1)) assert.Equal(t, "1", fs.Files["/sys/class/gpio/gpio139/value"].Contents) fs.Files["/sys/class/gpio/gpio50/value"].Contents = "1" i, err := a.DigitalRead("TWI2-SDA") assert.Equal(t, 1, i) require.NoError(t, err) require.ErrorContains(t, a.DigitalWrite("XIO-P0", 1), "'XIO-P0' is not a valid id for a digital pin") require.NoError(t, a.Finalize()) } ================================================ FILE: platforms/chip/chippro_pinmap.go ================================================ package chip var chipProPins = map[string]sysfsPin{ "PWM0": { pin: 34, pwmPin: 0, }, "PWM1": { pin: 205, pwmPin: 1, }, "LCD-D2": { pin: 98, pwmPin: -1, }, "LCD-D3": { pin: 99, pwmPin: -1, }, "LCD-D4": { pin: 100, pwmPin: -1, }, "LCD-D5": { pin: 101, pwmPin: -1, }, "LCD-D6": { pin: 102, pwmPin: -1, }, "LCD-D7": { pin: 103, pwmPin: -1, }, "LCD-D10": { pin: 106, pwmPin: -1, }, "LCD-D11": { pin: 107, pwmPin: -1, }, "LCD-D12": { pin: 108, pwmPin: -1, }, "LCD-D13": { pin: 109, pwmPin: -1, }, "LCD-D14": { pin: 110, pwmPin: -1, }, "LCD-D15": { pin: 111, pwmPin: -1, }, "LCD-D18": { pin: 114, pwmPin: -1, }, "LCD-D19": { pin: 115, pwmPin: -1, }, "LCD-D20": { pin: 116, pwmPin: -1, }, "LCD-D21": { pin: 117, pwmPin: -1, }, "LCD-D22": { pin: 118, pwmPin: -1, }, "LCD-D23": { pin: 119, pwmPin: -1, }, "LCD-CLK": { pin: 120, pwmPin: -1, }, "LCD-HSYNC": { pin: 122, pwmPin: -1, }, "LCD-VSYNC": { pin: 123, pwmPin: -1, }, "UART1-TX": { pin: 195, pwmPin: -1, }, "UART1-RX": { pin: 196, pwmPin: -1, }, "AP-EINT1": { pin: 193, pwmPin: -1, }, "AP-EINT3": { pin: 35, pwmPin: -1, }, "TWI2-SCK": { pin: 49, pwmPin: -1, }, "TWI2-SDA": { pin: 50, pwmPin: -1, }, "CSIPCK": { pin: 128, pwmPin: -1, }, "CSICK": { pin: 129, pwmPin: -1, }, "CSIHSYNC": { pin: 130, pwmPin: -1, }, "CSIVSYNC": { pin: 131, pwmPin: -1, }, "CSID0": { pin: 132, pwmPin: -1, }, "CSID1": { pin: 133, pwmPin: -1, }, "CSID2": { pin: 134, pwmPin: -1, }, "CSID3": { pin: 135, pwmPin: -1, }, "CSID4": { pin: 136, pwmPin: -1, }, "CSID5": { pin: 137, pwmPin: -1, }, "CSID6": { pin: 138, pwmPin: -1, }, "CSID7": { pin: 139, pwmPin: -1, }, } ================================================ FILE: platforms/chip/doc.go ================================================ /* Package chip contains the Gobot adaptor for the CHIP and CHIP Pro For further information refer to the chip README: https://github.com/hybridgroup/gobot/blob/release/platforms/chip/README.md */ package chip // import "gobot.io/x/gobot/v2/platforms/chip" ================================================ FILE: platforms/dexter/README.md ================================================ # Dexter This package contains the Gobot drivers for the various Dexter Industries (https://www.dexterindustries.com) robots. This package currently supports the following robots: - [GoPiGo3](https://www.dexterindustries.com/gopigo3/) ================================================ FILE: platforms/dexter/dexter.go ================================================ /* Package dexter contains Gobot drivers for the Dexter Industries robots This package currently supports the following robots: - GoPiGo3 For further information refer to Dexter README: https://github.com/hybridgroup/gobot/blob/release/platforms/dexter/README.md */ package dexter ================================================ FILE: platforms/dexter/gopigo3/README.md ================================================ # GoPiGo3 The GoPiGo3 is a robotics controller by Dexter Industries that is compatible with the Raspberry Pi. ## How to Install Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) ## How to Use This example will blink the left and right leds red/blue. ```go package main import ( "fmt" "time" "gobot.io/x/gobot/v2" g "gobot.io/x/gobot/v2/platforms/dexter/gopigo3" "gobot.io/x/gobot/v2/platforms/raspi" ) func main() { raspiAdaptor := raspi.NewAdaptor() gopigo3 := g.NewDriver(raspiAdaptor) work := func() { on := uint8(0xFF) gobot.Every(1000*time.Millisecond, func() { err := gopigo3.SetLED(g.LED_EYE_RIGHT, 0x00, 0x00, on) if err != nil { fmt.Println(err) } err = gopigo3.SetLED(g.LED_EYE_LEFT, ^on, 0x00, 0x00) if err != nil { fmt.Println(err) } on = ^on }) } robot := gobot.NewRobot("gopigo3", []gobot.Connection{raspiAdaptor}, []gobot.Device{gopigo3}, work, ) if err := robot.Start(); err != nil { panic(err) } } ``` ================================================ FILE: platforms/dexter/gopigo3/driver.go ================================================ // Package gopigo3 is based on https://github.com/DexterInd/GoPiGo3/blob/master/Software/Python/gopigo3.py // You will need to run the following commands if using a stock raspbian image before this library will work: // sudo curl -kL dexterindustries.com/update_gopigo3 | bash // sudo reboot package gopigo3 import ( "bytes" "encoding/binary" "fmt" "log" "math" "time" "github.com/hashicorp/go-multierror" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/spi" ) // spi address for gopigo3 const goPiGo3Address = 0x08 // register addresses for gopigo3 const ( NONE byte = iota GET_MANUFACTURER GET_NAME GET_HARDWARE_VERSION GET_FIRMWARE_VERSION GET_ID SET_LED GET_VOLTAGE_5V GET_VOLTAGE_VCC SET_SERVO SET_MOTOR_PWM SET_MOTOR_POSITION SET_MOTOR_POSITION_KP SET_MOTOR_POSITION_KD SET_MOTOR_DPS SET_MOTOR_LIMITS OFFSET_MOTOR_ENCODER GET_MOTOR_ENCODER_LEFT GET_MOTOR_ENCODER_RIGHT GET_MOTOR_STATUS_LEFT GET_MOTOR_STATUS_RIGHT SET_GROVE_TYPE SET_GROVE_MODE SET_GROVE_STATE SET_GROVE_PWM_DUTY SET_GROVE_PWM_FREQUENCY GET_GROVE_VALUE_1 GET_GROVE_VALUE_2 GET_GROVE_STATE_1_1 GET_GROVE_STATE_1_2 GET_GROVE_STATE_2_1 GET_GROVE_STATE_2_2 GET_GROVE_VOLTAGE_1_1 GET_GROVE_VOLTAGE_1_2 GET_GROVE_VOLTAGE_2_1 GET_GROVE_VOLTAGE_2_2 GET_GROVE_ANALOG_1_1 GET_GROVE_ANALOG_1_2 GET_GROVE_ANALOG_2_1 GET_GROVE_ANALOG_2_2 START_GROVE_I2C_1 START_GROVE_I2C_2 ) const ( // distance (mm) from left wheel to right wheel. This works with the initial GPG3 prototype. Will need to be adjusted. WHEEL_BASE_WIDTH = 117 // wheel diameter (mm) WHEEL_DIAMETER = 66.5 // circumference of the circle the wheels will trace while turning (mm) WHEEL_BASE_CIRCUMFERENCE = WHEEL_BASE_WIDTH * math.Pi // circumference of the wheels (mm) WHEEL_CIRCUMFERENCE = WHEEL_DIAMETER * math.Pi // motor gear ratio MOTOR_GEAR_RATIO = 120 // encoder ticks per motor rotation (number of magnet positions) ENCODER_TICKS_PER_ROTATION = 6 // encoder ticks per output shaft rotation degree MOTOR_TICKS_PER_DEGREE = ((MOTOR_GEAR_RATIO * ENCODER_TICKS_PER_ROTATION) / 360.0) GROVE_I2C_LENGTH_LIMIT = 16 MOTOR_FLOAT = -128 ) // GroveMode sets the mode of AD pins on the gopigo3. type GroveMode byte const ( GROVE_INPUT_DIGITAL GroveMode = 0 GROVE_OUTPUT_DIGITAL GroveMode = 1 GROVE_INPUT_DIGITAL_PULLUP GroveMode = 2 GROVE_INPUT_DIGITAL_PULLDOWN GroveMode = 3 GROVE_INPUT_ANALOG GroveMode = 4 GROVE_OUTPUT_PWM GroveMode = 5 GROVE_INPUT_ANALOG_PULLUP GroveMode = 6 GROVE_INPUT_ANALOG_PULLDOWN GroveMode = 7 ) // Servo contains the address for the 2 servo ports. type Servo byte const ( SERVO_1 Servo = 0x01 SERVO_2 Servo = 0x02 ) // Motor contains the address for the left and right motors. type Motor byte const ( MOTOR_LEFT Motor = 0x01 MOTOR_RIGHT Motor = 0x02 ) // Led contains the addresses for all leds on the board. type Led byte const ( LED_EYE_RIGHT Led = 0x01 LED_EYE_LEFT Led = 0x02 LED_BLINKER_LEFT Led = 0x04 LED_BLINKER_RIGHT Led = 0x08 LED_WIFI Led = 0x80 ) // Grove contains the addresses for pins/ports of the AD1/AD2 grove connector. type Grove byte const ( AD11 string = "AD_1_1" AD12 string = "AD_1_2" AD21 string = "AD_2_1" AD22 string = "AD_2_2" AD_1_1_G Grove = 0x01 // default pin for most grove devices, A0/D0 AD_1_2_G Grove = 0x02 AD_2_1_G Grove = 0x04 // default pin for most grove devices, A0/D0 AD_2_2_G Grove = 0x08 AD_1_G Grove = AD_1_1_G + AD_1_2_G AD_2_G Grove = AD_2_1_G + AD_2_2_G ) // GroveType represents the type of a grove device. type GroveType int const ( CUSTOM GroveType = 1 IR_DI_REMOTE GroveType = 2 IR_EV3_REMOTE GroveType = 3 US GroveType = 4 I2C GroveType = 5 ) // GroveState contains the state of a grove device. type GroveState int const ( VALID_DATA GroveState = iota NOT_CONFIGURED CONFIGURING NO_DATA I2C_ERROR ) // Driver is a Gobot Driver for the GoPiGo3 board. type Driver struct { spi.Config name string connector spi.Connector connection spi.Connection } // NewDriver creates a new Gobot Driver for the GoPiGo3 board. // // Params: // // a *Adaptor - the Adaptor to use with this Driver // // Optional params: // // spi.WithBusNumber(int): bus to use with this driver // spi.WithChipNumber(int): chip to use with this driver // spi.WithMode(int): mode to use with this driver // spi.WithBitCount(int): number of bits to use with this driver // spi.WithSpeed(int64): speed in Hz to use with this driver func NewDriver(a spi.Connector, options ...func(spi.Config)) *Driver { spiConfig := spi.NewConfig() // use /dev/spidev0.1 spiConfig.SetBusNumber(0) spiConfig.SetChipNumber(1) d := &Driver{ name: gobot.DefaultName("GoPiGo3"), connector: a, Config: spiConfig, } for _, option := range options { option(d) } return d } // Name returns the name of the device. func (d *Driver) Name() string { return d.name } // SetName sets the name of the device. func (d *Driver) SetName(n string) { d.name = n } // Connection returns the Connection of the device. func (d *Driver) Connection() gobot.Connection { if conn, ok := d.connection.(gobot.Connection); ok { return conn } log.Printf("%s has no gobot connection\n", d.name) return nil } // Halt stops the driver. func (d *Driver) Halt() error { err := d.resetAll() time.Sleep(10 * time.Millisecond) return err } // Start initializes the GoPiGo3 func (d *Driver) Start() error { bus := d.GetBusNumberOrDefault(d.connector.SpiDefaultBusNumber()) chip := d.GetChipNumberOrDefault(d.connector.SpiDefaultChipNumber()) mode := d.GetModeOrDefault(d.connector.SpiDefaultMode()) bits := d.GetBitCountOrDefault(d.connector.SpiDefaultBitCount()) maxSpeed := d.GetSpeedOrDefault(d.connector.SpiDefaultMaxSpeed()) var err error d.connection, err = d.connector.GetSpiConnection(bus, chip, mode, bits, maxSpeed) return err } // GetManufacturerName returns the manufacturer from the firmware. func (d *Driver) GetManufacturerName() (string, error) { // read 24 bytes to get manufacturer name response, err := d.readBytes(goPiGo3Address, GET_MANUFACTURER, 24) if err != nil { return "", err } if err := d.responseValid(response); err != nil { return "", err } mf := response[4:23] mf = bytes.Trim(mf, "\x00") return string(mf), nil } // GetBoardName returns the board name from the firmware. func (d *Driver) GetBoardName() (string, error) { // read 24 bytes to get board name response, err := d.readBytes(goPiGo3Address, GET_NAME, 24) if err != nil { return "", err } if err := d.responseValid(response); err != nil { return "", err } mf := response[4:23] mf = bytes.Trim(mf, "\x00") return string(mf), nil } // GetHardwareVersion returns the hardware version from the firmware. func (d *Driver) GetHardwareVersion() (string, error) { response, err := d.readUint32(goPiGo3Address, GET_HARDWARE_VERSION) if err != nil { return "", err } major := response / 1000000 minor := response / 1000 % 1000 patch := response % 1000 return fmt.Sprintf("%d.%d.%d", major, minor, patch), nil } // GetFirmwareVersion returns the current firmware version. func (d *Driver) GetFirmwareVersion() (string, error) { response, err := d.readUint32(goPiGo3Address, GET_FIRMWARE_VERSION) if err != nil { return "", err } major := response / 1000000 minor := response / 1000 % 1000 patch := response % 1000 return fmt.Sprintf("%d.%d.%d", major, minor, patch), nil } // GetSerialNumber returns the 128-bit hardware serial number of the board. func (d *Driver) GetSerialNumber() (string, error) { // read 20 bytes to get the serial number response, err := d.readBytes(goPiGo3Address, GET_ID, 20) if err != nil { return "", err } if err := d.responseValid(response); err != nil { return "", err } return fmt.Sprintf("%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", response[4], response[5], response[6], response[7], response[8], response[9], response[10], response[11], response[12], response[13], response[14], response[15], response[16], response[17], response[18], response[19]), nil } // Get5vVoltage returns the current voltage on the 5v line. func (d *Driver) Get5vVoltage() (float32, error) { val, err := d.readUint16(goPiGo3Address, GET_VOLTAGE_5V) return (float32(val) / 1000.0), err } // GetBatteryVoltage gets the battery voltage from the main battery pack (7v-12v). func (d *Driver) GetBatteryVoltage() (float32, error) { val, err := d.readUint16(goPiGo3Address, GET_VOLTAGE_VCC) return (float32(val) / 1000.0), err } // SetLED sets rgb values from 0 to 255. func (d *Driver) SetLED(led Led, red, green, blue uint8) error { return d.writeBytes([]byte{ goPiGo3Address, SET_LED, byte(led), red, green, blue, }) } // SetServo sets a servo's position in microseconds (0-16666). func (d *Driver) SetServo(srvo Servo, us uint16) error { return d.writeBytes([]byte{ goPiGo3Address, SET_SERVO, byte(srvo), byte((us >> 8) & 0xFF), byte(us & 0xFF), }) } // ServoWrite writes an angle (0-180) to the given servo (servo 1 or servo 2). // Must implement the ServoWriter interface of gpio package. func (d *Driver) ServoWrite(port string, angle byte) error { srvo := SERVO_1 // default for unknown ports if port == "2" || port == "SERVO_2" { srvo = SERVO_2 } pulseWidthRange := 1850 if angle > 180 { angle = 180 } pulseWidth := ((1500 - (pulseWidthRange / 2)) + ((pulseWidthRange / 180) * int(angle))) return d.SetServo(srvo, uint16(pulseWidth)) //nolint:gosec // TODO: fix later } // SetMotorPower sets a motor's power from -128 to 127. func (d *Driver) SetMotorPower(motor Motor, power int8) error { return d.writeBytes([]byte{ goPiGo3Address, SET_MOTOR_PWM, byte(motor), byte(power), }) } // SetMotorPosition sets the motor's position in degrees. func (d *Driver) SetMotorPosition(motor Motor, position int) error { positionRaw := position * MOTOR_TICKS_PER_DEGREE return d.writeBytes([]byte{ goPiGo3Address, SET_MOTOR_POSITION, byte(motor), byte((positionRaw >> 24) & 0xFF), byte((positionRaw >> 16) & 0xFF), byte((positionRaw >> 8) & 0xFF), byte(positionRaw & 0xFF), }) } // SetMotorDps sets the motor target speed in degrees per second. func (d *Driver) SetMotorDps(motor Motor, dps int) error { mdps := dps * MOTOR_TICKS_PER_DEGREE return d.writeBytes([]byte{ goPiGo3Address, SET_MOTOR_DPS, byte(motor), byte((mdps >> 8) & 0xFF), byte(mdps & 0xFF), }) } // SetMotorLimits sets the speed limits for a motor. func (d *Driver) SetMotorLimits(motor Motor, power int8, dps int) error { dpsUint := dps * MOTOR_TICKS_PER_DEGREE return d.writeBytes([]byte{ goPiGo3Address, SET_MOTOR_LIMITS, byte(motor), byte(power), byte((dpsUint >> 8) & 0xFF), byte(dpsUint & 0xFF), }) } // GetMotorStatus returns the status for the given motor. // //nolint:nonamedreturns // sufficient here func (d *Driver) GetMotorStatus(motor Motor) (flags uint8, power uint16, encoder, dps int, err error) { message := GET_MOTOR_STATUS_RIGHT if motor == MOTOR_LEFT { message = GET_MOTOR_STATUS_LEFT } response, err := d.readBytes(goPiGo3Address, message, 12) if err != nil { return flags, power, encoder, dps, err } if err := d.responseValid(response); err != nil { return flags, power, encoder, dps, err } // get flags flags = response[4] // get power power = uint16(response[5]) if power&0x80 == 0x80 { power = power - 0x100 } // get encoder enc := make([]byte, 4) enc[3] = response[6] enc[2] = response[7] enc[1] = response[8] enc[0] = response[9] e := binary.LittleEndian.Uint32(enc) encoder = int(e) if e&0x80000000 == 0x80000000 { encoder = int(uint64(e) - 0x100000000) //nolint:gosec // TODO: fix later } // get dps dpsRaw := make([]byte, 4) dpsRaw[1] = response[10] dpsRaw[0] = response[11] ds := binary.LittleEndian.Uint32(dpsRaw) dps = int(ds) if ds&0x8000 == 0x8000 { dps = int(ds - 0x10000) } return flags, power, encoder / MOTOR_TICKS_PER_DEGREE, dps / MOTOR_TICKS_PER_DEGREE, nil } // GetMotorEncoder reads a motor's encoder in degrees. func (d *Driver) GetMotorEncoder(motor Motor) (int64, error) { message := GET_MOTOR_ENCODER_RIGHT if motor == MOTOR_LEFT { message = GET_MOTOR_ENCODER_LEFT } response, err := d.readUint32(goPiGo3Address, message) if err != nil { return 0, err } encoder := int64(response) if response&0x80000000 != 0 { encoder = encoder - 0x100000000 } encoder = encoder / MOTOR_TICKS_PER_DEGREE return encoder, nil } // OffsetMotorEncoder offsets a motor's encoder for calibration purposes. func (d *Driver) OffsetMotorEncoder(motor Motor, offset float64) error { offsetUint := math.Float64bits(offset * MOTOR_TICKS_PER_DEGREE) return d.writeBytes([]byte{ goPiGo3Address, OFFSET_MOTOR_ENCODER, byte(motor), byte((offsetUint >> 24) & 0xFF), byte((offsetUint >> 16) & 0xFF), byte((offsetUint >> 8) & 0xFF), byte(offsetUint & 0xFF), }) } // SetGroveType sets the given port to a grove device type. func (d *Driver) SetGroveType(port Grove, gType GroveType) error { return d.writeBytes([]byte{ goPiGo3Address, SET_GROVE_TYPE, byte(port), byte(gType), }) } // SetGroveMode sets the mode a given pin/port of the grove connector. func (d *Driver) SetGroveMode(port Grove, mode GroveMode) error { return d.writeBytes([]byte{ goPiGo3Address, SET_GROVE_MODE, byte(port), byte(mode), }) } // SetPWMDuty sets the pwm duty cycle for the given pin/port. func (d *Driver) SetPWMDuty(port Grove, duty uint16) error { if duty > 100 { duty = 100 } duty = duty * 10 return d.writeBytes([]byte{ goPiGo3Address, SET_GROVE_PWM_DUTY, byte(port), byte((duty >> 8) & 0xFF), byte(duty & 0xFF), }) } // SetPWMFreq setst the pwm frequency for the given pin/port. func (d *Driver) SetPWMFreq(port Grove, freq uint16) error { if freq < 3 { freq = 3 } if freq > 48000 { freq = 48000 } return d.writeBytes([]byte{ goPiGo3Address, SET_GROVE_PWM_FREQUENCY, byte(port), byte((freq >> 8) & 0xFF), byte(freq & 0xFF), }) } // PwmWrite implents the pwm interface for the gopigo3. func (d *Driver) PwmWrite(pin string, val byte) error { var ( grovePin, grovePort Grove err error ) if grovePin, grovePort, _, _, err = getGroveAddresses(pin); err != nil { return err } if err := d.SetGroveType(grovePort, CUSTOM); err != nil { return err } time.Sleep(10 * time.Millisecond) if err = d.SetGroveMode(grovePin, GROVE_OUTPUT_PWM); err != nil { return err } time.Sleep(10 * time.Millisecond) if err = d.SetPWMFreq(grovePin, 24000); err != nil { return err } val64 := math.Float64frombits(uint64(val)) dutyCycle := uint16(math.Float64bits((100.0 / 255.0) * val64)) //nolint:gosec // TODO: fix later return d.SetPWMDuty(grovePin, dutyCycle) } // AnalogRead returns the analog value of the given pin. func (d *Driver) AnalogRead(pin string) (int, error) { grovePin, grovePort, analogCmd, _, err := getGroveAddresses(pin) if err != nil { return 0, err } if err := d.SetGroveType(grovePort, CUSTOM); err != nil { return 0, err } time.Sleep(10 * time.Millisecond) if err := d.SetGroveMode(grovePin, GROVE_INPUT_ANALOG); err != nil { return 0, err } time.Sleep(10 * time.Millisecond) response, err := d.readBytes(goPiGo3Address, analogCmd, 7) if err != nil { return 0, err } if err := d.responseValid(response); err != nil { return 0, err } if err := d.valueValid(response); err != nil { return 0, err } highBytes := uint16(response[5]) lowBytes := uint16(response[6]) return int((highBytes<<8)&0xFF00) | int(lowBytes&0xFF), nil } // DigitalWrite writes a 0/1 value to the given pin. func (d *Driver) DigitalWrite(pin string, val byte) error { var ( grovePin, grovePort Grove err error ) grovePin, grovePort, _, _, err = getGroveAddresses(pin) if err != nil { return err } if err := d.SetGroveType(grovePort, CUSTOM); err != nil { return err } time.Sleep(10 * time.Millisecond) if err := d.SetGroveMode(grovePin, GROVE_OUTPUT_DIGITAL); err != nil { return err } time.Sleep(10 * time.Millisecond) return d.writeBytes([]byte{ goPiGo3Address, SET_GROVE_STATE, byte(grovePin), val, }) } // DigitalRead reads the 0/1 value from the given pin. func (d *Driver) DigitalRead(pin string) (int, error) { grovePin, grovePort, _, stateCmd, err := getGroveAddresses(pin) if err != nil { return 0, err } err = d.SetGroveType(grovePort, CUSTOM) if err != nil { return 0, err } time.Sleep(10 * time.Millisecond) err = d.SetGroveMode(grovePin, GROVE_INPUT_DIGITAL) if err != nil { return 0, err } time.Sleep(10 * time.Millisecond) response, err := d.readBytes(goPiGo3Address, stateCmd, 6) if err != nil { return 0, err } if err := d.responseValid(response); err != nil { return 0, err } if err := d.valueValid(response); err != nil { return 0, err } return int(response[5]), nil } //nolint:nonamedreturns // sufficient here func getGroveAddresses(pin string) (gPin, gPort Grove, analog, state byte, err error) { switch pin { case "AD_1_1": gPin = AD_1_1_G gPort = AD_1_G analog = GET_GROVE_ANALOG_1_1 state = GET_GROVE_STATE_1_1 case "AD_1_2": gPin = AD_1_2_G gPort = AD_1_G analog = GET_GROVE_ANALOG_1_2 state = GET_GROVE_STATE_1_2 case "AD_2_1": gPin = AD_2_1_G gPort = AD_2_G analog = GET_GROVE_ANALOG_2_1 state = GET_GROVE_STATE_2_1 case "AD_2_2": gPin = AD_2_2_G gPort = AD_2_G analog = GET_GROVE_ANALOG_2_2 state = GET_GROVE_STATE_2_2 default: err = fmt.Errorf("invalid grove pin name") } return gPin, gPort, analog, state, err } func (d *Driver) responseValid(response []byte) error { if response[3] != 0xA5 { return fmt.Errorf("no SPI response, response not valid") } return nil } func (d *Driver) valueValid(value []byte) error { if value[4] != byte(VALID_DATA) { return fmt.Errorf("invalid value") } return nil } func (d *Driver) readBytes(address byte, msg byte, numBytes int) ([]byte, error) { w := make([]byte, numBytes) w[0] = address w[1] = msg r := make([]byte, len(w)) if err := d.connection.ReadCommandData(w, r); err != nil { return nil, err } return r, nil } func (d *Driver) readUint16(address, msg byte) (uint16, error) { r, err := d.readBytes(address, msg, 8) if err != nil { return 0, err } if err := d.responseValid(r); err != nil { return 0, err } return uint16(r[4])<<8 | uint16(r[5]), nil } func (d *Driver) readUint32(address, msg byte) (uint32, error) { r, err := d.readBytes(address, msg, 8) if err != nil { return 0, err } if err := d.responseValid(r); err != nil { return 0, err } return uint32(r[4])<<24 | uint32(r[5])<<16 | uint32(r[6])<<8 | uint32(r[7]), nil } func (d *Driver) writeBytes(w []byte) error { return d.connection.WriteBytes(w) } func (d *Driver) resetAll() error { err := d.SetGroveType(AD_1_G+AD_2_G, CUSTOM) time.Sleep(10 * time.Millisecond) if e := d.SetGroveMode(AD_1_G+AD_2_G, GROVE_INPUT_DIGITAL); e != nil { err = multierror.Append(err, e) } time.Sleep(10 * time.Millisecond) if e := d.SetMotorPower(MOTOR_LEFT+MOTOR_RIGHT, 0.0); e != nil { err = multierror.Append(err, e) } if e := d.SetMotorLimits(MOTOR_LEFT+MOTOR_RIGHT, 0, 0); e != nil { err = multierror.Append(err, e) } if e := d.SetServo(SERVO_1+SERVO_2, 0); e != nil { err = multierror.Append(err, e) } if e := d.SetLED(LED_EYE_LEFT+LED_EYE_RIGHT+LED_BLINKER_LEFT+LED_BLINKER_RIGHT, 0, 0, 0); e != nil { err = multierror.Append(err, e) } return err } ================================================ FILE: platforms/dexter/gopigo3/driver_test.go ================================================ package gopigo3 import ( "encoding/hex" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/spi" ) var ( _ gobot.Driver = (*Driver)(nil) negativeEncoder = false ) func initTestDriver() *Driver { d := NewDriver(&TestConnector{}) _ = d.Start() return d } func TestDriverStart(t *testing.T) { d := initTestDriver() require.NoError(t, d.Start()) } func TestDriverHalt(t *testing.T) { d := initTestDriver() require.NoError(t, d.Halt()) } func TestDriverManufacturerName(t *testing.T) { wantName := "Dexter Industries" d := initTestDriver() name, err := d.GetManufacturerName() require.NoError(t, err) assert.Equal(t, wantName, name) } func TestDriverBoardName(t *testing.T) { wantBoardName := "GoPiGo3" d := initTestDriver() name, err := d.GetBoardName() require.NoError(t, err) assert.Equal(t, wantBoardName, name) } func TestDriverHardwareVersion(t *testing.T) { wantHwVer := "3.1.3" d := initTestDriver() ver, err := d.GetHardwareVersion() require.NoError(t, err) assert.Equal(t, wantHwVer, ver) } func TestDriverFirmareVersion(t *testing.T) { wantFwVer := "0.3.4" d := initTestDriver() ver, err := d.GetFirmwareVersion() require.NoError(t, err) assert.Equal(t, wantFwVer, ver) } func TestGetSerialNumber(t *testing.T) { wantSerialNumber := "E0180A54514E343732202020FF112137" d := initTestDriver() serial, err := d.GetSerialNumber() require.NoError(t, err) assert.Equal(t, wantSerialNumber, serial) } func TestGetFiveVolts(t *testing.T) { wantVoltage := float32(5.047000) d := initTestDriver() voltage, err := d.Get5vVoltage() require.NoError(t, err) assert.InDelta(t, wantVoltage, voltage, 0.0) } func TestGetBatVolts(t *testing.T) { wantBatVoltage := float32(15.411000) d := initTestDriver() voltage, err := d.GetBatteryVoltage() require.NoError(t, err) assert.InDelta(t, wantBatVoltage, voltage, 0.0) } func TestGetMotorStatus(t *testing.T) { wantPower := uint16(65408) d := initTestDriver() f1, power, f2, f3, err := d.GetMotorStatus(MOTOR_LEFT) require.NoError(t, err) assert.Equal(t, wantPower, power) assert.Equal(t, uint8(0), f1) assert.Equal(t, 0, f2) assert.Equal(t, 0, f3) } func TestGetEncoderStatusPos(t *testing.T) { negativeEncoder = false wantEncoderValue := int64(127) d := initTestDriver() encoderValue, err := d.GetMotorEncoder(MOTOR_LEFT) require.NoError(t, err) assert.Equal(t, wantEncoderValue, encoderValue) } func TestGetEncoderStatusNeg(t *testing.T) { negativeEncoder = true wantEncoderValue := int64(-128) d := initTestDriver() encoderValue, err := d.GetMotorEncoder(MOTOR_LEFT) require.NoError(t, err) assert.Equal(t, wantEncoderValue, encoderValue) } func TestAnalogRead(t *testing.T) { wantVal := 160 d := initTestDriver() val, err := d.AnalogRead("AD_1_1") require.NoError(t, err) assert.Equal(t, wantVal, val) } func TestDigitalRead(t *testing.T) { wantVal := 1 d := initTestDriver() val, err := d.DigitalRead("AD_1_2") require.NoError(t, err) assert.Equal(t, wantVal, val) } func TestServoWrite(t *testing.T) { d := initTestDriver() err := d.ServoWrite("SERVO_1", 0x7F) require.NoError(t, err) } func TestSetMotorPosition(t *testing.T) { d := initTestDriver() err := d.SetMotorPosition(MOTOR_LEFT, 12.0) require.NoError(t, err) } func TestSetMotorPower(t *testing.T) { d := initTestDriver() err := d.SetMotorPower(MOTOR_LEFT, 127) require.NoError(t, err) } func TestSetMotorDps(t *testing.T) { d := initTestDriver() err := d.SetMotorDps(MOTOR_LEFT, 12.0) require.NoError(t, err) } func TestOffsetMotorEncoder(t *testing.T) { d := initTestDriver() err := d.OffsetMotorEncoder(MOTOR_LEFT, 12.0) require.NoError(t, err) } func TestSetPWMDuty(t *testing.T) { d := initTestDriver() err := d.SetPWMDuty(AD_1_1_G, 80) require.NoError(t, err) } func TestSetPWMfreq(t *testing.T) { d := initTestDriver() err := d.SetPWMFreq(AD_1_2_G, 100) require.NoError(t, err) } func TestPwmWrite(t *testing.T) { d := initTestDriver() err := d.PwmWrite("AD_2_2", 80) require.NoError(t, err) } func TestDigitalWrite(t *testing.T) { d := initTestDriver() err := d.DigitalWrite("AD_2_1", 1) require.NoError(t, err) } type TestConnector struct{} func (ctr *TestConnector) GetSpiConnection(busNum, chipNum, mode, bits int, maxSpeed int64) (spi.Connection, error) { return TestSpiDevice{}, nil } func (ctr *TestConnector) SpiDefaultBusNumber() int { return 0 } func (ctr *TestConnector) SpiDefaultChipNumber() int { return 0 } func (ctr *TestConnector) SpiDefaultMode() int { return 0 } func (ctr *TestConnector) SpiDefaultBitCount() int { return 8 } func (ctr *TestConnector) SpiDefaultMaxSpeed() int64 { return 0 } type TestSpiDevice struct{} func (c TestSpiDevice) Close() error { return nil } func (c TestSpiDevice) ReadByteData(byte) (byte, error) { return 0, nil } func (c TestSpiDevice) ReadBlockData(byte, []byte) error { return nil } func (c TestSpiDevice) WriteByte(byte) error { return nil } func (c TestSpiDevice) WriteByteData(byte, byte) error { return nil } func (c TestSpiDevice) WriteBlockData(byte, []byte) error { return nil } func (c TestSpiDevice) WriteBytes([]byte) error { return nil } func (c TestSpiDevice) ReadCommandData(w, r []byte) error { manName, _ := hex.DecodeString("ff0000a544657874657220496e6475737472696573000000") boardName, _ := hex.DecodeString("ff0000a5476f5069476f3300000000000000000000000000") hwVersion, _ := hex.DecodeString("ff0000a5002dcaab") fwVersion, _ := hex.DecodeString("ff0000a500000bbc") serialNum, _ := hex.DecodeString("ff0000a5e0180a54514e343732202020ff112137") fiveVoltVoltage, _ := hex.DecodeString("ff0000a513b7") batteryVoltage, _ := hex.DecodeString("ff0000a53c33") negMotorEncoder, _ := hex.DecodeString("ff0000a5ffffff00") motorEncoder, _ := hex.DecodeString("ff0000a5000000ff") motorStatus, _ := hex.DecodeString("ff0000a50080000000000000") analogValue, _ := hex.DecodeString("ff0000a50000a0") buttonPush, _ := hex.DecodeString("ff0000a50001") switch w[1] { case 1: copy(r, manName) return nil case 2: copy(r, boardName) return nil case 3: copy(r, hwVersion) return nil case 4: copy(r, fwVersion) return nil case 5: copy(r, serialNum) return nil case 7: copy(r, fiveVoltVoltage) return nil case 8: copy(r, batteryVoltage) return nil case 17: if negativeEncoder { copy(r, negMotorEncoder) return nil } copy(r, motorEncoder) return nil case 19: copy(r, motorStatus) return nil case 29: copy(r, buttonPush) return nil case 36: copy(r, analogValue) return nil } return nil } ================================================ FILE: platforms/digispark/LICENSE ================================================ Copyright (c) 2013-2018 The Hybrid Group Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: platforms/digispark/README.md ================================================ # Digispark The Digispark is an Attiny85 based microcontroller development board similar to the Arduino line, only cheaper, smaller, and a bit less powerful. With a whole host of shields to extend its functionality and the ability to use the familiar Arduino IDE the Digispark is a great way to jump into electronics, or perfect for when an Arduino is too big or too much. This package provides the Gobot adaptor for the [Digispark](http://digistump.com/products/1) ATTiny-based USB development board with the [Little Wire](http://littlewire.github.io/) protocol firmware installed. ## How to Install Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) This package requires `libusb`. ### OSX To install `libusb` on OSX using Homebrew: ```sh brew install libusb && brew install libusb-compat ``` ### Ubuntu To install libusb on linux: ```sh sudo apt-get install libusb-dev ``` ## How to Use ```go package main import ( "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/digispark" ) func main() { digisparkAdaptor := digispark.NewAdaptor() led := gpio.NewLedDriver(digisparkAdaptor, "0") work := func() { gobot.Every(1*time.Second, func() { if err := led.Toggle(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("blinkBot", []gobot.Connection{digisparkAdaptor}, []gobot.Device{led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ``` Build your application with build tag "libusb". ## How to Connect If your Digispark already has the Little Wire protocol firmware installed, you can connect right away with Gobot. Otherwise, you must first flash your Digispark with the Little Wire firmware. The easiest way to flash your Digispark is to use Gort [https://gort.io](https://gort.io). Download and install Gort, and then use the following commands: Then, install the needed Digispark firmware. ```sh gort digispark install ``` ### Connect on OSX **Important**: 2012 MBP The USB ports on the 2012 MBPs (Retina and non) cause issues due to their USB3 controllers, currently the best work around is to use a cheap USB hub (non USB3). Plug the Digispark into your computer via the USB port and run: ```sh gort digispark upload littlewire ``` ### Connect on Ubuntu Ubuntu requires an extra one-time step to set up the Digispark for communication with Gobot. Run the following command: ```sh gort digispark set-udev-rules ``` You might need to enter your administrative password. This steps adds a udev rule to allow access to the Digispark device. Once this is done, you can upload Little Wire to your Digispark: ```sh gort digispark upload littlewire ``` ### Connect on Windows We need instructions here, because it supposedly works. ### Manual instructions For manual instructions on how to install Little Wire on a Digispark check out Thanks to [@bluebie](https://github.com/Bluebie) for these instructions! () Now plug the Digispark into your computer via the USB port. ================================================ FILE: platforms/digispark/digispark_adaptor.go ================================================ //go:build libusb // +build libusb package digispark import ( "errors" "fmt" "strconv" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" ) // ErrConnection is the error resulting of a connection error with the digispark var ErrConnection = errors.New("connection error") // Adaptor is the Gobot Adaptor for the Digispark type Adaptor struct { name string littleWire lw servo bool pwm bool i2c bool connect func(*Adaptor) error } // NewAdaptor returns a new Digispark Adaptor func NewAdaptor() *Adaptor { return &Adaptor{ name: gobot.DefaultName("Digispark"), connect: func(d *Adaptor) error { d.littleWire = littleWireConnect() //nolint:forcetypeassert // ok here if d.littleWire.(*littleWire).lwHandle == nil { return ErrConnection } return nil }, } } // Name returns the Digispark adaptors name func (d *Adaptor) Name() string { return d.name } // SetName sets the Digispark adaptors name func (d *Adaptor) SetName(n string) { d.name = n } // Connect starts a connection to the digispark func (d *Adaptor) Connect() error { return d.connect(d) } // Finalize implements the Adaptor interface func (d *Adaptor) Finalize() error { return nil } // DigitalWrite writes a value to the pin. Acceptable values are 1 or 0. func (d *Adaptor) DigitalWrite(pin string, level byte) error { p, err := strconv.Atoi(pin) if err != nil { return err } //nolint:gosec // TODO: fix later if err := d.littleWire.pinMode(uint8(p), 0); err != nil { return err } //nolint:gosec // TODO: fix later return d.littleWire.digitalWrite(uint8(p), level) } // PwmWrite writes the 0-254 value to the specified pin func (d *Adaptor) PwmWrite(pin string, value byte) error { if !d.pwm { if err := d.littleWire.pwmInit(); err != nil { return err } if err := d.littleWire.pwmUpdatePrescaler(1); err != nil { return err } d.pwm = true } return d.littleWire.pwmUpdateCompare(value, value) } // ServoWrite writes the 0-180 degree val to the specified pin. func (d *Adaptor) ServoWrite(pin string, angle uint8) error { if !d.servo { if err := d.littleWire.servoInit(); err != nil { return err } d.servo = true } return d.littleWire.servoUpdateLocation(angle, angle) } // GetI2cConnection returns an i2c connection to a device on a specified bus. // Only supports bus number 0 func (d *Adaptor) GetI2cConnection(address int, bus int) (i2c.Connection, error) { if bus != 0 { return nil, fmt.Errorf("invalid bus number %d, only 0 is supported", bus) } //nolint:gosec // TODO: fix later c := NewDigisparkI2cConnection(d, uint8(address)) if err := c.Init(); err != nil { return nil, err } return i2c.Connection(c), nil } // DefaultI2cBus returns the default i2c bus for this platform func (d *Adaptor) DefaultI2cBus() int { return 0 } ================================================ FILE: platforms/digispark/digispark_adaptor_test.go ================================================ //go:build libusb // +build libusb //nolint:forcetypeassert // ok here package digispark import ( "errors" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" ) var _ gobot.Adaptor = (*Adaptor)(nil) var ( _ gpio.DigitalWriter = (*Adaptor)(nil) _ gpio.PwmWriter = (*Adaptor)(nil) _ gpio.ServoWriter = (*Adaptor)(nil) ) type mock struct { locationA uint8 locationB uint8 pwmChannelA uint8 pwmChannelB uint8 pwmPrescalerValue uint pin uint8 mode uint8 state uint8 } // setup mock for GPIO, PWM and servo tests func (l *mock) digitalWrite(pin uint8, state uint8) error { l.pin = pin l.state = state return l.error() } func (l *mock) pinMode(pin uint8, mode uint8) error { l.pin = pin l.mode = mode return l.error() } var pwmInitErrorFunc = func() error { return nil } func (l *mock) pwmInit() error { return pwmInitErrorFunc() } func (l *mock) pwmStop() error { return l.error() } func (l *mock) pwmUpdateCompare(channelA uint8, channelB uint8) error { l.pwmChannelA = channelA l.pwmChannelB = channelB return l.error() } func (l *mock) pwmUpdatePrescaler(value uint) error { l.pwmPrescalerValue = value return l.error() } func (l *mock) servoInit() error { return l.error() } func (l *mock) servoUpdateLocation(locationA uint8, locationB uint8) error { l.locationA = locationA l.locationB = locationB return l.error() } var errorFunc = func() error { return nil } func (l *mock) error() error { return errorFunc() } // i2c functions unused in this test scenarios func (l *mock) i2cInit() error { return nil } func (l *mock) i2cStart(address7bit uint8, direction uint8) error { return nil } func (l *mock) i2cWrite(sendBuffer []byte, length int, endWithStop uint8) error { return nil } func (l *mock) i2cRead(readBuffer []byte, length int, endWithStop uint8) error { return nil } func (l *mock) i2cUpdateDelay(duration uint) error { return nil } func initTestAdaptor() *Adaptor { a := NewAdaptor() a.connect = func(a *Adaptor) error { return nil } a.littleWire = new(mock) errorFunc = func() error { return nil } pwmInitErrorFunc = func() error { return nil } return a } func TestDigisparkAdaptorName(t *testing.T) { a := NewAdaptor() assert.True(t, strings.HasPrefix(a.Name(), "Digispark")) a.SetName("NewName") assert.Equal(t, "NewName", a.Name()) } func TestDigisparkAdaptorConnect(t *testing.T) { a := initTestAdaptor() require.NoError(t, a.Connect()) } func TestDigisparkAdaptorFinalize(t *testing.T) { a := initTestAdaptor() require.NoError(t, a.Finalize()) } func TestDigisparkAdaptorDigitalWrite(t *testing.T) { a := initTestAdaptor() err := a.DigitalWrite("0", uint8(1)) require.NoError(t, err) assert.Equal(t, uint8(0), a.littleWire.(*mock).pin) assert.Equal(t, uint8(1), a.littleWire.(*mock).state) err = a.DigitalWrite("?", uint8(1)) require.Error(t, err) errorFunc = func() error { return errors.New("pin mode error") } err = a.DigitalWrite("0", uint8(1)) require.ErrorContains(t, err, "pin mode error") } func TestDigisparkAdaptorServoWrite(t *testing.T) { a := initTestAdaptor() err := a.ServoWrite("2", uint8(80)) require.NoError(t, err) assert.Equal(t, uint8(80), a.littleWire.(*mock).locationA) assert.Equal(t, uint8(80), a.littleWire.(*mock).locationB) a = initTestAdaptor() errorFunc = func() error { return errors.New("servo error") } err = a.ServoWrite("2", uint8(80)) require.ErrorContains(t, err, "servo error") } func TestDigisparkAdaptorPwmWrite(t *testing.T) { a := initTestAdaptor() err := a.PwmWrite("1", uint8(100)) require.NoError(t, err) assert.Equal(t, uint8(100), a.littleWire.(*mock).pwmChannelA) assert.Equal(t, uint8(100), a.littleWire.(*mock).pwmChannelB) a = initTestAdaptor() pwmInitErrorFunc = func() error { return errors.New("pwminit error") } err = a.PwmWrite("1", uint8(100)) require.ErrorContains(t, err, "pwminit error") a = initTestAdaptor() errorFunc = func() error { return errors.New("pwm error") } err = a.PwmWrite("1", uint8(100)) require.ErrorContains(t, err, "pwm error") } ================================================ FILE: platforms/digispark/digispark_i2c.go ================================================ //go:build libusb // +build libusb package digispark import ( "errors" "fmt" "sync" ) // digisparkI2cConnection implements the interface gobot.I2cOperations type digisparkI2cConnection struct { address uint8 adaptor *Adaptor mtx sync.Mutex } // NewDigisparkI2cConnection creates an i2c connection to an i2c device at // the specified address func NewDigisparkI2cConnection(adaptor *Adaptor, address uint8) *digisparkI2cConnection { return &digisparkI2cConnection{adaptor: adaptor, address: address} } // Init makes sure that the i2c device is already initialized func (c *digisparkI2cConnection) Init() error { if !c.adaptor.i2c { if err := c.adaptor.littleWire.i2cInit(); err != nil { return err } c.adaptor.i2c = true } return nil } // Test tests i2c connection with the given address func (c *digisparkI2cConnection) Test(address uint8) error { if !c.adaptor.i2c { return errors.New("Digispark i2c not initialized") } return c.adaptor.littleWire.i2cStart(address, 0) } // UpdateDelay updates i2c signal delay amount; tune if necessary to fit your requirements func (c *digisparkI2cConnection) UpdateDelay(duration uint) error { if !c.adaptor.i2c { return errors.New("Digispark i2c not initialized") } return c.adaptor.littleWire.i2cUpdateDelay(duration) } // Read tries to read a full buffer from the i2c device. // Returns an empty array if the response from the board has timed out. func (c *digisparkI2cConnection) Read(b []byte) (int, error) { c.mtx.Lock() defer c.mtx.Unlock() return c.readInternal(b) } // Write writes the buffer content in data to the i2c device. func (c *digisparkI2cConnection) Write(data []byte) (int, error) { c.mtx.Lock() defer c.mtx.Unlock() return c.writeInternal(data, true) } // Close do nothing than return nil. func (c *digisparkI2cConnection) Close() error { return nil } // ReadByte reads one byte from the i2c device. func (c *digisparkI2cConnection) ReadByte() (byte, error) { c.mtx.Lock() defer c.mtx.Unlock() buf := []byte{0} if err := c.readAndCheckCount(buf); err != nil { return 0, err } val := buf[0] return val, nil } // ReadByteData reads one byte of the given register address from the i2c device. func (c *digisparkI2cConnection) ReadByteData(reg uint8) (uint8, error) { c.mtx.Lock() defer c.mtx.Unlock() if err := c.writeAndCheckCount([]byte{reg}, false); err != nil { return 0, err } buf := []byte{0} if err := c.readAndCheckCount(buf); err != nil { return 0, err } val := buf[0] return val, nil } // ReadWordData reads two bytes of the given register address from the i2c device. func (c *digisparkI2cConnection) ReadWordData(reg uint8) (uint16, error) { c.mtx.Lock() defer c.mtx.Unlock() if err := c.writeAndCheckCount([]byte{reg}, false); err != nil { return 0, err } buf := []byte{0, 0} if err := c.readAndCheckCount(buf); err != nil { return 0, err } low, high := buf[0], buf[1] val := (uint16(high) << 8) | uint16(low) return val, nil } // ReadBlockData reads a block of maximum 32 bytes from the given register address of the i2c device. func (c *digisparkI2cConnection) ReadBlockData(reg uint8, data []byte) error { c.mtx.Lock() defer c.mtx.Unlock() if err := c.writeAndCheckCount([]byte{reg}, false); err != nil { return err } if len(data) > 32 { data = data[:32] } return c.readAndCheckCount(data) } // WriteByte writes one byte to the i2c device. func (c *digisparkI2cConnection) WriteByte(val byte) error { c.mtx.Lock() defer c.mtx.Unlock() buf := []byte{val} return c.writeAndCheckCount(buf, true) } // WriteByteData writes one byte to the given register address of the i2c device. func (c *digisparkI2cConnection) WriteByteData(reg uint8, val byte) error { c.mtx.Lock() defer c.mtx.Unlock() buf := []byte{reg, val} return c.writeAndCheckCount(buf, true) } // WriteWordData writes two bytes to the given register address of the i2c device. func (c *digisparkI2cConnection) WriteWordData(reg uint8, val uint16) error { c.mtx.Lock() defer c.mtx.Unlock() low := uint8(val & 0xff) //nolint:gosec // ok here high := uint8((val >> 8) & 0xff) //nolint:gosec // ok here buf := []byte{reg, low, high} return c.writeAndCheckCount(buf, true) } // WriteBlockData writes a block of maximum 32 bytes to the given register address of the i2c device. func (c *digisparkI2cConnection) WriteBlockData(reg uint8, data []byte) error { c.mtx.Lock() defer c.mtx.Unlock() if len(data) > 32 { data = data[:32] } buf := make([]byte, len(data)+1) copy(buf[1:], data) buf[0] = reg return c.writeAndCheckCount(buf, true) } // WriteBytes writes a block of maximum 32 bytes to the current register address of the i2c device. func (c *digisparkI2cConnection) WriteBytes(buf []byte) error { c.mtx.Lock() defer c.mtx.Unlock() if len(buf) > 32 { buf = buf[:32] } return c.writeAndCheckCount(buf, true) } func (c *digisparkI2cConnection) readAndCheckCount(buf []byte) error { countRead, err := c.readInternal(buf) if err != nil { return err } expectedCount := len(buf) if countRead != expectedCount { return fmt.Errorf("digispark i2c read %d bytes, expected %d bytes", countRead, expectedCount) } return nil } func (c *digisparkI2cConnection) writeAndCheckCount(buf []byte, finalStop bool) error { countWritten, err := c.writeInternal(buf, finalStop) if err != nil { return err } expectedCount := len(buf) if countWritten != expectedCount { return fmt.Errorf("digispark i2c write %d bytes, expected %d bytes", countWritten, expectedCount) } return nil } func (c *digisparkI2cConnection) readInternal(b []byte) (int, error) { if !c.adaptor.i2c { err := errors.New("digispark i2c not initialized") return 0, err } if err := c.adaptor.littleWire.i2cStart(c.address, 1); err != nil { return 0, err } l := 8 stop := uint8(0) var countRead int for stop == 0 { if countRead+l >= len(b) { l = len(b) - countRead stop = 1 } if err := c.adaptor.littleWire.i2cRead(b[countRead:countRead+l], l, stop); err != nil { return countRead, err } countRead += l } return countRead, nil } func (c *digisparkI2cConnection) writeInternal(data []byte, finalStop bool) (int, error) { if !c.adaptor.i2c { return 0, errors.New("digispark i2c not initialized") } if err := c.adaptor.littleWire.i2cStart(c.address, 0); err != nil { return 0, err } l := 4 lastQuadruplet := false stop := uint8(0) var countWritten int for !lastQuadruplet { if countWritten+l >= len(data) { lastQuadruplet = true l = len(data) - countWritten if finalStop { stop = 1 } } if err := c.adaptor.littleWire.i2cWrite(data[countWritten:countWritten+l], l, stop); err != nil { return countWritten, err } countWritten += l } return countWritten, nil } ================================================ FILE: platforms/digispark/digispark_i2c_test.go ================================================ //go:build libusb // +build libusb //nolint:forcetypeassert // ok here package digispark import ( "fmt" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2/drivers/i2c" ) const ( availableI2cAddress = 0x40 maxUint8 = ^uint8(0) ) var ( _ i2c.Connector = (*Adaptor)(nil) i2cData = []byte{5, 4, 3, 2, 1, 0} ) type i2cMock struct { duration uint direction uint8 dataWritten []byte writeStartWasSend bool writeStopWasSend bool readStartWasSend bool readStopWasSend bool } func initTestAdaptorI2c() *Adaptor { a := NewAdaptor() a.connect = func(a *Adaptor) error { return nil } a.littleWire = new(i2cMock) return a } func TestDigisparkAdaptorI2cGetI2cConnection(t *testing.T) { // arrange var c i2c.Connection var err error a := initTestAdaptorI2c() // act c, err = a.GetI2cConnection(availableI2cAddress, a.DefaultI2cBus()) // assert require.NoError(t, err) assert.NotNil(t, c) } func TestDigisparkAdaptorI2cGetI2cConnectionFailWithInvalidBus(t *testing.T) { // arrange a := initTestAdaptorI2c() // act c, err := a.GetI2cConnection(0x40, 1) // assert require.ErrorContains(t, err, "invalid bus number 1, only 0 is supported") assert.Nil(t, c) } func TestDigisparkAdaptorI2cStartFailWithWrongAddress(t *testing.T) { // arrange data := []byte{0, 1, 2, 3, 4} a := initTestAdaptorI2c() c, _ := a.GetI2cConnection(0x39, a.DefaultI2cBus()) // act count, err := c.Write(data) // assert assert.Equal(t, 0, count) require.ErrorContains(t, err, fmt.Sprintf("invalid address, only %d is supported", availableI2cAddress)) assert.Equal(t, maxUint8, a.littleWire.(*i2cMock).direction) } func TestDigisparkAdaptorI2cWrite(t *testing.T) { // arrange data := []byte{0, 1, 2, 3, 4} dataLen := len(data) a := initTestAdaptorI2c() c, _ := a.GetI2cConnection(availableI2cAddress, a.DefaultI2cBus()) // act count, err := c.Write(data) // assert require.NoError(t, err) assert.True(t, a.littleWire.(*i2cMock).writeStartWasSend) assert.False(t, a.littleWire.(*i2cMock).readStartWasSend) assert.Equal(t, uint8(0), a.littleWire.(*i2cMock).direction) assert.Equal(t, dataLen, count) assert.Equal(t, data, a.littleWire.(*i2cMock).dataWritten) assert.True(t, a.littleWire.(*i2cMock).writeStopWasSend) assert.False(t, a.littleWire.(*i2cMock).readStopWasSend) } func TestDigisparkAdaptorI2cWriteByte(t *testing.T) { // arrange data := byte(0x02) a := initTestAdaptorI2c() c, _ := a.GetI2cConnection(availableI2cAddress, a.DefaultI2cBus()) // act err := c.WriteByte(data) // assert require.NoError(t, err) assert.True(t, a.littleWire.(*i2cMock).writeStartWasSend) assert.False(t, a.littleWire.(*i2cMock).readStartWasSend) assert.Equal(t, uint8(0), a.littleWire.(*i2cMock).direction) assert.Equal(t, []byte{data}, a.littleWire.(*i2cMock).dataWritten) assert.True(t, a.littleWire.(*i2cMock).writeStopWasSend) assert.False(t, a.littleWire.(*i2cMock).readStopWasSend) } func TestDigisparkAdaptorI2cWriteByteData(t *testing.T) { // arrange reg := uint8(0x03) data := byte(0x09) a := initTestAdaptorI2c() c, _ := a.GetI2cConnection(availableI2cAddress, a.DefaultI2cBus()) // act err := c.WriteByteData(reg, data) // assert require.NoError(t, err) assert.True(t, a.littleWire.(*i2cMock).writeStartWasSend) assert.False(t, a.littleWire.(*i2cMock).readStartWasSend) assert.Equal(t, uint8(0), a.littleWire.(*i2cMock).direction) assert.Equal(t, []byte{reg, data}, a.littleWire.(*i2cMock).dataWritten) assert.True(t, a.littleWire.(*i2cMock).writeStopWasSend) assert.False(t, a.littleWire.(*i2cMock).readStopWasSend) } func TestDigisparkAdaptorI2cWriteWordData(t *testing.T) { // arrange reg := uint8(0x04) data := uint16(0x0508) a := initTestAdaptorI2c() c, _ := a.GetI2cConnection(availableI2cAddress, a.DefaultI2cBus()) // act err := c.WriteWordData(reg, data) // assert require.NoError(t, err) assert.True(t, a.littleWire.(*i2cMock).writeStartWasSend) assert.False(t, a.littleWire.(*i2cMock).readStartWasSend) assert.Equal(t, uint8(0), a.littleWire.(*i2cMock).direction) assert.Equal(t, []byte{reg, 0x08, 0x05}, a.littleWire.(*i2cMock).dataWritten) assert.True(t, a.littleWire.(*i2cMock).writeStopWasSend) assert.False(t, a.littleWire.(*i2cMock).readStopWasSend) } func TestDigisparkAdaptorI2cWriteBlockData(t *testing.T) { // arrange reg := uint8(0x05) data := []byte{0x80, 0x81, 0x82} a := initTestAdaptorI2c() c, _ := a.GetI2cConnection(availableI2cAddress, a.DefaultI2cBus()) // act err := c.WriteBlockData(reg, data) // assert require.NoError(t, err) assert.True(t, a.littleWire.(*i2cMock).writeStartWasSend) assert.False(t, a.littleWire.(*i2cMock).readStartWasSend) assert.Equal(t, uint8(0), a.littleWire.(*i2cMock).direction) assert.Equal(t, append([]byte{reg}, data...), a.littleWire.(*i2cMock).dataWritten) assert.True(t, a.littleWire.(*i2cMock).writeStopWasSend) assert.False(t, a.littleWire.(*i2cMock).readStopWasSend) } func TestDigisparkAdaptorI2cRead(t *testing.T) { // arrange data := []byte{0, 1, 2, 3, 4} dataLen := len(data) a := initTestAdaptorI2c() c, _ := a.GetI2cConnection(availableI2cAddress, a.DefaultI2cBus()) // act count, err := c.Read(data) // assert assert.Equal(t, dataLen, count) require.NoError(t, err) assert.False(t, a.littleWire.(*i2cMock).writeStartWasSend) assert.True(t, a.littleWire.(*i2cMock).readStartWasSend) assert.Equal(t, uint8(1), a.littleWire.(*i2cMock).direction) assert.Equal(t, i2cData[:dataLen], data) assert.False(t, a.littleWire.(*i2cMock).writeStopWasSend) assert.True(t, a.littleWire.(*i2cMock).readStopWasSend) } func TestDigisparkAdaptorI2cReadByte(t *testing.T) { // arrange a := initTestAdaptorI2c() c, _ := a.GetI2cConnection(availableI2cAddress, a.DefaultI2cBus()) // act data, err := c.ReadByte() // assert require.NoError(t, err) assert.False(t, a.littleWire.(*i2cMock).writeStartWasSend) assert.True(t, a.littleWire.(*i2cMock).readStartWasSend) assert.Equal(t, uint8(1), a.littleWire.(*i2cMock).direction) assert.Equal(t, i2cData[0], data) assert.False(t, a.littleWire.(*i2cMock).writeStopWasSend) assert.True(t, a.littleWire.(*i2cMock).readStopWasSend) } func TestDigisparkAdaptorI2cReadByteData(t *testing.T) { // arrange reg := uint8(0x04) a := initTestAdaptorI2c() c, _ := a.GetI2cConnection(availableI2cAddress, a.DefaultI2cBus()) // act data, err := c.ReadByteData(reg) // assert require.NoError(t, err) assert.True(t, a.littleWire.(*i2cMock).writeStartWasSend) assert.True(t, a.littleWire.(*i2cMock).readStartWasSend) assert.Equal(t, uint8(1), a.littleWire.(*i2cMock).direction) assert.Equal(t, []byte{reg}, a.littleWire.(*i2cMock).dataWritten) assert.Equal(t, i2cData[0], data) assert.False(t, a.littleWire.(*i2cMock).writeStopWasSend) assert.True(t, a.littleWire.(*i2cMock).readStopWasSend) } func TestDigisparkAdaptorI2cReadWordData(t *testing.T) { // arrange reg := uint8(0x05) // 2 bytes of i2cData are used swapped expectedValue := uint16(0x0405) a := initTestAdaptorI2c() c, _ := a.GetI2cConnection(availableI2cAddress, a.DefaultI2cBus()) // act data, err := c.ReadWordData(reg) // assert require.NoError(t, err) assert.True(t, a.littleWire.(*i2cMock).writeStartWasSend) assert.True(t, a.littleWire.(*i2cMock).readStartWasSend) assert.Equal(t, uint8(1), a.littleWire.(*i2cMock).direction) assert.Equal(t, []byte{reg}, a.littleWire.(*i2cMock).dataWritten) assert.Equal(t, expectedValue, data) assert.False(t, a.littleWire.(*i2cMock).writeStopWasSend) assert.True(t, a.littleWire.(*i2cMock).readStopWasSend) } func TestDigisparkAdaptorI2cReadBlockData(t *testing.T) { // arrange reg := uint8(0x05) data := []byte{0, 0, 0, 0, 0} dataLen := len(data) a := initTestAdaptorI2c() c, _ := a.GetI2cConnection(availableI2cAddress, a.DefaultI2cBus()) // act err := c.ReadBlockData(reg, data) // assert require.NoError(t, err) assert.True(t, a.littleWire.(*i2cMock).writeStartWasSend) assert.True(t, a.littleWire.(*i2cMock).readStartWasSend) assert.Equal(t, uint8(1), a.littleWire.(*i2cMock).direction) assert.Equal(t, []byte{reg}, a.littleWire.(*i2cMock).dataWritten) assert.Equal(t, i2cData[:dataLen], data) assert.False(t, a.littleWire.(*i2cMock).writeStopWasSend) assert.True(t, a.littleWire.(*i2cMock).readStopWasSend) } func TestDigisparkAdaptorI2cUpdateDelay(t *testing.T) { // arrange a := initTestAdaptorI2c() c, _ := a.GetI2cConnection(availableI2cAddress, a.DefaultI2cBus()) // act err := c.(*digisparkI2cConnection).UpdateDelay(uint(100)) // assert require.NoError(t, err) assert.Equal(t, uint(100), a.littleWire.(*i2cMock).duration) } // setup mock for i2c tests func (l *i2cMock) i2cInit() error { l.direction = maxUint8 return l.error() } func (l *i2cMock) i2cStart(address7bit uint8, direction uint8) error { if address7bit != availableI2cAddress { return fmt.Errorf("invalid address, only %d is supported", availableI2cAddress) } if err := l.error(); err != nil { return err } l.direction = direction if direction == 1 { l.readStartWasSend = true } else { l.writeStartWasSend = true } return nil } func (l *i2cMock) i2cWrite(sendBuffer []byte, length int, endWithStop uint8) error { l.dataWritten = append(l.dataWritten, sendBuffer...) if endWithStop > 0 { l.writeStopWasSend = true } return l.error() } func (l *i2cMock) i2cRead(readBuffer []byte, length int, endWithStop uint8) error { if len(readBuffer) < length { length = len(readBuffer) } if len(i2cData) < length { length = len(i2cData) } copy(readBuffer[:length], i2cData[:length]) if endWithStop > 0 { l.readStopWasSend = true } return l.error() } func (l *i2cMock) i2cUpdateDelay(duration uint) error { l.duration = duration return l.error() } // GPIO, PWM and servo functions unused in this test scenarios func (l *i2cMock) digitalWrite(pin uint8, state uint8) error { return nil } func (l *i2cMock) pinMode(pin uint8, mode uint8) error { return nil } func (l *i2cMock) pwmInit() error { return nil } func (l *i2cMock) pwmStop() error { return nil } func (l *i2cMock) pwmUpdateCompare(channelA uint8, channelB uint8) error { return nil } func (l *i2cMock) pwmUpdatePrescaler(value uint) error { return nil } func (l *i2cMock) servoInit() error { return nil } func (l *i2cMock) servoUpdateLocation(locationA uint8, locationB uint8) error { return nil } func (l *i2cMock) error() error { return nil } ================================================ FILE: platforms/digispark/doc.go ================================================ //go:build libusb // +build libusb /* Package digispark provides the Gobot adaptor for the Digispark ATTiny-based USB development board. Installing: This package requires installing `libusb`. Then you can install the package with: Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) Example: package main import ( "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/digispark" ) func main() { digisparkAdaptor := digispark.NewAdaptor() led := gpio.NewLedDriver(digisparkAdaptor, "0") work := func() { gobot.Every(1*time.Second, func() { if err := led.Toggle(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("blinkBot", []gobot.Connection{digisparkAdaptor}, []gobot.Device{led}, work, ) if err := robot.Start(); err != nil { panic(err) } } For further information refer to digispark README: https://github.com/hybridgroup/gobot/blob/release/platforms/digispark/README.md */ package digispark // import "gobot.io/x/gobot/v2/platforms/digispark" ================================================ FILE: platforms/digispark/littleWire.c ================================================ /* Cross platform computer interface library for Little Wire project http://littlewire.github.io Copyright (C) <2013> ihsan Kehribar Copyright (C) <2013> Omer Kilic 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. */ /****************************************************************************** * See the littleWire.h for the function descriptions/comments /*****************************************************************************/ #include "littleWire.h" unsigned char crc8; int LastDiscrepancy; int LastFamilyDiscrepancy; int LastDeviceFlag; unsigned char rxBuffer[RX_BUFFER_SIZE]; /* This has to be unsigned for the data's sake */ unsigned char ROM_NO[8]; int lwStatus; lwCollection lwResults[16]; int lw_totalDevices; /****************************************************************************** / Taken from: http://www.maxim-ic.com/appnotes.cfm/appnote_number/187 /*****************************************************************************/ static unsigned char dscrc_table[] = { 0, 94,188,226, 97, 63,221,131,194,156,126, 32,163,253, 31, 65, 157,195, 33,127,252,162, 64, 30, 95, 1,227,189, 62, 96,130,220, 35,125,159,193, 66, 28,254,160,225,191, 93, 3,128,222, 60, 98, 190,224, 2, 92,223,129, 99, 61,124, 34,192,158, 29, 67,161,255, 70, 24,250,164, 39,121,155,197,132,218, 56,102,229,187, 89, 7, 219,133,103, 57,186,228, 6, 88, 25, 71,165,251,120, 38,196,154, 101, 59,217,135, 4, 90,184,230,167,249, 27, 69,198,152,122, 36, 248,166, 68, 26,153,199, 37,123, 58,100,134,216, 91, 5,231,185, 140,210, 48,110,237,179, 81, 15, 78, 16,242,172, 47,113,147,205, 17, 79,173,243,112, 46,204,146,211,141,111, 49,178,236, 14, 80, 175,241, 19, 77,206,144,114, 44,109, 51,209,143, 12, 82,176,238, 50,108,142,208, 83, 13,239,177,240,174, 76, 18,145,207, 45,115, 202,148,118, 40,171,245, 23, 73, 8, 86,180,234,105, 55,213,139, 87, 9,235,181, 54,104,138,212,149,203, 41,119,244,170, 72, 22, 233,183, 85, 11,136,214, 52,106, 43,117,151,201, 74, 20,246,168, 116, 42,200,150, 21, 75,169,247,182,232, 10, 84,215,137,107, 53}; /*****************************************************************************/ int littlewire_search() { struct usb_bus *bus; struct usb_device *dev; usb_init(); usb_find_busses(); usb_find_devices(); lw_totalDevices = 0; for (bus = usb_busses; bus; bus = bus->next) { for (dev = bus->devices; dev; dev = dev->next) { usb_dev_handle *udev; char description[256]; char string[256]; int ret, i; if((dev->descriptor.idVendor == VENDOR_ID) && (dev->descriptor.idProduct == PRODUCT_ID)) { udev = usb_open(dev); if (udev) { if (dev->descriptor.iSerialNumber) { ret = usb_get_string_simple(udev, dev->descriptor.iSerialNumber, string, sizeof(string)); if (ret > 0) { lwResults[lw_totalDevices].serialNumber = atoi(string); lwResults[lw_totalDevices].lw_device = dev; } } usb_close(udev); lw_totalDevices++; } } } } return lw_totalDevices; } littleWire* littlewire_connect_byID(int desiredID) { littleWire *tempHandle = NULL; if(desiredID > (lw_totalDevices-1)) { return tempHandle; } tempHandle = usb_open(lwResults[desiredID].lw_device); return tempHandle; } littleWire* littlewire_connect_bySerialNum(int mySerial) { littleWire *tempHandle = NULL; int temp_id = 0xDEAF; int i; for(i=0;i 999) { serialNumber = 999; } else if(serialNumber < 100) { serialNumber = 100; } sprintf(serBuf,"%d",serialNumber); lwStatus=usb_control_msg(lwHandle, 0xC0, 55, (serBuf[1]<<8)|serBuf[0],serBuf[2], rxBuffer, 8, USB_TIMEOUT); } void digitalWrite(littleWire* lwHandle, unsigned char pin, unsigned char state) { if(state){ lwStatus=usb_control_msg(lwHandle, 0xC0, 18, pin, 0, rxBuffer, 8, USB_TIMEOUT); } else{ lwStatus=usb_control_msg(lwHandle, 0xC0, 19, pin, 0, rxBuffer, 8, USB_TIMEOUT); } } void pinMode(littleWire* lwHandle, unsigned char pin, unsigned char mode) { if(mode){ lwStatus=usb_control_msg(lwHandle, 0xC0, 13, pin, 0, rxBuffer, 8, USB_TIMEOUT); } else { lwStatus=usb_control_msg(lwHandle, 0xC0, 14, pin, 0, rxBuffer, 8, USB_TIMEOUT); } } unsigned char digitalRead(littleWire* lwHandle, unsigned char pin) { lwStatus=usb_control_msg(lwHandle, 0xC0, 20, pin, 0, rxBuffer, 8, USB_TIMEOUT); return rxBuffer[0]; } void internalPullup(littleWire* lwHandle, unsigned char pin, unsigned char state) { if(state){ lwStatus=usb_control_msg(lwHandle, 0xC0, 18, pin, 0, rxBuffer, 8, USB_TIMEOUT); } else{ lwStatus=usb_control_msg(lwHandle, 0xC0, 19, pin, 0, rxBuffer, 8, USB_TIMEOUT); } } void analog_init(littleWire* lwHandle, unsigned char voltageRef) { lwStatus=usb_control_msg(lwHandle, 0xC0, 35, (voltageRef<<8) | 0x07, 0, rxBuffer, 8, USB_TIMEOUT); } unsigned int analogRead(littleWire* lwHandle, unsigned char channel) { lwStatus=usb_control_msg(lwHandle, 0xC0, 15, channel, 0, rxBuffer, 8, USB_TIMEOUT); return ((rxBuffer[1] *256) + (rxBuffer[0])); } void pwm_init(littleWire* lwHandle) { lwStatus=usb_control_msg(lwHandle, 0xC0, 16, 0, 0, rxBuffer, 8, USB_TIMEOUT); } void pwm_stop(littleWire* lwHandle) { lwStatus=usb_control_msg(lwHandle, 0xC0, 32, 0, 0, rxBuffer, 8, USB_TIMEOUT); } void pwm_updateCompare(littleWire* lwHandle, unsigned char channelA, unsigned char channelB) { lwStatus=usb_control_msg(lwHandle, 0xC0, 17, channelA, channelB, rxBuffer, 8, USB_TIMEOUT); } void pwm_updatePrescaler(littleWire* lwHandle, unsigned int value) { switch(value) { case 1024: lwStatus=usb_control_msg(lwHandle, 0xC0, 22, 4, 0, rxBuffer, 8, USB_TIMEOUT); break; case 256: lwStatus=usb_control_msg(lwHandle, 0xC0, 22, 3, 0, rxBuffer, 8, USB_TIMEOUT); break; case 64: lwStatus=usb_control_msg(lwHandle, 0xC0, 22, 2, 0, rxBuffer, 8, USB_TIMEOUT); break; case 8: lwStatus=usb_control_msg(lwHandle, 0xC0, 22, 1, 0, rxBuffer, 8, USB_TIMEOUT); break; case 1: lwStatus=usb_control_msg(lwHandle, 0xC0, 22, 0, 0, rxBuffer, 8, USB_TIMEOUT); break; } } void spi_init(littleWire* lwHandle) { lwStatus=usb_control_msg(lwHandle, 0xC0, 23, 0, 0, rxBuffer, 8, USB_TIMEOUT); } void spi_sendMessage(littleWire* lwHandle, unsigned char * sendBuffer, unsigned char * inputBuffer, unsigned char length ,unsigned char mode) { int i=0; if(length>4) length=4; lwStatus=usb_control_msg(lwHandle, 0xC0, (0xF0 + length + (mode<<3) ), (sendBuffer[1]<<8) + sendBuffer[0] , (sendBuffer[3]<<8) + sendBuffer[2], rxBuffer, 8, USB_TIMEOUT); lwStatus=usb_control_msg(lwHandle, 0xC0, 40, 0, 0, rxBuffer, 8, USB_TIMEOUT); for(i=0;i 0); else // if equal to last pick 1, if not then pick 0 search_direction = (id_bit_number == LastDiscrepancy); // if 0 was picked then record its position in LastZero if (search_direction == 0) { last_zero = id_bit_number; // check for Last discrepancy in family if (last_zero < 9) LastFamilyDiscrepancy = last_zero; } } // set or clear the bit in the ROM byte rom_byte_number // with mask rom_byte_mask if (search_direction == 1) ROM_NO[rom_byte_number] |= rom_byte_mask; else ROM_NO[rom_byte_number] &= ~rom_byte_mask; // serial number search direction write bit onewire_sendBit(lwHandle,search_direction); // increment the byte counter id_bit_number // and shift the mask rom_byte_mask id_bit_number++; rom_byte_mask <<= 1; // if the mask is 0 then go to new SerialNum byte rom_byte_number and reset mask if (rom_byte_mask == 0) { docrc8(ROM_NO[rom_byte_number]); // accumulate the CRC rom_byte_number++; rom_byte_mask = 1; } } } while(rom_byte_number < 8); // loop until through all ROM bytes 0-7 // if the search was successful then if (!((id_bit_number < 65) || (crc8 != 0))) { // search successful so set LastDiscrepancy,LastDeviceFlag,search_result LastDiscrepancy = last_zero; // check for last device if (LastDiscrepancy == 0) LastDeviceFlag = 1; search_result = 1; } } // if no device found then reset counters so next 'search' will be like a first if (!search_result || !ROM_NO[0]) { LastDiscrepancy = 0; LastDeviceFlag = 0; LastFamilyDiscrepancy = 0; search_result = 0; } return search_result; } int onewire_firstAddress(littleWire* lwHandle) { littleWire* temp = lwHandle; // reset the search state LastDiscrepancy = 0; LastDeviceFlag = 0; LastFamilyDiscrepancy = 0; return onewire_nextAddress(temp); } int littleWire_error () { if (lwStatus<0) return lwStatus; else return 0; } char *littleWire_errorName () { if (lwStatus<0) switch (lwStatus) { case -1: return "I/O Error"; break; case -2: return "Invalid parameter"; break; case -3: return "Access error"; break; case -4: return "No device"; break; case -5: return "Not found"; break; case -6: return "Busy"; break; case -7: return "Timeout"; break; case -8: return "Overflow"; break; case -9: return "Pipe"; break; case -10: return "Interrupted"; break; case -11: return "No memory"; break; case -12: return "Not supported"; break; case -99: return "Other"; break; default: return "unknown"; } else return 0; } ================================================ FILE: platforms/digispark/littleWire.go ================================================ //go:build libusb // +build libusb package digispark //#cgo pkg-config: libusb //#include "littleWire.h" //#include "littleWire_servo.h" // typedef usb_dev_handle littleWire; import "C" import ( "errors" "fmt" ) type lw interface { digitalWrite(pin uint8, state uint8) error pinMode(pin uint8, mode uint8) error pwmInit() error pwmStop() error pwmUpdateCompare(channelA uint8, channelb uint8) error pwmUpdatePrescaler(value uint) error servoInit() error servoUpdateLocation(locationA uint8, locationB uint8) error i2cInit() error i2cStart(address7bit uint8, direction uint8) error i2cWrite(sendBuffer []byte, length int, endWithStop uint8) error i2cRead(readBuffer []byte, length int, endWithStop uint8) error i2cUpdateDelay(duration uint) error error() error } type littleWire struct { lwHandle *C.littleWire } func littleWireConnect() *littleWire { return &littleWire{ lwHandle: C.littleWire_connect(), } } func (l *littleWire) digitalWrite(pin uint8, state uint8) error { C.digitalWrite(l.lwHandle, C.uchar(pin), C.uchar(state)) return l.error() } func (l *littleWire) pinMode(pin uint8, mode uint8) error { C.pinMode(l.lwHandle, C.uchar(pin), C.uchar(mode)) return l.error() } func (l *littleWire) pwmInit() error { C.pwm_init(l.lwHandle) return l.error() } func (l *littleWire) pwmStop() error { C.pwm_stop(l.lwHandle) return l.error() } func (l *littleWire) pwmUpdateCompare(channelA uint8, channelB uint8) error { C.pwm_updateCompare(l.lwHandle, C.uchar(channelA), C.uchar(channelB)) return l.error() } func (l *littleWire) pwmUpdatePrescaler(value uint) error { C.pwm_updatePrescaler(l.lwHandle, C.uint(value)) return l.error() } func (l *littleWire) servoInit() error { C.servo_init(l.lwHandle) return l.error() } func (l *littleWire) servoUpdateLocation(locationA uint8, locationB uint8) error { C.servo_updateLocation(l.lwHandle, C.uchar(locationA), C.uchar(locationB)) return l.error() } func (l *littleWire) i2cInit() error { C.i2c_init(l.lwHandle) return l.error() } // i2cStart starts the i2c communication; set direction to 1 for reading, 0 for writing func (l *littleWire) i2cStart(address7bit uint8, direction uint8) error { if C.i2c_start(l.lwHandle, C.uchar(address7bit), C.uchar(direction)) == 1 { return nil } if err := l.error(); err != nil { return err } return fmt.Errorf("Littlewire i2cStart failed for %d in direction %d", address7bit, direction) } // i2cWrite sends byte(s) over i2c with a given length <= 4 func (l *littleWire) i2cWrite(sendBuffer []byte, length int, endWithStop uint8) error { C.i2c_write(l.lwHandle, (*C.uchar)(&sendBuffer[0]), C.uchar(length), C.uchar(endWithStop)) return l.error() } // i2cRead reads byte(s) over i2c with a given length <= 8 func (l *littleWire) i2cRead(readBuffer []byte, length int, endWithStop uint8) error { C.i2c_read(l.lwHandle, (*C.uchar)(&readBuffer[0]), C.uchar(length), C.uchar(endWithStop)) return l.error() } // i2cUpdateDelay updates i2c signal delay amount. Tune if necessary to fit your requirements func (l *littleWire) i2cUpdateDelay(duration uint) error { C.i2c_updateDelay(l.lwHandle, C.uint(duration)) return l.error() } func (l *littleWire) error() error { str := C.GoString(C.littleWire_errorName()) if str != "" { return errors.New(str) } return nil } ================================================ FILE: platforms/digispark/littleWire.h ================================================ #ifndef LITTLEWIRE_H #define LITTLEWIRE_H /* Cross platform computer interface library for Little Wire project http://littlewire.github.io Copyright (C) <2013> ihsan Kehribar Copyright (C) <2013> Omer Kilic 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. */ #ifdef _WIN32 #include // this is libusb, see http://libusb.sourceforge.net/ #else #include // this is libusb, see http://libusb.sourceforge.net/ #endif #include "opendevice.h" // common code moved to separate module #include "littleWire_util.h" #include #define VENDOR_ID 0x1781 #define PRODUCT_ID 0x0c9f #define USB_TIMEOUT 5000 #define RX_BUFFER_SIZE 64 #define INPUT 1 #define OUTPUT 0 #define ENABLE 1 #define DISABLE 0 #define HIGH 1 #define LOW 0 #define AUTO_CS 1 #define MANUAL_CS 0 // Voltage ref definition #define VREF_VCC 0 #define VREF_1100mV 1 #define VREF_2560mV 2 // I2C definition #define END_WITH_STOP 1 #define NO_STOP 0 #define READ 1 #define WRITE 0 // General Purpose Pins #define PIN1 1 #define PIN2 2 #define PIN3 5 #define PIN4 0 // ADC Channels #define ADC_PIN3 0 #define ADC_PIN2 1 #define ADC_TEMP_SENS 2 // PWM Pins #define PWM1 PIN4 #define PWM2 PIN1 // Aliases #define ADC0 ADC_PIN3 #define ADC1 ADC_PIN2 #define ADC2 ADC_TEMP_SENS #define PWMA PWM1 #define PWMB PWM2 // 'AVR ISP' Pins #define SCK_PIN PIN2 #define MISO_PIN PIN1 #define MOSI_PIN PIN4 #define RESET_PIN PIN3 extern unsigned char rxBuffer[RX_BUFFER_SIZE]; /* This has to be unsigned for the data's sake */ extern unsigned char ROM_NO[8]; extern int lwStatus; /*! \addtogroup General * @brief General library functions * @{ */ typedef usb_dev_handle littleWire; typedef struct lwCollection { struct usb_device* lw_device; int serialNumber; }lwCollection; extern lwCollection lwResults[16]; extern int lw_totalDevices; /** * Tries to cache all the littleWire devices and stores them in lwResults array. \n * Don't actually connects to any of the device(s). * * @param (none) * @return Total number of littleWire devices found in the USB system. */ int littlewire_search(); /** * Tries to connect to the spesific littleWire device by array id. * * @param desiredID array index of the lwResults array. * @return littleWire pointer for healthy connection, NULL for a failed trial. */ littleWire* littlewire_connect_byID(int desiredID); /** * Tries to connect to the spesific littleWire with a given serial number. \n * If multiple devices have the same serial number, it connects to the last one it finds * * @param mySerial Serial number of the desired littlewire device. * @return littleWire pointer for healthy connection, NULL for a failed trial. */ littleWire* littlewire_connect_bySerialNum(int mySerial); /** * Tries to connect to the first littleWire device that libusb can find. * * @param (none) * @return littleWire pointer for healthy connection, NULL for a failed trial. */ littleWire* littleWire_connect(); /** * Reads the firmware version of the Little Wire \n * Format: 0xXY => X: Primary version Y: Minor version * * @param (none) * @return Firmware version */ unsigned char readFirmwareVersion(littleWire* lwHandle); /** * Changes the USB serial number of the Little Wire * * @param serialNumber Serial number integer value (100-99) * @return (none) */ void changeSerialNumber(littleWire* lwHandle,int serialNumber); /** * Sends a custom message to the device. \n * Useful when developing new features in the firmware. * * @param receiveBuffer Returned data buffer * @param command Firmware command * @param d1 data[0] for the command * @param d2 data[1] for the command * @param d3 data[2] for the command * @param d4 data[3] for the command * @return status */ int customMessage(littleWire* lwHandle,unsigned char* receiveBuffer,unsigned char command,unsigned char d1,unsigned char d2, unsigned char d3, unsigned char d4); /** * Returns the numeric value of the status of the last communication attempt * * @param (none) * @return Numeric value of the status of the last communication attempt */ int littleWire_error (); /** * Returns the string version of the last communication attempt status if there was an error * * @param (none) * @return String version of the last communication attempt status if there was an error */ char *littleWire_errorName (); /*! @} */ /*! \addtogroup GPIO * @brief GPIO library functions with Arduino-like syntax * @{ */ /** * Set pin value * * @param lwHandle littleWire device pointer * @param pin Pin name (\b PIN1 , \b PIN2 , \b PIN3 or \b PIN4 ) * @param state Pin state (\b HIGH or \b LOW) * @return (none) */ void digitalWrite(littleWire* lwHandle, unsigned char pin, unsigned char state); /** * Set pin as input/output * * @param lwHandle littleWire device pointer * @param pin Pin name (\b PIN1 , \b PIN2 , \b PIN3 or \b PIN4 ) * @param mode Mode of pin (\b INPUT or \b OUTPUT) * @return (none) */ void pinMode(littleWire* lwHandle, unsigned char pin, unsigned char mode); /** * Read pin value * * @param lwHandle littleWire device pointer * @param pin Pin name (\b PIN1 , \b PIN2 , \b PIN3 or \b PIN4 ) * @return Pin state (\b HIGH or \b LOW) */ unsigned char digitalRead(littleWire* lwHandle, unsigned char pin); /** * Sets the state of the internal pullup resistor. * \n Call this function after you assign the pin as an input. * * @param lwHandle littleWire device pointer * @param pin Pin name (\b PIN1 , \b PIN2 , \b PIN3 or \b PIN4 ) * @rparam state (\b ENABLE or \b DISABLE ) * @return (none) */ void internalPullup(littleWire* lwHandle, unsigned char pin, unsigned char state); /*! @} */ /*! \addtogroup ADC * @brief Analog to digital converter functions. * @{ */ /** * Initialize the analog module. VREF_VCC is the standard voltage coming from the USB plug * \n Others are the Attiny's internal voltage references. * * @param lwHandle littleWire device pointer * @param voltageRef (\b VREF_VCC , \b VREF_110mV or \b VREF_2560mV ) * @return (none) */ void analog_init(littleWire* lwHandle, unsigned char voltageRef); /** * Read analog voltage. Analog voltage reading from ADC_PIN3 isn't advised (it is a bit noisy) but supported. Use it at your own risk. * \n For more about internal temperature sensor, look at the Attiny85 datasheet. * * @param lwHandle littleWire device pointer * @param channel Source of ADC reading (\b ADC_PIN2 , \b ADC_PIN3 or \b ADC_TEMP_SENS ) * @return 10 bit ADC result */ unsigned int analogRead(littleWire* lwHandle, unsigned char channel); /*! @} */ /*! \addtogroup PWM * @brief Pulse width modulation functions. * @{ */ /** * Initialize the PWM module on the Little-Wire * * @param lwHandle littleWire device pointer * @return (none) */ void pwm_init(littleWire* lwHandle); /** * Stop the PWM module on the Little-Wire * * @param lwHandle littleWire device pointer * @return (none) */ void pwm_stop(littleWire* lwHandle); /** * Update the compare values of the PWM output pins. Resolution is 8 bit. * * @param lwHandle littleWire device pointer * @param channelA Compare value of \b PWMA pin * @param channelB Compare value of \b PWMB pin * @return (none) */ void pwm_updateCompare(littleWire* lwHandle, unsigned char channelA, unsigned char channelB); /** * Update the prescaler of the PWM module. Adjust this value according to your need for speed in PWM output. Default is 1024. Lower prescale means higher frequency PWM output. * * @param lwHandle littleWire device pointer * @param value Presecaler value (\b 1024, \b 256, \b 64, \b 8 or \b 1) * @return (none) */ void pwm_updatePrescaler(littleWire* lwHandle, unsigned int value); /*! @} */ /*! \addtogroup SPI * @brief Serial peripheral interface functions. * @{ */ /** * Initialize the SPI module on the Little-Wire * * @param lwHandle littleWire device pointer * @return (none) */ void spi_init(littleWire* lwHandle); /** * Send SPI message(s). SPI Mode is 0. * * @param lwHandle littleWire device pointer * @param sendBuffer Message array to send * @param inputBuffer Returned answer message * @param length Message length - maximum 4 * @param mode \b AUTO_CS or \b MANUAL_CS * @return (none) */ void spi_sendMessage(littleWire* lwHandle, unsigned char * sendBuffer, unsigned char * inputBuffer, unsigned char length ,unsigned char mode); /** * Send one byte SPI message over SDO pin. Slightly slower than the actual one. * \n There isn't any chip select control involved. Useful for debug console app * * @param lwHandle littleWire device pointer * @param message Message to send * @return Received SPI message */ unsigned char debugSpi(littleWire* lwHandle, unsigned char message); /** * Change the SPI message frequency by adjusting delay duration. By default, Little-Wire sends the SPI messages with maximum speed. * \n If your hardware can't catch up with the speed, increase the duration value to lower the SPI speed. * * @param lwHandle littleWire device pointer * @param duration Amount of delay. * @return (none) */ void spi_updateDelay(littleWire* lwHandle, unsigned int duration); /*! @} */ /*! \addtogroup I2C * @brief Inter IC communication functions. * @{ */ /** * Initialize the I2C module on the Little-Wire * * @return (none) */ void i2c_init(littleWire* lwHandle); /** * Start the i2c communication * * @param lwHandle littleWire device pointer * @param address 7 bit target address. * @param direction ( \b READ or \b WRITE ) * @return 1 if received ACK */ unsigned char i2c_start(littleWire* lwHandle, unsigned char address7bit, unsigned char direction); /** * Send byte(s) over i2c bus * * @param lwHandle littleWire device pointer * @param sendBuffer Message array to send * @param length Message length -> Max = 4 * @param endWithStop Should we send a STOP condition after this buffer? ( \b END_WITH_STOP or \b NO_STOP ) * @return (none) */ void i2c_write(littleWire* lwHandle, unsigned char* sendBuffer, unsigned char length, unsigned char endWithStop); /** * Read byte(s) over i2c bus * * @param lwHandle littleWire device pointer * @param readBuffer Returned message array * @param length Message length -> Max = 8 * @param endWithStop Should we send a STOP condition after this buffer? ( \b END_WITH_STOP or \b NO_STOP ) * @return (none) */ void i2c_read(littleWire* lwHandle, unsigned char* readBuffer, unsigned char length, unsigned char endWithStop); /** * Update i2c signal delay amount. Tune if necessary to fit your requirements. * * @param lwHandle littleWire device pointer * @param duration Delay amount * @return (none) */ void i2c_updateDelay(littleWire* lwHandle, unsigned int duration); /*! @} */ /*! \addtogroup Onewire * @brief Onewire functions. * @{ */ /** * Send a single bit over onewire bus. * * @param lwHandle littleWire device pointer * @param bitValue \b 1 or \b 0 * @return (none) */ void onewire_sendBit(littleWire* lwHandle, unsigned char bitValue); /** * Send a byte over onewire bus. * * @param lwHandle littleWire device pointer * @param messageToSend Message to send * @return (none) */ void onewire_writeByte(littleWire* lwHandle, unsigned char messageToSend); /** * Read a byte over onewire bus. * * @param lwHandle littleWire device pointer * @return Read byte */ unsigned char onewire_readByte(littleWire* lwHandle); /** * Read a single bit over onewire bus * * @param lwHandle littleWire device pointer * @return Read bit ( \b 1 or \b 0 ) */ unsigned char onewire_readBit(littleWire* lwHandle); /** * Send a reset pulse over onewire bus * * @param lwHandle littleWire device pointer * @return Nonzero if any device presents on the bus */ unsigned char onewire_resetPulse(littleWire* lwHandle); /** * Start searching for device address on the onewire bus. * \n Read the 8 byte address from \b ROM_NO array * * @param lwHandle littleWire device pointer * @return Nonzero if any device found */ int onewire_firstAddress(littleWire* lwHandle); /** * Try to find the next adress on the onewire bus. * \n Read the 8 byte address from \b ROM_NO array * * @param lwHandle littleWire device pointer * @return Nonzero if any new device found */ int onewire_nextAddress(littleWire* lwHandle); /*! @} */ /*! \addtogroup SOFT_PWM * @brief Software PWM functions. Designed to be used with RGB LEDs. * @{ */ /** * Sets the state of the softPWM module * * @param lwHandle littleWire device pointer * @param state State of the softPWM module ( \b ENABLE or \b DISABLE ) * @return (none) */ void softPWM_state(littleWire* lwHandle,unsigned char state); /** * Updates the values of softPWM modules * * @param lwHandle littleWire device pointer * @param ch1 Value of channel 1 - \b PIN4 * @param ch2 Value of channel 2 - \b PIN1 * @param ch3 Value of channel 3 - \b PIN2 * @return (none) */ void softPWM_write(littleWire* lwHandle,unsigned char ch1,unsigned char ch2,unsigned char ch3); /*! @} */ /*! @} */ /*! \addtogroup WS2812 * @brief WS2812 programmable RGB-LED support * @{ */ /** * Writes to a WS2812 RGB-LED. This function writes the passed rgb values to a WS2812 led string * connected to the given pin. Use this if you want to control a single LED. * * If RGB values were preloaded with the preload call, the values passed in this call are added * to the buffer and the entire buffer is written to the LED string. This feature can be used to * reduce the number of USB transmissions for a string. * * @param lwHandle littleWire device pointer * @param r value of the red channel * @param g value of the green channel * @param b value of the blue channel * @param pin Pin name (\b PIN1 , \b PIN2 , \b PIN3 or \b PIN4 ) * @return (none) */ void ws2812_write(littleWire* lwHandle, unsigned char pin,unsigned char r,unsigned char g,unsigned char b); /** * This function flushes the contents of the littlewire internal RGB buffer to the LED string. * * @param lwHandle littleWire device pointer * @param r value of the red channel * @param g value of the green channel * @param b value of the blue channel * @return (none) */ void ws2812_flush(littleWire* lwHandle, unsigned char pin); /** * Preloads a RGB value to the internal buffer. Up to 64 values can be preloaded. Further writes will be ignored * * @param lwHandle littleWire device pointer * @param r value of the red channel * @param g value of the green channel * @param b value of the blue channel * @return (none) */ void ws2812_preload(littleWire* lwHandle, unsigned char r,unsigned char g,unsigned char b); /*! @} */ /** * @mainpage Introduction \htmlinclude intro.html */ #endif ================================================ FILE: platforms/digispark/littleWire_servo.c ================================================ /* Higher level servo driving library for Little Wire. Copyright (C) <2013> ihsan Kehribar Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "littleWire_servo.h" /******************************************************************************** * Useful definitions ********************************************************************************/ const float MIN_LIMIT = 0.45; // in miliseconds const float MAX_LIMIT = 2.45; // in miliseconds const float STEP_SIZE = 0.062; // in miliseconds const float RANGE = 180.0; // in degrees /*******************************************************************************/ /******************************************************************************** * Servo module initialization ********************************************************************************/ void servo_init(littleWire* lwHandle) { pwm_init(lwHandle); // Initialize the PWM hardware. pinMode(lwHandle,PWMA,OUTPUT); pinMode(lwHandle,PWMB,OUTPUT); // Set PWM pins output. pwm_updatePrescaler(lwHandle,1024); // Make sure the PWM prescaler is set correctly. } /*******************************************************************************/ /******************************************************************************** * Servo locations update * locationChannelA in degrees * locationChannelB in degrees ********************************************************************************/ void servo_updateLocation(littleWire* lwHandle,unsigned char locationChannelA,unsigned char locationChannelB) { locationChannelA=(((locationChannelA/RANGE)*(MAX_LIMIT-MIN_LIMIT))+MIN_LIMIT)/STEP_SIZE; locationChannelB=(((locationChannelB/RANGE)*(MAX_LIMIT-MIN_LIMIT))+MIN_LIMIT)/STEP_SIZE; pwm_updateCompare(lwHandle,locationChannelA,locationChannelB); } /*******************************************************************************/ ================================================ FILE: platforms/digispark/littleWire_servo.h ================================================ #ifndef LITTLEWIRE_SERVO_H #define LITTLEWIRE_SERVO_H /* Higher level servo driving library for Little Wire. Copyright (C) <2013> ihsan Kehribar Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "littleWire.h" /*! \addtogroup Servo * @brief Servo functions. Higher level access to PWM module. * @{ */ /** * Initialize the PWM module on the Little-Wire with the Servo special settings. * * @param lwHandle littleWire device pointer * @return (none) */ void servo_init(littleWire* lwHandle); /** * Update servo locations * * @param lwHandle littleWire device pointer * @param locationChannelA Location of servo connected to channel A ( in degrees ) * @param locationChannelB Location of servo connected to channel B ( in degrees ) * @return (none) */ void servo_updateLocation(littleWire* lwHandle,unsigned char locationChannelA,unsigned char locationChannelB); /*! @} */ #endif ================================================ FILE: platforms/digispark/littleWire_util.c ================================================ #include /* Delay in miliseconds */ void delay(unsigned int duration) { #ifdef _WIN32 Sleep(duration); #else usleep(duration*1000); #endif } ================================================ FILE: platforms/digispark/littleWire_util.h ================================================ #ifndef LITTLEWIRE_UTIL_H #define LITTLEWIRE_UTIL_H #ifdef _WIN32 #include #else #include #endif /* Delay in miliseconds */ void delay(unsigned int duration); #endif ================================================ FILE: platforms/digispark/opendevice.c ================================================ /* Name: opendevice.c * Project: V-USB host-side library * Author: Christian Starkjohann * Creation Date: 2008-04-10 * Tabsize: 4 * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) * This Revision: $Id: opendevice.c 740 2009-04-13 18:23:31Z cs $ */ /* General Description: The functions in this module can be used to find and open a device based on libusb or libusb-win32. */ #include #include "opendevice.h" /* ------------------------------------------------------------------------- */ #define MATCH_SUCCESS 1 #define MATCH_FAILED 0 #define MATCH_ABORT -1 /* private interface: match text and p, return MATCH_SUCCESS, MATCH_FAILED, or MATCH_ABORT. */ static int _shellStyleMatch(char *text, char *p) { int last, matched, reverse; for(; *p; text++, p++){ if(*text == 0 && *p != '*') return MATCH_ABORT; switch(*p){ case '\\': /* Literal match with following character. */ p++; /* FALLTHROUGH */ default: if(*text != *p) return MATCH_FAILED; continue; case '?': /* Match anything. */ continue; case '*': while(*++p == '*') /* Consecutive stars act just like one. */ continue; if(*p == 0) /* Trailing star matches everything. */ return MATCH_SUCCESS; while(*text) if((matched = _shellStyleMatch(text++, p)) != MATCH_FAILED) return matched; return MATCH_ABORT; case '[': reverse = p[1] == '^'; if(reverse) /* Inverted character class. */ p++; matched = MATCH_FAILED; if(p[1] == ']' || p[1] == '-') if(*++p == *text) matched = MATCH_SUCCESS; for(last = *p; *++p && *p != ']'; last = *p) if (*p == '-' && p[1] != ']' ? *text <= *++p && *text >= last : *text == *p) matched = MATCH_SUCCESS; if(matched == reverse) return MATCH_FAILED; continue; } } return *text == 0; } /* public interface for shell style matching: returns 0 if fails, 1 if matches */ static int shellStyleMatch(char *text, char *pattern) { if(pattern == NULL) /* NULL pattern is synonymous to "*" */ return 1; return _shellStyleMatch(text, pattern) == MATCH_SUCCESS; } /* ------------------------------------------------------------------------- */ int usbGetStringAscii(usb_dev_handle *dev, int index, char *buf, int buflen) { char buffer[256]; int rval, i; if((rval = usb_get_string_simple(dev, index, buf, buflen)) >= 0) /* use libusb version if it works */ return rval; if((rval = usb_control_msg(dev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) + index, 0x0409, buffer, sizeof(buffer), 5000)) < 0) return rval; if(buffer[1] != USB_DT_STRING){ *buf = 0; return 0; } if((unsigned char)buffer[0] < rval) rval = (unsigned char)buffer[0]; rval /= 2; /* lossy conversion to ISO Latin1: */ for(i=1;i buflen) /* destination buffer overflow */ break; buf[i-1] = buffer[2 * i]; if(buffer[2 * i + 1] != 0) /* outside of ISO Latin1 range */ buf[i-1] = '?'; } buf[i-1] = 0; return i-1; } /* ------------------------------------------------------------------------- */ int usbOpenDevice(usb_dev_handle **device, int vendorID, char *vendorNamePattern, int productID, char *productNamePattern, char *serialNamePattern, FILE *printMatchingDevicesFp, FILE *warningsFp) { struct usb_bus *bus; struct usb_device *dev; usb_dev_handle *handle = NULL; int errorCode = USBOPEN_ERR_NOTFOUND; usb_find_busses(); usb_find_devices(); for(bus = usb_get_busses(); bus; bus = bus->next){ for(dev = bus->devices; dev; dev = dev->next){ /* iterate over all devices on all busses */ if((vendorID == 0 || dev->descriptor.idVendor == vendorID) && (productID == 0 || dev->descriptor.idProduct == productID)){ char vendor[256], product[256], serial[256]; int len; handle = usb_open(dev); /* we need to open the device in order to query strings */ if(!handle){ errorCode = USBOPEN_ERR_ACCESS; if(warningsFp != NULL) fprintf(warningsFp, "Warning: cannot open VID=0x%04x PID=0x%04x: %s\n", dev->descriptor.idVendor, dev->descriptor.idProduct, usb_strerror()); continue; } /* now check whether the names match: */ len = vendor[0] = 0; if(dev->descriptor.iManufacturer > 0){ len = usbGetStringAscii(handle, dev->descriptor.iManufacturer, vendor, sizeof(vendor)); } if(len < 0){ errorCode = USBOPEN_ERR_ACCESS; if(warningsFp != NULL) fprintf(warningsFp, "Warning: cannot query manufacturer for VID=0x%04x PID=0x%04x: %s\n", dev->descriptor.idVendor, dev->descriptor.idProduct, usb_strerror()); }else{ errorCode = USBOPEN_ERR_NOTFOUND; /* printf("seen device from vendor ->%s<-\n", vendor); */ if(shellStyleMatch(vendor, vendorNamePattern)){ len = product[0] = 0; if(dev->descriptor.iProduct > 0){ len = usbGetStringAscii(handle, dev->descriptor.iProduct, product, sizeof(product)); } if(len < 0){ errorCode = USBOPEN_ERR_ACCESS; if(warningsFp != NULL) fprintf(warningsFp, "Warning: cannot query product for VID=0x%04x PID=0x%04x: %s\n", dev->descriptor.idVendor, dev->descriptor.idProduct, usb_strerror()); }else{ errorCode = USBOPEN_ERR_NOTFOUND; /* printf("seen product ->%s<-\n", product); */ if(shellStyleMatch(product, productNamePattern)){ len = serial[0] = 0; if(dev->descriptor.iSerialNumber > 0){ len = usbGetStringAscii(handle, dev->descriptor.iSerialNumber, serial, sizeof(serial)); } if(len < 0){ errorCode = USBOPEN_ERR_ACCESS; if(warningsFp != NULL) fprintf(warningsFp, "Warning: cannot query serial for VID=0x%04x PID=0x%04x: %s\n", dev->descriptor.idVendor, dev->descriptor.idProduct, usb_strerror()); } if(shellStyleMatch(serial, serialNamePattern)){ if(printMatchingDevicesFp != NULL){ if(serial[0] == 0){ fprintf(printMatchingDevicesFp, "VID=0x%04x PID=0x%04x vendor=\"%s\" product=\"%s\"\n", dev->descriptor.idVendor, dev->descriptor.idProduct, vendor, product); }else{ fprintf(printMatchingDevicesFp, "VID=0x%04x PID=0x%04x vendor=\"%s\" product=\"%s\" serial=\"%s\"\n", dev->descriptor.idVendor, dev->descriptor.idProduct, vendor, product, serial); } }else{ break; } } } } } } usb_close(handle); handle = NULL; } } if(handle) /* we have found a deice */ break; } if(handle != NULL){ errorCode = 0; *device = handle; } if(printMatchingDevicesFp != NULL) /* never return an error for listing only */ errorCode = 0; return errorCode; } /* ------------------------------------------------------------------------- */ ================================================ FILE: platforms/digispark/opendevice.h ================================================ /* Name: opendevice.h * Project: V-USB host-side library * Author: Christian Starkjohann * Creation Date: 2008-04-10 * Tabsize: 4 * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) * This Revision: $Id: opendevice.h 755 2009-08-03 17:01:21Z cs $ */ /* General Description: This module offers additional functionality for host side drivers based on libusb or libusb-win32. It includes a function to find and open a device based on numeric IDs and textual description. It also includes a function to obtain textual descriptions from a device. To use this functionality, simply copy opendevice.c and opendevice.h into your project and add them to your Makefile. You may modify and redistribute these files according to the GNU General Public License (GPL) version 2 or 3. */ #ifndef __OPENDEVICE_H_INCLUDED__ #define __OPENDEVICE_H_INCLUDED__ #ifdef _WIN32 #include // this is libusb, see http://libusb.sourceforge.net/ #else #include // this is libusb, see http://libusb.sourceforge.net/ #endif #include int usbGetStringAscii(usb_dev_handle *dev, int index, char *buf, int buflen); /* This function gets a string descriptor from the device. 'index' is the * string descriptor index. The string is returned in ISO Latin 1 encoding in * 'buf' and it is terminated with a 0-character. The buffer size must be * passed in 'buflen' to prevent buffer overflows. A libusb device handle * must be given in 'dev'. * Returns: The length of the string (excluding the terminating 0) or * a negative number in case of an error. If there was an error, use * usb_strerror() to obtain the error message. */ int usbOpenDevice(usb_dev_handle **device, int vendorID, char *vendorNamePattern, int productID, char *productNamePattern, char *serialNamePattern, FILE *printMatchingDevicesFp, FILE *warningsFp); /* This function iterates over all devices on all USB busses and searches for * a device. Matching is done first by means of Vendor- and Product-ID (passed * in 'vendorID' and 'productID'. An ID of 0 matches any numeric ID (wildcard). * When a device matches by its IDs, matching by names is performed. Name * matching can be done on textual vendor name ('vendorNamePattern'), product * name ('productNamePattern') and serial number ('serialNamePattern'). A * device matches only if all non-null pattern match. If you don't care about * a string, pass NULL for the pattern. Patterns are Unix shell style pattern: * '*' stands for 0 or more characters, '?' for one single character, a list * of characters in square brackets for a single character from the list * (dashes are allowed to specify a range) and if the lis of characters begins * with a caret ('^'), it matches one character which is NOT in the list. * Other parameters to the function: If 'warningsFp' is not NULL, warning * messages are printed to this file descriptor with fprintf(). If * 'printMatchingDevicesFp' is not NULL, no device is opened but matching * devices are printed to the given file descriptor with fprintf(). * If a device is opened, the resulting USB handle is stored in '*device'. A * pointer to a "usb_dev_handle *" type variable must be passed here. * Returns: 0 on success, an error code (see defines below) on failure. */ /* usbOpenDevice() error codes: */ #define USBOPEN_SUCCESS 0 /* no error */ #define USBOPEN_ERR_ACCESS 1 /* not enough permissions to open device */ #define USBOPEN_ERR_IO 2 /* I/O error */ #define USBOPEN_ERR_NOTFOUND 3 /* device not found */ /* Obdev's free USB IDs, see USB-IDs-for-free.txt for details */ #define USB_VID_OBDEV_SHARED 5824 /* obdev's shared vendor ID */ #define USB_PID_OBDEV_SHARED_CUSTOM 1500 /* shared PID for custom class devices */ #define USB_PID_OBDEV_SHARED_HID 1503 /* shared PID for HIDs except mice & keyboards */ #define USB_PID_OBDEV_SHARED_CDCACM 1505 /* shared PID for CDC Modem devices */ #define USB_PID_OBDEV_SHARED_MIDI 1508 /* shared PID for MIDI class devices */ #endif /* __OPENDEVICE_H_INCLUDED__ */ ================================================ FILE: platforms/dji/README.md ================================================ # DJI This package contains the Gobot drivers for DJI (https://www.dji.com/) drones. This package currently supports the following drones: - [DJI Tello](https://www.ryzerobotics.com/tello) ================================================ FILE: platforms/dji/dji.go ================================================ // Package dji contains the Gobot drivers for DJI drones. // Currently only has support for the DJI Tello. // For more information, go to: package dji // import "gobot.io/x/gobot/v2/platforms/dji" ================================================ FILE: platforms/dji/tello/README.md ================================================ # Tello This package contains the Gobot driver for the Ryze Tello drone, sold by DJI. For more information on this drone, go to: [https://www.ryzerobotics.com/tello](https://www.ryzerobotics.com/tello) ## How to Install Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) ## How to Use Connect to the drone's Wi-Fi network from your computer. It will be named something like "TELLO-XXXXXX". Once you are connected you can run the Gobot code on your computer to control the drone. Here is a sample of how you initialize and use the driver: ```go package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/dji/tello" ) func main() { drone := tello.NewDriver("8888") work := func() { drone.TakeOff() gobot.After(5*time.Second, func() { drone.Land() }) } robot := gobot.NewRobot("tello", []gobot.Connection{}, []gobot.Device{drone}, work, ) if err := robot.Start(); err != nil { panic(err) } } ``` ## Telo Edu driver If you are planning to connect to the edu version of the tello, please use the `NewDriverWithIP` driver instead ```go drone := tello.NewDriverWithIP("192.168.10.1", "8888") ``` ## References This driver could not exist without the awesome members of the unofficial Tello forum: Special thanks to [@Kragrathea](https://github.com/Kragrathea) who figured out a LOT of the packets and code as implemented in C#: [https://github.com/Kragrathea/TelloPC](https://github.com/Kragrathea/TelloPC) Also thanks to [@microlinux](https://github.com/microlinux) with the Python library which served as the first example for the Tello community: [https://github.com/microlinux/tello](https://github.com/microlinux/tello) Thank you to bluejune for the [https://bitbucket.org/PingguSoft/pytello](https://bitbucket.org/PingguSoft/pytello) repo, especially the Wireshark Lua dissector which has proven indispensable. ================================================ FILE: platforms/dji/tello/crc.go ================================================ package tello var crc8table = []byte{ 0x00, 0x5e, 0xbc, 0xe2, 0x61, 0x3f, 0xdd, 0x83, 0xc2, 0x9c, 0x7e, 0x20, 0xa3, 0xfd, 0x1f, 0x41, 0x9d, 0xc3, 0x21, 0x7f, 0xfc, 0xa2, 0x40, 0x1e, 0x5f, 0x01, 0xe3, 0xbd, 0x3e, 0x60, 0x82, 0xdc, 0x23, 0x7d, 0x9f, 0xc1, 0x42, 0x1c, 0xfe, 0xa0, 0xe1, 0xbf, 0x5d, 0x03, 0x80, 0xde, 0x3c, 0x62, 0xbe, 0xe0, 0x02, 0x5c, 0xdf, 0x81, 0x63, 0x3d, 0x7c, 0x22, 0xc0, 0x9e, 0x1d, 0x43, 0xa1, 0xff, 0x46, 0x18, 0xfa, 0xa4, 0x27, 0x79, 0x9b, 0xc5, 0x84, 0xda, 0x38, 0x66, 0xe5, 0xbb, 0x59, 0x07, 0xdb, 0x85, 0x67, 0x39, 0xba, 0xe4, 0x06, 0x58, 0x19, 0x47, 0xa5, 0xfb, 0x78, 0x26, 0xc4, 0x9a, 0x65, 0x3b, 0xd9, 0x87, 0x04, 0x5a, 0xb8, 0xe6, 0xa7, 0xf9, 0x1b, 0x45, 0xc6, 0x98, 0x7a, 0x24, 0xf8, 0xa6, 0x44, 0x1a, 0x99, 0xc7, 0x25, 0x7b, 0x3a, 0x64, 0x86, 0xd8, 0x5b, 0x05, 0xe7, 0xb9, 0x8c, 0xd2, 0x30, 0x6e, 0xed, 0xb3, 0x51, 0x0f, 0x4e, 0x10, 0xf2, 0xac, 0x2f, 0x71, 0x93, 0xcd, 0x11, 0x4f, 0xad, 0xf3, 0x70, 0x2e, 0xcc, 0x92, 0xd3, 0x8d, 0x6f, 0x31, 0xb2, 0xec, 0x0e, 0x50, 0xaf, 0xf1, 0x13, 0x4d, 0xce, 0x90, 0x72, 0x2c, 0x6d, 0x33, 0xd1, 0x8f, 0x0c, 0x52, 0xb0, 0xee, 0x32, 0x6c, 0x8e, 0xd0, 0x53, 0x0d, 0xef, 0xb1, 0xf0, 0xae, 0x4c, 0x12, 0x91, 0xcf, 0x2d, 0x73, 0xca, 0x94, 0x76, 0x28, 0xab, 0xf5, 0x17, 0x49, 0x08, 0x56, 0xb4, 0xea, 0x69, 0x37, 0xd5, 0x8b, 0x57, 0x09, 0xeb, 0xb5, 0x36, 0x68, 0x8a, 0xd4, 0x95, 0xcb, 0x29, 0x77, 0xf4, 0xaa, 0x48, 0x16, 0xe9, 0xb7, 0x55, 0x0b, 0x88, 0xd6, 0x34, 0x6a, 0x2b, 0x75, 0x97, 0xc9, 0x4a, 0x14, 0xf6, 0xa8, 0x74, 0x2a, 0xc8, 0x96, 0x15, 0x4b, 0xa9, 0xf7, 0xb6, 0xe8, 0x0a, 0x54, 0xd7, 0x89, 0x6b, 0x35, } // CalculateCRC8 calculates the starting CRC8 byte for packet. func CalculateCRC8(pkt []byte) byte { crc := byte(0x77) for _, val := range pkt { crc = crc8table[(crc^val)&0xff] } return crc } //nolint:lll // ok here var crc16table = []uint16{ 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78, } // CalculateCRC16 calculates the ending CRC16 bytes for packet. func CalculateCRC16(pkt []byte) uint16 { crc := uint16(0x3692) for _, val := range pkt { crc = crc16table[(crc^uint16(val))&0xff] ^ (crc >> 8) } return crc } ================================================ FILE: platforms/dji/tello/driver.go ================================================ package tello import ( "bytes" "encoding/binary" "errors" "fmt" "io" "math" "net" "strconv" "sync" "sync/atomic" "time" "gobot.io/x/gobot/v2" ) const ( // BounceEvent event BounceEvent = "bounce" // ConnectedEvent event ConnectedEvent = "connected" // FlightDataEvent event FlightDataEvent = "flightdata" // TakeoffEvent event TakeoffEvent = "takeoff" // LandingEvent event LandingEvent = "landing" // PalmLandingEvent event PalmLandingEvent = "palm-landing" // FlipEvent event FlipEvent = "flip" // TimeEvent event TimeEvent = "time" // LogEvent event LogEvent = "log" // WifiDataEvent event WifiDataEvent = "wifidata" // LightStrengthEvent event LightStrengthEvent = "lightstrength" // SetExposureEvent event SetExposureEvent = "setexposure" // VideoFrameEvent event VideoFrameEvent = "videoframe" // SetVideoEncoderRateEvent event SetVideoEncoderRateEvent = "setvideoencoder" ) // the 16-bit messages and commands stored in bytes 6 & 5 of the packet const ( messageStart = 0x00cc // 204 wifiMessage = 0x001a // 26 videoRateQuery = 0x0028 // 40 lightMessage = 0x0035 // 53 flightMessage = 0x0056 // 86 logMessage = 0x1050 // 4176 videoEncoderRateCommand = 0x0020 // 32 videoStartCommand = 0x0025 // 37 exposureCommand = 0x0034 // 52 timeCommand = 0x0046 // 70 stickCommand = 0x0050 // 80 takeoffCommand = 0x0054 // 84 landCommand = 0x0055 // 85 flipCommand = 0x005c // 92 throwtakeoffCommand = 0x005d // 93 palmLandCommand = 0x005e // 94 bounceCommand = 0x1053 // 4179 ) // FlipType is used for the various flips supported by the Tello. type FlipType int const ( // FlipFront flips forward. FlipFront FlipType = 0 // FlipLeft flips left. FlipLeft FlipType = 1 // FlipBack flips backwards. FlipBack FlipType = 2 // FlipRight flips to the right. FlipRight FlipType = 3 // FlipForwardLeft flips forwards and to the left. FlipForwardLeft FlipType = 4 // FlipBackLeft flips backwards and to the left. FlipBackLeft FlipType = 5 // FlipBackRight flips backwards and to the right. FlipBackRight FlipType = 6 // FlipForwardRight flips forewards and to the right. FlipForwardRight FlipType = 7 ) // VideoBitRate is used to set the bit rate for the streaming video returned by the Tello. type VideoBitRate int const ( // VideoBitRateAuto sets the bitrate for streaming video to auto-adjust. VideoBitRateAuto VideoBitRate = 0 // VideoBitRate1M sets the bitrate for streaming video to 1 Mb/s. VideoBitRate1M VideoBitRate = 1 // VideoBitRate15M sets the bitrate for streaming video to 1.5 Mb/s VideoBitRate15M VideoBitRate = 2 // VideoBitRate2M sets the bitrate for streaming video to 2 Mb/s. VideoBitRate2M VideoBitRate = 3 // VideoBitRate3M sets the bitrate for streaming video to 3 Mb/s. VideoBitRate3M VideoBitRate = 4 // VideoBitRate4M sets the bitrate for streaming video to 4 Mb/s. VideoBitRate4M VideoBitRate = 5 ) // FlightData packet returned by the Tello. // // The meaning of some fields is not documented. If you learned more, please, contribute. // See https://github.com/hybridgroup/gobot/issues/798. type FlightData struct { BatteryLow bool BatteryLower bool BatteryPercentage int8 // How much battery left [in %]. CameraState int8 DroneBatteryLeft int16 DroneFlyTimeLeft int16 DroneHover bool // If the drone is in the air and not moving. EmOpen bool Flying bool // If the drone is currently in the air. OnGround bool // If the drone is currently on the ground. EastSpeed int16 // Movement speed towards East [in cm/s]. Negative if moving west. ElectricalMachineryState int16 FactoryMode bool FlyMode int8 FlyTime int16 // How long since take off [in s/10]. FrontIn bool FrontLSC bool FrontOut bool GravityState bool VerticalSpeed int16 // Movement speed up [in cm/s]. Height int16 // The height [in decimeters]. ImuCalibrationState int8 // The IMU calibration step (when doing IMU calibration). NorthSpeed int16 // Movement speed towards North [in cm/s]. Negative if moving South. ThrowFlyTimer int8 // Warnings: DownVisualState bool // If the ground is visible by the down camera. BatteryState bool // If there is an issue with battery. ImuState bool // If drone needs IMU (Inertial Measurement Unit) calibration. OutageRecording bool // If there is an issue with video recording. PowerState bool // If there is an issue with power supply. PressureState bool // If there is an issue with air pressure. TemperatureHigh bool // If drone is overheating. WindState bool // If the wind is too strong. } // WifiData packet returned by the Tello type WifiData struct { Disturb int8 Strength int8 } // Driver represents the DJI Tello drone type Driver struct { gobot.Eventer name string reqAddr string cmdConn io.WriteCloser // UDP connection to send/receive drone commands videoConn *net.UDPConn // UDP connection for drone video respPort string videoPort string cmdMutex sync.Mutex seq int16 rx, ry, lx, ly float32 throttle int bouncing bool doneCh chan struct{} doneChReaderCount int32 } // NewDriver creates a driver for the Tello drone. Pass in the UDP port to use for the responses // from the drone. func NewDriver(port string) *Driver { return NewDriverWithIP("192.168.10.1", port) } // NewDriverWithIP creates a driver for the Tello EDU drone. Pass in the ip address and UDP port to use for // the responses from the drone. func NewDriverWithIP(ip string, port string) *Driver { d := &Driver{ name: gobot.DefaultName("Tello"), reqAddr: ip + ":8889", respPort: port, videoPort: "11111", Eventer: gobot.NewEventer(), doneCh: make(chan struct{}, 1), } d.AddEvent(ConnectedEvent) d.AddEvent(FlightDataEvent) d.AddEvent(TakeoffEvent) d.AddEvent(LandingEvent) d.AddEvent(PalmLandingEvent) d.AddEvent(BounceEvent) d.AddEvent(FlipEvent) d.AddEvent(TimeEvent) d.AddEvent(LogEvent) d.AddEvent(WifiDataEvent) d.AddEvent(LightStrengthEvent) d.AddEvent(SetExposureEvent) d.AddEvent(VideoFrameEvent) d.AddEvent(SetVideoEncoderRateEvent) return d } // Name returns the name of the device. func (d *Driver) Name() string { return d.name } // SetName sets the name of the device. func (d *Driver) SetName(n string) { d.name = n } // Connection returns the Connection of the device. func (d *Driver) Connection() gobot.Connection { return nil } // Start starts the driver. func (d *Driver) Start() error { reqAddr, err := net.ResolveUDPAddr("udp", d.reqAddr) if err != nil { fmt.Println(err) return err } respPort, err := net.ResolveUDPAddr("udp", ":"+d.respPort) if err != nil { fmt.Println(err) return err } cmdConn, err := net.DialUDP("udp", respPort, reqAddr) if err != nil { fmt.Println(err) return err } d.cmdConn = cmdConn // handle responses d.addDoneChReaderCount(1) go func() { defer d.addDoneChReaderCount(-1) err := d.On(d.Event(ConnectedEvent), func(interface{}) { if err := d.SendDateTime(); err != nil { panic(err) } if err := d.processVideo(); err != nil { panic(err) } }) if err != nil { panic(err) } cmdLoop: for { select { case <-d.doneCh: break cmdLoop default: err := d.handleResponse(cmdConn) if err != nil { fmt.Println("response parse error:", err) } } } }() // starts notifications coming from drone to video port normally 11111 if err := d.SendCommand(d.connectionString()); err != nil { return err } // send stick commands d.addDoneChReaderCount(1) go func() { defer d.addDoneChReaderCount(-1) stickCmdLoop: for { select { case <-d.doneCh: break stickCmdLoop default: if err := d.SendStickCommand(); err != nil { fmt.Println("stick command error:", err) } time.Sleep(20 * time.Millisecond) } } }() return nil } // Halt stops the driver. func (d *Driver) Halt() error { // send a landing command when we disconnect, and give it 500ms to be received before we shutdown if d.cmdConn != nil { if err := d.Land(); err != nil { return err } } time.Sleep(500 * time.Millisecond) if d.cmdConn != nil { d.cmdConn.Close() } if d.videoConn != nil { d.videoConn.Close() } readerCount := atomic.LoadInt32(&d.doneChReaderCount) for i := 0; i < int(readerCount); i++ { d.doneCh <- struct{}{} } return nil } // TakeOff tells drones to liftoff and start flying. func (d *Driver) TakeOff() error { buf, _ := d.createPacket(takeoffCommand, 0x68, 0) d.seq++ if err := binary.Write(buf, binary.LittleEndian, d.seq); err != nil { return err } if err := binary.Write(buf, binary.LittleEndian, CalculateCRC16(buf.Bytes())); err != nil { return err } _, err := d.cmdConn.Write(buf.Bytes()) return err } // Throw & Go support func (d *Driver) ThrowTakeOff() error { buf, _ := d.createPacket(throwtakeoffCommand, 0x48, 0) d.seq++ if err := binary.Write(buf, binary.LittleEndian, d.seq); err != nil { return err } if err := binary.Write(buf, binary.LittleEndian, CalculateCRC16(buf.Bytes())); err != nil { return err } _, err := d.cmdConn.Write(buf.Bytes()) return err } // Land tells drone to come in for landing. func (d *Driver) Land() error { buf, _ := d.createPacket(landCommand, 0x68, 1) d.seq++ if err := binary.Write(buf, binary.LittleEndian, d.seq); err != nil { return err } if err := binary.Write(buf, binary.LittleEndian, byte(0x00)); err != nil { return err } if err := binary.Write(buf, binary.LittleEndian, CalculateCRC16(buf.Bytes())); err != nil { return err } _, err := d.cmdConn.Write(buf.Bytes()) return err } // StopLanding tells drone to stop landing. func (d *Driver) StopLanding() error { buf, _ := d.createPacket(landCommand, 0x68, 1) d.seq++ if err := binary.Write(buf, binary.LittleEndian, d.seq); err != nil { return err } if err := binary.Write(buf, binary.LittleEndian, byte(0x01)); err != nil { return err } if err := binary.Write(buf, binary.LittleEndian, CalculateCRC16(buf.Bytes())); err != nil { return err } _, err := d.cmdConn.Write(buf.Bytes()) return err } // PalmLand tells drone to come in for a hand landing. func (d *Driver) PalmLand() error { buf, _ := d.createPacket(palmLandCommand, 0x68, 1) d.seq++ if err := binary.Write(buf, binary.LittleEndian, d.seq); err != nil { return err } if err := binary.Write(buf, binary.LittleEndian, byte(0x00)); err != nil { return err } if err := binary.Write(buf, binary.LittleEndian, CalculateCRC16(buf.Bytes())); err != nil { return err } _, err := d.cmdConn.Write(buf.Bytes()) return err } // StartVideo tells Tello to send start info (SPS/PPS) for video stream. func (d *Driver) StartVideo() error { buf, _ := d.createPacket(videoStartCommand, 0x60, 0) // seq = 0 if err := binary.Write(buf, binary.LittleEndian, int16(0x00)); err != nil { return err } if err := binary.Write(buf, binary.LittleEndian, CalculateCRC16(buf.Bytes())); err != nil { return err } _, err := d.cmdConn.Write(buf.Bytes()) return err } // SetExposure sets the drone camera exposure level. Valid levels are 0, 1, and 2. func (d *Driver) SetExposure(level int) error { if level < 0 || level > 2 { return errors.New("invalid exposure level") } buf, _ := d.createPacket(exposureCommand, 0x48, 1) d.seq++ if err := binary.Write(buf, binary.LittleEndian, d.seq); err != nil { return err } if err := binary.Write(buf, binary.LittleEndian, byte(level)); err != nil { return err } if err := binary.Write(buf, binary.LittleEndian, CalculateCRC16(buf.Bytes())); err != nil { return err } _, err := d.cmdConn.Write(buf.Bytes()) return err } // SetVideoEncoderRate sets the drone video encoder rate. func (d *Driver) SetVideoEncoderRate(rate VideoBitRate) error { buf, _ := d.createPacket(videoEncoderRateCommand, 0x68, 1) d.seq++ if err := binary.Write(buf, binary.LittleEndian, d.seq); err != nil { return err } if err := binary.Write(buf, binary.LittleEndian, byte(rate)); err != nil { return err } if err := binary.Write(buf, binary.LittleEndian, CalculateCRC16(buf.Bytes())); err != nil { return err } _, err := d.cmdConn.Write(buf.Bytes()) return err } // SetFastMode sets the drone throttle to 1. func (d *Driver) SetFastMode() error { d.cmdMutex.Lock() defer d.cmdMutex.Unlock() d.throttle = 1 return nil } // SetSlowMode sets the drone throttle to 0. func (d *Driver) SetSlowMode() error { d.cmdMutex.Lock() defer d.cmdMutex.Unlock() d.throttle = 0 return nil } // Rate queries the current video bit rate. func (d *Driver) Rate() error { buf, _ := d.createPacket(videoRateQuery, 0x48, 0) d.seq++ if err := binary.Write(buf, binary.LittleEndian, d.seq); err != nil { return err } if err := binary.Write(buf, binary.LittleEndian, CalculateCRC16(buf.Bytes())); err != nil { return err } _, err := d.cmdConn.Write(buf.Bytes()) return err } // bound is a naive implementation that returns the smaller of x or y. func bound(x, y float32) float32 { //nolint:unparam // keep y as parameter if x < -y { return -y } if x > y { return y } return x } // Vector returns the current motion vector. // Values are from 0 to 1. // x, y, z denote forward, side and vertical translation, // and psi yaw (rotation around the z-axis). // //nolint:nonamedreturns // sufficient here func (d *Driver) Vector() (x, y, z, psi float32) { return d.ry, d.rx, d.ly, d.lx } // AddVector adds to the current motion vector. // Pass values from 0 to 1. // See Vector() for the frame of reference. func (d *Driver) AddVector(x, y, z, psi float32) error { d.cmdMutex.Lock() defer d.cmdMutex.Unlock() d.ry = bound(d.ry+x, 1) d.rx = bound(d.rx+y, 1) d.ly = bound(d.ly+z, 1) d.lx = bound(d.lx+psi, 1) return nil } // SetVector sets the current motion vector. // Pass values from 0 to 1. // See Vector() for the frame of reference. func (d *Driver) SetVector(x, y, z, psi float32) error { d.cmdMutex.Lock() defer d.cmdMutex.Unlock() d.ry = x d.rx = y d.ly = z d.lx = psi return nil } // SetX sets the x component of the current motion vector // Pass values from 0 to 1. // See Vector() for the frame of reference. func (d *Driver) SetX(x float32) error { d.cmdMutex.Lock() defer d.cmdMutex.Unlock() d.ry = x return nil } // SetY sets the y component of the current motion vector // Pass values from 0 to 1. // See Vector() for the frame of reference. func (d *Driver) SetY(y float32) error { d.cmdMutex.Lock() defer d.cmdMutex.Unlock() d.rx = y return nil } // SetZ sets the z component of the current motion vector // Pass values from 0 to 1. // See Vector() for the frame of reference. func (d *Driver) SetZ(z float32) error { d.cmdMutex.Lock() defer d.cmdMutex.Unlock() d.ly = z return nil } // SetPsi sets the psi component (yaw) of the current motion vector // Pass values from 0 to 1. // See Vector() for the frame of reference. func (d *Driver) SetPsi(psi float32) error { d.cmdMutex.Lock() defer d.cmdMutex.Unlock() d.lx = psi return nil } // Up tells the drone to ascend. Pass in an int from 0-100. func (d *Driver) Up(val int) error { d.cmdMutex.Lock() defer d.cmdMutex.Unlock() d.ly = float32(val) / 100.0 return nil } // Down tells the drone to descend. Pass in an int from 0-100. func (d *Driver) Down(val int) error { d.cmdMutex.Lock() defer d.cmdMutex.Unlock() d.ly = float32(val) / 100.0 * -1 return nil } // Forward tells the drone to go forward. Pass in an int from 0-100. func (d *Driver) Forward(val int) error { d.cmdMutex.Lock() defer d.cmdMutex.Unlock() d.ry = float32(val) / 100.0 return nil } // Backward tells drone to go in reverse. Pass in an int from 0-100. func (d *Driver) Backward(val int) error { d.cmdMutex.Lock() defer d.cmdMutex.Unlock() d.ry = float32(val) / 100.0 * -1 return nil } // Right tells drone to go right. Pass in an int from 0-100. func (d *Driver) Right(val int) error { d.cmdMutex.Lock() defer d.cmdMutex.Unlock() d.rx = float32(val) / 100.0 return nil } // Left tells drone to go left. Pass in an int from 0-100. func (d *Driver) Left(val int) error { d.cmdMutex.Lock() defer d.cmdMutex.Unlock() d.rx = float32(val) / 100.0 * -1 return nil } // Clockwise tells drone to rotate in a clockwise direction. Pass in an int from 0-100. func (d *Driver) Clockwise(val int) error { d.cmdMutex.Lock() defer d.cmdMutex.Unlock() d.lx = float32(val) / 100.0 return nil } // CounterClockwise tells drone to rotate in a counter-clockwise direction. // Pass in an int from 0-100. func (d *Driver) CounterClockwise(val int) error { d.cmdMutex.Lock() defer d.cmdMutex.Unlock() d.lx = float32(val) / 100.0 * -1 return nil } // Hover tells the drone to stop moving on the X, Y, and Z axes and stay in place func (d *Driver) Hover() { d.cmdMutex.Lock() defer d.cmdMutex.Unlock() d.rx = float32(0) d.ry = float32(0) d.lx = float32(0) d.ly = float32(0) } // CeaseRotation stops any rotational motion func (d *Driver) CeaseRotation() { d.cmdMutex.Lock() defer d.cmdMutex.Unlock() d.lx = float32(0) } // Bounce tells drone to start/stop performing the bouncing action func (d *Driver) Bounce() error { buf, _ := d.createPacket(bounceCommand, 0x68, 1) d.seq++ if err := binary.Write(buf, binary.LittleEndian, d.seq); err != nil { return err } if d.bouncing { if err := binary.Write(buf, binary.LittleEndian, byte(0x31)); err != nil { return err } } else { if err := binary.Write(buf, binary.LittleEndian, byte(0x30)); err != nil { return err } } if err := binary.Write(buf, binary.LittleEndian, CalculateCRC16(buf.Bytes())); err != nil { return err } _, err := d.cmdConn.Write(buf.Bytes()) d.bouncing = !d.bouncing return err } // Flip tells drone to flip func (d *Driver) Flip(direction FlipType) error { buf, _ := d.createPacket(flipCommand, 0x70, 1) d.seq++ if err := binary.Write(buf, binary.LittleEndian, d.seq); err != nil { return err } if err := binary.Write(buf, binary.LittleEndian, byte(direction)); err != nil { return err } if err := binary.Write(buf, binary.LittleEndian, CalculateCRC16(buf.Bytes())); err != nil { return err } _, err := d.cmdConn.Write(buf.Bytes()) return err } // FrontFlip tells the drone to perform a front flip. func (d *Driver) FrontFlip() error { return d.Flip(FlipFront) } // BackFlip tells the drone to perform a back flip. func (d *Driver) BackFlip() error { return d.Flip(FlipBack) } // RightFlip tells the drone to perform a flip to the right. func (d *Driver) RightFlip() error { return d.Flip(FlipRight) } // LeftFlip tells the drone to perform a flip to the left. func (d *Driver) LeftFlip() error { return d.Flip(FlipLeft) } // ParseFlightData from drone func (d *Driver) ParseFlightData(b []byte) (*FlightData, error) { buf := bytes.NewReader(b) fd := &FlightData{} var data byte if buf.Len() < 24 { err := errors.New("invalid buffer length for flight data packet") fmt.Println(err) return fd, err } if err := binary.Read(buf, binary.LittleEndian, &fd.Height); err != nil { return fd, err } if err := binary.Read(buf, binary.LittleEndian, &fd.NorthSpeed); err != nil { return fd, err } if err := binary.Read(buf, binary.LittleEndian, &fd.EastSpeed); err != nil { return fd, err } if err := binary.Read(buf, binary.LittleEndian, &fd.VerticalSpeed); err != nil { return fd, err } if err := binary.Read(buf, binary.LittleEndian, &fd.FlyTime); err != nil { return fd, err } if err := binary.Read(buf, binary.LittleEndian, &data); err != nil { return fd, err } fd.ImuState = (data >> 0 & 0x1) == 1 fd.PressureState = (data >> 1 & 0x1) == 1 fd.DownVisualState = (data >> 2 & 0x1) == 1 fd.PowerState = (data >> 3 & 0x1) == 1 fd.BatteryState = (data >> 4 & 0x1) == 1 fd.GravityState = (data >> 5 & 0x1) == 1 fd.WindState = (data >> 7 & 0x1) == 1 if err := binary.Read(buf, binary.LittleEndian, &fd.ImuCalibrationState); err != nil { return fd, err } if err := binary.Read(buf, binary.LittleEndian, &fd.BatteryPercentage); err != nil { return fd, err } if err := binary.Read(buf, binary.LittleEndian, &fd.DroneFlyTimeLeft); err != nil { return fd, err } if err := binary.Read(buf, binary.LittleEndian, &fd.DroneBatteryLeft); err != nil { return fd, err } if err := binary.Read(buf, binary.LittleEndian, &data); err != nil { return fd, err } fd.Flying = (data >> 0 & 0x1) == 1 fd.OnGround = (data >> 1 & 0x1) == 1 fd.EmOpen = (data >> 2 & 0x1) == 1 fd.DroneHover = (data >> 3 & 0x1) == 1 fd.OutageRecording = (data >> 4 & 0x1) == 1 fd.BatteryLow = (data >> 5 & 0x1) == 1 fd.BatteryLower = (data >> 6 & 0x1) == 1 fd.FactoryMode = (data >> 7 & 0x1) == 1 if err := binary.Read(buf, binary.LittleEndian, &fd.FlyMode); err != nil { return fd, err } if err := binary.Read(buf, binary.LittleEndian, &fd.ThrowFlyTimer); err != nil { return fd, err } if err := binary.Read(buf, binary.LittleEndian, &fd.CameraState); err != nil { return fd, err } if err := binary.Read(buf, binary.LittleEndian, &data); err != nil { return fd, err } fd.ElectricalMachineryState = int16(data & 0xff) if err := binary.Read(buf, binary.LittleEndian, &data); err != nil { return fd, err } fd.FrontIn = (data >> 0 & 0x1) == 1 fd.FrontOut = (data >> 1 & 0x1) == 1 fd.FrontLSC = (data >> 2 & 0x1) == 1 if err := binary.Read(buf, binary.LittleEndian, &data); err != nil { return fd, err } fd.TemperatureHigh = (data >> 0 & 0x1) == 1 return fd, nil } // SendStickCommand sends the joystick command packet to the drone. func (d *Driver) SendStickCommand() error { d.cmdMutex.Lock() defer d.cmdMutex.Unlock() buf, _ := d.createPacket(stickCommand, 0x60, 11) // seq = 0 if err := binary.Write(buf, binary.LittleEndian, int16(0x00)); err != nil { return err } // RightX center=1024 left =364 right =-364 axis1 := int16(660.0*d.rx + 1024.0) // RightY down =364 up =-364 axis2 := int16(660.0*d.ry + 1024.0) // LeftY down =364 up =-364 axis3 := int16(660.0*d.ly + 1024.0) // LeftX left =364 right =-364 axis4 := int16(660.0*d.lx + 1024.0) // speed control axis5 := int16(d.throttle) //nolint:gosec // TODO: fix later packedAxis := int64(axis1)&0x7FF | int64(axis2&0x7FF)<<11 | 0x7FF&int64(axis3)<<22 | 0x7FF&int64(axis4)<<33 | int64(axis5)<<44 if err := binary.Write(buf, binary.LittleEndian, byte(0xFF&packedAxis)); err != nil { return err } if err := binary.Write(buf, binary.LittleEndian, byte(packedAxis>>8&0xFF)); err != nil { return err } if err := binary.Write(buf, binary.LittleEndian, byte(packedAxis>>16&0xFF)); err != nil { return err } if err := binary.Write(buf, binary.LittleEndian, byte(packedAxis>>24&0xFF)); err != nil { return err } if err := binary.Write(buf, binary.LittleEndian, byte(packedAxis>>32&0xFF)); err != nil { return err } if err := binary.Write(buf, binary.LittleEndian, byte(packedAxis>>40&0xFF)); err != nil { return err } now := time.Now() if err := binary.Write(buf, binary.LittleEndian, byte(now.Hour())); err != nil { return err } if err := binary.Write(buf, binary.LittleEndian, byte(now.Minute())); err != nil { return err } if err := binary.Write(buf, binary.LittleEndian, byte(now.Second())); err != nil { return err } if err := binary.Write(buf, binary.LittleEndian, byte(now.UnixNano()/int64(time.Millisecond)&0xff)); err != nil { return err } if err := binary.Write(buf, binary.LittleEndian, byte(now.UnixNano()/int64(time.Millisecond)>>8)); err != nil { return err } if err := binary.Write(buf, binary.LittleEndian, CalculateCRC16(buf.Bytes())); err != nil { return err } _, err := d.cmdConn.Write(buf.Bytes()) return err } // SendDateTime sends the current date/time to the drone. func (d *Driver) SendDateTime() error { d.cmdMutex.Lock() defer d.cmdMutex.Unlock() buf, _ := d.createPacket(timeCommand, 0x50, 11) d.seq++ if err := binary.Write(buf, binary.LittleEndian, d.seq); err != nil { return err } now := time.Now() if err := binary.Write(buf, binary.LittleEndian, byte(0x00)); err != nil { return err } //nolint:gosec // TODO: fix later if err := binary.Write(buf, binary.LittleEndian, int16(now.Hour())); err != nil { return err } //nolint:gosec // TODO: fix later if err := binary.Write(buf, binary.LittleEndian, int16(now.Minute())); err != nil { return err } //nolint:gosec // TODO: fix later if err := binary.Write(buf, binary.LittleEndian, int16(now.Second())); err != nil { return err } //nolint:gosec // TODO: fix later if err := binary.Write(buf, binary.LittleEndian, int16(now.UnixNano()/int64(time.Millisecond)&0xff)); err != nil { return err } //nolint:gosec // TODO: fix later if err := binary.Write(buf, binary.LittleEndian, int16(now.UnixNano()/int64(time.Millisecond)>>8)); err != nil { return err } if err := binary.Write(buf, binary.LittleEndian, CalculateCRC16(buf.Bytes())); err != nil { return err } _, err := d.cmdConn.Write(buf.Bytes()) return err } // SendCommand is used to send a text command such as the initial connection request to the drone. func (d *Driver) SendCommand(cmd string) error { _, err := d.cmdConn.Write([]byte(cmd)) return err } func (d *Driver) handleResponse(r io.Reader) error { var buf [2048]byte var msgType uint16 n, err := r.Read(buf[0:]) if err != nil { return err } // parse binary packet if buf[0] == messageStart { msgType = (uint16(buf[6]) << 8) | uint16(buf[5]) switch msgType { case wifiMessage: wd := &WifiData{ Strength: int8(buf[9:10][0]), Disturb: int8(buf[10:11][0]), } d.Publish(d.Event(WifiDataEvent), wd) case lightMessage: d.Publish(d.Event(LightStrengthEvent), int8(buf[9:10][0])) case logMessage: d.Publish(d.Event(LogEvent), buf[9:]) case timeCommand: d.Publish(d.Event(TimeEvent), buf[7:8]) case bounceCommand: d.Publish(d.Event(BounceEvent), buf[7:8]) case takeoffCommand: d.Publish(d.Event(TakeoffEvent), buf[7:8]) case landCommand: d.Publish(d.Event(LandingEvent), buf[7:8]) case palmLandCommand: d.Publish(d.Event(PalmLandingEvent), buf[7:8]) case flipCommand: d.Publish(d.Event(FlipEvent), buf[7:8]) case flightMessage: fd, _ := d.ParseFlightData(buf[9:]) d.Publish(d.Event(FlightDataEvent), fd) case exposureCommand: d.Publish(d.Event(SetExposureEvent), buf[7:8]) case videoEncoderRateCommand: d.Publish(d.Event(SetVideoEncoderRateEvent), buf[7:8]) default: fmt.Printf("Unknown message: %+v\n", buf[0:n]) } return nil } // parse text packet if buf[0] == 0x63 && buf[1] == 0x6f && buf[2] == 0x6e { d.Publish(d.Event(ConnectedEvent), nil) } return nil } func (d *Driver) processVideo() error { videoPort, err := net.ResolveUDPAddr("udp", ":11111") if err != nil { return err } d.videoConn, err = net.ListenUDP("udp", videoPort) if err != nil { return err } d.addDoneChReaderCount(1) go func() { defer d.addDoneChReaderCount(-1) videoConnLoop: for { select { case <-d.doneCh: break videoConnLoop default: buf := make([]byte, 2048) n, _, err := d.videoConn.ReadFromUDP(buf) if err != nil { fmt.Println("Error: ", err) continue } d.Publish(d.Event(VideoFrameEvent), buf[2:n]) } } }() return nil } func (d *Driver) createPacket(cmd int16, pktType byte, pktLen int16) (*bytes.Buffer, error) { l := pktLen + 11 buf := &bytes.Buffer{} if err := binary.Write(buf, binary.LittleEndian, byte(messageStart)); err != nil { return buf, err } if err := binary.Write(buf, binary.LittleEndian, l<<3); err != nil { return buf, err } if err := binary.Write(buf, binary.LittleEndian, CalculateCRC8(buf.Bytes()[0:3])); err != nil { return buf, err } if err := binary.Write(buf, binary.LittleEndian, pktType); err != nil { return buf, err } if err := binary.Write(buf, binary.LittleEndian, cmd); err != nil { return buf, err } return buf, nil } func (d *Driver) connectionString() string { x, _ := strconv.Atoi(d.videoPort) b := [2]byte{} binary.LittleEndian.PutUint16(b[:], uint16(x)) //nolint:gosec // TODO: fix later res := fmt.Sprintf("conn_req:%s", b) return res } func (d *Driver) addDoneChReaderCount(delta int32) { atomic.AddInt32(&d.doneChReaderCount, delta) } func (f *FlightData) AirSpeed() float64 { return math.Sqrt( math.Pow(float64(f.NorthSpeed), 2) + math.Pow(float64(f.EastSpeed), 2) + math.Pow(float64(f.VerticalSpeed), 2)) } func (f *FlightData) GroundSpeed() float64 { return math.Sqrt( math.Pow(float64(f.NorthSpeed), 2) + math.Pow(float64(f.EastSpeed), 2)) } ================================================ FILE: platforms/dji/tello/driver_test.go ================================================ package tello import ( "bytes" "encoding/binary" "fmt" "io" "sync" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) var _ gobot.Driver = (*Driver)(nil) type WriteCloserDoNothing struct{} func (w *WriteCloserDoNothing) Write(p []byte) (int, error) { return 0, nil } func (w *WriteCloserDoNothing) Close() error { return nil } func TestNewDriver(t *testing.T) { d := NewDriver("8888") assert.Equal(t, "8888", d.respPort) } func Test_handleResponse(t *testing.T) { tests := map[string]struct { msg []byte wantEvent string wantData (interface{}) err error }{ "[empty message]": { msg: nil, err: io.EOF, }, "wifiMessage": { msg: statusMessage(wifiMessage, 0x07, 0x08, 0xA3, 0x0A), wantEvent: WifiDataEvent, wantData: &WifiData{Strength: -93, Disturb: 10}, }, "lightMessage": { msg: statusMessage(lightMessage, 0x17, 0x18, 0xFF), wantEvent: LightStrengthEvent, wantData: int8(-1), }, "logMessage": { msg: statusMessage(logMessage), wantEvent: LogEvent, wantData: make([]byte, 2048-9), }, "timeCommand": { msg: statusMessage(timeCommand, 0x27), wantEvent: TimeEvent, wantData: []uint8{0x27}, }, "bounceCommand": { msg: statusMessage(bounceCommand, 0x37), wantEvent: BounceEvent, wantData: []uint8{0x37}, }, "takeoffCommand": { msg: statusMessage(takeoffCommand, 0x47), wantEvent: TakeoffEvent, wantData: []uint8{0x47}, }, "landCommand": { msg: statusMessage(landCommand, 0x57), wantEvent: LandingEvent, wantData: []uint8{0x57}, }, "palmLandCommand": { msg: statusMessage(palmLandCommand, 0x67), wantEvent: PalmLandingEvent, wantData: []uint8{0x67}, }, "flipCommand": { msg: statusMessage(flipCommand, 0x77), wantEvent: FlipEvent, wantData: []uint8{0x77}, }, "flightMessage": { msg: statusMessage(flightMessage, 0x87, 0x88, 0x60, 0xA4), wantEvent: FlightDataEvent, wantData: &FlightData{Height: -23456}, }, "exposureCommand": { msg: statusMessage(exposureCommand, 0x97), wantEvent: SetExposureEvent, wantData: []uint8{0x97}, }, "videoEncoderRateCommand": { msg: statusMessage(videoEncoderRateCommand, 0xa7), wantEvent: SetVideoEncoderRateEvent, wantData: []uint8{0xA7}, }, "ConnectedEvent": { msg: []byte{0x63, 0x6f, 0x6e}, wantEvent: ConnectedEvent, wantData: nil, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { d := NewDriver("8888") events := d.Subscribe() err := d.handleResponse(bytes.NewReader(tc.msg)) require.ErrorIs(t, tc.err, err) if tc.wantEvent != "" { select { case ev, ok := <-events: if !ok { t.Error("subscription channel is closed") } require.Equal(t, tc.wantEvent, ev.Name) got := fmt.Sprintf("%T %+[1]v", ev.Data) want := fmt.Sprintf("%T %+[1]v", tc.wantData) require.Equal(t, want, got) case <-time.After(5 * time.Millisecond): t.Error("subscription channel seems empty") } } }) } } func TestHaltShouldTerminateAllTheRelatedGoroutines(t *testing.T) { d := NewDriver("8888") d.cmdConn = &WriteCloserDoNothing{} var wg sync.WaitGroup wg.Add(3) d.addDoneChReaderCount(1) go func() { <-d.doneCh d.addDoneChReaderCount(-1) wg.Done() fmt.Println("Done routine 1.") }() d.addDoneChReaderCount(1) go func() { <-d.doneCh d.addDoneChReaderCount(-1) wg.Done() fmt.Println("Done routine 2.") }() d.addDoneChReaderCount(1) go func() { <-d.doneCh d.addDoneChReaderCount(-1) wg.Done() fmt.Println("Done routine 3.") }() _ = d.Halt() wg.Wait() assert.Equal(t, int32(0), d.doneChReaderCount) } func TestHaltNotWaitForeverWhenCalledMultipleTimes(t *testing.T) { d := NewDriver("8888") d.cmdConn = &WriteCloserDoNothing{} _ = d.Halt() _ = d.Halt() _ = d.Halt() } func statusMessage(msgType uint16, msgAfter7 ...byte) []byte { msg := make([]byte, 7, len(msgAfter7)+7) msg[0] = messageStart binary.LittleEndian.PutUint16(msg[5:7], msgType) msg = append(msg, msgAfter7...) return msg } ================================================ FILE: platforms/dji/tello/pitch.go ================================================ package tello import "math" // ValidatePitch helps validate pitch values such as those created by // a joystick to values between 0-100 that are required as // params to Tello stick commands. func ValidatePitch(data float64, offset float64) int { value := math.Abs(data) / offset if value >= 0.1 { if value <= 1.0 { return int((float64(int(value*100)) / 100) * 100) } return 100 } return 0 } ================================================ FILE: platforms/dji/tello/pitch_test.go ================================================ package tello import ( "testing" "github.com/stretchr/testify/assert" ) func TestMinidroneValidatePitchWhenEqualOffset(t *testing.T) { assert.Equal(t, 100, ValidatePitch(32767.0, 32767.0)) } func TestMinidroneValidatePitchWhenTiny(t *testing.T) { assert.Equal(t, 0, ValidatePitch(1.1, 32767.0)) } func TestMinidroneValidatePitchWhenCentered(t *testing.T) { assert.Equal(t, 50, ValidatePitch(16383.5, 32767.0)) } ================================================ FILE: platforms/dragonboard/LICENSE ================================================ Copyright (c) 2015-2018 The Hybrid Group Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: platforms/dragonboard/README.md ================================================ # DragonBoard™ 410c The [DragonBoard 410c](http://www.96boards.org/product/dragonboard410c/), a product of Arrow Electronics, is the development board based on the mid-tier Qualcomm® Snapdragon™ 410E processor. It features advanced processing power, Wi-Fi, Bluetooth connectivity, and GPS, all packed into a board the size of a credit card. ## How to Install Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) Make sure you are using the latest Linaro Debian image. Both AArch32 and AArch64 work™ though you should stick to 64bit as OS internals may be different and aren't tested. You would normally install Go and Gobot on your workstation. Once installed, cross compile your program on your workstation, transfer the final executable to your DragonBoard and run the program on the DragonBoard itself as documented here. ## How to Use Please refer to one example for your platform, e.g. [dragonboard_button.go](https://github.com/hybridgroup/gobot/blob/release/examples/dragonboard_button.go). The pin numbering used by your Gobot program should match the way your board is labeled right on the board itself. See [here](https://www.96boards.org/db410c-getting-started/HardwareDocs/HWUserManual.md/). ## How to Connect ### Compiling Compile your Gobot program on your workstation like this: ```sh GOARCH=arm64 GOOS=linux go build examples/dragonboard_button.go ``` Once you have compiled your code, you can you can upload your program and execute it on the DragonBoard from your workstation using the `scp` and `ssh` commands like this: ```sh scp dragonboard_button root@192.168.1.xx: ssh -t root@192.168.1.xx "./dragonboard_button" ``` ================================================ FILE: platforms/dragonboard/doc.go ================================================ /* Package dragonboard contains the Gobot adaptor for the DragonBoard 410c For further information refer to the chip README: https://github.com/hybridgroup/gobot/blob/release/platforms/dragonboard/README.md */ package dragonboard // import "gobot.io/x/gobot/v2/platforms/dragonboard" ================================================ FILE: platforms/dragonboard/dragonboard_adaptor.go ================================================ package dragonboard import ( "fmt" "sync" multierror "github.com/hashicorp/go-multierror" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/adaptors" "gobot.io/x/gobot/v2/system" ) const ( defaultI2cBusNumber = 0 defaultSpiMaxSpeed = 5000 // 5kHz (more than 15kHz not possible with SPI over GPIO) ) // Adaptor represents a Gobot Adaptor for a DragonBoard 410c type Adaptor struct { *adaptors.DigitalPinsAdaptor *adaptors.I2cBusAdaptor *adaptors.SpiBusAdaptor // for usage of "adaptors.WithSpiGpioAccess()" name string sys *system.Accesser // used for unit tests only mutex sync.Mutex pinMap map[string]int } // Valid pins are the GPIO_A through GPIO_L pins from the // extender (pins 23-34 on header J8), as well as the SoC pins // aka all the other pins, APQ GPIO_0-GPIO_122 and PM_MPP_0-4. var fixedPins = map[string]int{ "GPIO_A": 36, "GPIO_B": 12, "GPIO_C": 13, "GPIO_D": 69, "GPIO_E": 115, "GPIO_F": 507, "GPIO_G": 24, "GPIO_H": 25, "GPIO_I": 35, "GPIO_J": 34, "GPIO_K": 28, "GPIO_L": 33, "LED_1": 21, "LED_2": 120, } // NewAdaptor creates a DragonBoard 410c Adaptor // // Optional parameters: // // adaptors.WithGpioCdevAccess(): use character device driver instead of sysfs // adaptors.WithSpiGpioAccess(sclk, ncs, sdo, sdi): use GPIO's instead of /dev/spidev#.# // // Further optional parameters for: // // GPIO, see [adaptors.NewDigitalPinsAdaptor] // I2C, see [adaptors.NewI2cBusAdaptor] // SPI, see [adaptors.NewSpiBusAdaptor] func NewAdaptor(opts ...interface{}) *Adaptor { sys := system.NewAccesser(system.WithDigitalPinSysfsAccess()) a := &Adaptor{ name: gobot.DefaultName("DragonBoard"), sys: sys, } var digitalPinsOpts []adaptors.DigitalPinsOptionApplier var i2cBusOpts []adaptors.I2CBusOptionApplier var spiBusOpts []adaptors.SpiBusOptionApplier for _, opt := range opts { switch o := opt.(type) { case adaptors.DigitalPinsOptionApplier: digitalPinsOpts = append(digitalPinsOpts, o) case adaptors.I2CBusOptionApplier: i2cBusOpts = append(i2cBusOpts, o) case adaptors.SpiBusOptionApplier: spiBusOpts = append(spiBusOpts, o) default: panic(fmt.Sprintf("'%s' can not be applied on adaptor '%s'", opt, a.name)) } } // Valid bus numbers are [0,1] which corresponds to /dev/i2c-0 through /dev/i2c-1. i2cBusNumberValidator := adaptors.NewBusNumberValidator([]int{0, 1}) a.DigitalPinsAdaptor = adaptors.NewDigitalPinsAdaptor(sys, a.translateDigitalPin, digitalPinsOpts...) a.I2cBusAdaptor = adaptors.NewI2cBusAdaptor(sys, i2cBusNumberValidator.Validate, defaultI2cBusNumber, i2cBusOpts...) // SPI is only supported when "adaptors.WithSpiGpioAccess()" is given if len(spiBusOpts) > 0 { a.SpiBusAdaptor = adaptors.NewSpiBusAdaptor(sys, func(int) error { return nil }, 0, 0, 0, 0, defaultSpiMaxSpeed, a.DigitalPinsAdaptor, spiBusOpts...) } a.pinMap = fixedPins for i := 0; i < 122; i++ { pin := fmt.Sprintf("GPIO_%d", i) a.pinMap[pin] = i } return a } // Name returns the name of the Adaptor func (a *Adaptor) Name() string { return a.name } // SetName sets the name of the Adaptor func (a *Adaptor) SetName(n string) { a.name = n } // Connect create new connection to board and pins. func (a *Adaptor) Connect() error { a.mutex.Lock() defer a.mutex.Unlock() if err := a.I2cBusAdaptor.Connect(); err != nil { return err } return a.DigitalPinsAdaptor.Connect() } // Finalize closes connection to board and pins func (a *Adaptor) Finalize() error { a.mutex.Lock() defer a.mutex.Unlock() err := a.DigitalPinsAdaptor.Finalize() if e := a.I2cBusAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } return err } func (a *Adaptor) translateDigitalPin(id string) (string, int, error) { if line, ok := a.pinMap[id]; ok { return "", line, nil } return "", -1, fmt.Errorf("'%s' is not a valid id for a digital pin", id) } ================================================ FILE: platforms/dragonboard/dragonboard_adaptor_test.go ================================================ package dragonboard import ( "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/adaptors" ) // make sure that this Adaptor fulfills all the required interfaces var ( _ gobot.Adaptor = (*Adaptor)(nil) _ gobot.DigitalPinnerProvider = (*Adaptor)(nil) _ gpio.DigitalReader = (*Adaptor)(nil) _ gpio.DigitalWriter = (*Adaptor)(nil) _ i2c.Connector = (*Adaptor)(nil) ) func initConnectedTestAdaptor() *Adaptor { a := NewAdaptor() if err := a.Connect(); err != nil { panic(err) } return a } func TestNewAdaptor(t *testing.T) { // arrange & act a := NewAdaptor() // assert assert.IsType(t, &Adaptor{}, a) assert.True(t, strings.HasPrefix(a.Name(), "DragonBoard")) assert.NotNil(t, a.sys) assert.NotNil(t, a.pinMap) assert.NotNil(t, a.DigitalPinsAdaptor) assert.NotNil(t, a.I2cBusAdaptor) assert.Nil(t, a.SpiBusAdaptor) assert.True(t, a.sys.HasDigitalPinSysfsAccess()) // act & assert a.SetName("NewName") assert.Equal(t, "NewName", a.Name()) } func TestNewAdaptorWithOption(t *testing.T) { // arrange & act a := NewAdaptor(adaptors.WithSpiGpioAccess("1", "2", "3", "4")) // assert assert.IsType(t, &Adaptor{}, a) assert.True(t, strings.HasPrefix(a.Name(), "DragonBoard")) assert.NotNil(t, a.sys) assert.NotNil(t, a.pinMap) assert.NotNil(t, a.DigitalPinsAdaptor) assert.NotNil(t, a.I2cBusAdaptor) assert.NotNil(t, a.SpiBusAdaptor) assert.True(t, a.sys.HasDigitalPinSysfsAccess()) } func TestDigitalIO(t *testing.T) { a := initConnectedTestAdaptor() mockPaths := []string{ "/sys/class/gpio/export", "/sys/class/gpio/unexport", "/sys/class/gpio/gpio36/value", "/sys/class/gpio/gpio36/direction", "/sys/class/gpio/gpio12/value", "/sys/class/gpio/gpio12/direction", } fs := a.sys.UseMockFilesystem(mockPaths) _ = a.DigitalWrite("GPIO_B", 1) assert.Equal(t, "1", fs.Files["/sys/class/gpio/gpio12/value"].Contents) fs.Files["/sys/class/gpio/gpio36/value"].Contents = "1" i, _ := a.DigitalRead("GPIO_A") assert.Equal(t, 1, i) require.ErrorContains(t, a.DigitalWrite("GPIO_M", 1), "'GPIO_M' is not a valid id for a digital pin") require.NoError(t, a.Finalize()) } func TestFinalizeErrorAfterGPIO(t *testing.T) { a := initConnectedTestAdaptor() mockPaths := []string{ "/sys/class/gpio/export", "/sys/class/gpio/unexport", "/sys/class/gpio/gpio36/value", "/sys/class/gpio/gpio36/direction", "/sys/class/gpio/gpio12/value", "/sys/class/gpio/gpio12/direction", } fs := a.sys.UseMockFilesystem(mockPaths) require.NoError(t, a.DigitalWrite("GPIO_B", 1)) fs.WithWriteError = true err := a.Finalize() require.ErrorContains(t, err, "write error") } func TestI2cDefaultBus(t *testing.T) { a := initConnectedTestAdaptor() assert.Equal(t, 0, a.DefaultI2cBus()) } func TestI2cFinalizeWithErrors(t *testing.T) { // arrange a := initConnectedTestAdaptor() a.sys.UseMockSyscall() fs := a.sys.UseMockFilesystem([]string{"/dev/i2c-1"}) con, err := a.GetI2cConnection(0xff, 1) require.NoError(t, err) _, err = con.Write([]byte{0xbf}) require.NoError(t, err) fs.WithCloseError = true // act err = a.Finalize() // assert require.ErrorContains(t, err, "close error") } ================================================ FILE: platforms/firmata/LICENSE ================================================ Copyright (c) 2013-2018 The Hybrid Group Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: platforms/firmata/README.md ================================================ # Firmata Arduino is an open-source electronics prototyping platform based on flexible, easy-to-use hardware and software. It's intended for artists, designers, hobbyists and anyone interested in creating interactive objects or environments. This package provides the adaptor for microcontrollers such as Arduino that support the [Firmata](https://github.com/firmata/protocol) protocol. You can connect to the microcontroller using either a serial connection, or a TCP connection to a WiFi-connected microcontroller such as the ESP8266. For more info about the Arduino platform, go to [http://arduino.cc/](http://arduino.cc/). ## How to Install Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) You must install Firmata on your microcontroller before you can connect to it using Gobot. You can do this in many cases using Gort ([http://gort.io](http://gort.io)). In order to use a TCP connection with a WiFi-enbaled microcontroller, you must install WifiFirmata on the microcontroller. You can use the Arduino IDE to do this. ## How to Use With a serial connection: ```go package main import ( "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/firmata" ) func main() { firmataAdaptor := firmata.NewAdaptor("/dev/ttyACM0") led := gpio.NewLedDriver(firmataAdaptor, "13") work := func() { gobot.Every(1*time.Second, func() { if err := led.Toggle(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("bot", []gobot.Connection{firmataAdaptor}, []gobot.Device{led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ``` With a TCP connection, use the `NewTCPAdaptor`: ```go package main import ( "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/firmata" ) func main() { firmataAdaptor := firmata.NewTCPAdaptor("192.168.0.66:3030") led := gpio.NewLedDriver(firmataAdaptor, "2") work := func() { gobot.Every(1*time.Second, func() { if err := led.Toggle(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("bot", []gobot.Connection{firmataAdaptor}, []gobot.Device{led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ``` **Important** note that analog pins A4 and A5 are normally used by the Firmata I2C interface, so you will not be able to use them as analog inputs without changing the Firmata sketch. ## How to Connect ### Upload the Firmata Firmware to the Arduino This section assumes you're using an Arduino Uno or another compatible board. If you already have the Firmata sketch installed, you can skip straight to the examples. ### OS X First plug the Arduino into your computer via the USB/serial port. A dialog box will appear telling you that a new network interface has been detected. Click "Network Preferences...", and when it opens, simply click "Apply". Once plugged in, use [Gort](http://gort.io)'s `gort scan serial` command to find out your connection info and serial port address: ```sh gort scan serial ``` Use the `gort arduino install` command to install `avrdude`, this will allow you to upload firmata to the arduino: ```sh gort arduino install ``` Once the avrdude uploader is installed we upload the firmata protocol to the arduino, use the arduino serial port address found when you ran `gort scan serial`: ```sh gort arduino upload firmata /dev/tty.usbmodem1421 ``` Now you are ready to connect and communicate with the Arduino using serial port connection Note that Gobot works best with the `tty.` version of the serial port as shown above, not the `cu.` version. ### Ubuntu First plug the Arduino into your computer via the USB/serial port. Once plugged in, use [Gort](http://gort.io)'s `gort scan serial` command to find out your connection info and serial port address: ```sh gort scan serial ``` Use the `gort arduino install` command to install `avrdude`, this will allow you to upload firmata to the arduino: ```sh gort arduino install ``` Once the avrdude uploader is installed we upload the firmata protocol to the arduino, use the arduino serial port address found when you ran `gort scan serial`, or leave it blank to use the default address `ttyACM0`: ```sh gort arduino upload firmata /dev/ttyACM0 ``` Now you are ready to connect and communicate with the Arduino using serial port connection ### Windows First download and install gort for your OS from the [gort.io](gort.io) [downloads page](http://gort.io/documentation/getting_started/downloads/) and install it. Open a command prompt window by right clicking on the start button and choose `Command Prompt (Admin)` (on windows 8.1). Then navigate to the folder where you uncompressed gort (uncomress to a folder first if you haven't done this yet). Once inside the gort folder, first install avrdude which we'll use to upload firmata to the arduino. ```cmd gort arduino install ``` When the installation is complete, close the command prompt window and open a new one. We need to do this for the env variables to reload. ```cmd gort scan serial ``` Take note of your arduinos serialport address (COM1 | COM2 | COM3| etc). You need to already have installed the arduino drivers from [arduino.cc/en/Main/Software](https://www.arduino.cc/en/Main/Software). Finally upload the firmata protocol sketch to the arduino. ```cmd gort arduino upload firmata ``` Make sure to substitute `` with the apropiate serialport address. Now you are ready to connect and communicate with the Arduino using serial port connection. ### Using arduino IDE Open arduino IDE and go to File > Examples > Firmata > StandardFirmata and open it. Select the appriate port for your arduino and click upload. Wait for the upload to finish and you should be ready to start using Gobot with your arduino. ## Hardware Support The following Firmata devices have been tested and are known to work: - [Arduino Uno R3](http://arduino.cc/en/Main/arduinoBoardUno) - [Arduino/Genuino 101](https://www.arduino.cc/en/Main/ArduinoBoard101) - [Teensy 3.0](http://www.pjrc.com/store/teensy3.html) The following WiFi devices have been tested and are known to work: - [NodeMCU 1.0](http://nodemcu.com/index_en.html) More devices are coming soon... ================================================ FILE: platforms/firmata/ble_firmata_adaptor.go ================================================ //go:build !windows // +build !windows package firmata import ( "io" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/ble" "gobot.io/x/gobot/v2/platforms/bleclient" ) const ( // ReceiveID is the BLE characteristic ID for receiving serial data ReceiveID = "6e400003b5a3f393e0a9e50e24dcca9e" // TransmitID is the BLE characteristic ID for transmitting serial data TransmitID = "6e400002b5a3f393e0a9e50e24dcca9e" ) // BLEAdaptor represents a Bluetooth LE based connection to a // microcontroller running FirmataBLE type BLEAdaptor struct { *Adaptor } // NewBLEAdaptor opens and uses a BLE connection to a // microcontroller running FirmataBLE func NewBLEAdaptor(args ...interface{}) *BLEAdaptor { address := args[0].(string) //nolint:forcetypeassert // ok here rid := ReceiveID wid := TransmitID //nolint:forcetypeassert // ok here if len(args) >= 3 { rid = args[1].(string) wid = args[2].(string) } a := NewAdaptor(address) a.SetName(gobot.DefaultName("BLEFirmata")) a.PortOpener = func(port string) (io.ReadWriteCloser, error) { a := bleclient.NewAdaptor(address) sp := ble.NewSerialPortDriver(a, rid, wid) if err := sp.Open(); err != nil { return sp, err } return sp, nil } return &BLEAdaptor{ Adaptor: a, } } ================================================ FILE: platforms/firmata/ble_firmata_adaptor_test.go ================================================ //go:build !windows // +build !windows package firmata import ( "strings" "testing" "github.com/stretchr/testify/assert" "gobot.io/x/gobot/v2" ) var _ gobot.Adaptor = (*BLEAdaptor)(nil) func initTestBLEAdaptor() *BLEAdaptor { a := NewBLEAdaptor("DEVICE", "123", "456") return a } func TestFirmataBLEAdaptor(t *testing.T) { a := initTestBLEAdaptor() assert.True(t, strings.HasPrefix(a.Name(), "BLEFirmata")) } ================================================ FILE: platforms/firmata/client/client.go ================================================ // Package client provies a client for interacting with microcontrollers // using the Firmata protocol https://github.com/firmata/protocol. package client // import "gobot.io/x/gobot/v2/platforms/firmata/client" import ( "errors" "fmt" "io" "math" "sync/atomic" "time" "gobot.io/x/gobot/v2" ) // Pin Modes const ( Input = 0x00 Output = 0x01 Analog = 0x02 Pwm = 0x03 Servo = 0x04 ) // Sysex Codes const ( ProtocolVersion byte = 0xF9 SystemReset byte = 0xFF DigitalMessage byte = 0x90 DigitalMessageRangeStart byte = 0x90 DigitalMessageRangeEnd byte = 0x9F AnalogMessage byte = 0xE0 AnalogMessageRangeStart byte = 0xE0 AnalogMessageRangeEnd byte = 0xEF ReportAnalog byte = 0xC0 ReportDigital byte = 0xD0 PinMode byte = 0xF4 StartSysex byte = 0xF0 EndSysex byte = 0xF7 CapabilityQuery byte = 0x6B CapabilityResponse byte = 0x6C PinStateQuery byte = 0x6D PinStateResponse byte = 0x6E AnalogMappingQuery byte = 0x69 AnalogMappingResponse byte = 0x6A StringData byte = 0x71 I2CRequest byte = 0x76 I2CReply byte = 0x77 I2CConfig byte = 0x78 FirmwareQuery byte = 0x79 I2CModeWrite byte = 0x00 I2CModeRead byte = 0x01 I2CModeContinuousRead byte = 0x02 I2CModeStopReading byte = 0x03 ServoConfig byte = 0x70 ) // Errors var ( ErrConnected = errors.New("client is already connected") ) // Client represents a client connection to a firmata board type Client struct { gobot.Eventer pins []Pin FirmwareName string ProtocolVersion string connecting atomic.Value connected atomic.Value connection io.ReadWriteCloser analogPins []int ConnectTimeout time.Duration } // Pin represents a pin on the firmata board type Pin struct { SupportedModes []int Mode int Value int State int AnalogChannel int } // I2cReply represents the response from an I2cReply message type I2cReply struct { Address int Register int Data []byte } // New returns a new Client func New() *Client { c := &Client{ ProtocolVersion: "", FirmwareName: "", connection: nil, ConnectTimeout: 15 * time.Second, pins: []Pin{}, analogPins: []int{}, Eventer: gobot.NewEventer(), } c.connecting.Store(false) c.connected.Store(false) for _, s := range []string{ "FirmwareQuery", "CapabilityQuery", "AnalogMappingQuery", "ProtocolVersion", "I2cReply", "StringData", "Error", } { c.AddEvent(s) } return c } func (b *Client) setConnecting(c bool) { b.connecting.Store(c) } func (b *Client) setConnected(c bool) { b.connected.Store(c) } // Disconnect disconnects the Client func (b *Client) Disconnect() error { b.setConnected(false) return b.connection.Close() } // Connecting returns true when the client is connecting func (b *Client) Connecting() bool { //nolint:forcetypeassert // ok here return b.connecting.Load().(bool) } // Connected returns the current connection state of the Client func (b *Client) Connected() bool { //nolint:forcetypeassert // ok here return b.connected.Load().(bool) } // Pins returns all available pins func (b *Client) Pins() []Pin { return b.pins } // Connect connects to the Client given conn. It first resets the firmata board // then continuously polls the firmata board for new information when it's // available. func (b *Client) Connect(conn io.ReadWriteCloser) error { if b.Connected() { return ErrConnected } b.connection = conn if err := b.Reset(); err != nil { return err } connected := make(chan bool, 1) connectError := make(chan error, 1) if err := b.Once(b.Event("ProtocolVersion"), func(data interface{}) { e := b.FirmwareQuery() if e != nil { b.setConnecting(false) connectError <- e } }); err != nil { return err } if err := b.Once(b.Event("FirmwareQuery"), func(data interface{}) { e := b.CapabilitiesQuery() if e != nil { b.setConnecting(false) connectError <- e } }); err != nil { return err } if err := b.Once(b.Event("CapabilityQuery"), func(data interface{}) { e := b.AnalogMappingQuery() if e != nil { b.setConnecting(false) connectError <- e } }); err != nil { return err } if err := b.Once(b.Event("AnalogMappingQuery"), func(data interface{}) { if err := b.ReportDigital(0, 1); err != nil { panic(err) } if err := b.ReportDigital(1, 1); err != nil { panic(err) } b.setConnecting(false) b.setConnected(true) connected <- true }); err != nil { return err } // start it off... b.setConnecting(true) if err := b.ProtocolVersionQuery(); err != nil { return err } go func() { for { if !b.Connecting() { return } if e := b.process(); e != nil { connectError <- e return } time.Sleep(10 * time.Millisecond) } }() select { case <-connected: case e := <-connectError: return e case <-time.After(b.ConnectTimeout): return errors.New("unable to connect. Perhaps you need to flash your Arduino with Firmata?") } go func() { for b.Connected() { if err := b.process(); err != nil { b.Publish(b.Event("Error"), err) } } }() return nil } // Reset sends the SystemReset sysex code. func (b *Client) Reset() error { return b.write([]byte{SystemReset}) } // SetPinMode sets the pin to mode. func (b *Client) SetPinMode(pin int, mode int) error { b.pins[byte(pin)].Mode = mode return b.write([]byte{PinMode, byte(pin), byte(mode)}) } // DigitalWrite writes value to pin. func (b *Client) DigitalWrite(pin int, value int) error { port := byte(math.Floor(float64(pin) / 8)) portValue := byte(0) b.pins[pin].Value = value for i := byte(0); i < 8; i++ { if b.pins[8*port+i].Value != 0 { portValue = portValue | (1 << i) } } return b.write([]byte{DigitalMessage | port, portValue & 0x7F, (portValue >> 7) & 0x7F}) } // ServoConfig sets the min and max pulse width for servo PWM range func (b *Client) ServoConfig(pin int, maximum int, minimum int) error { ret := []byte{ ServoConfig, byte(pin), byte(minimum & 0x7F), byte((minimum >> 7) & 0x7F), byte(maximum & 0x7F), byte((maximum >> 7) & 0x7F), } return b.WriteSysex(ret) } // AnalogWrite writes value to pin. func (b *Client) AnalogWrite(pin int, value int) error { b.pins[pin].Value = value return b.write([]byte{AnalogMessage | byte(pin), byte(value & 0x7F), byte((value >> 7) & 0x7F)}) } // FirmwareQuery sends the FirmwareQuery sysex code. func (b *Client) FirmwareQuery() error { return b.WriteSysex([]byte{FirmwareQuery}) } // PinStateQuery sends a PinStateQuery for pin. func (b *Client) PinStateQuery(pin int) error { return b.WriteSysex([]byte{PinStateQuery, byte(pin)}) } // ProtocolVersionQuery sends the ProtocolVersion sysex code. func (b *Client) ProtocolVersionQuery() error { return b.write([]byte{ProtocolVersion}) } // CapabilitiesQuery sends the CapabilityQuery sysex code. func (b *Client) CapabilitiesQuery() error { return b.WriteSysex([]byte{CapabilityQuery}) } // AnalogMappingQuery sends the AnalogMappingQuery sysex code. func (b *Client) AnalogMappingQuery() error { return b.WriteSysex([]byte{AnalogMappingQuery}) } // ReportDigital enables or disables digital reporting for pin, a non zero // state enables reporting func (b *Client) ReportDigital(pin int, state int) error { return b.togglePinReporting(pin, state, ReportDigital) } // ReportAnalog enables or disables analog reporting for pin, a non zero // state enables reporting func (b *Client) ReportAnalog(pin int, state int) error { return b.togglePinReporting(pin, state, ReportAnalog) } // I2cRead reads numBytes from address once. func (b *Client) I2cRead(address int, numBytes int) error { return b.WriteSysex([]byte{ I2CRequest, byte(address), (I2CModeRead << 3), byte(numBytes) & 0x7F, (byte(numBytes) >> 7) & 0x7F, }) } // I2cWrite writes data to address. func (b *Client) I2cWrite(address int, data []byte) error { ret := []byte{I2CRequest, byte(address), (I2CModeWrite << 3)} for _, val := range data { ret = append(ret, val&0x7F) ret = append(ret, (val>>7)&0x7F) } return b.WriteSysex(ret) } // I2cConfig configures the delay in which a register can be read from after it // has been written to. func (b *Client) I2cConfig(delay int) error { return b.WriteSysex([]byte{I2CConfig, byte(delay & 0xFF), byte((delay >> 8) & 0xFF)}) } func (b *Client) togglePinReporting(pin int, state int, mode byte) error { if state != 0 { state = 1 } else { state = 0 } return b.write([]byte{mode | byte(pin), byte(state)}) } // WriteSysex writes an arbitrary Sysex command to the microcontroller. func (b *Client) WriteSysex(data []byte) error { return b.write(append([]byte{StartSysex}, append(data, EndSysex)...)) } func (b *Client) write(data []byte) error { _, err := b.connection.Write(data) return err } func (b *Client) read(n int) ([]byte, error) { buf := make([]byte, n) _, err := io.ReadFull(b.connection, buf) return buf, err } func (b *Client) process() error { msgBuf, err := b.read(1) if err != nil { return err } messageType := msgBuf[0] switch { case ProtocolVersion == messageType: buf, err := b.read(2) if err != nil { return err } b.ProtocolVersion = fmt.Sprintf("%v.%v", buf[0], buf[1]) b.Publish(b.Event("ProtocolVersion"), b.ProtocolVersion) case AnalogMessageRangeStart <= messageType && AnalogMessageRangeEnd >= messageType: buf, err := b.read(2) if err != nil { return err } value := uint(buf[0]) | uint(buf[1])<<7 pin := int((messageType & 0x0F)) if len(b.analogPins) > pin { if len(b.pins) > b.analogPins[pin] { //nolint:gosec // TODO: fix later b.pins[b.analogPins[pin]].Value = int(value) b.Publish(b.Event(fmt.Sprintf("AnalogRead%v", pin)), b.pins[b.analogPins[pin]].Value) } } case DigitalMessageRangeStart <= messageType && DigitalMessageRangeEnd >= messageType: buf, err := b.read(2) if err != nil { return err } port := messageType & 0x0F portValue := buf[0] | (buf[1] << 7) for i := 0; i < 8; i++ { pinNumber := int((8*port + byte(i))) if len(b.pins) > pinNumber { if b.pins[pinNumber].Mode == Input { b.pins[pinNumber].Value = int((portValue >> (byte(i) & 0x07)) & 0x01) b.Publish(b.Event(fmt.Sprintf("DigitalRead%v", pinNumber)), b.pins[pinNumber].Value) } } } case StartSysex == messageType: buf, err := b.read(2) if err != nil { return err } currentBuffer := append(msgBuf, buf[0], buf[1]) for { buf, err = b.read(1) if err != nil { return err } currentBuffer = append(currentBuffer, buf[0]) if buf[0] == EndSysex { break } } command := currentBuffer[1] switch command { case CapabilityResponse: b.pins = []Pin{} supportedModes := 0 n := 0 for _, val := range currentBuffer[2 : len(currentBuffer)-1] { if val == 127 { modes := []int{} for _, mode := range []int{Input, Output, Analog, Pwm, Servo} { if (supportedModes & (1 << byte(mode))) != 0 { modes = append(modes, mode) } } b.pins = append(b.pins, Pin{SupportedModes: modes, Mode: Output}) b.AddEvent(fmt.Sprintf("DigitalRead%v", len(b.pins)-1)) b.AddEvent(fmt.Sprintf("PinState%v", len(b.pins)-1)) supportedModes = 0 n = 0 continue } if n == 0 { supportedModes = supportedModes | (1 << val) } n ^= 1 } b.Publish(b.Event("CapabilityQuery"), nil) case AnalogMappingResponse: pinIndex := 0 b.analogPins = []int{} for _, val := range currentBuffer[2 : len(currentBuffer)-1] { b.pins[pinIndex].AnalogChannel = int(val) if val != 127 { b.analogPins = append(b.analogPins, pinIndex) } b.AddEvent(fmt.Sprintf("AnalogRead%v", pinIndex)) pinIndex++ } b.Publish(b.Event("AnalogMappingQuery"), nil) case PinStateResponse: pin := currentBuffer[2] b.pins[pin].Mode = int(currentBuffer[3]) b.pins[pin].State = int(currentBuffer[4]) if len(currentBuffer) > 6 { //nolint:gosec // TODO: fix later b.pins[pin].State = int(uint(b.pins[pin].State) | uint(currentBuffer[5])<<7) } if len(currentBuffer) > 7 { //nolint:gosec // TODO: fix later b.pins[pin].State = int(uint(b.pins[pin].State) | uint(currentBuffer[6])<<14) } b.Publish(b.Event(fmt.Sprintf("PinState%v", pin)), b.pins[pin]) case I2CReply: reply := I2cReply{ Address: int(currentBuffer[2] | currentBuffer[3]<<7), Register: int(currentBuffer[4] | currentBuffer[5]<<7), Data: []byte{currentBuffer[6] | currentBuffer[7]<<7}, } for i := 8; i < len(currentBuffer); i = i + 2 { if currentBuffer[i] == byte(0xF7) { break } if i+2 > len(currentBuffer) { break } reply.Data = append(reply.Data, currentBuffer[i]|currentBuffer[i+1]<<7, ) } b.Publish(b.Event("I2cReply"), reply) case FirmwareQuery: name := []byte{} for _, val := range currentBuffer[4:(len(currentBuffer) - 1)] { if val != 0 { name = append(name, val) } } b.FirmwareName = string(name) b.Publish(b.Event("FirmwareQuery"), b.FirmwareName) case StringData: str := currentBuffer[2:] b.Publish(b.Event("StringData"), string(str[:len(str)-1])) default: data := make([]byte, len(currentBuffer)) copy(data, currentBuffer) b.Publish("SysexResponse", data) } } return nil } ================================================ FILE: platforms/firmata/client/client_test.go ================================================ package client import ( "bytes" "log" "sync" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) const semPublishWait = 30 * time.Millisecond type readWriteCloser struct { id string } var ( testWriteData = bytes.Buffer{} writeDataMutex sync.Mutex ) // do not set this data directly, use always addTestReadData() var ( testReadDataMap = make(map[string][]byte) rwDataMapMutex sync.Mutex ) // arduino uno r3 protocol response "2.3" var testDataProtocolResponse = []byte{249, 2, 3} // arduino uno r3 firmware response "StandardFirmata.ino" var testDataFirmwareResponse = []byte{ 240, 121, 2, 3, 83, 0, 116, 0, 97, 0, 110, 0, 100, 0, 97, 0, 114, 0, 100, 0, 70, 0, 105, 0, 114, 0, 109, 0, 97, 0, 116, 0, 97, 0, 46, 0, 105, 0, 110, 0, 111, 0, 247, } // arduino uno r3 capabilities response var testDataCapabilitiesResponse = []byte{ 240, 108, 127, 127, 0, 1, 1, 1, 4, 14, 127, 0, 1, 1, 1, 3, 8, 4, 14, 127, 0, 1, 1, 1, 4, 14, 127, 0, 1, 1, 1, 3, 8, 4, 14, 127, 0, 1, 1, 1, 3, 8, 4, 14, 127, 0, 1, 1, 1, 4, 14, 127, 0, 1, 1, 1, 4, 14, 127, 0, 1, 1, 1, 3, 8, 4, 14, 127, 0, 1, 1, 1, 3, 8, 4, 14, 127, 0, 1, 1, 1, 3, 8, 4, 14, 127, 0, 1, 1, 1, 4, 14, 127, 0, 1, 1, 1, 4, 14, 127, 0, 1, 1, 1, 2, 10, 127, 0, 1, 1, 1, 2, 10, 127, 0, 1, 1, 1, 2, 10, 127, 0, 1, 1, 1, 2, 10, 127, 0, 1, 1, 1, 2, 10, 6, 1, 127, 0, 1, 1, 1, 2, 10, 6, 1, 127, 247, } // arduino uno r3 analog mapping response var testDataAnalogMappingResponse = []byte{ 240, 106, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 0, 1, 2, 3, 4, 5, 247, } func (readWriteCloser) Write(p []byte) (int, error) { writeDataMutex.Lock() defer writeDataMutex.Unlock() return testWriteData.Write(p) } func (rwc readWriteCloser) addTestReadData(d []byte) { // concurrent read/change of map is not allowed rwDataMapMutex.Lock() defer rwDataMapMutex.Unlock() data, ok := testReadDataMap[rwc.id] if !ok { data = []byte{} } data = append(data, d...) testReadDataMap[rwc.id] = data } func (rwc readWriteCloser) Read(b []byte) (int, error) { // concurrent change of map is not allowed rwDataMapMutex.Lock() defer rwDataMapMutex.Unlock() data, ok := testReadDataMap[rwc.id] if !ok { // there was no content stored before to read log.Printf("no content stored in %s", rwc.id) return 0, nil } size := len(b) if len(data) < size { size = len(data) } copy(b, data[:size]) testReadDataMap[rwc.id] = data[size:] return size, nil } func (readWriteCloser) Close() error { return nil } func initTestFirmataWithReadWriteCloser(name string, data ...[]byte) (*Client, readWriteCloser) { b := New() rwc := readWriteCloser{id: name} b.connection = rwc for _, d := range data { rwc.addTestReadData(d) _ = b.process() } b.setConnected(true) return b, rwc } func TestPins(t *testing.T) { b, _ := initTestFirmataWithReadWriteCloser(t.Name(), testDataCapabilitiesResponse, testDataAnalogMappingResponse) assert.Len(t, b.Pins(), 20) assert.Len(t, b.analogPins, 6) } func TestProtocolVersionQuery(t *testing.T) { b, _ := initTestFirmataWithReadWriteCloser(t.Name()) require.NoError(t, b.ProtocolVersionQuery()) } func TestFirmwareQuery(t *testing.T) { b, _ := initTestFirmataWithReadWriteCloser(t.Name()) require.NoError(t, b.FirmwareQuery()) } func TestPinStateQuery(t *testing.T) { b, _ := initTestFirmataWithReadWriteCloser(t.Name()) require.NoError(t, b.PinStateQuery(1)) } func TestProcessProtocolVersion(t *testing.T) { sem := make(chan bool) b, rwc := initTestFirmataWithReadWriteCloser(t.Name()) rwc.addTestReadData(testDataProtocolResponse) _ = b.Once(b.Event("ProtocolVersion"), func(data interface{}) { assert.Equal(t, "2.3", data) sem <- true }) _ = b.process() select { case <-sem: case <-time.After(semPublishWait): require.Fail(t, "ProtocolVersion was not published") } } func TestProcessAnalogRead0(t *testing.T) { sem := make(chan bool) b, rwc := initTestFirmataWithReadWriteCloser(t.Name(), testDataCapabilitiesResponse, testDataAnalogMappingResponse) rwc.addTestReadData([]byte{0xE0, 0x23, 0x05}) _ = b.Once(b.Event("AnalogRead0"), func(data interface{}) { assert.Equal(t, 675, data) sem <- true }) _ = b.process() select { case <-sem: case <-time.After(semPublishWait): require.Fail(t, "AnalogRead0 was not published") } } func TestProcessAnalogRead1(t *testing.T) { sem := make(chan bool) b, rwc := initTestFirmataWithReadWriteCloser(t.Name(), testDataCapabilitiesResponse, testDataAnalogMappingResponse) rwc.addTestReadData([]byte{0xE1, 0x23, 0x06}) _ = b.Once(b.Event("AnalogRead1"), func(data interface{}) { assert.Equal(t, 803, data) sem <- true }) _ = b.process() select { case <-sem: case <-time.After(semPublishWait): require.Fail(t, "AnalogRead1 was not published") } } func TestProcessDigitalRead2(t *testing.T) { sem := make(chan bool) b, rwc := initTestFirmataWithReadWriteCloser(t.Name(), testDataCapabilitiesResponse) b.pins[2].Mode = Input rwc.addTestReadData([]byte{0x90, 0x04, 0x00}) _ = b.Once(b.Event("DigitalRead2"), func(data interface{}) { assert.Equal(t, 1, data) sem <- true }) _ = b.process() select { case <-sem: case <-time.After(semPublishWait): require.Fail(t, "DigitalRead2 was not published") } } func TestProcessDigitalRead4(t *testing.T) { sem := make(chan bool) b, rwc := initTestFirmataWithReadWriteCloser(t.Name(), testDataCapabilitiesResponse) b.pins[4].Mode = Input rwc.addTestReadData([]byte{0x90, 0x16, 0x00}) _ = b.Once(b.Event("DigitalRead4"), func(data interface{}) { assert.Equal(t, 1, data) sem <- true }) _ = b.process() select { case <-sem: case <-time.After(semPublishWait): require.Fail(t, "DigitalRead4 was not published") } } func TestDigitalWrite(t *testing.T) { b, _ := initTestFirmataWithReadWriteCloser(t.Name(), testDataCapabilitiesResponse) require.NoError(t, b.DigitalWrite(13, 0)) } func TestSetPinMode(t *testing.T) { b, _ := initTestFirmataWithReadWriteCloser(t.Name(), testDataCapabilitiesResponse) require.NoError(t, b.SetPinMode(13, Output)) } func TestAnalogWrite(t *testing.T) { b, _ := initTestFirmataWithReadWriteCloser(t.Name(), testDataCapabilitiesResponse) require.NoError(t, b.AnalogWrite(0, 128)) } func TestReportAnalog(t *testing.T) { b, _ := initTestFirmataWithReadWriteCloser(t.Name()) require.NoError(t, b.ReportAnalog(0, 1)) require.NoError(t, b.ReportAnalog(0, 0)) } func TestProcessPinState13(t *testing.T) { sem := make(chan bool) b, rwc := initTestFirmataWithReadWriteCloser(t.Name(), testDataCapabilitiesResponse, testDataAnalogMappingResponse) rwc.addTestReadData([]byte{240, 110, 13, 1, 1, 247}) _ = b.Once(b.Event("PinState13"), func(data interface{}) { assert.Equal(t, Pin{[]int{0, 1, 4}, 1, 0, 1, 127}, data) sem <- true }) _ = b.process() select { case <-sem: case <-time.After(semPublishWait): require.Fail(t, "PinState13 was not published") } } func TestI2cConfig(t *testing.T) { b, _ := initTestFirmataWithReadWriteCloser(t.Name()) require.NoError(t, b.I2cConfig(100)) } func TestI2cWrite(t *testing.T) { b, _ := initTestFirmataWithReadWriteCloser(t.Name()) require.NoError(t, b.I2cWrite(0x00, []byte{0x01, 0x02})) } func TestI2cRead(t *testing.T) { b, _ := initTestFirmataWithReadWriteCloser(t.Name()) require.NoError(t, b.I2cRead(0x00, 10)) } func TestWriteSysex(t *testing.T) { b, _ := initTestFirmataWithReadWriteCloser(t.Name()) require.NoError(t, b.WriteSysex([]byte{0x01, 0x02})) } func TestProcessI2cReply(t *testing.T) { sem := make(chan bool) b, rwc := initTestFirmataWithReadWriteCloser(t.Name()) rwc.addTestReadData([]byte{240, 119, 9, 0, 0, 0, 24, 1, 1, 0, 26, 1, 247}) _ = b.Once(b.Event("I2cReply"), func(data interface{}) { assert.Equal(t, I2cReply{ Address: 9, Register: 0, Data: []byte{152, 1, 154}, }, data) sem <- true }) _ = b.process() select { case <-sem: case <-time.After(semPublishWait): require.Fail(t, "I2cReply was not published") } } func TestProcessFirmwareQuery(t *testing.T) { sem := make(chan bool) b, rwc := initTestFirmataWithReadWriteCloser(t.Name()) rwc.addTestReadData(testDataFirmwareResponse) _ = b.Once(b.Event("FirmwareQuery"), func(data interface{}) { assert.Equal(t, "StandardFirmata.ino", data) sem <- true }) _ = b.process() select { case <-sem: case <-time.After(semPublishWait): require.Fail(t, "FirmwareQuery was not published") } } func TestProcessStringData(t *testing.T) { sem := make(chan bool) b, rwc := initTestFirmataWithReadWriteCloser(t.Name()) rwc.addTestReadData(append([]byte{240, 0x71}, append([]byte("Hello Firmata!"), 247)...)) _ = b.Once(b.Event("StringData"), func(data interface{}) { assert.Equal(t, "Hello Firmata!", data) sem <- true }) _ = b.process() select { case <-sem: case <-time.After(semPublishWait): require.Fail(t, "StringData was not published") } } func TestConnect(t *testing.T) { b, rwc := initTestFirmataWithReadWriteCloser(t.Name()) b.setConnected(false) rwc.addTestReadData(testDataProtocolResponse) _ = b.Once(b.Event("ProtocolVersion"), func(data interface{}) { rwc.addTestReadData(testDataFirmwareResponse) }) _ = b.Once(b.Event("FirmwareQuery"), func(data interface{}) { rwc.addTestReadData(testDataCapabilitiesResponse) }) _ = b.Once(b.Event("CapabilityQuery"), func(data interface{}) { rwc.addTestReadData(testDataAnalogMappingResponse) }) _ = b.Once(b.Event("AnalogMappingQuery"), func(data interface{}) { rwc.addTestReadData(testDataProtocolResponse) }) require.NoError(t, b.Connect(rwc)) time.Sleep(150 * time.Millisecond) require.NoError(t, b.Disconnect()) } func TestServoConfig(t *testing.T) { b := New() b.connection = readWriteCloser{} tests := []struct { description string arguments [3]int expected []byte result error }{ { description: "Min values for min & max", arguments: [3]int{9, 0, 0}, expected: []byte{0xF0, 0x70, 9, 0, 0, 0, 0, 0xF7}, }, { description: "Max values for min & max", arguments: [3]int{9, 0x3FFF, 0x3FFF}, expected: []byte{0xF0, 0x70, 9, 0x7F, 0x7F, 0x7F, 0x7F, 0xF7}, }, { description: "Clipped max values for min & max", arguments: [3]int{9, 0xFFFF, 0xFFFF}, expected: []byte{0xF0, 0x70, 9, 0x7F, 0x7F, 0x7F, 0x7F, 0xF7}, }, } for _, test := range tests { writeDataMutex.Lock() testWriteData.Reset() writeDataMutex.Unlock() err := b.ServoConfig(test.arguments[0], test.arguments[1], test.arguments[2]) writeDataMutex.Lock() assert.Equal(t, test.expected, testWriteData.Bytes()) assert.Equal(t, test.result, err) writeDataMutex.Unlock() } } func TestProcessSysexData(t *testing.T) { sem := make(chan bool) b, rwc := initTestFirmataWithReadWriteCloser(t.Name()) rwc.addTestReadData([]byte{240, 17, 1, 2, 3, 247}) _ = b.Once("SysexResponse", func(data interface{}) { assert.Equal(t, []byte{240, 17, 1, 2, 3, 247}, data) sem <- true }) _ = b.process() select { case <-sem: case <-time.After(semPublishWait): require.Fail(t, "SysexResponse was not published") } } ================================================ FILE: platforms/firmata/client/examples/blink.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "go.bug.st/serial" "gobot.io/x/gobot/v2/platforms/firmata/client" ) func main() { sp, err := serial.Open("/dev/ttyACM0", &serial.Mode{BaudRate: 57600}) if err != nil { panic(err) } board := client.New() fmt.Println("connecting.....") err = board.Connect(sp) defer func() { if err := board.Disconnect(); err != nil { fmt.Println(err) } }() if err != nil { panic(err) } fmt.Println("firmware name:", board.FirmwareName) fmt.Println("firmata version:", board.ProtocolVersion) pin := 13 if err = board.SetPinMode(pin, client.Output); err != nil { panic(err) } level := 0 for { level ^= 1 if err := board.DigitalWrite(pin, level); err != nil { panic(err) } fmt.Println("level:", level) time.Sleep(500 * time.Millisecond) } } ================================================ FILE: platforms/firmata/doc.go ================================================ /* Package firmata provides the Gobot adaptor for microcontrollers that support the Firmata protocol. Installing: Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) Example: package main import ( "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/firmata" ) func main() { firmataAdaptor := firmata.NewAdaptor("/dev/ttyACM0") led := gpio.NewLedDriver(firmataAdaptor, "13") work := func() { gobot.Every(1*time.Second, func() { if err := led.Toggle(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("bot", []gobot.Connection{firmataAdaptor}, []gobot.Device{led}, work, ) if err := robot.Start(); err != nil { panic(err) } } For further information refer to firmata readme: https://github.com/hybridgroup/gobot/blob/release/platforms/firmata/README.md */ package firmata // import "gobot.io/x/gobot/v2/platforms/firmata" ================================================ FILE: platforms/firmata/firmata_adaptor.go ================================================ //go:build !windows // +build !windows package firmata import ( "fmt" "io" "strconv" "time" "go.bug.st/serial" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/firmata/client" ) type firmataBoard interface { Connect(conn io.ReadWriteCloser) error Disconnect() error Pins() []client.Pin AnalogWrite(pin int, value int) error SetPinMode(pin int, mode int) error ReportAnalog(pin int, state int) error ReportDigital(pin int, state int) error DigitalWrite(pin int, value int) error I2cRead(address int, numBytes int) error I2cWrite(address int, data []byte) error I2cConfig(delay int) error ServoConfig(pin int, maximum int, minimum int) error WriteSysex(data []byte) error gobot.Eventer } type FirmataAdaptor interface { Connect() error Finalize() error Name() string SetName(n string) WriteSysex(data []byte) error gobot.Eventer } // Adaptor is the Gobot Adaptor for Firmata based boards type Adaptor struct { gobot.Eventer name string port string Board firmataBoard conn io.ReadWriteCloser PortOpener func(port string) (io.ReadWriteCloser, error) } // NewAdaptor returns a new Firmata Adaptor which optionally accepts: // // string: port the Adaptor uses to connect to a serial port with a baude rate of 57600 // io.ReadWriteCloser: connection the Adaptor uses to communication with the hardware // // If an io.ReadWriteCloser is not supplied, the Adaptor will open a connection // to a serial port with a baude rate of 57600. If an io.ReadWriteCloser // is supplied, then the Adaptor will use the provided io.ReadWriteCloser and use the // string port as a label to be displayed in the log and api. func NewAdaptor(args ...interface{}) *Adaptor { f := &Adaptor{ name: gobot.DefaultName("Firmata"), port: "", conn: nil, Board: client.New(), PortOpener: func(port string) (io.ReadWriteCloser, error) { return serial.Open(port, &serial.Mode{BaudRate: 57600}) }, Eventer: gobot.NewEventer(), } for _, arg := range args { switch a := arg.(type) { case string: f.port = a case io.ReadWriteCloser: f.conn = a } } return f } // Connect starts a connection to the board. func (f *Adaptor) Connect() error { if f.conn == nil { sp, err := f.PortOpener(f.Port()) if err != nil { return err } f.conn = sp } if err := f.Board.Connect(f.conn); err != nil { return err } return f.Board.On("SysexResponse", func(data interface{}) { f.Publish("SysexResponse", data) }) } // Disconnect closes the io connection to the Board func (f *Adaptor) Disconnect() error { if f.Board != nil { return f.Board.Disconnect() } return nil } // Finalize terminates the firmata connection func (f *Adaptor) Finalize() error { return f.Disconnect() } // Port returns the Firmata adaptors port func (f *Adaptor) Port() string { return f.port } // Name returns the Firmata adaptors name func (f *Adaptor) Name() string { return f.name } // SetName sets the Firmata adaptors name func (f *Adaptor) SetName(n string) { f.name = n } // ServoConfig sets the pulse width in microseconds for a pin attached to a servo func (f *Adaptor) ServoConfig(pin string, minimum, maximum int) error { p, err := strconv.Atoi(pin) if err != nil { return err } return f.Board.ServoConfig(p, maximum, minimum) } // ServoWrite writes the 0-180 degree angle to the specified pin. func (f *Adaptor) ServoWrite(pin string, angle byte) error { p, err := strconv.Atoi(pin) if err != nil { return err } if f.Board.Pins()[p].Mode != client.Servo { err = f.Board.SetPinMode(p, client.Servo) if err != nil { return err } } return f.Board.AnalogWrite(p, int(angle)) } // PwmWrite writes the 0-254 value to the specified pin func (f *Adaptor) PwmWrite(pin string, level byte) error { p, err := strconv.Atoi(pin) if err != nil { return err } if f.Board.Pins()[p].Mode != client.Pwm { err = f.Board.SetPinMode(p, client.Pwm) if err != nil { return err } } return f.Board.AnalogWrite(p, int(level)) } // DigitalWrite writes a value to the pin. Acceptable values are 1 or 0. func (f *Adaptor) DigitalWrite(pin string, level byte) error { p, err := strconv.Atoi(pin) if err != nil { return err } if f.Board.Pins()[p].Mode != client.Output { if err = f.Board.SetPinMode(p, client.Output); err != nil { return err } } return f.Board.DigitalWrite(p, int(level)) } // DigitalRead retrieves digital value from specified pin. // Returns -1 if the response from the board has timed out func (f *Adaptor) DigitalRead(pin string) (int, error) { p, err := strconv.Atoi(pin) if err != nil { return 0, err } if f.Board.Pins()[p].Mode != client.Input { if err := f.Board.SetPinMode(p, client.Input); err != nil { return 0, err } if err := f.Board.ReportDigital(p, 1); err != nil { return 0, err } <-time.After(10 * time.Millisecond) } return f.Board.Pins()[p].Value, nil } // AnalogRead retrieves value from analog pin. // Returns -1 if the response from the board has timed out func (f *Adaptor) AnalogRead(pin string) (int, error) { p, err := strconv.Atoi(pin) if err != nil { return 0, err } p = f.digitalPin(p) if f.Board.Pins()[p].Mode != client.Analog { if err := f.Board.SetPinMode(p, client.Analog); err != nil { return 0, err } if err := f.Board.ReportAnalog(p, 1); err != nil { return 0, err } <-time.After(10 * time.Millisecond) } return f.Board.Pins()[p].Value, nil } func (f *Adaptor) WriteSysex(data []byte) error { return f.Board.WriteSysex(data) } // digitalPin converts pin number to digital mapping func (f *Adaptor) digitalPin(pin int) int { return pin + 14 } // GetI2cConnection returns an i2c connection to a device on a specified bus. // Only supports bus number 0 func (f *Adaptor) GetI2cConnection(address int, bus int) (i2c.Connection, error) { if bus != 0 { return nil, fmt.Errorf("invalid bus number %d, only 0 is supported", bus) } if err := f.Board.I2cConfig(0); err != nil { return nil, err } return NewFirmataI2cConnection(f, address), nil } // DefaultI2cBus returns the default i2c bus for this platform func (f *Adaptor) DefaultI2cBus() int { return 0 } ================================================ FILE: platforms/firmata/firmata_adaptor_test.go ================================================ //go:build !windows // +build !windows //nolint:forcetypeassert // ok here package firmata import ( "bytes" "errors" "io" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/firmata/client" ) // make sure that this Adaptor fulfills all required analog and digital interfaces var ( _ gobot.Adaptor = (*Adaptor)(nil) _ gpio.DigitalReader = (*Adaptor)(nil) _ gpio.DigitalWriter = (*Adaptor)(nil) _ aio.AnalogReader = (*Adaptor)(nil) _ gpio.PwmWriter = (*Adaptor)(nil) _ gpio.ServoWriter = (*Adaptor)(nil) _ FirmataAdaptor = (*Adaptor)(nil) ) type readWriteCloser struct{} func (readWriteCloser) Write(p []byte) (int, error) { return testWriteData.Write(p) } var ( testReadData = []byte{} testWriteData = bytes.Buffer{} ) func (readWriteCloser) Read(b []byte) (int, error) { size := len(b) if len(testReadData) < size { size = len(testReadData) } copy(b, testReadData[:size]) testReadData = testReadData[size:] return size, nil } func (readWriteCloser) Close() error { return nil } type mockFirmataBoard struct { gobot.Eventer disconnectError error pins []client.Pin } func newMockFirmataBoard() *mockFirmataBoard { m := &mockFirmataBoard{ Eventer: gobot.NewEventer(), disconnectError: nil, pins: make([]client.Pin, 100), } m.pins[1].Value = 1 m.pins[15].Value = 133 return m } // setup mock for GPIO, PWM and servo tests func (mockFirmataBoard) Connect(io.ReadWriteCloser) error { return nil } func (m mockFirmataBoard) Disconnect() error { return m.disconnectError } func (m mockFirmataBoard) Pins() []client.Pin { return m.pins } func (mockFirmataBoard) AnalogWrite(int, int) error { return nil } func (mockFirmataBoard) SetPinMode(int, int) error { return nil } func (mockFirmataBoard) ReportAnalog(int, int) error { return nil } func (mockFirmataBoard) ReportDigital(int, int) error { return nil } func (mockFirmataBoard) DigitalWrite(int, int) error { return nil } func (mockFirmataBoard) ServoConfig(int, int, int) error { return nil } func (mockFirmataBoard) WriteSysex([]byte) error { return nil } // i2c functions unused in this test scenarios func (mockFirmataBoard) I2cRead(int, int) error { return nil } func (mockFirmataBoard) I2cWrite(int, []byte) error { return nil } func (mockFirmataBoard) I2cConfig(int) error { return nil } func initTestAdaptor() *Adaptor { a := NewAdaptor("/dev/null") a.Board = newMockFirmataBoard() a.PortOpener = func(port string) (io.ReadWriteCloser, error) { return &readWriteCloser{}, nil } _ = a.Connect() return a } func TestNewAdaptor(t *testing.T) { a := NewAdaptor("/dev/null") assert.Equal(t, "/dev/null", a.Port()) } func TestAdaptorFinalize(t *testing.T) { a := initTestAdaptor() require.NoError(t, a.Finalize()) a = initTestAdaptor() a.Board.(*mockFirmataBoard).disconnectError = errors.New("close error") require.ErrorContains(t, a.Finalize(), "close error") } func TestAdaptorConnect(t *testing.T) { openSP := func(port string) (io.ReadWriteCloser, error) { return &readWriteCloser{}, nil } a := NewAdaptor("/dev/null") a.PortOpener = openSP a.Board = newMockFirmataBoard() require.NoError(t, a.Connect()) a = NewAdaptor("/dev/null") a.Board = newMockFirmataBoard() a.PortOpener = func(port string) (io.ReadWriteCloser, error) { return nil, errors.New("connect error") } require.ErrorContains(t, a.Connect(), "connect error") a = NewAdaptor(&readWriteCloser{}) a.Board = newMockFirmataBoard() require.NoError(t, a.Connect()) a = NewAdaptor("/dev/null") a.Board = nil require.NoError(t, a.Disconnect()) } func TestAdaptorServoWrite(t *testing.T) { a := initTestAdaptor() require.NoError(t, a.ServoWrite("1", 50)) } func TestAdaptorServoWriteBadPin(t *testing.T) { a := initTestAdaptor() require.Error(t, a.ServoWrite("xyz", 50)) } func TestAdaptorPwmWrite(t *testing.T) { a := initTestAdaptor() require.NoError(t, a.PwmWrite("1", 50)) } func TestAdaptorPwmWriteBadPin(t *testing.T) { a := initTestAdaptor() require.Error(t, a.PwmWrite("xyz", 50)) } func TestAdaptorDigitalWrite(t *testing.T) { a := initTestAdaptor() require.NoError(t, a.DigitalWrite("1", 1)) } func TestAdaptorDigitalWriteBadPin(t *testing.T) { a := initTestAdaptor() require.Error(t, a.DigitalWrite("xyz", 50)) } func TestAdaptorDigitalRead(t *testing.T) { a := initTestAdaptor() val, err := a.DigitalRead("1") require.NoError(t, err) assert.Equal(t, 1, val) val, err = a.DigitalRead("0") require.NoError(t, err) assert.Equal(t, 0, val) } func TestAdaptorDigitalReadBadPin(t *testing.T) { a := initTestAdaptor() _, err := a.DigitalRead("xyz") require.Error(t, err) } func TestAdaptorAnalogRead(t *testing.T) { a := initTestAdaptor() val, err := a.AnalogRead("1") assert.Equal(t, 133, val) require.NoError(t, err) val, err = a.AnalogRead("0") require.NoError(t, err) assert.Equal(t, 0, val) } func TestAdaptorAnalogReadBadPin(t *testing.T) { a := initTestAdaptor() _, err := a.AnalogRead("xyz") require.Error(t, err) } func TestServoConfig(t *testing.T) { a := initTestAdaptor() err := a.ServoConfig("9", 0, 0) require.NoError(t, err) // test atoi error err = a.ServoConfig("a", 0, 0) require.ErrorContains(t, err, "invalid syntax") } ================================================ FILE: platforms/firmata/firmata_i2c.go ================================================ //go:build !windows // +build !windows package firmata import ( "fmt" "sync" "gobot.io/x/gobot/v2/platforms/firmata/client" ) // firmataI2cConnection implements the interface gobot.I2cOperations type firmataI2cConnection struct { address int adaptor *Adaptor mtx sync.Mutex } // NewFirmataI2cConnection creates an I2C connection to an I2C device at // the specified address func NewFirmataI2cConnection(adaptor *Adaptor, address int) *firmataI2cConnection { return &firmataI2cConnection{adaptor: adaptor, address: address} } // Read tries to read a full buffer from the i2c device. // Returns an empty array if the response from the board has timed out. func (c *firmataI2cConnection) Read(b []byte) (int, error) { c.mtx.Lock() defer c.mtx.Unlock() return c.readInternal(b) } // Write writes the buffer content in data to the i2c device. func (c *firmataI2cConnection) Write(data []byte) (int, error) { c.mtx.Lock() defer c.mtx.Unlock() return c.writeInternal(data) } // Close do nothing than return nil. func (c *firmataI2cConnection) Close() error { return nil } // ReadByte reads one byte from the i2c device. func (c *firmataI2cConnection) ReadByte() (byte, error) { c.mtx.Lock() defer c.mtx.Unlock() buf := []byte{0} if err := c.readAndCheckCount(buf); err != nil { return 0, err } return buf[0], nil } // ReadByteData reads one byte of the given register address from the i2c device. // TODO: implement the specification, because some devices will not work with this // // current: "S Addr Wr [A] Comm [A] P S Addr Rd [A] [Data] NA P" // required: "S Addr Wr [A] Comm [A] S Addr Rd [A] [Data] NA P" func (c *firmataI2cConnection) ReadByteData(reg uint8) (uint8, error) { c.mtx.Lock() defer c.mtx.Unlock() if err := c.writeAndCheckCount([]byte{reg}); err != nil { return 0, err } buf := []byte{0} if err := c.readAndCheckCount(buf); err != nil { return 0, err } return buf[0], nil } // ReadWordData reads two bytes of the given register address from the i2c device. // TODO: implement the specification, because some devices will not work with this // // current: "S Addr Wr [A] Comm [A] P S Addr Rd [A] [DataLow] A [DataHigh] NA P" // required: "S Addr Wr [A] Comm [A] S Addr Rd [A] [DataLow] A [DataHigh] NA P" func (c *firmataI2cConnection) ReadWordData(reg uint8) (uint16, error) { c.mtx.Lock() defer c.mtx.Unlock() if err := c.writeAndCheckCount([]byte{reg}); err != nil { return uint16(0), err } buf := []byte{0, 0} if err := c.readAndCheckCount(buf); err != nil { return uint16(0), err } low, high := buf[0], buf[1] return (uint16(high) << 8) | uint16(low), nil } // ReadBlockData reads a block of maximum 32 bytes from the given register address of the i2c device. // TODO: implement the specification, because some devices will not work with this // // current: "S Addr Wr [A] Comm [A] P S Addr Rd [A] [Count] A [Data] A [Data] A ... A [Data] NA P" // required: "S Addr Wr [A] Comm [A] S Addr Rd [A] [Count] A [Data] A [Data] A ... A [Data] NA P" func (c *firmataI2cConnection) ReadBlockData(reg uint8, data []byte) error { c.mtx.Lock() defer c.mtx.Unlock() if err := c.writeAndCheckCount([]byte{reg}); err != nil { return err } if len(data) > 32 { data = data[:32] } return c.readAndCheckCount(data) } // WriteByte writes one byte to the i2c device. func (c *firmataI2cConnection) WriteByte(val byte) error { c.mtx.Lock() defer c.mtx.Unlock() buf := []byte{val} return c.writeAndCheckCount(buf) } // WriteByteData writes one byte to the given register address of the i2c device. func (c *firmataI2cConnection) WriteByteData(reg uint8, val byte) error { c.mtx.Lock() defer c.mtx.Unlock() buf := []byte{reg, val} return c.writeAndCheckCount(buf) } // WriteWordData writes two bytes to the given register address of the i2c device. func (c *firmataI2cConnection) WriteWordData(reg uint8, val uint16) error { c.mtx.Lock() defer c.mtx.Unlock() low := uint8(val & 0xff) //nolint:gosec // ok here high := uint8((val >> 8) & 0xff) //nolint:gosec // ok here buf := []byte{reg, low, high} return c.writeAndCheckCount(buf) } // WriteBlockData writes a block of maximum 32 bytes to the given register address of the i2c device. func (c *firmataI2cConnection) WriteBlockData(reg uint8, data []byte) error { c.mtx.Lock() defer c.mtx.Unlock() if len(data) > 32 { data = data[:32] } buf := make([]byte, len(data)+1) copy(buf[1:], data) buf[0] = reg return c.writeAndCheckCount(buf) } // WriteBytes writes a block of maximum 32 bytes to the current register address of the i2c device. func (c *firmataI2cConnection) WriteBytes(buf []byte) error { c.mtx.Lock() defer c.mtx.Unlock() if len(buf) > 32 { buf = buf[:32] } return c.writeAndCheckCount(buf) } func (c *firmataI2cConnection) readAndCheckCount(buf []byte) error { countRead, err := c.readInternal(buf) if err != nil { return err } expectedCount := len(buf) if countRead != expectedCount { return fmt.Errorf("firmata i2c read %d bytes, expected %d bytes", countRead, expectedCount) } return nil } func (c *firmataI2cConnection) writeAndCheckCount(buf []byte) error { countWritten, err := c.writeInternal(buf) if err != nil { return err } expectedCount := len(buf) if countWritten != expectedCount { return fmt.Errorf("firmata i2c write %d bytes, expected %d bytes", countWritten, expectedCount) } return nil } func (c *firmataI2cConnection) readInternal(b []byte) (int, error) { ret := make(chan []byte) if err := c.adaptor.Board.I2cRead(c.address, len(b)); err != nil { return 0, err } if err := c.adaptor.Board.Once(c.adaptor.Board.Event("I2cReply"), func(data interface{}) { ret <- data.(client.I2cReply).Data //nolint:forcetypeassert // ok here }); err != nil { return 0, err } result := <-ret copy(b, result) return len(result), nil } func (c *firmataI2cConnection) writeInternal(data []byte) (int, error) { var chunk []byte var written int for len(data) >= 16 { chunk, data = data[:16], data[16:] if err := c.adaptor.Board.I2cWrite(c.address, chunk); err != nil { return written, err } written += len(chunk) } if len(data) > 0 { if err := c.adaptor.Board.I2cWrite(c.address, data); err != nil { return written, err } written += len(data) } return written, nil } ================================================ FILE: platforms/firmata/firmata_i2c_test.go ================================================ //go:build !windows // +build !windows //nolint:forcetypeassert,gosec // ok here package firmata import ( "io" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/firmata/client" ) // make sure that this Adaptor fulfills all required I2C interfaces var _ i2c.Connector = (*Adaptor)(nil) type i2cMockFirmataBoard struct { gobot.Eventer i2cDataForRead []byte numBytesToRead int i2cWritten []byte } // setup mock for i2c tests func (t *i2cMockFirmataBoard) I2cRead(address int, numBytes int) error { t.numBytesToRead = numBytes i2cReply := client.I2cReply{Data: t.i2cDataForRead} go func() { <-time.After(10 * time.Millisecond) t.Publish(t.Event("I2cReply"), i2cReply) }() return nil } func (t *i2cMockFirmataBoard) I2cWrite(address int, data []byte) error { t.i2cWritten = append(t.i2cWritten, data...) return nil } func (*i2cMockFirmataBoard) I2cConfig(int) error { return nil } // GPIO, PWM and servo functions unused in this test scenarios func (*i2cMockFirmataBoard) Connect(io.ReadWriteCloser) error { return nil } func (*i2cMockFirmataBoard) Disconnect() error { return nil } func (*i2cMockFirmataBoard) Pins() []client.Pin { return nil } func (*i2cMockFirmataBoard) AnalogWrite(int, int) error { return nil } func (*i2cMockFirmataBoard) SetPinMode(int, int) error { return nil } func (*i2cMockFirmataBoard) ReportAnalog(int, int) error { return nil } func (*i2cMockFirmataBoard) ReportDigital(int, int) error { return nil } func (*i2cMockFirmataBoard) DigitalWrite(int, int) error { return nil } func (*i2cMockFirmataBoard) ServoConfig(int, int, int) error { return nil } // WriteSysex of the client implementation not tested here func (*i2cMockFirmataBoard) WriteSysex([]byte) error { return nil } func newI2cMockFirmataBoard() *i2cMockFirmataBoard { m := &i2cMockFirmataBoard{ Eventer: gobot.NewEventer(), } m.AddEvent("I2cReply") return m } func initTestTestAdaptorWithI2cConnection() (i2c.Connection, *i2cMockFirmataBoard) { a := NewAdaptor() a.Board = newI2cMockFirmataBoard() con, err := a.GetI2cConnection(0, 0) if err != nil { panic(err) } return con, a.Board.(*i2cMockFirmataBoard) } func TestClose(t *testing.T) { i2c, _ := initTestTestAdaptorWithI2cConnection() require.NoError(t, i2c.Close()) } func TestRead(t *testing.T) { // arrange con, brd := initTestTestAdaptorWithI2cConnection() brd.i2cDataForRead = []byte{111} buf := []byte{0} // act countRead, err := con.Read(buf) require.NoError(t, err) assert.Equal(t, 1, countRead) assert.Equal(t, 1, brd.numBytesToRead) assert.Equal(t, brd.i2cDataForRead, buf) assert.Empty(t, brd.i2cWritten) } func TestReadByte(t *testing.T) { // arrange con, brd := initTestTestAdaptorWithI2cConnection() brd.i2cDataForRead = []byte{222} // act val, err := con.ReadByte() // assert require.NoError(t, err) assert.Equal(t, 1, brd.numBytesToRead) assert.Equal(t, brd.i2cDataForRead[0], val) assert.Empty(t, brd.i2cWritten) } func TestReadByteData(t *testing.T) { // arrange con, brd := initTestTestAdaptorWithI2cConnection() brd.i2cDataForRead = []byte{100} reg := uint8(0x01) // act val, err := con.ReadByteData(reg) // assert require.NoError(t, err) assert.Equal(t, 1, brd.numBytesToRead) assert.Equal(t, brd.i2cDataForRead[0], val) assert.Len(t, brd.i2cWritten, 1) assert.Equal(t, reg, brd.i2cWritten[0]) } func TestReadWordData(t *testing.T) { // arrange con, brd := initTestTestAdaptorWithI2cConnection() lsb := uint8(0x11) msb := uint8(0xff) brd.i2cDataForRead = []byte{lsb, msb} reg := uint8(0x22) // act val, err := con.ReadWordData(reg) // assert require.NoError(t, err) assert.Equal(t, 2, brd.numBytesToRead) assert.Equal(t, uint16(lsb)|uint16(msb)<<8, val) assert.Len(t, brd.i2cWritten, 1) assert.Equal(t, reg, brd.i2cWritten[0]) } func TestReadBlockData(t *testing.T) { // arrange con, brd := initTestTestAdaptorWithI2cConnection() brd.i2cDataForRead = []byte{50, 40, 30, 20, 10} reg := uint8(0x33) buf := []byte{1, 2, 3, 4, 5} // act err := con.ReadBlockData(reg, buf) // assert require.NoError(t, err) assert.Equal(t, 5, brd.numBytesToRead) assert.Equal(t, brd.i2cDataForRead, buf) assert.Len(t, brd.i2cWritten, 1) assert.Equal(t, reg, brd.i2cWritten[0]) } func TestWrite(t *testing.T) { // arrange con, brd := initTestTestAdaptorWithI2cConnection() want := []byte{0x00, 0x01} wantLen := len(want) // act written, err := con.Write(want) // assert require.NoError(t, err) assert.Equal(t, wantLen, written) assert.Equal(t, want, brd.i2cWritten) } func TestWrite20bytes(t *testing.T) { // arrange con, brd := initTestTestAdaptorWithI2cConnection() want := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19} wantLen := len(want) // act written, err := con.Write(want) // assert require.NoError(t, err) assert.Equal(t, wantLen, written) assert.Equal(t, want, brd.i2cWritten) } func TestWriteByte(t *testing.T) { // arrange con, brd := initTestTestAdaptorWithI2cConnection() want := uint8(0x11) // act err := con.WriteByte(want) // assert require.NoError(t, err) assert.Len(t, brd.i2cWritten, 1) assert.Equal(t, want, brd.i2cWritten[0]) } func TestWriteByteData(t *testing.T) { // arrange con, brd := initTestTestAdaptorWithI2cConnection() reg := uint8(0x12) val := uint8(0x22) // act err := con.WriteByteData(reg, val) // assert require.NoError(t, err) assert.Len(t, brd.i2cWritten, 2) assert.Equal(t, reg, brd.i2cWritten[0]) assert.Equal(t, val, brd.i2cWritten[1]) } func TestWriteWordData(t *testing.T) { // arrange con, brd := initTestTestAdaptorWithI2cConnection() reg := uint8(0x13) val := uint16(0x8002) // act err := con.WriteWordData(reg, val) // assert require.NoError(t, err) assert.Len(t, brd.i2cWritten, 3) assert.Equal(t, reg, brd.i2cWritten[0]) assert.Equal(t, uint8(val&0x00FF), brd.i2cWritten[1]) assert.Equal(t, uint8(val>>8), brd.i2cWritten[2]) } func TestWriteBlockData(t *testing.T) { // arrange con, brd := initTestTestAdaptorWithI2cConnection() reg := uint8(0x14) val := []byte{} // we prepare more than 32 bytes, because the call has to drop it for i := uint8(0); i < 40; i++ { val = append(val, i) } // act err := con.WriteBlockData(reg, val) // assert require.NoError(t, err) assert.Len(t, brd.i2cWritten, 33) assert.Equal(t, reg, brd.i2cWritten[0]) assert.Equal(t, val[0:32], brd.i2cWritten[1:]) } func TestDefaultBus(t *testing.T) { a := NewAdaptor() assert.Equal(t, 0, a.DefaultI2cBus()) } func TestGetI2cConnectionInvalidBus(t *testing.T) { a := NewAdaptor() _, err := a.GetI2cConnection(0x01, 99) require.ErrorContains(t, err, "invalid bus number 99, only 0 is supported") } ================================================ FILE: platforms/firmata/tcp_firmata_adaptor.go ================================================ //go:build !windows // +build !windows package firmata import ( "io" "net" "gobot.io/x/gobot/v2" ) // TCPAdaptor represents a TCP based connection to a microcontroller running // WiFiFirmata type TCPAdaptor struct { *Adaptor } // NewTCPAdaptor opens and uses a TCP connection to a microcontroller running // WiFiFirmata func NewTCPAdaptor(args ...interface{}) *TCPAdaptor { address := args[0].(string) //nolint:forcetypeassert // ok here a := NewAdaptor(address) a.SetName(gobot.DefaultName("TCPFirmata")) a.PortOpener = connect return &TCPAdaptor{ Adaptor: a, } } func connect(address string) (io.ReadWriteCloser, error) { dialer := net.Dialer{} return dialer.Dial("tcp", address) } ================================================ FILE: platforms/firmata/tcp_firmata_adaptor_test.go ================================================ //go:build !windows // +build !windows package firmata import ( "strings" "testing" "github.com/stretchr/testify/assert" "gobot.io/x/gobot/v2" ) var _ gobot.Adaptor = (*TCPAdaptor)(nil) func initTestTCPAdaptor() *TCPAdaptor { a := NewTCPAdaptor("localhost:4567") return a } func TestFirmataTCPAdaptor(t *testing.T) { a := initTestTCPAdaptor() assert.True(t, strings.HasPrefix(a.Name(), "TCPFirmata")) } ================================================ FILE: platforms/friendlyelec/nanopct6/LICENSE ================================================ Copyright (c) 2025 The Hybrid Group Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: platforms/friendlyelec/nanopct6/README.md ================================================ # FriendlyELEC NanoPC-T6 The FriendlyELEC NanoPC-T6 is a single board SoC computer based on the Rockchip RK3588 arm64 processor. It has built-in GPIO, I2C, PWM, SPI, 1-Wire, MIPI CSI and MIPI DSI interfaces. For more info about the FriendlyELEC NanoPC-T6, go to [https://wiki.friendlyelec.com/wiki/index.php/NanoPC-T6](https://wiki.friendlyelec.com/wiki/index.php/NanoPC-T6). ## How to Install Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) Tested OS: * [armbian](https://www.armbian.com/nanopct6/) with "Armbian 24.11.1 Bookworm Minimal / IOT" ## Configuration steps for the OS ### System access and configuration basics Please follow the instructions of the OS provider. A ssh access is used in this guide. ```sh ssh @192.168.1.xxx ``` ### Enabling hardware drivers Not all drivers are enabled by default. You can have a look at the configuration file, to find out what is enabled at your system: ```sh cat /boot/armbianEnv.txt ``` ```sh sudo apt install armbian-config sudo armbian-config ``` ## How to Use The pin numbering used by your Gobot program should match the way your board is labeled right on the board itself. ```go r := nanopct6.NewAdaptor() led := gpio.NewLedDriver(r, "7") ``` ## How to Connect ### Compiling Compile your Gobot program on your workstation like this: ```sh GOARCH=arm64 GOOS=linux go build -o output/ examples/nanopct6_blink.go ``` Once you have compiled your code, you can upload your program and execute it on the board from your workstation using the `scp` and `ssh` commands like this: ```sh scp nanopct6_blink @192.168.1.xxx:~ ssh -t @192.168.1.xxx "./nanopct6_blink" ``` ## Troubleshooting ================================================ FILE: platforms/friendlyelec/nanopct6/adaptor.go ================================================ package nanopct6 import ( "fmt" "sync" multierror "github.com/hashicorp/go-multierror" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/adaptors" "gobot.io/x/gobot/v2/system" ) const ( defaultI2cBusNumber = 8 // on 40 pin header defaultSpiBusNumber = 0 defaultSpiChipNumber = 0 defaultSpiMode = 0 defaultSpiBitsNumber = 8 defaultSpiMaxSpeed = 500000 ) // Adaptor represents a Gobot Adaptor for the FriendlyELEC NanoPC-T6 type Adaptor struct { *adaptors.AnalogPinsAdaptor *adaptors.DigitalPinsAdaptor *adaptors.PWMPinsAdaptor *adaptors.I2cBusAdaptor *adaptors.SpiBusAdaptor *adaptors.OneWireBusAdaptor name string sys *system.Accesser // used for unit tests only mutex *sync.Mutex } // NewAdaptor creates a NanoPC-T6 Adaptor // // Optional parameters: // // adaptors.WithGpioSysfsAccess(): use legacy sysfs driver instead of default character device driver // adaptors.WithSpiGpioAccess(sclk, ncs, sdo, sdi): use GPIO's instead of /dev/spidev#.# // adaptors.WithGpiosActiveLow(pin's): invert the pin behavior // adaptors.WithGpiosPullUp/Down(pin's): sets the internal pull resistor // adaptors.WithGpiosOpenDrain/Source(pin's): sets the output behavior // adaptors.WithGpioDebounce(pin, period): sets the input debouncer // adaptors.WithGpioEventOnFallingEdge/RaisingEdge/BothEdges(pin, handler): activate edge detection // // Further optional parameters for: // // AIO, see [adaptors.NewAnalogPinsAdaptor] // GPIO, see [adaptors.NewDigitalPinsAdaptor] // I2C, see [adaptors.NewI2cBusAdaptor] // 1-wire, see [adaptors.NewOneWireBusAdaptor] // PWM, see [adaptors.NewPWMPinsAdaptor] // SPI, see [adaptors.NewSpiBusAdaptor] func NewAdaptor(opts ...interface{}) *Adaptor { sys := system.NewAccesser() a := &Adaptor{ name: gobot.DefaultName("NanoPC-T6"), sys: sys, mutex: &sync.Mutex{}, } var analogPinsOpts []adaptors.AnalogPinsOptionApplier var digitalPinsOpts []adaptors.DigitalPinsOptionApplier var pwmPinsOpts []adaptors.PwmPinsOptionApplier var i2cBusOpts []adaptors.I2CBusOptionApplier var spiBusOpts []adaptors.SpiBusOptionApplier var oneWireBusOpts []adaptors.OneWireBusOptionApplier for _, opt := range opts { switch o := opt.(type) { case adaptors.AnalogPinsOptionApplier: analogPinsOpts = append(analogPinsOpts, o) case adaptors.DigitalPinsOptionApplier: digitalPinsOpts = append(digitalPinsOpts, o) case adaptors.PwmPinsOptionApplier: pwmPinsOpts = append(pwmPinsOpts, o) case adaptors.I2CBusOptionApplier: i2cBusOpts = append(i2cBusOpts, o) case adaptors.SpiBusOptionApplier: spiBusOpts = append(spiBusOpts, o) case adaptors.OneWireBusOptionApplier: oneWireBusOpts = append(oneWireBusOpts, o) default: panic(fmt.Sprintf("'%s' can not be applied on adaptor '%s'", opt, a.name)) } } analogPinTranslator := adaptors.NewAnalogPinTranslator(sys, analogPinDefinitions) digitalPinTranslator := adaptors.NewDigitalPinTranslator(sys, gpioPinDefinitions) pwmPinTranslator := adaptors.NewPWMPinTranslator(sys, pwmPinDefinitions) // Valid bus numbers are [3,4,5,7,8] which corresponds to /dev/i2c-3, /dev/i2c-4 ... // needs to be enabled by DT-overlay: i2c3-m0, i2c4-m3, i2c5-m0, i2c8-m2 // i2c7-m0 maybe shared with sound, so 0x?? is in use // We don't support /dev/i2c-0 (voltage regulator), /dev/i2c-1 (?), /dev/i2c-2 (voltage regulator), // /dev/i2c-6 (RTC, USB-C, EEPROM 24c02), /dev/i2c-9 (ddc), /dev/i2c-10 (ddc), /dev/i2c-11 (fde50000.dp). i2cBusNumberValidator := adaptors.NewBusNumberValidator([]int{3, 4, 5, 7, 8}) // Valid bus numbers are [0,4] which corresponds to /dev/spidev0.x, /dev/spidev4.x // x is the chip number <255 spiBusNumberValidator := adaptors.NewBusNumberValidator([]int{0, 4}) a.AnalogPinsAdaptor = adaptors.NewAnalogPinsAdaptor(sys, analogPinTranslator.Translate, analogPinsOpts...) a.DigitalPinsAdaptor = adaptors.NewDigitalPinsAdaptor(sys, digitalPinTranslator.Translate, digitalPinsOpts...) a.PWMPinsAdaptor = adaptors.NewPWMPinsAdaptor(sys, pwmPinTranslator.Translate, pwmPinsOpts...) a.I2cBusAdaptor = adaptors.NewI2cBusAdaptor(sys, i2cBusNumberValidator.Validate, defaultI2cBusNumber, i2cBusOpts...) a.SpiBusAdaptor = adaptors.NewSpiBusAdaptor(sys, spiBusNumberValidator.Validate, defaultSpiBusNumber, defaultSpiChipNumber, defaultSpiMode, defaultSpiBitsNumber, defaultSpiMaxSpeed, a.DigitalPinsAdaptor, spiBusOpts...) // pin 16 needs to be activated by DT-overlay w1-gpio3-b3 a.OneWireBusAdaptor = adaptors.NewOneWireBusAdaptor(sys, oneWireBusOpts...) return a } // Name returns the name of the Adaptor func (a *Adaptor) Name() string { return a.name } // SetName sets the name of the Adaptor func (a *Adaptor) SetName(n string) { a.name = n } // Connect create new connection to board and pins. func (a *Adaptor) Connect() error { a.mutex.Lock() defer a.mutex.Unlock() if err := a.OneWireBusAdaptor.Connect(); err != nil { return err } if err := a.SpiBusAdaptor.Connect(); err != nil { return err } if err := a.I2cBusAdaptor.Connect(); err != nil { return err } if err := a.AnalogPinsAdaptor.Connect(); err != nil { return err } if err := a.PWMPinsAdaptor.Connect(); err != nil { return err } return a.DigitalPinsAdaptor.Connect() } // Finalize closes connection to board, pins and bus func (a *Adaptor) Finalize() error { a.mutex.Lock() defer a.mutex.Unlock() err := a.DigitalPinsAdaptor.Finalize() if e := a.PWMPinsAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } if e := a.AnalogPinsAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } if e := a.I2cBusAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } if e := a.SpiBusAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } if e := a.OneWireBusAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } return err } ================================================ FILE: platforms/friendlyelec/nanopct6/adaptor_test.go ================================================ package nanopct6 import ( "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/adaptors" "gobot.io/x/gobot/v2/system" ) const ( pwmDir = "/sys/devices/platform/febf0030.pwm/pwm/pwmchip7/" //nolint:gosec // false positive pwmExportPath = pwmDir + "export" pwmUnexportPath = pwmDir + "unexport" pwmPwmDir = pwmDir + "pwm0/" pwmEnablePath = pwmPwmDir + "enable" pwmPeriodPath = pwmPwmDir + "period" pwmDutyCyclePath = pwmPwmDir + "duty_cycle" pwmPolarityPath = pwmPwmDir + "polarity" pwmInvertedIdentifier = "inversed" ) var pwmMockPaths = []string{ pwmExportPath, pwmUnexportPath, pwmEnablePath, pwmPeriodPath, pwmDutyCyclePath, pwmPolarityPath, } // make sure that this Adaptor fulfills all the required interfaces var ( _ gobot.Adaptor = (*Adaptor)(nil) _ gobot.DigitalPinnerProvider = (*Adaptor)(nil) _ gobot.PWMPinnerProvider = (*Adaptor)(nil) _ gpio.DigitalReader = (*Adaptor)(nil) _ gpio.DigitalWriter = (*Adaptor)(nil) _ aio.AnalogReader = (*Adaptor)(nil) _ i2c.Connector = (*Adaptor)(nil) ) func preparePwmFs(fs *system.MockFilesystem) { fs.Files[pwmEnablePath].Contents = "0" fs.Files[pwmPeriodPath].Contents = "0" fs.Files[pwmDutyCyclePath].Contents = "0" fs.Files[pwmPolarityPath].Contents = pwmInvertedIdentifier } func initConnectedTestAdaptorWithMockedFilesystem(mockPaths []string) (*Adaptor, *system.MockFilesystem) { a := initConnectedTestAdaptor() fs := a.sys.UseMockFilesystem(mockPaths) return a, fs } func initConnectedTestAdaptor() *Adaptor { a := NewAdaptor() if err := a.Connect(); err != nil { panic(err) } return a } func TestNewAdaptor(t *testing.T) { // arrange & act a := NewAdaptor() // assert assert.IsType(t, &Adaptor{}, a) assert.True(t, strings.HasPrefix(a.Name(), "NanoPC-T6")) assert.NotNil(t, a.sys) assert.NotNil(t, a.mutex) assert.NotNil(t, a.AnalogPinsAdaptor) assert.NotNil(t, a.DigitalPinsAdaptor) assert.NotNil(t, a.PWMPinsAdaptor) assert.NotNil(t, a.I2cBusAdaptor) assert.NotNil(t, a.SpiBusAdaptor) assert.True(t, a.sys.HasDigitalPinCdevAccess()) // act & assert a.SetName("NewName") assert.Equal(t, "NewName", a.Name()) } func TestNewAdaptorWithOption(t *testing.T) { // arrange & act a := NewAdaptor(adaptors.WithGpiosActiveLow("1"), adaptors.WithGpioSysfsAccess()) // assert require.NoError(t, a.Connect()) assert.True(t, a.sys.HasDigitalPinSysfsAccess()) } func TestDigitalIO(t *testing.T) { // some basic tests, further tests are done in "digitalpinsadaptor.go" // arrange a := initConnectedTestAdaptor() dpa := a.sys.UseMockDigitalPinAccess() require.True(t, a.sys.HasDigitalPinCdevAccess()) // act & assert write err := a.DigitalWrite("7", 1) require.NoError(t, err) assert.Equal(t, []int{1}, dpa.Written("gpiochip3", "10")) // arrange, act & assert read dpa.UseValues("gpiochip0", "20", []int{3}) i, err := a.DigitalRead("10") require.NoError(t, err) assert.Equal(t, 3, i) // act and assert unknown pin require.ErrorContains(t, a.DigitalWrite("99", 1), "'99' is not a valid id for a digital pin") // act and assert finalize require.NoError(t, a.Finalize()) assert.Equal(t, 0, dpa.Exported("gpiochip3", "10")) assert.Equal(t, 0, dpa.Exported("gpiochip0", "20")) } func TestDigitalIOSysfs(t *testing.T) { // some basic tests, further tests are done in "digitalpinsadaptor.go" // arrange a := NewAdaptor(adaptors.WithGpioSysfsAccess()) require.NoError(t, a.Connect()) dpa := a.sys.UseMockDigitalPinAccess() require.True(t, a.sys.HasDigitalPinSysfsAccess()) // act & assert write err := a.DigitalWrite("7", 1) require.NoError(t, err) assert.Equal(t, []int{1}, dpa.Written("", "106")) // arrange, act & assert read dpa.UseValues("", "20", []int{4}) i, err := a.DigitalRead("10") require.NoError(t, err) assert.Equal(t, 4, i) // act and assert unknown pin require.ErrorContains(t, a.DigitalWrite("99", 1), "'99' is not a valid id for a digital pin") // act and assert finalize require.NoError(t, a.Finalize()) assert.Equal(t, 0, dpa.Exported("", "106")) assert.Equal(t, 0, dpa.Exported("", "20")) } func TestAnalogRead(t *testing.T) { mockPaths := []string{ "/sys/class/thermal/thermal_zone0/temp", } a, fs := initConnectedTestAdaptorWithMockedFilesystem(mockPaths) fs.Files["/sys/class/thermal/thermal_zone0/temp"].Contents = "567\n" got, err := a.AnalogRead("soc_thermal") require.NoError(t, err) assert.Equal(t, 567, got) _, err = a.AnalogRead("thermal_zone10") require.ErrorContains(t, err, "'thermal_zone10' is not a valid id for an analog pin") fs.WithReadError = true _, err = a.AnalogRead("soc_thermal") require.ErrorContains(t, err, "read error") fs.WithReadError = false require.NoError(t, a.Finalize()) } func TestFinalizeErrorAfterGPIO(t *testing.T) { // arrange a := initConnectedTestAdaptor() dpa := a.sys.UseMockDigitalPinAccess() require.True(t, a.sys.HasDigitalPinCdevAccess()) require.NoError(t, a.DigitalWrite("7", 1)) dpa.UseUnexportError("gpiochip3", "10") // act err := a.Finalize() // assert require.ErrorContains(t, err, "unexport error") } func TestFinalizeErrorAfterPWM(t *testing.T) { // indirect test for PWM.Finalize() is called for the adaptor // arrange a, fs := initConnectedTestAdaptorWithMockedFilesystem(pwmMockPaths) preparePwmFs(fs) require.NoError(t, a.PwmWrite("13", 1)) fs.WithWriteError = true // act err := a.Finalize() // assert require.ErrorContains(t, err, "write error") } func TestSpiDefaultValues(t *testing.T) { a := NewAdaptor() assert.Equal(t, 0, a.SpiDefaultBusNumber()) assert.Equal(t, 0, a.SpiDefaultChipNumber()) assert.Equal(t, 0, a.SpiDefaultMode()) assert.Equal(t, 8, a.SpiDefaultBitCount()) assert.Equal(t, int64(500000), a.SpiDefaultMaxSpeed()) } func TestI2cDefaultBus(t *testing.T) { a := NewAdaptor() assert.Equal(t, 8, a.DefaultI2cBus()) } func TestI2cFinalizeWithErrors(t *testing.T) { // arrange a := initConnectedTestAdaptor() a.sys.UseMockSyscall() fs := a.sys.UseMockFilesystem([]string{"/dev/i2c-4"}) con, err := a.GetI2cConnection(0xff, 4) require.NoError(t, err) _, err = con.Write([]byte{0xbf}) require.NoError(t, err) fs.WithCloseError = true // act err = a.Finalize() // assert require.ErrorContains(t, err, "close error") } ================================================ FILE: platforms/friendlyelec/nanopct6/doc.go ================================================ /* Package nanopct6 contains the Gobot adaptor for the FriendlyELEC NanoPC-T6. For further information refer to the boards README: https://github.com/hybridgroup/gobot/blob/release/platforms/friendlyelec/nanopct6/README.md */ package nanopct6 // import "gobot.io/x/gobot/v2/platforms/friendlyelec/nanopct6" ================================================ FILE: platforms/friendlyelec/nanopct6/pinmap.go ================================================ package nanopct6 import "gobot.io/x/gobot/v2/platforms/adaptors" // notes for character device // sysfs: Chip*32 + (A=0, B=8, C=16) + Nr // tested with cdev on a NanoPC-T6 2301 board: armbian Linux, OK: works, ?: unknown, NOK: not working // IN: works only as input, PU: if used as input, external pullup resistor needed var gpioPinDefinitions = adaptors.DigitalPinDefinitions{ "10": {Sysfs: 20, Cdev: adaptors.CdevPin{Chip: 0, Line: 20}}, // GPIO0_C4_UART0_RX_M0 - OK "8": {Sysfs: 21, Cdev: adaptors.CdevPin{Chip: 0, Line: 21}}, // GPIO0_C5_UART0_TX_M0_PWM4_M0 - OK "32": {Sysfs: 22, Cdev: adaptors.CdevPin{Chip: 0, Line: 22}}, // GPIO0_C6_PWM5_M1 - OK "27": {Sysfs: 32, Cdev: adaptors.CdevPin{Chip: 1, Line: 0}}, // GPIO1_A0_UART6_RX_M1 - OK "28": {Sysfs: 33, Cdev: adaptors.CdevPin{Chip: 1, Line: 1}}, // GPIO1_A1_UART6_TX_M1 - OK (UP) "15": {Sysfs: 39, Cdev: adaptors.CdevPin{Chip: 1, Line: 7}}, // GPIO1_A7 - OK "26": {Sysfs: 40, Cdev: adaptors.CdevPin{Chip: 1, Line: 8}}, // GPIO1_B0 - OK "21": {Sysfs: 41, Cdev: adaptors.CdevPin{Chip: 1, Line: 9}}, // GPIO1_B1_SPI0_MISO_M2 - OK (UP) "19": {Sysfs: 42, Cdev: adaptors.CdevPin{Chip: 1, Line: 10}}, // GPIO1_B2_SPI0_MOSI_M2_UART4_RX_M2 - OK "23": {Sysfs: 43, Cdev: adaptors.CdevPin{Chip: 1, Line: 11}}, // GPIO1_B3_SPI0_CLK_M2_UART4_TX_M2 - OK "24": {Sysfs: 44, Cdev: adaptors.CdevPin{Chip: 1, Line: 12}}, // GPIO1_B4_SPI0_CS0_M2_UART7_RX_M2 - OK "22": {Sysfs: 45, Cdev: adaptors.CdevPin{Chip: 1, Line: 13}}, // GPIO1_B5_SPI0_CS1_M0_UART7_TX_M2 - OK "5": {Sysfs: 62, Cdev: adaptors.CdevPin{Chip: 1, Line: 30}}, // GPIO1_D6_I2C8_SCL_M2 - OK "3": {Sysfs: 63, Cdev: adaptors.CdevPin{Chip: 1, Line: 31}}, // GPIO1_D7_I2C8_SDA_M2 - OK "CSI1_11": {Sysfs: 81, Cdev: adaptors.CdevPin{Chip: 2, Line: 17}}, // GPIO2_C1 - ? "CSI1_12": {Sysfs: 82, Cdev: adaptors.CdevPin{Chip: 2, Line: 18}}, // GPIO2_C2 - ? "35": {Sysfs: 96, Cdev: adaptors.CdevPin{Chip: 3, Line: 0}}, // GPIO3_A0_SPI4_MISO_M1_I2S3_MCLK_PWM10_M0 - OK "38": {Sysfs: 97, Cdev: adaptors.CdevPin{Chip: 3, Line: 1}}, // GPIO3_A1_SPI4_MOSI_M1_I2S3_SCLK - OK "40": {Sysfs: 98, Cdev: adaptors.CdevPin{Chip: 3, Line: 2}}, // GPIO3_A2_SPI4_CLK_M1_UART8_TX_M1_I2S3_LRCK - OK "36": {Sysfs: 99, Cdev: adaptors.CdevPin{Chip: 3, Line: 3}}, // GPIO3_A3_SPI4_CS0_M1_UART8_RX_M1_I2S3_SDO - OK "37": {Sysfs: 100, Cdev: adaptors.CdevPin{Chip: 3, Line: 4}}, // GPIO3_A4_SPI4_CS1_M1_I2S3_SDI - OK "DSI0_12": {Sysfs: 102, Cdev: adaptors.CdevPin{Chip: 3, Line: 6}}, // GPIO3_A6 - ? "33": {Sysfs: 104, Cdev: adaptors.CdevPin{Chip: 3, Line: 8}}, // GPIO3_B0_PWM9_M0 - OK "DSI0_10": {Sysfs: 105, Cdev: adaptors.CdevPin{Chip: 3, Line: 9}}, // GPIO3_B1_PWM2_M1 - ? "7": {Sysfs: 106, Cdev: adaptors.CdevPin{Chip: 3, Line: 10}}, // GPIO3_B2_I2S2_SDI_M1 - OK "16": {Sysfs: 107, Cdev: adaptors.CdevPin{Chip: 3, Line: 11}}, // GPIO3_B3_I2S2_SDO_M1 - OK "18": {Sysfs: 108, Cdev: adaptors.CdevPin{Chip: 3, Line: 12}}, // GPIO3_B4_I2S2_MCLK_M1 - OK "29": {Sysfs: 109, Cdev: adaptors.CdevPin{Chip: 3, Line: 13}}, // GPIO3_B5_UART3_TX_M1_I2S2_SCLK_M1_PWM12_M0 - OK "31": {Sysfs: 110, Cdev: adaptors.CdevPin{Chip: 3, Line: 14}}, // GPIO3_B6_UART3_RX_M1_I2S2_LRCK_M1_PWM13_M0 - OK "12": {Sysfs: 111, Cdev: adaptors.CdevPin{Chip: 3, Line: 15}}, // GPIO3_B7 - OK (UP) "DSI0_8": {Sysfs: 112, Cdev: adaptors.CdevPin{Chip: 3, Line: 16}}, // GPIO3_C0 - ? "DSI0_14": {Sysfs: 113, Cdev: adaptors.CdevPin{Chip: 3, Line: 17}}, // GPIO3_C1 - ? "11": {Sysfs: 114, Cdev: adaptors.CdevPin{Chip: 3, Line: 18}}, // GPIO3_C2_PWM14_M0 - OK "13": {Sysfs: 115, Cdev: adaptors.CdevPin{Chip: 3, Line: 19}}, // GPIO3_C3_PWM15_IR_M0 - OK "DSI1_10": {Sysfs: 125, Cdev: adaptors.CdevPin{Chip: 3, Line: 29}}, // GPIO3_D5_PWM11_M3 - ? "DSI1_8": {Sysfs: 128, Cdev: adaptors.CdevPin{Chip: 4, Line: 0}}, // GPIO4_A0 - ? "DSI1_14": {Sysfs: 129, Cdev: adaptors.CdevPin{Chip: 4, Line: 1}}, // GPIO4_A1 - ? "DSI1_12": {Sysfs: 131, Cdev: adaptors.CdevPin{Chip: 4, Line: 3}}, // GPIO4_A3 - ? "CSI0_11": {Sysfs: 148, Cdev: adaptors.CdevPin{Chip: 4, Line: 20}}, // GPIO4_C4 - ? "CSI0_12": {Sysfs: 149, Cdev: adaptors.CdevPin{Chip: 4, Line: 21}}, // GPIO4_C5 - ? } var pwmPinDefinitions = adaptors.PWMPinDefinitions{ // needs to be enabled by DT-overlay pwm2-m1 (pwm2 = "/pwm@fd8b0020";) "DSI0_10": {Dir: "/sys/devices/platform/fd8b0020.pwm/pwm/", DirRegexp: "pwmchip[0|1|2|3|4|5|6|7]$", Channel: 0}, // needs to be enabled by DT-overlay pwm4-m0 (pwm4 = "/pwm@febd0000";) "8": {Dir: "/sys/devices/platform/febd0000.pwm/pwm/", DirRegexp: "pwmchip[0|1|2|3|4|5|6|7]$", Channel: 0}, // needs to be enabled by DT-overlay pwm5-m1 (pwm5 = "/pwm@febd0010";) "32": {Dir: "/sys/devices/platform/febd0010.pwm/pwm/", DirRegexp: "pwmchip[0|1|2|3|4|5|6|7]$", Channel: 0}, // needs to be enabled by DT-overlay pwm9-m0 (pwm9 = "/pwm@febe0010";) "33": {Dir: "/sys/devices/platform/febe0010.pwm/pwm/", DirRegexp: "pwmchip[0|1|2|3|4|5|6|7]$", Channel: 0}, // needs to be enabled by DT-overlay pwm10-m0 (pwm10 = "/pwm@febe0020";) "35": {Dir: "/sys/devices/platform/febe0020.pwm/pwm/", DirRegexp: "pwmchip[0|1|2|3|4|5|6|7]$", Channel: 0}, // needs to be enabled by DT-overlay pwm11-m3 (pwm11 = "/pwm@febe0030";) "DSI1_10": {Dir: "/sys/devices/platform/febe0030.pwm/pwm/", DirRegexp: "pwmchip[0|1|2|3|4|5|6|7]$", Channel: 0}, // needs to be enabled by DT-overlay pwm12-m0 (pwm12 = "/pwm@febf0000";) "29": {Dir: "/sys/devices/platform/febf0000.pwm/pwm/", DirRegexp: "pwmchip[0|1|2|3|4|5|6|7]$", Channel: 0}, // needs to be enabled by DT-overlay pwm13-m0 (pwm13 = "/pwm@febf0010";) "31": {Dir: "/sys/devices/platform/febf0010.pwm/pwm/", DirRegexp: "pwmchip[0|1|2|3|4|5|6|7]$", Channel: 0}, // needs to be enabled by DT-overlay pwm14-m0 (pwm14 = "/pwm@febf0020";) "11": {Dir: "/sys/devices/platform/febf0020.pwm/pwm/", DirRegexp: "pwmchip[0|1|2|3|4|5|6|7]$", Channel: 0}, // needs to be enabled by DT-overlay pwm15-m0 (pwm15 = "/pwm@febf0030";) "13": {Dir: "/sys/devices/platform/febf0030.pwm/pwm/", DirRegexp: "pwmchip[0|1|2|3|4|5|6|7]$", Channel: 0}, } var analogPinDefinitions = adaptors.AnalogPinDefinitions{ // +/-273.200 °C need >=7 characters to read: +/-273200 millidegree Celsius // names equals /sys/class/thermal/thermal_zone*/hwmon*/name "soc_thermal": {Path: "/sys/class/thermal/thermal_zone0/temp", W: false, ReadBufLen: 7}, "bigcore0_thermal": {Path: "/sys/class/thermal/thermal_zone1/temp", W: false, ReadBufLen: 7}, "bigcore1_thermal": {Path: "/sys/class/thermal/thermal_zone2/temp", W: false, ReadBufLen: 7}, "littlecore_thermal": {Path: "/sys/class/thermal/thermal_zone3/temp", W: false, ReadBufLen: 7}, "center_thermal": {Path: "/sys/class/thermal/thermal_zone4/temp", W: false, ReadBufLen: 7}, "gpu_thermal": {Path: "/sys/class/thermal/thermal_zone5/temp", W: false, ReadBufLen: 7}, "npu_thermal": {Path: "/sys/class/thermal/thermal_zone6/temp", W: false, ReadBufLen: 7}, } ================================================ FILE: platforms/friendlyelec/nanopi/LICENSE ================================================ Copyright (c) 2014-2018 The Hybrid Group Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: platforms/friendlyelec/nanopi/README.md ================================================ # NanoPi Boards The FriendlyELEC NanoPi Boards are single board SoC computers with different hardware design. It has built-in GPIO, PWM, SPI, and I2C interfaces. For more info about the NanoPi Boards, go to [https://wiki.friendlyelec.com/wiki/index.php/NanoPi_NEO](https://wiki.friendlyelec.com/wiki/index.php/NanoPi_NEO). ## How to Install Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) Tested OS: * [armbian](https://www.armbian.com/nanopi-neo/) with Debian or Ubuntu ### System access and configuration basics Please follow the installation instructions for the chosen OS. ### Enabling hardware drivers Please follow the configuration instructions for the chosen OS. E.g. for armbian: ```sh sudo armbian-config ``` After configuration was changed, an reboot is necessary. ```sh sudo reboot ``` ## How to Use The pin numbering used by your Gobot program should match the way your board is labeled right on the board itself. ```go r := nanopi.NewNeoAdaptor() led := gpio.NewLedDriver(r, "7") ``` ## How to Connect ### Compiling Compile your Gobot program on your workstation like this: ```sh GOARM=7 GOARCH=arm GOOS=linux go build -o output/ examples/nanopi_blink.go ``` Once you have compiled your code, you can upload your program and execute it on the board from your workstation using the `scp` and `ssh` commands like this: ```sh scp output/nanopi_blink nan@nanopineo:~ ssh -t nan@nanopineo "./nanopi_blink" ``` ## GPIO's At least for NEO, nearly all 14 GPIO's supports the advanced pin options "bias", "drive", "debounce" and "edge detection". > Configure of edge detection will cause an initial event. GPIO header pins 19, 21, 23, 24 - do NOT support "debounce" and > "edge detection" for NEO. Using unsupported options leads to reconfigure errors with text "no such device or address". ## PWM A single PWM output is available at UART0-RX (UART_RXD0, internal PA5). So the UART0 needs to be disabled. The sunxi- overlay (e.g. for armbian) disables the UART0 and the kernel console at ttyS0. The related kernel module needs to be loaded: `sudo modprobe pwm-sun4i`. The default frequency is 100Hz. ## I2C The default bus number is set to 0, which is connected to header pins 3 (PA12-SDA) and 5 (PA11-SCL). At least for NEO rev.1.4 it is possible to activate bus 1, which is connected to "USB/Audio/IR" header pins 9 "PCM0_CLK/I2S0_BCK" (PA19-SDA) and 8 "PCM0_SYNC/I2S0_LRC" (PA18-SCL). Armbian allows to activate bus 2 (PE12-SCL, PE13-SDA), which pins are not wired for NEO and NEO2, but we do not block it at adaptor side. ## SPI There is a known issue on [armbian](https://forum.armbian.com/topic/20033-51525-breaks-spi-on-nanopi-neo-and-does-not-create-devspidev00/) for later Kernels. ================================================ FILE: platforms/friendlyelec/nanopi/adaptor.go ================================================ package nanopi import ( "fmt" "sync" multierror "github.com/hashicorp/go-multierror" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/adaptors" "gobot.io/x/gobot/v2/system" ) const ( defaultI2cBusNumber = 0 defaultSpiBusNumber = 0 defaultSpiChipNumber = 0 defaultSpiMode = 0 defaultSpiBitsNumber = 8 defaultSpiMaxSpeed = 500000 ) // Adaptor represents a Gobot Adaptor for the FriendlyELEC NanoPi Boards type Adaptor struct { *adaptors.AnalogPinsAdaptor *adaptors.DigitalPinsAdaptor *adaptors.PWMPinsAdaptor *adaptors.I2cBusAdaptor *adaptors.SpiBusAdaptor name string sys *system.Accesser // used for unit tests only mutex sync.Mutex } // NewNeoAdaptor creates a board adaptor for NanoPi NEO // // Optional parameters: // // adaptors.WithGpioSysfsAccess(): use legacy sysfs driver instead of default character device driver // adaptors.WithSpiGpioAccess(sclk, ncs, sdo, sdi): use GPIO's instead of /dev/spidev#.# // adaptors.WithGpiosActiveLow(pin's): invert the pin behavior // adaptors.WithGpiosPullUp/Down(pin's): sets the internal pull resistor // adaptors.WithGpiosOpenDrain/Source(pin's): sets the output behavior // adaptors.WithGpioDebounce(pin, period): sets the input debouncer // adaptors.WithGpioEventOnFallingEdge/RaisingEdge/BothEdges(pin, handler): activate edge detection // // Further optional parameters for: // // AIO, see [adaptors.NewAnalogPinsAdaptor] // GPIO, see [adaptors.NewDigitalPinsAdaptor] // I2C, see [adaptors.NewI2cBusAdaptor] // PWM, see [adaptors.NewPWMPinsAdaptor] // SPI, see [adaptors.NewSpiBusAdaptor] func NewNeoAdaptor(opts ...interface{}) *Adaptor { sys := system.NewAccesser() a := &Adaptor{ name: gobot.DefaultName("NanoPi NEO Board"), sys: sys, } var analogPinsOpts []adaptors.AnalogPinsOptionApplier var digitalPinsOpts []adaptors.DigitalPinsOptionApplier var pwmPinsOpts []adaptors.PwmPinsOptionApplier var i2cBusOpts []adaptors.I2CBusOptionApplier var spiBusOpts []adaptors.SpiBusOptionApplier for _, opt := range opts { switch o := opt.(type) { case adaptors.AnalogPinsOptionApplier: analogPinsOpts = append(analogPinsOpts, o) case adaptors.DigitalPinsOptionApplier: digitalPinsOpts = append(digitalPinsOpts, o) case adaptors.PwmPinsOptionApplier: pwmPinsOpts = append(pwmPinsOpts, o) case adaptors.I2CBusOptionApplier: i2cBusOpts = append(i2cBusOpts, o) case adaptors.SpiBusOptionApplier: spiBusOpts = append(spiBusOpts, o) default: panic(fmt.Sprintf("'%s' can not be applied on adaptor '%s'", opt, a.name)) } } analogPinTranslator := adaptors.NewAnalogPinTranslator(sys, analogPinDefinitions) digitalPinTranslator := adaptors.NewDigitalPinTranslator(sys, neoDigitalPinDefinitions) pwmPinTranslator := adaptors.NewPWMPinTranslator(sys, neoPWMPinDefinitions) // Valid bus numbers are [0..2] which corresponds to /dev/i2c-0 through /dev/i2c-2. i2cBusNumberValidator := adaptors.NewBusNumberValidator([]int{0, 1, 2}) // Valid bus numbers are [0] which corresponds to /dev/spidev0.x // x is the chip number <255 spiBusNumberValidator := adaptors.NewBusNumberValidator([]int{0}) a.AnalogPinsAdaptor = adaptors.NewAnalogPinsAdaptor(sys, analogPinTranslator.Translate, analogPinsOpts...) a.DigitalPinsAdaptor = adaptors.NewDigitalPinsAdaptor(sys, digitalPinTranslator.Translate, digitalPinsOpts...) a.PWMPinsAdaptor = adaptors.NewPWMPinsAdaptor(sys, pwmPinTranslator.Translate, pwmPinsOpts...) a.I2cBusAdaptor = adaptors.NewI2cBusAdaptor(sys, i2cBusNumberValidator.Validate, defaultI2cBusNumber, i2cBusOpts...) a.SpiBusAdaptor = adaptors.NewSpiBusAdaptor(sys, spiBusNumberValidator.Validate, defaultSpiBusNumber, defaultSpiChipNumber, defaultSpiMode, defaultSpiBitsNumber, defaultSpiMaxSpeed, a.DigitalPinsAdaptor, spiBusOpts...) return a } // Name returns the name of the Adaptor func (a *Adaptor) Name() string { return a.name } // SetName sets the name of the Adaptor func (a *Adaptor) SetName(n string) { a.name = n } // Connect create new connection to board and pins. func (a *Adaptor) Connect() error { a.mutex.Lock() defer a.mutex.Unlock() if err := a.SpiBusAdaptor.Connect(); err != nil { return err } if err := a.I2cBusAdaptor.Connect(); err != nil { return err } if err := a.AnalogPinsAdaptor.Connect(); err != nil { return err } if err := a.PWMPinsAdaptor.Connect(); err != nil { return err } return a.DigitalPinsAdaptor.Connect() } // Finalize closes connection to board, pins and bus func (a *Adaptor) Finalize() error { a.mutex.Lock() defer a.mutex.Unlock() err := a.DigitalPinsAdaptor.Finalize() if e := a.PWMPinsAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } if e := a.AnalogPinsAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } if e := a.I2cBusAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } if e := a.SpiBusAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } return err } ================================================ FILE: platforms/friendlyelec/nanopi/adaptor_test.go ================================================ package nanopi import ( "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/adaptors" "gobot.io/x/gobot/v2/system" ) const ( pwmDir = "/sys/devices/platform/soc/1c21400.pwm/pwm/pwmchip0/" //nolint:gosec // false positive pwmExportPath = pwmDir + "export" pwmUnexportPath = pwmDir + "unexport" pwmPwmDir = pwmDir + "pwm0/" pwmEnablePath = pwmPwmDir + "enable" pwmPeriodPath = pwmPwmDir + "period" pwmDutyCyclePath = pwmPwmDir + "duty_cycle" pwmPolarityPath = pwmPwmDir + "polarity" pwmInvertedIdentifier = "inversed" ) var pwmMockPaths = []string{ pwmExportPath, pwmUnexportPath, pwmEnablePath, pwmPeriodPath, pwmDutyCyclePath, pwmPolarityPath, } // make sure that this Adaptor fulfills all the required interfaces var ( _ gobot.Adaptor = (*Adaptor)(nil) _ gobot.DigitalPinnerProvider = (*Adaptor)(nil) _ gobot.PWMPinnerProvider = (*Adaptor)(nil) _ gpio.DigitalReader = (*Adaptor)(nil) _ gpio.DigitalWriter = (*Adaptor)(nil) _ gpio.PwmWriter = (*Adaptor)(nil) _ gpio.ServoWriter = (*Adaptor)(nil) _ aio.AnalogReader = (*Adaptor)(nil) _ i2c.Connector = (*Adaptor)(nil) ) func preparePwmFs(fs *system.MockFilesystem) { fs.Files[pwmEnablePath].Contents = "0" fs.Files[pwmPeriodPath].Contents = "0" fs.Files[pwmDutyCyclePath].Contents = "0" fs.Files[pwmPolarityPath].Contents = pwmInvertedIdentifier } func initConnectedTestAdaptorWithMockedFilesystem(mockPaths []string) (*Adaptor, *system.MockFilesystem) { a := initConnectedTestAdaptor() fs := a.sys.UseMockFilesystem(mockPaths) return a, fs } func initConnectedTestAdaptor() *Adaptor { a := NewNeoAdaptor() if err := a.Connect(); err != nil { panic(err) } return a } func TestNewAdaptor(t *testing.T) { // arrange & act a := NewNeoAdaptor() // assert assert.IsType(t, &Adaptor{}, a) assert.True(t, strings.HasPrefix(a.Name(), "NanoPi NEO Board")) assert.NotNil(t, a.sys) assert.NotNil(t, a.AnalogPinsAdaptor) assert.NotNil(t, a.DigitalPinsAdaptor) assert.NotNil(t, a.PWMPinsAdaptor) assert.NotNil(t, a.I2cBusAdaptor) assert.NotNil(t, a.SpiBusAdaptor) assert.True(t, a.sys.HasDigitalPinCdevAccess()) // act & assert a.SetName("NewName") assert.Equal(t, "NewName", a.Name()) } func TestNewAdaptorWithOption(t *testing.T) { // arrange & act a := NewNeoAdaptor(adaptors.WithGpiosActiveLow("1"), adaptors.WithGpioSysfsAccess()) // assert require.NoError(t, a.Connect()) assert.True(t, a.sys.HasDigitalPinSysfsAccess()) } func TestDigitalIO(t *testing.T) { // some basic tests, further tests are done in "digitalpinsadaptor.go" // arrange a := initConnectedTestAdaptor() dpa := a.sys.UseMockDigitalPinAccess() require.True(t, a.sys.HasDigitalPinCdevAccess()) // act & assert write err := a.DigitalWrite("7", 1) require.NoError(t, err) assert.Equal(t, []int{1}, dpa.Written("gpiochip0", "203")) // arrange, act & assert read dpa.UseValues("gpiochip0", "199", []int{2}) i, err := a.DigitalRead("10") require.NoError(t, err) assert.Equal(t, 2, i) // act and assert unknown pin require.ErrorContains(t, a.DigitalWrite("99", 1), "'99' is not a valid id for a digital pin") // act and assert finalize require.NoError(t, a.Finalize()) assert.Equal(t, 0, dpa.Exported("gpiochip0", "203")) assert.Equal(t, 0, dpa.Exported("gpiochip0", "199")) } func TestDigitalIOSysfs(t *testing.T) { // some basic tests, further tests are done in "digitalpinsadaptor.go" // arrange a := NewNeoAdaptor(adaptors.WithGpioSysfsAccess()) require.NoError(t, a.Connect()) dpa := a.sys.UseMockDigitalPinAccess() require.True(t, a.sys.HasDigitalPinSysfsAccess()) // act & assert write err := a.DigitalWrite("7", 1) require.NoError(t, err) assert.Equal(t, []int{1}, dpa.Written("", "203")) // arrange, act & assert read dpa.UseValues("", "199", []int{2}) i, err := a.DigitalRead("10") require.NoError(t, err) assert.Equal(t, 2, i) // act and assert unknown pin require.ErrorContains(t, a.DigitalWrite("99", 1), "'99' is not a valid id for a digital pin") // act and assert finalize require.NoError(t, a.Finalize()) assert.Equal(t, 0, dpa.Exported("", "203")) assert.Equal(t, 0, dpa.Exported("", "199")) } func TestAnalog(t *testing.T) { mockPaths := []string{ "/sys/class/thermal/thermal_zone0/temp", } a, fs := initConnectedTestAdaptorWithMockedFilesystem(mockPaths) fs.Files["/sys/class/thermal/thermal_zone0/temp"].Contents = "567\n" got, err := a.AnalogRead("thermal_zone0") require.NoError(t, err) assert.Equal(t, 567, got) _, err = a.AnalogRead("thermal_zone10") require.ErrorContains(t, err, "'thermal_zone10' is not a valid id for an analog pin") fs.WithReadError = true _, err = a.AnalogRead("thermal_zone0") require.ErrorContains(t, err, "read error") fs.WithReadError = false require.NoError(t, a.Finalize()) } func TestFinalizeErrorAfterGPIO(t *testing.T) { // arrange a := initConnectedTestAdaptor() dpa := a.sys.UseMockDigitalPinAccess() require.True(t, a.sys.HasDigitalPinCdevAccess()) require.NoError(t, a.DigitalWrite("7", 1)) dpa.UseUnexportError("gpiochip0", "203") // act err := a.Finalize() // assert require.ErrorContains(t, err, "unexport error") } func TestFinalizeErrorAfterPWM(t *testing.T) { // indirect test for PWM.Finalize() is called for the adaptor // arrange a, fs := initConnectedTestAdaptorWithMockedFilesystem(pwmMockPaths) preparePwmFs(fs) require.NoError(t, a.PwmWrite("PWM", 1)) fs.WithWriteError = true // act err := a.Finalize() // assert require.ErrorContains(t, err, "write error") } func TestSpiDefaultValues(t *testing.T) { a := NewNeoAdaptor() assert.Equal(t, 0, a.SpiDefaultBusNumber()) assert.Equal(t, 0, a.SpiDefaultChipNumber()) assert.Equal(t, 0, a.SpiDefaultMode()) assert.Equal(t, 8, a.SpiDefaultBitCount()) assert.Equal(t, int64(500000), a.SpiDefaultMaxSpeed()) } func TestI2cDefaultBus(t *testing.T) { a := NewNeoAdaptor() assert.Equal(t, 0, a.DefaultI2cBus()) } func TestI2cFinalizeWithErrors(t *testing.T) { // arrange a := NewNeoAdaptor() a.sys.UseMockSyscall() fs := a.sys.UseMockFilesystem([]string{"/dev/i2c-1"}) require.NoError(t, a.Connect()) con, err := a.GetI2cConnection(0xff, 1) require.NoError(t, err) _, err = con.Write([]byte{0xbf}) require.NoError(t, err) fs.WithCloseError = true // act err = a.Finalize() // assert require.ErrorContains(t, err, "close error") } ================================================ FILE: platforms/friendlyelec/nanopi/doc.go ================================================ /* Package nanopi contains the Gobot adaptor for the FriendlyELEC NanoPi Boards. For further information refer to nanopi README: https://github.com/hybridgroup/gobot/blob/release/platforms/friendlyelec/nanopi/README.md */ package nanopi // import "gobot.io/x/gobot/v2/platforms/friendlyelec/nanopi" ================================================ FILE: platforms/friendlyelec/nanopi/neo_pinmap.go ================================================ package nanopi import "gobot.io/x/gobot/v2/platforms/adaptors" // pin definition for NanoPi NEO // pins: A=0+Nr, C=64+Nr, G=192+Nr var neoDigitalPinDefinitions = adaptors.DigitalPinDefinitions{ "11": {Sysfs: 0, Cdev: adaptors.CdevPin{Chip: 0, Line: 0}}, // UART2_TX/GPIOA0 "22": {Sysfs: 1, Cdev: adaptors.CdevPin{Chip: 0, Line: 1}}, // UART2_RX/GPIOA1 "13": {Sysfs: 2, Cdev: adaptors.CdevPin{Chip: 0, Line: 2}}, // UART2_RTS/GPIOA2 "15": {Sysfs: 3, Cdev: adaptors.CdevPin{Chip: 0, Line: 3}}, // UART2_CTS/GPIOA3 "12": {Sysfs: 6, Cdev: adaptors.CdevPin{Chip: 0, Line: 6}}, // GPIOA6 "19": {Sysfs: 64, Cdev: adaptors.CdevPin{Chip: 0, Line: 64}}, // SPI0_SDO/GPIOC0 "21": {Sysfs: 65, Cdev: adaptors.CdevPin{Chip: 0, Line: 65}}, // SPI0_SDI/GPIOC1 "23": {Sysfs: 66, Cdev: adaptors.CdevPin{Chip: 0, Line: 66}}, // SPI0_CLK/GPIOC2 "24": {Sysfs: 67, Cdev: adaptors.CdevPin{Chip: 0, Line: 67}}, // SPI0_CS/GPIOC3 "8": {Sysfs: 198, Cdev: adaptors.CdevPin{Chip: 0, Line: 198}}, // UART1_TX/GPIOG6 "10": {Sysfs: 199, Cdev: adaptors.CdevPin{Chip: 0, Line: 199}}, // UART1_RX/GPIOG7 "16": {Sysfs: 200, Cdev: adaptors.CdevPin{Chip: 0, Line: 200}}, // UART1_RTS/GPIOG8 "18": {Sysfs: 201, Cdev: adaptors.CdevPin{Chip: 0, Line: 201}}, // UART1_CTS/GPIOG9 "7": {Sysfs: 203, Cdev: adaptors.CdevPin{Chip: 0, Line: 203}}, // GPIOG11 } var neoPWMPinDefinitions = adaptors.PWMPinDefinitions{ // UART_RXD0, GPIOA5, PWM "PWM": {Dir: "/sys/devices/platform/soc/1c21400.pwm/pwm/", DirRegexp: "pwmchip[0]$", Channel: 0}, } var analogPinDefinitions = adaptors.AnalogPinDefinitions{ // +/-273.200 °C need >=7 characters to read: +/-273200 millidegree Celsius "thermal_zone0": {Path: "/sys/class/thermal/thermal_zone0/temp", W: false, ReadBufLen: 7}, } ================================================ FILE: platforms/holystone/README.md ================================================ # Holystone This package contains the Gobot drivers for the various Holystone (http://www.holystone.com/) drones. This package currently supports the following drones: - [Holystone HS200](http://www.holystone.com/product/Holy_Stone_HS200W_FPV_Drone_with_720P_HD_Live_Video_Wifi_Camera_2_4GHz_4CH_6_Axis_Gyro_RC_Quadcopter_with_Altitude_Hold,_Gravity_Sensor_and_Headless_Mode_Function_RTF,_Color_Red-39.html) ================================================ FILE: platforms/holystone/holystone.go ================================================ // Package holystone contains the Gobot drivers for the Holystone drones. // Currently only have support for the HS200 drone. // For more information, go to: // http://www.holystone.com/product/Holy_Stone_HS200W_FPV_Drone_with_720P_HD_Live_Video_Wifi_Camera_2_4GHz_4CH_6_Axis_Gyro_RC_Quadcopter_with_Altitude_Hold,_Gravity_Sensor_and_Headless_Mode_Function_RTF,_Color_Red-39.html // //nolint:lll // ok here package holystone // import "gobot.io/x/gobot/v2/platforms/holystone" ================================================ FILE: platforms/holystone/hs200/README.md ================================================ # Holystone HS200 This package contains the Gobot driver for the Holystone HS200 drone. For more information on this drone, go to: ## How to Install Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) ## How to Use - Connect to the drone's Wi-Fi network and identify the drone/gateway IP address. - Use that IP address when you create a new driver. - Some drones appear to use a different TCP port (8080 vs. 8888?). If the example doesn't work scan the drone for open ports or modify the driver not to use TCP. Here is a sample of how you initialize and use the driver: ```go package main import ( "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/holystone/hs200" ) func main() { drone := hs200.NewDriver("172.16.10.1:8888", "172.16.10.1:8080") work := func() { drone.TakeOff() gobot.After(5*time.Second, func() { drone.Land() }) } robot := gobot.NewRobot("hs200", []gobot.Connection{}, []gobot.Device{drone}, work, ) if err := robot.Start(); err != nil { panic(err) } } ``` ## References ## Random notes - The hs200 sends out an RTSP video feed from its own board camera. Not clear how this is turned on. The data is apparently streamed over UDP. (Reference mentions rtsp://192.168.0.1/0 in VLC, I didn't try it!) - The Android control app seems to be sending out the following TCP bytes for an unknown purpose: `00 01 02 03 04 05 06 07 08 09 25 25` but the drone flies without a TCP connection. - The drone apparently always replies "noact\r\n" over TCP. - The app occasionally sends out 29 bytes long UDP packets besides the 11 byte control packet for an unknown purpose: `26 e1 07 00 00 07 00 00 00 10 00 00 00 00 00 00 00 14 00 00 00 0e 00 00 00 03 00 00 00` - The doesn't seem to be any telemetry coming out of the drone besides the video feed. - The drone can sometimes be a little flaky. Ensure you've got a fully charged battery, minimal Wi-Fi interference, various connectors on the drone all well seated. - It's not clear whether the drone's remote uses Wi-Fi or not, possibly Wi-Fi is only for the mobile app. ================================================ FILE: platforms/holystone/hs200/doc.go ================================================ // Package hs200 is the Gobot driver for the Holystone HS200 drone. package hs200 // import "gobot.io/x/gobot/v2/platforms/holystone/hs200" ================================================ FILE: platforms/holystone/hs200/hs200_driver.go ================================================ package hs200 import ( "net" "sync" "time" "gobot.io/x/gobot/v2" ) // Driver represents the control information for the hs200 drone type Driver struct { name string mutex *sync.RWMutex // Protect the command from concurrent access stopc chan struct{} // Stop the flight loop goroutine cmd []byte // the UDP command packet we keep sending the drone enabled bool // Are we in an enabled state tcpaddress string udpaddress string udpconn net.Conn // UDP connection to the drone tcpconn net.Conn // TCP connection to the drone } // NewDriver creates a driver for the HolyStone hs200 func NewDriver(tcpaddress string, udpaddress string) *Driver { command := []byte{ 0xff, // 2 byte header 0x04, // Left joystick 0x7e, // throttle 0x00 - 0xff(?) 0x3f, // rotate left/right // Right joystick 0xc0, // forward / backward 0x80 - 0xfe(?) 0x3f, // left / right 0x00 - 0x7e(?) // Trim 0x90, // ? yaw (used as a setting to trim the yaw of the uav) 0x10, // ? pitch (used as a setting to trim the pitch of the uav) 0x10, // ? roll (used as a setting to trim the roll of the uav) 0x00, // flags/buttons 0x00, // checksum; 255 - ((sum of flight controls from index 1 to 9) % 256) } command[10] = checksum(command) return &Driver{ name: gobot.DefaultName("HS200"), stopc: make(chan struct{}), tcpaddress: tcpaddress, udpaddress: udpaddress, cmd: command, mutex: &sync.RWMutex{}, } } // Name returns the name of the device. func (d *Driver) Name() string { return d.name } // SetName sets the name of the device. func (d *Driver) SetName(n string) { d.name = n } // Connection returns the Connection of the device. func (d *Driver) Connection() gobot.Connection { return nil } // Start starts the driver. func (d *Driver) Start() error { dialer := net.Dialer{} tc, terr := dialer.Dial("tcp", d.tcpaddress) if terr != nil { return terr } uc, uerr := dialer.Dial("udp4", d.udpaddress) if uerr != nil { return uerr } d.udpconn = uc d.tcpconn = tc return nil } // Halt stops the driver. func (d *Driver) Halt() error { d.stop() return nil } func (d *Driver) stop() { d.mutex.Lock() defer d.mutex.Unlock() d.enabled = false } func (d *Driver) flightLoop(stopc chan struct{}) { udpTick := time.NewTicker(50 * time.Millisecond) defer udpTick.Stop() tcpTick := time.NewTicker(1000 * time.Millisecond) defer tcpTick.Stop() for { select { case <-udpTick.C: d.sendUDP() case <-tcpTick.C: // Send TCP commands from here once we figure out what they do... case <-stopc: d.stop() return } } } func checksum(c []byte) byte { var sum byte for i := 1; i < 10; i++ { sum += c[i] } return 255 - sum } func (d *Driver) sendUDP() { d.mutex.RLock() defer d.mutex.RUnlock() if _, err := d.udpconn.Write(d.cmd); err != nil { panic(err) } } // Enable enables the drone to start flying. func (d *Driver) Enable() { d.mutex.Lock() defer d.mutex.Unlock() if !d.enabled { go d.flightLoop(d.stopc) d.enabled = true } } // Disable disables the drone from flying. func (d *Driver) Disable() { d.mutex.Lock() defer d.mutex.Unlock() if d.enabled { d.stopc <- struct{}{} } } // TakeOff tells drones to liftoff and start flying. func (d *Driver) TakeOff() { d.mutex.Lock() d.cmd[9] = 0x40 d.cmd[10] = checksum(d.cmd) d.mutex.Unlock() time.Sleep(500 * time.Millisecond) d.mutex.Lock() d.cmd[9] = 0x04 d.cmd[10] = checksum(d.cmd) d.mutex.Unlock() } // Land tells drone to come in for landing. func (d *Driver) Land() { d.mutex.Lock() d.cmd[9] = 0x80 d.cmd[10] = checksum(d.cmd) d.mutex.Unlock() time.Sleep(500 * time.Millisecond) d.mutex.Lock() d.cmd[9] = 0x04 d.cmd[10] = checksum(d.cmd) d.mutex.Unlock() } // floatToCmdByte converts a float in the range of -1 to +1 to an integer command func floatToCmdByte(cmd float32, mid byte, maxv byte) byte { if cmd > 1.0 { cmd = 1.0 } if cmd < -1.0 { cmd = -1.0 } cmd = cmd * float32(maxv) bval := byte(cmd + float32(mid) + 0.5) return bval } // Throttle sends the drone up from a hover (or down if speed is negative) func (d *Driver) Throttle(speed float32) { d.mutex.Lock() defer d.mutex.Unlock() d.cmd[2] = floatToCmdByte(speed, 0x7e, 0x7e) d.cmd[10] = checksum(d.cmd) } // Rotate rotates the drone (yaw) func (d *Driver) Rotate(speed float32) { d.mutex.Lock() defer d.mutex.Unlock() d.cmd[3] = floatToCmdByte(speed, 0x3f, 0x3f) d.cmd[10] = checksum(d.cmd) } // Forward sends the drone forward (or backwards if speed is negative, pitch the drone) func (d *Driver) Forward(speed float32) { speed = -speed d.mutex.Lock() defer d.mutex.Unlock() d.cmd[4] = floatToCmdByte(speed, 0xc0, 0x3f) d.cmd[10] = checksum(d.cmd) } // Right moves the drone to the right (or left if speed is negative, rolls the drone) func (d *Driver) Right(speed float32) { d.mutex.Lock() defer d.mutex.Unlock() d.cmd[5] = floatToCmdByte(speed, 0x3f, 0x3f) d.cmd[10] = checksum(d.cmd) } ================================================ FILE: platforms/holystone/hs200/hs200_driver_test.go ================================================ package hs200 import ( "testing" "github.com/stretchr/testify/assert" "gobot.io/x/gobot/v2" ) var _ gobot.Driver = (*Driver)(nil) func TestHS200Driver(t *testing.T) { d := NewDriver("127.0.0.1:8080", "127.0.0.1:9090") assert.Equal(t, "127.0.0.1:8080", d.tcpaddress) assert.Equal(t, "127.0.0.1:9090", d.udpaddress) } ================================================ FILE: platforms/intel-iot/LICENSE ================================================ Copyright (c) 2014-2018 The Hybrid Group Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: platforms/intel-iot/README.md ================================================ # Intel IoT This package contains the Gobot adaptor for the [Intel Edison](http://www.intel.com/content/www/us/en/do-it-yourself/edison.html) and [Intel Joule](http://intel.com/joule) IoT platforms. This package currently supports the following Intel IoT hardware: - Intel Edison with the Arduino breakout board - Intel Joule Developer Kit ================================================ FILE: platforms/intel-iot/curie/README.md ================================================ # Curie The Intel Curie is a tiny computer for the Internet of Things. It is the processor used by the [Arduino/Genuino 101](https://www.arduino.cc/en/Main/ArduinoBoard101) and the [Intel TinyTILE](https://software.intel.com/en-us/node/675623). In addition to the GPIO, ADC, and I2C hardware interfaces, the Curie also has a built-in Inertial Measurement Unit (IMU), including an accelerometer, gyroscope, and thermometer. For more info about the Intel Curie platform go to: [https://www.intel.com/content/www/us/en/products/boards-kits/curie.html](https://www.intel.com/content/www/us/en/products/boards-kits/curie.html). ## How to Install Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) You would normally install Go and Gobot on your computer. When you execute the Gobot program code, it communicates with the connected microcontroller using the [Firmata protocol](https://github.com/firmata/protocol), either using a serial port, or the Bluetooth LE wireless interface. ## How To Use ```go package main import ( "log" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/firmata" "gobot.io/x/gobot/v2/platforms/intel-iot/curie" ) func main() { firmataAdaptor := firmata.NewAdaptor("/dev/ttyACM0") led := gpio.NewLedDriver(firmataAdaptor, "13") imu := curie.NewIMUDriver(firmataAdaptor) work := func() { _ = imu.On("Accelerometer", func(data interface{}) { log.Println("Accelerometer", data) }) _ = imu.On("Gyroscope", func(data interface{}) { log.Println("Gyroscope", data) }) _ = imu.On("Temperature", func(data interface{}) { log.Println("Temperature", data) }) gobot.Every(1*time.Second, func() { if err := led.Toggle(); err != nil { fmt.Println(err) } }) gobot.Every(100*time.Millisecond, func() { imu.ReadAccelerometer() imu.ReadGyroscope() imu.ReadTemperature() }) } robot := gobot.NewRobot("curieBot", []gobot.Connection{firmataAdaptor}, []gobot.Device{imu, led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ``` ## How to Connect ### Installing Firmware You need to flash your Intel Curie with firmware that uses ConfigurableFirmata along with the FirmataCurieIMU plugin. There are 2 versions of this firmware, once that allows connecting using the serial interface, the other using a Bluetooth LE connection. To setup your Arduino environment: - Install the latest Arduino, if you have not done so yet. - Install the "Intel Curie Boards" board files using the "Board Manager". You can find it in the Arduino IDE under the "Tools" menu. Choose "Boards > Boards Manager". - Search for the "Intel Curie Boards" package in the "Boards Manager" dialog, and then install the latest version. - Follow the [installation instructions](https://github.com/firmata/ConfigurableFirmata#installation) for the ConfigurableFirmata library - Download the ZIP file for the FirmataCurieIMU library. You can download the latest version of FirmataCurieIMU from here: [https://github.com/intel-iot-devkit/firmata-curie-imu/archive/master.zip](https://github.com/intel-iot-devkit/firmata-curie-imu/archive/master.zip) - Once you have downloaded the FirmataCurieIMU library, install it by using the "Library Manager". You can find it in the Arduino IDE under the "Sketch" menu. Choose "Include Library > Add .ZIP Library". Select the ZIP file for the FirmataCurieIMU library that you just downloaded. - Linux only: On some Linux distributions, additional device rules are required in order to connect to the board. Run the following command then unplug the board and plug it back in before proceeding: ```sh curl -sL https://raw.githubusercontent.com/01org/corelibs-arduino101/master/scripts/create_dfu_udev_rule | sudo -E bash - ``` Now you are ready to install your firmware. You must decide if you want to connect via the serial port, or using Bluetooth LE. ### Serial Port To use your Intel Curie connected via serial port, you should use the sketch located here: [https://github.com/intel-iot-devkit/firmata-curie-imu/blob/master/examples/everythingIMU/everythingIMU.ino](https://github.com/intel-iot-devkit/firmata-curie-imu/blob/master/examples/everythingIMU/everythingIMU.ino) Once you have loaded this sketch on your Intel Curie, you can run your Gobot code to communicate with it. Leave your Arduino 101 or TinyTILE connected using the serial cable that you used to flash the firmware, and refer to that same serial port name in your Gobot code. ### Bluetooth LE To use your Intel Curie connected via Bluetooth LE, you should use the sketch located here: [https://github.com/intel-iot-devkit/firmata-curie-imu/blob/master/examples/bleIMU/bleIMU.ino](https://github.com/intel-iot-devkit/firmata-curie-imu/blob/master/examples/bleIMU/bleIMU.ino) Once you have loaded this sketch on your Intel Curie, you can run your Gobot code to communicate with it. Power up your Arduino 101 or TinyTILE using a battery or other power source, and connect using the BLE address or name. The default BLE name is "FIRMATA". ================================================ FILE: platforms/intel-iot/curie/doc.go ================================================ /* Package curie contains the Gobot driver for the Intel Curie IMU. For further information refer to intel-iot README: https://github.com/hybridgroup/gobot/blob/release/platforms/intel-iot/curie/README.md */ package curie // import "gobot.io/x/gobot/v2/platforms/intel-iot/curie" ================================================ FILE: platforms/intel-iot/curie/imu_driver.go ================================================ package curie import ( "errors" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/firmata" ) const ( CURIE_IMU = 0x11 CURIE_IMU_READ_ACCEL = 0x00 CURIE_IMU_READ_GYRO = 0x01 CURIE_IMU_READ_TEMP = 0x02 CURIE_IMU_SHOCK_DETECT = 0x03 CURIE_IMU_STEP_COUNTER = 0x04 CURIE_IMU_TAP_DETECT = 0x05 CURIE_IMU_READ_MOTION = 0x06 ) // AccelerometerData is what gets returned with the "Accelerometer" event. type AccelerometerData struct { X int16 Y int16 Z int16 } // GyroscopeData is what gets returned with the "Gyroscope" event. type GyroscopeData struct { X int16 Y int16 Z int16 } // ShockData is what gets returned with the "Shock" event. type ShockData struct { Axis byte Direction byte } // TapData is what gets returned with the "Tap" event. type TapData struct { Axis byte Direction byte } // MotionData is what gets returned with the "Motion" event. type MotionData struct { AX int16 AY int16 AZ int16 GX int16 GY int16 GZ int16 } // IMUDriver represents the IMU that is built-in to the Curie type IMUDriver struct { gobot.Eventer name string connection *firmata.Adaptor } // NewIMUDriver returns a new IMUDriver func NewIMUDriver(a *firmata.Adaptor) *IMUDriver { imu := &IMUDriver{ name: gobot.DefaultName("CurieIMU"), connection: a, Eventer: gobot.NewEventer(), } return imu } // Start starts up the IMUDriver func (imu *IMUDriver) Start() error { return imu.connection.On("SysexResponse", func(res interface{}) { //nolint:forcetypeassert // ok here data := res.([]byte) if err := imu.handleEvent(data); err != nil { panic(err) } }) } // Halt stops the IMUDriver func (imu *IMUDriver) Halt() error { return nil } // Name returns the IMUDrivers name func (imu *IMUDriver) Name() string { return imu.name } // SetName sets the IMUDrivers name func (imu *IMUDriver) SetName(n string) { imu.name = n } // Connection returns the IMUDrivers Connection func (imu *IMUDriver) Connection() gobot.Connection { return imu.connection } // ReadAccelerometer calls the Curie's built-in accelerometer. The result will // be returned by the Sysex response message func (imu *IMUDriver) ReadAccelerometer() error { return imu.connection.WriteSysex([]byte{CURIE_IMU, CURIE_IMU_READ_ACCEL}) } // ReadGyroscope calls the Curie's built-in gyroscope. The result will // be returned by the Sysex response message func (imu *IMUDriver) ReadGyroscope() error { return imu.connection.WriteSysex([]byte{CURIE_IMU, CURIE_IMU_READ_GYRO}) } // ReadTemperature calls the Curie's built-in temperature sensor. // The result will be returned by the Sysex response message func (imu *IMUDriver) ReadTemperature() error { return imu.connection.WriteSysex([]byte{CURIE_IMU, CURIE_IMU_READ_TEMP}) } // EnableShockDetection turns on/off the Curie's built-in shock detection. // The result will be returned by the Sysex response message func (imu *IMUDriver) EnableShockDetection(detect bool) error { var d byte if detect { d = 1 } return imu.connection.WriteSysex([]byte{CURIE_IMU, CURIE_IMU_SHOCK_DETECT, d}) } // EnableStepCounter turns on/off the Curie's built-in step counter. // The result will be returned by the Sysex response message func (imu *IMUDriver) EnableStepCounter(count bool) error { var c byte if count { c = 1 } return imu.connection.WriteSysex([]byte{CURIE_IMU, CURIE_IMU_STEP_COUNTER, c}) } // EnableTapDetection turns on/off the Curie's built-in tap detection. // The result will be returned by the Sysex response message func (imu *IMUDriver) EnableTapDetection(detect bool) error { var d byte if detect { d = 1 } return imu.connection.WriteSysex([]byte{CURIE_IMU, CURIE_IMU_TAP_DETECT, d}) } // ReadMotion calls the Curie's built-in accelerometer & gyroscope. // The result will be returned by the Sysex response message func (imu *IMUDriver) ReadMotion() error { return imu.connection.WriteSysex([]byte{CURIE_IMU, CURIE_IMU_READ_MOTION}) } func (imu *IMUDriver) handleEvent(data []byte) error { if data[1] == CURIE_IMU { switch data[2] { case CURIE_IMU_READ_ACCEL: if val, err := parseAccelerometerData(data); err == nil { imu.Publish("Accelerometer", val) } else { return err } case CURIE_IMU_READ_GYRO: if val, err := parseGyroscopeData(data); err == nil { imu.Publish("Gyroscope", val) } else { return err } case CURIE_IMU_READ_TEMP: if val, err := parseTemperatureData(data); err == nil { imu.Publish("Temperature", val) } else { return err } case CURIE_IMU_SHOCK_DETECT: if val, err := parseShockData(data); err == nil { imu.Publish("Shock", val) } else { return err } case CURIE_IMU_STEP_COUNTER: if val, err := parseStepData(data); err == nil { imu.Publish("Steps", val) } else { return err } case CURIE_IMU_TAP_DETECT: if val, err := parseTapData(data); err == nil { imu.Publish("Tap", val) } else { return err } case CURIE_IMU_READ_MOTION: if val, err := parseMotionData(data); err == nil { imu.Publish("Motion", val) } else { return err } } } return nil } func parseAccelerometerData(data []byte) (*AccelerometerData, error) { if len(data) < 9 { return nil, errors.New("invalid data") } x := int16(uint16(data[3]) | uint16(data[4])<<7) //nolint:gosec // ok here y := int16(uint16(data[5]) | uint16(data[6])<<7) //nolint:gosec // ok here z := int16(uint16(data[7]) | uint16(data[8])<<7) //nolint:gosec // ok here res := &AccelerometerData{X: x, Y: y, Z: z} return res, nil } func parseGyroscopeData(data []byte) (*GyroscopeData, error) { if len(data) < 9 { return nil, errors.New("invalid data") } x := int16(uint16(data[3]) | uint16(data[4])<<7) //nolint:gosec // ok here y := int16(uint16(data[5]) | uint16(data[6])<<7) //nolint:gosec // ok here z := int16(uint16(data[7]) | uint16(data[8])<<7) //nolint:gosec // ok here res := &GyroscopeData{X: x, Y: y, Z: z} return res, nil } func parseTemperatureData(data []byte) (float32, error) { if len(data) < 8 { return 0, errors.New("invalid data") } t1 := int16(uint16(data[3]) | uint16(data[4])<<7) //nolint:gosec // ok here t2 := int16(uint16(data[5]) | uint16(data[6])<<7) //nolint:gosec // ok here res := (float32(t1+(t2*8)) / 512.0) + 23.0 return res, nil } func parseShockData(data []byte) (*ShockData, error) { if len(data) < 6 { return nil, errors.New("invalid data") } res := &ShockData{Axis: data[3], Direction: data[4]} return res, nil } func parseStepData(data []byte) (int16, error) { if len(data) < 6 { return 0, errors.New("invalid data") } res := int16(uint16(data[3]) | uint16(data[4])<<7) //nolint:gosec // ok here return res, nil } func parseTapData(data []byte) (*TapData, error) { if len(data) < 6 { return nil, errors.New("invalid data") } res := &TapData{Axis: data[3], Direction: data[4]} return res, nil } func parseMotionData(data []byte) (*MotionData, error) { if len(data) < 16 { return nil, errors.New("invalid data") } ax := int16(uint16(data[3]) | uint16(data[4])<<7) //nolint:gosec // ok here ay := int16(uint16(data[5]) | uint16(data[6])<<7) //nolint:gosec // ok here az := int16(uint16(data[7]) | uint16(data[8])<<7) //nolint:gosec // ok here gx := int16(uint16(data[9]) | uint16(data[10])<<7) //nolint:gosec // ok here gy := int16(uint16(data[11]) | uint16(data[12])<<7) //nolint:gosec // ok here gz := int16(uint16(data[13]) | uint16(data[14])<<7) //nolint:gosec // ok here res := &MotionData{AX: ax, AY: ay, AZ: az, GX: gx, GY: gy, GZ: gz} return res, nil } ================================================ FILE: platforms/intel-iot/curie/imu_driver_test.go ================================================ package curie import ( "bytes" "io" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/firmata" "gobot.io/x/gobot/v2/platforms/firmata/client" ) var _ gobot.Driver = (*IMUDriver)(nil) type readWriteCloser struct{} func (readWriteCloser) Write(p []byte) (int, error) { return testWriteData.Write(p) } var ( testReadData = []byte{} testWriteData = bytes.Buffer{} ) func (readWriteCloser) Read(b []byte) (int, error) { size := len(b) if len(testReadData) < size { size = len(testReadData) } copy(b, testReadData[:size]) testReadData = testReadData[size:] return size, nil } func (readWriteCloser) Close() error { return nil } type mockFirmataBoard struct { gobot.Eventer disconnectError error pins []client.Pin } func newMockFirmataBoard() *mockFirmataBoard { m := &mockFirmataBoard{ Eventer: gobot.NewEventer(), disconnectError: nil, pins: make([]client.Pin, 100), } m.pins[1].Value = 1 m.pins[15].Value = 133 m.AddEvent("I2cReply") return m } func (mockFirmataBoard) Connect(io.ReadWriteCloser) error { return nil } func (m mockFirmataBoard) Disconnect() error { return m.disconnectError } func (m mockFirmataBoard) Pins() []client.Pin { return m.pins } func (mockFirmataBoard) AnalogWrite(int, int) error { return nil } func (mockFirmataBoard) SetPinMode(int, int) error { return nil } func (mockFirmataBoard) ReportAnalog(int, int) error { return nil } func (mockFirmataBoard) ReportDigital(int, int) error { return nil } func (mockFirmataBoard) DigitalWrite(int, int) error { return nil } func (mockFirmataBoard) I2cRead(int, int) error { return nil } func (mockFirmataBoard) I2cWrite(int, []byte) error { return nil } func (mockFirmataBoard) I2cConfig(int) error { return nil } func (mockFirmataBoard) ServoConfig(int, int, int) error { return nil } func (mockFirmataBoard) WriteSysex(data []byte) error { return nil } func initTestIMUDriver() *IMUDriver { a := firmata.NewAdaptor("/dev/null") a.Board = newMockFirmataBoard() a.PortOpener = func(port string) (io.ReadWriteCloser, error) { return &readWriteCloser{}, nil } return NewIMUDriver(a) } func TestIMUDriverStart(t *testing.T) { d := initTestIMUDriver() require.NoError(t, d.Start()) } func TestIMUDriverHalt(t *testing.T) { d := initTestIMUDriver() require.NoError(t, d.Halt()) } func TestIMUDriverDefaultName(t *testing.T) { d := initTestIMUDriver() assert.True(t, strings.HasPrefix(d.Name(), "CurieIMU")) } func TestIMUDriverSetName(t *testing.T) { d := initTestIMUDriver() d.SetName("mybot") assert.Equal(t, "mybot", d.Name()) } func TestIMUDriverConnection(t *testing.T) { d := initTestIMUDriver() assert.NotNil(t, d.Connection()) } func TestIMUDriverReadAccelerometer(t *testing.T) { d := initTestIMUDriver() _ = d.Start() require.NoError(t, d.ReadAccelerometer()) } func TestIMUDriverReadAccelerometerData(t *testing.T) { _, err := parseAccelerometerData([]byte{}) require.ErrorContains(t, err, "invalid data") result, err := parseAccelerometerData([]byte{0xF0, 0x11, 0x00, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0xf7}) require.NoError(t, err) assert.Equal(t, &AccelerometerData{X: 1920, Y: 1920, Z: 1920}, result) } func TestIMUDriverReadGyroscope(t *testing.T) { d := initTestIMUDriver() _ = d.Start() require.NoError(t, d.ReadGyroscope()) } func TestIMUDriverReadGyroscopeData(t *testing.T) { _, err := parseGyroscopeData([]byte{}) require.ErrorContains(t, err, "invalid data") result, err := parseGyroscopeData([]byte{0xF0, 0x11, 0x01, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0xf7}) require.NoError(t, err) assert.Equal(t, &GyroscopeData{X: 1920, Y: 1920, Z: 1920}, result) } func TestIMUDriverReadTemperature(t *testing.T) { d := initTestIMUDriver() _ = d.Start() require.NoError(t, d.ReadTemperature()) } func TestIMUDriverReadTemperatureData(t *testing.T) { _, err := parseTemperatureData([]byte{}) require.ErrorContains(t, err, "invalid data") result, err := parseTemperatureData([]byte{0xF0, 0x11, 0x02, 0x00, 0x02, 0x03, 0x04, 0xf7}) require.NoError(t, err) assert.InDelta(t, float32(31.546875), result, 0.0) } func TestIMUDriverEnableShockDetection(t *testing.T) { d := initTestIMUDriver() _ = d.Start() require.NoError(t, d.EnableShockDetection(true)) } func TestIMUDriverShockDetectData(t *testing.T) { _, err := parseShockData([]byte{}) require.ErrorContains(t, err, "invalid data") result, err := parseShockData([]byte{0xF0, 0x11, 0x03, 0x00, 0x02, 0xf7}) require.NoError(t, err) assert.Equal(t, &ShockData{Axis: 0, Direction: 2}, result) } func TestIMUDriverEnableStepCounter(t *testing.T) { d := initTestIMUDriver() _ = d.Start() require.NoError(t, d.EnableStepCounter(true)) } func TestIMUDriverStepCountData(t *testing.T) { _, err := parseStepData([]byte{}) require.ErrorContains(t, err, "invalid data") result, err := parseStepData([]byte{0xF0, 0x11, 0x04, 0x00, 0x02, 0xf7}) require.NoError(t, err) assert.Equal(t, int16(256), result) } func TestIMUDriverEnableTapDetection(t *testing.T) { d := initTestIMUDriver() _ = d.Start() require.NoError(t, d.EnableTapDetection(true)) } func TestIMUDriverTapDetectData(t *testing.T) { _, err := parseTapData([]byte{}) require.ErrorContains(t, err, "invalid data") result, err := parseTapData([]byte{0xF0, 0x11, 0x05, 0x00, 0x02, 0xf7}) require.NoError(t, err) assert.Equal(t, &TapData{Axis: 0, Direction: 2}, result) } func TestIMUDriverEnableReadMotion(t *testing.T) { d := initTestIMUDriver() _ = d.Start() require.NoError(t, d.ReadMotion()) } func TestIMUDriverReadMotionData(t *testing.T) { _, err := parseMotionData([]byte{}) require.ErrorContains(t, err, "invalid data") result, err := parseMotionData([]byte{ 0xF0, 0x11, 0x06, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0xf7, }) require.NoError(t, err) assert.Equal(t, &MotionData{AX: 1920, AY: 1920, AZ: 1920, GX: 1920, GY: 1920, GZ: 1920}, result) } func TestIMUDriverHandleEvents(t *testing.T) { d := initTestIMUDriver() _ = d.Start() require.NoError(t, d.handleEvent([]byte{0xF0, 0x11, 0x00, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0xf7})) require.NoError(t, d.handleEvent([]byte{0xF0, 0x11, 0x01, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0xf7})) require.NoError(t, d.handleEvent([]byte{0xF0, 0x11, 0x02, 0x00, 0x02, 0x03, 0x04, 0xf7})) require.NoError(t, d.handleEvent([]byte{0xF0, 0x11, 0x03, 0x00, 0x02, 0xf7})) require.NoError(t, d.handleEvent([]byte{0xF0, 0x11, 0x04, 0x00, 0x02, 0xf7})) require.NoError(t, d.handleEvent([]byte{0xF0, 0x11, 0x05, 0x00, 0x02, 0xf7})) require.NoError(t, d.handleEvent([]byte{ 0xF0, 0x11, 0x06, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0xf7, })) } ================================================ FILE: platforms/intel-iot/edison/README.md ================================================ # Edison The Intel Edison is a WiFi and Bluetooth enabled development platform for the Internet of Things. It packs a robust set of features into its small size and supports a broad spectrum of I/O and software support. For more info about the Edison platform click [here](http://www.intel.com/content/www/us/en/do-it-yourself/edison.html). ## How to Install Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) ### Setting up your Intel Edison Everything you need to get started with the Edison is in the Intel Getting Started Guide: Don't forget to configure your Edison's wifi connection and flash your Edison with the latest firmware image! The recommended way to connect to your device is via wifi, for that follow the directions here: If you don't have a wifi network available, the Intel documentation explains how to use another connection type, but note that this guide assumes you are using wifi connection. You can obtain the IP address of your Edison, by running the floowing command: ```sh ip addr show | grep inet ``` Don't forget to setup the a password for the device otherwise you won't be able to connect using SSH. From within the screen session, run the following command: ```ah configure_edison --password ``` Note that you MUST setup a password otherwise SSH won't be enabled. If later on you aren't able to scp to the device, try to reset the password. This password will obviously be needed next time you connect to your device. ## How To Use ```go package main import ( "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/intel-iot/edison" ) func main() { e := edison.NewAdaptor() led := gpio.NewLedDriver(e, "13") work := func() { gobot.Every(1*time.Second, func() { if err := led.Toggle(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("blinkBot", []gobot.Connection{e}, []gobot.Device{led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ``` You can read the [full API documentation online](http://godoc.org/gobot.io/x/gobot/v2). ## How to Connect ### Compiling Compile your Gobot program on your workstation like this: ```sh GOARCH=386 GOOS=linux go build examples/edison_blink.go ``` Once you have compiled your code, you can you can upload your program and execute it on the Intel Edison from your workstation using the `scp` and `ssh` commands like this: ```sh scp edison_blink root@:/home/root/ ssh -t root@ "./edison_blink" ``` At this point you should see one of the onboard LEDs blinking. Press control + c to exit. To update the program after you made a change, you will need to scp it over once again and start it from the command line (via screen). ================================================ FILE: platforms/intel-iot/edison/arduino_pinmap.go ================================================ package edison import "gobot.io/x/gobot/v2/system" var arduinoPinMap = map[string]sysfsPin{ "0": { pin: 130, resistor: 216, levelShifter: 248, pwmPin: -1, mux: []mux{}, }, "1": { pin: 131, resistor: 217, levelShifter: 249, pwmPin: -1, mux: []mux{}, }, "2": { pin: 128, resistor: 218, levelShifter: 250, pwmPin: -1, mux: []mux{}, }, "3": { pin: 12, resistor: 219, levelShifter: 251, pwmPin: 0, mux: []mux{}, }, "4": { pin: 129, resistor: 220, levelShifter: 252, pwmPin: -1, mux: []mux{}, }, "5": { pin: 13, resistor: 221, levelShifter: 253, pwmPin: 1, mux: []mux{}, }, "6": { pin: 182, resistor: 222, levelShifter: 254, pwmPin: 2, mux: []mux{}, }, "7": { pin: 48, resistor: 223, levelShifter: 255, pwmPin: -1, mux: []mux{}, }, "8": { pin: 49, resistor: 224, levelShifter: 256, pwmPin: -1, mux: []mux{}, }, "9": { pin: 183, resistor: 225, levelShifter: 257, pwmPin: 3, mux: []mux{}, }, "10": { pin: 41, resistor: 226, levelShifter: 258, pwmPin: 4, mux: []mux{ {263, system.HIGH}, {240, system.LOW}, }, }, "11": { pin: 43, resistor: 227, levelShifter: 259, pwmPin: 5, mux: []mux{ {262, system.HIGH}, {241, system.LOW}, }, }, "12": { pin: 42, resistor: 228, levelShifter: 260, pwmPin: -1, mux: []mux{ {242, system.LOW}, }, }, "13": { pin: 40, resistor: 229, levelShifter: 261, pwmPin: -1, mux: []mux{ {243, system.LOW}, }, }, } ================================================ FILE: platforms/intel-iot/edison/doc.go ================================================ /* Package edison contains the Gobot adaptor for the Intel Edison. For further information refer to intel-iot README: https://github.com/hybridgroup/gobot/blob/release/platforms/intel-iot/edison/README.md */ package edison // import "gobot.io/x/gobot/v2/platforms/intel-iot/edison" ================================================ FILE: platforms/intel-iot/edison/edison_adaptor.go ================================================ package edison import ( "fmt" "os" "strconv" "sync" multierror "github.com/hashicorp/go-multierror" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/adaptors" "gobot.io/x/gobot/v2/system" ) const ( defaultI2cBusNumber = 6 defaultI2cBusNumberOther = 1 ) type mux struct { pin int value int } type sysfsPin struct { pin int resistor int levelShifter int pwmPin int mux []mux } // Adaptor represents a Gobot Adaptor for an Intel Edison type Adaptor struct { *adaptors.AnalogPinsAdaptor *adaptors.PWMPinsAdaptor *adaptors.I2cBusAdaptor name string board string sys *system.Accesser mutex sync.Mutex pinMap map[string]sysfsPin tristate gobot.DigitalPinner digitalPins map[int]gobot.DigitalPinner arduinoI2cInitialized bool } // NewAdaptor returns a new Edison Adaptor of the given type. // Supported types are: "arduino", "miniboard", "sparkfun", an empty string defaults to "arduino" // // Further optional parameters for: // // AIO, see [adaptors.NewAnalogPinsAdaptor] // I2C, see [adaptors.NewI2cBusAdaptor] // PWM, see [adaptors.NewPWMPinsAdaptor] func NewAdaptor(opts ...interface{}) *Adaptor { sys := system.NewAccesser(system.WithDigitalPinSysfsAccess()) sys.AddDigitalPinSupport() a := &Adaptor{ name: gobot.DefaultName("Edison"), board: "arduino", sys: sys, pinMap: arduinoPinMap, } var analogPinsOpts []adaptors.AnalogPinsOptionApplier pwmPinsOpts := []adaptors.PwmPinsOptionApplier{adaptors.WithPWMPinInitializer(pwmPinInitializer)} var i2cBusOpts []adaptors.I2CBusOptionApplier for _, opt := range opts { switch o := opt.(type) { case string: if o != "" { a.board = o } case adaptors.AnalogPinsOptionApplier: analogPinsOpts = append(analogPinsOpts, o) case adaptors.PwmPinsOptionApplier: pwmPinsOpts = append(pwmPinsOpts, o) case adaptors.I2CBusOptionApplier: i2cBusOpts = append(i2cBusOpts, o) default: panic(fmt.Sprintf("'%s' can not be applied on adaptor '%s'", opt, a.name)) } } a.AnalogPinsAdaptor = adaptors.NewAnalogPinsAdaptor(sys, a.translateAnalogPin, analogPinsOpts...) a.PWMPinsAdaptor = adaptors.NewPWMPinsAdaptor(sys, a.translateAndMuxPWMPin, pwmPinsOpts...) defI2cBusNr := defaultI2cBusNumber if a.board != "arduino" { defI2cBusNr = defaultI2cBusNumberOther } a.I2cBusAdaptor = adaptors.NewI2cBusAdaptor(sys, a.validateAndSetupI2cBusNumber, defI2cBusNr, i2cBusOpts...) return a } // Name returns the adaptors name func (a *Adaptor) Name() string { return a.name } // SetName sets the adaptors name func (a *Adaptor) SetName(n string) { a.name = n } // Connect initializes the Edison for use with the Arduino breakout board func (a *Adaptor) Connect() error { a.digitalPins = make(map[int]gobot.DigitalPinner) if err := a.I2cBusAdaptor.Connect(); err != nil { return err } if err := a.AnalogPinsAdaptor.Connect(); err != nil { return err } if err := a.PWMPinsAdaptor.Connect(); err != nil { return err } switch a.board { case "sparkfun": a.pinMap = sparkfunPinMap case "arduino": a.board = "arduino" a.pinMap = arduinoPinMap if err := a.arduinoSetup(); err != nil { return err } case "miniboard": a.pinMap = miniboardPinMap default: return fmt.Errorf("unknown board type: %s", a.board) } return nil } // Finalize releases all i2c devices and exported analog, digital, pwm pins. func (a *Adaptor) Finalize() error { var err error if a.tristate != nil { if errs := a.tristate.Unexport(); errs != nil { err = multierror.Append(err, errs) } } a.tristate = nil for _, pin := range a.digitalPins { if pin != nil { if errs := pin.Unexport(); errs != nil { err = multierror.Append(err, errs) } } } a.digitalPins = nil if e := a.PWMPinsAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } if e := a.AnalogPinsAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } if e := a.I2cBusAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } a.arduinoI2cInitialized = false return err } // DigitalRead reads digital value from pin func (a *Adaptor) DigitalRead(pin string) (int, error) { a.mutex.Lock() defer a.mutex.Unlock() sysPin, err := a.digitalPin(pin, system.WithPinDirectionInput()) if err != nil { return 0, err } return sysPin.Read() } // DigitalWrite writes a value to the pin. Acceptable values are 1 or 0. func (a *Adaptor) DigitalWrite(pin string, val byte) error { a.mutex.Lock() defer a.mutex.Unlock() return a.digitalWrite(pin, val) } // DigitalPin returns a digital pin. If the pin is initially acquired, it is an input. // Pin direction and other options can be changed afterwards by pin.ApplyOptions() at any time. func (a *Adaptor) DigitalPin(id string) (gobot.DigitalPinner, error) { a.mutex.Lock() defer a.mutex.Unlock() return a.digitalPin(id) } // AnalogRead returns value from analog reading of specified pin func (a *Adaptor) AnalogRead(pin string) (int, error) { rawRead, err := a.AnalogPinsAdaptor.AnalogRead(pin) if err != nil { return 0, err } return rawRead / 4, err } func (a *Adaptor) validateAndSetupI2cBusNumber(busNr int) error { // Valid bus number is 6 for "arduino", otherwise 1. if busNr == 6 && a.board == "arduino" { if !a.arduinoI2cInitialized { if err := a.arduinoI2CSetup(); err != nil { return err } a.arduinoI2cInitialized = true return nil } return nil } if busNr == 1 && a.board != "arduino" { return nil } return fmt.Errorf("unsupported I2C bus '%d'", busNr) } // arduinoSetup does needed setup for the Arduino compatible breakout board func (a *Adaptor) arduinoSetup() error { // TODO: also check to see if device labels for // /sys/class/gpio/gpiochip{200,216,232,248}/label == "pcal9555a" tpin, err := a.newExportedDigitalPin(214, system.WithPinDirectionOutput(system.LOW)) if err != nil { return err } a.tristate = tpin for _, i := range []int{263, 262} { if err := a.newUnexportedDigitalPin(i, system.WithPinDirectionOutput(system.HIGH)); err != nil { return err } } for _, i := range []int{240, 241, 242, 243} { if err := a.newUnexportedDigitalPin(i, system.WithPinDirectionOutput(system.LOW)); err != nil { return err } } for _, i := range []string{"111", "115", "114", "109"} { if err := a.changePinMode(i, "1"); err != nil { return err } } for _, i := range []string{"131", "129", "40"} { if err := a.changePinMode(i, "0"); err != nil { return err } } return a.tristate.Write(system.HIGH) } func (a *Adaptor) arduinoI2CSetup() error { if a.tristate == nil { return fmt.Errorf("not connected") } if err := a.tristate.Write(system.LOW); err != nil { return err } for _, i := range []int{14, 165, 212, 213} { if err := a.newUnexportedDigitalPin(i, system.WithPinDirectionInput()); err != nil { return err } } for _, i := range []int{236, 237, 204, 205} { if err := a.newUnexportedDigitalPin(i, system.WithPinDirectionOutput(system.LOW)); err != nil { return err } } for _, i := range []string{"28", "27"} { if err := a.changePinMode(i, "1"); err != nil { return err } } return a.tristate.Write(system.HIGH) } func (a *Adaptor) digitalPin(id string, o ...func(gobot.DigitalPinOptioner) bool) (gobot.DigitalPinner, error) { i := a.pinMap[id] err := a.ensureDigitalPin(i.pin, o...) if err != nil { return nil, err } pin := a.digitalPins[i.pin] vpin, ok := pin.(gobot.DigitalPinValuer) if !ok { return nil, fmt.Errorf("can not determine the direction behavior") } dir := vpin.DirectionBehavior() if i.resistor > 0 { rop := system.WithPinDirectionOutput(system.LOW) if dir == system.OUT { rop = system.WithPinDirectionInput() } if err := a.ensureDigitalPin(i.resistor, rop); err != nil { return nil, err } } if i.levelShifter > 0 { lop := system.WithPinDirectionOutput(system.LOW) if dir == system.OUT { lop = system.WithPinDirectionOutput(system.HIGH) } if err := a.ensureDigitalPin(i.levelShifter, lop); err != nil { return nil, err } } if len(i.mux) > 0 { for _, mux := range i.mux { if err := a.ensureDigitalPin(mux.pin, system.WithPinDirectionOutput(mux.value)); err != nil { return nil, err } } } return pin, nil } func (a *Adaptor) ensureDigitalPin(idx int, o ...func(gobot.DigitalPinOptioner) bool) error { pin := a.digitalPins[idx] var err error if pin == nil { pin, err = a.newExportedDigitalPin(idx, o...) if err != nil { return err } a.digitalPins[idx] = pin } else { if err := pin.ApplyOptions(o...); err != nil { return err } } return nil } func pwmPinInitializer(_ string, pin gobot.PWMPinner) error { if err := pin.Export(); err != nil { return err } return pin.SetEnabled(true) } func (a *Adaptor) translateAnalogPin(pin string) (string, bool, uint16, error) { path := fmt.Sprintf("/sys/bus/iio/devices/iio:device1/in_voltage%s_raw", pin) const ( write = false readBufLen = 200 ) return path, write, readBufLen, nil } func (a *Adaptor) translateAndMuxPWMPin(id string) (string, int, error) { sysPin, ok := a.pinMap[id] if !ok { return "", -1, fmt.Errorf("'%s' is not a valid id for a pin", id) } if sysPin.pwmPin == -1 { return "", -1, fmt.Errorf("'%s' is not a valid id for a PWM pin", id) } if err := a.digitalWrite(id, 1); err != nil { return "", -1, err } if err := a.changePinMode(strconv.Itoa(sysPin.pin), "1"); err != nil { return "", -1, err } return "/sys/class/pwm/pwmchip0", sysPin.pwmPin, nil } func (a *Adaptor) newUnexportedDigitalPin(i int, o ...func(gobot.DigitalPinOptioner) bool) error { io := a.sys.NewDigitalPin("", i, o...) if err := io.Export(); err != nil { return err } return io.Unexport() } func (a *Adaptor) newExportedDigitalPin( pin int, o ...func(gobot.DigitalPinOptioner) bool, ) (gobot.DigitalPinner, error) { sysPin := a.sys.NewDigitalPin("", pin, o...) err := sysPin.Export() return sysPin, err } // changePinMode writes pin mode to current_pinmux file func (a *Adaptor) changePinMode(pin, mode string) error { file, err := a.sys.OpenFile("/sys/kernel/debug/gpio_debug/gpio"+pin+"/current_pinmux", os.O_WRONLY, 0o644) defer file.Close() //nolint:staticcheck // for historical reasons if err != nil { return err } _, err = file.Write([]byte("mode" + mode)) return err } func (a *Adaptor) digitalWrite(pin string, val byte) error { sysPin, err := a.digitalPin(pin, system.WithPinDirectionOutput(int(val))) if err != nil { return err } return sysPin.Write(int(val)) } ================================================ FILE: platforms/intel-iot/edison/edison_adaptor_test.go ================================================ package edison import ( "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/system" ) // make sure that this Adaptor fulfills all the required interfaces var ( _ gobot.Adaptor = (*Adaptor)(nil) _ gobot.DigitalPinnerProvider = (*Adaptor)(nil) _ gobot.PWMPinnerProvider = (*Adaptor)(nil) _ gpio.DigitalReader = (*Adaptor)(nil) _ gpio.DigitalWriter = (*Adaptor)(nil) _ aio.AnalogReader = (*Adaptor)(nil) _ gpio.PwmWriter = (*Adaptor)(nil) _ i2c.Connector = (*Adaptor)(nil) ) var testPinFiles = []string{ "/sys/bus/iio/devices/iio:device1/in_voltage0_raw", "/sys/kernel/debug/gpio_debug/gpio111/current_pinmux", "/sys/kernel/debug/gpio_debug/gpio115/current_pinmux", "/sys/kernel/debug/gpio_debug/gpio114/current_pinmux", "/sys/kernel/debug/gpio_debug/gpio109/current_pinmux", "/sys/kernel/debug/gpio_debug/gpio131/current_pinmux", "/sys/kernel/debug/gpio_debug/gpio129/current_pinmux", "/sys/kernel/debug/gpio_debug/gpio40/current_pinmux", "/sys/kernel/debug/gpio_debug/gpio13/current_pinmux", "/sys/kernel/debug/gpio_debug/gpio28/current_pinmux", "/sys/kernel/debug/gpio_debug/gpio27/current_pinmux", "/sys/class/pwm/pwmchip0/export", "/sys/class/pwm/pwmchip0/unexport", "/sys/class/pwm/pwmchip0/pwm1/duty_cycle", "/sys/class/pwm/pwmchip0/pwm1/period", "/sys/class/pwm/pwmchip0/pwm1/enable", "/sys/class/gpio/export", "/sys/class/gpio/unexport", "/sys/class/gpio/gpio13/value", "/sys/class/gpio/gpio13/direction", "/sys/class/gpio/gpio40/value", "/sys/class/gpio/gpio40/direction", "/sys/class/gpio/gpio128/value", "/sys/class/gpio/gpio128/direction", "/sys/class/gpio/gpio221/value", "/sys/class/gpio/gpio221/direction", "/sys/class/gpio/gpio243/value", "/sys/class/gpio/gpio243/direction", "/sys/class/gpio/gpio229/value", "/sys/class/gpio/gpio229/direction", "/sys/class/gpio/gpio253/value", "/sys/class/gpio/gpio253/direction", "/sys/class/gpio/gpio261/value", "/sys/class/gpio/gpio261/direction", "/sys/class/gpio/gpio214/value", "/sys/class/gpio/gpio214/direction", "/sys/class/gpio/gpio14/direction", "/sys/class/gpio/gpio14/value", "/sys/class/gpio/gpio165/direction", "/sys/class/gpio/gpio165/value", "/sys/class/gpio/gpio212/direction", "/sys/class/gpio/gpio212/value", "/sys/class/gpio/gpio213/direction", "/sys/class/gpio/gpio213/value", "/sys/class/gpio/gpio236/direction", "/sys/class/gpio/gpio236/value", "/sys/class/gpio/gpio237/direction", "/sys/class/gpio/gpio237/value", "/sys/class/gpio/gpio204/direction", "/sys/class/gpio/gpio204/value", "/sys/class/gpio/gpio205/direction", "/sys/class/gpio/gpio205/value", "/sys/class/gpio/gpio263/direction", "/sys/class/gpio/gpio263/value", "/sys/class/gpio/gpio262/direction", "/sys/class/gpio/gpio262/value", "/sys/class/gpio/gpio240/direction", "/sys/class/gpio/gpio240/value", "/sys/class/gpio/gpio241/direction", "/sys/class/gpio/gpio241/value", "/sys/class/gpio/gpio242/direction", "/sys/class/gpio/gpio242/value", "/sys/class/gpio/gpio218/direction", "/sys/class/gpio/gpio218/value", "/sys/class/gpio/gpio250/direction", "/sys/class/gpio/gpio250/value", "/dev/i2c-6", } var pwmMockPathsMux13Arduino = []string{ "/sys/class/gpio/export", "/sys/class/gpio/unexport", "/sys/kernel/debug/gpio_debug/gpio13/current_pinmux", "/sys/kernel/debug/gpio_debug/gpio40/current_pinmux", "/sys/kernel/debug/gpio_debug/gpio109/current_pinmux", "/sys/kernel/debug/gpio_debug/gpio111/current_pinmux", "/sys/kernel/debug/gpio_debug/gpio114/current_pinmux", "/sys/kernel/debug/gpio_debug/gpio115/current_pinmux", "/sys/kernel/debug/gpio_debug/gpio129/current_pinmux", "/sys/kernel/debug/gpio_debug/gpio131/current_pinmux", "/sys/class/gpio/gpio13/direction", "/sys/class/gpio/gpio13/value", "/sys/class/gpio/gpio214/direction", "/sys/class/gpio/gpio214/value", "/sys/class/gpio/gpio221/direction", "/sys/class/gpio/gpio221/value", "/sys/class/gpio/gpio240/direction", "/sys/class/gpio/gpio240/value", "/sys/class/gpio/gpio241/direction", "/sys/class/gpio/gpio241/value", "/sys/class/gpio/gpio242/direction", "/sys/class/gpio/gpio242/value", "/sys/class/gpio/gpio243/direction", "/sys/class/gpio/gpio243/value", "/sys/class/gpio/gpio253/direction", "/sys/class/gpio/gpio253/value", "/sys/class/gpio/gpio262/direction", "/sys/class/gpio/gpio262/value", "/sys/class/gpio/gpio263/direction", "/sys/class/gpio/gpio263/value", } var pwmMockPathsMux13ArduinoI2c = []string{ "/dev/i2c-6", "/sys/class/gpio/export", "/sys/class/gpio/unexport", "/sys/kernel/debug/gpio_debug/gpio13/current_pinmux", "/sys/kernel/debug/gpio_debug/gpio27/current_pinmux", "/sys/kernel/debug/gpio_debug/gpio28/current_pinmux", "/sys/kernel/debug/gpio_debug/gpio40/current_pinmux", "/sys/kernel/debug/gpio_debug/gpio109/current_pinmux", "/sys/kernel/debug/gpio_debug/gpio111/current_pinmux", "/sys/kernel/debug/gpio_debug/gpio114/current_pinmux", "/sys/kernel/debug/gpio_debug/gpio115/current_pinmux", "/sys/kernel/debug/gpio_debug/gpio129/current_pinmux", "/sys/kernel/debug/gpio_debug/gpio131/current_pinmux", "/sys/class/gpio/gpio13/direction", "/sys/class/gpio/gpio13/value", "/sys/class/gpio/gpio14/direction", "/sys/class/gpio/gpio14/value", "/sys/class/gpio/gpio28/direction", "/sys/class/gpio/gpio28/value", "/sys/class/gpio/gpio165/direction", "/sys/class/gpio/gpio165/value", "/sys/class/gpio/gpio212/direction", "/sys/class/gpio/gpio212/value", "/sys/class/gpio/gpio213/direction", "/sys/class/gpio/gpio213/value", "/sys/class/gpio/gpio214/direction", "/sys/class/gpio/gpio214/value", "/sys/class/gpio/gpio221/direction", "/sys/class/gpio/gpio221/value", "/sys/class/gpio/gpio236/direction", "/sys/class/gpio/gpio236/value", "/sys/class/gpio/gpio237/direction", "/sys/class/gpio/gpio237/value", "/sys/class/gpio/gpio204/value", "/sys/class/gpio/gpio204/direction", "/sys/class/gpio/gpio205/value", "/sys/class/gpio/gpio205/direction", "/sys/class/gpio/gpio240/direction", "/sys/class/gpio/gpio240/value", "/sys/class/gpio/gpio241/direction", "/sys/class/gpio/gpio241/value", "/sys/class/gpio/gpio242/direction", "/sys/class/gpio/gpio242/value", "/sys/class/gpio/gpio243/direction", "/sys/class/gpio/gpio243/value", "/sys/class/gpio/gpio253/direction", "/sys/class/gpio/gpio253/value", "/sys/class/gpio/gpio262/direction", "/sys/class/gpio/gpio262/value", "/sys/class/gpio/gpio263/direction", "/sys/class/gpio/gpio263/value", } var pwmMockPathsMux13 = []string{ "/sys/kernel/debug/gpio_debug/gpio13/current_pinmux", "/sys/class/gpio/export", "/sys/class/gpio/gpio13/direction", "/sys/class/gpio/gpio13/value", "/sys/class/gpio/gpio221/direction", "/sys/class/gpio/gpio221/value", "/sys/class/gpio/gpio253/direction", "/sys/class/gpio/gpio253/value", "/sys/class/pwm/pwmchip0/export", "/sys/class/pwm/pwmchip0/unexport", "/sys/class/pwm/pwmchip0/pwm1/duty_cycle", "/sys/class/pwm/pwmchip0/pwm1/period", "/sys/class/pwm/pwmchip0/pwm1/enable", } var pwmMockPathsMux40 = []string{ "/sys/kernel/debug/gpio_debug/gpio40/current_pinmux", "/sys/class/gpio/export", "/sys/class/gpio/unexport", "/sys/class/gpio/gpio40/value", "/sys/class/gpio/gpio40/direction", "/sys/class/gpio/gpio229/value", // resistor "/sys/class/gpio/gpio229/direction", "/sys/class/gpio/gpio243/value", "/sys/class/gpio/gpio243/direction", "/sys/class/gpio/gpio261/value", // level shifter "/sys/class/gpio/gpio261/direction", } func initConnectedTestAdaptorWithMockedFilesystem() (*Adaptor, *system.MockFilesystem) { a, fs := initTestAdaptorWithMockedFilesystem("arduino") if err := a.Connect(); err != nil { panic(err) } return a, fs } func initTestAdaptorWithMockedFilesystem(boardType string) (*Adaptor, *system.MockFilesystem) { a := NewAdaptor(boardType) fs := a.sys.UseMockFilesystem(testPinFiles) fs.Files["/sys/class/pwm/pwmchip0/pwm1/period"].Contents = "5000" return a, fs } func TestNewAdaptor(t *testing.T) { // arrange & act a := NewAdaptor() // assert assert.IsType(t, &Adaptor{}, a) assert.True(t, strings.HasPrefix(a.Name(), "Edison")) assert.Equal(t, 6, a.DefaultI2cBus()) assert.Equal(t, "arduino", a.board) assert.NotNil(t, a.sys) assert.NotNil(t, a.AnalogPinsAdaptor) assert.NotNil(t, a.PWMPinsAdaptor) assert.NotNil(t, a.I2cBusAdaptor) assert.True(t, a.sys.HasDigitalPinSysfsAccess()) // act & assert a.SetName("NewName") assert.Equal(t, "NewName", a.Name()) } func TestConnect(t *testing.T) { // arrange a, _ := initTestAdaptorWithMockedFilesystem("arduino") // act & assert require.NoError(t, a.Connect()) } func TestArduinoSetupFail263(t *testing.T) { a, fs := initConnectedTestAdaptorWithMockedFilesystem() delete(fs.Files, "/sys/class/gpio/gpio263/direction") err := a.arduinoSetup() require.ErrorContains(t, err, "/sys/class/gpio/gpio263/direction: no such file") } func TestArduinoSetupFail240(t *testing.T) { a, fs := initConnectedTestAdaptorWithMockedFilesystem() delete(fs.Files, "/sys/class/gpio/gpio240/direction") err := a.arduinoSetup() require.ErrorContains(t, err, "/sys/class/gpio/gpio240/direction: no such file") } func TestArduinoSetupFail111(t *testing.T) { a, fs := initConnectedTestAdaptorWithMockedFilesystem() delete(fs.Files, "/sys/kernel/debug/gpio_debug/gpio111/current_pinmux") err := a.arduinoSetup() require.ErrorContains(t, err, "/sys/kernel/debug/gpio_debug/gpio111/current_pinmux: no such file") } func TestArduinoSetupFail131(t *testing.T) { a, fs := initConnectedTestAdaptorWithMockedFilesystem() delete(fs.Files, "/sys/kernel/debug/gpio_debug/gpio131/current_pinmux") err := a.arduinoSetup() require.ErrorContains(t, err, "/sys/kernel/debug/gpio_debug/gpio131/current_pinmux: no such file") } func TestArduinoI2CSetupFailTristate(t *testing.T) { a, fs := initConnectedTestAdaptorWithMockedFilesystem() require.NoError(t, a.arduinoSetup()) fs.WithWriteError = true err := a.arduinoI2CSetup() require.ErrorContains(t, err, "write error") } func TestArduinoI2CSetupFail14(t *testing.T) { a, fs := initConnectedTestAdaptorWithMockedFilesystem() require.NoError(t, a.arduinoSetup()) delete(fs.Files, "/sys/class/gpio/gpio14/direction") err := a.arduinoI2CSetup() require.ErrorContains(t, err, "/sys/class/gpio/gpio14/direction: no such file") } func TestArduinoI2CSetupUnexportFail(t *testing.T) { a, fs := initConnectedTestAdaptorWithMockedFilesystem() require.NoError(t, a.arduinoSetup()) delete(fs.Files, "/sys/class/gpio/unexport") err := a.arduinoI2CSetup() require.ErrorContains(t, err, "/sys/class/gpio/unexport: no such file") } func TestArduinoI2CSetupFail236(t *testing.T) { a, fs := initConnectedTestAdaptorWithMockedFilesystem() require.NoError(t, a.arduinoSetup()) delete(fs.Files, "/sys/class/gpio/gpio236/direction") err := a.arduinoI2CSetup() require.ErrorContains(t, err, "/sys/class/gpio/gpio236/direction: no such file") } func TestArduinoI2CSetupFail28(t *testing.T) { a, fs := initConnectedTestAdaptorWithMockedFilesystem() require.NoError(t, a.arduinoSetup()) delete(fs.Files, "/sys/kernel/debug/gpio_debug/gpio28/current_pinmux") err := a.arduinoI2CSetup() require.ErrorContains(t, err, "/sys/kernel/debug/gpio_debug/gpio28/current_pinmux: no such file") } func TestConnectArduinoError(t *testing.T) { a, fs := initTestAdaptorWithMockedFilesystem("arduino") fs.WithWriteError = true err := a.Connect() require.ErrorContains(t, err, "write error") } func TestConnectArduinoWriteError(t *testing.T) { a, fs := initTestAdaptorWithMockedFilesystem("arduino") fs.WithWriteError = true err := a.Connect() require.ErrorContains(t, err, "write error") } func TestConnectSparkfun(t *testing.T) { a, _ := initTestAdaptorWithMockedFilesystem("sparkfun") require.NoError(t, a.Connect()) assert.Equal(t, 1, a.DefaultI2cBus()) assert.Equal(t, "sparkfun", a.board) } func TestConnectMiniboard(t *testing.T) { a, _ := initTestAdaptorWithMockedFilesystem("miniboard") require.NoError(t, a.Connect()) assert.Equal(t, 1, a.DefaultI2cBus()) assert.Equal(t, "miniboard", a.board) } func TestConnectUnknown(t *testing.T) { a := NewAdaptor("wha") err := a.Connect() require.ErrorContains(t, err, "unknown board type: wha") } func TestFinalize(t *testing.T) { a, fs := initConnectedTestAdaptorWithMockedFilesystem() _ = a.DigitalWrite("3", 1) require.NoError(t, a.PwmWrite("5", 100)) _, _ = a.GetI2cConnection(0xff, 6) require.NoError(t, a.Finalize()) // assert that finalize after finalize is working require.NoError(t, a.Finalize()) // assert that re-connect is working require.NoError(t, a.Connect()) // remove one file to force Finalize error delete(fs.Files, "/sys/class/gpio/unexport") err := a.Finalize() require.ErrorContains(t, err, "1 error occurred") require.ErrorContains(t, err, "/sys/class/gpio/unexport") } func TestFinalizeError(t *testing.T) { a, fs := initConnectedTestAdaptorWithMockedFilesystem() require.NoError(t, a.PwmWrite("5", 100)) fs.WithWriteError = true err := a.Finalize() require.ErrorContains(t, err, "6 errors occurred") require.ErrorContains(t, err, "write error") require.ErrorContains(t, err, "SetEnabled(false) failed for id 1 with write error") require.ErrorContains(t, err, "Unexport() failed for id 1 with write error") } func TestDigitalIO(t *testing.T) { a, fs := initConnectedTestAdaptorWithMockedFilesystem() require.NoError(t, a.DigitalWrite("13", 1)) assert.Equal(t, "1", fs.Files["/sys/class/gpio/gpio40/value"].Contents) require.NoError(t, a.DigitalWrite("2", 0)) i, err := a.DigitalRead("2") require.NoError(t, err) assert.Equal(t, 0, i) } func TestDigitalPinInFileError(t *testing.T) { a := NewAdaptor() fs := a.sys.UseMockFilesystem(pwmMockPathsMux40) delete(fs.Files, "/sys/class/gpio/gpio40/value") delete(fs.Files, "/sys/class/gpio/gpio40/direction") _ = a.Connect() // we drop this error _, err := a.DigitalPin("13") require.ErrorContains(t, err, "no such file") } func TestDigitalPinInResistorFileError(t *testing.T) { a := NewAdaptor() fs := a.sys.UseMockFilesystem(pwmMockPathsMux40) delete(fs.Files, "/sys/class/gpio/gpio229/value") delete(fs.Files, "/sys/class/gpio/gpio229/direction") _ = a.Connect() // we drop this error _, err := a.DigitalPin("13") require.ErrorContains(t, err, "no such file") } func TestDigitalPinInLevelShifterFileError(t *testing.T) { a := NewAdaptor() fs := a.sys.UseMockFilesystem(pwmMockPathsMux40) delete(fs.Files, "/sys/class/gpio/gpio261/value") delete(fs.Files, "/sys/class/gpio/gpio261/direction") _ = a.Connect() // we drop this error _, err := a.DigitalPin("13") require.ErrorContains(t, err, "no such file") } func TestDigitalPinInMuxFileError(t *testing.T) { a := NewAdaptor() fs := a.sys.UseMockFilesystem(pwmMockPathsMux40) delete(fs.Files, "/sys/class/gpio/gpio243/value") delete(fs.Files, "/sys/class/gpio/gpio243/direction") _ = a.Connect() // we drop this error _, err := a.DigitalPin("13") require.ErrorContains(t, err, "no such file") } func TestDigitalWriteError(t *testing.T) { a, fs := initConnectedTestAdaptorWithMockedFilesystem() fs.WithWriteError = true err := a.DigitalWrite("13", 1) require.ErrorContains(t, err, "write error") } func TestDigitalReadWriteError(t *testing.T) { a, fs := initConnectedTestAdaptorWithMockedFilesystem() fs.WithWriteError = true _, err := a.DigitalRead("13") require.ErrorContains(t, err, "write error") } func TestPwm(t *testing.T) { a, fs := initConnectedTestAdaptorWithMockedFilesystem() err := a.PwmWrite("5", 100) require.NoError(t, err) assert.Equal(t, "1960", fs.Files["/sys/class/pwm/pwmchip0/pwm1/duty_cycle"].Contents) err = a.PwmWrite("7", 100) require.ErrorContains(t, err, "'7' is not a valid id for a PWM pin") } func TestPwmExportError(t *testing.T) { a := NewAdaptor() fs := a.sys.UseMockFilesystem(pwmMockPathsMux13Arduino) delete(fs.Files, "/sys/class/pwm/pwmchip0/export") err := a.Connect() require.NoError(t, err) err = a.PwmWrite("5", 100) require.ErrorContains(t, err, "/sys/class/pwm/pwmchip0/export: no such file") } func TestPwmEnableError(t *testing.T) { a := NewAdaptor() fs := a.sys.UseMockFilesystem(pwmMockPathsMux13) delete(fs.Files, "/sys/class/pwm/pwmchip0/pwm1/enable") _ = a.Connect() // we drop this error err := a.PwmWrite("5", 100) require.ErrorContains(t, err, "/sys/class/pwm/pwmchip0/pwm1/enable: no such file") } func TestPwmWritePinError(t *testing.T) { a, fs := initConnectedTestAdaptorWithMockedFilesystem() fs.WithWriteError = true err := a.PwmWrite("5", 100) require.ErrorContains(t, err, "write error") } func TestPwmWriteError(t *testing.T) { a, fs := initConnectedTestAdaptorWithMockedFilesystem() fs.WithWriteError = true err := a.PwmWrite("5", 100) require.ErrorContains(t, err, "write error") } func TestPwmReadError(t *testing.T) { a, fs := initConnectedTestAdaptorWithMockedFilesystem() fs.WithReadError = true err := a.PwmWrite("5", 100) require.ErrorContains(t, err, "read error") } func TestAnalog(t *testing.T) { a, fs := initConnectedTestAdaptorWithMockedFilesystem() fs.Files["/sys/bus/iio/devices/iio:device1/in_voltage0_raw"].Contents = "1000\n" i, err := a.AnalogRead("0") require.NoError(t, err) assert.Equal(t, 250, i) } func TestAnalogError(t *testing.T) { a, fs := initConnectedTestAdaptorWithMockedFilesystem() fs.WithReadError = true _, err := a.AnalogRead("0") require.ErrorContains(t, err, "read error") } func TestI2cWorkflow(t *testing.T) { a, _ := initConnectedTestAdaptorWithMockedFilesystem() a.sys.UseMockSyscall() con, err := a.GetI2cConnection(0xff, 6) require.NoError(t, err) _, err = con.Write([]byte{0x00, 0x01}) require.NoError(t, err) data := []byte{42, 42} _, err = con.Read(data) require.NoError(t, err) assert.Equal(t, []byte{0x00, 0x01}, data) require.NoError(t, a.Finalize()) } func TestI2cFinalizeWithErrors(t *testing.T) { // arrange a := NewAdaptor() a.sys.UseMockSyscall() fs := a.sys.UseMockFilesystem(pwmMockPathsMux13ArduinoI2c) require.NoError(t, a.Connect()) con, err := a.GetI2cConnection(0xff, 6) require.NoError(t, err) _, err = con.Write([]byte{0x0A}) require.NoError(t, err) fs.WithCloseError = true // act err = a.Finalize() // assert require.Error(t, err) require.ErrorContains(t, err, "close error") } func Test_validateAndSetupI2cBusNumber(t *testing.T) { tests := map[string]struct { board string busNr int wantErr string }{ "arduino_number_negative_error": { busNr: -1, wantErr: "unsupported I2C bus '-1'", }, "arduino_number_1_error": { busNr: 1, wantErr: "unsupported I2C bus '1'", }, "arduino_number_6_ok": { busNr: 6, }, "sparkfun_number_negative_error": { board: "sparkfun", busNr: -1, wantErr: "unsupported I2C bus '-1'", }, "sparkfun_number_1_ok": { board: "sparkfun", busNr: 1, }, "miniboard_number_6_error": { board: "miniboard", busNr: 6, wantErr: "unsupported I2C bus '6'", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange a := NewAdaptor(tc.board) a.sys.UseMockFilesystem(pwmMockPathsMux13ArduinoI2c) _ = a.Connect() // act err := a.validateAndSetupI2cBusNumber(tc.busNr) // assert if tc.wantErr != "" { require.EqualError(t, err, tc.wantErr) } else { require.NoError(t, err) } }) } } ================================================ FILE: platforms/intel-iot/edison/miniboard_pinmap.go ================================================ package edison var miniboardPinMap = map[string]sysfsPin{ "J17-1": { pin: 182, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J17-2": { pin: -1, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J17-3": { pin: -1, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J17-4": { pin: -1, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J17-5": { pin: 135, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J17-6": { pin: -1, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J17-7": { pin: 27, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J17-8": { pin: 20, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J17-9": { pin: 28, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J17-10": { pin: 111, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J17-11": { pin: 109, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J17-12": { pin: 115, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J17-13": { pin: -1, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J17-14": { pin: 128, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J18-1": { pin: 13, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J18-2": { pin: 165, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J18-3": { pin: -1, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J18-4": { pin: -1, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J18-5": { pin: -1, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J18-6": { pin: 19, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J18-7": { pin: 12, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J18-8": { pin: 183, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J18-9": { pin: -1, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J18-10": { pin: 110, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J18-11": { pin: 114, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J18-12": { pin: 129, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J18-13": { pin: 130, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J18-14": { pin: -1, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J19-1": { pin: -1, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J19-2": { pin: -1, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J19-3": { pin: -1, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J19-4": { pin: 44, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J19-5": { pin: 46, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J19-6": { pin: 48, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J19-7": { pin: -1, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J19-8": { pin: 131, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J19-9": { pin: 14, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J19-10": { pin: 40, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J19-11": { pin: 43, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J19-12": { pin: 77, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J19-13": { pin: 82, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J19-14": { pin: 83, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J20-1": { pin: -1, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J20-2": { pin: -1, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J20-3": { pin: -1, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J20-4": { pin: 45, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J20-5": { pin: 47, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J20-6": { pin: 49, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J20-7": { pin: 15, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J20-8": { pin: 84, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J20-9": { pin: 42, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J20-10": { pin: 41, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J20-11": { pin: 78, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J20-12": { pin: 79, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J20-13": { pin: 80, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "J20-14": { pin: 81, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, } ================================================ FILE: platforms/intel-iot/edison/sparkfun_pinmap.go ================================================ package edison var sparkfunPinMap = map[string]sysfsPin{ "12": { pin: 12, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "13": { pin: 13, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "14": { pin: 14, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "15": { pin: 15, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "44": { pin: 44, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "45": { pin: 45, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "46": { pin: 46, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "47": { pin: 47, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "48": { pin: 48, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "49": { pin: 49, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "128": { pin: 128, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "129": { pin: 129, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "130": { pin: 130, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "131": { pin: 131, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "182": { pin: 182, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, "183": { pin: 183, resistor: -1, levelShifter: -1, pwmPin: -1, mux: []mux{}, }, } ================================================ FILE: platforms/intel-iot/intel-iot.go ================================================ /* Package inteliot contains Gobot adaptors for the Intel IoT platforms. This package currently supports the following Intel IoT hardware: - Intel Edison with the Arduino breakout board - Intel Joule developer kit For further information refer to intel-iot README: https://github.com/hybridgroup/gobot/blob/release/platforms/intel-iot/README.md */ package inteliot ================================================ FILE: platforms/intel-iot/joule/README.md ================================================ # Edison The Intel Joule is a WiFi and Bluetooth enabled development platform for the Internet of Things. For more info about the Intel Joule platform go to: ## How to Install Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) ### Setting up your Intel Joule Everything you need to get started with the Joule is in the Intel Getting Started Guide located at: Don't forget to configure your Joule's WiFi connection and update your Joule to the latest firmware image. Gobot has been tested using the reference OS based on Ostro. ## How To Use ```go package main import ( "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/intel-iot/joule" ) func main() { e := joule.NewAdaptor() led := gpio.NewLedDriver(e, "GP103") work := func() { gobot.Every(1*time.Second, func() { if err := led.Toggle(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("blinkBot", []gobot.Connection{e}, []gobot.Device{led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ``` You can read the [full API documentation online](http://godoc.org/gobot.io/x/gobot/v2). ## How to Connect ### Compiling Compile your Gobot program on your workstation like this: ```sh GOARCH=386 GOOS=linux go build joule_blink.go ``` Once you have compiled your code, you can you can upload your program and execute it on the Intel Joule from your workstation using the `scp` and `ssh` commands like this: ```sh scp joule_blink root@:/home/root/ ssh -t root@ "./joule_blink" ``` At this point you should see one of the onboard LEDs blinking. Press control + c to exit. To update the program after you made a change, you will need to scp it over once again and start it from the command line (via screen). ## Pin Mapping The Gobot pin mapping for the Intel Joule uses a naming system based on how the pins are labeled on the board itself. There are 2 jumpers on the Joule expansion board, labeled "J12" and "J13". There are 2 rows of pins on each jumper, labeled from 1 to 40. So to use the 26th pin of jumper J12, you use pin name "J12_26". In addition, there are pins that control the build-in LEDs (pins GP100 thru GP103) as used in the example above. The i2c interfaces on the Intel Joule developer kit board require that you terminate the SDA & SCL lines using 2 10K resistors pulled up to the voltage used for the i2c device, for example 5V. ================================================ FILE: platforms/intel-iot/joule/doc.go ================================================ /* Package joule contains the Gobot adaptor for the Intel Joule. For further information refer to intel-iot README: https://github.com/hybridgroup/gobot/blob/release/platforms/intel-iot/joule/README.md */ package joule // import "gobot.io/x/gobot/v2/platforms/intel-iot/joule" ================================================ FILE: platforms/intel-iot/joule/joule_adaptor.go ================================================ package joule import ( "fmt" "sync" multierror "github.com/hashicorp/go-multierror" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/adaptors" "gobot.io/x/gobot/v2/system" ) const ( defaultI2cBusNumber = 0 defaultSpiMaxSpeed = 5000 // 5kHz (more than 15kHz not possible with SPI over GPIO) ) type sysfsPin struct { pin int pwmPin int } // Adaptor represents an Intel Joule type Adaptor struct { *adaptors.DigitalPinsAdaptor *adaptors.PWMPinsAdaptor *adaptors.I2cBusAdaptor *adaptors.SpiBusAdaptor // for usage of "adaptors.WithSpiGpioAccess()" name string sys *system.Accesser // used for unit tests only mutex sync.Mutex } // NewAdaptor returns a new Joule Adaptor // // Optional parameters: // // adaptors.WithGpioCdevAccess(): use character device driver instead of sysfs // adaptors.WithSpiGpioAccess(sclk, ncs, sdo, sdi): use GPIO's instead of /dev/spidev#.# // // Further optional parameters for: // // GPIO, see [adaptors.NewDigitalPinsAdaptor] // I2C, see [adaptors.NewI2cBusAdaptor] // PWM, see [adaptors.NewPWMPinsAdaptor] // SPI, see [adaptors.NewSpiBusAdaptor] func NewAdaptor(opts ...interface{}) *Adaptor { sys := system.NewAccesser(system.WithDigitalPinSysfsAccess()) a := &Adaptor{ name: gobot.DefaultName("Joule"), sys: sys, } var digitalPinsOpts []adaptors.DigitalPinsOptionApplier pwmPinsOpts := []adaptors.PwmPinsOptionApplier{adaptors.WithPWMPinInitializer(pwmPinInitializer)} var i2cBusOpts []adaptors.I2CBusOptionApplier var spiBusOpts []adaptors.SpiBusOptionApplier for _, opt := range opts { switch o := opt.(type) { case adaptors.DigitalPinsOptionApplier: digitalPinsOpts = append(digitalPinsOpts, o) case adaptors.PwmPinsOptionApplier: pwmPinsOpts = append(pwmPinsOpts, o) case adaptors.I2CBusOptionApplier: i2cBusOpts = append(i2cBusOpts, o) case adaptors.SpiBusOptionApplier: spiBusOpts = append(spiBusOpts, o) default: panic(fmt.Sprintf("'%s' can not be applied on adaptor '%s'", opt, a.name)) } } // Valid bus numbers are [0..2] which corresponds to /dev/i2c-0 through /dev/i2c-2. i2cBusNumberValidator := adaptors.NewBusNumberValidator([]int{0, 1, 2}) a.DigitalPinsAdaptor = adaptors.NewDigitalPinsAdaptor(sys, a.translateDigitalPin, digitalPinsOpts...) a.PWMPinsAdaptor = adaptors.NewPWMPinsAdaptor(sys, a.translatePWMPin, pwmPinsOpts...) a.I2cBusAdaptor = adaptors.NewI2cBusAdaptor(sys, i2cBusNumberValidator.Validate, defaultI2cBusNumber, i2cBusOpts...) // SPI is only supported when "adaptors.WithSpiGpioAccess()" is given if len(spiBusOpts) > 0 { a.SpiBusAdaptor = adaptors.NewSpiBusAdaptor(sys, func(int) error { return nil }, 0, 0, 0, 0, defaultSpiMaxSpeed, a.DigitalPinsAdaptor, spiBusOpts...) } return a } // Name returns the adaptors name func (a *Adaptor) Name() string { return a.name } // SetName sets the adaptors name func (a *Adaptor) SetName(n string) { a.name = n } // Connect create new connection to board and pins. func (a *Adaptor) Connect() error { a.mutex.Lock() defer a.mutex.Unlock() if err := a.I2cBusAdaptor.Connect(); err != nil { return err } if err := a.PWMPinsAdaptor.Connect(); err != nil { return err } return a.DigitalPinsAdaptor.Connect() } // Finalize releases all i2c devices and exported digital and pwm pins. func (a *Adaptor) Finalize() error { a.mutex.Lock() defer a.mutex.Unlock() err := a.DigitalPinsAdaptor.Finalize() if e := a.PWMPinsAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } if e := a.I2cBusAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } return err } func (a *Adaptor) translateDigitalPin(id string) (string, int, error) { if val, ok := sysfsPinMap[id]; ok { return "", val.pin, nil } return "", -1, fmt.Errorf("'%s' is not a valid id for a digital pin", id) } func (a *Adaptor) translatePWMPin(id string) (string, int, error) { sysPin, ok := sysfsPinMap[id] if !ok { return "", -1, fmt.Errorf("'%s' is not a valid id for a pin", id) } if sysPin.pwmPin == -1 { return "", -1, fmt.Errorf("'%s' is not a valid id for a PWM pin", id) } return "/sys/class/pwm/pwmchip0", sysPin.pwmPin, nil } func pwmPinInitializer(_ string, pin gobot.PWMPinner) error { if err := pin.Export(); err != nil { return err } if err := pin.SetPeriod(10000000); err != nil { return err } return pin.SetEnabled(true) } ================================================ FILE: platforms/intel-iot/joule/joule_adaptor_test.go ================================================ package joule import ( "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/adaptors" "gobot.io/x/gobot/v2/system" ) // make sure that this Adaptor fulfills all the required interfaces var ( _ gobot.Adaptor = (*Adaptor)(nil) _ gobot.DigitalPinnerProvider = (*Adaptor)(nil) _ gobot.PWMPinnerProvider = (*Adaptor)(nil) _ gpio.DigitalReader = (*Adaptor)(nil) _ gpio.DigitalWriter = (*Adaptor)(nil) _ gpio.PwmWriter = (*Adaptor)(nil) _ i2c.Connector = (*Adaptor)(nil) ) func initConnectedTestAdaptorWithMockedFilesystem() (*Adaptor, *system.MockFilesystem) { a := NewAdaptor() mockPaths := []string{ "/sys/class/pwm/pwmchip0/export", "/sys/class/pwm/pwmchip0/unexport", "/sys/class/pwm/pwmchip0/pwm0/duty_cycle", "/sys/class/pwm/pwmchip0/pwm0/period", "/sys/class/pwm/pwmchip0/pwm0/enable", "/sys/class/gpio/export", "/sys/class/gpio/unexport", "/sys/class/gpio/gpio13/value", "/sys/class/gpio/gpio13/direction", "/sys/class/gpio/gpio40/value", "/sys/class/gpio/gpio40/direction", "/sys/class/gpio/gpio446/value", "/sys/class/gpio/gpio446/direction", "/sys/class/gpio/gpio463/value", "/sys/class/gpio/gpio463/direction", "/sys/class/gpio/gpio421/value", "/sys/class/gpio/gpio421/direction", "/sys/class/gpio/gpio221/value", "/sys/class/gpio/gpio221/direction", "/sys/class/gpio/gpio243/value", "/sys/class/gpio/gpio243/direction", "/sys/class/gpio/gpio229/value", "/sys/class/gpio/gpio229/direction", "/sys/class/gpio/gpio253/value", "/sys/class/gpio/gpio253/direction", "/sys/class/gpio/gpio261/value", "/sys/class/gpio/gpio261/direction", "/sys/class/gpio/gpio214/value", "/sys/class/gpio/gpio214/direction", "/sys/class/gpio/gpio14/direction", "/sys/class/gpio/gpio14/value", "/sys/class/gpio/gpio165/direction", "/sys/class/gpio/gpio165/value", "/sys/class/gpio/gpio212/direction", "/sys/class/gpio/gpio212/value", "/sys/class/gpio/gpio213/direction", "/sys/class/gpio/gpio213/value", "/sys/class/gpio/gpio236/direction", "/sys/class/gpio/gpio236/value", "/sys/class/gpio/gpio237/direction", "/sys/class/gpio/gpio237/value", "/sys/class/gpio/gpio204/direction", "/sys/class/gpio/gpio204/value", "/sys/class/gpio/gpio205/direction", "/sys/class/gpio/gpio205/value", "/sys/class/gpio/gpio263/direction", "/sys/class/gpio/gpio263/value", "/sys/class/gpio/gpio262/direction", "/sys/class/gpio/gpio262/value", "/sys/class/gpio/gpio240/direction", "/sys/class/gpio/gpio240/value", "/sys/class/gpio/gpio241/direction", "/sys/class/gpio/gpio241/value", "/sys/class/gpio/gpio242/direction", "/sys/class/gpio/gpio242/value", "/sys/class/gpio/gpio218/direction", "/sys/class/gpio/gpio218/value", "/sys/class/gpio/gpio250/direction", "/sys/class/gpio/gpio250/value", "/sys/class/gpio/gpio451/direction", "/sys/class/gpio/gpio451/value", "/dev/i2c-0", } fs := a.sys.UseMockFilesystem(mockPaths) fs.Files["/sys/class/pwm/pwmchip0/pwm0/period"].Contents = "5000" if err := a.Connect(); err != nil { panic(err) } return a, fs } func TestNewAdaptor(t *testing.T) { // arrange & act a := NewAdaptor() // assert assert.IsType(t, &Adaptor{}, a) assert.True(t, strings.HasPrefix(a.Name(), "Joule")) assert.NotNil(t, a.sys) assert.NotNil(t, a.DigitalPinsAdaptor) assert.NotNil(t, a.PWMPinsAdaptor) assert.NotNil(t, a.I2cBusAdaptor) assert.Nil(t, a.SpiBusAdaptor) assert.True(t, a.sys.HasDigitalPinSysfsAccess()) // act & assert a.SetName("NewName") assert.Equal(t, "NewName", a.Name()) } func TestNewAdaptorWithOption(t *testing.T) { // arrange & act a := NewAdaptor(adaptors.WithSpiGpioAccess("1", "2", "3", "4")) // assert assert.IsType(t, &Adaptor{}, a) assert.True(t, strings.HasPrefix(a.Name(), "Joule")) assert.NotNil(t, a.sys) assert.NotNil(t, a.DigitalPinsAdaptor) assert.NotNil(t, a.PWMPinsAdaptor) assert.NotNil(t, a.I2cBusAdaptor) assert.NotNil(t, a.SpiBusAdaptor) assert.True(t, a.sys.HasDigitalPinSysfsAccess()) } func TestFinalize(t *testing.T) { a, _ := initConnectedTestAdaptorWithMockedFilesystem() _ = a.DigitalWrite("J12_1", 1) _ = a.PwmWrite("J12_26", 100) require.NoError(t, a.Finalize()) // assert finalize after finalize is working require.NoError(t, a.Finalize()) // assert re-connect is working require.NoError(t, a.Connect()) } func TestDigitalIO(t *testing.T) { a, fs := initConnectedTestAdaptorWithMockedFilesystem() _ = a.DigitalWrite("J12_1", 1) assert.Equal(t, "1", fs.Files["/sys/class/gpio/gpio451/value"].Contents) _ = a.DigitalWrite("J12_1", 0) i, err := a.DigitalRead("J12_1") require.NoError(t, err) assert.Equal(t, 0, i) _, err = a.DigitalRead("P9_99") require.ErrorContains(t, err, "'P9_99' is not a valid id for a digital pin") } func TestPwm(t *testing.T) { a, fs := initConnectedTestAdaptorWithMockedFilesystem() err := a.PwmWrite("J12_26", 100) require.NoError(t, err) assert.Equal(t, "3921568", fs.Files["/sys/class/pwm/pwmchip0/pwm0/duty_cycle"].Contents) err = a.PwmWrite("4", 100) require.ErrorContains(t, err, "'4' is not a valid id for a pin") err = a.PwmWrite("J12_1", 100) require.ErrorContains(t, err, "'J12_1' is not a valid id for a PWM pin") } func TestPwmPinExportError(t *testing.T) { a, fs := initConnectedTestAdaptorWithMockedFilesystem() delete(fs.Files, "/sys/class/pwm/pwmchip0/export") err := a.PwmWrite("J12_26", 100) require.ErrorContains(t, err, "/sys/class/pwm/pwmchip0/export: no such file") } func TestPwmPinEnableError(t *testing.T) { a, fs := initConnectedTestAdaptorWithMockedFilesystem() delete(fs.Files, "/sys/class/pwm/pwmchip0/pwm0/enable") err := a.PwmWrite("J12_26", 100) require.ErrorContains(t, err, "/sys/class/pwm/pwmchip0/pwm0/enable: no such file") } func TestI2cDefaultBus(t *testing.T) { a := NewAdaptor() assert.Equal(t, 0, a.DefaultI2cBus()) } func TestI2cFinalizeWithErrors(t *testing.T) { // arrange a := NewAdaptor() a.sys.UseMockSyscall() fs := a.sys.UseMockFilesystem([]string{"/dev/i2c-2"}) require.NoError(t, a.Connect()) con, err := a.GetI2cConnection(0xff, 2) require.NoError(t, err) _, err = con.Write([]byte{0xbf}) require.NoError(t, err) fs.WithCloseError = true // act err = a.Finalize() // assert require.ErrorContains(t, err, "close error") } ================================================ FILE: platforms/intel-iot/joule/tuchuck_pinmap.go ================================================ package joule var sysfsPinMap = map[string]sysfsPin{ // GPIO22 "J12_1": { pin: 451, pwmPin: -1, }, // SPP1RX "J12_2": { pin: 421, pwmPin: -1, }, // PMICRST "J12_3": { pin: -1, pwmPin: -1, }, // SPP1TX "J12_4": { pin: 422, pwmPin: -1, }, // 19.2mhz "J12_5": { pin: 356, pwmPin: -1, }, // SPP1FS0 "J12_6": { pin: 417, pwmPin: -1, }, // UART0TX "J12_7": { pin: -1, pwmPin: -1, }, // SPP1FS2 "J12_8": { pin: 419, pwmPin: -1, }, // PWRGD "J12_9": { pin: -1, pwmPin: -1, }, // SPP1CLK "J12_10": { pin: 416, pwmPin: -1, }, // I2C0SDA "J12_11": { pin: -1, pwmPin: -1, }, // I2S1SDI "J12_12": { pin: -1, pwmPin: -1, }, // I2C0SCL "J12_13": { pin: -1, pwmPin: -1, }, // I2S1SDO "J12_14": { pin: -1, pwmPin: -1, }, // II0SDA "J12_15": { pin: -1, pwmPin: -1, }, // I2S1WS "J12_16": { pin: 380, pwmPin: -1, }, // IIC0SCL "J12_17": { pin: -1, pwmPin: -1, }, // I2S1CLK "J12_18": { pin: 379, pwmPin: -1, }, // IIC1SDA "J12_19": { pin: -1, pwmPin: -1, }, // I2S1MCL "J12_20": { pin: 378, pwmPin: -1, }, // IIC1SCL "J12_21": { pin: -1, pwmPin: -1, }, // UART1TX "J12_22": { pin: -1, pwmPin: -1, }, // ISH_IO6 "J12_23": { pin: 343, pwmPin: -1, }, // UART1RX "J12_24": { pin: -1, pwmPin: -1, }, // ISH_IO5 "J12_25": { pin: 342, pwmPin: -1, }, // PWM0 "J12_26": { pin: 463, pwmPin: 0, }, // ISH_IO4 "J12_27": { pin: 341, pwmPin: -1, }, // PWM1 "J12_28": { pin: 464, pwmPin: 1, }, // ISH_IO3 "J12_29": { pin: 340, pwmPin: -1, }, // PWM2 "J12_30": { pin: 465, pwmPin: 2, }, // ISH_IO2 "J12_31": { pin: 339, pwmPin: -1, }, // PWM3 "J12_32": { pin: 466, pwmPin: 3, }, // ISH_IO1 "J12_33": { pin: 338, pwmPin: -1, }, // 1.8V "J12_34": { pin: -1, pwmPin: -1, }, // ISH_IO0 "J12_35": { pin: 337, pwmPin: -1, }, // GND "J12_36": { pin: -1, pwmPin: -1, }, // GND "J12_37": { pin: -1, pwmPin: -1, }, // GND "J12_38": { pin: -1, pwmPin: -1, }, // GND "J12_39": { pin: -1, pwmPin: -1, }, // GND "J12_40": { pin: -1, pwmPin: -1, }, // Second header // GND "J13_1": { pin: -1, pwmPin: -1, }, // 5V "J13_2": { pin: -1, pwmPin: -1, }, // GND "J13_3": { pin: -1, pwmPin: -1, }, // 5V "J13_4": { pin: -1, pwmPin: -1, }, // GND "J13_5": { pin: -1, pwmPin: -1, }, // 3.3V "J13_6": { pin: -1, pwmPin: -1, }, // GND "J13_7": { pin: -1, pwmPin: -1, }, // 3.3V "J13_8": { pin: -1, pwmPin: -1, }, // GND "J13_9": { pin: -1, pwmPin: -1, }, // 1.8V "J13_10": { pin: -1, pwmPin: -1, }, // GPIO "J13_11": { pin: 456, pwmPin: -1, }, // 1.8V "J13_12": { pin: -1, pwmPin: -1, }, // PANEL "J13_13": { pin: 270, pwmPin: -1, }, // GND "J13_14": { pin: -1, pwmPin: -1, }, // PANEL "J13_15": { pin: 271, pwmPin: -1, }, // CAMERA "J13_16": { pin: -1, pwmPin: -1, }, // PANEL "J13_17": { pin: 272, pwmPin: -1, }, // CAMERA "J13_18": { pin: -1, pwmPin: -1, }, // SPP0FS0 "J13_19": { pin: 411, pwmPin: -1, }, // CAMERA "J13_20": { pin: -1, pwmPin: -1, }, // SPP0FS1 "J13_21": { pin: 412, pwmPin: -1, }, // SPI_DAT "J13_22": { pin: -1, pwmPin: -1, }, // SPP0FS2 "J13_23": { pin: 413, pwmPin: -1, }, // SPICLKB "J13_24": { pin: 384, pwmPin: -1, }, // SPP0CLK "J13_25": { pin: 410, pwmPin: -1, }, // SPICLKA "J13_26": { pin: 383, pwmPin: -1, }, // SPP0TX "J13_27": { pin: 414, pwmPin: -1, }, // UART0RX "J13_28": { pin: -1, pwmPin: -1, }, // SPP0RX "J13_29": { pin: 415, pwmPin: -1, }, // UART0RT "J13_30": { pin: -1, pwmPin: -1, }, // I2C1SDA "J13_31": { pin: -1, pwmPin: -1, }, // UART0CT "J13_32": { pin: -1, pwmPin: -1, }, // I2C1SCL "J13_33": { pin: -1, pwmPin: -1, }, // IURT0TX "J13_34": { pin: -1, pwmPin: -1, }, // I2C2SDA "J13_35": { pin: -1, pwmPin: -1, }, // IURT0RX "J13_36": { pin: -1, pwmPin: -1, }, // I2C2SCL "J13_37": { pin: -1, pwmPin: -1, }, // IURT0RT "J13_38": { pin: -1, pwmPin: -1, }, // RTC_CLK "J13_39": { pin: 367, pwmPin: -1, }, // IURT0CT "J13_40": { pin: -1, pwmPin: -1, }, // Built-in LEDs // LED100 "GP100": { pin: 337, pwmPin: -1, }, // LED101 "GP101": { pin: 338, pwmPin: -1, }, // LED102 "GP102": { pin: 339, pwmPin: -1, }, // LED103 "GP103": { pin: 340, pwmPin: -1, }, // LEDWIFI "GP104": { pin: 438, pwmPin: -1, }, // LEDBT "GP105": { pin: 439, pwmPin: -1, }, } ================================================ FILE: platforms/jetson/README.md ================================================ # Jetson Nano The Jetson Nano is ARM based single board computer with digital & PWM GPIO, and i2c interfaces built in. The Gobot adaptor for the Jetson Nano should support Jetno Nano. For more info about the Jetson Nano platform, click [here](https://developer.nvidia.com/embedded/jetson-nano/). ## How to Install Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) We recommend updating to the latest jetson-nano OS when using the Jetson Nano, however Gobot should also support older versions of the OS, should your application require this. ## How to Use The pin numbering used by your Gobot program should match the way your board is labeled right on the board itself. ```go package main import ( "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/jetson" ) func main() { r := jetson.NewAdaptor() led := gpio.NewLedDriver(r, "40") work := func() { gobot.Every(1*time.Second, func() { if err := led.Toggle(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("blinkBot", []gobot.Connection{r}, []gobot.Device{led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ``` ## How to Connect ### Compiling Once you have compiled your code, you can upload your program and execute it on the Jetson Nano from your workstation using the `scp` and `ssh` commands like this: ```sh scp jetson-nano_blink jn@192.168.1.xxx:/home/jn/ ssh -t jn@192.168.1.xxx "./jetson-nano_blink" ``` ================================================ FILE: platforms/jetson/adaptor.go ================================================ package jetson import ( "fmt" "sync" multierror "github.com/hashicorp/go-multierror" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/adaptors" "gobot.io/x/gobot/v2/system" ) const ( pwmPeriodDefault = 3000000 // 3 ms = 333 Hz pwmPeriodMinimum = 5334 pwmDutyRateMinimum = 0.0005 // minimum duty of 1500 for default period, ~3 for minimum period defaultI2cBusNumber = 1 defaultSpiBusNumber = 0 defaultSpiChipNumber = 0 defaultSpiMode = 0 defaultSpiBitsNumber = 8 defaultSpiMaxSpeed = 10000000 ) // Adaptor is the Gobot adaptor for the Jetson Nano type Adaptor struct { *adaptors.DigitalPinsAdaptor *adaptors.PWMPinsAdaptor *adaptors.I2cBusAdaptor *adaptors.SpiBusAdaptor name string sys *system.Accesser // used for unit tests only mutex *sync.Mutex } // NewAdaptor creates a Jetson Nano adaptor // // Optional parameters: // // adaptors.WithGpioCdevAccess(): use character device driver instead of sysfs // adaptors.WithSpiGpioAccess(sclk, ncs, sdo, sdi): use GPIO's instead of /dev/spidev#.# // // Further optional parameters for: // // GPIO, see [adaptors.NewDigitalPinsAdaptor] // I2C, see [adaptors.NewI2cBusAdaptor] // PWM, see [adaptors.NewPWMPinsAdaptor] // SPI, see [adaptors.NewSpiBusAdaptor] func NewAdaptor(opts ...interface{}) *Adaptor { sys := system.NewAccesser(system.WithDigitalPinSysfsAccess()) a := &Adaptor{ name: gobot.DefaultName("JetsonNano"), sys: sys, mutex: &sync.Mutex{}, } var digitalPinsOpts []adaptors.DigitalPinsOptionApplier pwmPinsOpts := []adaptors.PwmPinsOptionApplier{ adaptors.WithPWMDefaultPeriod(pwmPeriodDefault), adaptors.WithPWMMinimumPeriod(pwmPeriodMinimum), adaptors.WithPWMMinimumDutyRate(pwmDutyRateMinimum), } var i2cBusOpts []adaptors.I2CBusOptionApplier var spiBusOpts []adaptors.SpiBusOptionApplier for _, opt := range opts { switch o := opt.(type) { case adaptors.DigitalPinsOptionApplier: digitalPinsOpts = append(digitalPinsOpts, o) case adaptors.PwmPinsOptionApplier: pwmPinsOpts = append(pwmPinsOpts, o) case adaptors.I2CBusOptionApplier: i2cBusOpts = append(i2cBusOpts, o) case adaptors.SpiBusOptionApplier: spiBusOpts = append(spiBusOpts, o) default: panic(fmt.Sprintf("'%s' can not be applied on adaptor '%s'", opt, a.name)) } } // Valid bus numbers are [0,1] which corresponds to /dev/i2c-0 through /dev/i2c-1. i2cBusNumberValidator := adaptors.NewBusNumberValidator([]int{0, 1}) // Valid bus numbers are [0,1] which corresponds to /dev/spidev0.x through /dev/spidev1.x. // x is the chip number <255 spiBusNumberValidator := adaptors.NewBusNumberValidator([]int{0, 1}) a.DigitalPinsAdaptor = adaptors.NewDigitalPinsAdaptor(sys, a.translateDigitalPin, digitalPinsOpts...) a.PWMPinsAdaptor = adaptors.NewPWMPinsAdaptor(sys, a.translatePWMPin, pwmPinsOpts...) a.I2cBusAdaptor = adaptors.NewI2cBusAdaptor(sys, i2cBusNumberValidator.Validate, defaultI2cBusNumber, i2cBusOpts...) a.SpiBusAdaptor = adaptors.NewSpiBusAdaptor(sys, spiBusNumberValidator.Validate, defaultSpiBusNumber, defaultSpiChipNumber, defaultSpiMode, defaultSpiBitsNumber, defaultSpiMaxSpeed, a.DigitalPinsAdaptor, spiBusOpts...) return a } // Name returns the adaptors name func (a *Adaptor) Name() string { a.mutex.Lock() defer a.mutex.Unlock() return a.name } // SetName sets the adaptors name func (a *Adaptor) SetName(n string) { a.mutex.Lock() defer a.mutex.Unlock() a.name = n } // Connect create new connection to board and pins. func (a *Adaptor) Connect() error { a.mutex.Lock() defer a.mutex.Unlock() if err := a.SpiBusAdaptor.Connect(); err != nil { return err } if err := a.I2cBusAdaptor.Connect(); err != nil { return err } if err := a.PWMPinsAdaptor.Connect(); err != nil { return err } return a.DigitalPinsAdaptor.Connect() } // Finalize closes connection to board and pins func (a *Adaptor) Finalize() error { a.mutex.Lock() defer a.mutex.Unlock() err := a.DigitalPinsAdaptor.Finalize() if e := a.PWMPinsAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } if e := a.I2cBusAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } if e := a.SpiBusAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } return err } func (a *Adaptor) translateDigitalPin(id string) (string, int, error) { if line, ok := gpioPins[id]; ok { return "", line, nil } return "", -1, fmt.Errorf("'%s' is not a valid id for a digital pin", id) } func (a *Adaptor) translatePWMPin(id string) (string, int, error) { if channel, ok := pwmPins[id]; ok { return "/sys/class/pwm/pwmchip0", channel, nil } return "", 0, fmt.Errorf("'%s' is not a valid pin id for PWM on '%s'", id, a.name) } ================================================ FILE: platforms/jetson/adaptor_test.go ================================================ package jetson import ( "runtime" "strconv" "strings" "sync" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/drivers/spi" "gobot.io/x/gobot/v2/system" ) // make sure that this Adaptor fulfills all the required interfaces var ( _ gobot.Adaptor = (*Adaptor)(nil) _ gobot.DigitalPinnerProvider = (*Adaptor)(nil) _ gobot.PWMPinnerProvider = (*Adaptor)(nil) _ gpio.DigitalReader = (*Adaptor)(nil) _ gpio.DigitalWriter = (*Adaptor)(nil) _ i2c.Connector = (*Adaptor)(nil) _ spi.Connector = (*Adaptor)(nil) ) func initConnectedTestAdaptorWithMockedFilesystem(mockPaths []string) (*Adaptor, *system.MockFilesystem) { a := NewAdaptor() fs := a.sys.UseMockFilesystem(mockPaths) if err := a.Connect(); err != nil { panic(err) } return a, fs } func TestNewAdaptor(t *testing.T) { // arrange & act a := NewAdaptor() // assert assert.IsType(t, &Adaptor{}, a) assert.True(t, strings.HasPrefix(a.Name(), "JetsonNano")) assert.NotNil(t, a.sys) assert.NotNil(t, a.mutex) assert.NotNil(t, a.DigitalPinsAdaptor) assert.NotNil(t, a.PWMPinsAdaptor) assert.NotNil(t, a.I2cBusAdaptor) assert.NotNil(t, a.SpiBusAdaptor) assert.True(t, a.sys.HasDigitalPinSysfsAccess()) // act & assert a.SetName("NewName") assert.Equal(t, "NewName", a.Name()) } func TestFinalize(t *testing.T) { mockPaths := []string{ "/sys/class/gpio/export", "/sys/class/gpio/unexport", "/dev/i2c-1", "/dev/i2c-0", "/dev/spidev0.0", "/dev/spidev0.1", } a, _ := initConnectedTestAdaptorWithMockedFilesystem(mockPaths) _ = a.DigitalWrite("3", 1) _, _ = a.GetI2cConnection(0xff, 0) require.NoError(t, a.Finalize()) } func TestPWMPinsConnect(t *testing.T) { a := NewAdaptor() err := a.PwmWrite("33", 1) require.ErrorContains(t, err, "not connected") err = a.Connect() require.NoError(t, err) } func TestPWMPinsReConnect(t *testing.T) { // arrange mockPaths := []string{ "/sys/class/pwm/pwmchip0/export", "/sys/class/pwm/pwmchip0/unexport", "/sys/class/pwm/pwmchip0/pwm2/duty_cycle", "/sys/class/pwm/pwmchip0/pwm2/period", "/sys/class/pwm/pwmchip0/pwm2/polarity", "/sys/class/pwm/pwmchip0/pwm2/enable", } a, _ := initConnectedTestAdaptorWithMockedFilesystem(mockPaths) require.NoError(t, a.PwmWrite("33", 1)) require.NoError(t, a.Finalize()) // act err := a.Connect() // assert require.NoError(t, err) } func TestDigitalIO(t *testing.T) { mockPaths := []string{ "/sys/class/gpio/export", "/sys/class/gpio/unexport", "/sys/class/gpio/gpio216/value", "/sys/class/gpio/gpio216/direction", "/sys/class/gpio/gpio14/value", "/sys/class/gpio/gpio14/direction", } a, fs := initConnectedTestAdaptorWithMockedFilesystem(mockPaths) err := a.DigitalWrite("7", 1) require.NoError(t, err) assert.Equal(t, "1", fs.Files["/sys/class/gpio/gpio216/value"].Contents) err = a.DigitalWrite("13", 1) require.NoError(t, err) i, err := a.DigitalRead("13") require.NoError(t, err) assert.Equal(t, 1, i) require.ErrorContains(t, a.DigitalWrite("notexist", 1), "'notexist' is not a valid id for a digital pin") require.NoError(t, a.Finalize()) } func TestDigitalPinConcurrency(t *testing.T) { oldProcs := runtime.GOMAXPROCS(0) runtime.GOMAXPROCS(8) defer runtime.GOMAXPROCS(oldProcs) for retry := 0; retry < 20; retry++ { a := NewAdaptor() var wg sync.WaitGroup for i := 0; i < 20; i++ { wg.Add(1) pinAsString := strconv.Itoa(i) go func(pin string) { defer wg.Done() _, _ = a.DigitalPin(pin) }(pinAsString) } wg.Wait() } } func TestSpiDefaultValues(t *testing.T) { a := NewAdaptor() assert.Equal(t, 0, a.SpiDefaultBusNumber()) assert.Equal(t, 0, a.SpiDefaultChipNumber()) assert.Equal(t, 0, a.SpiDefaultMode()) assert.Equal(t, int64(10000000), a.SpiDefaultMaxSpeed()) } func TestI2cDefaultBus(t *testing.T) { a := NewAdaptor() assert.Equal(t, 1, a.DefaultI2cBus()) } func TestI2cFinalizeWithErrors(t *testing.T) { // arrange a := NewAdaptor() a.sys.UseMockSyscall() fs := a.sys.UseMockFilesystem([]string{"/dev/i2c-1"}) require.NoError(t, a.Connect()) con, err := a.GetI2cConnection(0xff, 1) require.NoError(t, err) _, err = con.Write([]byte{0xbf}) require.NoError(t, err) fs.WithCloseError = true // act err = a.Finalize() // assert require.ErrorContains(t, err, "close error") } func Test_translatePWMPin(t *testing.T) { tests := map[string]struct { pin string wantDir string wantChannel int wantErr error }{ "32_pwm0": { pin: "32", wantDir: "/sys/class/pwm/pwmchip0", wantChannel: 0, }, "33_pwm2": { pin: "33", wantDir: "/sys/class/pwm/pwmchip0", wantChannel: 2, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange a := NewAdaptor() // act dir, channel, err := a.translatePWMPin(tc.pin) // assert assert.Equal(t, tc.wantErr, err) assert.Equal(t, tc.wantDir, dir) assert.Equal(t, tc.wantChannel, channel) }) } } ================================================ FILE: platforms/jetson/doc.go ================================================ /* Package jetson contains the Gobot adaptor for the Jetson Nano. For further information refer to Jetson README: https://github.com/hybridgroup/gobot/blob/release/platforms/jetson/README.md */ package jetson // import "gobot.io/x/gobot/v2/platforms/jetson" ================================================ FILE: platforms/jetson/pinmap.go ================================================ package jetson var gpioPins = map[string]int{ "7": 216, "11": 50, "12": 79, "13": 14, "15": 194, "16": 232, "18": 15, "19": 16, "21": 17, "22": 13, "23": 18, "24": 19, "26": 20, "29": 149, "31": 200, "32": 168, "33": 38, "35": 76, "36": 51, "37": 12, "38": 77, "40": 78, } // pin to pwm channel (pwm0, pwm2) var pwmPins = map[string]int{ "32": 0, "33": 2, } ================================================ FILE: platforms/joystick/LICENSE ================================================ Copyright (c) 2014-2023 The Hybrid Group Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: platforms/joystick/README.md ================================================ # Joystick You can use Gobot with many USB joysticks and game controllers. Current configurations included: - Dualshock3 game controller - Dualshock4 game controller - Dualsense game controller - Thrustmaster T-Flight Hotas X Joystick - XBox360 game controller - XBox360 "Rock Band" drum controller - Nintendo Switch Joy-Con controller pair ## How to Install Any platform specific info here... ### macOS ### Linux (Ubuntu and Raspbian) ### Windows ## How to Use Controller configurations are stored in Gobot, but you can also use external file in JSON format. Take a look at the `configs` directory for examples. ## How to Connect Plug your USB joystick or game controller into your USB port. If your device is supported by your operating system, it might prompt you to install some system drivers. For the Dualshock4, you must pair the device with your computers Bluetooth interface first, before running your Gobot program. ## Examples This small program receives joystick and button press events from an PlayStation 3 game controller. ```go package main import ( "fmt" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/joystick" ) func main() { joystickAdaptor := joystick.NewAdaptor("0") stick := joystick.NewDriver(joystickAdaptor, "dualshock3", ) work := func() { // buttons _ = stick.On(joystick.SquarePress, func(data interface{}) { fmt.Println("square_press") }) _ = stick.On(joystick.SquareRelease, func(data interface{}) { fmt.Println("square_release") }) _ = stick.On(joystick.TrianglePress, func(data interface{}) { fmt.Println("triangle_press") }) _ = stick.On(joystick.TriangleRelease, func(data interface{}) { fmt.Println("triangle_release") }) _ = stick.On(joystick.CirclePress, func(data interface{}) { fmt.Println("circle_press") }) _ = stick.On(joystick.CircleRelease, func(data interface{}) { fmt.Println("circle_release") }) _ = stick.On(joystick.XPress, func(data interface{}) { fmt.Println("x_press") }) _ = stick.On(joystick.XRelease, func(data interface{}) { fmt.Println("x_release") }) _ = stick.On(joystick.StartPress, func(data interface{}) { fmt.Println("start_press") }) _ = stick.On(joystick.StartRelease, func(data interface{}) { fmt.Println("start_release") }) _ = stick.On(joystick.SelectPress, func(data interface{}) { fmt.Println("select_press") }) _ = stick.On(joystick.SelectRelease, func(data interface{}) { fmt.Println("select_release") }) // joysticks _ = stick.On(joystick.LeftX, func(data interface{}) { fmt.Println("left_x", data) }) _ = stick.On(joystick.LeftY, func(data interface{}) { fmt.Println("left_y", data) }) _ = stick.On(joystick.RightX, func(data interface{}) { fmt.Println("right_x", data) }) _ = stick.On(joystick.RightY, func(data interface{}) { fmt.Println("right_y", data) }) // triggers _ = stick.On(joystick.R1Press, func(data interface{}) { fmt.Println("R1Press", data) }) _ = stick.On(joystick.R2Press, func(data interface{}) { fmt.Println("R2Press", data) }) _ = stick.On(joystick.L1Press, func(data interface{}) { fmt.Println("L1Press", data) }) _ = stick.On(joystick.L2Press, func(data interface{}) { fmt.Println("L2Press", data) }) } robot := gobot.NewRobot("joystickBot", []gobot.Connection{joystickAdaptor}, []gobot.Device{stick}, work, ) if err := robot.Start(); err != nil { panic(err) } } ``` ## How to Add A New Joystick You can create a file similar to `joystick_dualshock3.go` and submit a pull request with the new configuration so others can use it as well. ================================================ FILE: platforms/joystick/bin/scanner.go ================================================ //go:build utils // +build utils // Do not build by default. // // Joystick scanner // Based on original code from // https://github.com/0xcafed00d/joystick/blob/master/joysticktest/joysticktest.go // Simple program that displays the state of the specified joystick // // go run joysticktest.go 2 // // displays state of joystick id 2 package main import ( "fmt" "os" "strconv" "time" "github.com/0xcafed00d/joystick" "github.com/nsf/termbox-go" ) func printAt(x, y int, s string) { for _, r := range s { termbox.SetCell(x, y, r, termbox.ColorDefault, termbox.ColorDefault) x++ } } func readJoystick(js joystick.Joystick) { jinfo, err := js.Read() if err != nil { printAt(1, 5, "Error: "+err.Error()) return } printAt(1, 5, "Buttons:") for button := 0; button < js.ButtonCount(); button++ { //nolint:gosec // TODO: fix later if jinfo.Buttons&(1< 1 { i, err := strconv.Atoi(os.Args[1]) if err != nil { fmt.Println(err) return } jsid = i } js, jserr := joystick.Open(jsid) if jserr != nil { fmt.Println(jserr) return } err := termbox.Init() if err != nil { panic(err) } defer termbox.Close() eventQueue := make(chan termbox.Event) go func() { for { eventQueue <- termbox.PollEvent() } }() ticker := time.NewTicker(time.Millisecond * 40) for doQuit := false; !doQuit; { select { case ev := <-eventQueue: if ev.Type == termbox.EventKey { if ev.Ch == 'q' { doQuit = true } } if ev.Type == termbox.EventResize { termbox.Flush() } case <-ticker.C: printAt(1, 0, "-- Press 'q' to Exit --") printAt(1, 1, fmt.Sprintf("Joystick Name: %s", js.Name())) //nolint:perfsprint // ok here printAt(1, 2, fmt.Sprintf(" Axis Count: %d", js.AxisCount())) printAt(1, 3, fmt.Sprintf(" Button Count: %d", js.ButtonCount())) readJoystick(js) termbox.Flush() } } } ================================================ FILE: platforms/joystick/configs/dualsense.json ================================================ { "name": "Sony PLAYSTATION(R)5 Controller", "guid": "E7D56FCA-A01F-4A14-B0D0-4FDAFD847E5E", "axis": [ { "name": "left_x", "id": 0 }, { "name": "left_y", "id": 1 }, { "name": "right_x", "id": 2 }, { "name": "right_y", "id": 3 }, { "name": "l2", "id": 4 }, { "name": "r2", "id": 5 } ], "buttons": [ { "name": "x", "id": 0 }, { "name": "circle", "id": 1 }, { "name": "square", "id": 2 }, { "name": "triangle", "id": 3 }, { "name": "l1", "id": 9 }, { "name": "r1", "id": 10 }, { "name": "create", "id": 4 }, { "name": "options", "id": 6 }, { "name": "ps", "id": 5 }, { "name": "up", "id": 11 }, { "name": "down", "id": 12 }, { "name": "left", "id": 13 }, { "name": "right", "id": 14 }, { "name": "trackpad", "id": 15 } ] } ================================================ FILE: platforms/joystick/configs/dualshock3.json ================================================ { "name": "Sony PLAYSTATION(R)3 Controller", "guid": "030000004c0500006802000011010000", "axis": [ { "name": "left_x", "id": 0 }, { "name": "left_y", "id": 1 }, { "name": "l2", "id": 2 }, { "name": "right_x", "id": 3 }, { "name": "right_y", "id": 4 }, { "name": "r2", "id": 5 } ], "buttons": [ { "name": "square", "id": 15 }, { "name": "triangle", "id": 12 }, { "name": "circle", "id": 13 }, { "name": "x", "id": 14 }, { "name": "up", "id": 4 }, { "name": "down", "id": 6 }, { "name": "left", "id": 7 }, { "name": "right", "id": 5 }, { "name": "left_stick", "id": 1 }, { "name": "right_stick", "id": 2 }, { "name": "l1", "id": 10 }, { "name": "l2", "id": 8 }, { "name": "r1", "id": 11 }, { "name": "r2", "id": 9 }, { "name": "start", "id": 3 }, { "name": "select", "id": 0 }, { "name": "home", "id": 16 } ] } ================================================ FILE: platforms/joystick/configs/dualshock4.json ================================================ { "name": "Sony PLAYSTATION(R)4 Controller", "guid": "1234", "axis": [ { "name": "left_x", "id": 0 }, { "name": "left_y", "id": 1 }, { "name": "right_x", "id": 3 }, { "name": "right_y", "id": 4 }, { "name": "l2", "id": 2 }, { "name": "r2", "id": 5 }, { "name": "up", "id": 7 }, { "name": "down", "id": 7 }, { "name": "left", "id": 6 }, { "name": "right", "id": 6 } ], "buttons": [ { "name": "square", "id": 3 }, { "name": "triangle", "id": 2 }, { "name": "circle", "id": 1 }, { "name": "x", "id": 0 }, { "name": "l1", "id": 4 }, { "name": "l2", "id": 6 }, { "name": "r2", "id": 7 }, { "name": "r1", "id": 5 }, { "name": "share", "id": 8 }, { "name": "options", "id": 9 }, { "name": "ps", "id": 10 }, { "name": "left", "id": 11 }, { "name": "right", "id": 12 } ] } ================================================ FILE: platforms/joystick/configs/magicseer1.json ================================================ { "name": "Magicse R1", "guid": "030000004c0", "axis": [ { "name": "left_x", "id": 0 }, { "name": "left_y", "id": 1 }, { "name": "right_x", "id": 2 }, { "name": "right_y", "id": 3 } ], "buttons": [ { "name": "a", "id": 1 }, { "name": "b", "id": 3 }, { "name": "c", "id": 0 }, { "name": "d", "id": 4 }, { "name": "enter", "id": 6 }, { "name": "back", "id": 7 } ], "hats": [ ] } ================================================ FILE: platforms/joystick/configs/shield.json ================================================ { "name": "Nvidia SHIELD Controller", "guid": "30001983600083000100", "hats": [ { "hat": 0, "name": "down", "id": 4 }, { "hat": 0, "name": "up", "id": 1 }, { "hat": 0, "name": "left", "id": 8 }, { "hat": 0, "name": "right", "id": 2 }, { "hat": 0, "name": "released", "id": 0 } ], "axis": [ { "name": "left_x", "id": 0 }, { "name": "left_y", "id": 1 }, { "name": "right_x", "id": 2 }, { "name": "right_y", "id": 3 }, { "name": "rt", "id": 4 }, { "name": "lt", "id": 5 } ], "buttons": [ { "name": "x", "id": 2 }, { "name": "a", "id": 0 }, { "name": "b", "id": 1 }, { "name": "y", "id": 3 }, { "name": "lb", "id": 4 }, { "name": "rb", "id": 5 }, { "name": "back", "id": 14 }, { "name": "start", "id": 7 }, { "name": "home", "id": 15 }, { "name": "right_stick", "id": 9 }, { "name": "left_stick", "id": 8 } ] } ================================================ FILE: platforms/joystick/configs/xbox360_power_a_mini_proex.json ================================================ { "name": "PowerA MINI PROEX Controller", "guid": "30001983600083000100", "hats": [ { "hat": 0, "name": "down", "id": 4 }, { "hat": 0, "name": "up", "id": 1 }, { "hat": 0, "name": "left", "id": 8 }, { "hat": 0, "name": "upLeft", "id": 9 }, { "hat": 0, "name": "downLeft", "id": 12 }, { "hat": 0, "name": "right", "id": 2 }, { "hat": 0, "name": "upRight", "id": 3 }, { "hat": 0, "name": "downRight", "id": 6 }, { "hat": 0, "name": "released", "id": 0 } ], "axis": [ { "name": "left_x", "id": 0 }, { "name": "left_y", "id": 1 }, { "name": "right_x", "id": 3 }, { "name": "right_y", "id": 4 }, { "name": "rt", "id": 5 }, { "name": "lt", "id": 2 } ], "buttons": [ { "name": "x", "id": 2 }, { "name": "a", "id": 0 }, { "name": "b", "id": 1 }, { "name": "y", "id": 3 }, { "name": "lb", "id": 4 }, { "name": "rb", "id": 5 }, { "name": "back", "id": 6 }, { "name": "start", "id": 7 }, { "name": "home", "id": 8 }, { "name": "right_stick", "id": 10 }, { "name": "left_stick", "id": 9 } ] } ================================================ FILE: platforms/joystick/doc.go ================================================ /* Package joystick provides the Gobot adaptor and drivers for game controllers and joysticks. Installing: Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) Example: package main import ( "fmt" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/joystick" ) func main() { joystickAdaptor := joystick.NewAdaptor("0") joystick := joystick.NewDriver(joystickAdaptor, "dualshock3") work := func() { _ = joystick.On(joystick.Event("square_press"), func(data interface{}) { fmt.Println("square_press") }) _ = joystick.On(joystick.Event("square_release"), func(data interface{}) { fmt.Println("square_release") }) _ = joystick.On(joystick.Event("triangle_press"), func(data interface{}) { fmt.Println("triangle_press") }) _ = joystick.On(joystick.Event("triangle_release"), func(data interface{}) { fmt.Println("triangle_release") }) _ = joystick.On(joystick.Event("left_x"), func(data interface{}) { fmt.Println("left_x", data) }) _ = joystick.On(joystick.Event("left_y"), func(data interface{}) { fmt.Println("left_y", data) }) _ = joystick.On(joystick.Event("right_x"), func(data interface{}) { fmt.Println("right_x", data) }) _ = joystick.On(joystick.Event("right_y"), func(data interface{}) { fmt.Println("right_y", data) }) } robot := gobot.NewRobot("joystickBot", []gobot.Connection{joystickAdaptor}, []gobot.Device{joystick}, work, ) if err := robot.Start(); err != nil { panic(err) } } For further information refer to joystick README: https://github.com/hybridgroup/gobot/blob/release/platforms/joystick/README.md */ package joystick // import "gobot.io/x/gobot/v2/platforms/joystick" ================================================ FILE: platforms/joystick/events.go ================================================ package joystick const ( // left X joystick event LeftX = "left_x" // left Y joystick event LeftY = "left_y" // right X joystick event RightX = "right_x" // right Y joystick event RightY = "right_y" // L1 button joystick event L1 = "l1" // L1 button press event L1Press = "l1_press" // L1 button release event L1Release = "l1_release" // L2 joystick event L2 = "l2" // L2 button press event L2Press = "l2_press" // L2 button release event L2Release = "l2_release" // L3 button press event L3Press = "l3_press" // L3 button release event L3Release = "l3_release" // R1 button joystick event R1 = "r1" // R1 button press event R1Press = "r1_press" // R1 button release event R1Release = "r1_release" // R2 joystick event R2 = "r2" // R2 button press event R2Press = "r2_press" // R1 button release event R2Release = "r2_release" // R3 button press event R3Press = "r3_press" // R1 button release event R3Release = "r3_release" // up gamepad press event UpPress = "up_press" // up gamepad release event UpRelease = "up_release" // down gamepad press event DownPress = "down_press" // down gamepad release event DownRelease = "down_release" // left gamepad press event LeftPress = "left_press" // left gamepad release event LeftRelease = "left_release" // right gamepad press event RightPress = "right_press" // right gamepad release event RightRelease = "right_release" // square button press event SquarePress = "square_press" // square button release event SquareRelease = "square_release" // circle button press event CirclePress = "circle_press" // circle button release event CircleRelease = "circle_release" // triangle button press event TrianglePress = "triangle_press" // triangle button release event TriangleRelease = "triangle_release" // X button press event XPress = "x_press" // X button release event XRelease = "x_release" // share button press event SharePress = "share_press" // share button release event ShareRelease = "share_release" // create button press event CreatePress = "create_press" // create button release event CreateRelease = "create_release" // ps button press event PSPress = "ps_press" // ps button release event PSRelease = "ps_release" // trackpad button press event TrackpadPress = "trackpad_press" // trackpad button release event TrackpadRelease = "trackpad_release" // options button press event OptionsPress = "options_press" // options button release event OptionsRelease = "options_release" // home button press event HomePress = "home_press" // home button release event HomeRelease = "home_release" // start button press event StartPress = "start_press" // start button release event StartRelease = "start_release" // select button press event SelectPress = "select_press" // select button release event SelectRelease = "select_release" // rt button press event RTPress = "rt_press" // rt button release event RTRelease = "rt_release" // lt button press event LTPress = "lt_press" // lt button release event LTRelease = "lt_release" // Y button press event YPress = "y_press" // Y button release event YRelease = "y_release" // A button press event APress = "a_press" // A button release event ARelease = "a_release" // B button press event BPress = "b_press" // B button release event BRelease = "b_release" // rb button press event RBPress = "rb_press" // rb button release event RBRelease = "rb_release" // lb button press event LBPress = "lb_press" // lb button release event LBRelease = "lb_release" // back button press event BackPress = "back_press" // back button release event BackRelease = "back_release" // red pad press event RedPress = "red_press" // red pad release event RedRelease = "red_release" // yellow pad press event YellowPress = "yellow_press" // yellow pad release event YellowRelease = "yellow_release" // blue pad press event BluePress = "blue_press" // blue pad release event BlueRelease = "blue_release" // green pad press event GreenPress = "green_press" // green pad release event GreenRelease = "green_release" // pedal press event PedalPress = "pedal_press" // pedal release event PedalRelease = "pedal_release" ) ================================================ FILE: platforms/joystick/joystick_adaptor.go ================================================ package joystick import ( "fmt" "strconv" js "github.com/0xcafed00d/joystick" "gobot.io/x/gobot/v2" ) // Adaptor represents a connection to a joystick type Adaptor struct { name string id string joystick js.Joystick connect func(*Adaptor) error } // NewAdaptor returns a new Joystick Adaptor. // Pass in the ID of the joystick you wish to connect to. func NewAdaptor(id string) *Adaptor { return &Adaptor{ name: gobot.DefaultName("Joystick"), connect: func(j *Adaptor) error { i, err := strconv.Atoi(id) if err != nil { return fmt.Errorf("invalid joystick ID: %v", err) } joy, err := js.Open(i) if err != nil { return fmt.Errorf("no joystick available: %v", err) } j.id = id j.joystick = joy return nil }, } } // Name returns the adaptors name func (j *Adaptor) Name() string { return j.name } // SetName sets the adaptors name func (j *Adaptor) SetName(n string) { j.name = n } // Connect connects to the joystick func (j *Adaptor) Connect() error { return j.connect(j) } // Finalize closes connection to joystick func (j *Adaptor) Finalize() error { j.joystick.Close() return nil } ================================================ FILE: platforms/joystick/joystick_adaptor_test.go ================================================ package joystick import ( "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) var _ gobot.Adaptor = (*Adaptor)(nil) func initTestAdaptor() *Adaptor { a := NewAdaptor("6") a.connect = func(j *Adaptor) error { j.joystick = &testJoystick{} return nil } return a } func TestJoystickAdaptorName(t *testing.T) { a := initTestAdaptor() assert.True(t, strings.HasPrefix(a.Name(), "Joystick")) a.SetName("NewName") assert.Equal(t, "NewName", a.Name()) } func TestAdaptorConnect(t *testing.T) { a := initTestAdaptor() require.NoError(t, a.Connect()) a = NewAdaptor("6") err := a.Connect() require.ErrorContains(t, err, "no joystick available") } func TestAdaptorFinalize(t *testing.T) { a := initTestAdaptor() _ = a.Connect() require.NoError(t, a.Finalize()) } ================================================ FILE: platforms/joystick/joystick_driver.go ================================================ package joystick import ( "encoding/json" "fmt" "os" "time" js "github.com/0xcafed00d/joystick" "gobot.io/x/gobot/v2" ) const ( // Dualshock3 joystick configuration. Dualshock3 = "dualshock3" // Dualshock4 joystick configuration. Dualshock4 = "dualshock4" // Dualsense joystick configuration. Dualsense = "dualsense" // TFlightHotasX flight stick configuration. TFlightHotasX = "tflightHotasX" // Configuration for Xbox 360 controller. Xbox360 = "xbox360" // Xbox360RockBandDrums controller configuration. Xbox360RockBandDrums = "xbox360RockBandDrums" // Configuration for the Xbox One controller. XboxOne = "xboxOne" // Nvidia Shield TV Controller Shield = "shield" // Nintendo Switch Joycon Controller Pair NintendoSwitchPair = "joyconPair" ) // Driver represents a joystick type Driver struct { gobot.Eventer name string interval time.Duration connection gobot.Connection configPath string config joystickConfig buttonState map[int]bool axisState map[int]int halt chan bool } // pair is a JSON representation of name and id type pair struct { Name string `json:"name"` ID int `json:"id"` } // joystickConfig is a JSON representation of configuration values type joystickConfig struct { Name string `json:"name"` GUID string `json:"guid"` Axis []pair `json:"axis"` Buttons []pair `json:"buttons"` } // NewDriver returns a new Driver with a polling interval of // 10 Milliseconds given a Joystick Adaptor and json button configuration // file location. // // Optionally accepts: // // time.Duration: Interval at which the Driver is polled for new information func NewDriver(a *Adaptor, config string, v ...time.Duration) *Driver { d := &Driver{ name: gobot.DefaultName("Joystick"), connection: a, Eventer: gobot.NewEventer(), configPath: config, buttonState: make(map[int]bool), axisState: make(map[int]int), interval: 10 * time.Millisecond, halt: make(chan bool), } if len(v) > 0 { d.interval = v[0] } d.AddEvent("error") return d } // Name returns the Drivers name func (j *Driver) Name() string { return j.name } // SetName sets the Drivers name func (j *Driver) SetName(n string) { j.name = n } // Connection returns the Drivers connection func (j *Driver) Connection() gobot.Connection { return j.connection } // adaptor returns joystick adaptor func (j *Driver) adaptor() *Adaptor { //nolint:forcetypeassert // ok here return j.Connection().(*Adaptor) } // Start and polls the state of the joystick at the given interval. // // Emits the Events: // // Error error - On button error // Events defined in the json button configuration file. // They will have the format: // [button]_press // [button]_release // [axis] func (j *Driver) Start() error { if err := j.initConfig(); err != nil { return err } j.initEvents() go func() { for { state, err := j.adaptor().joystick.Read() if err != nil { j.Publish(j.Event("error"), err) break } // might just be missing a button definition, so keep going if err := j.handleButtons(state); err != nil { j.Publish(j.Event("error"), err) } // might just be missing an axis definition, so keep going if err := j.handleAxes(state); err != nil { j.Publish(j.Event("error"), err) } select { case <-time.After(j.interval): case <-j.halt: return } } }() return nil } func (j *Driver) initConfig() error { switch j.configPath { case Dualshock3: j.config = dualshock3Config case Dualshock4: j.config = dualshock4Config case Dualsense: j.config = dualsenseConfig case TFlightHotasX: j.config = tflightHotasXConfig case Xbox360: j.config = xbox360Config case Xbox360RockBandDrums: j.config = xbox360RockBandDrumsConfig case XboxOne: j.config = xboxOneConfig case Shield: j.config = shieldConfig case NintendoSwitchPair: j.config = joyconPairConfig default: err := j.loadFile() if err != nil { return fmt.Errorf("loadfile error: %w", err) } } return nil } func (j *Driver) initEvents() { for _, value := range j.config.Buttons { j.AddEvent(fmt.Sprintf("%s_press", value.Name)) //nolint:perfsprint // ok here j.AddEvent(fmt.Sprintf("%s_release", value.Name)) //nolint:perfsprint // ok here } for _, value := range j.config.Axis { j.AddEvent(value.Name) } } // Halt stops joystick driver func (j *Driver) Halt() error { j.halt <- true return nil } func (j *Driver) handleButtons(state js.State) error { for button := 0; button < j.adaptor().joystick.ButtonCount(); button++ { //nolint:gosec // TODO: fix later buttonPressed := state.Buttons&(1<= 48 && code <= 57 { event.Key = int(code) } // alphabet if code >= 97 && code <= 122 { event.Key = int(code) } return event } // arrow keys if input[0] == Escape && input[1] == 91 { code = input[2] if code >= 65 && code <= 68 { event.Key = int(code) return event } } return event } // fetches original state, sets up TTY for raw (unbuffered) input func configure() error { state, err := stty("-g") if err != nil { return err } originalState = state // -echo: terminal doesn't echo typed characters back to the terminal // -icanon: terminal doesn't interpret special characters (like backspace) _, err = stty("-echo", "-icanon") return err } // restores the TTY to the original state func restore() error { if _, err := stty("echo"); err != nil { return err } _, err := stty(originalState) return err } func stty(args ...string) (string, error) { cmd := exec.CommandContext(context.Background(), "stty", args...) cmd.Stdin = os.Stdin out, err := cmd.Output() if err != nil { return "", err } return string(out), nil } ================================================ FILE: platforms/keyboard/keyboard_driver.go ================================================ package keyboard import ( "log" "os" "gobot.io/x/gobot/v2" ) const ( // Key board event Key = "key" ) // Driver is gobot software device to the keyboard type Driver struct { gobot.Eventer name string connect func(*Driver) error listen func(*Driver) stdin *os.File } // NewDriver returns a new keyboard Driver. func NewDriver() *Driver { k := &Driver{ name: gobot.DefaultName("Keyboard"), connect: func(k *Driver) error { if err := configure(); err != nil { return err } k.stdin = os.Stdin return nil }, listen: func(k *Driver) { ctrlc := bytes{3} for { var keybuf bytes if _, err := k.stdin.Read(keybuf[0:3]); err != nil { panic(err) } if keybuf == ctrlc { proc, err := os.FindProcess(os.Getpid()) if err != nil { log.Fatal(err) } if err := proc.Signal(os.Interrupt); err != nil { panic(err) } break } k.Publish(Key, Parse(keybuf)) } }, Eventer: gobot.NewEventer(), } k.AddEvent(Key) return k } // Name returns the Driver Name func (k *Driver) Name() string { return k.name } // SetName sets the Driver Name func (k *Driver) SetName(n string) { k.name = n } // Connection returns the Driver Connection func (k *Driver) Connection() gobot.Connection { return nil } // Start initializes keyboard by grabbing key events as they come in and // publishing each as a key event func (k *Driver) Start() error { if err := k.connect(k); err != nil { return err } go k.listen(k) return nil } // Halt stops keyboard driver func (k *Driver) Halt() error { if originalState != "" { return restore() } return nil } ================================================ FILE: platforms/keyboard/keyboard_driver_test.go ================================================ package keyboard import ( "os" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) var _ gobot.Driver = (*Driver)(nil) func initTestKeyboardDriver() *Driver { d := NewDriver() d.connect = func(k *Driver) error { k.stdin = &os.File{} return nil } d.listen = func(k *Driver) {} return d } func TestKeyboardDriver(t *testing.T) { d := initTestKeyboardDriver() assert.Equal(t, (gobot.Connection)(nil), d.Connection()) } func TestKeyboardDriverName(t *testing.T) { d := initTestKeyboardDriver() assert.True(t, strings.HasPrefix(d.Name(), "Keyboard")) d.SetName("NewName") assert.Equal(t, "NewName", d.Name()) } func TestKeyboardDriverStart(t *testing.T) { d := initTestKeyboardDriver() require.NoError(t, d.Start()) } func TestKeyboardDriverHalt(t *testing.T) { d := initTestKeyboardDriver() require.NoError(t, d.Halt()) } ================================================ FILE: platforms/keyboard/keyboard_test.go ================================================ package keyboard import ( "testing" "github.com/stretchr/testify/assert" ) func TestParseSpace(t *testing.T) { assert.Equal(t, Spacebar, Parse(bytes{32, 0, 0}).Key) } func TestParseEscape(t *testing.T) { assert.Equal(t, Escape, Parse(bytes{27, 0, 0}).Key) } func TestParseHyphen(t *testing.T) { assert.Equal(t, Hyphen, Parse(bytes{45, 0, 0}).Key) } func TestParseAsterisk(t *testing.T) { assert.Equal(t, Asterisk, Parse(bytes{42, 0, 0}).Key) } func TestParsePlus(t *testing.T) { assert.Equal(t, Plus, Parse(bytes{43, 0, 0}).Key) } func TestParseSlash(t *testing.T) { assert.Equal(t, Slash, Parse(bytes{47, 0, 0}).Key) } func TestParseDot(t *testing.T) { assert.Equal(t, Dot, Parse(bytes{46, 0, 0}).Key) } func TestParseNotEscape(t *testing.T) { assert.NotEqual(t, Escape, Parse(bytes{27, 91, 65}).Key) } func TestParseNumberKeys(t *testing.T) { assert.Equal(t, 48, Parse(bytes{48, 0, 0}).Key) assert.Equal(t, 50, Parse(bytes{50, 0, 0}).Key) assert.Equal(t, 57, Parse(bytes{57, 0, 0}).Key) } func TestParseAlphaKeys(t *testing.T) { assert.Equal(t, 97, Parse(bytes{97, 0, 0}).Key) assert.Equal(t, 101, Parse(bytes{101, 0, 0}).Key) assert.Equal(t, 122, Parse(bytes{122, 0, 0}).Key) } func TestParseNotAlphaKeys(t *testing.T) { assert.NotEqual(t, 132, Parse(bytes{132, 0, 0}).Key) } func TestParseArrowKeys(t *testing.T) { assert.Equal(t, 65, Parse(bytes{27, 91, 65}).Key) assert.Equal(t, 66, Parse(bytes{27, 91, 66}).Key) assert.Equal(t, 67, Parse(bytes{27, 91, 67}).Key) assert.Equal(t, 68, Parse(bytes{27, 91, 68}).Key) } func TestParseNotArrowKeys(t *testing.T) { assert.NotEqual(t, Escape, Parse(bytes{27, 91, 65}).Key) assert.NotEqual(t, 70, Parse(bytes{27, 91, 70}).Key) } ================================================ FILE: platforms/leap/LICENSE ================================================ Copyright (c) 2013-2018 The Hybrid Group Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: platforms/leap/README.md ================================================ # Leap The Leap Motion is a user-interface device that tracks the user's hand motions, and translates them into events that can control robots and physical computing hardware. For more info about the Leap Motion platform click [Leap Motion](https://www.leapmotion.com/) ## How to Install Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) First install the [Leap Motion Software](https://www.leapmotion.com/setup) ## How to Use ```go package main import ( "fmt" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/leap" ) func main() { leapMotionAdaptor := leap.NewAdaptor("127.0.0.1:6437") l := leap.NewDriver(leapMotionAdaptor) work := func() { l.On(l.Event("message"), func(data interface{}) { fmt.Println(data.(leap.Frame)) }) } robot := gobot.NewRobot("leapBot", []gobot.Connection{leapMotionAdaptor}, []gobot.Device{l}, work, ) if err := robot.Start(); err != nil { panic(err) } } ``` ## How To Connect ### OSX This driver works out of the box with the vanilla installation of the Leap Motion Software that you get in their [Setup Guide](https://www.leapmotion.com/setup). The main steps are: * Run Leap Motion.app to open a websocket connection in port 6437. * Connect your Computer and Leap Motion Controller. * Connect to the device via Gobot. ### Ubuntu The Linux download of the Leap Motion software can be obtained from [Leap Motion Dev Center](https://developer.leapmotion.com/downloads) (requires free signup). The main steps are: * Run the leapd daemon, to open a websocket connection in port 6437. * Connect your computer and the Leap Motion controller * Connect to the device via Gobot ================================================ FILE: platforms/leap/doc.go ================================================ /* Package leap provides the Gobot adaptor and driver for the Leap Motion. Installing: Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) Install the [Leap Motion Software](https://www.leapmotion.com/setup). Example: package main import ( "fmt" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/leap" ) func main() { leapMotionAdaptor := leap.NewAdaptor("127.0.0.1:6437") l := leap.NewDriver(leapMotionAdaptor) work := func() { l.On(l.Event("message"), func(data interface{}) { fmt.Println(data.(leap.Frame)) }) } robot := gobot.NewRobot("leapBot", []gobot.Connection{leapMotionAdaptor}, []gobot.Device{l}, work, ) if err := robot.Start(); err != nil { panic(err) } } For more information refer to the leap README: https://github.com/hybridgroup/gobot/blob/release/platforms/leap/README.md */ package leap // import "gobot.io/x/gobot/v2/platforms/leap" ================================================ FILE: platforms/leap/leap_motion_adaptor.go ================================================ package leap import ( "io" "golang.org/x/net/websocket" "gobot.io/x/gobot/v2" ) // Adaptor is the Gobot Adaptor connection to the Leap Motion type Adaptor struct { name string port string ws io.ReadWriteCloser connect func(string) (io.ReadWriteCloser, error) } // NewAdaptor creates a new leap motion adaptor using specified port, // which is this case is the host IP or name of the Leap Motion daemon func NewAdaptor(port string) *Adaptor { return &Adaptor{ name: gobot.DefaultName("LeapMotion"), port: port, connect: func(host string) (io.ReadWriteCloser, error) { return websocket.Dial("ws://"+host+"/v6.json", "", "http://"+host) }, } } // Name returns the Adaptor Name func (l *Adaptor) Name() string { return l.name } // SetName sets the Adaptor Name func (l *Adaptor) SetName(n string) { l.name = n } // Port returns the Adaptor Port which is this case is the host IP or name func (l *Adaptor) Port() string { return l.port } // Connect returns true if connection to leap motion is established successfully func (l *Adaptor) Connect() error { ws, err := l.connect(l.Port()) if err != nil { return err } l.ws = ws return nil } // Finalize ends connection to leap motion func (l *Adaptor) Finalize() error { return nil } ================================================ FILE: platforms/leap/leap_motion_adaptor_test.go ================================================ package leap import ( "errors" "io" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) var _ gobot.Adaptor = (*Adaptor)(nil) func initTestLeapMotionAdaptor() *Adaptor { a := NewAdaptor("") a.connect = func(port string) (io.ReadWriteCloser, error) { return nil, nil } //nolint:nilnil // ok for test return a } func TestLeapMotionAdaptor(t *testing.T) { a := NewAdaptor("127.0.0.1") assert.Equal(t, "127.0.0.1", a.Port()) } func TestLeapMotionAdaptorName(t *testing.T) { a := NewAdaptor("127.0.0.1") assert.True(t, strings.HasPrefix(a.Name(), "Leap")) a.SetName("NewName") assert.Equal(t, "NewName", a.Name()) } func TestLeapMotionAdaptorConnect(t *testing.T) { a := initTestLeapMotionAdaptor() require.NoError(t, a.Connect()) a.connect = func(port string) (io.ReadWriteCloser, error) { return nil, errors.New("connection error") } require.ErrorContains(t, a.Connect(), "connection error") } func TestLeapMotionAdaptorFinalize(t *testing.T) { a := initTestLeapMotionAdaptor() require.NoError(t, a.Finalize()) } ================================================ FILE: platforms/leap/leap_motion_driver.go ================================================ package leap import ( "encoding/json" "io" "log" "golang.org/x/net/websocket" "gobot.io/x/gobot/v2" ) const ( // MessageEvent event MessageEvent = "message" // HandEvent event HandEvent = "hand" // GestureEvent event GestureEvent = "gesture" ) // Driver the Gobot software device to the Leap Motion type Driver struct { gobot.Eventer name string connection gobot.Connection receive func(ws io.ReadWriteCloser, msg *[]byte) } // NewDriver creates a new leap motion driver // // Adds the following events: // // "message" - Gets triggered when receiving a message from leap motion // "hand" - Gets triggered per-message when leap motion detects a hand // "gesture" - Gets triggered per-message when leap motion detects a gesture func NewDriver(a *Adaptor) *Driver { l := &Driver{ name: gobot.DefaultName("LeapMotion"), connection: a, Eventer: gobot.NewEventer(), receive: func(ws io.ReadWriteCloser, msg *[]byte) { //nolint:forcetypeassert // ok here if err := websocket.Message.Receive(ws.(*websocket.Conn), msg); err != nil { panic(err) } }, } l.AddEvent(MessageEvent) l.AddEvent(HandEvent) l.AddEvent(GestureEvent) return l } // Name returns the Driver Name func (l *Driver) Name() string { return l.name } // SetName sets the Driver Name func (l *Driver) SetName(n string) { l.name = n } // Connection returns the Driver's Connection func (l *Driver) Connection() gobot.Connection { return l.connection } // adaptor returns leap motion adaptor func (l *Driver) adaptor() *Adaptor { //nolint:forcetypeassert // ok here return l.Connection().(*Adaptor) } func enableFeature(l *Driver, feature string) error { command := map[string]bool{feature: true} b, err := json.Marshal(command) if err != nil { return err } if _, err = l.adaptor().ws.Write(b); err != nil { return err } return nil } // Start inits leap motion driver by enabling gestures // and listening from incoming messages. // // Publishes the following events: // // "message" - Emits Frame on new message received from Leap. // "hand" - Emits Hand when detected in message from Leap. // "gesture" - Emits Gesture when detected in message from Leap. func (l *Driver) Start() error { if err := enableFeature(l, "enableGestures"); err != nil { return err } if err := enableFeature(l, "background"); err != nil { return err } go func() { var msg []byte var frame Frame var err error for { l.receive(l.adaptor().ws, &msg) frame, err = l.ParseFrame(msg) if err != nil { log.Println(err) continue } l.Publish(MessageEvent, frame) for _, hand := range frame.Hands { l.Publish(HandEvent, hand) } for _, gesture := range frame.Gestures { l.Publish(GestureEvent, gesture) } } }() return nil } // Halt returns nil if driver is halted successfully func (l *Driver) Halt() error { return nil } ================================================ FILE: platforms/leap/leap_motion_driver_test.go ================================================ package leap import ( "errors" "io" "os" "strings" "sync" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) var _ gobot.Driver = (*Driver)(nil) type NullReadWriteCloser struct { mtx sync.Mutex writeError error } func (n *NullReadWriteCloser) WriteError(e error) { n.mtx.Lock() defer n.mtx.Unlock() n.writeError = e } func (n *NullReadWriteCloser) Write(p []byte) (int, error) { n.mtx.Lock() defer n.mtx.Unlock() return len(p), n.writeError } func (n *NullReadWriteCloser) Read(b []byte) (int, error) { return len(b), nil } func (n *NullReadWriteCloser) Close() error { return nil } func initTestLeapMotionDriver() (*Driver, *NullReadWriteCloser) { a := NewAdaptor("") rwc := &NullReadWriteCloser{} a.connect = func(port string) (io.ReadWriteCloser, error) { return rwc, nil } _ = a.Connect() d := NewDriver(a) d.receive = func(ws io.ReadWriteCloser, buf *[]byte) { file, _ := os.ReadFile("./test/support/example_frame.json") copy(*buf, file) } return d, rwc } func TestLeapMotionDriver(t *testing.T) { d, _ := initTestLeapMotionDriver() assert.NotNil(t, d.Connection()) } func TestLeapMotionDriverName(t *testing.T) { d, _ := initTestLeapMotionDriver() assert.True(t, strings.HasPrefix(d.Name(), "Leap")) d.SetName("NewName") assert.Equal(t, "NewName", d.Name()) } func TestLeapMotionDriverStart(t *testing.T) { d, _ := initTestLeapMotionDriver() require.NoError(t, d.Start()) d2, rwc := initTestLeapMotionDriver() e := errors.New("write error") rwc.WriteError(e) assert.Equal(t, e, d2.Start()) } func TestLeapMotionDriverHalt(t *testing.T) { d, _ := initTestLeapMotionDriver() require.NoError(t, d.Halt()) } func TestLeapMotionDriverParser(t *testing.T) { d, _ := initTestLeapMotionDriver() file, _ := os.ReadFile("./test/support/example_frame.json") parsedFrame, _ := d.ParseFrame(file) if parsedFrame.Hands == nil || parsedFrame.Pointables == nil || parsedFrame.Gestures == nil { require.Fail(t, "ParseFrame incorrectly parsed frame") } assert.Equal(t, uint64(134211791358), parsedFrame.Timestamp) assert.InDelta(t, 247.410, parsedFrame.Hands[0].X(), 0.0) assert.InDelta(t, 275.868, parsedFrame.Hands[0].Y(), 0.0) assert.InDelta(t, 132.843, parsedFrame.Hands[0].Z(), 0.0) assert.InDelta(t, 214.293, parsedFrame.Pointables[0].BTipPosition[0], 0.0) assert.InDelta(t, 213.865, parsedFrame.Pointables[0].BTipPosition[1], 0.0) assert.InDelta(t, 95.0224, parsedFrame.Pointables[0].BTipPosition[2], 0.0) assert.InDelta(t, -0.468069, parsedFrame.Pointables[0].Bases[0][0][0], 0.0) assert.InDelta(t, 0.807844, parsedFrame.Pointables[0].Bases[0][0][1], 0.0) assert.InDelta(t, -0.358190, parsedFrame.Pointables[0].Bases[0][0][2], 0.0) assert.InDelta(t, 19.7871, parsedFrame.Pointables[0].Width, 0.0) } ================================================ FILE: platforms/leap/parser.go ================================================ package leap import ( "encoding/json" ) // Gesture is a Leap Motion gesture that has been detected type Gesture struct { Center []float64 `json:"center"` Direction []float64 `json:"direction"` Duration int `json:"duration"` HandIDs []int `json:"handIds"` ID int `json:"id"` Normal []float64 `json:"normal"` PointableIDs []int `json:"pointableIds"` Position []float64 `json:"position"` Progress float64 `json:"progress"` Radius float64 `json:"radius"` Speed float64 `json:"speed"` StartPosition []float64 `json:"StartPosition"` State string `json:"state"` Type string `json:"type"` } // Hand is a Leap Motion hand that has been detected type Hand struct { ArmBasis [][]float64 `json:"armBasis"` ArmWidth float64 `json:"armWidth"` Confidence float64 `json:"confidence"` Direction []float64 `json:"direction"` Elbow []float64 `json:"elbow"` GrabStrength float64 `json:"grabStrength"` ID int `json:"id"` PalmNormal []float64 `json:"palmNormal"` PalmPosition []float64 `json:"PalmPosition"` PalmVelocity []float64 `json:"PalmVelocity"` PinchStrength float64 `json:"PinchStrength"` R [][]float64 `json:"r"` S float64 `json:"s"` SphereCenter []float64 `json:"sphereCenter"` SphereRadius float64 `json:"sphereRadius"` StabilizedPalmPosition []float64 `json:"stabilizedPalmPosition"` T []float64 `json:"t"` TimeVisible float64 `json:"TimeVisible"` Type string `json:"type"` Wrist []float64 `json:"wrist"` } // Pointable is a Leap Motion pointing motion that has been detected type Pointable struct { Bases [][][]float64 `json:"bases"` BTipPosition []float64 `json:"btipPosition"` CarpPosition []float64 `json:"carpPosition"` DipPosition []float64 `json:"dipPosition"` Direction []float64 `json:"direction"` Extended bool `json:"extended"` HandID int `json:"handId"` ID int `json:"id"` Length float64 `json:"length"` MCPPosition []float64 `json:"mcpPosition"` PIPPosition []float64 `json:"pipPosition"` StabilizedTipPosition []float64 `json:"stabilizedTipPosition"` TimeVisible float64 `json:"timeVisible"` TipPosition []float64 `json:"tipPosition"` TipVelocity []float64 `json:"tipVelocity"` Tool bool `json:"tool"` TouchDistance float64 `json:"touchDistance"` TouchZone string `json:"touchZone"` Type int `json:"type"` Width float64 `json:"width"` } // InteractionBox is the area within which the gestural interaction has been detected type InteractionBox struct { Center []float64 `json:"center"` Size []float64 `json:"size"` } // Frame is the base representation returned that holds every other objects type Frame struct { CurrentFrameRate float64 `json:"currentFrameRate"` Gestures []Gesture `json:"gestures"` Hands []Hand `json:"hands"` ID int `json:"id"` InteractionBox InteractionBox `json:"interactionBox"` Pointables []Pointable `json:"pointables"` R [][]float64 `json:"r"` S float64 `json:"s"` T []float64 `json:"t"` Timestamp uint64 `json:"timestamp"` } // X returns hand x value func (h *Hand) X() float64 { return h.PalmPosition[0] } // Y returns hand y value func (h *Hand) Y() float64 { return h.PalmPosition[1] } // Z returns hand z value func (h *Hand) Z() float64 { return h.PalmPosition[2] } // ParseFrame converts json data to a Frame func (l *Driver) ParseFrame(data []byte) (Frame, error) { var frame Frame err := json.Unmarshal(data, &frame) return frame, err } ================================================ FILE: platforms/leap/test/support/example_frame.json ================================================ { "currentFrameRate": 110.583, "devices": [], "gestures": [ { "direction": [ 0.721478, -0.510801, 0.467495 ], "duration": 108349, "handIds": [ 129 ], "id": 1, "pointableIds": [ 1290 ], "position": [ 228.679, 214.101, 101.574 ], "progress": 1.00000, "state": "stop", "type": "keyTap" } ], "hands": [ { "armBasis": [ [ 0.642307, 0.418027, 0.642414 ], [ -0.760890, 0.448533, 0.468898 ], [ -0.0921319, -0.789982, 0.606168 ] ], "armWidth": 62.2635, "confidence": 0.152371, "direction": [ 0.221251, -0.0617914, -0.973257 ], "elbow": [ 212.001, 79.2408, 343.710 ], "grabStrength": 0.00000, "id": 129, "palmNormal": [ 0.813532, -0.538649, 0.219139 ], "palmPosition": [ 247.410, 275.868, 132.843 ], "palmVelocity": [ -0.713996, -23.6569, -13.8691 ], "palmWidth": 88.9102, "pinchStrength": 0.00000, "r": [ [ 0.192921, 0.960078, -0.202565 ], [ -0.745728, 0.00929180, -0.666186 ], [ -0.637708, 0.279579, 0.717750 ] ], "s": 1.30419, "sphereCenter": [ 287.160, 297.142, 100.094 ], "sphereRadius": 67.0665, "stabilizedPalmPosition": [ 247.480, 276.296, 133.123 ], "t": [ 61.7977, 116.515, 56.4642 ], "timeVisible": 1.87085, "type": "right", "wrist": [ 236.308, 287.660, 183.786 ] } ], "id": 641123, "interactionBox": { "center": [ 0.00000, 189.367, 0.00000 ], "size": [ 222.740, 222.740, 139.896 ] }, "pointables": [ { "bases": [ [ [ -0.468069, 0.807844, -0.358190 ], [ -0.882976, -0.411231, 0.226369 ], [ 0.0355723, 0.422230, 0.905791 ] ], [ [ -0.466451, 0.822774, -0.324757 ], [ -0.870335, -0.361355, 0.334573 ], [ 0.157925, 0.438709, 0.884643 ] ], [ [ -0.466451, 0.822774, -0.324757 ], [ -0.884402, -0.440445, 0.154403 ], [ -0.0159988, 0.359238, 0.933109 ] ], [ [ -0.466451, 0.822774, -0.324757 ], [ -0.817784, -0.261199, 0.512840 ], [ 0.337125, 0.504796, 0.794687 ] ] ], "btipPosition": [ 214.293, 213.865, 95.0224 ], "carpPosition": [ 229.172, 258.776, 187.433 ], "dipPosition": [ 222.002, 225.409, 113.196 ], "direction": [ 0.0159988, -0.359238, -0.933109 ], "extended": true, "handId": 129, "id": 1290, "length": 50.9251, "mcpPosition": [ 229.172, 258.776, 187.433 ], "pipPosition": [ 221.469, 237.377, 144.284 ], "stabilizedTipPosition": [ 220.428, 215.841, 99.4813 ], "timeVisible": 1.87085, "tipPosition": [ 212.427, 218.656, 99.7341 ], "tipVelocity": [ -324.525, 55.5317, -41.1663 ], "tool": false, "touchDistance": 0.341002, "touchZone": "hovering", "type": 0, "width": 19.7871 }, { "bases": [ [ [ 0.654255, 0.750454, 0.0936476 ], [ -0.683587, 0.639792, -0.351248 ], [ -0.323510, 0.165789, 0.931588 ] ], [ [ 0.641810, 0.756085, 0.128125 ], [ -0.742571, 0.654463, -0.142363 ], [ -0.191492, -0.00377221, 0.981487 ] ], [ [ 0.641810, 0.756085, 0.128125 ], [ -0.726482, 0.652969, -0.214139 ], [ -0.245569, 0.0443555, 0.968364 ] ], [ [ 0.641810, 0.756085, 0.128125 ], [ -0.709564, 0.648876, -0.274734 ], [ -0.290860, 0.0854138, 0.952946 ] ] ], "btipPosition": [ 269.006, 271.529, 17.2009 ], "carpPosition": [ 225.768, 285.455, 171.343 ], "dipPosition": [ 263.665, 273.097, 34.6993 ], "direction": [ 0.245569, -0.0443555, -0.968364 ], "extended": true, "handId": 129, "id": 1292, "length": 65.4748, "mcpPosition": [ 247.823, 274.152, 107.833 ], "pipPosition": [ 256.842, 274.330, 61.6066 ], "stabilizedTipPosition": [ 268.409, 272.318, 21.5696 ], "timeVisible": 1.87085, "tipPosition": [ 268.718, 271.794, 21.5136 ], "tipVelocity": [ -13.9732, 6.53920, -19.5770 ], "tool": false, "touchDistance": 0.332816, "touchZone": "hovering", "type": 2, "width": 18.5630 }, { "bases": [ [ [ 0.649174, 0.716291, 0.255928 ], [ -0.645061, 0.696732, -0.313783 ], [ -0.403074, 0.0386109, 0.914353 ] ], [ [ 0.610655, 0.716881, 0.336426 ], [ -0.767227, 0.640801, 0.0271437 ], [ -0.196123, -0.274690, 0.941319 ] ], [ [ 0.610655, 0.716881, 0.336426 ], [ -0.728617, 0.675044, -0.115904 ], [ -0.310191, -0.174348, 0.934550 ] ], [ [ 0.610655, 0.716881, 0.336426 ], [ -0.679596, 0.692496, -0.242072 ], [ -0.406510, -0.0808113, 0.910065 ] ] ], "btipPosition": [ 282.293, 310.673, 32.4311 ], "carpPosition": [ 233.241, 294.849, 171.406 ], "dipPosition": [ 274.872, 309.198, 49.0461 ], "direction": [ 0.310191, 0.174348, -0.934550 ], "extended": true, "handId": 129, "id": 1293, "length": 62.9558, "mcpPosition": [ 257.913, 292.486, 115.440 ], "pipPosition": [ 266.475, 304.478, 74.3433 ], "stabilizedTipPosition": [ 281.546, 310.434, 36.7157 ], "timeVisible": 1.87085, "tipPosition": [ 281.024, 309.986, 36.2968 ], "tipVelocity": [ -49.1356, 23.1718, -14.1464 ], "tool": false, "touchDistance": 0.332567, "touchZone": "hovering", "type": 3, "width": 17.6638 }, { "bases": [ [ [ 0.695759, 0.590913, 0.408339 ], [ -0.569298, 0.800316, -0.188135 ], [ -0.437971, -0.101569, 0.893233 ] ], [ [ 0.555629, 0.543209, 0.629445 ], [ -0.762608, 0.634559, 0.125553 ], [ -0.331219, -0.549780, 0.766835 ] ], [ [ 0.555629, 0.543209, 0.629445 ], [ -0.707544, 0.706513, 0.0148494 ], [ -0.436645, -0.453610, 0.776903 ] ], [ [ 0.555629, 0.543209, 0.629445 ], [ -0.645129, 0.759246, -0.0857538 ], [ -0.524486, -0.358426, 0.772299 ] ] ], "btipPosition": [ 298.360, 340.270, 71.0701 ], "carpPosition": [ 244.922, 300.813, 176.031 ], "dipPosition": [ 289.526, 334.233, 84.0778 ], "direction": [ 0.436645, 0.453610, -0.776904 ], "extended": true, "handId": 129, "id": 1294, "length": 49.3562, "mcpPosition": [ 269.737, 306.568, 125.421 ], "pipPosition": [ 281.181, 325.564, 98.9257 ], "stabilizedTipPosition": [ 297.824, 337.184, 73.7178 ], "timeVisible": 1.87085, "tipPosition": [ 295.463, 338.639, 73.5436 ], "tipVelocity": [ -67.9258, 44.5899, -9.70583 ], "tool": false, "touchDistance": 0.332281, "touchZone": "hovering", "type": 4, "width": 15.6904 }, { "bases": [ [ [ 0.567299, 0.817958, -0.0954824 ], [ -0.785572, 0.502726, -0.360755 ], [ -0.247081, 0.279664, 0.927760 ] ], [ [ 0.556741, 0.828691, -0.0575341 ], [ -0.461401, 0.250903, -0.850974 ], [ -0.690760, 0.500319, 0.522046 ] ], [ [ 0.556741, 0.828691, -0.0575341 ], [ 0.184936, -0.191172, -0.963977 ], [ -0.809838, 0.526046, -0.259688 ] ], [ [ 0.556741, 0.828691, -0.0575341 ], [ 0.450238, -0.359238, -0.817456 ], [ -0.698087, 0.429207, -0.573111 ] ] ], "btipPosition": [ 297.722, 214.346, 100.704 ], "carpPosition": [ 220.180, 275.044, 173.613 ], "dipPosition": [ 286.067, 221.511, 91.1361 ], "direction": [ 0.809838, -0.526046, 0.259688 ], "extended": false, "handId": 129, "id": 1291, "length": 57.4633, "mcpPosition": [ 237.942, 254.939, 106.918 ], "pipPosition": [ 266.941, 233.936, 85.0028 ], "stabilizedTipPosition": [ 294.484, 215.800, 98.6516 ], "timeVisible": 1.87085, "tipPosition": [ 294.960, 216.076, 98.9796 ], "tipVelocity": [ 77.7159, 38.2101, -21.6539 ], "tool": false, "touchDistance": 0.340420, "touchZone": "none", "type": 1, "width": 18.9007 } ], "r": [ [ 0.192921, 0.960078, -0.202565 ], [ -0.745728, 0.00929180, -0.666186 ], [ -0.637708, 0.279579, 0.717750 ] ], "s": 1.30419, "t": [ 61.7977, 116.515, 56.4642 ], "timestamp": 134211791358 } ================================================ FILE: platforms/mavlink/LICENSE ================================================ Copyright (c) 2013-2018 The Hybrid Group Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: platforms/mavlink/README.md ================================================ # Mavlink For information on the MAVlink communication protocol click [here](https://mavlink.io/). This package supports Mavlink over serial (such as a [SiK modem](http://ardupilot.org/copter/docs/common-sik-telemetry-radio.html)) and Mavlink over UDP (such as via [mavproxy](https://github.com/ArduPilot/MAVProxy)). Serial is useful for point to point links, and UDP is useful for where you have multiple simultaneous clients such as the robot and [QGroundControl](http://qgroundcontrol.com/). As at 2018-04, this package supports Mavlink 1.0 only. If the robot doesn't receiving data then check that the other devices are configured to send version 1.0 frames. For Mavlink 2.0 please refer to [gomavlib](https://github.com/bluenviron/gomavlib). ## How to Install Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) ## How to Use ```go package main import ( "fmt" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/mavlink" common "gobot.io/x/gobot/v2/platforms/mavlink/common" ) func main() { adaptor := mavlink.NewAdaptor("/dev/ttyACM0") iris := mavlink.NewDriver(adaptor) work := func() { iris.Once(iris.Event("packet"), func(data interface{}) { packet := data.(*common.MAVLinkPacket) dataStream := common.NewRequestDataStream(100, packet.SystemID, packet.ComponentID, 4, 1, ) iris.SendPacket(common.CraftMAVLinkPacket(packet.SystemID, packet.ComponentID, dataStream, )) }) iris.On(iris.Event("message"), func(data interface{}) { if data.(common.MAVLinkMessage).Id() == 30 { message := data.(*common.Attitude) fmt.Println("Attitude") fmt.Println("TIME_BOOT_MS", message.TIME_BOOT_MS) fmt.Println("ROLL", message.ROLL) fmt.Println("PITCH", message.PITCH) fmt.Println("YAW", message.YAW) fmt.Println("ROLLSPEED", message.ROLLSPEED) fmt.Println("PITCHSPEED", message.PITCHSPEED) fmt.Println("YAWSPEED", message.YAWSPEED) fmt.Println("") } }) } robot := gobot.NewRobot("mavBot", []gobot.Connection{adaptor}, []gobot.Device{iris}, work, ) if err := robot.Start(); err != nil { panic(err) } } ``` ## How to use: UDP ``` go adaptor := mavlink.NewUDPAdaptor(":14550") ``` To test, install Mavproxy and set it up to listen on serial and repeat over UDP: `$ mavproxy.py --out=udpbcast:192.168.0.255:14550` Change the address to the broadcast address of your subnet. ================================================ FILE: platforms/mavlink/common/common.go ================================================ //nolint:dupl,gocritic,lll // seems to be useful here package mavlink // // MAVLink comm protocol generated from common.xml // http://qgroundcontrol.org/mavlink/ // import ( "bytes" "encoding/binary" "fmt" ) var messages = map[uint8]MAVLinkMessage{ 0: &Heartbeat{}, 1: &SysStatus{}, 2: &SystemTime{}, 4: &Ping{}, 5: &ChangeOperatorControl{}, 6: &ChangeOperatorControlAck{}, 7: &AuthKey{}, 11: &SetMode{}, 20: &ParamRequestRead{}, 21: &ParamRequestList{}, 22: &ParamValue{}, 23: &ParamSet{}, 24: &GpsRawInt{}, 25: &GpsStatus{}, 26: &ScaledImu{}, 27: &RawImu{}, 28: &RawPressure{}, 29: &ScaledPressure{}, 30: &Attitude{}, 31: &AttitudeQuaternion{}, 32: &LocalPositionNed{}, 33: &GlobalPositionInt{}, 34: &RcChannelsScaled{}, 35: &RcChannelsRaw{}, 36: &ServoOutputRaw{}, 37: &MissionRequestPartialList{}, 38: &MissionWritePartialList{}, 39: &MissionItem{}, 40: &MissionRequest{}, 41: &MissionSetCurrent{}, 42: &MissionCurrent{}, 43: &MissionRequestList{}, 44: &MissionCount{}, 45: &MissionClearAll{}, 46: &MissionItemReached{}, 47: &MissionAck{}, 48: &SetGpsGlobalOrigin{}, 49: &GpsGlobalOrigin{}, 50: &SetLocalPositionSetpoint{}, 51: &LocalPositionSetpoint{}, 52: &GlobalPositionSetpointInt{}, 53: &SetGlobalPositionSetpointInt{}, 54: &SafetySetAllowedArea{}, 55: &SafetyAllowedArea{}, 56: &SetRollPitchYawThrust{}, 57: &SetRollPitchYawSpeedThrust{}, 58: &RollPitchYawThrustSetpoint{}, 59: &RollPitchYawSpeedThrustSetpoint{}, 60: &SetQuadMotorsSetpoint{}, 61: &SetQuadSwarmRollPitchYawThrust{}, 62: &NavControllerOutput{}, 63: &SetQuadSwarmLedRollPitchYawThrust{}, 64: &StateCorrection{}, 65: &RcChannels{}, 66: &RequestDataStream{}, 67: &DataStream{}, 69: &ManualControl{}, 70: &RcChannelsOverride{}, 74: &VfrHud{}, 76: &CommandLong{}, 77: &CommandAck{}, 80: &RollPitchYawRatesThrustSetpoint{}, 81: &ManualSetpoint{}, 82: &AttitudeSetpointExternal{}, 83: &LocalNedPositionSetpointExternal{}, 84: &GlobalPositionSetpointExternalInt{}, 89: &LocalPositionNedSystemGlobalOffset{}, 90: &HilState{}, 91: &HilControls{}, 92: &HilRcInputsRaw{}, 100: &OpticalFlow{}, 101: &GlobalVisionPositionEstimate{}, 102: &VisionPositionEstimate{}, 103: &VisionSpeedEstimate{}, 104: &ViconPositionEstimate{}, 105: &HighresImu{}, 106: &OmnidirectionalFlow{}, 107: &HilSensor{}, 108: &SimState{}, 109: &RadioStatus{}, 110: &FileTransferStart{}, 111: &FileTransferDirList{}, 112: &FileTransferRes{}, 113: &HilGps{}, 114: &HilOpticalFlow{}, 115: &HilStateQuaternion{}, 116: &ScaledImu2{}, 117: &LogRequestList{}, 118: &LogEntry{}, 119: &LogRequestData{}, 120: &LogData{}, 121: &LogErase{}, 122: &LogRequestEnd{}, 123: &GpsInjectData{}, 124: &Gps2Raw{}, 125: &PowerStatus{}, 126: &SerialControl{}, 127: &GpsRtk{}, 128: &Gps2Rtk{}, 130: &DataTransmissionHandshake{}, 131: &EncapsulatedData{}, 132: &DistanceSensor{}, 133: &TerrainRequest{}, 134: &TerrainData{}, 135: &TerrainCheck{}, 136: &TerrainReport{}, 147: &BatteryStatus{}, 148: &Setpoint8Dof{}, 149: &Setpoint6Dof{}, 249: &MemoryVect{}, 250: &DebugVect{}, 251: &NamedValueFloat{}, 252: &NamedValueInt{}, 253: &Statustext{}, 254: &Debug{}, } // NewMAVLinkMessage returns a new MAVLinkMessage or an error if it encounters an unknown Message ID func NewMAVLinkMessage(msgid uint8, data []byte) (MAVLinkMessage, error) { message := messages[msgid] if message != nil { message.Decode(data) return message, nil } return nil, fmt.Errorf("unknown Message ID: %v", msgid) } // // MAV_AUTOPILOT /*Micro air vehicle / autopilot classes. This identifies the individual model.*/ // const ( MAV_AUTOPILOT_GENERIC = 0 // Generic autopilot, full support for everything | MAV_AUTOPILOT_PIXHAWK = 1 // PIXHAWK autopilot, http://pixhawk.ethz.ch | MAV_AUTOPILOT_SLUGS = 2 // SLUGS autopilot, http://slugsuav.soe.ucsc.edu | MAV_AUTOPILOT_ARDUPILOTMEGA = 3 // ArduPilotMega / ArduCopter, http://diydrones.com | MAV_AUTOPILOT_OPENPILOT = 4 // OpenPilot, http://openpilot.org | MAV_AUTOPILOT_GENERIC_WAYPOINTS_ONLY = 5 // Generic autopilot only supporting simple waypoints | MAV_AUTOPILOT_GENERIC_WAYPOINTS_AND_SIMPLE_NAVIGATION_ONLY = 6 // Generic autopilot supporting waypoints and other simple navigation commands | MAV_AUTOPILOT_GENERIC_MISSION_FULL = 7 // Generic autopilot supporting the full mission command set | MAV_AUTOPILOT_INVALID = 8 // No valid autopilot, e.g. a GCS or other MAVLink component | MAV_AUTOPILOT_PPZ = 9 // PPZ UAV - http://nongnu.org/paparazzi | MAV_AUTOPILOT_UDB = 10 // UAV Dev Board | MAV_AUTOPILOT_FP = 11 // FlexiPilot | MAV_AUTOPILOT_PX4 = 12 // PX4 Autopilot - http://pixhawk.ethz.ch/px4/ | MAV_AUTOPILOT_SMACCMPILOT = 13 // SMACCMPilot - http://smaccmpilot.org | MAV_AUTOPILOT_AUTOQUAD = 14 // AutoQuad -- http://autoquad.org | MAV_AUTOPILOT_ARMAZILA = 15 // Armazila -- http://armazila.com | MAV_AUTOPILOT_AEROB = 16 // Aerob -- http://aerob.ru | MAV_AUTOPILOT_ENUM_END = 17 // | ) // // MAV_TYPE /**/ // const ( MAV_TYPE_GENERIC = 0 // Generic micro air vehicle. | MAV_TYPE_FIXED_WING = 1 // Fixed wing aircraft. | MAV_TYPE_QUADROTOR = 2 // Quadrotor | MAV_TYPE_COAXIAL = 3 // Coaxial helicopter | MAV_TYPE_HELICOPTER = 4 // Normal helicopter with tail rotor. | MAV_TYPE_ANTENNA_TRACKER = 5 // Ground installation | MAV_TYPE_GCS = 6 // Operator control unit / ground control station | MAV_TYPE_AIRSHIP = 7 // Airship, controlled | MAV_TYPE_FREE_BALLOON = 8 // Free balloon, uncontrolled | MAV_TYPE_ROCKET = 9 // Rocket | MAV_TYPE_GROUND_ROVER = 10 // Ground rover | MAV_TYPE_SURFACE_BOAT = 11 // Surface vessel, boat, ship | MAV_TYPE_SUBMARINE = 12 // Submarine | MAV_TYPE_HEXAROTOR = 13 // Hexarotor | MAV_TYPE_OCTOROTOR = 14 // Octorotor | MAV_TYPE_TRICOPTER = 15 // Octorotor | MAV_TYPE_FLAPPING_WING = 16 // Flapping wing | MAV_TYPE_KITE = 17 // Flapping wing | MAV_TYPE_ONBOARD_CONTROLLER = 18 // Onboard companion controller | MAV_TYPE_ENUM_END = 19 // | ) // // MAV_MODE_FLAG /*These flags encode the MAV mode.*/ // const ( MAV_MODE_FLAG_CUSTOM_MODE_ENABLED = 1 // 0b00000001 Reserved for future use. | MAV_MODE_FLAG_TEST_ENABLED = 2 // 0b00000010 system has a test mode enabled. This flag is intended for temporary system tests and should not be used for stable implementations. | MAV_MODE_FLAG_AUTO_ENABLED = 4 // 0b00000100 autonomous mode enabled, system finds its own goal positions. Guided flag can be set or not, depends on the actual implementation. | MAV_MODE_FLAG_GUIDED_ENABLED = 8 // 0b00001000 guided mode enabled, system flies MISSIONs / mission items. | MAV_MODE_FLAG_STABILIZE_ENABLED = 16 // 0b00010000 system stabilizes electronically its attitude (and optionally position). It needs however further control inputs to move around. | MAV_MODE_FLAG_HIL_ENABLED = 32 // 0b00100000 hardware in the loop simulation. All motors / actuators are blocked, but internal software is full operational. | MAV_MODE_FLAG_MANUAL_INPUT_ENABLED = 64 // 0b01000000 remote control input is enabled. | MAV_MODE_FLAG_SAFETY_ARMED = 128 // 0b10000000 MAV safety set to armed. Motors are enabled / running / can start. Ready to fly. | MAV_MODE_FLAG_ENUM_END = 129 // | ) // // MAV_MODE_FLAG_DECODE_POSITION /*These values encode the bit positions of the decode position. These values can be used to read the value of a flag bit by combining the base_mode variable with AND with the flag position value. The result will be either 0 or 1, depending on if the flag is set or not.*/ // const ( MAV_MODE_FLAG_DECODE_POSITION_CUSTOM_MODE = 1 // Eighth bit: 00000001 | MAV_MODE_FLAG_DECODE_POSITION_TEST = 2 // Seventh bit: 00000010 | MAV_MODE_FLAG_DECODE_POSITION_AUTO = 4 // Sixt bit: 00000100 | MAV_MODE_FLAG_DECODE_POSITION_GUIDED = 8 // Fifth bit: 00001000 | MAV_MODE_FLAG_DECODE_POSITION_STABILIZE = 16 // Fourth bit: 00010000 | MAV_MODE_FLAG_DECODE_POSITION_HIL = 32 // Third bit: 00100000 | MAV_MODE_FLAG_DECODE_POSITION_MANUAL = 64 // Second bit: 01000000 | MAV_MODE_FLAG_DECODE_POSITION_SAFETY = 128 // First bit: 10000000 | MAV_MODE_FLAG_DECODE_POSITION_ENUM_END = 129 // | ) // // MAV_GOTO /*Override command, pauses current mission execution and moves immediately to a position*/ // const ( MAV_GOTO_DO_HOLD = 0 // Hold at the current position. | MAV_GOTO_DO_CONTINUE = 1 // Continue with the next item in mission execution. | MAV_GOTO_HOLD_AT_CURRENT_POSITION = 2 // Hold at the current position of the system | MAV_GOTO_HOLD_AT_SPECIFIED_POSITION = 3 // Hold at the position specified in the parameters of the DO_HOLD action | MAV_GOTO_ENUM_END = 4 // | ) // // MAV_MODE /*These defines are predefined OR-combined mode flags. There is no need to use values from this enum, but it simplifies the use of the mode flags. Note that manual input is enabled in all modes as a safety override.*/ // const ( MAV_MODE_PREFLIGHT = 0 // System is not ready to fly, booting, calibrating, etc. No flag is set. | MAV_MODE_MANUAL_DISARMED = 64 // System is allowed to be active, under manual (RC) control, no stabilization | MAV_MODE_TEST_DISARMED = 66 // UNDEFINED mode. This solely depends on the autopilot - use with caution, intended for developers only. | MAV_MODE_STABILIZE_DISARMED = 80 // System is allowed to be active, under assisted RC control. | MAV_MODE_GUIDED_DISARMED = 88 // System is allowed to be active, under autonomous control, manual setpoint | MAV_MODE_AUTO_DISARMED = 92 // System is allowed to be active, under autonomous control and navigation (the trajectory is decided onboard and not pre-programmed by MISSIONs) | MAV_MODE_MANUAL_ARMED = 192 // System is allowed to be active, under manual (RC) control, no stabilization | MAV_MODE_TEST_ARMED = 194 // UNDEFINED mode. This solely depends on the autopilot - use with caution, intended for developers only. | MAV_MODE_STABILIZE_ARMED = 208 // System is allowed to be active, under assisted RC control. | MAV_MODE_GUIDED_ARMED = 216 // System is allowed to be active, under autonomous control, manual setpoint | MAV_MODE_AUTO_ARMED = 220 // System is allowed to be active, under autonomous control and navigation (the trajectory is decided onboard and not pre-programmed by MISSIONs) | MAV_MODE_ENUM_END = 221 // | ) // // MAV_STATE /**/ // const ( MAV_STATE_UNINIT = 0 // Uninitialized system, state is unknown. | MAV_STATE_BOOT = 1 // System is booting up. | MAV_STATE_CALIBRATING = 2 // System is calibrating and not flight-ready. | MAV_STATE_STANDBY = 3 // System is grounded and on standby. It can be launched any time. | MAV_STATE_ACTIVE = 4 // System is active and might be already airborne. Motors are engaged. | MAV_STATE_CRITICAL = 5 // System is in a non-normal flight mode. It can however still navigate. | MAV_STATE_EMERGENCY = 6 // System is in a non-normal flight mode. It lost control over parts or over the whole airframe. It is in mayday and going down. | MAV_STATE_POWEROFF = 7 // System just initialized its power-down sequence, will shut down now. | MAV_STATE_ENUM_END = 8 // | ) // // MAV_COMPONENT /**/ // const ( MAV_COMP_ID_ALL = 0 // | MAV_COMP_ID_CAMERA = 100 // | MAV_COMP_ID_SERVO1 = 140 // | MAV_COMP_ID_SERVO2 = 141 // | MAV_COMP_ID_SERVO3 = 142 // | MAV_COMP_ID_SERVO4 = 143 // | MAV_COMP_ID_SERVO5 = 144 // | MAV_COMP_ID_SERVO6 = 145 // | MAV_COMP_ID_SERVO7 = 146 // | MAV_COMP_ID_SERVO8 = 147 // | MAV_COMP_ID_SERVO9 = 148 // | MAV_COMP_ID_SERVO10 = 149 // | MAV_COMP_ID_SERVO11 = 150 // | MAV_COMP_ID_SERVO12 = 151 // | MAV_COMP_ID_SERVO13 = 152 // | MAV_COMP_ID_SERVO14 = 153 // | MAV_COMP_ID_MAPPER = 180 // | MAV_COMP_ID_MISSIONPLANNER = 190 // | MAV_COMP_ID_PATHPLANNER = 195 // | MAV_COMP_ID_IMU = 200 // | MAV_COMP_ID_IMU_2 = 201 // | MAV_COMP_ID_IMU_3 = 202 // | MAV_COMP_ID_GPS = 220 // | MAV_COMP_ID_UDP_BRIDGE = 240 // | MAV_COMP_ID_UART_BRIDGE = 241 // | MAV_COMP_ID_SYSTEM_CONTROL = 250 // | MAV_COMPONENT_ENUM_END = 251 // | ) // // MAV_SYS_STATUS_SENSOR /*These encode the sensors whose status is sent as part of the SYS_STATUS message.*/ // const ( MAV_SYS_STATUS_SENSOR_3D_GYRO = 1 // 0x01 3D gyro | MAV_SYS_STATUS_SENSOR_3D_ACCEL = 2 // 0x02 3D accelerometer | MAV_SYS_STATUS_SENSOR_3D_MAG = 4 // 0x04 3D magnetometer | MAV_SYS_STATUS_SENSOR_ABSOLUTE_PRESSURE = 8 // 0x08 absolute pressure | MAV_SYS_STATUS_SENSOR_DIFFERENTIAL_PRESSURE = 16 // 0x10 differential pressure | MAV_SYS_STATUS_SENSOR_GPS = 32 // 0x20 GPS | MAV_SYS_STATUS_SENSOR_OPTICAL_FLOW = 64 // 0x40 optical flow | MAV_SYS_STATUS_SENSOR_VISION_POSITION = 128 // 0x80 computer vision position | MAV_SYS_STATUS_SENSOR_LASER_POSITION = 256 // 0x100 laser based position | MAV_SYS_STATUS_SENSOR_EXTERNAL_GROUND_TRUTH = 512 // 0x200 external ground truth (Vicon or Leica) | MAV_SYS_STATUS_SENSOR_ANGULAR_RATE_CONTROL = 1024 // 0x400 3D angular rate control | MAV_SYS_STATUS_SENSOR_ATTITUDE_STABILIZATION = 2048 // 0x800 attitude stabilization | MAV_SYS_STATUS_SENSOR_YAW_POSITION = 4096 // 0x1000 yaw position | MAV_SYS_STATUS_SENSOR_Z_ALTITUDE_CONTROL = 8192 // 0x2000 z/altitude control | MAV_SYS_STATUS_SENSOR_XY_POSITION_CONTROL = 16384 // 0x4000 x/y position control | MAV_SYS_STATUS_SENSOR_MOTOR_OUTPUTS = 32768 // 0x8000 motor outputs / control | MAV_SYS_STATUS_SENSOR_RC_RECEIVER = 65536 // 0x10000 rc receiver | MAV_SYS_STATUS_SENSOR_3D_GYRO2 = 131072 // 0x20000 2nd 3D gyro | MAV_SYS_STATUS_SENSOR_3D_ACCEL2 = 262144 // 0x40000 2nd 3D accelerometer | MAV_SYS_STATUS_SENSOR_3D_MAG2 = 524288 // 0x80000 2nd 3D magnetometer | MAV_SYS_STATUS_GEOFENCE = 1048576 // 0x100000 geofence | MAV_SYS_STATUS_AHRS = 2097152 // 0x200000 AHRS subsystem health | MAV_SYS_STATUS_TERRAIN = 4194304 // 0x400000 Terrain subsystem health | MAV_SYS_STATUS_SENSOR_ENUM_END = 4194305 // | ) // // MAV_FRAME /**/ // const ( MAV_FRAME_GLOBAL = 0 // Global coordinate frame, WGS84 coordinate system. First value / x: latitude, second value / y: longitude, third value / z: positive altitude over mean sea level (MSL) | MAV_FRAME_LOCAL_NED = 1 // Local coordinate frame, Z-up (x: north, y: east, z: down). | MAV_FRAME_MISSION = 2 // NOT a coordinate frame, indicates a mission command. | MAV_FRAME_GLOBAL_RELATIVE_ALT = 3 // Global coordinate frame, WGS84 coordinate system, relative altitude over ground with respect to the home position. First value / x: latitude, second value / y: longitude, third value / z: positive altitude with 0 being at the altitude of the home location. | MAV_FRAME_LOCAL_ENU = 4 // Local coordinate frame, Z-down (x: east, y: north, z: up) | MAV_FRAME_GLOBAL_INT = 5 // Global coordinate frame with some fields as scaled integers, WGS84 coordinate system. First value / x: latitude, second value / y: longitude, third value / z: positive altitude over mean sea level (MSL). Lat / Lon are scaled * 1E7 to avoid floating point accuracy limitations. | MAV_FRAME_GLOBAL_RELATIVE_ALT_INT = 6 // Global coordinate frame with some fields as scaled integers, WGS84 coordinate system, relative altitude over ground with respect to the home position. First value / x: latitude, second value / y: longitude, third value / z: positive altitude with 0 being at the altitude of the home location. Lat / Lon are scaled * 1E7 to avoid floating point accuracy limitations. | MAV_FRAME_LOCAL_OFFSET_NED = 7 // Offset to the current local frame. Anything expressed in this frame should be added to the current local frame position. | MAV_FRAME_BODY_NED = 8 // Setpoint in body NED frame. This makes sense if all position control is externalized - e.g. useful to command 2 m/s^2 acceleration to the right. | MAV_FRAME_BODY_OFFSET_NED = 9 // Offset in body NED frame. This makes sense if adding setpoints to the current flight path, to avoid an obstacle - e.g. useful to command 2 m/s^2 acceleration to the east. | MAV_FRAME_GLOBAL_TERRAIN_ALT = 10 // Global coordinate frame with above terrain level altitude. WGS84 coordinate system, relative altitude over terrain with respect to the waypoint coordinate. First value / x: latitude, second value / y: longitude, third value / z: positive altitude with 0 being at ground level in terrain model. | MAV_FRAME_ENUM_END = 11 // | ) // // MAVLINK_DATA_STREAM_TYPE /**/ // const ( MAVLINK_DATA_STREAM_IMG_JPEG = 1 // | MAVLINK_DATA_STREAM_IMG_BMP = 2 // | MAVLINK_DATA_STREAM_IMG_RAW8U = 3 // | MAVLINK_DATA_STREAM_IMG_RAW32U = 4 // | MAVLINK_DATA_STREAM_IMG_PGM = 5 // | MAVLINK_DATA_STREAM_IMG_PNG = 6 // | MAVLINK_DATA_STREAM_TYPE_ENUM_END = 7 // | ) // // FENCE_ACTION /**/ // const ( FENCE_ACTION_NONE = 0 // Disable fenced mode | FENCE_ACTION_GUIDED = 1 // Switched to guided mode to return point (fence point 0) | FENCE_ACTION_REPORT = 2 // Report fence breach, but don't take action | FENCE_ACTION_GUIDED_THR_PASS = 3 // Switched to guided mode to return point (fence point 0) with manual throttle control | FENCE_ACTION_ENUM_END = 4 // | ) // // FENCE_BREACH /**/ // const ( FENCE_BREACH_NONE = 0 // No last fence breach | FENCE_BREACH_MINALT = 1 // Breached minimum altitude | FENCE_BREACH_MAXALT = 2 // Breached maximum altitude | FENCE_BREACH_BOUNDARY = 3 // Breached fence boundary | FENCE_BREACH_ENUM_END = 4 // | ) // // MAV_MOUNT_MODE /*Enumeration of possible mount operation modes*/ // const ( MAV_MOUNT_MODE_RETRACT = 0 // Load and keep safe position (Roll,Pitch,Yaw) from permant memory and stop stabilization | MAV_MOUNT_MODE_NEUTRAL = 1 // Load and keep neutral position (Roll,Pitch,Yaw) from permanent memory. | MAV_MOUNT_MODE_MAVLINK_TARGETING = 2 // Load neutral position and start MAVLink Roll,Pitch,Yaw control with stabilization | MAV_MOUNT_MODE_RC_TARGETING = 3 // Load neutral position and start RC Roll,Pitch,Yaw control with stabilization | MAV_MOUNT_MODE_GPS_POINT = 4 // Load neutral position and start to point to Lat,Lon,Alt | MAV_MOUNT_MODE_ENUM_END = 5 // | ) // // MAV_CMD /*Commands to be executed by the MAV. They can be executed on user request, or as part of a mission script. If the action is used in a mission, the parameter mapping to the waypoint/mission message is as follows: Param 1, Param 2, Param 3, Param 4, X: Param 5, Y:Param 6, Z:Param 7. This command list is similar what ARINC 424 is for commercial aircraft: A data format how to interpret waypoint/mission data.*/ // const ( MAV_CMD_NAV_WAYPOINT = 16 // Navigate to MISSION. | Hold time in decimal seconds. (ignored by fixed wing, time to stay at MISSION for rotary wing) | Acceptance radius in meters (if the sphere with this radius is hit, the MISSION counts as reached) | 0 to pass through the WP, if > 0 radius in meters to pass by WP. Positive value for clockwise orbit, negative value for counter-clockwise orbit. Allows trajectory control. | Desired yaw angle at MISSION (rotary wing) | Latitude | Longitude | Altitude | MAV_CMD_NAV_LOITER_UNLIM = 17 // Loiter around this MISSION an unlimited amount of time | Empty | Empty | Radius around MISSION, in meters. If positive loiter clockwise, else counter-clockwise | Desired yaw angle. | Latitude | Longitude | Altitude | MAV_CMD_NAV_LOITER_TURNS = 18 // Loiter around this MISSION for X turns | Turns | Empty | Radius around MISSION, in meters. If positive loiter clockwise, else counter-clockwise | Desired yaw angle. | Latitude | Longitude | Altitude | MAV_CMD_NAV_LOITER_TIME = 19 // Loiter around this MISSION for X seconds | Seconds (decimal) | Empty | Radius around MISSION, in meters. If positive loiter clockwise, else counter-clockwise | Desired yaw angle. | Latitude | Longitude | Altitude | MAV_CMD_NAV_RETURN_TO_LAUNCH = 20 // Return to launch location | Empty | Empty | Empty | Empty | Empty | Empty | Empty | MAV_CMD_NAV_LAND = 21 // Land at location | Empty | Empty | Empty | Desired yaw angle. | Latitude | Longitude | Altitude | MAV_CMD_NAV_TAKEOFF = 22 // Takeoff from ground / hand | Minimum pitch (if airspeed sensor present), desired pitch without sensor | Empty | Empty | Yaw angle (if magnetometer present), ignored without magnetometer | Latitude | Longitude | Altitude | MAV_CMD_NAV_ROI = 80 // Sets the region of interest (ROI) for a sensor set or the vehicle itself. This can then be used by the vehicles control system to control the vehicle attitude and the attitude of various sensors such as cameras. | Region of intereset mode. (see MAV_ROI enum) | MISSION index/ target ID. (see MAV_ROI enum) | ROI index (allows a vehicle to manage multiple ROI's) | Empty | x the location of the fixed ROI (see MAV_FRAME) | y | z | MAV_CMD_NAV_PATHPLANNING = 81 // Control autonomous path planning on the MAV. | 0: Disable local obstacle avoidance / local path planning (without resetting map), 1: Enable local path planning, 2: Enable and reset local path planning | 0: Disable full path planning (without resetting map), 1: Enable, 2: Enable and reset map/occupancy grid, 3: Enable and reset planned route, but not occupancy grid | Empty | Yaw angle at goal, in compass degrees, [0..360] | Latitude/X of goal | Longitude/Y of goal | Altitude/Z of goal | MAV_CMD_NAV_SPLINE_WAYPOINT = 82 // Navigate to MISSION using a spline path. | Hold time in decimal seconds. (ignored by fixed wing, time to stay at MISSION for rotary wing) | Empty | Empty | Empty | Latitude/X of goal | Longitude/Y of goal | Altitude/Z of goal | MAV_CMD_NAV_GUIDED_ENABLE = 92 // hand control over to an external controller | On / Off (> 0.5f on) | Empty | Empty | Empty | Empty | Empty | Empty | MAV_CMD_NAV_LAST = 95 // NOP - This command is only used to mark the upper limit of the NAV/ACTION commands in the enumeration | Empty | Empty | Empty | Empty | Empty | Empty | Empty | MAV_CMD_CONDITION_DELAY = 112 // Delay mission state machine. | Delay in seconds (decimal) | Empty | Empty | Empty | Empty | Empty | Empty | MAV_CMD_CONDITION_CHANGE_ALT = 113 // Ascend/descend at rate. Delay mission state machine until desired altitude reached. | Descent / Ascend rate (m/s) | Empty | Empty | Empty | Empty | Empty | Finish Altitude | MAV_CMD_CONDITION_DISTANCE = 114 // Delay mission state machine until within desired distance of next NAV point. | Distance (meters) | Empty | Empty | Empty | Empty | Empty | Empty | MAV_CMD_CONDITION_YAW = 115 // Reach a certain target angle. | target angle: [0-360], 0 is north | speed during yaw change:[deg per second] | direction: negative: counter clockwise, positive: clockwise [-1,1] | relative offset or absolute angle: [ 1,0] | Empty | Empty | Empty | MAV_CMD_CONDITION_LAST = 159 // NOP - This command is only used to mark the upper limit of the CONDITION commands in the enumeration | Empty | Empty | Empty | Empty | Empty | Empty | Empty | MAV_CMD_DO_SET_MODE = 176 // Set system mode. | Mode, as defined by ENUM MAV_MODE | Custom mode - this is system specific, please refer to the individual autopilot specifications for details. | Empty | Empty | Empty | Empty | Empty | MAV_CMD_DO_JUMP = 177 // Jump to the desired command in the mission list. Repeat this action only the specified number of times | Sequence number | Repeat count | Empty | Empty | Empty | Empty | Empty | MAV_CMD_DO_CHANGE_SPEED = 178 // Change speed and/or throttle set points. | Speed type (0=Airspeed, 1=Ground Speed) | Speed (m/s, -1 indicates no change) | Throttle ( Percent, -1 indicates no change) | Empty | Empty | Empty | Empty | MAV_CMD_DO_SET_HOME = 179 // Changes the home location either to the current location or a specified location. | Use current (1=use current location, 0=use specified location) | Empty | Empty | Empty | Latitude | Longitude | Altitude | MAV_CMD_DO_SET_PARAMETER = 180 // Set a system parameter. Caution! Use of this command requires knowledge of the numeric enumeration value of the parameter. | Parameter number | Parameter value | Empty | Empty | Empty | Empty | Empty | MAV_CMD_DO_SET_RELAY = 181 // Set a relay to a condition. | Relay number | Setting (1=on, 0=off, others possible depending on system hardware) | Empty | Empty | Empty | Empty | Empty | MAV_CMD_DO_REPEAT_RELAY = 182 // Cycle a relay on and off for a desired number of cyles with a desired period. | Relay number | Cycle count | Cycle time (seconds, decimal) | Empty | Empty | Empty | Empty | MAV_CMD_DO_SET_SERVO = 183 // Set a servo to a desired PWM value. | Servo number | PWM (microseconds, 1000 to 2000 typical) | Empty | Empty | Empty | Empty | Empty | MAV_CMD_DO_REPEAT_SERVO = 184 // Cycle a between its nominal setting and a desired PWM for a desired number of cycles with a desired period. | Servo number | PWM (microseconds, 1000 to 2000 typical) | Cycle count | Cycle time (seconds) | Empty | Empty | Empty | MAV_CMD_DO_FLIGHTTERMINATION = 185 // Terminate flight immediately | Flight termination activated if > 0.5 | Empty | Empty | Empty | Empty | Empty | Empty | MAV_CMD_DO_RALLY_LAND = 190 // Mission command to perform a landing from a rally point. | Break altitude (meters) | Landing speed (m/s) | Empty | Empty | Empty | Empty | Empty | MAV_CMD_DO_GO_AROUND = 191 // Mission command to safely abort an autonmous landing. | Altitude (meters) | Empty | Empty | Empty | Empty | Empty | Empty | MAV_CMD_DO_CONTROL_VIDEO = 200 // Control onboard camera system. | Camera ID (-1 for all) | Transmission: 0: disabled, 1: enabled compressed, 2: enabled raw | Transmission mode: 0: video stream, >0: single images every n seconds (decimal) | Recording: 0: disabled, 1: enabled compressed, 2: enabled raw | Empty | Empty | Empty | MAV_CMD_DO_SET_ROI = 201 // Sets the region of interest (ROI) for a sensor set or the vehicle itself. This can then be used by the vehicles control system to control the vehicle attitude and the attitude of various sensors such as cameras. | Region of intereset mode. (see MAV_ROI enum) | MISSION index/ target ID. (see MAV_ROI enum) | ROI index (allows a vehicle to manage multiple ROI's) | Empty | x the location of the fixed ROI (see MAV_FRAME) | y | z | MAV_CMD_DO_DIGICAM_CONFIGURE = 202 // Mission command to configure an on-board camera controller system. | Modes: P, TV, AV, M, Etc | Shutter speed: Divisor number for one second | Aperture: F stop number | ISO number e.g. 80, 100, 200, Etc | Exposure type enumerator | Command Identity | Main engine cut-off time before camera trigger in seconds/10 (0 means no cut-off) | MAV_CMD_DO_DIGICAM_CONTROL = 203 // Mission command to control an on-board camera controller system. | Session control e.g. show/hide lens | Zoom's absolute position | Zooming step value to offset zoom from the current position | Focus Locking, Unlocking or Re-locking | Shooting Command | Command Identity | Empty | MAV_CMD_DO_MOUNT_CONFIGURE = 204 // Mission command to configure a camera or antenna mount | Mount operation mode (see MAV_MOUNT_MODE enum) | stabilize roll? (1 = yes, 0 = no) | stabilize pitch? (1 = yes, 0 = no) | stabilize yaw? (1 = yes, 0 = no) | Empty | Empty | Empty | MAV_CMD_DO_MOUNT_CONTROL = 205 // Mission command to control a camera or antenna mount | pitch or lat in degrees, depending on mount mode. | roll or lon in degrees depending on mount mode | yaw or alt (in meters) depending on mount mode | reserved | reserved | reserved | MAV_MOUNT_MODE enum value | MAV_CMD_DO_SET_CAM_TRIGG_DIST = 206 // Mission command to set CAM_TRIGG_DIST for this flight | Camera trigger distance (meters) | Empty | Empty | Empty | Empty | Empty | Empty | MAV_CMD_DO_FENCE_ENABLE = 207 // Mission command to enable the geofence | enable? (0=disable, 1=enable) | Empty | Empty | Empty | Empty | Empty | Empty | MAV_CMD_DO_PARACHUTE = 208 // Mission command to trigger a parachute | action (0=disable, 1=enable, 2=release, for some systems see PARACHUTE_ACTION enum, not in general message set.) | Empty | Empty | Empty | Empty | Empty | Empty | MAV_CMD_DO_INVERTED_FLIGHT = 210 // Change to/from inverted flight | inverted (0=normal, 1=inverted) | Empty | Empty | Empty | Empty | Empty | Empty | MAV_CMD_DO_MOUNT_CONTROL_QUAT = 220 // Mission command to control a camera or antenna mount, using a quaternion as reference. | q1 - quaternion param #1, w (1 in null-rotation) | q2 - quaternion param #2, x (0 in null-rotation) | q3 - quaternion param #3, y (0 in null-rotation) | q4 - quaternion param #4, z (0 in null-rotation) | Empty | Empty | Empty | MAV_CMD_DO_GUIDED_CONTROLLER = 221 // set id of the controller | System ID | Component ID | Empty | Empty | Empty | Empty | Empty | MAV_CMD_DO_GUIDED_LIMITS = 222 // set limits for external control | timeout - maximum time (in seconds) that external controller will be allowed to control vehicle. 0 means no timeout | absolute altitude min (in meters, WGS84) - if vehicle moves below this alt, the command will be aborted and the mission will continue. 0 means no lower altitude limit | absolute altitude max (in meters)- if vehicle moves above this alt, the command will be aborted and the mission will continue. 0 means no upper altitude limit | horizontal move limit (in meters, WGS84) - if vehicle moves more than this distance from it's location at the moment the command was executed, the command will be aborted and the mission will continue. 0 means no horizontal altitude limit | Empty | Empty | Empty | MAV_CMD_DO_LAST = 240 // NOP - This command is only used to mark the upper limit of the DO commands in the enumeration | Empty | Empty | Empty | Empty | Empty | Empty | Empty | MAV_CMD_PREFLIGHT_CALIBRATION = 241 // Trigger calibration. This command will be only accepted if in pre-flight mode. | Gyro calibration: 0: no, 1: yes | Magnetometer calibration: 0: no, 1: yes | Ground pressure: 0: no, 1: yes | Radio calibration: 0: no, 1: yes | Accelerometer calibration: 0: no, 1: yes | Compass/Motor interference calibration: 0: no, 1: yes | Empty | MAV_CMD_PREFLIGHT_SET_SENSOR_OFFSETS = 242 // Set sensor offsets. This command will be only accepted if in pre-flight mode. | Sensor to adjust the offsets for: 0: gyros, 1: accelerometer, 2: magnetometer, 3: barometer, 4: optical flow, 5: second magnetometer | X axis offset (or generic dimension 1), in the sensor's raw units | Y axis offset (or generic dimension 2), in the sensor's raw units | Z axis offset (or generic dimension 3), in the sensor's raw units | Generic dimension 4, in the sensor's raw units | Generic dimension 5, in the sensor's raw units | Generic dimension 6, in the sensor's raw units | MAV_CMD_PREFLIGHT_STORAGE = 245 // Request storage of different parameter values and logs. This command will be only accepted if in pre-flight mode. | Parameter storage: 0: READ FROM FLASH/EEPROM, 1: WRITE CURRENT TO FLASH/EEPROM | Mission storage: 0: READ FROM FLASH/EEPROM, 1: WRITE CURRENT TO FLASH/EEPROM | Reserved | Reserved | Empty | Empty | Empty | MAV_CMD_PREFLIGHT_REBOOT_SHUTDOWN = 246 // Request the reboot or shutdown of system components. | 0: Do nothing for autopilot, 1: Reboot autopilot, 2: Shutdown autopilot. | 0: Do nothing for onboard computer, 1: Reboot onboard computer, 2: Shutdown onboard computer. | Reserved | Reserved | Empty | Empty | Empty | MAV_CMD_OVERRIDE_GOTO = 252 // Hold / continue the current action | MAV_GOTO_DO_HOLD: hold MAV_GOTO_DO_CONTINUE: continue with next item in mission plan | MAV_GOTO_HOLD_AT_CURRENT_POSITION: Hold at current position MAV_GOTO_HOLD_AT_SPECIFIED_POSITION: hold at specified position | MAV_FRAME coordinate frame of hold point | Desired yaw angle in degrees | Latitude / X position | Longitude / Y position | Altitude / Z position | MAV_CMD_MISSION_START = 300 // start running a mission | first_item: the first mission item to run | last_item: the last mission item to run (after this item is run, the mission ends) | MAV_CMD_COMPONENT_ARM_DISARM = 400 // Arms / Disarms a component | 1 to arm, 0 to disarm | MAV_CMD_START_RX_PAIR = 500 // Starts receiver pairing | 0:Spektrum | 0:Spektrum DSM2, 1:Spektrum DSMX | MAV_CMD_ENUM_END = 501 // | ) // // MAV_DATA_STREAM /*Data stream IDs. A data stream is not a fixed set of messages, but rather a recommendation to the autopilot software. Individual autopilots may or may not obey the recommended messages.*/ // const ( MAV_DATA_STREAM_ALL = 0 // Enable all data streams | MAV_DATA_STREAM_RAW_SENSORS = 1 // Enable IMU_RAW, GPS_RAW, GPS_STATUS packets. | MAV_DATA_STREAM_EXTENDED_STATUS = 2 // Enable GPS_STATUS, CONTROL_STATUS, AUX_STATUS | MAV_DATA_STREAM_RC_CHANNELS = 3 // Enable RC_CHANNELS_SCALED, RC_CHANNELS_RAW, SERVO_OUTPUT_RAW | MAV_DATA_STREAM_RAW_CONTROLLER = 4 // Enable ATTITUDE_CONTROLLER_OUTPUT, POSITION_CONTROLLER_OUTPUT, NAV_CONTROLLER_OUTPUT. | MAV_DATA_STREAM_POSITION = 6 // Enable LOCAL_POSITION, GLOBAL_POSITION/GLOBAL_POSITION_INT messages. | MAV_DATA_STREAM_EXTRA1 = 10 // Dependent on the autopilot | MAV_DATA_STREAM_EXTRA2 = 11 // Dependent on the autopilot | MAV_DATA_STREAM_EXTRA3 = 12 // Dependent on the autopilot | MAV_DATA_STREAM_ENUM_END = 13 // | ) // // MAV_ROI /* The ROI (region of interest) for the vehicle. This can be used by the vehicle for camera/vehicle attitude alignment (see MAV_CMD_NAV_ROI).*/ // const ( MAV_ROI_NONE = 0 // No region of interest. | MAV_ROI_WPNEXT = 1 // Point toward next MISSION. | MAV_ROI_WPINDEX = 2 // Point toward given MISSION. | MAV_ROI_LOCATION = 3 // Point toward fixed location. | MAV_ROI_TARGET = 4 // Point toward of given id. | MAV_ROI_ENUM_END = 5 // | ) // // MAV_CMD_ACK /*ACK / NACK / ERROR values as a result of MAV_CMDs and for mission item transmission.*/ // const ( MAV_CMD_ACK_OK = 1 // Command / mission item is ok. | MAV_CMD_ACK_ERR_FAIL = 2 // Generic error message if none of the other reasons fails or if no detailed error reporting is implemented. | MAV_CMD_ACK_ERR_ACCESS_DENIED = 3 // The system is refusing to accept this command from this source / communication partner. | MAV_CMD_ACK_ERR_NOT_SUPPORTED = 4 // Command or mission item is not supported, other commands would be accepted. | MAV_CMD_ACK_ERR_COORDINATE_FRAME_NOT_SUPPORTED = 5 // The coordinate frame of this command / mission item is not supported. | MAV_CMD_ACK_ERR_COORDINATES_OUT_OF_RANGE = 6 // The coordinate frame of this command is ok, but he coordinate values exceed the safety limits of this system. This is a generic error, please use the more specific error messages below if possible. | MAV_CMD_ACK_ERR_X_LAT_OUT_OF_RANGE = 7 // The X or latitude value is out of range. | MAV_CMD_ACK_ERR_Y_LON_OUT_OF_RANGE = 8 // The Y or longitude value is out of range. | MAV_CMD_ACK_ERR_Z_ALT_OUT_OF_RANGE = 9 // The Z or altitude value is out of range. | MAV_CMD_ACK_ENUM_END = 10 // | ) // // MAV_PARAM_TYPE /*Specifies the datatype of a MAVLink parameter.*/ // const ( MAV_PARAM_TYPE_UINT8 = 1 // 8-bit unsigned integer | MAV_PARAM_TYPE_INT8 = 2 // 8-bit signed integer | MAV_PARAM_TYPE_UINT16 = 3 // 16-bit unsigned integer | MAV_PARAM_TYPE_INT16 = 4 // 16-bit signed integer | MAV_PARAM_TYPE_UINT32 = 5 // 32-bit unsigned integer | MAV_PARAM_TYPE_INT32 = 6 // 32-bit signed integer | MAV_PARAM_TYPE_UINT64 = 7 // 64-bit unsigned integer | MAV_PARAM_TYPE_INT64 = 8 // 64-bit signed integer | MAV_PARAM_TYPE_REAL32 = 9 // 32-bit floating-point | MAV_PARAM_TYPE_REAL64 = 10 // 64-bit floating-point | MAV_PARAM_TYPE_ENUM_END = 11 // | ) // // MAV_RESULT /*result from a mavlink command*/ // const ( MAV_RESULT_ACCEPTED = 0 // Command ACCEPTED and EXECUTED | MAV_RESULT_TEMPORARILY_REJECTED = 1 // Command TEMPORARY REJECTED/DENIED | MAV_RESULT_DENIED = 2 // Command PERMANENTLY DENIED | MAV_RESULT_UNSUPPORTED = 3 // Command UNKNOWN/UNSUPPORTED | MAV_RESULT_FAILED = 4 // Command executed, but failed | MAV_RESULT_ENUM_END = 5 // | ) // // MAV_MISSION_RESULT /*result in a mavlink mission ack*/ // const ( MAV_MISSION_ACCEPTED = 0 // mission accepted OK | MAV_MISSION_ERROR = 1 // generic error / not accepting mission commands at all right now | MAV_MISSION_UNSUPPORTED_FRAME = 2 // coordinate frame is not supported | MAV_MISSION_UNSUPPORTED = 3 // command is not supported | MAV_MISSION_NO_SPACE = 4 // mission item exceeds storage space | MAV_MISSION_INVALID = 5 // one of the parameters has an invalid value | MAV_MISSION_INVALID_PARAM1 = 6 // param1 has an invalid value | MAV_MISSION_INVALID_PARAM2 = 7 // param2 has an invalid value | MAV_MISSION_INVALID_PARAM3 = 8 // param3 has an invalid value | MAV_MISSION_INVALID_PARAM4 = 9 // param4 has an invalid value | MAV_MISSION_INVALID_PARAM5_X = 10 // x/param5 has an invalid value | MAV_MISSION_INVALID_PARAM6_Y = 11 // y/param6 has an invalid value | MAV_MISSION_INVALID_PARAM7 = 12 // param7 has an invalid value | MAV_MISSION_INVALID_SEQUENCE = 13 // received waypoint out of sequence | MAV_MISSION_DENIED = 14 // not accepting any mission commands from this communication partner | MAV_MISSION_RESULT_ENUM_END = 15 // | ) // // MAV_SEVERITY /*Indicates the severity level, generally used for status messages to indicate their relative urgency. Based on RFC-5424 using expanded definitions at: http://www.kiwisyslog.com/kb/info:-syslog-message-levels/.*/ // const ( MAV_SEVERITY_EMERGENCY = 0 // System is unusable. This is a "panic" condition. | MAV_SEVERITY_ALERT = 1 // Action should be taken immediately. Indicates error in non-critical systems. | MAV_SEVERITY_CRITICAL = 2 // Action must be taken immediately. Indicates failure in a primary system. | MAV_SEVERITY_ERROR = 3 // Indicates an error in secondary/redundant systems. | MAV_SEVERITY_WARNING = 4 // Indicates about a possible future error if this is not resolved within a given timeframe. Example would be a low battery warning. | MAV_SEVERITY_NOTICE = 5 // An unusual event has occurred, though not an error condition. This should be investigated for the root cause. | MAV_SEVERITY_INFO = 6 // Normal operational messages. Useful for logging. No action is required for these messages. | MAV_SEVERITY_DEBUG = 7 // Useful non-operational messages that can assist in debugging. These should not occur during normal operation. | MAV_SEVERITY_ENUM_END = 8 // | ) // // MAV_POWER_STATUS /*Power supply status flags (bitmask)*/ // const ( MAV_POWER_STATUS_BRICK_VALID = 1 // main brick power supply valid | MAV_POWER_STATUS_SERVO_VALID = 2 // main servo power supply valid for FMU | MAV_POWER_STATUS_USB_CONNECTED = 4 // USB power is connected | MAV_POWER_STATUS_PERIPH_OVERCURRENT = 8 // peripheral supply is in over-current state | MAV_POWER_STATUS_PERIPH_HIPOWER_OVERCURRENT = 16 // hi-power peripheral supply is in over-current state | MAV_POWER_STATUS_CHANGED = 32 // Power status has changed since boot | MAV_POWER_STATUS_ENUM_END = 33 // | ) // // SERIAL_CONTROL_DEV /*SERIAL_CONTROL device types*/ // const ( SERIAL_CONTROL_DEV_TELEM1 = 0 // First telemetry port | SERIAL_CONTROL_DEV_TELEM2 = 1 // Second telemetry port | SERIAL_CONTROL_DEV_GPS1 = 2 // First GPS port | SERIAL_CONTROL_DEV_GPS2 = 3 // Second GPS port | SERIAL_CONTROL_DEV_ENUM_END = 4 // | ) // // SERIAL_CONTROL_FLAG /*SERIAL_CONTROL flags (bitmask)*/ // const ( SERIAL_CONTROL_FLAG_REPLY = 1 // Set if this is a reply | SERIAL_CONTROL_FLAG_RESPOND = 2 // Set if the sender wants the receiver to send a response as another SERIAL_CONTROL message | SERIAL_CONTROL_FLAG_EXCLUSIVE = 4 // Set if access to the serial port should be removed from whatever driver is currently using it, giving exclusive access to the SERIAL_CONTROL protocol. The port can be handed back by sending a request without this flag set | SERIAL_CONTROL_FLAG_BLOCKING = 8 // Block on writes to the serial port | SERIAL_CONTROL_FLAG_MULTI = 16 // Send multiple replies until port is drained | SERIAL_CONTROL_FLAG_ENUM_END = 17 // | ) // // MAV_DISTANCE_SENSOR /*Enumeration of distance sensor types*/ // const ( MAV_DISTANCE_SENSOR_LASER = 0 // Laser altimeter, e.g. LightWare SF02/F or PulsedLight units | MAV_DISTANCE_SENSOR_ULTRASOUND = 1 // Ultrasound altimeter, e.g. MaxBotix units | MAV_DISTANCE_SENSOR_ENUM_END = 2 // | ) // MESSAGE HEARTBEAT // // MAVLINK_MSG_ID_HEARTBEAT 0 // // MAVLINK_MSG_ID_HEARTBEAT_LEN 9 // // MAVLINK_MSG_ID_HEARTBEAT_CRC 50 type Heartbeat struct { CUSTOM_MODE uint32 // A bitfield for use for autopilot-specific flags. TYPE uint8 // Type of the MAV (quadrotor, helicopter, etc., up to 15 types, defined in MAV_TYPE ENUM) AUTOPILOT uint8 // Autopilot type / class. defined in MAV_AUTOPILOT ENUM BASE_MODE uint8 // System mode bitfield, see MAV_MODE_FLAG ENUM in mavlink/include/mavlink_types.h SYSTEM_STATUS uint8 // System status flag, see MAV_STATE ENUM MAVLINK_VERSION uint8 // MAVLink version, not writable by user, gets added by protocol because of magic data type: uint8_t_mavlink_version } // NewHeartbeat returns a new Heartbeat func NewHeartbeat(CUSTOM_MODE uint32, TYPE uint8, AUTOPILOT uint8, BASE_MODE uint8, SYSTEM_STATUS uint8, MAVLINK_VERSION uint8) *Heartbeat { m := Heartbeat{} m.CUSTOM_MODE = CUSTOM_MODE m.TYPE = TYPE m.AUTOPILOT = AUTOPILOT m.BASE_MODE = BASE_MODE m.SYSTEM_STATUS = SYSTEM_STATUS m.MAVLINK_VERSION = MAVLINK_VERSION return &m } // Id returns the Heartbeat Message ID func (*Heartbeat) Id() uint8 { return 0 } // Len returns the Heartbeat Message Length func (*Heartbeat) Len() uint8 { return 9 } // Crc returns the Heartbeat Message CRC func (*Heartbeat) Crc() uint8 { return 50 } // Pack returns a packed byte array which represents a Heartbeat payload func (m *Heartbeat) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.CUSTOM_MODE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TYPE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.AUTOPILOT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.BASE_MODE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.SYSTEM_STATUS); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.MAVLINK_VERSION); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the Heartbeat func (m *Heartbeat) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.CUSTOM_MODE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TYPE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.AUTOPILOT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.BASE_MODE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.SYSTEM_STATUS); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.MAVLINK_VERSION); err != nil { panic(err) } } // MESSAGE SYS_STATUS // // MAVLINK_MSG_ID_SYS_STATUS 1 // // MAVLINK_MSG_ID_SYS_STATUS_LEN 31 // // MAVLINK_MSG_ID_SYS_STATUS_CRC 124 type SysStatus struct { ONBOARD_CONTROL_SENSORS_PRESENT uint32 // Bitmask showing which onboard controllers and sensors are present. Value of 0: not present. Value of 1: present. Indices defined by ENUM MAV_SYS_STATUS_SENSOR ONBOARD_CONTROL_SENSORS_ENABLED uint32 // Bitmask showing which onboard controllers and sensors are enabled: Value of 0: not enabled. Value of 1: enabled. Indices defined by ENUM MAV_SYS_STATUS_SENSOR ONBOARD_CONTROL_SENSORS_HEALTH uint32 // Bitmask showing which onboard controllers and sensors are operational or have an error: Value of 0: not enabled. Value of 1: enabled. Indices defined by ENUM MAV_SYS_STATUS_SENSOR LOAD uint16 // Maximum usage in percent of the mainloop time, (0%: 0, 100%: 1000) should be always below 1000 VOLTAGE_BATTERY uint16 // Battery voltage, in millivolts (1 = 1 millivolt) CURRENT_BATTERY int16 // Battery current, in 10*milliamperes (1 = 10 milliampere), -1: autopilot does not measure the current DROP_RATE_COMM uint16 // Communication drops in percent, (0%: 0, 100%: 10'000), (UART, I2C, SPI, CAN), dropped packets on all links (packets that were corrupted on reception on the MAV) ERRORS_COMM uint16 // Communication errors (UART, I2C, SPI, CAN), dropped packets on all links (packets that were corrupted on reception on the MAV) ERRORS_COUNT1 uint16 // Autopilot-specific errors ERRORS_COUNT2 uint16 // Autopilot-specific errors ERRORS_COUNT3 uint16 // Autopilot-specific errors ERRORS_COUNT4 uint16 // Autopilot-specific errors BATTERY_REMAINING int8 // Remaining battery energy: (0%: 0, 100%: 100), -1: autopilot estimate the remaining battery } // NewSysStatus returns a new SysStatus func NewSysStatus(ONBOARD_CONTROL_SENSORS_PRESENT uint32, ONBOARD_CONTROL_SENSORS_ENABLED uint32, ONBOARD_CONTROL_SENSORS_HEALTH uint32, LOAD uint16, VOLTAGE_BATTERY uint16, CURRENT_BATTERY int16, DROP_RATE_COMM uint16, ERRORS_COMM uint16, ERRORS_COUNT1 uint16, ERRORS_COUNT2 uint16, ERRORS_COUNT3 uint16, ERRORS_COUNT4 uint16, BATTERY_REMAINING int8) *SysStatus { m := SysStatus{} m.ONBOARD_CONTROL_SENSORS_PRESENT = ONBOARD_CONTROL_SENSORS_PRESENT m.ONBOARD_CONTROL_SENSORS_ENABLED = ONBOARD_CONTROL_SENSORS_ENABLED m.ONBOARD_CONTROL_SENSORS_HEALTH = ONBOARD_CONTROL_SENSORS_HEALTH m.LOAD = LOAD m.VOLTAGE_BATTERY = VOLTAGE_BATTERY m.CURRENT_BATTERY = CURRENT_BATTERY m.DROP_RATE_COMM = DROP_RATE_COMM m.ERRORS_COMM = ERRORS_COMM m.ERRORS_COUNT1 = ERRORS_COUNT1 m.ERRORS_COUNT2 = ERRORS_COUNT2 m.ERRORS_COUNT3 = ERRORS_COUNT3 m.ERRORS_COUNT4 = ERRORS_COUNT4 m.BATTERY_REMAINING = BATTERY_REMAINING return &m } // Id returns the SysStatus Message ID func (*SysStatus) Id() uint8 { return 1 } // Len returns the SysStatus Message Length func (*SysStatus) Len() uint8 { return 31 } // Crc returns the SysStatus Message CRC func (*SysStatus) Crc() uint8 { return 124 } // Pack returns a packed byte array which represents a SysStatus payload func (m *SysStatus) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.ONBOARD_CONTROL_SENSORS_PRESENT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ONBOARD_CONTROL_SENSORS_ENABLED); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ONBOARD_CONTROL_SENSORS_HEALTH); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.LOAD); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VOLTAGE_BATTERY); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CURRENT_BATTERY); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.DROP_RATE_COMM); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ERRORS_COMM); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ERRORS_COUNT1); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ERRORS_COUNT2); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ERRORS_COUNT3); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ERRORS_COUNT4); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.BATTERY_REMAINING); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the SysStatus func (m *SysStatus) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.ONBOARD_CONTROL_SENSORS_PRESENT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ONBOARD_CONTROL_SENSORS_ENABLED); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ONBOARD_CONTROL_SENSORS_HEALTH); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.LOAD); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VOLTAGE_BATTERY); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CURRENT_BATTERY); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.DROP_RATE_COMM); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ERRORS_COMM); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ERRORS_COUNT1); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ERRORS_COUNT2); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ERRORS_COUNT3); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ERRORS_COUNT4); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.BATTERY_REMAINING); err != nil { panic(err) } } // MESSAGE SYSTEM_TIME // // MAVLINK_MSG_ID_SYSTEM_TIME 2 // // MAVLINK_MSG_ID_SYSTEM_TIME_LEN 12 // // MAVLINK_MSG_ID_SYSTEM_TIME_CRC 137 type SystemTime struct { TIME_UNIX_USEC uint64 // Timestamp of the primary reference clock in microseconds since UNIX epoch. TIME_BOOT_MS uint32 // Timestamp of the component clock since boot time in milliseconds. } // NewSystemTime returns a new SystemTime func NewSystemTime(TIME_UNIX_USEC uint64, TIME_BOOT_MS uint32) *SystemTime { m := SystemTime{} m.TIME_UNIX_USEC = TIME_UNIX_USEC m.TIME_BOOT_MS = TIME_BOOT_MS return &m } // Id returns the SystemTime Message ID func (*SystemTime) Id() uint8 { return 2 } // Len returns the SystemTime Message Length func (*SystemTime) Len() uint8 { return 12 } // Crc returns the SystemTime Message CRC func (*SystemTime) Crc() uint8 { return 137 } // Pack returns a packed byte array which represents a SystemTime payload func (m *SystemTime) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TIME_UNIX_USEC); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TIME_BOOT_MS); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the SystemTime func (m *SystemTime) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TIME_UNIX_USEC); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TIME_BOOT_MS); err != nil { panic(err) } } // MESSAGE PING // // MAVLINK_MSG_ID_PING 4 // // MAVLINK_MSG_ID_PING_LEN 14 // // MAVLINK_MSG_ID_PING_CRC 237 type Ping struct { TIME_USEC uint64 // Unix timestamp in microseconds SEQ uint32 // PING sequence TARGET_SYSTEM uint8 // 0: request ping from all receiving systems, if greater than 0: message is a ping response and number is the system id of the requesting system TARGET_COMPONENT uint8 // 0: request ping from all receiving components, if greater than 0: message is a ping response and number is the system id of the requesting system } // NewPing returns a new Ping func NewPing(TIME_USEC uint64, SEQ uint32, TARGET_SYSTEM uint8, TARGET_COMPONENT uint8) *Ping { m := Ping{} m.TIME_USEC = TIME_USEC m.SEQ = SEQ m.TARGET_SYSTEM = TARGET_SYSTEM m.TARGET_COMPONENT = TARGET_COMPONENT return &m } // Id returns the Ping Message ID func (*Ping) Id() uint8 { return 4 } // Len returns the Ping Message Length func (*Ping) Len() uint8 { return 14 } // Crc returns the Ping Message CRC func (*Ping) Crc() uint8 { return 237 } // Pack returns a packed byte array which represents a Ping payload func (m *Ping) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TIME_USEC); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.SEQ); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_COMPONENT); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the Ping func (m *Ping) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TIME_USEC); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.SEQ); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_COMPONENT); err != nil { panic(err) } } // MESSAGE CHANGE_OPERATOR_CONTROL // // MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL 5 // // MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_LEN 28 // // MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_CRC 217 type ChangeOperatorControl struct { TARGET_SYSTEM uint8 // System the GCS requests control for CONTROL_REQUEST uint8 // 0: request control of this MAV, 1: Release control of this MAV VERSION uint8 // 0: key as plaintext, 1-255: future, different hashing/encryption variants. The GCS should in general use the safest mode possible initially and then gradually move down the encryption level if it gets a NACK message indicating an encryption mismatch. PASSKEY [25]uint8 // Password / Key, depending on version plaintext or encrypted. 25 or less characters, NULL terminated. The characters may involve A-Z, a-z, 0-9, and "!?,.-" } // NewChangeOperatorControl returns a new ChangeOperatorControl func NewChangeOperatorControl(TARGET_SYSTEM uint8, CONTROL_REQUEST uint8, VERSION uint8, PASSKEY [25]uint8) *ChangeOperatorControl { m := ChangeOperatorControl{} m.TARGET_SYSTEM = TARGET_SYSTEM m.CONTROL_REQUEST = CONTROL_REQUEST m.VERSION = VERSION m.PASSKEY = PASSKEY return &m } // Id returns the ChangeOperatorControl Message ID func (*ChangeOperatorControl) Id() uint8 { return 5 } // Len returns the ChangeOperatorControl Message Length func (*ChangeOperatorControl) Len() uint8 { return 28 } // Crc returns the ChangeOperatorControl Message CRC func (*ChangeOperatorControl) Crc() uint8 { return 217 } // Pack returns a packed byte array which represents a ChangeOperatorControl payload func (m *ChangeOperatorControl) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CONTROL_REQUEST); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VERSION); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PASSKEY); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the ChangeOperatorControl func (m *ChangeOperatorControl) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CONTROL_REQUEST); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VERSION); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PASSKEY); err != nil { panic(err) } } const ( MAVLINK_MSG_CHANGE_OPERATOR_CONTROL_FIELD_passkey_LEN = 25 ) // MESSAGE CHANGE_OPERATOR_CONTROL_ACK // // MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK 6 // // MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_LEN 3 // // MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_CRC 104 type ChangeOperatorControlAck struct { GCS_SYSTEM_ID uint8 // ID of the GCS this message CONTROL_REQUEST uint8 // 0: request control of this MAV, 1: Release control of this MAV ACK uint8 // 0: ACK, 1: NACK: Wrong passkey, 2: NACK: Unsupported passkey encryption method, 3: NACK: Already under control } // NewChangeOperatorControlAck returns a new ChangeOperatorControlAck func NewChangeOperatorControlAck(GCS_SYSTEM_ID uint8, CONTROL_REQUEST uint8, ACK uint8) *ChangeOperatorControlAck { m := ChangeOperatorControlAck{} m.GCS_SYSTEM_ID = GCS_SYSTEM_ID m.CONTROL_REQUEST = CONTROL_REQUEST m.ACK = ACK return &m } // Id returns the ChangeOperatorControlAck Message ID func (*ChangeOperatorControlAck) Id() uint8 { return 6 } // Len returns the ChangeOperatorControlAck Message Length func (*ChangeOperatorControlAck) Len() uint8 { return 3 } // Crc returns the ChangeOperatorControlAck Message CRC func (*ChangeOperatorControlAck) Crc() uint8 { return 104 } // Pack returns a packed byte array which represents a ChangeOperatorControlAck payload func (m *ChangeOperatorControlAck) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.GCS_SYSTEM_ID); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CONTROL_REQUEST); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ACK); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the ChangeOperatorControlAck func (m *ChangeOperatorControlAck) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.GCS_SYSTEM_ID); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CONTROL_REQUEST); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ACK); err != nil { panic(err) } } // MESSAGE AUTH_KEY // // MAVLINK_MSG_ID_AUTH_KEY 7 // // MAVLINK_MSG_ID_AUTH_KEY_LEN 32 // // MAVLINK_MSG_ID_AUTH_KEY_CRC 119 type AuthKey struct { KEY [32]uint8 // key } // NewAuthKey returns a new AuthKey func NewAuthKey(KEY [32]uint8) *AuthKey { m := AuthKey{} m.KEY = KEY return &m } // Id returns the AuthKey Message ID func (*AuthKey) Id() uint8 { return 7 } // Len returns the AuthKey Message Length func (*AuthKey) Len() uint8 { return 32 } // Crc returns the AuthKey Message CRC func (*AuthKey) Crc() uint8 { return 119 } // Pack returns a packed byte array which represents a AuthKey payload func (m *AuthKey) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.KEY); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the AuthKey func (m *AuthKey) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.KEY); err != nil { panic(err) } } const ( MAVLINK_MSG_AUTH_KEY_FIELD_key_LEN = 32 ) // MESSAGE SET_MODE // // MAVLINK_MSG_ID_SET_MODE 11 // // MAVLINK_MSG_ID_SET_MODE_LEN 6 // // MAVLINK_MSG_ID_SET_MODE_CRC 89 type SetMode struct { CUSTOM_MODE uint32 // The new autopilot-specific mode. This field can be ignored by an autopilot. TARGET_SYSTEM uint8 // The system setting the mode BASE_MODE uint8 // The new base mode } // NewSetMode returns a new SetMode func NewSetMode(CUSTOM_MODE uint32, TARGET_SYSTEM uint8, BASE_MODE uint8) *SetMode { m := SetMode{} m.CUSTOM_MODE = CUSTOM_MODE m.TARGET_SYSTEM = TARGET_SYSTEM m.BASE_MODE = BASE_MODE return &m } // Id returns the SetMode Message ID func (*SetMode) Id() uint8 { return 11 } // Len returns the SetMode Message Length func (*SetMode) Len() uint8 { return 6 } // Crc returns the SetMode Message CRC func (*SetMode) Crc() uint8 { return 89 } // Pack returns a packed byte array which represents a SetMode payload func (m *SetMode) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.CUSTOM_MODE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.BASE_MODE); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the SetMode func (m *SetMode) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.CUSTOM_MODE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.BASE_MODE); err != nil { panic(err) } } // MESSAGE PARAM_REQUEST_READ // // MAVLINK_MSG_ID_PARAM_REQUEST_READ 20 // // MAVLINK_MSG_ID_PARAM_REQUEST_READ_LEN 20 // // MAVLINK_MSG_ID_PARAM_REQUEST_READ_CRC 214 type ParamRequestRead struct { PARAM_INDEX int16 // Parameter index. Send -1 to use the param ID field as identifier (else the param id will be ignored) TARGET_SYSTEM uint8 // System ID TARGET_COMPONENT uint8 // Component ID PARAM_ID [16]uint8 // Onboard parameter id, terminated by NULL if the length is less than 16 human-readable chars and WITHOUT null termination (NULL) byte if the length is exactly 16 chars - applications have to provide 16+1 bytes storage if the ID is stored as string } // NewParamRequestRead returns a new ParamRequestRead func NewParamRequestRead(PARAM_INDEX int16, TARGET_SYSTEM uint8, TARGET_COMPONENT uint8, PARAM_ID [16]uint8) *ParamRequestRead { m := ParamRequestRead{} m.PARAM_INDEX = PARAM_INDEX m.TARGET_SYSTEM = TARGET_SYSTEM m.TARGET_COMPONENT = TARGET_COMPONENT m.PARAM_ID = PARAM_ID return &m } // Id returns the ParamRequestRead Message ID func (*ParamRequestRead) Id() uint8 { return 20 } // Len returns the ParamRequestRead Message Length func (*ParamRequestRead) Len() uint8 { return 20 } // Crc returns the ParamRequestRead Message CRC func (*ParamRequestRead) Crc() uint8 { return 214 } // Pack returns a packed byte array which represents a ParamRequestRead payload func (m *ParamRequestRead) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.PARAM_INDEX); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_COMPONENT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PARAM_ID); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the ParamRequestRead func (m *ParamRequestRead) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.PARAM_INDEX); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_COMPONENT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PARAM_ID); err != nil { panic(err) } } const ( MAVLINK_MSG_PARAM_REQUEST_READ_FIELD_param_id_LEN = 16 ) // MESSAGE PARAM_REQUEST_LIST // // MAVLINK_MSG_ID_PARAM_REQUEST_LIST 21 // // MAVLINK_MSG_ID_PARAM_REQUEST_LIST_LEN 2 // // MAVLINK_MSG_ID_PARAM_REQUEST_LIST_CRC 159 type ParamRequestList struct { TARGET_SYSTEM uint8 // System ID TARGET_COMPONENT uint8 // Component ID } // NewParamRequestList returns a new ParamRequestList func NewParamRequestList(TARGET_SYSTEM uint8, TARGET_COMPONENT uint8) *ParamRequestList { m := ParamRequestList{} m.TARGET_SYSTEM = TARGET_SYSTEM m.TARGET_COMPONENT = TARGET_COMPONENT return &m } // Id returns the ParamRequestList Message ID func (*ParamRequestList) Id() uint8 { return 21 } // Len returns the ParamRequestList Message Length func (*ParamRequestList) Len() uint8 { return 2 } // Crc returns the ParamRequestList Message CRC func (*ParamRequestList) Crc() uint8 { return 159 } // Pack returns a packed byte array which represents a ParamRequestList payload func (m *ParamRequestList) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_COMPONENT); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the ParamRequestList func (m *ParamRequestList) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_COMPONENT); err != nil { panic(err) } } // MESSAGE PARAM_VALUE // // MAVLINK_MSG_ID_PARAM_VALUE 22 // // MAVLINK_MSG_ID_PARAM_VALUE_LEN 25 // // MAVLINK_MSG_ID_PARAM_VALUE_CRC 220 type ParamValue struct { PARAM_VALUE float32 // Onboard parameter value PARAM_COUNT uint16 // Total number of onboard parameters PARAM_INDEX uint16 // Index of this onboard parameter PARAM_ID [16]uint8 // Onboard parameter id, terminated by NULL if the length is less than 16 human-readable chars and WITHOUT null termination (NULL) byte if the length is exactly 16 chars - applications have to provide 16+1 bytes storage if the ID is stored as string PARAM_TYPE uint8 // Onboard parameter type: see the MAV_PARAM_TYPE enum for supported data types. } // NewParamValue returns a new ParamValue func NewParamValue(PARAM_VALUE float32, PARAM_COUNT uint16, PARAM_INDEX uint16, PARAM_ID [16]uint8, PARAM_TYPE uint8) *ParamValue { m := ParamValue{} m.PARAM_VALUE = PARAM_VALUE m.PARAM_COUNT = PARAM_COUNT m.PARAM_INDEX = PARAM_INDEX m.PARAM_ID = PARAM_ID m.PARAM_TYPE = PARAM_TYPE return &m } // Id returns the ParamValue Message ID func (*ParamValue) Id() uint8 { return 22 } // Len returns the ParamValue Message Length func (*ParamValue) Len() uint8 { return 25 } // Crc returns the ParamValue Message CRC func (*ParamValue) Crc() uint8 { return 220 } // Pack returns a packed byte array which represents a ParamValue payload func (m *ParamValue) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.PARAM_VALUE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PARAM_COUNT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PARAM_INDEX); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PARAM_ID); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PARAM_TYPE); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the ParamValue func (m *ParamValue) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.PARAM_VALUE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PARAM_COUNT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PARAM_INDEX); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PARAM_ID); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PARAM_TYPE); err != nil { panic(err) } } const ( MAVLINK_MSG_PARAM_VALUE_FIELD_param_id_LEN = 16 ) // MESSAGE PARAM_SET // // MAVLINK_MSG_ID_PARAM_SET 23 // // MAVLINK_MSG_ID_PARAM_SET_LEN 23 // // MAVLINK_MSG_ID_PARAM_SET_CRC 168 type ParamSet struct { PARAM_VALUE float32 // Onboard parameter value TARGET_SYSTEM uint8 // System ID TARGET_COMPONENT uint8 // Component ID PARAM_ID [16]uint8 // Onboard parameter id, terminated by NULL if the length is less than 16 human-readable chars and WITHOUT null termination (NULL) byte if the length is exactly 16 chars - applications have to provide 16+1 bytes storage if the ID is stored as string PARAM_TYPE uint8 // Onboard parameter type: see the MAV_PARAM_TYPE enum for supported data types. } // NewParamSet returns a new ParamSet func NewParamSet(PARAM_VALUE float32, TARGET_SYSTEM uint8, TARGET_COMPONENT uint8, PARAM_ID [16]uint8, PARAM_TYPE uint8) *ParamSet { m := ParamSet{} m.PARAM_VALUE = PARAM_VALUE m.TARGET_SYSTEM = TARGET_SYSTEM m.TARGET_COMPONENT = TARGET_COMPONENT m.PARAM_ID = PARAM_ID m.PARAM_TYPE = PARAM_TYPE return &m } // Id returns the ParamSet Message ID func (*ParamSet) Id() uint8 { return 23 } // Len returns the ParamSet Message Length func (*ParamSet) Len() uint8 { return 23 } // Crc returns the ParamSet Message CRC func (*ParamSet) Crc() uint8 { return 168 } // Pack returns a packed byte array which represents a ParamSet payload func (m *ParamSet) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.PARAM_VALUE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_COMPONENT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PARAM_ID); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PARAM_TYPE); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the ParamSet func (m *ParamSet) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.PARAM_VALUE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_COMPONENT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PARAM_ID); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PARAM_TYPE); err != nil { panic(err) } } const ( MAVLINK_MSG_PARAM_SET_FIELD_param_id_LEN = 16 ) // MESSAGE GPS_RAW_INT // // MAVLINK_MSG_ID_GPS_RAW_INT 24 // // MAVLINK_MSG_ID_GPS_RAW_INT_LEN 30 // // MAVLINK_MSG_ID_GPS_RAW_INT_CRC 24 type GpsRawInt struct { TIME_USEC uint64 // Timestamp (microseconds since UNIX epoch or microseconds since system boot) LAT int32 // Latitude (WGS84), in degrees * 1E7 LON int32 // Longitude (WGS84), in degrees * 1E7 ALT int32 // Altitude (WGS84), in meters * 1000 (positive for up) EPH uint16 // GPS HDOP horizontal dilution of position in cm (m*100). If unknown, set to: UINT16_MAX EPV uint16 // GPS VDOP vertical dilution of position in cm (m*100). If unknown, set to: UINT16_MAX VEL uint16 // GPS ground speed (m/s * 100). If unknown, set to: UINT16_MAX COG uint16 // Course over ground (NOT heading, but direction of movement) in degrees * 100, 0.0..359.99 degrees. If unknown, set to: UINT16_MAX FIX_TYPE uint8 // 0-1: no fix, 2: 2D fix, 3: 3D fix, 4: DGPS, 5: RTK. Some applications will not use the value of this field unless it is at least two, so always correctly fill in the fix. SATELLITES_VISIBLE uint8 // Number of satellites visible. If unknown, set to 255 } // NewGpsRawInt returns a new GpsRawInt func NewGpsRawInt(TIME_USEC uint64, LAT int32, LON int32, ALT int32, EPH uint16, EPV uint16, VEL uint16, COG uint16, FIX_TYPE uint8, SATELLITES_VISIBLE uint8) *GpsRawInt { m := GpsRawInt{} m.TIME_USEC = TIME_USEC m.LAT = LAT m.LON = LON m.ALT = ALT m.EPH = EPH m.EPV = EPV m.VEL = VEL m.COG = COG m.FIX_TYPE = FIX_TYPE m.SATELLITES_VISIBLE = SATELLITES_VISIBLE return &m } // Id returns the GpsRawInt Message ID func (*GpsRawInt) Id() uint8 { return 24 } // Len returns the GpsRawInt Message Length func (*GpsRawInt) Len() uint8 { return 30 } // Crc returns the GpsRawInt Message CRC func (*GpsRawInt) Crc() uint8 { return 24 } // Pack returns a packed byte array which represents a GpsRawInt payload func (m *GpsRawInt) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TIME_USEC); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.LAT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.LON); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ALT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.EPH); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.EPV); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VEL); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.COG); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.FIX_TYPE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.SATELLITES_VISIBLE); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the GpsRawInt func (m *GpsRawInt) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TIME_USEC); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.LAT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.LON); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ALT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.EPH); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.EPV); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VEL); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.COG); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.FIX_TYPE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.SATELLITES_VISIBLE); err != nil { panic(err) } } // MESSAGE GPS_STATUS // // MAVLINK_MSG_ID_GPS_STATUS 25 // // MAVLINK_MSG_ID_GPS_STATUS_LEN 101 // // MAVLINK_MSG_ID_GPS_STATUS_CRC 23 type GpsStatus struct { SATELLITES_VISIBLE uint8 // Number of satellites visible SATELLITE_PRN [20]uint8 // Global satellite ID SATELLITE_USED [20]uint8 // 0: Satellite not used, 1: used for localization SATELLITE_ELEVATION [20]uint8 // Elevation (0: right on top of receiver, 90: on the horizon) of satellite SATELLITE_AZIMUTH [20]uint8 // Direction of satellite, 0: 0 deg, 255: 360 deg. SATELLITE_SNR [20]uint8 // Signal to noise ratio of satellite } // NewGpsStatus returns a new GpsStatus func NewGpsStatus(SATELLITES_VISIBLE uint8, SATELLITE_PRN [20]uint8, SATELLITE_USED [20]uint8, SATELLITE_ELEVATION [20]uint8, SATELLITE_AZIMUTH [20]uint8, SATELLITE_SNR [20]uint8) *GpsStatus { m := GpsStatus{} m.SATELLITES_VISIBLE = SATELLITES_VISIBLE m.SATELLITE_PRN = SATELLITE_PRN m.SATELLITE_USED = SATELLITE_USED m.SATELLITE_ELEVATION = SATELLITE_ELEVATION m.SATELLITE_AZIMUTH = SATELLITE_AZIMUTH m.SATELLITE_SNR = SATELLITE_SNR return &m } // Id returns the GpsStatus Message ID func (*GpsStatus) Id() uint8 { return 25 } // Len returns the GpsStatus Message Length func (*GpsStatus) Len() uint8 { return 101 } // Crc returns the GpsStatus Message CRC func (*GpsStatus) Crc() uint8 { return 23 } // Pack returns a packed byte array which represents a GpsStatus payload func (m *GpsStatus) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.SATELLITES_VISIBLE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.SATELLITE_PRN); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.SATELLITE_USED); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.SATELLITE_ELEVATION); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.SATELLITE_AZIMUTH); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.SATELLITE_SNR); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the GpsStatus func (m *GpsStatus) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.SATELLITES_VISIBLE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.SATELLITE_PRN); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.SATELLITE_USED); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.SATELLITE_ELEVATION); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.SATELLITE_AZIMUTH); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.SATELLITE_SNR); err != nil { panic(err) } } const ( MAVLINK_MSG_GPS_STATUS_FIELD_satellite_prn_LEN = 20 MAVLINK_MSG_GPS_STATUS_FIELD_satellite_used_LEN = 20 MAVLINK_MSG_GPS_STATUS_FIELD_satellite_elevation_LEN = 20 MAVLINK_MSG_GPS_STATUS_FIELD_satellite_azimuth_LEN = 20 MAVLINK_MSG_GPS_STATUS_FIELD_satellite_snr_LEN = 20 ) // MESSAGE SCALED_IMU // // MAVLINK_MSG_ID_SCALED_IMU 26 // // MAVLINK_MSG_ID_SCALED_IMU_LEN 22 // // MAVLINK_MSG_ID_SCALED_IMU_CRC 170 type ScaledImu struct { TIME_BOOT_MS uint32 // Timestamp (milliseconds since system boot) XACC int16 // X acceleration (mg) YACC int16 // Y acceleration (mg) ZACC int16 // Z acceleration (mg) XGYRO int16 // Angular speed around X axis (millirad /sec) YGYRO int16 // Angular speed around Y axis (millirad /sec) ZGYRO int16 // Angular speed around Z axis (millirad /sec) XMAG int16 // X Magnetic field (milli tesla) YMAG int16 // Y Magnetic field (milli tesla) ZMAG int16 // Z Magnetic field (milli tesla) } // NewScaledImu returns a new ScaledImu func NewScaledImu(TIME_BOOT_MS uint32, XACC int16, YACC int16, ZACC int16, XGYRO int16, YGYRO int16, ZGYRO int16, XMAG int16, YMAG int16, ZMAG int16) *ScaledImu { m := ScaledImu{} m.TIME_BOOT_MS = TIME_BOOT_MS m.XACC = XACC m.YACC = YACC m.ZACC = ZACC m.XGYRO = XGYRO m.YGYRO = YGYRO m.ZGYRO = ZGYRO m.XMAG = XMAG m.YMAG = YMAG m.ZMAG = ZMAG return &m } // Id returns the ScaledImu Message ID func (*ScaledImu) Id() uint8 { return 26 } // Len returns the ScaledImu Message Length func (*ScaledImu) Len() uint8 { return 22 } // Crc returns the ScaledImu Message CRC func (*ScaledImu) Crc() uint8 { return 170 } // Pack returns a packed byte array which represents a ScaledImu payload func (m *ScaledImu) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TIME_BOOT_MS); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.XACC); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.YACC); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ZACC); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.XGYRO); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.YGYRO); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ZGYRO); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.XMAG); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.YMAG); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ZMAG); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the ScaledImu func (m *ScaledImu) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TIME_BOOT_MS); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.XACC); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.YACC); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ZACC); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.XGYRO); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.YGYRO); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ZGYRO); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.XMAG); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.YMAG); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ZMAG); err != nil { panic(err) } } // MESSAGE RAW_IMU // // MAVLINK_MSG_ID_RAW_IMU 27 // // MAVLINK_MSG_ID_RAW_IMU_LEN 26 // // MAVLINK_MSG_ID_RAW_IMU_CRC 144 type RawImu struct { TIME_USEC uint64 // Timestamp (microseconds since UNIX epoch or microseconds since system boot) XACC int16 // X acceleration (raw) YACC int16 // Y acceleration (raw) ZACC int16 // Z acceleration (raw) XGYRO int16 // Angular speed around X axis (raw) YGYRO int16 // Angular speed around Y axis (raw) ZGYRO int16 // Angular speed around Z axis (raw) XMAG int16 // X Magnetic field (raw) YMAG int16 // Y Magnetic field (raw) ZMAG int16 // Z Magnetic field (raw) } // NewRawImu returns a new RawImu func NewRawImu(TIME_USEC uint64, XACC int16, YACC int16, ZACC int16, XGYRO int16, YGYRO int16, ZGYRO int16, XMAG int16, YMAG int16, ZMAG int16) *RawImu { m := RawImu{} m.TIME_USEC = TIME_USEC m.XACC = XACC m.YACC = YACC m.ZACC = ZACC m.XGYRO = XGYRO m.YGYRO = YGYRO m.ZGYRO = ZGYRO m.XMAG = XMAG m.YMAG = YMAG m.ZMAG = ZMAG return &m } // Id returns the RawImu Message ID func (*RawImu) Id() uint8 { return 27 } // Len returns the RawImu Message Length func (*RawImu) Len() uint8 { return 26 } // Crc returns the RawImu Message CRC func (*RawImu) Crc() uint8 { return 144 } // Pack returns a packed byte array which represents a RawImu payload func (m *RawImu) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TIME_USEC); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.XACC); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.YACC); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ZACC); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.XGYRO); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.YGYRO); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ZGYRO); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.XMAG); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.YMAG); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ZMAG); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the RawImu func (m *RawImu) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TIME_USEC); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.XACC); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.YACC); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ZACC); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.XGYRO); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.YGYRO); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ZGYRO); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.XMAG); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.YMAG); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ZMAG); err != nil { panic(err) } } // MESSAGE RAW_PRESSURE // // MAVLINK_MSG_ID_RAW_PRESSURE 28 // // MAVLINK_MSG_ID_RAW_PRESSURE_LEN 16 // // MAVLINK_MSG_ID_RAW_PRESSURE_CRC 67 type RawPressure struct { TIME_USEC uint64 // Timestamp (microseconds since UNIX epoch or microseconds since system boot) PRESS_ABS int16 // Absolute pressure (raw) PRESS_DIFF1 int16 // Differential pressure 1 (raw) PRESS_DIFF2 int16 // Differential pressure 2 (raw) TEMPERATURE int16 // Raw Temperature measurement (raw) } // NewRawPressure returns a new RawPressure func NewRawPressure(TIME_USEC uint64, PRESS_ABS int16, PRESS_DIFF1 int16, PRESS_DIFF2 int16, TEMPERATURE int16) *RawPressure { m := RawPressure{} m.TIME_USEC = TIME_USEC m.PRESS_ABS = PRESS_ABS m.PRESS_DIFF1 = PRESS_DIFF1 m.PRESS_DIFF2 = PRESS_DIFF2 m.TEMPERATURE = TEMPERATURE return &m } // Id returns the RawPressure Message ID func (*RawPressure) Id() uint8 { return 28 } // Len returns the RawPressure Message Length func (*RawPressure) Len() uint8 { return 16 } // Crc returns the RawPressure Message CRC func (*RawPressure) Crc() uint8 { return 67 } // Pack returns a packed byte array which represents a RawPressure payload func (m *RawPressure) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TIME_USEC); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PRESS_ABS); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PRESS_DIFF1); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PRESS_DIFF2); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TEMPERATURE); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the RawPressure func (m *RawPressure) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TIME_USEC); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PRESS_ABS); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PRESS_DIFF1); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PRESS_DIFF2); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TEMPERATURE); err != nil { panic(err) } } // MESSAGE SCALED_PRESSURE // // MAVLINK_MSG_ID_SCALED_PRESSURE 29 // // MAVLINK_MSG_ID_SCALED_PRESSURE_LEN 14 // // MAVLINK_MSG_ID_SCALED_PRESSURE_CRC 115 type ScaledPressure struct { TIME_BOOT_MS uint32 // Timestamp (milliseconds since system boot) PRESS_ABS float32 // Absolute pressure (hectopascal) PRESS_DIFF float32 // Differential pressure 1 (hectopascal) TEMPERATURE int16 // Temperature measurement (0.01 degrees celsius) } // NewScaledPressure returns a new ScaledPressure func NewScaledPressure(TIME_BOOT_MS uint32, PRESS_ABS float32, PRESS_DIFF float32, TEMPERATURE int16) *ScaledPressure { m := ScaledPressure{} m.TIME_BOOT_MS = TIME_BOOT_MS m.PRESS_ABS = PRESS_ABS m.PRESS_DIFF = PRESS_DIFF m.TEMPERATURE = TEMPERATURE return &m } // Id returns the ScaledPressure Message ID func (*ScaledPressure) Id() uint8 { return 29 } // Len returns the ScaledPressure Message Length func (*ScaledPressure) Len() uint8 { return 14 } // Crc returns the ScaledPressure Message CRC func (*ScaledPressure) Crc() uint8 { return 115 } // Pack returns a packed byte array which represents a ScaledPressure payload func (m *ScaledPressure) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TIME_BOOT_MS); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PRESS_ABS); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PRESS_DIFF); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TEMPERATURE); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the ScaledPressure func (m *ScaledPressure) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TIME_BOOT_MS); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PRESS_ABS); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PRESS_DIFF); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TEMPERATURE); err != nil { panic(err) } } // MESSAGE ATTITUDE // // MAVLINK_MSG_ID_ATTITUDE 30 // // MAVLINK_MSG_ID_ATTITUDE_LEN 28 // // MAVLINK_MSG_ID_ATTITUDE_CRC 39 type Attitude struct { TIME_BOOT_MS uint32 // Timestamp (milliseconds since system boot) ROLL float32 // Roll angle (rad, -pi..+pi) PITCH float32 // Pitch angle (rad, -pi..+pi) YAW float32 // Yaw angle (rad, -pi..+pi) ROLLSPEED float32 // Roll angular speed (rad/s) PITCHSPEED float32 // Pitch angular speed (rad/s) YAWSPEED float32 // Yaw angular speed (rad/s) } // NewAttitude returns a new Attitude func NewAttitude(TIME_BOOT_MS uint32, ROLL float32, PITCH float32, YAW float32, ROLLSPEED float32, PITCHSPEED float32, YAWSPEED float32) *Attitude { m := Attitude{} m.TIME_BOOT_MS = TIME_BOOT_MS m.ROLL = ROLL m.PITCH = PITCH m.YAW = YAW m.ROLLSPEED = ROLLSPEED m.PITCHSPEED = PITCHSPEED m.YAWSPEED = YAWSPEED return &m } // Id returns the Attitude Message ID func (*Attitude) Id() uint8 { return 30 } // Len returns the Attitude Message Length func (*Attitude) Len() uint8 { return 28 } // Crc returns the Attitude Message CRC func (*Attitude) Crc() uint8 { return 39 } // Pack returns a packed byte array which represents a Attitude payload func (m *Attitude) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TIME_BOOT_MS); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ROLL); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PITCH); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.YAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ROLLSPEED); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PITCHSPEED); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.YAWSPEED); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the Attitude func (m *Attitude) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TIME_BOOT_MS); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ROLL); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PITCH); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.YAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ROLLSPEED); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PITCHSPEED); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.YAWSPEED); err != nil { panic(err) } } // MESSAGE ATTITUDE_QUATERNION // // MAVLINK_MSG_ID_ATTITUDE_QUATERNION 31 // // MAVLINK_MSG_ID_ATTITUDE_QUATERNION_LEN 32 // // MAVLINK_MSG_ID_ATTITUDE_QUATERNION_CRC 246 type AttitudeQuaternion struct { TIME_BOOT_MS uint32 // Timestamp (milliseconds since system boot) Q1 float32 // Quaternion component 1, w (1 in null-rotation) Q2 float32 // Quaternion component 2, x (0 in null-rotation) Q3 float32 // Quaternion component 3, y (0 in null-rotation) Q4 float32 // Quaternion component 4, z (0 in null-rotation) ROLLSPEED float32 // Roll angular speed (rad/s) PITCHSPEED float32 // Pitch angular speed (rad/s) YAWSPEED float32 // Yaw angular speed (rad/s) } // NewAttitudeQuaternion returns a new AttitudeQuaternion func NewAttitudeQuaternion(TIME_BOOT_MS uint32, Q1 float32, Q2 float32, Q3 float32, Q4 float32, ROLLSPEED float32, PITCHSPEED float32, YAWSPEED float32) *AttitudeQuaternion { m := AttitudeQuaternion{} m.TIME_BOOT_MS = TIME_BOOT_MS m.Q1 = Q1 m.Q2 = Q2 m.Q3 = Q3 m.Q4 = Q4 m.ROLLSPEED = ROLLSPEED m.PITCHSPEED = PITCHSPEED m.YAWSPEED = YAWSPEED return &m } // Id returns the AttitudeQuaternion Message ID func (*AttitudeQuaternion) Id() uint8 { return 31 } // Len returns the AttitudeQuaternion Message Length func (*AttitudeQuaternion) Len() uint8 { return 32 } // Crc returns the AttitudeQuaternion Message CRC func (*AttitudeQuaternion) Crc() uint8 { return 246 } // Pack returns a packed byte array which represents a AttitudeQuaternion payload func (m *AttitudeQuaternion) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TIME_BOOT_MS); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.Q1); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.Q2); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.Q3); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.Q4); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ROLLSPEED); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PITCHSPEED); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.YAWSPEED); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the AttitudeQuaternion func (m *AttitudeQuaternion) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TIME_BOOT_MS); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.Q1); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.Q2); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.Q3); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.Q4); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ROLLSPEED); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PITCHSPEED); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.YAWSPEED); err != nil { panic(err) } } // MESSAGE LOCAL_POSITION_NED // // MAVLINK_MSG_ID_LOCAL_POSITION_NED 32 // // MAVLINK_MSG_ID_LOCAL_POSITION_NED_LEN 28 // // MAVLINK_MSG_ID_LOCAL_POSITION_NED_CRC 185 type LocalPositionNed struct { TIME_BOOT_MS uint32 // Timestamp (milliseconds since system boot) X float32 // X Position Y float32 // Y Position Z float32 // Z Position VX float32 // X Speed VY float32 // Y Speed VZ float32 // Z Speed } // NewLocalPositionNed returns a new LocalPositionNed func NewLocalPositionNed(TIME_BOOT_MS uint32, X float32, Y float32, Z float32, VX float32, VY float32, VZ float32) *LocalPositionNed { m := LocalPositionNed{} m.TIME_BOOT_MS = TIME_BOOT_MS m.X = X m.Y = Y m.Z = Z m.VX = VX m.VY = VY m.VZ = VZ return &m } // Id returns the LocalPositionNed Message ID func (*LocalPositionNed) Id() uint8 { return 32 } // Len returns the LocalPositionNed Message Length func (*LocalPositionNed) Len() uint8 { return 28 } // Crc returns the LocalPositionNed Message CRC func (*LocalPositionNed) Crc() uint8 { return 185 } // Pack returns a packed byte array which represents a LocalPositionNed payload func (m *LocalPositionNed) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TIME_BOOT_MS); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.X); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.Y); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.Z); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VX); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VY); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VZ); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the LocalPositionNed func (m *LocalPositionNed) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TIME_BOOT_MS); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.X); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.Y); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.Z); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VX); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VY); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VZ); err != nil { panic(err) } } // MESSAGE GLOBAL_POSITION_INT // // MAVLINK_MSG_ID_GLOBAL_POSITION_INT 33 // // MAVLINK_MSG_ID_GLOBAL_POSITION_INT_LEN 28 // // MAVLINK_MSG_ID_GLOBAL_POSITION_INT_CRC 104 type GlobalPositionInt struct { TIME_BOOT_MS uint32 // Timestamp (milliseconds since system boot) LAT int32 // Latitude, expressed as * 1E7 LON int32 // Longitude, expressed as * 1E7 ALT int32 // Altitude in meters, expressed as * 1000 (millimeters), above MSL RELATIVE_ALT int32 // Altitude above ground in meters, expressed as * 1000 (millimeters) VX int16 // Ground X Speed (Latitude), expressed as m/s * 100 VY int16 // Ground Y Speed (Longitude), expressed as m/s * 100 VZ int16 // Ground Z Speed (Altitude), expressed as m/s * 100 HDG uint16 // Compass heading in degrees * 100, 0.0..359.99 degrees. If unknown, set to: UINT16_MAX } // NewGlobalPositionInt returns a new GlobalPositionInt func NewGlobalPositionInt(TIME_BOOT_MS uint32, LAT int32, LON int32, ALT int32, RELATIVE_ALT int32, VX int16, VY int16, VZ int16, HDG uint16) *GlobalPositionInt { m := GlobalPositionInt{} m.TIME_BOOT_MS = TIME_BOOT_MS m.LAT = LAT m.LON = LON m.ALT = ALT m.RELATIVE_ALT = RELATIVE_ALT m.VX = VX m.VY = VY m.VZ = VZ m.HDG = HDG return &m } // Id returns the GlobalPositionInt Message ID func (*GlobalPositionInt) Id() uint8 { return 33 } // Len returns the GlobalPositionInt Message Length func (*GlobalPositionInt) Len() uint8 { return 28 } // Crc returns the GlobalPositionInt Message CRC func (*GlobalPositionInt) Crc() uint8 { return 104 } // Pack returns a packed byte array which represents a GlobalPositionInt payload func (m *GlobalPositionInt) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TIME_BOOT_MS); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.LAT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.LON); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ALT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.RELATIVE_ALT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VX); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VY); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VZ); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.HDG); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the GlobalPositionInt func (m *GlobalPositionInt) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TIME_BOOT_MS); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.LAT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.LON); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ALT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.RELATIVE_ALT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VX); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VY); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VZ); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.HDG); err != nil { panic(err) } } // MESSAGE RC_CHANNELS_SCALED // // MAVLINK_MSG_ID_RC_CHANNELS_SCALED 34 // // MAVLINK_MSG_ID_RC_CHANNELS_SCALED_LEN 22 // // MAVLINK_MSG_ID_RC_CHANNELS_SCALED_CRC 237 type RcChannelsScaled struct { TIME_BOOT_MS uint32 // Timestamp (milliseconds since system boot) CHAN1_SCALED int16 // RC channel 1 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. CHAN2_SCALED int16 // RC channel 2 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. CHAN3_SCALED int16 // RC channel 3 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. CHAN4_SCALED int16 // RC channel 4 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. CHAN5_SCALED int16 // RC channel 5 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. CHAN6_SCALED int16 // RC channel 6 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. CHAN7_SCALED int16 // RC channel 7 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. CHAN8_SCALED int16 // RC channel 8 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. PORT uint8 // Servo output port (set of 8 outputs = 1 port). Most MAVs will just use one, but this allows for more than 8 servos. RSSI uint8 // Receive signal strength indicator, 0: 0%, 100: 100%, 255: invalid/unknown. } // NewRcChannelsScaled returns a new RcChannelsScaled func NewRcChannelsScaled(TIME_BOOT_MS uint32, CHAN1_SCALED int16, CHAN2_SCALED int16, CHAN3_SCALED int16, CHAN4_SCALED int16, CHAN5_SCALED int16, CHAN6_SCALED int16, CHAN7_SCALED int16, CHAN8_SCALED int16, PORT uint8, RSSI uint8) *RcChannelsScaled { m := RcChannelsScaled{} m.TIME_BOOT_MS = TIME_BOOT_MS m.CHAN1_SCALED = CHAN1_SCALED m.CHAN2_SCALED = CHAN2_SCALED m.CHAN3_SCALED = CHAN3_SCALED m.CHAN4_SCALED = CHAN4_SCALED m.CHAN5_SCALED = CHAN5_SCALED m.CHAN6_SCALED = CHAN6_SCALED m.CHAN7_SCALED = CHAN7_SCALED m.CHAN8_SCALED = CHAN8_SCALED m.PORT = PORT m.RSSI = RSSI return &m } // Id returns the RcChannelsScaled Message ID func (*RcChannelsScaled) Id() uint8 { return 34 } // Len returns the RcChannelsScaled Message Length func (*RcChannelsScaled) Len() uint8 { return 22 } // Crc returns the RcChannelsScaled Message CRC func (*RcChannelsScaled) Crc() uint8 { return 237 } // Pack returns a packed byte array which represents a RcChannelsScaled payload func (m *RcChannelsScaled) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TIME_BOOT_MS); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN1_SCALED); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN2_SCALED); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN3_SCALED); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN4_SCALED); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN5_SCALED); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN6_SCALED); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN7_SCALED); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN8_SCALED); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PORT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.RSSI); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the RcChannelsScaled func (m *RcChannelsScaled) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TIME_BOOT_MS); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN1_SCALED); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN2_SCALED); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN3_SCALED); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN4_SCALED); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN5_SCALED); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN6_SCALED); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN7_SCALED); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN8_SCALED); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PORT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.RSSI); err != nil { panic(err) } } // MESSAGE RC_CHANNELS_RAW // // MAVLINK_MSG_ID_RC_CHANNELS_RAW 35 // // MAVLINK_MSG_ID_RC_CHANNELS_RAW_LEN 22 // // MAVLINK_MSG_ID_RC_CHANNELS_RAW_CRC 244 type RcChannelsRaw struct { TIME_BOOT_MS uint32 // Timestamp (milliseconds since system boot) CHAN1_RAW uint16 // RC channel 1 value, in microseconds. A value of UINT16_MAX implies the channel is unused. CHAN2_RAW uint16 // RC channel 2 value, in microseconds. A value of UINT16_MAX implies the channel is unused. CHAN3_RAW uint16 // RC channel 3 value, in microseconds. A value of UINT16_MAX implies the channel is unused. CHAN4_RAW uint16 // RC channel 4 value, in microseconds. A value of UINT16_MAX implies the channel is unused. CHAN5_RAW uint16 // RC channel 5 value, in microseconds. A value of UINT16_MAX implies the channel is unused. CHAN6_RAW uint16 // RC channel 6 value, in microseconds. A value of UINT16_MAX implies the channel is unused. CHAN7_RAW uint16 // RC channel 7 value, in microseconds. A value of UINT16_MAX implies the channel is unused. CHAN8_RAW uint16 // RC channel 8 value, in microseconds. A value of UINT16_MAX implies the channel is unused. PORT uint8 // Servo output port (set of 8 outputs = 1 port). Most MAVs will just use one, but this allows for more than 8 servos. RSSI uint8 // Receive signal strength indicator, 0: 0%, 100: 100%, 255: invalid/unknown. } // NewRcChannelsRaw returns a new RcChannelsRaw func NewRcChannelsRaw(TIME_BOOT_MS uint32, CHAN1_RAW uint16, CHAN2_RAW uint16, CHAN3_RAW uint16, CHAN4_RAW uint16, CHAN5_RAW uint16, CHAN6_RAW uint16, CHAN7_RAW uint16, CHAN8_RAW uint16, PORT uint8, RSSI uint8) *RcChannelsRaw { m := RcChannelsRaw{} m.TIME_BOOT_MS = TIME_BOOT_MS m.CHAN1_RAW = CHAN1_RAW m.CHAN2_RAW = CHAN2_RAW m.CHAN3_RAW = CHAN3_RAW m.CHAN4_RAW = CHAN4_RAW m.CHAN5_RAW = CHAN5_RAW m.CHAN6_RAW = CHAN6_RAW m.CHAN7_RAW = CHAN7_RAW m.CHAN8_RAW = CHAN8_RAW m.PORT = PORT m.RSSI = RSSI return &m } // Id returns the RcChannelsRaw Message ID func (*RcChannelsRaw) Id() uint8 { return 35 } // Len returns the RcChannelsRaw Message Length func (*RcChannelsRaw) Len() uint8 { return 22 } // Crc returns the RcChannelsRaw Message CRC func (*RcChannelsRaw) Crc() uint8 { return 244 } // Pack returns a packed byte array which represents a RcChannelsRaw payload func (m *RcChannelsRaw) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TIME_BOOT_MS); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN1_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN2_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN3_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN4_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN5_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN6_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN7_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN8_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PORT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.RSSI); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the RcChannelsRaw func (m *RcChannelsRaw) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TIME_BOOT_MS); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN1_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN2_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN3_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN4_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN5_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN6_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN7_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN8_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PORT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.RSSI); err != nil { panic(err) } } // MESSAGE SERVO_OUTPUT_RAW // // MAVLINK_MSG_ID_SERVO_OUTPUT_RAW 36 // // MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_LEN 21 // // MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_CRC 222 type ServoOutputRaw struct { TIME_USEC uint32 // Timestamp (microseconds since system boot) SERVO1_RAW uint16 // Servo output 1 value, in microseconds SERVO2_RAW uint16 // Servo output 2 value, in microseconds SERVO3_RAW uint16 // Servo output 3 value, in microseconds SERVO4_RAW uint16 // Servo output 4 value, in microseconds SERVO5_RAW uint16 // Servo output 5 value, in microseconds SERVO6_RAW uint16 // Servo output 6 value, in microseconds SERVO7_RAW uint16 // Servo output 7 value, in microseconds SERVO8_RAW uint16 // Servo output 8 value, in microseconds PORT uint8 // Servo output port (set of 8 outputs = 1 port). Most MAVs will just use one, but this allows to encode more than 8 servos. } // NewServoOutputRaw returns a new ServoOutputRaw func NewServoOutputRaw(TIME_USEC uint32, SERVO1_RAW uint16, SERVO2_RAW uint16, SERVO3_RAW uint16, SERVO4_RAW uint16, SERVO5_RAW uint16, SERVO6_RAW uint16, SERVO7_RAW uint16, SERVO8_RAW uint16, PORT uint8) *ServoOutputRaw { m := ServoOutputRaw{} m.TIME_USEC = TIME_USEC m.SERVO1_RAW = SERVO1_RAW m.SERVO2_RAW = SERVO2_RAW m.SERVO3_RAW = SERVO3_RAW m.SERVO4_RAW = SERVO4_RAW m.SERVO5_RAW = SERVO5_RAW m.SERVO6_RAW = SERVO6_RAW m.SERVO7_RAW = SERVO7_RAW m.SERVO8_RAW = SERVO8_RAW m.PORT = PORT return &m } // Id returns the ServoOutputRaw Message ID func (*ServoOutputRaw) Id() uint8 { return 36 } // Len returns the ServoOutputRaw Message Length func (*ServoOutputRaw) Len() uint8 { return 21 } // Crc returns the ServoOutputRaw Message CRC func (*ServoOutputRaw) Crc() uint8 { return 222 } // Pack returns a packed byte array which represents a ServoOutputRaw payload func (m *ServoOutputRaw) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TIME_USEC); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.SERVO1_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.SERVO2_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.SERVO3_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.SERVO4_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.SERVO5_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.SERVO6_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.SERVO7_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.SERVO8_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PORT); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the ServoOutputRaw func (m *ServoOutputRaw) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TIME_USEC); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.SERVO1_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.SERVO2_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.SERVO3_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.SERVO4_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.SERVO5_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.SERVO6_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.SERVO7_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.SERVO8_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PORT); err != nil { panic(err) } } // MESSAGE MISSION_REQUEST_PARTIAL_LIST // // MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST 37 // // MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_LEN 6 // // MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_CRC 212 type MissionRequestPartialList struct { START_INDEX int16 // Start index, 0 by default END_INDEX int16 // End index, -1 by default (-1: send list to end). Else a valid index of the list TARGET_SYSTEM uint8 // System ID TARGET_COMPONENT uint8 // Component ID } // NewMissionRequestPartialList returns a new MissionRequestPartialList func NewMissionRequestPartialList(START_INDEX int16, END_INDEX int16, TARGET_SYSTEM uint8, TARGET_COMPONENT uint8) *MissionRequestPartialList { m := MissionRequestPartialList{} m.START_INDEX = START_INDEX m.END_INDEX = END_INDEX m.TARGET_SYSTEM = TARGET_SYSTEM m.TARGET_COMPONENT = TARGET_COMPONENT return &m } // Id returns the MissionRequestPartialList Message ID func (*MissionRequestPartialList) Id() uint8 { return 37 } // Len returns the MissionRequestPartialList Message Length func (*MissionRequestPartialList) Len() uint8 { return 6 } // Crc returns the MissionRequestPartialList Message CRC func (*MissionRequestPartialList) Crc() uint8 { return 212 } // Pack returns a packed byte array which represents a MissionRequestPartialList payload func (m *MissionRequestPartialList) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.START_INDEX); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.END_INDEX); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_COMPONENT); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the MissionRequestPartialList func (m *MissionRequestPartialList) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.START_INDEX); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.END_INDEX); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_COMPONENT); err != nil { panic(err) } } // MESSAGE MISSION_WRITE_PARTIAL_LIST // // MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST 38 // // MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_LEN 6 // // MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_CRC 9 type MissionWritePartialList struct { START_INDEX int16 // Start index, 0 by default and smaller / equal to the largest index of the current onboard list. END_INDEX int16 // End index, equal or greater than start index. TARGET_SYSTEM uint8 // System ID TARGET_COMPONENT uint8 // Component ID } // NewMissionWritePartialList returns a new MissionWritePartialList func NewMissionWritePartialList(START_INDEX int16, END_INDEX int16, TARGET_SYSTEM uint8, TARGET_COMPONENT uint8) *MissionWritePartialList { m := MissionWritePartialList{} m.START_INDEX = START_INDEX m.END_INDEX = END_INDEX m.TARGET_SYSTEM = TARGET_SYSTEM m.TARGET_COMPONENT = TARGET_COMPONENT return &m } // Id returns the MissionWritePartialList Message ID func (*MissionWritePartialList) Id() uint8 { return 38 } // Len returns the MissionWritePartialList Message Length func (*MissionWritePartialList) Len() uint8 { return 6 } // Crc returns the MissionWritePartialList Message CRC func (*MissionWritePartialList) Crc() uint8 { return 9 } // Pack returns a packed byte array which represents a MissionWritePartialList payload func (m *MissionWritePartialList) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.START_INDEX); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.END_INDEX); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_COMPONENT); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the MissionWritePartialList func (m *MissionWritePartialList) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.START_INDEX); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.END_INDEX); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_COMPONENT); err != nil { panic(err) } } // MESSAGE MISSION_ITEM // // MAVLINK_MSG_ID_MISSION_ITEM 39 // // MAVLINK_MSG_ID_MISSION_ITEM_LEN 37 // // MAVLINK_MSG_ID_MISSION_ITEM_CRC 254 type MissionItem struct { PARAM1 float32 // PARAM1, see MAV_CMD enum PARAM2 float32 // PARAM2, see MAV_CMD enum PARAM3 float32 // PARAM3, see MAV_CMD enum PARAM4 float32 // PARAM4, see MAV_CMD enum X float32 // PARAM5 / local: x position, global: latitude Y float32 // PARAM6 / y position: global: longitude Z float32 // PARAM7 / z position: global: altitude (relative or absolute, depending on frame. SEQ uint16 // Sequence COMMAND uint16 // The scheduled action for the MISSION. see MAV_CMD in common.xml MAVLink specs TARGET_SYSTEM uint8 // System ID TARGET_COMPONENT uint8 // Component ID FRAME uint8 // The coordinate system of the MISSION. see MAV_FRAME in mavlink_types.h CURRENT uint8 // false:0, true:1 AUTOCONTINUE uint8 // autocontinue to next wp } // NewMissionItem returns a new MissionItem func NewMissionItem(PARAM1 float32, PARAM2 float32, PARAM3 float32, PARAM4 float32, X float32, Y float32, Z float32, SEQ uint16, COMMAND uint16, TARGET_SYSTEM uint8, TARGET_COMPONENT uint8, FRAME uint8, CURRENT uint8, AUTOCONTINUE uint8) *MissionItem { m := MissionItem{} m.PARAM1 = PARAM1 m.PARAM2 = PARAM2 m.PARAM3 = PARAM3 m.PARAM4 = PARAM4 m.X = X m.Y = Y m.Z = Z m.SEQ = SEQ m.COMMAND = COMMAND m.TARGET_SYSTEM = TARGET_SYSTEM m.TARGET_COMPONENT = TARGET_COMPONENT m.FRAME = FRAME m.CURRENT = CURRENT m.AUTOCONTINUE = AUTOCONTINUE return &m } // Id returns the MissionItem Message ID func (*MissionItem) Id() uint8 { return 39 } // Len returns the MissionItem Message Length func (*MissionItem) Len() uint8 { return 37 } // Crc returns the MissionItem Message CRC func (*MissionItem) Crc() uint8 { return 254 } // Pack returns a packed byte array which represents a MissionItem payload func (m *MissionItem) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.PARAM1); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PARAM2); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PARAM3); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PARAM4); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.X); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.Y); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.Z); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.SEQ); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.COMMAND); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_COMPONENT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.FRAME); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CURRENT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.AUTOCONTINUE); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the MissionItem func (m *MissionItem) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.PARAM1); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PARAM2); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PARAM3); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PARAM4); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.X); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.Y); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.Z); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.SEQ); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.COMMAND); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_COMPONENT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.FRAME); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CURRENT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.AUTOCONTINUE); err != nil { panic(err) } } // MESSAGE MISSION_REQUEST // // MAVLINK_MSG_ID_MISSION_REQUEST 40 // // MAVLINK_MSG_ID_MISSION_REQUEST_LEN 4 // // MAVLINK_MSG_ID_MISSION_REQUEST_CRC 230 type MissionRequest struct { SEQ uint16 // Sequence TARGET_SYSTEM uint8 // System ID TARGET_COMPONENT uint8 // Component ID } // NewMissionRequest returns a new MissionRequest func NewMissionRequest(SEQ uint16, TARGET_SYSTEM uint8, TARGET_COMPONENT uint8) *MissionRequest { m := MissionRequest{} m.SEQ = SEQ m.TARGET_SYSTEM = TARGET_SYSTEM m.TARGET_COMPONENT = TARGET_COMPONENT return &m } // Id returns the MissionRequest Message ID func (*MissionRequest) Id() uint8 { return 40 } // Len returns the MissionRequest Message Length func (*MissionRequest) Len() uint8 { return 4 } // Crc returns the MissionRequest Message CRC func (*MissionRequest) Crc() uint8 { return 230 } // Pack returns a packed byte array which represents a MissionRequest payload func (m *MissionRequest) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.SEQ); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_COMPONENT); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the MissionRequest func (m *MissionRequest) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.SEQ); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_COMPONENT); err != nil { panic(err) } } // MESSAGE MISSION_SET_CURRENT // // MAVLINK_MSG_ID_MISSION_SET_CURRENT 41 // // MAVLINK_MSG_ID_MISSION_SET_CURRENT_LEN 4 // // MAVLINK_MSG_ID_MISSION_SET_CURRENT_CRC 28 type MissionSetCurrent struct { SEQ uint16 // Sequence TARGET_SYSTEM uint8 // System ID TARGET_COMPONENT uint8 // Component ID } // NewMissionSetCurrent returns a new MissionSetCurrent func NewMissionSetCurrent(SEQ uint16, TARGET_SYSTEM uint8, TARGET_COMPONENT uint8) *MissionSetCurrent { m := MissionSetCurrent{} m.SEQ = SEQ m.TARGET_SYSTEM = TARGET_SYSTEM m.TARGET_COMPONENT = TARGET_COMPONENT return &m } // Id returns the MissionSetCurrent Message ID func (*MissionSetCurrent) Id() uint8 { return 41 } // Len returns the MissionSetCurrent Message Length func (*MissionSetCurrent) Len() uint8 { return 4 } // Crc returns the MissionSetCurrent Message CRC func (*MissionSetCurrent) Crc() uint8 { return 28 } // Pack returns a packed byte array which represents a MissionSetCurrent payload func (m *MissionSetCurrent) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.SEQ); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_COMPONENT); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the MissionSetCurrent func (m *MissionSetCurrent) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.SEQ); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_COMPONENT); err != nil { panic(err) } } // MESSAGE MISSION_CURRENT // // MAVLINK_MSG_ID_MISSION_CURRENT 42 // // MAVLINK_MSG_ID_MISSION_CURRENT_LEN 2 // // MAVLINK_MSG_ID_MISSION_CURRENT_CRC 28 type MissionCurrent struct { SEQ uint16 // Sequence } // NewMissionCurrent returns a new MissionCurrent func NewMissionCurrent(SEQ uint16) *MissionCurrent { m := MissionCurrent{} m.SEQ = SEQ return &m } // Id returns the MissionCurrent Message ID func (*MissionCurrent) Id() uint8 { return 42 } // Len returns the MissionCurrent Message Length func (*MissionCurrent) Len() uint8 { return 2 } // Crc returns the MissionCurrent Message CRC func (*MissionCurrent) Crc() uint8 { return 28 } // Pack returns a packed byte array which represents a MissionCurrent payload func (m *MissionCurrent) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.SEQ); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the MissionCurrent func (m *MissionCurrent) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.SEQ); err != nil { panic(err) } } // MESSAGE MISSION_REQUEST_LIST // // MAVLINK_MSG_ID_MISSION_REQUEST_LIST 43 // // MAVLINK_MSG_ID_MISSION_REQUEST_LIST_LEN 2 // // MAVLINK_MSG_ID_MISSION_REQUEST_LIST_CRC 132 type MissionRequestList struct { TARGET_SYSTEM uint8 // System ID TARGET_COMPONENT uint8 // Component ID } // NewMissionRequestList returns a new MissionRequestList func NewMissionRequestList(TARGET_SYSTEM uint8, TARGET_COMPONENT uint8) *MissionRequestList { m := MissionRequestList{} m.TARGET_SYSTEM = TARGET_SYSTEM m.TARGET_COMPONENT = TARGET_COMPONENT return &m } // Id returns the MissionRequestList Message ID func (*MissionRequestList) Id() uint8 { return 43 } // Len returns the MissionRequestList Message Length func (*MissionRequestList) Len() uint8 { return 2 } // Crc returns the MissionRequestList Message CRC func (*MissionRequestList) Crc() uint8 { return 132 } // Pack returns a packed byte array which represents a MissionRequestList payload func (m *MissionRequestList) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_COMPONENT); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the MissionRequestList func (m *MissionRequestList) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_COMPONENT); err != nil { panic(err) } } // MESSAGE MISSION_COUNT // // MAVLINK_MSG_ID_MISSION_COUNT 44 // // MAVLINK_MSG_ID_MISSION_COUNT_LEN 4 // // MAVLINK_MSG_ID_MISSION_COUNT_CRC 221 type MissionCount struct { COUNT uint16 // Number of mission items in the sequence TARGET_SYSTEM uint8 // System ID TARGET_COMPONENT uint8 // Component ID } // NewMissionCount returns a new MissionCount func NewMissionCount(COUNT uint16, TARGET_SYSTEM uint8, TARGET_COMPONENT uint8) *MissionCount { m := MissionCount{} m.COUNT = COUNT m.TARGET_SYSTEM = TARGET_SYSTEM m.TARGET_COMPONENT = TARGET_COMPONENT return &m } // Id returns the MissionCount Message ID func (*MissionCount) Id() uint8 { return 44 } // Len returns the MissionCount Message Length func (*MissionCount) Len() uint8 { return 4 } // Crc returns the MissionCount Message CRC func (*MissionCount) Crc() uint8 { return 221 } // Pack returns a packed byte array which represents a MissionCount payload func (m *MissionCount) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.COUNT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_COMPONENT); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the MissionCount func (m *MissionCount) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.COUNT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_COMPONENT); err != nil { panic(err) } } // MESSAGE MISSION_CLEAR_ALL // // MAVLINK_MSG_ID_MISSION_CLEAR_ALL 45 // // MAVLINK_MSG_ID_MISSION_CLEAR_ALL_LEN 2 // // MAVLINK_MSG_ID_MISSION_CLEAR_ALL_CRC 232 type MissionClearAll struct { TARGET_SYSTEM uint8 // System ID TARGET_COMPONENT uint8 // Component ID } // NewMissionClearAll returns a new MissionClearAll func NewMissionClearAll(TARGET_SYSTEM uint8, TARGET_COMPONENT uint8) *MissionClearAll { m := MissionClearAll{} m.TARGET_SYSTEM = TARGET_SYSTEM m.TARGET_COMPONENT = TARGET_COMPONENT return &m } // Id returns the MissionClearAll Message ID func (*MissionClearAll) Id() uint8 { return 45 } // Len returns the MissionClearAll Message Length func (*MissionClearAll) Len() uint8 { return 2 } // Crc returns the MissionClearAll Message CRC func (*MissionClearAll) Crc() uint8 { return 232 } // Pack returns a packed byte array which represents a MissionClearAll payload func (m *MissionClearAll) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_COMPONENT); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the MissionClearAll func (m *MissionClearAll) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_COMPONENT); err != nil { panic(err) } } // MESSAGE MISSION_ITEM_REACHED // // MAVLINK_MSG_ID_MISSION_ITEM_REACHED 46 // // MAVLINK_MSG_ID_MISSION_ITEM_REACHED_LEN 2 // // MAVLINK_MSG_ID_MISSION_ITEM_REACHED_CRC 11 type MissionItemReached struct { SEQ uint16 // Sequence } // NewMissionItemReached returns a new MissionItemReached func NewMissionItemReached(SEQ uint16) *MissionItemReached { m := MissionItemReached{} m.SEQ = SEQ return &m } // Id returns the MissionItemReached Message ID func (*MissionItemReached) Id() uint8 { return 46 } // Len returns the MissionItemReached Message Length func (*MissionItemReached) Len() uint8 { return 2 } // Crc returns the MissionItemReached Message CRC func (*MissionItemReached) Crc() uint8 { return 11 } // Pack returns a packed byte array which represents a MissionItemReached payload func (m *MissionItemReached) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.SEQ); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the MissionItemReached func (m *MissionItemReached) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.SEQ); err != nil { panic(err) } } // MESSAGE MISSION_ACK // // MAVLINK_MSG_ID_MISSION_ACK 47 // // MAVLINK_MSG_ID_MISSION_ACK_LEN 3 // // MAVLINK_MSG_ID_MISSION_ACK_CRC 153 type MissionAck struct { TARGET_SYSTEM uint8 // System ID TARGET_COMPONENT uint8 // Component ID TYPE uint8 // See MAV_MISSION_RESULT enum } // NewMissionAck returns a new MissionAck func NewMissionAck(TARGET_SYSTEM uint8, TARGET_COMPONENT uint8, TYPE uint8) *MissionAck { m := MissionAck{} m.TARGET_SYSTEM = TARGET_SYSTEM m.TARGET_COMPONENT = TARGET_COMPONENT m.TYPE = TYPE return &m } // Id returns the MissionAck Message ID func (*MissionAck) Id() uint8 { return 47 } // Len returns the MissionAck Message Length func (*MissionAck) Len() uint8 { return 3 } // Crc returns the MissionAck Message CRC func (*MissionAck) Crc() uint8 { return 153 } // Pack returns a packed byte array which represents a MissionAck payload func (m *MissionAck) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_COMPONENT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TYPE); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the MissionAck func (m *MissionAck) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_COMPONENT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TYPE); err != nil { panic(err) } } // MESSAGE SET_GPS_GLOBAL_ORIGIN // // MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN 48 // // MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_LEN 13 // // MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_CRC 41 type SetGpsGlobalOrigin struct { LATITUDE int32 // Latitude (WGS84), in degrees * 1E7 LONGITUDE int32 // Longitude (WGS84, in degrees * 1E7 ALTITUDE int32 // Altitude (WGS84), in meters * 1000 (positive for up) TARGET_SYSTEM uint8 // System ID } // NewSetGpsGlobalOrigin returns a new SetGpsGlobalOrigin func NewSetGpsGlobalOrigin(LATITUDE int32, LONGITUDE int32, ALTITUDE int32, TARGET_SYSTEM uint8) *SetGpsGlobalOrigin { m := SetGpsGlobalOrigin{} m.LATITUDE = LATITUDE m.LONGITUDE = LONGITUDE m.ALTITUDE = ALTITUDE m.TARGET_SYSTEM = TARGET_SYSTEM return &m } // Id returns the SetGpsGlobalOrigin Message ID func (*SetGpsGlobalOrigin) Id() uint8 { return 48 } // Len returns the SetGpsGlobalOrigin Message Length func (*SetGpsGlobalOrigin) Len() uint8 { return 13 } // Crc returns the SetGpsGlobalOrigin Message CRC func (*SetGpsGlobalOrigin) Crc() uint8 { return 41 } // Pack returns a packed byte array which represents a SetGpsGlobalOrigin payload func (m *SetGpsGlobalOrigin) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.LATITUDE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.LONGITUDE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ALTITUDE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_SYSTEM); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the SetGpsGlobalOrigin func (m *SetGpsGlobalOrigin) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.LATITUDE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.LONGITUDE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ALTITUDE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_SYSTEM); err != nil { panic(err) } } // MESSAGE GPS_GLOBAL_ORIGIN // // MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN 49 // // MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_LEN 12 // // MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_CRC 39 type GpsGlobalOrigin struct { LATITUDE int32 // Latitude (WGS84), in degrees * 1E7 LONGITUDE int32 // Longitude (WGS84), in degrees * 1E7 ALTITUDE int32 // Altitude (WGS84), in meters * 1000 (positive for up) } // NewGpsGlobalOrigin returns a new GpsGlobalOrigin func NewGpsGlobalOrigin(LATITUDE int32, LONGITUDE int32, ALTITUDE int32) *GpsGlobalOrigin { m := GpsGlobalOrigin{} m.LATITUDE = LATITUDE m.LONGITUDE = LONGITUDE m.ALTITUDE = ALTITUDE return &m } // Id returns the GpsGlobalOrigin Message ID func (*GpsGlobalOrigin) Id() uint8 { return 49 } // Len returns the GpsGlobalOrigin Message Length func (*GpsGlobalOrigin) Len() uint8 { return 12 } // Crc returns the GpsGlobalOrigin Message CRC func (*GpsGlobalOrigin) Crc() uint8 { return 39 } // Pack returns a packed byte array which represents a GpsGlobalOrigin payload func (m *GpsGlobalOrigin) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.LATITUDE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.LONGITUDE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ALTITUDE); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the GpsGlobalOrigin func (m *GpsGlobalOrigin) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.LATITUDE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.LONGITUDE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ALTITUDE); err != nil { panic(err) } } // MESSAGE SET_LOCAL_POSITION_SETPOINT // // MAVLINK_MSG_ID_SET_LOCAL_POSITION_SETPOINT 50 // // MAVLINK_MSG_ID_SET_LOCAL_POSITION_SETPOINT_LEN 19 // // MAVLINK_MSG_ID_SET_LOCAL_POSITION_SETPOINT_CRC 214 type SetLocalPositionSetpoint struct { X float32 // x position Y float32 // y position Z float32 // z position YAW float32 // Desired yaw angle TARGET_SYSTEM uint8 // System ID TARGET_COMPONENT uint8 // Component ID COORDINATE_FRAME uint8 // Coordinate frame - valid values are only MAV_FRAME_LOCAL_NED or MAV_FRAME_LOCAL_ENU } // NewSetLocalPositionSetpoint returns a new SetLocalPositionSetpoint func NewSetLocalPositionSetpoint(X float32, Y float32, Z float32, YAW float32, TARGET_SYSTEM uint8, TARGET_COMPONENT uint8, COORDINATE_FRAME uint8) *SetLocalPositionSetpoint { m := SetLocalPositionSetpoint{} m.X = X m.Y = Y m.Z = Z m.YAW = YAW m.TARGET_SYSTEM = TARGET_SYSTEM m.TARGET_COMPONENT = TARGET_COMPONENT m.COORDINATE_FRAME = COORDINATE_FRAME return &m } // Id returns the SetLocalPositionSetpoint Message ID func (*SetLocalPositionSetpoint) Id() uint8 { return 50 } // Len returns the SetLocalPositionSetpoint Message Length func (*SetLocalPositionSetpoint) Len() uint8 { return 19 } // Crc returns the SetLocalPositionSetpoint Message CRC func (*SetLocalPositionSetpoint) Crc() uint8 { return 214 } // Pack returns a packed byte array which represents a SetLocalPositionSetpoint payload func (m *SetLocalPositionSetpoint) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.X); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.Y); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.Z); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.YAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_COMPONENT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.COORDINATE_FRAME); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the SetLocalPositionSetpoint func (m *SetLocalPositionSetpoint) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.X); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.Y); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.Z); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.YAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_COMPONENT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.COORDINATE_FRAME); err != nil { panic(err) } } // MESSAGE LOCAL_POSITION_SETPOINT // // MAVLINK_MSG_ID_LOCAL_POSITION_SETPOINT 51 // // MAVLINK_MSG_ID_LOCAL_POSITION_SETPOINT_LEN 17 // // MAVLINK_MSG_ID_LOCAL_POSITION_SETPOINT_CRC 223 type LocalPositionSetpoint struct { X float32 // x position Y float32 // y position Z float32 // z position YAW float32 // Desired yaw angle COORDINATE_FRAME uint8 // Coordinate frame - valid values are only MAV_FRAME_LOCAL_NED or MAV_FRAME_LOCAL_ENU } // NewLocalPositionSetpoint returns a new LocalPositionSetpoint func NewLocalPositionSetpoint(X float32, Y float32, Z float32, YAW float32, COORDINATE_FRAME uint8) *LocalPositionSetpoint { m := LocalPositionSetpoint{} m.X = X m.Y = Y m.Z = Z m.YAW = YAW m.COORDINATE_FRAME = COORDINATE_FRAME return &m } // Id returns the LocalPositionSetpoint Message ID func (*LocalPositionSetpoint) Id() uint8 { return 51 } // Len returns the LocalPositionSetpoint Message Length func (*LocalPositionSetpoint) Len() uint8 { return 17 } // Crc returns the LocalPositionSetpoint Message CRC func (*LocalPositionSetpoint) Crc() uint8 { return 223 } // Pack returns a packed byte array which represents a LocalPositionSetpoint payload func (m *LocalPositionSetpoint) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.X); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.Y); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.Z); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.YAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.COORDINATE_FRAME); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the LocalPositionSetpoint func (m *LocalPositionSetpoint) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.X); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.Y); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.Z); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.YAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.COORDINATE_FRAME); err != nil { panic(err) } } // MESSAGE GLOBAL_POSITION_SETPOINT_INT // // MAVLINK_MSG_ID_GLOBAL_POSITION_SETPOINT_INT 52 // // MAVLINK_MSG_ID_GLOBAL_POSITION_SETPOINT_INT_LEN 15 // // MAVLINK_MSG_ID_GLOBAL_POSITION_SETPOINT_INT_CRC 141 type GlobalPositionSetpointInt struct { LATITUDE int32 // Latitude (WGS84), in degrees * 1E7 LONGITUDE int32 // Longitude (WGS84), in degrees * 1E7 ALTITUDE int32 // Altitude (WGS84), in meters * 1000 (positive for up) YAW int16 // Desired yaw angle in degrees * 100 COORDINATE_FRAME uint8 // Coordinate frame - valid values are only MAV_FRAME_GLOBAL or MAV_FRAME_GLOBAL_RELATIVE_ALT } // NewGlobalPositionSetpointInt returns a new GlobalPositionSetpointInt func NewGlobalPositionSetpointInt(LATITUDE int32, LONGITUDE int32, ALTITUDE int32, YAW int16, COORDINATE_FRAME uint8) *GlobalPositionSetpointInt { m := GlobalPositionSetpointInt{} m.LATITUDE = LATITUDE m.LONGITUDE = LONGITUDE m.ALTITUDE = ALTITUDE m.YAW = YAW m.COORDINATE_FRAME = COORDINATE_FRAME return &m } // Id returns the GlobalPositionSetpointInt Message ID func (*GlobalPositionSetpointInt) Id() uint8 { return 52 } // Len returns the GlobalPositionSetpointInt Message Length func (*GlobalPositionSetpointInt) Len() uint8 { return 15 } // Crc returns the GlobalPositionSetpointInt Message CRC func (*GlobalPositionSetpointInt) Crc() uint8 { return 141 } // Pack returns a packed byte array which represents a GlobalPositionSetpointInt payload func (m *GlobalPositionSetpointInt) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.LATITUDE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.LONGITUDE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ALTITUDE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.YAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.COORDINATE_FRAME); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the GlobalPositionSetpointInt func (m *GlobalPositionSetpointInt) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.LATITUDE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.LONGITUDE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ALTITUDE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.YAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.COORDINATE_FRAME); err != nil { panic(err) } } // MESSAGE SET_GLOBAL_POSITION_SETPOINT_INT // // MAVLINK_MSG_ID_SET_GLOBAL_POSITION_SETPOINT_INT 53 // // MAVLINK_MSG_ID_SET_GLOBAL_POSITION_SETPOINT_INT_LEN 15 // // MAVLINK_MSG_ID_SET_GLOBAL_POSITION_SETPOINT_INT_CRC 33 type SetGlobalPositionSetpointInt struct { LATITUDE int32 // Latitude (WGS84), in degrees * 1E7 LONGITUDE int32 // Longitude (WGS84), in degrees * 1E7 ALTITUDE int32 // Altitude (WGS84), in meters * 1000 (positive for up) YAW int16 // Desired yaw angle in degrees * 100 COORDINATE_FRAME uint8 // Coordinate frame - valid values are only MAV_FRAME_GLOBAL or MAV_FRAME_GLOBAL_RELATIVE_ALT } // NewSetGlobalPositionSetpointInt returns a new SetGlobalPositionSetpointInt func NewSetGlobalPositionSetpointInt(LATITUDE int32, LONGITUDE int32, ALTITUDE int32, YAW int16, COORDINATE_FRAME uint8) *SetGlobalPositionSetpointInt { m := SetGlobalPositionSetpointInt{} m.LATITUDE = LATITUDE m.LONGITUDE = LONGITUDE m.ALTITUDE = ALTITUDE m.YAW = YAW m.COORDINATE_FRAME = COORDINATE_FRAME return &m } // Id returns the SetGlobalPositionSetpointInt Message ID func (*SetGlobalPositionSetpointInt) Id() uint8 { return 53 } // Len returns the SetGlobalPositionSetpointInt Message Length func (*SetGlobalPositionSetpointInt) Len() uint8 { return 15 } // Crc returns the SetGlobalPositionSetpointInt Message CRC func (*SetGlobalPositionSetpointInt) Crc() uint8 { return 33 } // Pack returns a packed byte array which represents a SetGlobalPositionSetpointInt payload func (m *SetGlobalPositionSetpointInt) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.LATITUDE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.LONGITUDE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ALTITUDE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.YAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.COORDINATE_FRAME); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the SetGlobalPositionSetpointInt func (m *SetGlobalPositionSetpointInt) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.LATITUDE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.LONGITUDE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ALTITUDE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.YAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.COORDINATE_FRAME); err != nil { panic(err) } } // MESSAGE SAFETY_SET_ALLOWED_AREA // // MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA 54 // // MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_LEN 27 // // MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_CRC 15 type SafetySetAllowedArea struct { P1X float32 // x position 1 / Latitude 1 P1Y float32 // y position 1 / Longitude 1 P1Z float32 // z position 1 / Altitude 1 P2X float32 // x position 2 / Latitude 2 P2Y float32 // y position 2 / Longitude 2 P2Z float32 // z position 2 / Altitude 2 TARGET_SYSTEM uint8 // System ID TARGET_COMPONENT uint8 // Component ID FRAME uint8 // Coordinate frame, as defined by MAV_FRAME enum in mavlink_types.h. Can be either global, GPS, right-handed with Z axis up or local, right handed, Z axis down. } // NewSafetySetAllowedArea returns a new SafetySetAllowedArea func NewSafetySetAllowedArea(P1X float32, P1Y float32, P1Z float32, P2X float32, P2Y float32, P2Z float32, TARGET_SYSTEM uint8, TARGET_COMPONENT uint8, FRAME uint8) *SafetySetAllowedArea { m := SafetySetAllowedArea{} m.P1X = P1X m.P1Y = P1Y m.P1Z = P1Z m.P2X = P2X m.P2Y = P2Y m.P2Z = P2Z m.TARGET_SYSTEM = TARGET_SYSTEM m.TARGET_COMPONENT = TARGET_COMPONENT m.FRAME = FRAME return &m } // Id returns the SafetySetAllowedArea Message ID func (*SafetySetAllowedArea) Id() uint8 { return 54 } // Len returns the SafetySetAllowedArea Message Length func (*SafetySetAllowedArea) Len() uint8 { return 27 } // Crc returns the SafetySetAllowedArea Message CRC func (*SafetySetAllowedArea) Crc() uint8 { return 15 } // Pack returns a packed byte array which represents a SafetySetAllowedArea payload func (m *SafetySetAllowedArea) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.P1X); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.P1Y); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.P1Z); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.P2X); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.P2Y); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.P2Z); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_COMPONENT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.FRAME); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the SafetySetAllowedArea func (m *SafetySetAllowedArea) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.P1X); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.P1Y); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.P1Z); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.P2X); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.P2Y); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.P2Z); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_COMPONENT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.FRAME); err != nil { panic(err) } } // MESSAGE SAFETY_ALLOWED_AREA // // MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA 55 // // MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_LEN 25 // // MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_CRC 3 type SafetyAllowedArea struct { P1X float32 // x position 1 / Latitude 1 P1Y float32 // y position 1 / Longitude 1 P1Z float32 // z position 1 / Altitude 1 P2X float32 // x position 2 / Latitude 2 P2Y float32 // y position 2 / Longitude 2 P2Z float32 // z position 2 / Altitude 2 FRAME uint8 // Coordinate frame, as defined by MAV_FRAME enum in mavlink_types.h. Can be either global, GPS, right-handed with Z axis up or local, right handed, Z axis down. } // NewSafetyAllowedArea returns a new SafetyAllowedArea func NewSafetyAllowedArea(P1X float32, P1Y float32, P1Z float32, P2X float32, P2Y float32, P2Z float32, FRAME uint8) *SafetyAllowedArea { m := SafetyAllowedArea{} m.P1X = P1X m.P1Y = P1Y m.P1Z = P1Z m.P2X = P2X m.P2Y = P2Y m.P2Z = P2Z m.FRAME = FRAME return &m } // Id returns the SafetyAllowedArea Message ID func (*SafetyAllowedArea) Id() uint8 { return 55 } // Len returns the SafetyAllowedArea Message Length func (*SafetyAllowedArea) Len() uint8 { return 25 } // Crc returns the SafetyAllowedArea Message CRC func (*SafetyAllowedArea) Crc() uint8 { return 3 } // Pack returns a packed byte array which represents a SafetyAllowedArea payload func (m *SafetyAllowedArea) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.P1X); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.P1Y); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.P1Z); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.P2X); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.P2Y); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.P2Z); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.FRAME); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the SafetyAllowedArea func (m *SafetyAllowedArea) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.P1X); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.P1Y); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.P1Z); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.P2X); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.P2Y); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.P2Z); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.FRAME); err != nil { panic(err) } } // MESSAGE SET_ROLL_PITCH_YAW_THRUST // // MAVLINK_MSG_ID_SET_ROLL_PITCH_YAW_THRUST 56 // // MAVLINK_MSG_ID_SET_ROLL_PITCH_YAW_THRUST_LEN 18 // // MAVLINK_MSG_ID_SET_ROLL_PITCH_YAW_THRUST_CRC 100 type SetRollPitchYawThrust struct { ROLL float32 // Desired roll angle in radians PITCH float32 // Desired pitch angle in radians YAW float32 // Desired yaw angle in radians THRUST float32 // Collective thrust, normalized to 0 .. 1 TARGET_SYSTEM uint8 // System ID TARGET_COMPONENT uint8 // Component ID } // NewSetRollPitchYawThrust returns a new SetRollPitchYawThrust func NewSetRollPitchYawThrust(ROLL float32, PITCH float32, YAW float32, THRUST float32, TARGET_SYSTEM uint8, TARGET_COMPONENT uint8) *SetRollPitchYawThrust { m := SetRollPitchYawThrust{} m.ROLL = ROLL m.PITCH = PITCH m.YAW = YAW m.THRUST = THRUST m.TARGET_SYSTEM = TARGET_SYSTEM m.TARGET_COMPONENT = TARGET_COMPONENT return &m } // Id returns the SetRollPitchYawThrust Message ID func (*SetRollPitchYawThrust) Id() uint8 { return 56 } // Len returns the SetRollPitchYawThrust Message Length func (*SetRollPitchYawThrust) Len() uint8 { return 18 } // Crc returns the SetRollPitchYawThrust Message CRC func (*SetRollPitchYawThrust) Crc() uint8 { return 100 } // Pack returns a packed byte array which represents a SetRollPitchYawThrust payload func (m *SetRollPitchYawThrust) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.ROLL); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PITCH); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.YAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.THRUST); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_COMPONENT); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the SetRollPitchYawThrust func (m *SetRollPitchYawThrust) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.ROLL); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PITCH); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.YAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.THRUST); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_COMPONENT); err != nil { panic(err) } } // MESSAGE SET_ROLL_PITCH_YAW_SPEED_THRUST // // MAVLINK_MSG_ID_SET_ROLL_PITCH_YAW_SPEED_THRUST 57 // // MAVLINK_MSG_ID_SET_ROLL_PITCH_YAW_SPEED_THRUST_LEN 18 // // MAVLINK_MSG_ID_SET_ROLL_PITCH_YAW_SPEED_THRUST_CRC 24 type SetRollPitchYawSpeedThrust struct { ROLL_SPEED float32 // Desired roll angular speed in rad/s PITCH_SPEED float32 // Desired pitch angular speed in rad/s YAW_SPEED float32 // Desired yaw angular speed in rad/s THRUST float32 // Collective thrust, normalized to 0 .. 1 TARGET_SYSTEM uint8 // System ID TARGET_COMPONENT uint8 // Component ID } // NewSetRollPitchYawSpeedThrust returns a new SetRollPitchYawSpeedThrust func NewSetRollPitchYawSpeedThrust(ROLL_SPEED float32, PITCH_SPEED float32, YAW_SPEED float32, THRUST float32, TARGET_SYSTEM uint8, TARGET_COMPONENT uint8) *SetRollPitchYawSpeedThrust { m := SetRollPitchYawSpeedThrust{} m.ROLL_SPEED = ROLL_SPEED m.PITCH_SPEED = PITCH_SPEED m.YAW_SPEED = YAW_SPEED m.THRUST = THRUST m.TARGET_SYSTEM = TARGET_SYSTEM m.TARGET_COMPONENT = TARGET_COMPONENT return &m } // Id returns the SetRollPitchYawSpeedThrust Message ID func (*SetRollPitchYawSpeedThrust) Id() uint8 { return 57 } // Len returns the SetRollPitchYawSpeedThrust Message Length func (*SetRollPitchYawSpeedThrust) Len() uint8 { return 18 } // Crc returns the SetRollPitchYawSpeedThrust Message CRC func (*SetRollPitchYawSpeedThrust) Crc() uint8 { return 24 } // Pack returns a packed byte array which represents a SetRollPitchYawSpeedThrust payload func (m *SetRollPitchYawSpeedThrust) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.ROLL_SPEED); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PITCH_SPEED); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.YAW_SPEED); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.THRUST); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_COMPONENT); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the SetRollPitchYawSpeedThrust func (m *SetRollPitchYawSpeedThrust) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.ROLL_SPEED); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PITCH_SPEED); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.YAW_SPEED); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.THRUST); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_COMPONENT); err != nil { panic(err) } } // MESSAGE ROLL_PITCH_YAW_THRUST_SETPOINT // // MAVLINK_MSG_ID_ROLL_PITCH_YAW_THRUST_SETPOINT 58 // // MAVLINK_MSG_ID_ROLL_PITCH_YAW_THRUST_SETPOINT_LEN 20 // // MAVLINK_MSG_ID_ROLL_PITCH_YAW_THRUST_SETPOINT_CRC 239 type RollPitchYawThrustSetpoint struct { TIME_BOOT_MS uint32 // Timestamp in milliseconds since system boot ROLL float32 // Desired roll angle in radians PITCH float32 // Desired pitch angle in radians YAW float32 // Desired yaw angle in radians THRUST float32 // Collective thrust, normalized to 0 .. 1 } // NewRollPitchYawThrustSetpoint returns a new RollPitchYawThrustSetpoint func NewRollPitchYawThrustSetpoint(TIME_BOOT_MS uint32, ROLL float32, PITCH float32, YAW float32, THRUST float32) *RollPitchYawThrustSetpoint { m := RollPitchYawThrustSetpoint{} m.TIME_BOOT_MS = TIME_BOOT_MS m.ROLL = ROLL m.PITCH = PITCH m.YAW = YAW m.THRUST = THRUST return &m } // Id returns the RollPitchYawThrustSetpoint Message ID func (*RollPitchYawThrustSetpoint) Id() uint8 { return 58 } // Len returns the RollPitchYawThrustSetpoint Message Length func (*RollPitchYawThrustSetpoint) Len() uint8 { return 20 } // Crc returns the RollPitchYawThrustSetpoint Message CRC func (*RollPitchYawThrustSetpoint) Crc() uint8 { return 239 } // Pack returns a packed byte array which represents a RollPitchYawThrustSetpoint payload func (m *RollPitchYawThrustSetpoint) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TIME_BOOT_MS); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ROLL); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PITCH); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.YAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.THRUST); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the RollPitchYawThrustSetpoint func (m *RollPitchYawThrustSetpoint) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TIME_BOOT_MS); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ROLL); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PITCH); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.YAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.THRUST); err != nil { panic(err) } } // MESSAGE ROLL_PITCH_YAW_SPEED_THRUST_SETPOINT // // MAVLINK_MSG_ID_ROLL_PITCH_YAW_SPEED_THRUST_SETPOINT 59 // // MAVLINK_MSG_ID_ROLL_PITCH_YAW_SPEED_THRUST_SETPOINT_LEN 20 // // MAVLINK_MSG_ID_ROLL_PITCH_YAW_SPEED_THRUST_SETPOINT_CRC 238 type RollPitchYawSpeedThrustSetpoint struct { TIME_BOOT_MS uint32 // Timestamp in milliseconds since system boot ROLL_SPEED float32 // Desired roll angular speed in rad/s PITCH_SPEED float32 // Desired pitch angular speed in rad/s YAW_SPEED float32 // Desired yaw angular speed in rad/s THRUST float32 // Collective thrust, normalized to 0 .. 1 } // NewRollPitchYawSpeedThrustSetpoint returns a new RollPitchYawSpeedThrustSetpoint func NewRollPitchYawSpeedThrustSetpoint(TIME_BOOT_MS uint32, ROLL_SPEED float32, PITCH_SPEED float32, YAW_SPEED float32, THRUST float32) *RollPitchYawSpeedThrustSetpoint { m := RollPitchYawSpeedThrustSetpoint{} m.TIME_BOOT_MS = TIME_BOOT_MS m.ROLL_SPEED = ROLL_SPEED m.PITCH_SPEED = PITCH_SPEED m.YAW_SPEED = YAW_SPEED m.THRUST = THRUST return &m } // Id returns the RollPitchYawSpeedThrustSetpoint Message ID func (*RollPitchYawSpeedThrustSetpoint) Id() uint8 { return 59 } // Len returns the RollPitchYawSpeedThrustSetpoint Message Length func (*RollPitchYawSpeedThrustSetpoint) Len() uint8 { return 20 } // Crc returns the RollPitchYawSpeedThrustSetpoint Message CRC func (*RollPitchYawSpeedThrustSetpoint) Crc() uint8 { return 238 } // Pack returns a packed byte array which represents a RollPitchYawSpeedThrustSetpoint payload func (m *RollPitchYawSpeedThrustSetpoint) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TIME_BOOT_MS); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ROLL_SPEED); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PITCH_SPEED); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.YAW_SPEED); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.THRUST); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the RollPitchYawSpeedThrustSetpoint func (m *RollPitchYawSpeedThrustSetpoint) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TIME_BOOT_MS); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ROLL_SPEED); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PITCH_SPEED); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.YAW_SPEED); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.THRUST); err != nil { panic(err) } } // MESSAGE SET_QUAD_MOTORS_SETPOINT // // MAVLINK_MSG_ID_SET_QUAD_MOTORS_SETPOINT 60 // // MAVLINK_MSG_ID_SET_QUAD_MOTORS_SETPOINT_LEN 9 // // MAVLINK_MSG_ID_SET_QUAD_MOTORS_SETPOINT_CRC 30 type SetQuadMotorsSetpoint struct { MOTOR_FRONT_NW uint16 // Front motor in + configuration, front left motor in x configuration MOTOR_RIGHT_NE uint16 // Right motor in + configuration, front right motor in x configuration MOTOR_BACK_SE uint16 // Back motor in + configuration, back right motor in x configuration MOTOR_LEFT_SW uint16 // Left motor in + configuration, back left motor in x configuration TARGET_SYSTEM uint8 // System ID of the system that should set these motor commands } // NewSetQuadMotorsSetpoint returns a new SetQuadMotorsSetpoint func NewSetQuadMotorsSetpoint(MOTOR_FRONT_NW uint16, MOTOR_RIGHT_NE uint16, MOTOR_BACK_SE uint16, MOTOR_LEFT_SW uint16, TARGET_SYSTEM uint8) *SetQuadMotorsSetpoint { m := SetQuadMotorsSetpoint{} m.MOTOR_FRONT_NW = MOTOR_FRONT_NW m.MOTOR_RIGHT_NE = MOTOR_RIGHT_NE m.MOTOR_BACK_SE = MOTOR_BACK_SE m.MOTOR_LEFT_SW = MOTOR_LEFT_SW m.TARGET_SYSTEM = TARGET_SYSTEM return &m } // Id returns the SetQuadMotorsSetpoint Message ID func (*SetQuadMotorsSetpoint) Id() uint8 { return 60 } // Len returns the SetQuadMotorsSetpoint Message Length func (*SetQuadMotorsSetpoint) Len() uint8 { return 9 } // Crc returns the SetQuadMotorsSetpoint Message CRC func (*SetQuadMotorsSetpoint) Crc() uint8 { return 30 } // Pack returns a packed byte array which represents a SetQuadMotorsSetpoint payload func (m *SetQuadMotorsSetpoint) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.MOTOR_FRONT_NW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.MOTOR_RIGHT_NE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.MOTOR_BACK_SE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.MOTOR_LEFT_SW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_SYSTEM); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the SetQuadMotorsSetpoint func (m *SetQuadMotorsSetpoint) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.MOTOR_FRONT_NW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.MOTOR_RIGHT_NE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.MOTOR_BACK_SE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.MOTOR_LEFT_SW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_SYSTEM); err != nil { panic(err) } } // MESSAGE SET_QUAD_SWARM_ROLL_PITCH_YAW_THRUST // // MAVLINK_MSG_ID_SET_QUAD_SWARM_ROLL_PITCH_YAW_THRUST 61 // // MAVLINK_MSG_ID_SET_QUAD_SWARM_ROLL_PITCH_YAW_THRUST_LEN 34 // // MAVLINK_MSG_ID_SET_QUAD_SWARM_ROLL_PITCH_YAW_THRUST_CRC 240 type SetQuadSwarmRollPitchYawThrust struct { ROLL [4]int16 // Desired roll angle in radians +-PI (+-INT16_MAX) PITCH [4]int16 // Desired pitch angle in radians +-PI (+-INT16_MAX) YAW [4]int16 // Desired yaw angle in radians, scaled to int16 +-PI (+-INT16_MAX) THRUST [4]uint16 // Collective thrust, scaled to uint16 (0..UINT16_MAX) GROUP uint8 // ID of the quadrotor group (0 - 255, up to 256 groups supported) MODE uint8 // ID of the flight mode (0 - 255, up to 256 modes supported) } // NewSetQuadSwarmRollPitchYawThrust returns a new SetQuadSwarmRollPitchYawThrust func NewSetQuadSwarmRollPitchYawThrust(ROLL [4]int16, PITCH [4]int16, YAW [4]int16, THRUST [4]uint16, GROUP uint8, MODE uint8) *SetQuadSwarmRollPitchYawThrust { m := SetQuadSwarmRollPitchYawThrust{} m.ROLL = ROLL m.PITCH = PITCH m.YAW = YAW m.THRUST = THRUST m.GROUP = GROUP m.MODE = MODE return &m } // Id returns the SetQuadSwarmRollPitchYawThrust Message ID func (*SetQuadSwarmRollPitchYawThrust) Id() uint8 { return 61 } // Len returns the SetQuadSwarmRollPitchYawThrust Message Length func (*SetQuadSwarmRollPitchYawThrust) Len() uint8 { return 34 } // Crc returns the SetQuadSwarmRollPitchYawThrust Message CRC func (*SetQuadSwarmRollPitchYawThrust) Crc() uint8 { return 240 } // Pack returns a packed byte array which represents a SetQuadSwarmRollPitchYawThrust payload func (m *SetQuadSwarmRollPitchYawThrust) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.ROLL); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PITCH); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.YAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.THRUST); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.GROUP); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.MODE); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the SetQuadSwarmRollPitchYawThrust func (m *SetQuadSwarmRollPitchYawThrust) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.ROLL); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PITCH); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.YAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.THRUST); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.GROUP); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.MODE); err != nil { panic(err) } } const ( MAVLINK_MSG_SET_QUAD_SWARM_ROLL_PITCH_YAW_THRUST_FIELD_roll_LEN = 4 MAVLINK_MSG_SET_QUAD_SWARM_ROLL_PITCH_YAW_THRUST_FIELD_pitch_LEN = 4 MAVLINK_MSG_SET_QUAD_SWARM_ROLL_PITCH_YAW_THRUST_FIELD_yaw_LEN = 4 MAVLINK_MSG_SET_QUAD_SWARM_ROLL_PITCH_YAW_THRUST_FIELD_thrust_LEN = 4 ) // MESSAGE NAV_CONTROLLER_OUTPUT // // MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT 62 // // MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_LEN 26 // // MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_CRC 183 type NavControllerOutput struct { NAV_ROLL float32 // Current desired roll in degrees NAV_PITCH float32 // Current desired pitch in degrees ALT_ERROR float32 // Current altitude error in meters ASPD_ERROR float32 // Current airspeed error in meters/second XTRACK_ERROR float32 // Current crosstrack error on x-y plane in meters NAV_BEARING int16 // Current desired heading in degrees TARGET_BEARING int16 // Bearing to current MISSION/target in degrees WP_DIST uint16 // Distance to active MISSION in meters } // NewNavControllerOutput returns a new NavControllerOutput func NewNavControllerOutput(NAV_ROLL float32, NAV_PITCH float32, ALT_ERROR float32, ASPD_ERROR float32, XTRACK_ERROR float32, NAV_BEARING int16, TARGET_BEARING int16, WP_DIST uint16) *NavControllerOutput { m := NavControllerOutput{} m.NAV_ROLL = NAV_ROLL m.NAV_PITCH = NAV_PITCH m.ALT_ERROR = ALT_ERROR m.ASPD_ERROR = ASPD_ERROR m.XTRACK_ERROR = XTRACK_ERROR m.NAV_BEARING = NAV_BEARING m.TARGET_BEARING = TARGET_BEARING m.WP_DIST = WP_DIST return &m } // Id returns the NavControllerOutput Message ID func (*NavControllerOutput) Id() uint8 { return 62 } // Len returns the NavControllerOutput Message Length func (*NavControllerOutput) Len() uint8 { return 26 } // Crc returns the NavControllerOutput Message CRC func (*NavControllerOutput) Crc() uint8 { return 183 } // Pack returns a packed byte array which represents a NavControllerOutput payload func (m *NavControllerOutput) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.NAV_ROLL); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.NAV_PITCH); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ALT_ERROR); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ASPD_ERROR); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.XTRACK_ERROR); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.NAV_BEARING); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_BEARING); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.WP_DIST); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the NavControllerOutput func (m *NavControllerOutput) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.NAV_ROLL); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.NAV_PITCH); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ALT_ERROR); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ASPD_ERROR); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.XTRACK_ERROR); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.NAV_BEARING); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_BEARING); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.WP_DIST); err != nil { panic(err) } } // MESSAGE SET_QUAD_SWARM_LED_ROLL_PITCH_YAW_THRUST // // MAVLINK_MSG_ID_SET_QUAD_SWARM_LED_ROLL_PITCH_YAW_THRUST 63 // // MAVLINK_MSG_ID_SET_QUAD_SWARM_LED_ROLL_PITCH_YAW_THRUST_LEN 46 // // MAVLINK_MSG_ID_SET_QUAD_SWARM_LED_ROLL_PITCH_YAW_THRUST_CRC 130 type SetQuadSwarmLedRollPitchYawThrust struct { ROLL [4]int16 // Desired roll angle in radians +-PI (+-INT16_MAX) PITCH [4]int16 // Desired pitch angle in radians +-PI (+-INT16_MAX) YAW [4]int16 // Desired yaw angle in radians, scaled to int16 +-PI (+-INT16_MAX) THRUST [4]uint16 // Collective thrust, scaled to uint16 (0..UINT16_MAX) GROUP uint8 // ID of the quadrotor group (0 - 255, up to 256 groups supported) MODE uint8 // ID of the flight mode (0 - 255, up to 256 modes supported) LED_RED [4]uint8 // RGB red channel (0-255) LED_BLUE [4]uint8 // RGB green channel (0-255) LED_GREEN [4]uint8 // RGB blue channel (0-255) } // NewSetQuadSwarmLedRollPitchYawThrust returns a new SetQuadSwarmLedRollPitchYawThrust func NewSetQuadSwarmLedRollPitchYawThrust(ROLL [4]int16, PITCH [4]int16, YAW [4]int16, THRUST [4]uint16, GROUP uint8, MODE uint8, LED_RED [4]uint8, LED_BLUE [4]uint8, LED_GREEN [4]uint8) *SetQuadSwarmLedRollPitchYawThrust { m := SetQuadSwarmLedRollPitchYawThrust{} m.ROLL = ROLL m.PITCH = PITCH m.YAW = YAW m.THRUST = THRUST m.GROUP = GROUP m.MODE = MODE m.LED_RED = LED_RED m.LED_BLUE = LED_BLUE m.LED_GREEN = LED_GREEN return &m } // Id returns the SetQuadSwarmLedRollPitchYawThrust Message ID func (*SetQuadSwarmLedRollPitchYawThrust) Id() uint8 { return 63 } // Len returns the SetQuadSwarmLedRollPitchYawThrust Message Length func (*SetQuadSwarmLedRollPitchYawThrust) Len() uint8 { return 46 } // Crc returns the SetQuadSwarmLedRollPitchYawThrust Message CRC func (*SetQuadSwarmLedRollPitchYawThrust) Crc() uint8 { return 130 } // Pack returns a packed byte array which represents a SetQuadSwarmLedRollPitchYawThrust payload func (m *SetQuadSwarmLedRollPitchYawThrust) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.ROLL); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PITCH); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.YAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.THRUST); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.GROUP); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.MODE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.LED_RED); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.LED_BLUE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.LED_GREEN); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the SetQuadSwarmLedRollPitchYawThrust func (m *SetQuadSwarmLedRollPitchYawThrust) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.ROLL); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PITCH); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.YAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.THRUST); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.GROUP); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.MODE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.LED_RED); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.LED_BLUE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.LED_GREEN); err != nil { panic(err) } } const ( MAVLINK_MSG_SET_QUAD_SWARM_LED_ROLL_PITCH_YAW_THRUST_FIELD_roll_LEN = 4 MAVLINK_MSG_SET_QUAD_SWARM_LED_ROLL_PITCH_YAW_THRUST_FIELD_pitch_LEN = 4 MAVLINK_MSG_SET_QUAD_SWARM_LED_ROLL_PITCH_YAW_THRUST_FIELD_yaw_LEN = 4 MAVLINK_MSG_SET_QUAD_SWARM_LED_ROLL_PITCH_YAW_THRUST_FIELD_thrust_LEN = 4 MAVLINK_MSG_SET_QUAD_SWARM_LED_ROLL_PITCH_YAW_THRUST_FIELD_led_red_LEN = 4 MAVLINK_MSG_SET_QUAD_SWARM_LED_ROLL_PITCH_YAW_THRUST_FIELD_led_blue_LEN = 4 MAVLINK_MSG_SET_QUAD_SWARM_LED_ROLL_PITCH_YAW_THRUST_FIELD_led_green_LEN = 4 ) // MESSAGE STATE_CORRECTION // // MAVLINK_MSG_ID_STATE_CORRECTION 64 // // MAVLINK_MSG_ID_STATE_CORRECTION_LEN 36 // // MAVLINK_MSG_ID_STATE_CORRECTION_CRC 130 type StateCorrection struct { XERR float32 // x position error YERR float32 // y position error ZERR float32 // z position error ROLLERR float32 // roll error (radians) PITCHERR float32 // pitch error (radians) YAWERR float32 // yaw error (radians) VXERR float32 // x velocity VYERR float32 // y velocity VZERR float32 // z velocity } // NewStateCorrection returns a new StateCorrection func NewStateCorrection(XERR float32, YERR float32, ZERR float32, ROLLERR float32, PITCHERR float32, YAWERR float32, VXERR float32, VYERR float32, VZERR float32) *StateCorrection { m := StateCorrection{} m.XERR = XERR m.YERR = YERR m.ZERR = ZERR m.ROLLERR = ROLLERR m.PITCHERR = PITCHERR m.YAWERR = YAWERR m.VXERR = VXERR m.VYERR = VYERR m.VZERR = VZERR return &m } // Id returns the StateCorrection Message ID func (*StateCorrection) Id() uint8 { return 64 } // Len returns the StateCorrection Message Length func (*StateCorrection) Len() uint8 { return 36 } // Crc returns the StateCorrection Message CRC func (*StateCorrection) Crc() uint8 { return 130 } // Pack returns a packed byte array which represents a StateCorrection payload func (m *StateCorrection) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.XERR); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.YERR); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ZERR); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ROLLERR); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PITCHERR); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.YAWERR); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VXERR); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VYERR); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VZERR); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the StateCorrection func (m *StateCorrection) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.XERR); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.YERR); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ZERR); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ROLLERR); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PITCHERR); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.YAWERR); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VXERR); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VYERR); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VZERR); err != nil { panic(err) } } // MESSAGE RC_CHANNELS // // MAVLINK_MSG_ID_RC_CHANNELS 65 // // MAVLINK_MSG_ID_RC_CHANNELS_LEN 42 // // MAVLINK_MSG_ID_RC_CHANNELS_CRC 118 type RcChannels struct { TIME_BOOT_MS uint32 // Timestamp (milliseconds since system boot) CHAN1_RAW uint16 // RC channel 1 value, in microseconds. A value of UINT16_MAX implies the channel is unused. CHAN2_RAW uint16 // RC channel 2 value, in microseconds. A value of UINT16_MAX implies the channel is unused. CHAN3_RAW uint16 // RC channel 3 value, in microseconds. A value of UINT16_MAX implies the channel is unused. CHAN4_RAW uint16 // RC channel 4 value, in microseconds. A value of UINT16_MAX implies the channel is unused. CHAN5_RAW uint16 // RC channel 5 value, in microseconds. A value of UINT16_MAX implies the channel is unused. CHAN6_RAW uint16 // RC channel 6 value, in microseconds. A value of UINT16_MAX implies the channel is unused. CHAN7_RAW uint16 // RC channel 7 value, in microseconds. A value of UINT16_MAX implies the channel is unused. CHAN8_RAW uint16 // RC channel 8 value, in microseconds. A value of UINT16_MAX implies the channel is unused. CHAN9_RAW uint16 // RC channel 9 value, in microseconds. A value of UINT16_MAX implies the channel is unused. CHAN10_RAW uint16 // RC channel 10 value, in microseconds. A value of UINT16_MAX implies the channel is unused. CHAN11_RAW uint16 // RC channel 11 value, in microseconds. A value of UINT16_MAX implies the channel is unused. CHAN12_RAW uint16 // RC channel 12 value, in microseconds. A value of UINT16_MAX implies the channel is unused. CHAN13_RAW uint16 // RC channel 13 value, in microseconds. A value of UINT16_MAX implies the channel is unused. CHAN14_RAW uint16 // RC channel 14 value, in microseconds. A value of UINT16_MAX implies the channel is unused. CHAN15_RAW uint16 // RC channel 15 value, in microseconds. A value of UINT16_MAX implies the channel is unused. CHAN16_RAW uint16 // RC channel 16 value, in microseconds. A value of UINT16_MAX implies the channel is unused. CHAN17_RAW uint16 // RC channel 17 value, in microseconds. A value of UINT16_MAX implies the channel is unused. CHAN18_RAW uint16 // RC channel 18 value, in microseconds. A value of UINT16_MAX implies the channel is unused. CHANCOUNT uint8 // Total number of RC channels being received. This can be larger than 18, indicating that more channels are available but not given in this message. This value should be 0 when no RC channels are available. RSSI uint8 // Receive signal strength indicator, 0: 0%, 100: 100%, 255: invalid/unknown. } // NewRcChannels returns a new RcChannels func NewRcChannels(TIME_BOOT_MS uint32, CHAN1_RAW uint16, CHAN2_RAW uint16, CHAN3_RAW uint16, CHAN4_RAW uint16, CHAN5_RAW uint16, CHAN6_RAW uint16, CHAN7_RAW uint16, CHAN8_RAW uint16, CHAN9_RAW uint16, CHAN10_RAW uint16, CHAN11_RAW uint16, CHAN12_RAW uint16, CHAN13_RAW uint16, CHAN14_RAW uint16, CHAN15_RAW uint16, CHAN16_RAW uint16, CHAN17_RAW uint16, CHAN18_RAW uint16, CHANCOUNT uint8, RSSI uint8) *RcChannels { m := RcChannels{} m.TIME_BOOT_MS = TIME_BOOT_MS m.CHAN1_RAW = CHAN1_RAW m.CHAN2_RAW = CHAN2_RAW m.CHAN3_RAW = CHAN3_RAW m.CHAN4_RAW = CHAN4_RAW m.CHAN5_RAW = CHAN5_RAW m.CHAN6_RAW = CHAN6_RAW m.CHAN7_RAW = CHAN7_RAW m.CHAN8_RAW = CHAN8_RAW m.CHAN9_RAW = CHAN9_RAW m.CHAN10_RAW = CHAN10_RAW m.CHAN11_RAW = CHAN11_RAW m.CHAN12_RAW = CHAN12_RAW m.CHAN13_RAW = CHAN13_RAW m.CHAN14_RAW = CHAN14_RAW m.CHAN15_RAW = CHAN15_RAW m.CHAN16_RAW = CHAN16_RAW m.CHAN17_RAW = CHAN17_RAW m.CHAN18_RAW = CHAN18_RAW m.CHANCOUNT = CHANCOUNT m.RSSI = RSSI return &m } // Id returns the RcChannels Message ID func (*RcChannels) Id() uint8 { return 65 } // Len returns the RcChannels Message Length func (*RcChannels) Len() uint8 { return 42 } // Crc returns the RcChannels Message CRC func (*RcChannels) Crc() uint8 { return 118 } // Pack returns a packed byte array which represents a RcChannels payload func (m *RcChannels) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TIME_BOOT_MS); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN1_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN2_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN3_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN4_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN5_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN6_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN7_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN8_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN9_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN10_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN11_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN12_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN13_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN14_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN15_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN16_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN17_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN18_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHANCOUNT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.RSSI); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the RcChannels func (m *RcChannels) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TIME_BOOT_MS); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN1_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN2_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN3_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN4_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN5_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN6_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN7_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN8_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN9_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN10_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN11_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN12_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN13_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN14_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN15_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN16_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN17_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN18_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHANCOUNT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.RSSI); err != nil { panic(err) } } // MESSAGE REQUEST_DATA_STREAM // // MAVLINK_MSG_ID_REQUEST_DATA_STREAM 66 // // MAVLINK_MSG_ID_REQUEST_DATA_STREAM_LEN 6 // // MAVLINK_MSG_ID_REQUEST_DATA_STREAM_CRC 148 type RequestDataStream struct { REQ_MESSAGE_RATE uint16 // The requested interval between two messages of this type TARGET_SYSTEM uint8 // The target requested to send the message stream. TARGET_COMPONENT uint8 // The target requested to send the message stream. REQ_STREAM_ID uint8 // The ID of the requested data stream START_STOP uint8 // 1 to start sending, 0 to stop sending. } // NewRequestDataStream returns a new RequestDataStream func NewRequestDataStream(REQ_MESSAGE_RATE uint16, TARGET_SYSTEM uint8, TARGET_COMPONENT uint8, REQ_STREAM_ID uint8, START_STOP uint8) *RequestDataStream { m := RequestDataStream{} m.REQ_MESSAGE_RATE = REQ_MESSAGE_RATE m.TARGET_SYSTEM = TARGET_SYSTEM m.TARGET_COMPONENT = TARGET_COMPONENT m.REQ_STREAM_ID = REQ_STREAM_ID m.START_STOP = START_STOP return &m } // Id returns the RequestDataStream Message ID func (*RequestDataStream) Id() uint8 { return 66 } // Len returns the RequestDataStream Message Length func (*RequestDataStream) Len() uint8 { return 6 } // Crc returns the RequestDataStream Message CRC func (*RequestDataStream) Crc() uint8 { return 148 } // Pack returns a packed byte array which represents a RequestDataStream payload func (m *RequestDataStream) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.REQ_MESSAGE_RATE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_COMPONENT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.REQ_STREAM_ID); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.START_STOP); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the RequestDataStream func (m *RequestDataStream) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.REQ_MESSAGE_RATE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_COMPONENT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.REQ_STREAM_ID); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.START_STOP); err != nil { panic(err) } } // MESSAGE DATA_STREAM // // MAVLINK_MSG_ID_DATA_STREAM 67 // // MAVLINK_MSG_ID_DATA_STREAM_LEN 4 // // MAVLINK_MSG_ID_DATA_STREAM_CRC 21 type DataStream struct { MESSAGE_RATE uint16 // The requested interval between two messages of this type STREAM_ID uint8 // The ID of the requested data stream ON_OFF uint8 // 1 stream is enabled, 0 stream is stopped. } // NewDataStream returns a new DataStream func NewDataStream(MESSAGE_RATE uint16, STREAM_ID uint8, ON_OFF uint8) *DataStream { m := DataStream{} m.MESSAGE_RATE = MESSAGE_RATE m.STREAM_ID = STREAM_ID m.ON_OFF = ON_OFF return &m } // Id returns the DataStream Message ID func (*DataStream) Id() uint8 { return 67 } // Len returns the DataStream Message Length func (*DataStream) Len() uint8 { return 4 } // Crc returns the DataStream Message CRC func (*DataStream) Crc() uint8 { return 21 } // Pack returns a packed byte array which represents a DataStream payload func (m *DataStream) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.MESSAGE_RATE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.STREAM_ID); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ON_OFF); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the DataStream func (m *DataStream) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.MESSAGE_RATE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.STREAM_ID); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ON_OFF); err != nil { panic(err) } } // MESSAGE MANUAL_CONTROL // // MAVLINK_MSG_ID_MANUAL_CONTROL 69 // // MAVLINK_MSG_ID_MANUAL_CONTROL_LEN 11 // // MAVLINK_MSG_ID_MANUAL_CONTROL_CRC 243 type ManualControl struct { X int16 // X-axis, normalized to the range [-1000,1000]. A value of INT16_MAX indicates that this axis is invalid. Generally corresponds to forward(1000)-backward(-1000) movement on a joystick and the pitch of a vehicle. Y int16 // Y-axis, normalized to the range [-1000,1000]. A value of INT16_MAX indicates that this axis is invalid. Generally corresponds to left(-1000)-right(1000) movement on a joystick and the roll of a vehicle. Z int16 // Z-axis, normalized to the range [-1000,1000]. A value of INT16_MAX indicates that this axis is invalid. Generally corresponds to a separate slider movement with maximum being 1000 and minimum being -1000 on a joystick and the thrust of a vehicle. R int16 // R-axis, normalized to the range [-1000,1000]. A value of INT16_MAX indicates that this axis is invalid. Generally corresponds to a twisting of the joystick, with counter-clockwise being 1000 and clockwise being -1000, and the yaw of a vehicle. BUTTONS uint16 // A bitfield corresponding to the joystick buttons' current state, 1 for pressed, 0 for released. The lowest bit corresponds to Button 1. TARGET uint8 // The system to be controlled. } // NewManualControl returns a new ManualControl func NewManualControl(X int16, Y int16, Z int16, R int16, BUTTONS uint16, TARGET uint8) *ManualControl { m := ManualControl{} m.X = X m.Y = Y m.Z = Z m.R = R m.BUTTONS = BUTTONS m.TARGET = TARGET return &m } // Id returns the ManualControl Message ID func (*ManualControl) Id() uint8 { return 69 } // Len returns the ManualControl Message Length func (*ManualControl) Len() uint8 { return 11 } // Crc returns the ManualControl Message CRC func (*ManualControl) Crc() uint8 { return 243 } // Pack returns a packed byte array which represents a ManualControl payload func (m *ManualControl) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.X); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.Y); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.Z); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.R); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.BUTTONS); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the ManualControl func (m *ManualControl) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.X); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.Y); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.Z); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.R); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.BUTTONS); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET); err != nil { panic(err) } } // MESSAGE RC_CHANNELS_OVERRIDE // // MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE 70 // // MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_LEN 18 // // MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_CRC 124 type RcChannelsOverride struct { CHAN1_RAW uint16 // RC channel 1 value, in microseconds. A value of UINT16_MAX means to ignore this field. CHAN2_RAW uint16 // RC channel 2 value, in microseconds. A value of UINT16_MAX means to ignore this field. CHAN3_RAW uint16 // RC channel 3 value, in microseconds. A value of UINT16_MAX means to ignore this field. CHAN4_RAW uint16 // RC channel 4 value, in microseconds. A value of UINT16_MAX means to ignore this field. CHAN5_RAW uint16 // RC channel 5 value, in microseconds. A value of UINT16_MAX means to ignore this field. CHAN6_RAW uint16 // RC channel 6 value, in microseconds. A value of UINT16_MAX means to ignore this field. CHAN7_RAW uint16 // RC channel 7 value, in microseconds. A value of UINT16_MAX means to ignore this field. CHAN8_RAW uint16 // RC channel 8 value, in microseconds. A value of UINT16_MAX means to ignore this field. TARGET_SYSTEM uint8 // System ID TARGET_COMPONENT uint8 // Component ID } // NewRcChannelsOverride returns a new RcChannelsOverride func NewRcChannelsOverride(CHAN1_RAW uint16, CHAN2_RAW uint16, CHAN3_RAW uint16, CHAN4_RAW uint16, CHAN5_RAW uint16, CHAN6_RAW uint16, CHAN7_RAW uint16, CHAN8_RAW uint16, TARGET_SYSTEM uint8, TARGET_COMPONENT uint8) *RcChannelsOverride { m := RcChannelsOverride{} m.CHAN1_RAW = CHAN1_RAW m.CHAN2_RAW = CHAN2_RAW m.CHAN3_RAW = CHAN3_RAW m.CHAN4_RAW = CHAN4_RAW m.CHAN5_RAW = CHAN5_RAW m.CHAN6_RAW = CHAN6_RAW m.CHAN7_RAW = CHAN7_RAW m.CHAN8_RAW = CHAN8_RAW m.TARGET_SYSTEM = TARGET_SYSTEM m.TARGET_COMPONENT = TARGET_COMPONENT return &m } // Id returns the RcChannelsOverride Message ID func (*RcChannelsOverride) Id() uint8 { return 70 } // Len returns the RcChannelsOverride Message Length func (*RcChannelsOverride) Len() uint8 { return 18 } // Crc returns the RcChannelsOverride Message CRC func (*RcChannelsOverride) Crc() uint8 { return 124 } // Pack returns a packed byte array which represents a RcChannelsOverride payload func (m *RcChannelsOverride) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.CHAN1_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN2_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN3_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN4_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN5_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN6_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN7_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN8_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_COMPONENT); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the RcChannelsOverride func (m *RcChannelsOverride) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.CHAN1_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN2_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN3_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN4_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN5_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN6_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN7_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN8_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_COMPONENT); err != nil { panic(err) } } // MESSAGE VFR_HUD // // MAVLINK_MSG_ID_VFR_HUD 74 // // MAVLINK_MSG_ID_VFR_HUD_LEN 20 // // MAVLINK_MSG_ID_VFR_HUD_CRC 20 type VfrHud struct { AIRSPEED float32 // Current airspeed in m/s GROUNDSPEED float32 // Current ground speed in m/s ALT float32 // Current altitude (MSL), in meters CLIMB float32 // Current climb rate in meters/second HEADING int16 // Current heading in degrees, in compass units (0..360, 0=north) THROTTLE uint16 // Current throttle setting in integer percent, 0 to 100 } // NewVfrHud returns a new VfrHud func NewVfrHud(AIRSPEED float32, GROUNDSPEED float32, ALT float32, CLIMB float32, HEADING int16, THROTTLE uint16) *VfrHud { m := VfrHud{} m.AIRSPEED = AIRSPEED m.GROUNDSPEED = GROUNDSPEED m.ALT = ALT m.CLIMB = CLIMB m.HEADING = HEADING m.THROTTLE = THROTTLE return &m } // Id returns the VfrHud Message ID func (*VfrHud) Id() uint8 { return 74 } // Len returns the VfrHud Message Length func (*VfrHud) Len() uint8 { return 20 } // Crc returns the VfrHud Message CRC func (*VfrHud) Crc() uint8 { return 20 } // Pack returns a packed byte array which represents a VfrHud payload func (m *VfrHud) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.AIRSPEED); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.GROUNDSPEED); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ALT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CLIMB); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.HEADING); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.THROTTLE); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the VfrHud func (m *VfrHud) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.AIRSPEED); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.GROUNDSPEED); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ALT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CLIMB); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.HEADING); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.THROTTLE); err != nil { panic(err) } } // MESSAGE COMMAND_LONG // // MAVLINK_MSG_ID_COMMAND_LONG 76 // // MAVLINK_MSG_ID_COMMAND_LONG_LEN 33 // // MAVLINK_MSG_ID_COMMAND_LONG_CRC 152 type CommandLong struct { PARAM1 float32 // Parameter 1, as defined by MAV_CMD enum. PARAM2 float32 // Parameter 2, as defined by MAV_CMD enum. PARAM3 float32 // Parameter 3, as defined by MAV_CMD enum. PARAM4 float32 // Parameter 4, as defined by MAV_CMD enum. PARAM5 float32 // Parameter 5, as defined by MAV_CMD enum. PARAM6 float32 // Parameter 6, as defined by MAV_CMD enum. PARAM7 float32 // Parameter 7, as defined by MAV_CMD enum. COMMAND uint16 // Command ID, as defined by MAV_CMD enum. TARGET_SYSTEM uint8 // System which should execute the command TARGET_COMPONENT uint8 // Component which should execute the command, 0 for all components CONFIRMATION uint8 // 0: First transmission of this command. 1-255: Confirmation transmissions (e.g. for kill command) } // NewCommandLong returns a new CommandLong func NewCommandLong(PARAM1 float32, PARAM2 float32, PARAM3 float32, PARAM4 float32, PARAM5 float32, PARAM6 float32, PARAM7 float32, COMMAND uint16, TARGET_SYSTEM uint8, TARGET_COMPONENT uint8, CONFIRMATION uint8) *CommandLong { m := CommandLong{} m.PARAM1 = PARAM1 m.PARAM2 = PARAM2 m.PARAM3 = PARAM3 m.PARAM4 = PARAM4 m.PARAM5 = PARAM5 m.PARAM6 = PARAM6 m.PARAM7 = PARAM7 m.COMMAND = COMMAND m.TARGET_SYSTEM = TARGET_SYSTEM m.TARGET_COMPONENT = TARGET_COMPONENT m.CONFIRMATION = CONFIRMATION return &m } // Id returns the CommandLong Message ID func (*CommandLong) Id() uint8 { return 76 } // Len returns the CommandLong Message Length func (*CommandLong) Len() uint8 { return 33 } // Crc returns the CommandLong Message CRC func (*CommandLong) Crc() uint8 { return 152 } // Pack returns a packed byte array which represents a CommandLong payload func (m *CommandLong) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.PARAM1); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PARAM2); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PARAM3); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PARAM4); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PARAM5); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PARAM6); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PARAM7); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.COMMAND); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_COMPONENT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CONFIRMATION); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the CommandLong func (m *CommandLong) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.PARAM1); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PARAM2); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PARAM3); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PARAM4); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PARAM5); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PARAM6); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PARAM7); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.COMMAND); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_COMPONENT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CONFIRMATION); err != nil { panic(err) } } // MESSAGE COMMAND_ACK // // MAVLINK_MSG_ID_COMMAND_ACK 77 // // MAVLINK_MSG_ID_COMMAND_ACK_LEN 3 // // MAVLINK_MSG_ID_COMMAND_ACK_CRC 143 type CommandAck struct { COMMAND uint16 // Command ID, as defined by MAV_CMD enum. RESULT uint8 // See MAV_RESULT enum } // NewCommandAck returns a new CommandAck func NewCommandAck(COMMAND uint16, RESULT uint8) *CommandAck { m := CommandAck{} m.COMMAND = COMMAND m.RESULT = RESULT return &m } // Id returns the CommandAck Message ID func (*CommandAck) Id() uint8 { return 77 } // Len returns the CommandAck Message Length func (*CommandAck) Len() uint8 { return 3 } // Crc returns the CommandAck Message CRC func (*CommandAck) Crc() uint8 { return 143 } // Pack returns a packed byte array which represents a CommandAck payload func (m *CommandAck) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.COMMAND); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.RESULT); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the CommandAck func (m *CommandAck) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.COMMAND); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.RESULT); err != nil { panic(err) } } // MESSAGE ROLL_PITCH_YAW_RATES_THRUST_SETPOINT // // MAVLINK_MSG_ID_ROLL_PITCH_YAW_RATES_THRUST_SETPOINT 80 // // MAVLINK_MSG_ID_ROLL_PITCH_YAW_RATES_THRUST_SETPOINT_LEN 20 // // MAVLINK_MSG_ID_ROLL_PITCH_YAW_RATES_THRUST_SETPOINT_CRC 127 type RollPitchYawRatesThrustSetpoint struct { TIME_BOOT_MS uint32 // Timestamp in milliseconds since system boot ROLL_RATE float32 // Desired roll rate in radians per second PITCH_RATE float32 // Desired pitch rate in radians per second YAW_RATE float32 // Desired yaw rate in radians per second THRUST float32 // Collective thrust, normalized to 0 .. 1 } // NewRollPitchYawRatesThrustSetpoint returns a new RollPitchYawRatesThrustSetpoint func NewRollPitchYawRatesThrustSetpoint(TIME_BOOT_MS uint32, ROLL_RATE float32, PITCH_RATE float32, YAW_RATE float32, THRUST float32) *RollPitchYawRatesThrustSetpoint { m := RollPitchYawRatesThrustSetpoint{} m.TIME_BOOT_MS = TIME_BOOT_MS m.ROLL_RATE = ROLL_RATE m.PITCH_RATE = PITCH_RATE m.YAW_RATE = YAW_RATE m.THRUST = THRUST return &m } // Id returns the RollPitchYawRatesThrustSetpoint Message ID func (*RollPitchYawRatesThrustSetpoint) Id() uint8 { return 80 } // Len returns the RollPitchYawRatesThrustSetpoint Message Length func (*RollPitchYawRatesThrustSetpoint) Len() uint8 { return 20 } // Crc returns the RollPitchYawRatesThrustSetpoint Message CRC func (*RollPitchYawRatesThrustSetpoint) Crc() uint8 { return 127 } // Pack returns a packed byte array which represents a RollPitchYawRatesThrustSetpoint payload func (m *RollPitchYawRatesThrustSetpoint) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TIME_BOOT_MS); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ROLL_RATE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PITCH_RATE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.YAW_RATE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.THRUST); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the RollPitchYawRatesThrustSetpoint func (m *RollPitchYawRatesThrustSetpoint) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TIME_BOOT_MS); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ROLL_RATE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PITCH_RATE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.YAW_RATE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.THRUST); err != nil { panic(err) } } // MESSAGE MANUAL_SETPOINT // // MAVLINK_MSG_ID_MANUAL_SETPOINT 81 // // MAVLINK_MSG_ID_MANUAL_SETPOINT_LEN 22 // // MAVLINK_MSG_ID_MANUAL_SETPOINT_CRC 106 type ManualSetpoint struct { TIME_BOOT_MS uint32 // Timestamp in milliseconds since system boot ROLL float32 // Desired roll rate in radians per second PITCH float32 // Desired pitch rate in radians per second YAW float32 // Desired yaw rate in radians per second THRUST float32 // Collective thrust, normalized to 0 .. 1 MODE_SWITCH uint8 // Flight mode switch position, 0.. 255 MANUAL_OVERRIDE_SWITCH uint8 // Override mode switch position, 0.. 255 } // NewManualSetpoint returns a new ManualSetpoint func NewManualSetpoint(TIME_BOOT_MS uint32, ROLL float32, PITCH float32, YAW float32, THRUST float32, MODE_SWITCH uint8, MANUAL_OVERRIDE_SWITCH uint8) *ManualSetpoint { m := ManualSetpoint{} m.TIME_BOOT_MS = TIME_BOOT_MS m.ROLL = ROLL m.PITCH = PITCH m.YAW = YAW m.THRUST = THRUST m.MODE_SWITCH = MODE_SWITCH m.MANUAL_OVERRIDE_SWITCH = MANUAL_OVERRIDE_SWITCH return &m } // Id returns the ManualSetpoint Message ID func (*ManualSetpoint) Id() uint8 { return 81 } // Len returns the ManualSetpoint Message Length func (*ManualSetpoint) Len() uint8 { return 22 } // Crc returns the ManualSetpoint Message CRC func (*ManualSetpoint) Crc() uint8 { return 106 } // Pack returns a packed byte array which represents a ManualSetpoint payload func (m *ManualSetpoint) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TIME_BOOT_MS); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ROLL); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PITCH); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.YAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.THRUST); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.MODE_SWITCH); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.MANUAL_OVERRIDE_SWITCH); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the ManualSetpoint func (m *ManualSetpoint) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TIME_BOOT_MS); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ROLL); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PITCH); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.YAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.THRUST); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.MODE_SWITCH); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.MANUAL_OVERRIDE_SWITCH); err != nil { panic(err) } } // MESSAGE ATTITUDE_SETPOINT_EXTERNAL // // MAVLINK_MSG_ID_ATTITUDE_SETPOINT_EXTERNAL 82 // // MAVLINK_MSG_ID_ATTITUDE_SETPOINT_EXTERNAL_LEN 39 // // MAVLINK_MSG_ID_ATTITUDE_SETPOINT_EXTERNAL_CRC 147 type AttitudeSetpointExternal struct { TIME_BOOT_MS uint32 // Timestamp in milliseconds since system boot Q [4]float32 // Attitude quaternion (w, x, y, z order, zero-rotation is 1, 0, 0, 0) BODY_ROLL_RATE float32 // Body roll rate in radians per second BODY_PITCH_RATE float32 // Body roll rate in radians per second BODY_YAW_RATE float32 // Body roll rate in radians per second THRUST float32 // Collective thrust, normalized to 0 .. 1 (-1 .. 1 for vehicles capable of reverse trust) TARGET_SYSTEM uint8 // System ID TARGET_COMPONENT uint8 // Component ID TYPE_MASK uint8 // Mappings: If any of these bits are set, the corresponding input should be ignored: bit 1: body roll rate, bit 2: body pitch rate, bit 3: body yaw rate. bit 4-bit 7: reserved, bit 8: attitude } // NewAttitudeSetpointExternal returns a new AttitudeSetpointExternal func NewAttitudeSetpointExternal(TIME_BOOT_MS uint32, Q [4]float32, BODY_ROLL_RATE float32, BODY_PITCH_RATE float32, BODY_YAW_RATE float32, THRUST float32, TARGET_SYSTEM uint8, TARGET_COMPONENT uint8, TYPE_MASK uint8) *AttitudeSetpointExternal { m := AttitudeSetpointExternal{} m.TIME_BOOT_MS = TIME_BOOT_MS m.Q = Q m.BODY_ROLL_RATE = BODY_ROLL_RATE m.BODY_PITCH_RATE = BODY_PITCH_RATE m.BODY_YAW_RATE = BODY_YAW_RATE m.THRUST = THRUST m.TARGET_SYSTEM = TARGET_SYSTEM m.TARGET_COMPONENT = TARGET_COMPONENT m.TYPE_MASK = TYPE_MASK return &m } // Id returns the AttitudeSetpointExternal Message ID func (*AttitudeSetpointExternal) Id() uint8 { return 82 } // Len returns the AttitudeSetpointExternal Message Length func (*AttitudeSetpointExternal) Len() uint8 { return 39 } // Crc returns the AttitudeSetpointExternal Message CRC func (*AttitudeSetpointExternal) Crc() uint8 { return 147 } // Pack returns a packed byte array which represents a AttitudeSetpointExternal payload func (m *AttitudeSetpointExternal) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TIME_BOOT_MS); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.Q); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.BODY_ROLL_RATE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.BODY_PITCH_RATE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.BODY_YAW_RATE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.THRUST); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_COMPONENT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TYPE_MASK); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the AttitudeSetpointExternal func (m *AttitudeSetpointExternal) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TIME_BOOT_MS); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.Q); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.BODY_ROLL_RATE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.BODY_PITCH_RATE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.BODY_YAW_RATE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.THRUST); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_COMPONENT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TYPE_MASK); err != nil { panic(err) } } const ( MAVLINK_MSG_ATTITUDE_SETPOINT_EXTERNAL_FIELD_q_LEN = 4 ) // MESSAGE LOCAL_NED_POSITION_SETPOINT_EXTERNAL // // MAVLINK_MSG_ID_LOCAL_NED_POSITION_SETPOINT_EXTERNAL 83 // // MAVLINK_MSG_ID_LOCAL_NED_POSITION_SETPOINT_EXTERNAL_LEN 45 // // MAVLINK_MSG_ID_LOCAL_NED_POSITION_SETPOINT_EXTERNAL_CRC 211 type LocalNedPositionSetpointExternal struct { TIME_BOOT_MS uint32 // Timestamp in milliseconds since system boot X float32 // X Position in NED frame in meters Y float32 // Y Position in NED frame in meters Z float32 // Z Position in NED frame in meters (note, altitude is negative in NED) VX float32 // X velocity in NED frame in meter / s VY float32 // Y velocity in NED frame in meter / s VZ float32 // Z velocity in NED frame in meter / s AFX float32 // X acceleration or force (if bit 10 of type_mask is set) in NED frame in meter / s^2 or N AFY float32 // Y acceleration or force (if bit 10 of type_mask is set) in NED frame in meter / s^2 or N AFZ float32 // Z acceleration or force (if bit 10 of type_mask is set) in NED frame in meter / s^2 or N TYPE_MASK uint16 // Bitmask to indicate which dimensions should be ignored by the vehicle: a value of 0b0000000000000000 or 0b0000001000000000 indicates that none of the setpoint dimensions should be ignored. If bit 10 is set the floats afx afy afz should be interpreted as force instead of acceleration. Mapping: bit 1: x, bit 2: y, bit 3: z, bit 4: vx, bit 5: vy, bit 6: vz, bit 7: ax, bit 8: ay, bit 9: az, bit 10: is force setpoint TARGET_SYSTEM uint8 // System ID TARGET_COMPONENT uint8 // Component ID COORDINATE_FRAME uint8 // Valid options are: MAV_FRAME_LOCAL_NED, MAV_FRAME_LOCAL_OFFSET_NED = 5, MAV_FRAME_BODY_NED = 6, MAV_FRAME_BODY_OFFSET_NED = 7 } // NewLocalNedPositionSetpointExternal returns a new LocalNedPositionSetpointExternal func NewLocalNedPositionSetpointExternal(TIME_BOOT_MS uint32, X float32, Y float32, Z float32, VX float32, VY float32, VZ float32, AFX float32, AFY float32, AFZ float32, TYPE_MASK uint16, TARGET_SYSTEM uint8, TARGET_COMPONENT uint8, COORDINATE_FRAME uint8) *LocalNedPositionSetpointExternal { m := LocalNedPositionSetpointExternal{} m.TIME_BOOT_MS = TIME_BOOT_MS m.X = X m.Y = Y m.Z = Z m.VX = VX m.VY = VY m.VZ = VZ m.AFX = AFX m.AFY = AFY m.AFZ = AFZ m.TYPE_MASK = TYPE_MASK m.TARGET_SYSTEM = TARGET_SYSTEM m.TARGET_COMPONENT = TARGET_COMPONENT m.COORDINATE_FRAME = COORDINATE_FRAME return &m } // Id returns the LocalNedPositionSetpointExternal Message ID func (*LocalNedPositionSetpointExternal) Id() uint8 { return 83 } // Len returns the LocalNedPositionSetpointExternal Message Length func (*LocalNedPositionSetpointExternal) Len() uint8 { return 45 } // Crc returns the LocalNedPositionSetpointExternal Message CRC func (*LocalNedPositionSetpointExternal) Crc() uint8 { return 211 } // Pack returns a packed byte array which represents a LocalNedPositionSetpointExternal payload func (m *LocalNedPositionSetpointExternal) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TIME_BOOT_MS); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.X); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.Y); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.Z); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VX); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VY); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VZ); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.AFX); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.AFY); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.AFZ); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TYPE_MASK); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_COMPONENT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.COORDINATE_FRAME); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the LocalNedPositionSetpointExternal func (m *LocalNedPositionSetpointExternal) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TIME_BOOT_MS); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.X); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.Y); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.Z); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VX); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VY); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VZ); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.AFX); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.AFY); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.AFZ); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TYPE_MASK); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_COMPONENT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.COORDINATE_FRAME); err != nil { panic(err) } } // MESSAGE GLOBAL_POSITION_SETPOINT_EXTERNAL_INT // // MAVLINK_MSG_ID_GLOBAL_POSITION_SETPOINT_EXTERNAL_INT 84 // // MAVLINK_MSG_ID_GLOBAL_POSITION_SETPOINT_EXTERNAL_INT_LEN 44 // // MAVLINK_MSG_ID_GLOBAL_POSITION_SETPOINT_EXTERNAL_INT_CRC 198 type GlobalPositionSetpointExternalInt struct { TIME_BOOT_MS uint32 // Timestamp in milliseconds since system boot. The rationale for the timestamp in the setpoint is to allow the system to compensate for the transport delay of the setpoint. This allows the system to compensate processing latency. LAT_INT int32 // X Position in WGS84 frame in 1e7 * meters LON_INT int32 // Y Position in WGS84 frame in 1e7 * meters ALT float32 // Altitude in WGS84, not AMSL VX float32 // X velocity in NED frame in meter / s VY float32 // Y velocity in NED frame in meter / s VZ float32 // Z velocity in NED frame in meter / s AFX float32 // X acceleration or force (if bit 10 of type_mask is set) in NED frame in meter / s^2 or N AFY float32 // Y acceleration or force (if bit 10 of type_mask is set) in NED frame in meter / s^2 or N AFZ float32 // Z acceleration or force (if bit 10 of type_mask is set) in NED frame in meter / s^2 or N TYPE_MASK uint16 // Bitmask to indicate which dimensions should be ignored by the vehicle: a value of 0b0000000000000000 or 0b0000001000000000 indicates that none of the setpoint dimensions should be ignored. If bit 10 is set the floats afx afy afz should be interpreted as force instead of acceleration. Mapping: bit 1: x, bit 2: y, bit 3: z, bit 4: vx, bit 5: vy, bit 6: vz, bit 7: ax, bit 8: ay, bit 9: az, bit 10: is force setpoint TARGET_SYSTEM uint8 // System ID TARGET_COMPONENT uint8 // Component ID } // NewGlobalPositionSetpointExternalInt returns a new GlobalPositionSetpointExternalInt func NewGlobalPositionSetpointExternalInt(TIME_BOOT_MS uint32, LAT_INT int32, LON_INT int32, ALT float32, VX float32, VY float32, VZ float32, AFX float32, AFY float32, AFZ float32, TYPE_MASK uint16, TARGET_SYSTEM uint8, TARGET_COMPONENT uint8) *GlobalPositionSetpointExternalInt { m := GlobalPositionSetpointExternalInt{} m.TIME_BOOT_MS = TIME_BOOT_MS m.LAT_INT = LAT_INT m.LON_INT = LON_INT m.ALT = ALT m.VX = VX m.VY = VY m.VZ = VZ m.AFX = AFX m.AFY = AFY m.AFZ = AFZ m.TYPE_MASK = TYPE_MASK m.TARGET_SYSTEM = TARGET_SYSTEM m.TARGET_COMPONENT = TARGET_COMPONENT return &m } // Id returns the GlobalPositionSetpointExternalInt Message ID func (*GlobalPositionSetpointExternalInt) Id() uint8 { return 84 } // Len returns the GlobalPositionSetpointExternalInt Message Length func (*GlobalPositionSetpointExternalInt) Len() uint8 { return 44 } // Crc returns the GlobalPositionSetpointExternalInt Message CRC func (*GlobalPositionSetpointExternalInt) Crc() uint8 { return 198 } // Pack returns a packed byte array which represents a GlobalPositionSetpointExternalInt payload func (m *GlobalPositionSetpointExternalInt) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TIME_BOOT_MS); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.LAT_INT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.LON_INT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ALT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VX); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VY); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VZ); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.AFX); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.AFY); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.AFZ); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TYPE_MASK); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_COMPONENT); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the GlobalPositionSetpointExternalInt func (m *GlobalPositionSetpointExternalInt) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TIME_BOOT_MS); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.LAT_INT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.LON_INT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ALT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VX); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VY); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VZ); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.AFX); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.AFY); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.AFZ); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TYPE_MASK); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_COMPONENT); err != nil { panic(err) } } // MESSAGE LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET // // MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET 89 // // MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_LEN 28 // // MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_CRC 231 type LocalPositionNedSystemGlobalOffset struct { TIME_BOOT_MS uint32 // Timestamp (milliseconds since system boot) X float32 // X Position Y float32 // Y Position Z float32 // Z Position ROLL float32 // Roll PITCH float32 // Pitch YAW float32 // Yaw } // NewLocalPositionNedSystemGlobalOffset returns a new LocalPositionNedSystemGlobalOffset func NewLocalPositionNedSystemGlobalOffset(TIME_BOOT_MS uint32, X float32, Y float32, Z float32, ROLL float32, PITCH float32, YAW float32) *LocalPositionNedSystemGlobalOffset { m := LocalPositionNedSystemGlobalOffset{} m.TIME_BOOT_MS = TIME_BOOT_MS m.X = X m.Y = Y m.Z = Z m.ROLL = ROLL m.PITCH = PITCH m.YAW = YAW return &m } // Id returns the LocalPositionNedSystemGlobalOffset Message ID func (*LocalPositionNedSystemGlobalOffset) Id() uint8 { return 89 } // Len returns the LocalPositionNedSystemGlobalOffset Message Length func (*LocalPositionNedSystemGlobalOffset) Len() uint8 { return 28 } // Crc returns the LocalPositionNedSystemGlobalOffset Message CRC func (*LocalPositionNedSystemGlobalOffset) Crc() uint8 { return 231 } // Pack returns a packed byte array which represents a LocalPositionNedSystemGlobalOffset payload func (m *LocalPositionNedSystemGlobalOffset) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TIME_BOOT_MS); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.X); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.Y); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.Z); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ROLL); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PITCH); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.YAW); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the LocalPositionNedSystemGlobalOffset func (m *LocalPositionNedSystemGlobalOffset) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TIME_BOOT_MS); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.X); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.Y); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.Z); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ROLL); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PITCH); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.YAW); err != nil { panic(err) } } // MESSAGE HIL_STATE // // MAVLINK_MSG_ID_HIL_STATE 90 // // MAVLINK_MSG_ID_HIL_STATE_LEN 56 // // MAVLINK_MSG_ID_HIL_STATE_CRC 183 type HilState struct { TIME_USEC uint64 // Timestamp (microseconds since UNIX epoch or microseconds since system boot) ROLL float32 // Roll angle (rad) PITCH float32 // Pitch angle (rad) YAW float32 // Yaw angle (rad) ROLLSPEED float32 // Body frame roll / phi angular speed (rad/s) PITCHSPEED float32 // Body frame pitch / theta angular speed (rad/s) YAWSPEED float32 // Body frame yaw / psi angular speed (rad/s) LAT int32 // Latitude, expressed as * 1E7 LON int32 // Longitude, expressed as * 1E7 ALT int32 // Altitude in meters, expressed as * 1000 (millimeters) VX int16 // Ground X Speed (Latitude), expressed as m/s * 100 VY int16 // Ground Y Speed (Longitude), expressed as m/s * 100 VZ int16 // Ground Z Speed (Altitude), expressed as m/s * 100 XACC int16 // X acceleration (mg) YACC int16 // Y acceleration (mg) ZACC int16 // Z acceleration (mg) } // NewHilState returns a new HilState func NewHilState(TIME_USEC uint64, ROLL float32, PITCH float32, YAW float32, ROLLSPEED float32, PITCHSPEED float32, YAWSPEED float32, LAT int32, LON int32, ALT int32, VX int16, VY int16, VZ int16, XACC int16, YACC int16, ZACC int16) *HilState { m := HilState{} m.TIME_USEC = TIME_USEC m.ROLL = ROLL m.PITCH = PITCH m.YAW = YAW m.ROLLSPEED = ROLLSPEED m.PITCHSPEED = PITCHSPEED m.YAWSPEED = YAWSPEED m.LAT = LAT m.LON = LON m.ALT = ALT m.VX = VX m.VY = VY m.VZ = VZ m.XACC = XACC m.YACC = YACC m.ZACC = ZACC return &m } // Id returns the HilState Message ID func (*HilState) Id() uint8 { return 90 } // Len returns the HilState Message Length func (*HilState) Len() uint8 { return 56 } // Crc returns the HilState Message CRC func (*HilState) Crc() uint8 { return 183 } // Pack returns a packed byte array which represents a HilState payload func (m *HilState) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TIME_USEC); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ROLL); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PITCH); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.YAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ROLLSPEED); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PITCHSPEED); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.YAWSPEED); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.LAT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.LON); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ALT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VX); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VY); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VZ); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.XACC); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.YACC); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ZACC); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the HilState func (m *HilState) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TIME_USEC); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ROLL); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PITCH); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.YAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ROLLSPEED); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PITCHSPEED); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.YAWSPEED); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.LAT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.LON); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ALT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VX); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VY); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VZ); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.XACC); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.YACC); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ZACC); err != nil { panic(err) } } // MESSAGE HIL_CONTROLS // // MAVLINK_MSG_ID_HIL_CONTROLS 91 // // MAVLINK_MSG_ID_HIL_CONTROLS_LEN 42 // // MAVLINK_MSG_ID_HIL_CONTROLS_CRC 63 type HilControls struct { TIME_USEC uint64 // Timestamp (microseconds since UNIX epoch or microseconds since system boot) ROLL_AILERONS float32 // Control output -1 .. 1 PITCH_ELEVATOR float32 // Control output -1 .. 1 YAW_RUDDER float32 // Control output -1 .. 1 THROTTLE float32 // Throttle 0 .. 1 AUX1 float32 // Aux 1, -1 .. 1 AUX2 float32 // Aux 2, -1 .. 1 AUX3 float32 // Aux 3, -1 .. 1 AUX4 float32 // Aux 4, -1 .. 1 MODE uint8 // System mode (MAV_MODE) NAV_MODE uint8 // Navigation mode (MAV_NAV_MODE) } // NewHilControls returns a new HilControls func NewHilControls(TIME_USEC uint64, ROLL_AILERONS float32, PITCH_ELEVATOR float32, YAW_RUDDER float32, THROTTLE float32, AUX1 float32, AUX2 float32, AUX3 float32, AUX4 float32, MODE uint8, NAV_MODE uint8) *HilControls { m := HilControls{} m.TIME_USEC = TIME_USEC m.ROLL_AILERONS = ROLL_AILERONS m.PITCH_ELEVATOR = PITCH_ELEVATOR m.YAW_RUDDER = YAW_RUDDER m.THROTTLE = THROTTLE m.AUX1 = AUX1 m.AUX2 = AUX2 m.AUX3 = AUX3 m.AUX4 = AUX4 m.MODE = MODE m.NAV_MODE = NAV_MODE return &m } // Id returns the HilControls Message ID func (*HilControls) Id() uint8 { return 91 } // Len returns the HilControls Message Length func (*HilControls) Len() uint8 { return 42 } // Crc returns the HilControls Message CRC func (*HilControls) Crc() uint8 { return 63 } // Pack returns a packed byte array which represents a HilControls payload func (m *HilControls) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TIME_USEC); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ROLL_AILERONS); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PITCH_ELEVATOR); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.YAW_RUDDER); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.THROTTLE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.AUX1); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.AUX2); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.AUX3); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.AUX4); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.MODE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.NAV_MODE); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the HilControls func (m *HilControls) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TIME_USEC); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ROLL_AILERONS); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PITCH_ELEVATOR); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.YAW_RUDDER); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.THROTTLE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.AUX1); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.AUX2); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.AUX3); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.AUX4); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.MODE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.NAV_MODE); err != nil { panic(err) } } // MESSAGE HIL_RC_INPUTS_RAW // // MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW 92 // // MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_LEN 33 // // MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_CRC 54 type HilRcInputsRaw struct { TIME_USEC uint64 // Timestamp (microseconds since UNIX epoch or microseconds since system boot) CHAN1_RAW uint16 // RC channel 1 value, in microseconds CHAN2_RAW uint16 // RC channel 2 value, in microseconds CHAN3_RAW uint16 // RC channel 3 value, in microseconds CHAN4_RAW uint16 // RC channel 4 value, in microseconds CHAN5_RAW uint16 // RC channel 5 value, in microseconds CHAN6_RAW uint16 // RC channel 6 value, in microseconds CHAN7_RAW uint16 // RC channel 7 value, in microseconds CHAN8_RAW uint16 // RC channel 8 value, in microseconds CHAN9_RAW uint16 // RC channel 9 value, in microseconds CHAN10_RAW uint16 // RC channel 10 value, in microseconds CHAN11_RAW uint16 // RC channel 11 value, in microseconds CHAN12_RAW uint16 // RC channel 12 value, in microseconds RSSI uint8 // Receive signal strength indicator, 0: 0%, 255: 100% } // NewHilRcInputsRaw returns a new HilRcInputsRaw func NewHilRcInputsRaw(TIME_USEC uint64, CHAN1_RAW uint16, CHAN2_RAW uint16, CHAN3_RAW uint16, CHAN4_RAW uint16, CHAN5_RAW uint16, CHAN6_RAW uint16, CHAN7_RAW uint16, CHAN8_RAW uint16, CHAN9_RAW uint16, CHAN10_RAW uint16, CHAN11_RAW uint16, CHAN12_RAW uint16, RSSI uint8) *HilRcInputsRaw { m := HilRcInputsRaw{} m.TIME_USEC = TIME_USEC m.CHAN1_RAW = CHAN1_RAW m.CHAN2_RAW = CHAN2_RAW m.CHAN3_RAW = CHAN3_RAW m.CHAN4_RAW = CHAN4_RAW m.CHAN5_RAW = CHAN5_RAW m.CHAN6_RAW = CHAN6_RAW m.CHAN7_RAW = CHAN7_RAW m.CHAN8_RAW = CHAN8_RAW m.CHAN9_RAW = CHAN9_RAW m.CHAN10_RAW = CHAN10_RAW m.CHAN11_RAW = CHAN11_RAW m.CHAN12_RAW = CHAN12_RAW m.RSSI = RSSI return &m } // Id returns the HilRcInputsRaw Message ID func (*HilRcInputsRaw) Id() uint8 { return 92 } // Len returns the HilRcInputsRaw Message Length func (*HilRcInputsRaw) Len() uint8 { return 33 } // Crc returns the HilRcInputsRaw Message CRC func (*HilRcInputsRaw) Crc() uint8 { return 54 } // Pack returns a packed byte array which represents a HilRcInputsRaw payload func (m *HilRcInputsRaw) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TIME_USEC); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN1_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN2_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN3_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN4_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN5_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN6_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN7_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN8_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN9_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN10_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN11_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CHAN12_RAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.RSSI); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the HilRcInputsRaw func (m *HilRcInputsRaw) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TIME_USEC); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN1_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN2_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN3_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN4_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN5_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN6_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN7_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN8_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN9_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN10_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN11_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CHAN12_RAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.RSSI); err != nil { panic(err) } } // MESSAGE OPTICAL_FLOW // // MAVLINK_MSG_ID_OPTICAL_FLOW 100 // // MAVLINK_MSG_ID_OPTICAL_FLOW_LEN 26 // // MAVLINK_MSG_ID_OPTICAL_FLOW_CRC 175 type OpticalFlow struct { TIME_USEC uint64 // Timestamp (UNIX) FLOW_COMP_M_X float32 // Flow in meters in x-sensor direction, angular-speed compensated FLOW_COMP_M_Y float32 // Flow in meters in y-sensor direction, angular-speed compensated GROUND_DISTANCE float32 // Ground distance in meters. Positive value: distance known. Negative value: Unknown distance FLOW_X int16 // Flow in pixels * 10 in x-sensor direction (dezi-pixels) FLOW_Y int16 // Flow in pixels * 10 in y-sensor direction (dezi-pixels) SENSOR_ID uint8 // Sensor ID QUALITY uint8 // Optical flow quality / confidence. 0: bad, 255: maximum quality } // NewOpticalFlow returns a new OpticalFlow func NewOpticalFlow(TIME_USEC uint64, FLOW_COMP_M_X float32, FLOW_COMP_M_Y float32, GROUND_DISTANCE float32, FLOW_X int16, FLOW_Y int16, SENSOR_ID uint8, QUALITY uint8) *OpticalFlow { m := OpticalFlow{} m.TIME_USEC = TIME_USEC m.FLOW_COMP_M_X = FLOW_COMP_M_X m.FLOW_COMP_M_Y = FLOW_COMP_M_Y m.GROUND_DISTANCE = GROUND_DISTANCE m.FLOW_X = FLOW_X m.FLOW_Y = FLOW_Y m.SENSOR_ID = SENSOR_ID m.QUALITY = QUALITY return &m } // Id returns the OpticalFlow Message ID func (*OpticalFlow) Id() uint8 { return 100 } // Len returns the OpticalFlow Message Length func (*OpticalFlow) Len() uint8 { return 26 } // Crc returns the OpticalFlow Message CRC func (*OpticalFlow) Crc() uint8 { return 175 } // Pack returns a packed byte array which represents a OpticalFlow payload func (m *OpticalFlow) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TIME_USEC); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.FLOW_COMP_M_X); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.FLOW_COMP_M_Y); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.GROUND_DISTANCE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.FLOW_X); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.FLOW_Y); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.SENSOR_ID); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.QUALITY); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the OpticalFlow func (m *OpticalFlow) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TIME_USEC); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.FLOW_COMP_M_X); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.FLOW_COMP_M_Y); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.GROUND_DISTANCE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.FLOW_X); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.FLOW_Y); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.SENSOR_ID); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.QUALITY); err != nil { panic(err) } } // MESSAGE GLOBAL_VISION_POSITION_ESTIMATE // // MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE 101 // // MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_LEN 32 // // MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_CRC 102 type GlobalVisionPositionEstimate struct { USEC uint64 // Timestamp (microseconds, synced to UNIX time or since system boot) X float32 // Global X position Y float32 // Global Y position Z float32 // Global Z position ROLL float32 // Roll angle in rad PITCH float32 // Pitch angle in rad YAW float32 // Yaw angle in rad } // NewGlobalVisionPositionEstimate returns a new GlobalVisionPositionEstimate func NewGlobalVisionPositionEstimate(USEC uint64, X float32, Y float32, Z float32, ROLL float32, PITCH float32, YAW float32) *GlobalVisionPositionEstimate { m := GlobalVisionPositionEstimate{} m.USEC = USEC m.X = X m.Y = Y m.Z = Z m.ROLL = ROLL m.PITCH = PITCH m.YAW = YAW return &m } // Id returns the GlobalVisionPositionEstimate Message ID func (*GlobalVisionPositionEstimate) Id() uint8 { return 101 } // Len returns the GlobalVisionPositionEstimate Message Length func (*GlobalVisionPositionEstimate) Len() uint8 { return 32 } // Crc returns the GlobalVisionPositionEstimate Message CRC func (*GlobalVisionPositionEstimate) Crc() uint8 { return 102 } // Pack returns a packed byte array which represents a GlobalVisionPositionEstimate payload func (m *GlobalVisionPositionEstimate) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.USEC); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.X); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.Y); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.Z); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ROLL); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PITCH); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.YAW); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the GlobalVisionPositionEstimate func (m *GlobalVisionPositionEstimate) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.USEC); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.X); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.Y); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.Z); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ROLL); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PITCH); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.YAW); err != nil { panic(err) } } // MESSAGE VISION_POSITION_ESTIMATE // // MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE 102 // // MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_LEN 32 // // MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_CRC 158 type VisionPositionEstimate struct { USEC uint64 // Timestamp (microseconds, synced to UNIX time or since system boot) X float32 // Global X position Y float32 // Global Y position Z float32 // Global Z position ROLL float32 // Roll angle in rad PITCH float32 // Pitch angle in rad YAW float32 // Yaw angle in rad } // NewVisionPositionEstimate returns a new VisionPositionEstimate func NewVisionPositionEstimate(USEC uint64, X float32, Y float32, Z float32, ROLL float32, PITCH float32, YAW float32) *VisionPositionEstimate { m := VisionPositionEstimate{} m.USEC = USEC m.X = X m.Y = Y m.Z = Z m.ROLL = ROLL m.PITCH = PITCH m.YAW = YAW return &m } // Id returns the VisionPositionEstimate Message ID func (*VisionPositionEstimate) Id() uint8 { return 102 } // Len returns the VisionPositionEstimate Message Length func (*VisionPositionEstimate) Len() uint8 { return 32 } // Crc returns the VisionPositionEstimate Message CRC func (*VisionPositionEstimate) Crc() uint8 { return 158 } // Pack returns a packed byte array which represents a VisionPositionEstimate payload func (m *VisionPositionEstimate) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.USEC); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.X); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.Y); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.Z); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ROLL); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PITCH); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.YAW); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the VisionPositionEstimate func (m *VisionPositionEstimate) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.USEC); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.X); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.Y); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.Z); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ROLL); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PITCH); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.YAW); err != nil { panic(err) } } // MESSAGE VISION_SPEED_ESTIMATE // // MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE 103 // // MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_LEN 20 // // MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_CRC 208 type VisionSpeedEstimate struct { USEC uint64 // Timestamp (microseconds, synced to UNIX time or since system boot) X float32 // Global X speed Y float32 // Global Y speed Z float32 // Global Z speed } // NewVisionSpeedEstimate returns a new VisionSpeedEstimate func NewVisionSpeedEstimate(USEC uint64, X float32, Y float32, Z float32) *VisionSpeedEstimate { m := VisionSpeedEstimate{} m.USEC = USEC m.X = X m.Y = Y m.Z = Z return &m } // Id returns the VisionSpeedEstimate Message ID func (*VisionSpeedEstimate) Id() uint8 { return 103 } // Len returns the VisionSpeedEstimate Message Length func (*VisionSpeedEstimate) Len() uint8 { return 20 } // Crc returns the VisionSpeedEstimate Message CRC func (*VisionSpeedEstimate) Crc() uint8 { return 208 } // Pack returns a packed byte array which represents a VisionSpeedEstimate payload func (m *VisionSpeedEstimate) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.USEC); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.X); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.Y); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.Z); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the VisionSpeedEstimate func (m *VisionSpeedEstimate) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.USEC); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.X); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.Y); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.Z); err != nil { panic(err) } } // MESSAGE VICON_POSITION_ESTIMATE // // MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE 104 // // MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_LEN 32 // // MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_CRC 56 type ViconPositionEstimate struct { USEC uint64 // Timestamp (microseconds, synced to UNIX time or since system boot) X float32 // Global X position Y float32 // Global Y position Z float32 // Global Z position ROLL float32 // Roll angle in rad PITCH float32 // Pitch angle in rad YAW float32 // Yaw angle in rad } // NewViconPositionEstimate returns a new ViconPositionEstimate func NewViconPositionEstimate(USEC uint64, X float32, Y float32, Z float32, ROLL float32, PITCH float32, YAW float32) *ViconPositionEstimate { m := ViconPositionEstimate{} m.USEC = USEC m.X = X m.Y = Y m.Z = Z m.ROLL = ROLL m.PITCH = PITCH m.YAW = YAW return &m } // Id returns the ViconPositionEstimate Message ID func (*ViconPositionEstimate) Id() uint8 { return 104 } // Len returns the ViconPositionEstimate Message Length func (*ViconPositionEstimate) Len() uint8 { return 32 } // Crc returns the ViconPositionEstimate Message CRC func (*ViconPositionEstimate) Crc() uint8 { return 56 } // Pack returns a packed byte array which represents a ViconPositionEstimate payload func (m *ViconPositionEstimate) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.USEC); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.X); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.Y); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.Z); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ROLL); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PITCH); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.YAW); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the ViconPositionEstimate func (m *ViconPositionEstimate) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.USEC); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.X); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.Y); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.Z); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ROLL); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PITCH); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.YAW); err != nil { panic(err) } } // MESSAGE HIGHRES_IMU // // MAVLINK_MSG_ID_HIGHRES_IMU 105 // // MAVLINK_MSG_ID_HIGHRES_IMU_LEN 62 // // MAVLINK_MSG_ID_HIGHRES_IMU_CRC 93 type HighresImu struct { TIME_USEC uint64 // Timestamp (microseconds, synced to UNIX time or since system boot) XACC float32 // X acceleration (m/s^2) YACC float32 // Y acceleration (m/s^2) ZACC float32 // Z acceleration (m/s^2) XGYRO float32 // Angular speed around X axis (rad / sec) YGYRO float32 // Angular speed around Y axis (rad / sec) ZGYRO float32 // Angular speed around Z axis (rad / sec) XMAG float32 // X Magnetic field (Gauss) YMAG float32 // Y Magnetic field (Gauss) ZMAG float32 // Z Magnetic field (Gauss) ABS_PRESSURE float32 // Absolute pressure in millibar DIFF_PRESSURE float32 // Differential pressure in millibar PRESSURE_ALT float32 // Altitude calculated from pressure TEMPERATURE float32 // Temperature in degrees celsius FIELDS_UPDATED uint16 // Bitmask for fields that have updated since last message, bit 0 = xacc, bit 12: temperature } // NewHighresImu returns a new HighresImu func NewHighresImu(TIME_USEC uint64, XACC float32, YACC float32, ZACC float32, XGYRO float32, YGYRO float32, ZGYRO float32, XMAG float32, YMAG float32, ZMAG float32, ABS_PRESSURE float32, DIFF_PRESSURE float32, PRESSURE_ALT float32, TEMPERATURE float32, FIELDS_UPDATED uint16) *HighresImu { m := HighresImu{} m.TIME_USEC = TIME_USEC m.XACC = XACC m.YACC = YACC m.ZACC = ZACC m.XGYRO = XGYRO m.YGYRO = YGYRO m.ZGYRO = ZGYRO m.XMAG = XMAG m.YMAG = YMAG m.ZMAG = ZMAG m.ABS_PRESSURE = ABS_PRESSURE m.DIFF_PRESSURE = DIFF_PRESSURE m.PRESSURE_ALT = PRESSURE_ALT m.TEMPERATURE = TEMPERATURE m.FIELDS_UPDATED = FIELDS_UPDATED return &m } // Id returns the HighresImu Message ID func (*HighresImu) Id() uint8 { return 105 } // Len returns the HighresImu Message Length func (*HighresImu) Len() uint8 { return 62 } // Crc returns the HighresImu Message CRC func (*HighresImu) Crc() uint8 { return 93 } // Pack returns a packed byte array which represents a HighresImu payload func (m *HighresImu) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TIME_USEC); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.XACC); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.YACC); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ZACC); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.XGYRO); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.YGYRO); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ZGYRO); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.XMAG); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.YMAG); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ZMAG); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ABS_PRESSURE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.DIFF_PRESSURE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PRESSURE_ALT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TEMPERATURE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.FIELDS_UPDATED); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the HighresImu func (m *HighresImu) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TIME_USEC); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.XACC); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.YACC); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ZACC); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.XGYRO); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.YGYRO); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ZGYRO); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.XMAG); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.YMAG); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ZMAG); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ABS_PRESSURE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.DIFF_PRESSURE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PRESSURE_ALT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TEMPERATURE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.FIELDS_UPDATED); err != nil { panic(err) } } // MESSAGE OMNIDIRECTIONAL_FLOW // // MAVLINK_MSG_ID_OMNIDIRECTIONAL_FLOW 106 // // MAVLINK_MSG_ID_OMNIDIRECTIONAL_FLOW_LEN 54 // // MAVLINK_MSG_ID_OMNIDIRECTIONAL_FLOW_CRC 211 type OmnidirectionalFlow struct { TIME_USEC uint64 // Timestamp (microseconds, synced to UNIX time or since system boot) FRONT_DISTANCE_M float32 // Front distance in meters. Positive value (including zero): distance known. Negative value: Unknown distance LEFT [10]int16 // Flow in deci pixels (1 = 0.1 pixel) on left hemisphere RIGHT [10]int16 // Flow in deci pixels (1 = 0.1 pixel) on right hemisphere SENSOR_ID uint8 // Sensor ID QUALITY uint8 // Optical flow quality / confidence. 0: bad, 255: maximum quality } // NewOmnidirectionalFlow returns a new OmnidirectionalFlow func NewOmnidirectionalFlow(TIME_USEC uint64, FRONT_DISTANCE_M float32, LEFT [10]int16, RIGHT [10]int16, SENSOR_ID uint8, QUALITY uint8) *OmnidirectionalFlow { m := OmnidirectionalFlow{} m.TIME_USEC = TIME_USEC m.FRONT_DISTANCE_M = FRONT_DISTANCE_M m.LEFT = LEFT m.RIGHT = RIGHT m.SENSOR_ID = SENSOR_ID m.QUALITY = QUALITY return &m } // Id returns the OmnidirectionalFlow Message ID func (*OmnidirectionalFlow) Id() uint8 { return 106 } // Len returns the OmnidirectionalFlow Message Length func (*OmnidirectionalFlow) Len() uint8 { return 54 } // Crc returns the OmnidirectionalFlow Message CRC func (*OmnidirectionalFlow) Crc() uint8 { return 211 } // Pack returns a packed byte array which represents a OmnidirectionalFlow payload func (m *OmnidirectionalFlow) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TIME_USEC); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.FRONT_DISTANCE_M); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.LEFT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.RIGHT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.SENSOR_ID); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.QUALITY); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the OmnidirectionalFlow func (m *OmnidirectionalFlow) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TIME_USEC); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.FRONT_DISTANCE_M); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.LEFT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.RIGHT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.SENSOR_ID); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.QUALITY); err != nil { panic(err) } } const ( MAVLINK_MSG_OMNIDIRECTIONAL_FLOW_FIELD_left_LEN = 10 MAVLINK_MSG_OMNIDIRECTIONAL_FLOW_FIELD_right_LEN = 10 ) // MESSAGE HIL_SENSOR // // MAVLINK_MSG_ID_HIL_SENSOR 107 // // MAVLINK_MSG_ID_HIL_SENSOR_LEN 64 // // MAVLINK_MSG_ID_HIL_SENSOR_CRC 108 type HilSensor struct { TIME_USEC uint64 // Timestamp (microseconds, synced to UNIX time or since system boot) XACC float32 // X acceleration (m/s^2) YACC float32 // Y acceleration (m/s^2) ZACC float32 // Z acceleration (m/s^2) XGYRO float32 // Angular speed around X axis in body frame (rad / sec) YGYRO float32 // Angular speed around Y axis in body frame (rad / sec) ZGYRO float32 // Angular speed around Z axis in body frame (rad / sec) XMAG float32 // X Magnetic field (Gauss) YMAG float32 // Y Magnetic field (Gauss) ZMAG float32 // Z Magnetic field (Gauss) ABS_PRESSURE float32 // Absolute pressure in millibar DIFF_PRESSURE float32 // Differential pressure (airspeed) in millibar PRESSURE_ALT float32 // Altitude calculated from pressure TEMPERATURE float32 // Temperature in degrees celsius FIELDS_UPDATED uint32 // Bitmask for fields that have updated since last message, bit 0 = xacc, bit 12: temperature } // NewHilSensor returns a new HilSensor func NewHilSensor(TIME_USEC uint64, XACC float32, YACC float32, ZACC float32, XGYRO float32, YGYRO float32, ZGYRO float32, XMAG float32, YMAG float32, ZMAG float32, ABS_PRESSURE float32, DIFF_PRESSURE float32, PRESSURE_ALT float32, TEMPERATURE float32, FIELDS_UPDATED uint32) *HilSensor { m := HilSensor{} m.TIME_USEC = TIME_USEC m.XACC = XACC m.YACC = YACC m.ZACC = ZACC m.XGYRO = XGYRO m.YGYRO = YGYRO m.ZGYRO = ZGYRO m.XMAG = XMAG m.YMAG = YMAG m.ZMAG = ZMAG m.ABS_PRESSURE = ABS_PRESSURE m.DIFF_PRESSURE = DIFF_PRESSURE m.PRESSURE_ALT = PRESSURE_ALT m.TEMPERATURE = TEMPERATURE m.FIELDS_UPDATED = FIELDS_UPDATED return &m } // Id returns the HilSensor Message ID func (*HilSensor) Id() uint8 { return 107 } // Len returns the HilSensor Message Length func (*HilSensor) Len() uint8 { return 64 } // Crc returns the HilSensor Message CRC func (*HilSensor) Crc() uint8 { return 108 } // Pack returns a packed byte array which represents a HilSensor payload func (m *HilSensor) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TIME_USEC); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.XACC); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.YACC); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ZACC); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.XGYRO); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.YGYRO); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ZGYRO); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.XMAG); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.YMAG); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ZMAG); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ABS_PRESSURE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.DIFF_PRESSURE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PRESSURE_ALT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TEMPERATURE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.FIELDS_UPDATED); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the HilSensor func (m *HilSensor) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TIME_USEC); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.XACC); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.YACC); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ZACC); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.XGYRO); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.YGYRO); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ZGYRO); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.XMAG); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.YMAG); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ZMAG); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ABS_PRESSURE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.DIFF_PRESSURE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PRESSURE_ALT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TEMPERATURE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.FIELDS_UPDATED); err != nil { panic(err) } } // MESSAGE SIM_STATE // // MAVLINK_MSG_ID_SIM_STATE 108 // // MAVLINK_MSG_ID_SIM_STATE_LEN 84 // // MAVLINK_MSG_ID_SIM_STATE_CRC 32 type SimState struct { Q1 float32 // True attitude quaternion component 1, w (1 in null-rotation) Q2 float32 // True attitude quaternion component 2, x (0 in null-rotation) Q3 float32 // True attitude quaternion component 3, y (0 in null-rotation) Q4 float32 // True attitude quaternion component 4, z (0 in null-rotation) ROLL float32 // Attitude roll expressed as Euler angles, not recommended except for human-readable outputs PITCH float32 // Attitude pitch expressed as Euler angles, not recommended except for human-readable outputs YAW float32 // Attitude yaw expressed as Euler angles, not recommended except for human-readable outputs XACC float32 // X acceleration m/s/s YACC float32 // Y acceleration m/s/s ZACC float32 // Z acceleration m/s/s XGYRO float32 // Angular speed around X axis rad/s YGYRO float32 // Angular speed around Y axis rad/s ZGYRO float32 // Angular speed around Z axis rad/s LAT float32 // Latitude in degrees LON float32 // Longitude in degrees ALT float32 // Altitude in meters STD_DEV_HORZ float32 // Horizontal position standard deviation STD_DEV_VERT float32 // Vertical position standard deviation VN float32 // True velocity in m/s in NORTH direction in earth-fixed NED frame VE float32 // True velocity in m/s in EAST direction in earth-fixed NED frame VD float32 // True velocity in m/s in DOWN direction in earth-fixed NED frame } // NewSimState returns a new SimState func NewSimState(Q1 float32, Q2 float32, Q3 float32, Q4 float32, ROLL float32, PITCH float32, YAW float32, XACC float32, YACC float32, ZACC float32, XGYRO float32, YGYRO float32, ZGYRO float32, LAT float32, LON float32, ALT float32, STD_DEV_HORZ float32, STD_DEV_VERT float32, VN float32, VE float32, VD float32) *SimState { m := SimState{} m.Q1 = Q1 m.Q2 = Q2 m.Q3 = Q3 m.Q4 = Q4 m.ROLL = ROLL m.PITCH = PITCH m.YAW = YAW m.XACC = XACC m.YACC = YACC m.ZACC = ZACC m.XGYRO = XGYRO m.YGYRO = YGYRO m.ZGYRO = ZGYRO m.LAT = LAT m.LON = LON m.ALT = ALT m.STD_DEV_HORZ = STD_DEV_HORZ m.STD_DEV_VERT = STD_DEV_VERT m.VN = VN m.VE = VE m.VD = VD return &m } // Id returns the SimState Message ID func (*SimState) Id() uint8 { return 108 } // Len returns the SimState Message Length func (*SimState) Len() uint8 { return 84 } // Crc returns the SimState Message CRC func (*SimState) Crc() uint8 { return 32 } // Pack returns a packed byte array which represents a SimState payload func (m *SimState) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.Q1); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.Q2); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.Q3); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.Q4); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ROLL); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PITCH); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.YAW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.XACC); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.YACC); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ZACC); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.XGYRO); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.YGYRO); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ZGYRO); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.LAT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.LON); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ALT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.STD_DEV_HORZ); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.STD_DEV_VERT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VN); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VD); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the SimState func (m *SimState) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.Q1); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.Q2); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.Q3); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.Q4); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ROLL); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PITCH); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.YAW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.XACC); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.YACC); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ZACC); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.XGYRO); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.YGYRO); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ZGYRO); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.LAT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.LON); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ALT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.STD_DEV_HORZ); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.STD_DEV_VERT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VN); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VD); err != nil { panic(err) } } // MESSAGE RADIO_STATUS // // MAVLINK_MSG_ID_RADIO_STATUS 109 // // MAVLINK_MSG_ID_RADIO_STATUS_LEN 9 // // MAVLINK_MSG_ID_RADIO_STATUS_CRC 185 type RadioStatus struct { RXERRORS uint16 // receive errors FIXED uint16 // count of error corrected packets RSSI uint8 // local signal strength REMRSSI uint8 // remote signal strength TXBUF uint8 // how full the tx buffer is as a percentage NOISE uint8 // background noise level REMNOISE uint8 // remote background noise level } // NewRadioStatus returns a new RadioStatus func NewRadioStatus(RXERRORS uint16, FIXED uint16, RSSI uint8, REMRSSI uint8, TXBUF uint8, NOISE uint8, REMNOISE uint8) *RadioStatus { m := RadioStatus{} m.RXERRORS = RXERRORS m.FIXED = FIXED m.RSSI = RSSI m.REMRSSI = REMRSSI m.TXBUF = TXBUF m.NOISE = NOISE m.REMNOISE = REMNOISE return &m } // Id returns the RadioStatus Message ID func (*RadioStatus) Id() uint8 { return 109 } // Len returns the RadioStatus Message Length func (*RadioStatus) Len() uint8 { return 9 } // Crc returns the RadioStatus Message CRC func (*RadioStatus) Crc() uint8 { return 185 } // Pack returns a packed byte array which represents a RadioStatus payload func (m *RadioStatus) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.RXERRORS); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.FIXED); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.RSSI); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.REMRSSI); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TXBUF); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.NOISE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.REMNOISE); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the RadioStatus func (m *RadioStatus) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.RXERRORS); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.FIXED); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.RSSI); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.REMRSSI); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TXBUF); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.NOISE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.REMNOISE); err != nil { panic(err) } } // MESSAGE FILE_TRANSFER_START // // MAVLINK_MSG_ID_FILE_TRANSFER_START 110 // // MAVLINK_MSG_ID_FILE_TRANSFER_START_LEN 254 // // MAVLINK_MSG_ID_FILE_TRANSFER_START_CRC 235 type FileTransferStart struct { TRANSFER_UID uint64 // Unique transfer ID FILE_SIZE uint32 // File size in bytes DEST_PATH [240]uint8 // Destination path DIRECTION uint8 // Transfer direction: 0: from requester, 1: to requester FLAGS uint8 // RESERVED } // NewFileTransferStart returns a new FileTransferStart func NewFileTransferStart(TRANSFER_UID uint64, FILE_SIZE uint32, DEST_PATH [240]uint8, DIRECTION uint8, FLAGS uint8) *FileTransferStart { m := FileTransferStart{} m.TRANSFER_UID = TRANSFER_UID m.FILE_SIZE = FILE_SIZE m.DEST_PATH = DEST_PATH m.DIRECTION = DIRECTION m.FLAGS = FLAGS return &m } // Id returns the FileTransferStart Message ID func (*FileTransferStart) Id() uint8 { return 110 } // Len returns the FileTransferStart Message Length func (*FileTransferStart) Len() uint8 { return 254 } // Crc returns the FileTransferStart Message CRC func (*FileTransferStart) Crc() uint8 { return 235 } // Pack returns a packed byte array which represents a FileTransferStart payload func (m *FileTransferStart) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TRANSFER_UID); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.FILE_SIZE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.DEST_PATH); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.DIRECTION); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.FLAGS); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the FileTransferStart func (m *FileTransferStart) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TRANSFER_UID); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.FILE_SIZE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.DEST_PATH); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.DIRECTION); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.FLAGS); err != nil { panic(err) } } const ( MAVLINK_MSG_FILE_TRANSFER_START_FIELD_dest_path_LEN = 240 ) // MESSAGE FILE_TRANSFER_DIR_LIST // // MAVLINK_MSG_ID_FILE_TRANSFER_DIR_LIST 111 // // MAVLINK_MSG_ID_FILE_TRANSFER_DIR_LIST_LEN 249 // // MAVLINK_MSG_ID_FILE_TRANSFER_DIR_LIST_CRC 93 type FileTransferDirList struct { TRANSFER_UID uint64 // Unique transfer ID DIR_PATH [240]uint8 // Directory path to list FLAGS uint8 // RESERVED } // NewFileTransferDirList returns a new FileTransferDirList func NewFileTransferDirList(TRANSFER_UID uint64, DIR_PATH [240]uint8, FLAGS uint8) *FileTransferDirList { m := FileTransferDirList{} m.TRANSFER_UID = TRANSFER_UID m.DIR_PATH = DIR_PATH m.FLAGS = FLAGS return &m } // Id returns the FileTransferDirList Message ID func (*FileTransferDirList) Id() uint8 { return 111 } // Len returns the FileTransferDirList Message Length func (*FileTransferDirList) Len() uint8 { return 249 } // Crc returns the FileTransferDirList Message CRC func (*FileTransferDirList) Crc() uint8 { return 93 } // Pack returns a packed byte array which represents a FileTransferDirList payload func (m *FileTransferDirList) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TRANSFER_UID); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.DIR_PATH); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.FLAGS); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the FileTransferDirList func (m *FileTransferDirList) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TRANSFER_UID); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.DIR_PATH); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.FLAGS); err != nil { panic(err) } } const ( MAVLINK_MSG_FILE_TRANSFER_DIR_LIST_FIELD_dir_path_LEN = 240 ) // MESSAGE FILE_TRANSFER_RES // // MAVLINK_MSG_ID_FILE_TRANSFER_RES 112 // // MAVLINK_MSG_ID_FILE_TRANSFER_RES_LEN 9 // // MAVLINK_MSG_ID_FILE_TRANSFER_RES_CRC 124 type FileTransferRes struct { TRANSFER_UID uint64 // Unique transfer ID RESULT uint8 // 0: OK, 1: not permitted, 2: bad path / file name, 3: no space left on device } // NewFileTransferRes returns a new FileTransferRes func NewFileTransferRes(TRANSFER_UID uint64, RESULT uint8) *FileTransferRes { m := FileTransferRes{} m.TRANSFER_UID = TRANSFER_UID m.RESULT = RESULT return &m } // Id returns the FileTransferRes Message ID func (*FileTransferRes) Id() uint8 { return 112 } // Len returns the FileTransferRes Message Length func (*FileTransferRes) Len() uint8 { return 9 } // Crc returns the FileTransferRes Message CRC func (*FileTransferRes) Crc() uint8 { return 124 } // Pack returns a packed byte array which represents a FileTransferRes payload func (m *FileTransferRes) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TRANSFER_UID); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.RESULT); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the FileTransferRes func (m *FileTransferRes) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TRANSFER_UID); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.RESULT); err != nil { panic(err) } } // MESSAGE HIL_GPS // // MAVLINK_MSG_ID_HIL_GPS 113 // // MAVLINK_MSG_ID_HIL_GPS_LEN 36 // // MAVLINK_MSG_ID_HIL_GPS_CRC 124 type HilGps struct { TIME_USEC uint64 // Timestamp (microseconds since UNIX epoch or microseconds since system boot) LAT int32 // Latitude (WGS84), in degrees * 1E7 LON int32 // Longitude (WGS84), in degrees * 1E7 ALT int32 // Altitude (WGS84), in meters * 1000 (positive for up) EPH uint16 // GPS HDOP horizontal dilution of position in cm (m*100). If unknown, set to: 65535 EPV uint16 // GPS VDOP vertical dilution of position in cm (m*100). If unknown, set to: 65535 VEL uint16 // GPS ground speed (m/s * 100). If unknown, set to: 65535 VN int16 // GPS velocity in cm/s in NORTH direction in earth-fixed NED frame VE int16 // GPS velocity in cm/s in EAST direction in earth-fixed NED frame VD int16 // GPS velocity in cm/s in DOWN direction in earth-fixed NED frame COG uint16 // Course over ground (NOT heading, but direction of movement) in degrees * 100, 0.0..359.99 degrees. If unknown, set to: 65535 FIX_TYPE uint8 // 0-1: no fix, 2: 2D fix, 3: 3D fix. Some applications will not use the value of this field unless it is at least two, so always correctly fill in the fix. SATELLITES_VISIBLE uint8 // Number of satellites visible. If unknown, set to 255 } // NewHilGps returns a new HilGps func NewHilGps(TIME_USEC uint64, LAT int32, LON int32, ALT int32, EPH uint16, EPV uint16, VEL uint16, VN int16, VE int16, VD int16, COG uint16, FIX_TYPE uint8, SATELLITES_VISIBLE uint8) *HilGps { m := HilGps{} m.TIME_USEC = TIME_USEC m.LAT = LAT m.LON = LON m.ALT = ALT m.EPH = EPH m.EPV = EPV m.VEL = VEL m.VN = VN m.VE = VE m.VD = VD m.COG = COG m.FIX_TYPE = FIX_TYPE m.SATELLITES_VISIBLE = SATELLITES_VISIBLE return &m } // Id returns the HilGps Message ID func (*HilGps) Id() uint8 { return 113 } // Len returns the HilGps Message Length func (*HilGps) Len() uint8 { return 36 } // Crc returns the HilGps Message CRC func (*HilGps) Crc() uint8 { return 124 } // Pack returns a packed byte array which represents a HilGps payload func (m *HilGps) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TIME_USEC); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.LAT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.LON); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ALT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.EPH); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.EPV); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VEL); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VN); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VD); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.COG); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.FIX_TYPE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.SATELLITES_VISIBLE); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the HilGps func (m *HilGps) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TIME_USEC); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.LAT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.LON); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ALT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.EPH); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.EPV); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VEL); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VN); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VD); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.COG); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.FIX_TYPE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.SATELLITES_VISIBLE); err != nil { panic(err) } } // MESSAGE HIL_OPTICAL_FLOW // // MAVLINK_MSG_ID_HIL_OPTICAL_FLOW 114 // // MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_LEN 26 // // MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_CRC 119 type HilOpticalFlow struct { TIME_USEC uint64 // Timestamp (UNIX) FLOW_COMP_M_X float32 // Flow in meters in x-sensor direction, angular-speed compensated FLOW_COMP_M_Y float32 // Flow in meters in y-sensor direction, angular-speed compensated GROUND_DISTANCE float32 // Ground distance in meters. Positive value: distance known. Negative value: Unknown distance FLOW_X int16 // Flow in pixels in x-sensor direction FLOW_Y int16 // Flow in pixels in y-sensor direction SENSOR_ID uint8 // Sensor ID QUALITY uint8 // Optical flow quality / confidence. 0: bad, 255: maximum quality } // NewHilOpticalFlow returns a new HilOpticalFlow func NewHilOpticalFlow(TIME_USEC uint64, FLOW_COMP_M_X float32, FLOW_COMP_M_Y float32, GROUND_DISTANCE float32, FLOW_X int16, FLOW_Y int16, SENSOR_ID uint8, QUALITY uint8) *HilOpticalFlow { m := HilOpticalFlow{} m.TIME_USEC = TIME_USEC m.FLOW_COMP_M_X = FLOW_COMP_M_X m.FLOW_COMP_M_Y = FLOW_COMP_M_Y m.GROUND_DISTANCE = GROUND_DISTANCE m.FLOW_X = FLOW_X m.FLOW_Y = FLOW_Y m.SENSOR_ID = SENSOR_ID m.QUALITY = QUALITY return &m } // Id returns the HilOpticalFlow Message ID func (*HilOpticalFlow) Id() uint8 { return 114 } // Len returns the HilOpticalFlow Message Length func (*HilOpticalFlow) Len() uint8 { return 26 } // Crc returns the HilOpticalFlow Message CRC func (*HilOpticalFlow) Crc() uint8 { return 119 } // Pack returns a packed byte array which represents a HilOpticalFlow payload func (m *HilOpticalFlow) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TIME_USEC); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.FLOW_COMP_M_X); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.FLOW_COMP_M_Y); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.GROUND_DISTANCE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.FLOW_X); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.FLOW_Y); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.SENSOR_ID); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.QUALITY); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the HilOpticalFlow func (m *HilOpticalFlow) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TIME_USEC); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.FLOW_COMP_M_X); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.FLOW_COMP_M_Y); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.GROUND_DISTANCE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.FLOW_X); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.FLOW_Y); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.SENSOR_ID); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.QUALITY); err != nil { panic(err) } } // MESSAGE HIL_STATE_QUATERNION // // MAVLINK_MSG_ID_HIL_STATE_QUATERNION 115 // // MAVLINK_MSG_ID_HIL_STATE_QUATERNION_LEN 64 // // MAVLINK_MSG_ID_HIL_STATE_QUATERNION_CRC 4 type HilStateQuaternion struct { TIME_USEC uint64 // Timestamp (microseconds since UNIX epoch or microseconds since system boot) ATTITUDE_QUATERNION [4]float32 // Vehicle attitude expressed as normalized quaternion in w, x, y, z order (with 1 0 0 0 being the null-rotation) ROLLSPEED float32 // Body frame roll / phi angular speed (rad/s) PITCHSPEED float32 // Body frame pitch / theta angular speed (rad/s) YAWSPEED float32 // Body frame yaw / psi angular speed (rad/s) LAT int32 // Latitude, expressed as * 1E7 LON int32 // Longitude, expressed as * 1E7 ALT int32 // Altitude in meters, expressed as * 1000 (millimeters) VX int16 // Ground X Speed (Latitude), expressed as m/s * 100 VY int16 // Ground Y Speed (Longitude), expressed as m/s * 100 VZ int16 // Ground Z Speed (Altitude), expressed as m/s * 100 IND_AIRSPEED uint16 // Indicated airspeed, expressed as m/s * 100 TRUE_AIRSPEED uint16 // True airspeed, expressed as m/s * 100 XACC int16 // X acceleration (mg) YACC int16 // Y acceleration (mg) ZACC int16 // Z acceleration (mg) } // NewHilStateQuaternion returns a new HilStateQuaternion func NewHilStateQuaternion(TIME_USEC uint64, ATTITUDE_QUATERNION [4]float32, ROLLSPEED float32, PITCHSPEED float32, YAWSPEED float32, LAT int32, LON int32, ALT int32, VX int16, VY int16, VZ int16, IND_AIRSPEED uint16, TRUE_AIRSPEED uint16, XACC int16, YACC int16, ZACC int16) *HilStateQuaternion { m := HilStateQuaternion{} m.TIME_USEC = TIME_USEC m.ATTITUDE_QUATERNION = ATTITUDE_QUATERNION m.ROLLSPEED = ROLLSPEED m.PITCHSPEED = PITCHSPEED m.YAWSPEED = YAWSPEED m.LAT = LAT m.LON = LON m.ALT = ALT m.VX = VX m.VY = VY m.VZ = VZ m.IND_AIRSPEED = IND_AIRSPEED m.TRUE_AIRSPEED = TRUE_AIRSPEED m.XACC = XACC m.YACC = YACC m.ZACC = ZACC return &m } // Id returns the HilStateQuaternion Message ID func (*HilStateQuaternion) Id() uint8 { return 115 } // Len returns the HilStateQuaternion Message Length func (*HilStateQuaternion) Len() uint8 { return 64 } // Crc returns the HilStateQuaternion Message CRC func (*HilStateQuaternion) Crc() uint8 { return 4 } // Pack returns a packed byte array which represents a HilStateQuaternion payload func (m *HilStateQuaternion) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TIME_USEC); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ATTITUDE_QUATERNION); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ROLLSPEED); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PITCHSPEED); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.YAWSPEED); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.LAT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.LON); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ALT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VX); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VY); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VZ); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.IND_AIRSPEED); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TRUE_AIRSPEED); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.XACC); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.YACC); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ZACC); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the HilStateQuaternion func (m *HilStateQuaternion) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TIME_USEC); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ATTITUDE_QUATERNION); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ROLLSPEED); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PITCHSPEED); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.YAWSPEED); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.LAT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.LON); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ALT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VX); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VY); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VZ); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.IND_AIRSPEED); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TRUE_AIRSPEED); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.XACC); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.YACC); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ZACC); err != nil { panic(err) } } const ( MAVLINK_MSG_HIL_STATE_QUATERNION_FIELD_attitude_quaternion_LEN = 4 ) // MESSAGE SCALED_IMU2 // // MAVLINK_MSG_ID_SCALED_IMU2 116 // // MAVLINK_MSG_ID_SCALED_IMU2_LEN 22 // // MAVLINK_MSG_ID_SCALED_IMU2_CRC 76 type ScaledImu2 struct { TIME_BOOT_MS uint32 // Timestamp (milliseconds since system boot) XACC int16 // X acceleration (mg) YACC int16 // Y acceleration (mg) ZACC int16 // Z acceleration (mg) XGYRO int16 // Angular speed around X axis (millirad /sec) YGYRO int16 // Angular speed around Y axis (millirad /sec) ZGYRO int16 // Angular speed around Z axis (millirad /sec) XMAG int16 // X Magnetic field (milli tesla) YMAG int16 // Y Magnetic field (milli tesla) ZMAG int16 // Z Magnetic field (milli tesla) } // NewScaledImu2 returns a new ScaledImu2 func NewScaledImu2(TIME_BOOT_MS uint32, XACC int16, YACC int16, ZACC int16, XGYRO int16, YGYRO int16, ZGYRO int16, XMAG int16, YMAG int16, ZMAG int16) *ScaledImu2 { m := ScaledImu2{} m.TIME_BOOT_MS = TIME_BOOT_MS m.XACC = XACC m.YACC = YACC m.ZACC = ZACC m.XGYRO = XGYRO m.YGYRO = YGYRO m.ZGYRO = ZGYRO m.XMAG = XMAG m.YMAG = YMAG m.ZMAG = ZMAG return &m } // Id returns the ScaledImu2 Message ID func (*ScaledImu2) Id() uint8 { return 116 } // Len returns the ScaledImu2 Message Length func (*ScaledImu2) Len() uint8 { return 22 } // Crc returns the ScaledImu2 Message CRC func (*ScaledImu2) Crc() uint8 { return 76 } // Pack returns a packed byte array which represents a ScaledImu2 payload func (m *ScaledImu2) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TIME_BOOT_MS); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.XACC); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.YACC); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ZACC); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.XGYRO); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.YGYRO); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ZGYRO); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.XMAG); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.YMAG); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ZMAG); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the ScaledImu2 func (m *ScaledImu2) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TIME_BOOT_MS); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.XACC); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.YACC); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ZACC); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.XGYRO); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.YGYRO); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ZGYRO); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.XMAG); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.YMAG); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ZMAG); err != nil { panic(err) } } // MESSAGE LOG_REQUEST_LIST // // MAVLINK_MSG_ID_LOG_REQUEST_LIST 117 // // MAVLINK_MSG_ID_LOG_REQUEST_LIST_LEN 6 // // MAVLINK_MSG_ID_LOG_REQUEST_LIST_CRC 128 type LogRequestList struct { START uint16 // First log id (0 for first available) END uint16 // Last log id (0xffff for last available) TARGET_SYSTEM uint8 // System ID TARGET_COMPONENT uint8 // Component ID } // NewLogRequestList returns a new LogRequestList func NewLogRequestList(START uint16, END uint16, TARGET_SYSTEM uint8, TARGET_COMPONENT uint8) *LogRequestList { m := LogRequestList{} m.START = START m.END = END m.TARGET_SYSTEM = TARGET_SYSTEM m.TARGET_COMPONENT = TARGET_COMPONENT return &m } // Id returns the LogRequestList Message ID func (*LogRequestList) Id() uint8 { return 117 } // Len returns the LogRequestList Message Length func (*LogRequestList) Len() uint8 { return 6 } // Crc returns the LogRequestList Message CRC func (*LogRequestList) Crc() uint8 { return 128 } // Pack returns a packed byte array which represents a LogRequestList payload func (m *LogRequestList) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.START); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.END); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_COMPONENT); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the LogRequestList func (m *LogRequestList) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.START); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.END); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_COMPONENT); err != nil { panic(err) } } // MESSAGE LOG_ENTRY // // MAVLINK_MSG_ID_LOG_ENTRY 118 // // MAVLINK_MSG_ID_LOG_ENTRY_LEN 14 // // MAVLINK_MSG_ID_LOG_ENTRY_CRC 56 type LogEntry struct { TIME_UTC uint32 // UTC timestamp of log in seconds since 1970, or 0 if not available SIZE uint32 // Size of the log (may be approximate) in bytes ID uint16 // Log id NUM_LOGS uint16 // Total number of logs LAST_LOG_NUM uint16 // High log number } // NewLogEntry returns a new LogEntry func NewLogEntry(TIME_UTC uint32, SIZE uint32, ID uint16, NUM_LOGS uint16, LAST_LOG_NUM uint16) *LogEntry { m := LogEntry{} m.TIME_UTC = TIME_UTC m.SIZE = SIZE m.ID = ID m.NUM_LOGS = NUM_LOGS m.LAST_LOG_NUM = LAST_LOG_NUM return &m } // Id returns the LogEntry Message ID func (*LogEntry) Id() uint8 { return 118 } // Len returns the LogEntry Message Length func (*LogEntry) Len() uint8 { return 14 } // Crc returns the LogEntry Message CRC func (*LogEntry) Crc() uint8 { return 56 } // Pack returns a packed byte array which represents a LogEntry payload func (m *LogEntry) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TIME_UTC); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.SIZE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ID); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.NUM_LOGS); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.LAST_LOG_NUM); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the LogEntry func (m *LogEntry) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TIME_UTC); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.SIZE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ID); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.NUM_LOGS); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.LAST_LOG_NUM); err != nil { panic(err) } } // MESSAGE LOG_REQUEST_DATA // // MAVLINK_MSG_ID_LOG_REQUEST_DATA 119 // // MAVLINK_MSG_ID_LOG_REQUEST_DATA_LEN 12 // // MAVLINK_MSG_ID_LOG_REQUEST_DATA_CRC 116 type LogRequestData struct { OFS uint32 // Offset into the log COUNT uint32 // Number of bytes ID uint16 // Log id (from LOG_ENTRY reply) TARGET_SYSTEM uint8 // System ID TARGET_COMPONENT uint8 // Component ID } // NewLogRequestData returns a new LogRequestData func NewLogRequestData(OFS uint32, COUNT uint32, ID uint16, TARGET_SYSTEM uint8, TARGET_COMPONENT uint8) *LogRequestData { m := LogRequestData{} m.OFS = OFS m.COUNT = COUNT m.ID = ID m.TARGET_SYSTEM = TARGET_SYSTEM m.TARGET_COMPONENT = TARGET_COMPONENT return &m } // Id returns the LogRequestData Message ID func (*LogRequestData) Id() uint8 { return 119 } // Len returns the LogRequestData Message Length func (*LogRequestData) Len() uint8 { return 12 } // Crc returns the LogRequestData Message CRC func (*LogRequestData) Crc() uint8 { return 116 } // Pack returns a packed byte array which represents a LogRequestData payload func (m *LogRequestData) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.OFS); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.COUNT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ID); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_COMPONENT); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the LogRequestData func (m *LogRequestData) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.OFS); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.COUNT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ID); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_COMPONENT); err != nil { panic(err) } } // MESSAGE LOG_DATA // // MAVLINK_MSG_ID_LOG_DATA 120 // // MAVLINK_MSG_ID_LOG_DATA_LEN 97 // // MAVLINK_MSG_ID_LOG_DATA_CRC 134 type LogData struct { OFS uint32 // Offset into the log ID uint16 // Log id (from LOG_ENTRY reply) COUNT uint8 // Number of bytes (zero for end of log) DATA [90]uint8 // log data } // NewLogData returns a new LogData func NewLogData(OFS uint32, ID uint16, COUNT uint8, DATA [90]uint8) *LogData { m := LogData{} m.OFS = OFS m.ID = ID m.COUNT = COUNT m.DATA = DATA return &m } // Id returns the LogData Message ID func (*LogData) Id() uint8 { return 120 } // Len returns the LogData Message Length func (*LogData) Len() uint8 { return 97 } // Crc returns the LogData Message CRC func (*LogData) Crc() uint8 { return 134 } // Pack returns a packed byte array which represents a LogData payload func (m *LogData) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.OFS); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ID); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.COUNT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.DATA); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the LogData func (m *LogData) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.OFS); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ID); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.COUNT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.DATA); err != nil { panic(err) } } const ( MAVLINK_MSG_LOG_DATA_FIELD_data_LEN = 90 ) // MESSAGE LOG_ERASE // // MAVLINK_MSG_ID_LOG_ERASE 121 // // MAVLINK_MSG_ID_LOG_ERASE_LEN 2 // // MAVLINK_MSG_ID_LOG_ERASE_CRC 237 type LogErase struct { TARGET_SYSTEM uint8 // System ID TARGET_COMPONENT uint8 // Component ID } // NewLogErase returns a new LogErase func NewLogErase(TARGET_SYSTEM uint8, TARGET_COMPONENT uint8) *LogErase { m := LogErase{} m.TARGET_SYSTEM = TARGET_SYSTEM m.TARGET_COMPONENT = TARGET_COMPONENT return &m } // Id returns the LogErase Message ID func (*LogErase) Id() uint8 { return 121 } // Len returns the LogErase Message Length func (*LogErase) Len() uint8 { return 2 } // Crc returns the LogErase Message CRC func (*LogErase) Crc() uint8 { return 237 } // Pack returns a packed byte array which represents a LogErase payload func (m *LogErase) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_COMPONENT); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the LogErase func (m *LogErase) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_COMPONENT); err != nil { panic(err) } } // MESSAGE LOG_REQUEST_END // // MAVLINK_MSG_ID_LOG_REQUEST_END 122 // // MAVLINK_MSG_ID_LOG_REQUEST_END_LEN 2 // // MAVLINK_MSG_ID_LOG_REQUEST_END_CRC 203 type LogRequestEnd struct { TARGET_SYSTEM uint8 // System ID TARGET_COMPONENT uint8 // Component ID } // NewLogRequestEnd returns a new LogRequestEnd func NewLogRequestEnd(TARGET_SYSTEM uint8, TARGET_COMPONENT uint8) *LogRequestEnd { m := LogRequestEnd{} m.TARGET_SYSTEM = TARGET_SYSTEM m.TARGET_COMPONENT = TARGET_COMPONENT return &m } // Id returns the LogRequestEnd Message ID func (*LogRequestEnd) Id() uint8 { return 122 } // Len returns the LogRequestEnd Message Length func (*LogRequestEnd) Len() uint8 { return 2 } // Crc returns the LogRequestEnd Message CRC func (*LogRequestEnd) Crc() uint8 { return 203 } // Pack returns a packed byte array which represents a LogRequestEnd payload func (m *LogRequestEnd) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_COMPONENT); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the LogRequestEnd func (m *LogRequestEnd) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_COMPONENT); err != nil { panic(err) } } // MESSAGE GPS_INJECT_DATA // // MAVLINK_MSG_ID_GPS_INJECT_DATA 123 // // MAVLINK_MSG_ID_GPS_INJECT_DATA_LEN 113 // // MAVLINK_MSG_ID_GPS_INJECT_DATA_CRC 250 type GpsInjectData struct { TARGET_SYSTEM uint8 // System ID TARGET_COMPONENT uint8 // Component ID LEN uint8 // data length DATA [110]uint8 // raw data (110 is enough for 12 satellites of RTCMv2) } // NewGpsInjectData returns a new GpsInjectData func NewGpsInjectData(TARGET_SYSTEM uint8, TARGET_COMPONENT uint8, LEN uint8, DATA [110]uint8) *GpsInjectData { m := GpsInjectData{} m.TARGET_SYSTEM = TARGET_SYSTEM m.TARGET_COMPONENT = TARGET_COMPONENT m.LEN = LEN m.DATA = DATA return &m } // Id returns the GpsInjectData Message ID func (*GpsInjectData) Id() uint8 { return 123 } // Len returns the GpsInjectData Message Length func (*GpsInjectData) Len() uint8 { return 113 } // Crc returns the GpsInjectData Message CRC func (*GpsInjectData) Crc() uint8 { return 250 } // Pack returns a packed byte array which represents a GpsInjectData payload func (m *GpsInjectData) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_COMPONENT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.LEN); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.DATA); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the GpsInjectData func (m *GpsInjectData) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TARGET_SYSTEM); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_COMPONENT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.LEN); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.DATA); err != nil { panic(err) } } const ( MAVLINK_MSG_GPS_INJECT_DATA_FIELD_data_LEN = 110 ) // MESSAGE GPS2_RAW // // MAVLINK_MSG_ID_GPS2_RAW 124 // // MAVLINK_MSG_ID_GPS2_RAW_LEN 35 // // MAVLINK_MSG_ID_GPS2_RAW_CRC 87 type Gps2Raw struct { TIME_USEC uint64 // Timestamp (microseconds since UNIX epoch or microseconds since system boot) LAT int32 // Latitude (WGS84), in degrees * 1E7 LON int32 // Longitude (WGS84), in degrees * 1E7 ALT int32 // Altitude (WGS84), in meters * 1000 (positive for up) DGPS_AGE uint32 // Age of DGPS info EPH uint16 // GPS HDOP horizontal dilution of position in cm (m*100). If unknown, set to: UINT16_MAX EPV uint16 // GPS VDOP vertical dilution of position in cm (m*100). If unknown, set to: UINT16_MAX VEL uint16 // GPS ground speed (m/s * 100). If unknown, set to: UINT16_MAX COG uint16 // Course over ground (NOT heading, but direction of movement) in degrees * 100, 0.0..359.99 degrees. If unknown, set to: UINT16_MAX FIX_TYPE uint8 // 0-1: no fix, 2: 2D fix, 3: 3D fix, 4: DGPS fix, 5: RTK Fix. Some applications will not use the value of this field unless it is at least two, so always correctly fill in the fix. SATELLITES_VISIBLE uint8 // Number of satellites visible. If unknown, set to 255 DGPS_NUMCH uint8 // Number of DGPS satellites } // NewGps2Raw returns a new Gps2Raw func NewGps2Raw(TIME_USEC uint64, LAT int32, LON int32, ALT int32, DGPS_AGE uint32, EPH uint16, EPV uint16, VEL uint16, COG uint16, FIX_TYPE uint8, SATELLITES_VISIBLE uint8, DGPS_NUMCH uint8) *Gps2Raw { m := Gps2Raw{} m.TIME_USEC = TIME_USEC m.LAT = LAT m.LON = LON m.ALT = ALT m.DGPS_AGE = DGPS_AGE m.EPH = EPH m.EPV = EPV m.VEL = VEL m.COG = COG m.FIX_TYPE = FIX_TYPE m.SATELLITES_VISIBLE = SATELLITES_VISIBLE m.DGPS_NUMCH = DGPS_NUMCH return &m } // Id returns the Gps2Raw Message ID func (*Gps2Raw) Id() uint8 { return 124 } // Len returns the Gps2Raw Message Length func (*Gps2Raw) Len() uint8 { return 35 } // Crc returns the Gps2Raw Message CRC func (*Gps2Raw) Crc() uint8 { return 87 } // Pack returns a packed byte array which represents a Gps2Raw payload func (m *Gps2Raw) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TIME_USEC); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.LAT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.LON); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ALT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.DGPS_AGE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.EPH); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.EPV); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VEL); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.COG); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.FIX_TYPE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.SATELLITES_VISIBLE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.DGPS_NUMCH); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the Gps2Raw func (m *Gps2Raw) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TIME_USEC); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.LAT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.LON); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ALT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.DGPS_AGE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.EPH); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.EPV); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VEL); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.COG); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.FIX_TYPE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.SATELLITES_VISIBLE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.DGPS_NUMCH); err != nil { panic(err) } } // MESSAGE POWER_STATUS // // MAVLINK_MSG_ID_POWER_STATUS 125 // // MAVLINK_MSG_ID_POWER_STATUS_LEN 6 // // MAVLINK_MSG_ID_POWER_STATUS_CRC 203 type PowerStatus struct { VCC uint16 // 5V rail voltage in millivolts VSERVO uint16 // servo rail voltage in millivolts FLAGS uint16 // power supply status flags (see MAV_POWER_STATUS enum) } // NewPowerStatus returns a new PowerStatus func NewPowerStatus(VCC uint16, VSERVO uint16, FLAGS uint16) *PowerStatus { m := PowerStatus{} m.VCC = VCC m.VSERVO = VSERVO m.FLAGS = FLAGS return &m } // Id returns the PowerStatus Message ID func (*PowerStatus) Id() uint8 { return 125 } // Len returns the PowerStatus Message Length func (*PowerStatus) Len() uint8 { return 6 } // Crc returns the PowerStatus Message CRC func (*PowerStatus) Crc() uint8 { return 203 } // Pack returns a packed byte array which represents a PowerStatus payload func (m *PowerStatus) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.VCC); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VSERVO); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.FLAGS); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the PowerStatus func (m *PowerStatus) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.VCC); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VSERVO); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.FLAGS); err != nil { panic(err) } } // MESSAGE SERIAL_CONTROL // // MAVLINK_MSG_ID_SERIAL_CONTROL 126 // // MAVLINK_MSG_ID_SERIAL_CONTROL_LEN 79 // // MAVLINK_MSG_ID_SERIAL_CONTROL_CRC 220 type SerialControl struct { BAUDRATE uint32 // Baudrate of transfer. Zero means no change. TIMEOUT uint16 // Timeout for reply data in milliseconds DEVICE uint8 // See SERIAL_CONTROL_DEV enum FLAGS uint8 // See SERIAL_CONTROL_FLAG enum COUNT uint8 // how many bytes in this transfer DATA [70]uint8 // serial data } // NewSerialControl returns a new SerialControl func NewSerialControl(BAUDRATE uint32, TIMEOUT uint16, DEVICE uint8, FLAGS uint8, COUNT uint8, DATA [70]uint8) *SerialControl { m := SerialControl{} m.BAUDRATE = BAUDRATE m.TIMEOUT = TIMEOUT m.DEVICE = DEVICE m.FLAGS = FLAGS m.COUNT = COUNT m.DATA = DATA return &m } // Id returns the SerialControl Message ID func (*SerialControl) Id() uint8 { return 126 } // Len returns the SerialControl Message Length func (*SerialControl) Len() uint8 { return 79 } // Crc returns the SerialControl Message CRC func (*SerialControl) Crc() uint8 { return 220 } // Pack returns a packed byte array which represents a SerialControl payload func (m *SerialControl) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.BAUDRATE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TIMEOUT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.DEVICE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.FLAGS); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.COUNT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.DATA); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the SerialControl func (m *SerialControl) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.BAUDRATE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TIMEOUT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.DEVICE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.FLAGS); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.COUNT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.DATA); err != nil { panic(err) } } const ( MAVLINK_MSG_SERIAL_CONTROL_FIELD_data_LEN = 70 ) // MESSAGE GPS_RTK // // MAVLINK_MSG_ID_GPS_RTK 127 // // MAVLINK_MSG_ID_GPS_RTK_LEN 35 // // MAVLINK_MSG_ID_GPS_RTK_CRC 25 type GpsRtk struct { TIME_LAST_BASELINE_MS uint32 // Time since boot of last baseline message received in ms. TOW uint32 // GPS Time of Week of last baseline BASELINE_A_MM int32 // Current baseline in ECEF x or NED north component in mm. BASELINE_B_MM int32 // Current baseline in ECEF y or NED east component in mm. BASELINE_C_MM int32 // Current baseline in ECEF z or NED down component in mm. ACCURACY uint32 // Current estimate of baseline accuracy. IAR_NUM_HYPOTHESES int32 // Current number of integer ambiguity hypotheses. WN uint16 // GPS Week Number of last baseline RTK_RECEIVER_ID uint8 // Identification of connected RTK receiver. RTK_HEALTH uint8 // GPS-specific health report for RTK data. RTK_RATE uint8 // Rate of baseline messages being received by GPS, in HZ NSATS uint8 // Current number of sats used for RTK calculation. BASELINE_COORDS_TYPE uint8 // Coordinate system of baseline. 0 == ECEF, 1 == NED } // NewGpsRtk returns a new GpsRtk func NewGpsRtk(TIME_LAST_BASELINE_MS uint32, TOW uint32, BASELINE_A_MM int32, BASELINE_B_MM int32, BASELINE_C_MM int32, ACCURACY uint32, IAR_NUM_HYPOTHESES int32, WN uint16, RTK_RECEIVER_ID uint8, RTK_HEALTH uint8, RTK_RATE uint8, NSATS uint8, BASELINE_COORDS_TYPE uint8) *GpsRtk { m := GpsRtk{} m.TIME_LAST_BASELINE_MS = TIME_LAST_BASELINE_MS m.TOW = TOW m.BASELINE_A_MM = BASELINE_A_MM m.BASELINE_B_MM = BASELINE_B_MM m.BASELINE_C_MM = BASELINE_C_MM m.ACCURACY = ACCURACY m.IAR_NUM_HYPOTHESES = IAR_NUM_HYPOTHESES m.WN = WN m.RTK_RECEIVER_ID = RTK_RECEIVER_ID m.RTK_HEALTH = RTK_HEALTH m.RTK_RATE = RTK_RATE m.NSATS = NSATS m.BASELINE_COORDS_TYPE = BASELINE_COORDS_TYPE return &m } // Id returns the GpsRtk Message ID func (*GpsRtk) Id() uint8 { return 127 } // Len returns the GpsRtk Message Length func (*GpsRtk) Len() uint8 { return 35 } // Crc returns the GpsRtk Message CRC func (*GpsRtk) Crc() uint8 { return 25 } // Pack returns a packed byte array which represents a GpsRtk payload func (m *GpsRtk) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TIME_LAST_BASELINE_MS); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TOW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.BASELINE_A_MM); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.BASELINE_B_MM); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.BASELINE_C_MM); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ACCURACY); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.IAR_NUM_HYPOTHESES); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.WN); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.RTK_RECEIVER_ID); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.RTK_HEALTH); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.RTK_RATE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.NSATS); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.BASELINE_COORDS_TYPE); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the GpsRtk func (m *GpsRtk) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TIME_LAST_BASELINE_MS); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TOW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.BASELINE_A_MM); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.BASELINE_B_MM); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.BASELINE_C_MM); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ACCURACY); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.IAR_NUM_HYPOTHESES); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.WN); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.RTK_RECEIVER_ID); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.RTK_HEALTH); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.RTK_RATE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.NSATS); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.BASELINE_COORDS_TYPE); err != nil { panic(err) } } // MESSAGE GPS2_RTK // // MAVLINK_MSG_ID_GPS2_RTK 128 // // MAVLINK_MSG_ID_GPS2_RTK_LEN 35 // // MAVLINK_MSG_ID_GPS2_RTK_CRC 226 type Gps2Rtk struct { TIME_LAST_BASELINE_MS uint32 // Time since boot of last baseline message received in ms. TOW uint32 // GPS Time of Week of last baseline BASELINE_A_MM int32 // Current baseline in ECEF x or NED north component in mm. BASELINE_B_MM int32 // Current baseline in ECEF y or NED east component in mm. BASELINE_C_MM int32 // Current baseline in ECEF z or NED down component in mm. ACCURACY uint32 // Current estimate of baseline accuracy. IAR_NUM_HYPOTHESES int32 // Current number of integer ambiguity hypotheses. WN uint16 // GPS Week Number of last baseline RTK_RECEIVER_ID uint8 // Identification of connected RTK receiver. RTK_HEALTH uint8 // GPS-specific health report for RTK data. RTK_RATE uint8 // Rate of baseline messages being received by GPS, in HZ NSATS uint8 // Current number of sats used for RTK calculation. BASELINE_COORDS_TYPE uint8 // Coordinate system of baseline. 0 == ECEF, 1 == NED } // NewGps2Rtk returns a new Gps2Rtk func NewGps2Rtk(TIME_LAST_BASELINE_MS uint32, TOW uint32, BASELINE_A_MM int32, BASELINE_B_MM int32, BASELINE_C_MM int32, ACCURACY uint32, IAR_NUM_HYPOTHESES int32, WN uint16, RTK_RECEIVER_ID uint8, RTK_HEALTH uint8, RTK_RATE uint8, NSATS uint8, BASELINE_COORDS_TYPE uint8) *Gps2Rtk { m := Gps2Rtk{} m.TIME_LAST_BASELINE_MS = TIME_LAST_BASELINE_MS m.TOW = TOW m.BASELINE_A_MM = BASELINE_A_MM m.BASELINE_B_MM = BASELINE_B_MM m.BASELINE_C_MM = BASELINE_C_MM m.ACCURACY = ACCURACY m.IAR_NUM_HYPOTHESES = IAR_NUM_HYPOTHESES m.WN = WN m.RTK_RECEIVER_ID = RTK_RECEIVER_ID m.RTK_HEALTH = RTK_HEALTH m.RTK_RATE = RTK_RATE m.NSATS = NSATS m.BASELINE_COORDS_TYPE = BASELINE_COORDS_TYPE return &m } // Id returns the Gps2Rtk Message ID func (*Gps2Rtk) Id() uint8 { return 128 } // Len returns the Gps2Rtk Message Length func (*Gps2Rtk) Len() uint8 { return 35 } // Crc returns the Gps2Rtk Message CRC func (*Gps2Rtk) Crc() uint8 { return 226 } // Pack returns a packed byte array which represents a Gps2Rtk payload func (m *Gps2Rtk) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TIME_LAST_BASELINE_MS); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TOW); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.BASELINE_A_MM); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.BASELINE_B_MM); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.BASELINE_C_MM); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ACCURACY); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.IAR_NUM_HYPOTHESES); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.WN); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.RTK_RECEIVER_ID); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.RTK_HEALTH); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.RTK_RATE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.NSATS); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.BASELINE_COORDS_TYPE); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the Gps2Rtk func (m *Gps2Rtk) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TIME_LAST_BASELINE_MS); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TOW); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.BASELINE_A_MM); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.BASELINE_B_MM); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.BASELINE_C_MM); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ACCURACY); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.IAR_NUM_HYPOTHESES); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.WN); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.RTK_RECEIVER_ID); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.RTK_HEALTH); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.RTK_RATE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.NSATS); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.BASELINE_COORDS_TYPE); err != nil { panic(err) } } // MESSAGE DATA_TRANSMISSION_HANDSHAKE // // MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE 130 // // MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_LEN 13 // // MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_CRC 29 type DataTransmissionHandshake struct { SIZE uint32 // total data size in bytes (set on ACK only) WIDTH uint16 // Width of a matrix or image HEIGHT uint16 // Height of a matrix or image PACKETS uint16 // number of packets being sent (set on ACK only) TYPE uint8 // type of requested/acknowledged data (as defined in ENUM DATA_TYPES in mavlink/include/mavlink_types.h) PAYLOAD uint8 // payload size per packet (normally 253 byte, see DATA field size in message ENCAPSULATED_DATA) (set on ACK only) JPG_QUALITY uint8 // JPEG quality out of [1,100] } // NewDataTransmissionHandshake returns a new DataTransmissionHandshake func NewDataTransmissionHandshake(SIZE uint32, WIDTH uint16, HEIGHT uint16, PACKETS uint16, TYPE uint8, PAYLOAD uint8, JPG_QUALITY uint8) *DataTransmissionHandshake { m := DataTransmissionHandshake{} m.SIZE = SIZE m.WIDTH = WIDTH m.HEIGHT = HEIGHT m.PACKETS = PACKETS m.TYPE = TYPE m.PAYLOAD = PAYLOAD m.JPG_QUALITY = JPG_QUALITY return &m } // Id returns the DataTransmissionHandshake Message ID func (*DataTransmissionHandshake) Id() uint8 { return 130 } // Len returns the DataTransmissionHandshake Message Length func (*DataTransmissionHandshake) Len() uint8 { return 13 } // Crc returns the DataTransmissionHandshake Message CRC func (*DataTransmissionHandshake) Crc() uint8 { return 29 } // Pack returns a packed byte array which represents a DataTransmissionHandshake payload func (m *DataTransmissionHandshake) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.SIZE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.WIDTH); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.HEIGHT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PACKETS); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TYPE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PAYLOAD); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.JPG_QUALITY); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the DataTransmissionHandshake func (m *DataTransmissionHandshake) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.SIZE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.WIDTH); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.HEIGHT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PACKETS); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TYPE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PAYLOAD); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.JPG_QUALITY); err != nil { panic(err) } } // MESSAGE ENCAPSULATED_DATA // // MAVLINK_MSG_ID_ENCAPSULATED_DATA 131 // // MAVLINK_MSG_ID_ENCAPSULATED_DATA_LEN 255 // // MAVLINK_MSG_ID_ENCAPSULATED_DATA_CRC 223 type EncapsulatedData struct { SEQNR uint16 // sequence number (starting with 0 on every transmission) DATA [253]uint8 // image data bytes } // NewEncapsulatedData returns a new EncapsulatedData func NewEncapsulatedData(SEQNR uint16, DATA [253]uint8) *EncapsulatedData { m := EncapsulatedData{} m.SEQNR = SEQNR m.DATA = DATA return &m } // Id returns the EncapsulatedData Message ID func (*EncapsulatedData) Id() uint8 { return 131 } // Len returns the EncapsulatedData Message Length func (*EncapsulatedData) Len() uint8 { return 255 } // Crc returns the EncapsulatedData Message CRC func (*EncapsulatedData) Crc() uint8 { return 223 } // Pack returns a packed byte array which represents a EncapsulatedData payload func (m *EncapsulatedData) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.SEQNR); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.DATA); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the EncapsulatedData func (m *EncapsulatedData) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.SEQNR); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.DATA); err != nil { panic(err) } } const ( MAVLINK_MSG_ENCAPSULATED_DATA_FIELD_data_LEN = 253 ) // MESSAGE DISTANCE_SENSOR // // MAVLINK_MSG_ID_DISTANCE_SENSOR 132 // // MAVLINK_MSG_ID_DISTANCE_SENSOR_LEN 14 // // MAVLINK_MSG_ID_DISTANCE_SENSOR_CRC 85 type DistanceSensor struct { TIME_BOOT_MS uint32 // Time since system boot MIN_DISTANCE uint16 // Minimum distance the sensor can measure in centimeters MAX_DISTANCE uint16 // Maximum distance the sensor can measure in centimeters CURRENT_DISTANCE uint16 // Current distance reading TYPE uint8 // Type from MAV_DISTANCE_SENSOR enum. ID uint8 // Onboard ID of the sensor ORIENTATION uint8 // Direction the sensor faces from FIXME enum. COVARIANCE uint8 // Measurement covariance in centimeters, 0 for unknown / invalid readings } // NewDistanceSensor returns a new DistanceSensor func NewDistanceSensor(TIME_BOOT_MS uint32, MIN_DISTANCE uint16, MAX_DISTANCE uint16, CURRENT_DISTANCE uint16, TYPE uint8, ID uint8, ORIENTATION uint8, COVARIANCE uint8) *DistanceSensor { m := DistanceSensor{} m.TIME_BOOT_MS = TIME_BOOT_MS m.MIN_DISTANCE = MIN_DISTANCE m.MAX_DISTANCE = MAX_DISTANCE m.CURRENT_DISTANCE = CURRENT_DISTANCE m.TYPE = TYPE m.ID = ID m.ORIENTATION = ORIENTATION m.COVARIANCE = COVARIANCE return &m } // Id returns the DistanceSensor Message ID func (*DistanceSensor) Id() uint8 { return 132 } // Len returns the DistanceSensor Message Length func (*DistanceSensor) Len() uint8 { return 14 } // Crc returns the DistanceSensor Message CRC func (*DistanceSensor) Crc() uint8 { return 85 } // Pack returns a packed byte array which represents a DistanceSensor payload func (m *DistanceSensor) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TIME_BOOT_MS); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.MIN_DISTANCE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.MAX_DISTANCE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CURRENT_DISTANCE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TYPE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ID); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ORIENTATION); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.COVARIANCE); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the DistanceSensor func (m *DistanceSensor) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TIME_BOOT_MS); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.MIN_DISTANCE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.MAX_DISTANCE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CURRENT_DISTANCE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TYPE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ID); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ORIENTATION); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.COVARIANCE); err != nil { panic(err) } } // MESSAGE TERRAIN_REQUEST // // MAVLINK_MSG_ID_TERRAIN_REQUEST 133 // // MAVLINK_MSG_ID_TERRAIN_REQUEST_LEN 18 // // MAVLINK_MSG_ID_TERRAIN_REQUEST_CRC 6 type TerrainRequest struct { MASK uint64 // Bitmask of requested 4x4 grids (row major 8x7 array of grids, 56 bits) LAT int32 // Latitude of SW corner of first grid (degrees *10^7) LON int32 // Longitude of SW corner of first grid (in degrees *10^7) GRID_SPACING uint16 // Grid spacing in meters } // NewTerrainRequest returns a new TerrainRequest func NewTerrainRequest(MASK uint64, LAT int32, LON int32, GRID_SPACING uint16) *TerrainRequest { m := TerrainRequest{} m.MASK = MASK m.LAT = LAT m.LON = LON m.GRID_SPACING = GRID_SPACING return &m } // Id returns the TerrainRequest Message ID func (*TerrainRequest) Id() uint8 { return 133 } // Len returns the TerrainRequest Message Length func (*TerrainRequest) Len() uint8 { return 18 } // Crc returns the TerrainRequest Message CRC func (*TerrainRequest) Crc() uint8 { return 6 } // Pack returns a packed byte array which represents a TerrainRequest payload func (m *TerrainRequest) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.MASK); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.LAT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.LON); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.GRID_SPACING); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the TerrainRequest func (m *TerrainRequest) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.MASK); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.LAT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.LON); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.GRID_SPACING); err != nil { panic(err) } } // MESSAGE TERRAIN_DATA // // MAVLINK_MSG_ID_TERRAIN_DATA 134 // // MAVLINK_MSG_ID_TERRAIN_DATA_LEN 43 // // MAVLINK_MSG_ID_TERRAIN_DATA_CRC 229 type TerrainData struct { LAT int32 // Latitude of SW corner of first grid (degrees *10^7) LON int32 // Longitude of SW corner of first grid (in degrees *10^7) GRID_SPACING uint16 // Grid spacing in meters DATA [16]int16 // Terrain data in meters AMSL GRIDBIT uint8 // bit within the terrain request mask } // NewTerrainData returns a new TerrainData func NewTerrainData(LAT int32, LON int32, GRID_SPACING uint16, DATA [16]int16, GRIDBIT uint8) *TerrainData { m := TerrainData{} m.LAT = LAT m.LON = LON m.GRID_SPACING = GRID_SPACING m.DATA = DATA m.GRIDBIT = GRIDBIT return &m } // Id returns the TerrainData Message ID func (*TerrainData) Id() uint8 { return 134 } // Len returns the TerrainData Message Length func (*TerrainData) Len() uint8 { return 43 } // Crc returns the TerrainData Message CRC func (*TerrainData) Crc() uint8 { return 229 } // Pack returns a packed byte array which represents a TerrainData payload func (m *TerrainData) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.LAT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.LON); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.GRID_SPACING); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.DATA); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.GRIDBIT); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the TerrainData func (m *TerrainData) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.LAT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.LON); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.GRID_SPACING); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.DATA); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.GRIDBIT); err != nil { panic(err) } } const ( MAVLINK_MSG_TERRAIN_DATA_FIELD_data_LEN = 16 ) // MESSAGE TERRAIN_CHECK // // MAVLINK_MSG_ID_TERRAIN_CHECK 135 // // MAVLINK_MSG_ID_TERRAIN_CHECK_LEN 8 // // MAVLINK_MSG_ID_TERRAIN_CHECK_CRC 203 type TerrainCheck struct { LAT int32 // Latitude (degrees *10^7) LON int32 // Longitude (degrees *10^7) } // NewTerrainCheck returns a new TerrainCheck func NewTerrainCheck(LAT int32, LON int32) *TerrainCheck { m := TerrainCheck{} m.LAT = LAT m.LON = LON return &m } // Id returns the TerrainCheck Message ID func (*TerrainCheck) Id() uint8 { return 135 } // Len returns the TerrainCheck Message Length func (*TerrainCheck) Len() uint8 { return 8 } // Crc returns the TerrainCheck Message CRC func (*TerrainCheck) Crc() uint8 { return 203 } // Pack returns a packed byte array which represents a TerrainCheck payload func (m *TerrainCheck) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.LAT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.LON); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the TerrainCheck func (m *TerrainCheck) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.LAT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.LON); err != nil { panic(err) } } // MESSAGE TERRAIN_REPORT // // MAVLINK_MSG_ID_TERRAIN_REPORT 136 // // MAVLINK_MSG_ID_TERRAIN_REPORT_LEN 22 // // MAVLINK_MSG_ID_TERRAIN_REPORT_CRC 1 type TerrainReport struct { LAT int32 // Latitude (degrees *10^7) LON int32 // Longitude (degrees *10^7) TERRAIN_HEIGHT float32 // Terrain height in meters AMSL CURRENT_HEIGHT float32 // Current vehicle height above lat/lon terrain height (meters) SPACING uint16 // grid spacing (zero if terrain at this location unavailable) PENDING uint16 // Number of 4x4 terrain blocks waiting to be received or read from disk LOADED uint16 // Number of 4x4 terrain blocks in memory } // NewTerrainReport returns a new TerrainReport func NewTerrainReport(LAT int32, LON int32, TERRAIN_HEIGHT float32, CURRENT_HEIGHT float32, SPACING uint16, PENDING uint16, LOADED uint16) *TerrainReport { m := TerrainReport{} m.LAT = LAT m.LON = LON m.TERRAIN_HEIGHT = TERRAIN_HEIGHT m.CURRENT_HEIGHT = CURRENT_HEIGHT m.SPACING = SPACING m.PENDING = PENDING m.LOADED = LOADED return &m } // Id returns the TerrainReport Message ID func (*TerrainReport) Id() uint8 { return 136 } // Len returns the TerrainReport Message Length func (*TerrainReport) Len() uint8 { return 22 } // Crc returns the TerrainReport Message CRC func (*TerrainReport) Crc() uint8 { return 1 } // Pack returns a packed byte array which represents a TerrainReport payload func (m *TerrainReport) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.LAT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.LON); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TERRAIN_HEIGHT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CURRENT_HEIGHT); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.SPACING); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.PENDING); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.LOADED); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the TerrainReport func (m *TerrainReport) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.LAT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.LON); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TERRAIN_HEIGHT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CURRENT_HEIGHT); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.SPACING); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.PENDING); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.LOADED); err != nil { panic(err) } } // MESSAGE BATTERY_STATUS // // MAVLINK_MSG_ID_BATTERY_STATUS 147 // // MAVLINK_MSG_ID_BATTERY_STATUS_LEN 24 // // MAVLINK_MSG_ID_BATTERY_STATUS_CRC 177 type BatteryStatus struct { CURRENT_CONSUMED int32 // Consumed charge, in milliampere hours (1 = 1 mAh), -1: autopilot does not provide mAh consumption estimate ENERGY_CONSUMED int32 // Consumed energy, in 100*Joules (integrated U*I*dt) (1 = 100 Joule), -1: autopilot does not provide energy consumption estimate VOLTAGE_CELL_1 uint16 // Battery voltage of cell 1, in millivolts (1 = 1 millivolt) VOLTAGE_CELL_2 uint16 // Battery voltage of cell 2, in millivolts (1 = 1 millivolt), -1: no cell VOLTAGE_CELL_3 uint16 // Battery voltage of cell 3, in millivolts (1 = 1 millivolt), -1: no cell VOLTAGE_CELL_4 uint16 // Battery voltage of cell 4, in millivolts (1 = 1 millivolt), -1: no cell VOLTAGE_CELL_5 uint16 // Battery voltage of cell 5, in millivolts (1 = 1 millivolt), -1: no cell VOLTAGE_CELL_6 uint16 // Battery voltage of cell 6, in millivolts (1 = 1 millivolt), -1: no cell CURRENT_BATTERY int16 // Battery current, in 10*milliamperes (1 = 10 milliampere), -1: autopilot does not measure the current ACCU_ID uint8 // Accupack ID BATTERY_REMAINING int8 // Remaining battery energy: (0%: 0, 100%: 100), -1: autopilot does not estimate the remaining battery } // NewBatteryStatus returns a new BatteryStatus func NewBatteryStatus(CURRENT_CONSUMED int32, ENERGY_CONSUMED int32, VOLTAGE_CELL_1 uint16, VOLTAGE_CELL_2 uint16, VOLTAGE_CELL_3 uint16, VOLTAGE_CELL_4 uint16, VOLTAGE_CELL_5 uint16, VOLTAGE_CELL_6 uint16, CURRENT_BATTERY int16, ACCU_ID uint8, BATTERY_REMAINING int8) *BatteryStatus { m := BatteryStatus{} m.CURRENT_CONSUMED = CURRENT_CONSUMED m.ENERGY_CONSUMED = ENERGY_CONSUMED m.VOLTAGE_CELL_1 = VOLTAGE_CELL_1 m.VOLTAGE_CELL_2 = VOLTAGE_CELL_2 m.VOLTAGE_CELL_3 = VOLTAGE_CELL_3 m.VOLTAGE_CELL_4 = VOLTAGE_CELL_4 m.VOLTAGE_CELL_5 = VOLTAGE_CELL_5 m.VOLTAGE_CELL_6 = VOLTAGE_CELL_6 m.CURRENT_BATTERY = CURRENT_BATTERY m.ACCU_ID = ACCU_ID m.BATTERY_REMAINING = BATTERY_REMAINING return &m } // Id returns the BatteryStatus Message ID func (*BatteryStatus) Id() uint8 { return 147 } // Len returns the BatteryStatus Message Length func (*BatteryStatus) Len() uint8 { return 24 } // Crc returns the BatteryStatus Message CRC func (*BatteryStatus) Crc() uint8 { return 177 } // Pack returns a packed byte array which represents a BatteryStatus payload func (m *BatteryStatus) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.CURRENT_CONSUMED); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ENERGY_CONSUMED); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VOLTAGE_CELL_1); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VOLTAGE_CELL_2); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VOLTAGE_CELL_3); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VOLTAGE_CELL_4); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VOLTAGE_CELL_5); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VOLTAGE_CELL_6); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.CURRENT_BATTERY); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ACCU_ID); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.BATTERY_REMAINING); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the BatteryStatus func (m *BatteryStatus) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.CURRENT_CONSUMED); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ENERGY_CONSUMED); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VOLTAGE_CELL_1); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VOLTAGE_CELL_2); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VOLTAGE_CELL_3); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VOLTAGE_CELL_4); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VOLTAGE_CELL_5); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VOLTAGE_CELL_6); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.CURRENT_BATTERY); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ACCU_ID); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.BATTERY_REMAINING); err != nil { panic(err) } } // MESSAGE SETPOINT_8DOF // // MAVLINK_MSG_ID_SETPOINT_8DOF 148 // // MAVLINK_MSG_ID_SETPOINT_8DOF_LEN 33 // // MAVLINK_MSG_ID_SETPOINT_8DOF_CRC 241 type Setpoint8Dof struct { VAL1 float32 // Value 1 VAL2 float32 // Value 2 VAL3 float32 // Value 3 VAL4 float32 // Value 4 VAL5 float32 // Value 5 VAL6 float32 // Value 6 VAL7 float32 // Value 7 VAL8 float32 // Value 8 TARGET_SYSTEM uint8 // System ID } // NewSetpoint8Dof returns a new Setpoint8Dof func NewSetpoint8Dof(VAL1 float32, VAL2 float32, VAL3 float32, VAL4 float32, VAL5 float32, VAL6 float32, VAL7 float32, VAL8 float32, TARGET_SYSTEM uint8) *Setpoint8Dof { m := Setpoint8Dof{} m.VAL1 = VAL1 m.VAL2 = VAL2 m.VAL3 = VAL3 m.VAL4 = VAL4 m.VAL5 = VAL5 m.VAL6 = VAL6 m.VAL7 = VAL7 m.VAL8 = VAL8 m.TARGET_SYSTEM = TARGET_SYSTEM return &m } // Id returns the Setpoint8Dof Message ID func (*Setpoint8Dof) Id() uint8 { return 148 } // Len returns the Setpoint8Dof Message Length func (*Setpoint8Dof) Len() uint8 { return 33 } // Crc returns the Setpoint8Dof Message CRC func (*Setpoint8Dof) Crc() uint8 { return 241 } // Pack returns a packed byte array which represents a Setpoint8Dof payload func (m *Setpoint8Dof) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.VAL1); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VAL2); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VAL3); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VAL4); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VAL5); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VAL6); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VAL7); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VAL8); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_SYSTEM); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the Setpoint8Dof func (m *Setpoint8Dof) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.VAL1); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VAL2); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VAL3); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VAL4); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VAL5); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VAL6); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VAL7); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VAL8); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_SYSTEM); err != nil { panic(err) } } // MESSAGE SETPOINT_6DOF // // MAVLINK_MSG_ID_SETPOINT_6DOF 149 // // MAVLINK_MSG_ID_SETPOINT_6DOF_LEN 25 // // MAVLINK_MSG_ID_SETPOINT_6DOF_CRC 15 type Setpoint6Dof struct { TRANS_X float32 // Translational Component in x TRANS_Y float32 // Translational Component in y TRANS_Z float32 // Translational Component in z ROT_X float32 // Rotational Component in x ROT_Y float32 // Rotational Component in y ROT_Z float32 // Rotational Component in z TARGET_SYSTEM uint8 // System ID } // NewSetpoint6Dof returns a new Setpoint6Dof func NewSetpoint6Dof(TRANS_X float32, TRANS_Y float32, TRANS_Z float32, ROT_X float32, ROT_Y float32, ROT_Z float32, TARGET_SYSTEM uint8) *Setpoint6Dof { m := Setpoint6Dof{} m.TRANS_X = TRANS_X m.TRANS_Y = TRANS_Y m.TRANS_Z = TRANS_Z m.ROT_X = ROT_X m.ROT_Y = ROT_Y m.ROT_Z = ROT_Z m.TARGET_SYSTEM = TARGET_SYSTEM return &m } // Id returns the Setpoint6Dof Message ID func (*Setpoint6Dof) Id() uint8 { return 149 } // Len returns the Setpoint6Dof Message Length func (*Setpoint6Dof) Len() uint8 { return 25 } // Crc returns the Setpoint6Dof Message CRC func (*Setpoint6Dof) Crc() uint8 { return 15 } // Pack returns a packed byte array which represents a Setpoint6Dof payload func (m *Setpoint6Dof) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TRANS_X); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TRANS_Y); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TRANS_Z); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ROT_X); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ROT_Y); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ROT_Z); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TARGET_SYSTEM); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the Setpoint6Dof func (m *Setpoint6Dof) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TRANS_X); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TRANS_Y); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TRANS_Z); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ROT_X); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ROT_Y); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.ROT_Z); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TARGET_SYSTEM); err != nil { panic(err) } } // MESSAGE MEMORY_VECT // // MAVLINK_MSG_ID_MEMORY_VECT 249 // // MAVLINK_MSG_ID_MEMORY_VECT_LEN 36 // // MAVLINK_MSG_ID_MEMORY_VECT_CRC 204 type MemoryVect struct { ADDRESS uint16 // Starting address of the debug variables VER uint8 // Version code of the type variable. 0=unknown, type ignored and assumed int16_t. 1=as below TYPE uint8 // Type code of the memory variables. for ver = 1: 0=16 x int16_t, 1=16 x uint16_t, 2=16 x Q15, 3=16 x 1Q14 VALUE [32]int8 // Memory contents at specified address } // NewMemoryVect returns a new MemoryVect func NewMemoryVect(ADDRESS uint16, VER uint8, TYPE uint8, VALUE [32]int8) *MemoryVect { m := MemoryVect{} m.ADDRESS = ADDRESS m.VER = VER m.TYPE = TYPE m.VALUE = VALUE return &m } // Id returns the MemoryVect Message ID func (*MemoryVect) Id() uint8 { return 249 } // Len returns the MemoryVect Message Length func (*MemoryVect) Len() uint8 { return 36 } // Crc returns the MemoryVect Message CRC func (*MemoryVect) Crc() uint8 { return 204 } // Pack returns a packed byte array which represents a MemoryVect payload func (m *MemoryVect) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.ADDRESS); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VER); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TYPE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VALUE); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the MemoryVect func (m *MemoryVect) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.ADDRESS); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VER); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TYPE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VALUE); err != nil { panic(err) } } const ( MAVLINK_MSG_MEMORY_VECT_FIELD_value_LEN = 32 ) // MESSAGE DEBUG_VECT // // MAVLINK_MSG_ID_DEBUG_VECT 250 // // MAVLINK_MSG_ID_DEBUG_VECT_LEN 30 // // MAVLINK_MSG_ID_DEBUG_VECT_CRC 49 type DebugVect struct { TIME_USEC uint64 // Timestamp X float32 // x Y float32 // y Z float32 // z NAME [10]uint8 // Name } // NewDebugVect returns a new DebugVect func NewDebugVect(TIME_USEC uint64, X float32, Y float32, Z float32, NAME [10]uint8) *DebugVect { m := DebugVect{} m.TIME_USEC = TIME_USEC m.X = X m.Y = Y m.Z = Z m.NAME = NAME return &m } // Id returns the DebugVect Message ID func (*DebugVect) Id() uint8 { return 250 } // Len returns the DebugVect Message Length func (*DebugVect) Len() uint8 { return 30 } // Crc returns the DebugVect Message CRC func (*DebugVect) Crc() uint8 { return 49 } // Pack returns a packed byte array which represents a DebugVect payload func (m *DebugVect) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TIME_USEC); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.X); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.Y); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.Z); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.NAME); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the DebugVect func (m *DebugVect) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TIME_USEC); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.X); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.Y); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.Z); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.NAME); err != nil { panic(err) } } const ( MAVLINK_MSG_DEBUG_VECT_FIELD_name_LEN = 10 ) // MESSAGE NAMED_VALUE_FLOAT // // MAVLINK_MSG_ID_NAMED_VALUE_FLOAT 251 // // MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_LEN 18 // // MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_CRC 170 type NamedValueFloat struct { TIME_BOOT_MS uint32 // Timestamp (milliseconds since system boot) VALUE float32 // Floating point value NAME [10]uint8 // Name of the debug variable } // NewNamedValueFloat returns a new NamedValueFloat func NewNamedValueFloat(TIME_BOOT_MS uint32, VALUE float32, NAME [10]uint8) *NamedValueFloat { m := NamedValueFloat{} m.TIME_BOOT_MS = TIME_BOOT_MS m.VALUE = VALUE m.NAME = NAME return &m } // Id returns the NamedValueFloat Message ID func (*NamedValueFloat) Id() uint8 { return 251 } // Len returns the NamedValueFloat Message Length func (*NamedValueFloat) Len() uint8 { return 18 } // Crc returns the NamedValueFloat Message CRC func (*NamedValueFloat) Crc() uint8 { return 170 } // Pack returns a packed byte array which represents a NamedValueFloat payload func (m *NamedValueFloat) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TIME_BOOT_MS); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VALUE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.NAME); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the NamedValueFloat func (m *NamedValueFloat) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TIME_BOOT_MS); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VALUE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.NAME); err != nil { panic(err) } } const ( MAVLINK_MSG_NAMED_VALUE_FLOAT_FIELD_name_LEN = 10 ) // MESSAGE NAMED_VALUE_INT // // MAVLINK_MSG_ID_NAMED_VALUE_INT 252 // // MAVLINK_MSG_ID_NAMED_VALUE_INT_LEN 18 // // MAVLINK_MSG_ID_NAMED_VALUE_INT_CRC 44 type NamedValueInt struct { TIME_BOOT_MS uint32 // Timestamp (milliseconds since system boot) VALUE int32 // Signed integer value NAME [10]uint8 // Name of the debug variable } // NewNamedValueInt returns a new NamedValueInt func NewNamedValueInt(TIME_BOOT_MS uint32, VALUE int32, NAME [10]uint8) *NamedValueInt { m := NamedValueInt{} m.TIME_BOOT_MS = TIME_BOOT_MS m.VALUE = VALUE m.NAME = NAME return &m } // Id returns the NamedValueInt Message ID func (*NamedValueInt) Id() uint8 { return 252 } // Len returns the NamedValueInt Message Length func (*NamedValueInt) Len() uint8 { return 18 } // Crc returns the NamedValueInt Message CRC func (*NamedValueInt) Crc() uint8 { return 44 } // Pack returns a packed byte array which represents a NamedValueInt payload func (m *NamedValueInt) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TIME_BOOT_MS); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VALUE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.NAME); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the NamedValueInt func (m *NamedValueInt) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TIME_BOOT_MS); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VALUE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.NAME); err != nil { panic(err) } } const ( MAVLINK_MSG_NAMED_VALUE_INT_FIELD_name_LEN = 10 ) // MESSAGE STATUSTEXT // // MAVLINK_MSG_ID_STATUSTEXT 253 // // MAVLINK_MSG_ID_STATUSTEXT_LEN 51 // // MAVLINK_MSG_ID_STATUSTEXT_CRC 83 type Statustext struct { SEVERITY uint8 // Severity of status. Relies on the definitions within RFC-5424. See enum MAV_SEVERITY. TEXT [50]uint8 // Status text message, without null termination character } // NewStatustext returns a new Statustext func NewStatustext(SEVERITY uint8, TEXT [50]uint8) *Statustext { m := Statustext{} m.SEVERITY = SEVERITY m.TEXT = TEXT return &m } // Id returns the Statustext Message ID func (*Statustext) Id() uint8 { return 253 } // Len returns the Statustext Message Length func (*Statustext) Len() uint8 { return 51 } // Crc returns the Statustext Message CRC func (*Statustext) Crc() uint8 { return 83 } // Pack returns a packed byte array which represents a Statustext payload func (m *Statustext) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.SEVERITY); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.TEXT); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the Statustext func (m *Statustext) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.SEVERITY); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.TEXT); err != nil { panic(err) } } const ( MAVLINK_MSG_STATUSTEXT_FIELD_text_LEN = 50 ) // MESSAGE DEBUG // // MAVLINK_MSG_ID_DEBUG 254 // // MAVLINK_MSG_ID_DEBUG_LEN 9 // // MAVLINK_MSG_ID_DEBUG_CRC 46 type Debug struct { TIME_BOOT_MS uint32 // Timestamp (milliseconds since system boot) VALUE float32 // DEBUG value IND uint8 // index of debug variable } // NewDebug returns a new Debug func NewDebug(TIME_BOOT_MS uint32, VALUE float32, IND uint8) *Debug { m := Debug{} m.TIME_BOOT_MS = TIME_BOOT_MS m.VALUE = VALUE m.IND = IND return &m } // Id returns the Debug Message ID func (*Debug) Id() uint8 { return 254 } // Len returns the Debug Message Length func (*Debug) Len() uint8 { return 9 } // Crc returns the Debug Message CRC func (*Debug) Crc() uint8 { return 46 } // Pack returns a packed byte array which represents a Debug payload func (m *Debug) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.TIME_BOOT_MS); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.VALUE); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.IND); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the Debug func (m *Debug) Decode(buf []byte) { data := bytes.NewBuffer(buf) if err := binary.Read(data, binary.LittleEndian, &m.TIME_BOOT_MS); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.VALUE); err != nil { panic(err) } if err := binary.Read(data, binary.LittleEndian, &m.IND); err != nil { panic(err) } } ================================================ FILE: platforms/mavlink/common/mavlink.go ================================================ package mavlink // // MAVLink comm protocol built from common.xml // http://pixhawk.ethz.ch/software/mavlink // import ( "bytes" "encoding/binary" "io" "time" ) const ( MAVLINK_BIG_ENDIAN = 0 MAVLINK_LITTLE_ENDIAN = 1 MAVLINK_10_STX = 254 MAVLINK_20_STX = 253 MAVLINK_ENDIAN = MAVLINK_LITTLE_ENDIAN MAVLINK_ALIGNED_FIELDS = 1 MAVLINK_CRC_EXTRA = 1 X25_INIT_CRC = 0xffff X25_VALIDATE_CRC = 0xf0b8 ) var sequence uint16 = 0 func generateSequence() uint8 { sequence = (sequence + 1) % 256 return uint8(sequence) //nolint:gosec // ok here } // The MAVLinkMessage interface is implemented by MAVLink messages type MAVLinkMessage interface { Id() uint8 Len() uint8 Crc() uint8 Pack() []byte Decode(buf []byte) } // A MAVLinkPacket represents a raw packet received from a micro air vehicle type MAVLinkPacket struct { Protocol uint8 Length uint8 Sequence uint8 SystemID uint8 ComponentID uint8 MessageID uint8 Data []uint8 Checksum uint16 } // ReadMAVLinkPacket reads an io.Reader for a new packet and returns a new MAVLink packet // or returns the error received by the io.Reader func ReadMAVLinkPacket(r io.Reader) (*MAVLinkPacket, error) { for { header, err := read(r, 1) if err != nil { return nil, err } if header[0] == 254 { length, err := read(r, 1) if err != nil { return nil, err } else if length[0] > 250 { continue } m := &MAVLinkPacket{} data, err := read(r, int(length[0])+7) if err != nil { return nil, err } data = append([]byte{header[0], length[0]}, data...) m.Decode(data) return m, nil } } } // CraftMAVLinkPacket returns a new MAVLinkPacket from a MAVLinkMessage func CraftMAVLinkPacket(systemID uint8, cComponentID uint8, mMessage MAVLinkMessage) *MAVLinkPacket { return NewMAVLinkPacket( 0xFE, mMessage.Len(), generateSequence(), systemID, cComponentID, mMessage.Id(), mMessage.Pack(), ) } // NewMAVLinkPacket returns a new MAVLinkPacket func NewMAVLinkPacket( pProtocol uint8, lLength uint8, sSequence uint8, sSystemID uint8, cComponentID uint8, mMessageID uint8, dData []uint8, ) *MAVLinkPacket { m := &MAVLinkPacket{ Protocol: pProtocol, Length: lLength, Sequence: sSequence, SystemID: sSystemID, ComponentID: cComponentID, MessageID: mMessageID, Data: dData, } m.Checksum = crcCalculate(m) return m } // MAVLinkMessage returns the decoded MAVLinkMessage from the MAVLinkPacket // or returns an error generated from the MAVLinkMessage func (m *MAVLinkPacket) MAVLinkMessage() (MAVLinkMessage, error) { return NewMAVLinkMessage(m.MessageID, m.Data) } // Pack returns a packed byte array which represents the MAVLinkPacket func (m *MAVLinkPacket) Pack() []byte { data := new(bytes.Buffer) if err := binary.Write(data, binary.LittleEndian, m.Protocol); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.Length); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.Sequence); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.SystemID); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.ComponentID); err != nil { panic(err) } if err := binary.Write(data, binary.LittleEndian, m.MessageID); err != nil { panic(err) } data.Write(m.Data) if err := binary.Write(data, binary.LittleEndian, m.Checksum); err != nil { panic(err) } return data.Bytes() } // Decode accepts a packed byte array and populates the fields of the MAVLinkPacket func (m *MAVLinkPacket) Decode(buf []byte) { m.Protocol = buf[0] m.Length = buf[1] m.Sequence = buf[2] m.SystemID = buf[3] m.ComponentID = buf[4] m.MessageID = buf[5] m.Data = buf[6 : 6+int(m.Length)] checksum := buf[7+int(m.Length):] m.Checksum = uint16(checksum[1])<<8 | uint16(checksum[0]) } func read(r io.Reader, length int) ([]byte, error) { buf := []byte{} for length > 0 { tmp := make([]byte, length) i, err := r.Read(tmp) if err != nil { return nil, err } length -= i buf = append(buf, tmp...) if length != i { time.Sleep(1 * time.Millisecond) } else { break } } return buf, nil } // Accumulate the X.25 CRC by adding one char at a time. // // The checksum function adds the hash of one char at a time to the // 16 bit checksum (uint16). // // data to hash // crcAccum the already accumulated checksum func crcAccumulate(data uint8, crcAccum uint16) uint16 { /*Accumulate one byte of data into the CRC*/ var tmp uint8 tmp = data ^ (uint8)(crcAccum&0xff) //nolint:gosec // ok here tmp ^= (tmp << 4) crcAccum = (crcAccum >> 8) ^ (uint16(tmp) << 8) ^ (uint16(tmp) << 3) ^ (uint16(tmp) >> 4) return crcAccum } // Initiliaze the buffer for the X.25 CRC func crcInit() uint16 { return X25_INIT_CRC } // Calculates the X.25 checksum on a byte buffer // // return the checksum over the buffer bytes func crcCalculate(m *MAVLinkPacket) uint16 { crc := crcInit() for _, v := range m.Pack()[1 : m.Length+6] { crc = crcAccumulate(v, crc) } message, _ := m.MAVLinkMessage() crc = crcAccumulate(message.Crc(), crc) return crc } ================================================ FILE: platforms/mavlink/common/version.go ================================================ package mavlink // // MAVLink comm protocol built from common.xml // http://pixhawk.ethz.ch/software/mavlink // const ( MAVLINK_BUILD_DATE = "Fri Sep 26 19:23:02 2014" MAVLINK_WIRE_PROTOCOL_VERSION = "1.0" MAVLINK_MAX_DIALECT_PAYLOAD_SIZE = 255 MAVLINK_VERSION = 3 ) ================================================ FILE: platforms/mavlink/doc.go ================================================ /* Package mavlink contains the Gobot adaptor and driver for the MAVlink Communication Protocol. Installing: Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) Example: package main import ( "fmt" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/mavlink" common "gobot.io/x/gobot/v2/platforms/mavlink/common" ) func main() { adaptor := mavlink.NewAdaptor("/dev/ttyACM0") iris := mavlink.NewDriver(adaptor) work := func() { iris.Once(iris.Event("packet"), func(data interface{}) { packet := data.(*common.MAVLinkPacket) dataStream := common.NewRequestDataStream(100, packet.SystemID, packet.ComponentID, 4, 1, ) iris.SendPacket(common.CraftMAVLinkPacket(packet.SystemID, packet.ComponentID, dataStream, )) }) iris.On(iris.Event("message"), func(data interface{}) { if data.(common.MAVLinkMessage).Id() == 30 { message := data.(*common.Attitude) fmt.Println("Attitude") fmt.Println("TIME_BOOT_MS", message.TIME_BOOT_MS) fmt.Println("ROLL", message.ROLL) fmt.Println("PITCH", message.PITCH) fmt.Println("YAW", message.YAW) fmt.Println("ROLLSPEED", message.ROLLSPEED) fmt.Println("PITCHSPEED", message.PITCHSPEED) fmt.Println("YAWSPEED", message.YAWSPEED) fmt.Println("") } }) } robot := gobot.NewRobot("mavBot", []gobot.Connection{adaptor}, []gobot.Device{iris}, work, ) if err := robot.Start(); err != nil { panic(err) } } For further information refer to mavlink README: https://github.com/hybridgroup/gobot/blob/release/platforms/mavlink/README.md */ package mavlink // import "gobot.io/x/gobot/v2/platforms/mavlink" ================================================ FILE: platforms/mavlink/mavlink_adaptor.go ================================================ package mavlink import ( "io" "go.bug.st/serial" "gobot.io/x/gobot/v2" common "gobot.io/x/gobot/v2/platforms/mavlink/common" ) // Adaptor is a Mavlink transport adaptor. type BaseAdaptor interface { gobot.Connection io.Writer ReadMAVLinkPacket() (*common.MAVLinkPacket, error) } // Adaptor is a Mavlink-over-serial adaptor. type Adaptor struct { name string port string sp io.ReadWriteCloser connect func(string) (io.ReadWriteCloser, error) } // NewAdaptor creates a new mavlink adaptor with specified port func NewAdaptor(port string) *Adaptor { return &Adaptor{ name: "Mavlink", port: port, connect: func(port string) (io.ReadWriteCloser, error) { return serial.Open(port, &serial.Mode{BaudRate: 57600}) }, } } func (m *Adaptor) Name() string { return m.name } func (m *Adaptor) SetName(n string) { m.name = n } func (m *Adaptor) Port() string { return m.port } // Connect returns true if connection to device is successful func (m *Adaptor) Connect() error { sp, err := m.connect(m.Port()) if err != nil { return err } m.sp = sp return nil } // Finalize returns true if connection to devices is closed successfully func (m *Adaptor) Finalize() error { return m.sp.Close() } func (m *Adaptor) ReadMAVLinkPacket() (*common.MAVLinkPacket, error) { return common.ReadMAVLinkPacket(m.sp) } func (m *Adaptor) Write(b []byte) (int, error) { return m.sp.Write(b) } ================================================ FILE: platforms/mavlink/mavlink_adaptor_test.go ================================================ package mavlink import ( "errors" "io" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) var _ gobot.Adaptor = (*Adaptor)(nil) type nullReadWriteCloser struct{} var payload = []byte{ 0xFE, 0x09, 0x4E, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x51, 0x04, 0x03, 0x1C, 0x7F, } var testAdaptorRead = func(p []byte) (int, error) { return len(p), nil } func (nullReadWriteCloser) Write(p []byte) (int, error) { return testAdaptorRead(p) } var testAdaptorWrite = func(b []byte) (int, error) { if len(payload) > 0 { copy(b, payload[:len(b)]) payload = payload[len(b):] return len(b), nil } return 0, errors.New("out of bytes") } func (nullReadWriteCloser) Read(b []byte) (int, error) { return testAdaptorWrite(b) } var testAdaptorClose = func() error { return nil } func (nullReadWriteCloser) Close() error { return testAdaptorClose() } func initTestMavlinkAdaptor() *Adaptor { m := NewAdaptor("/dev/null") m.sp = nullReadWriteCloser{} m.connect = func(port string) (io.ReadWriteCloser, error) { return nil, nil } //nolint:nilnil // ok for tests return m } func TestMavlinkAdaptor(t *testing.T) { a := initTestMavlinkAdaptor() assert.Equal(t, "/dev/null", a.Port()) } func TestMavlinkAdaptorName(t *testing.T) { a := initTestMavlinkAdaptor() assert.True(t, strings.HasPrefix(a.Name(), "Mavlink")) a.SetName("NewName") assert.Equal(t, "NewName", a.Name()) } func TestMavlinkAdaptorConnect(t *testing.T) { a := initTestMavlinkAdaptor() require.NoError(t, a.Connect()) a.connect = func(port string) (io.ReadWriteCloser, error) { return nil, errors.New("connect error") } require.ErrorContains(t, a.Connect(), "connect error") } func TestMavlinkAdaptorFinalize(t *testing.T) { a := initTestMavlinkAdaptor() require.NoError(t, a.Finalize()) testAdaptorClose = func() error { return errors.New("close error") } require.ErrorContains(t, a.Finalize(), "close error") } ================================================ FILE: platforms/mavlink/mavlink_driver.go ================================================ package mavlink import ( "time" "gobot.io/x/gobot/v2" common "gobot.io/x/gobot/v2/platforms/mavlink/common" ) const ( // PacketEvent event PacketEvent = "packet" // MessageEvent event MessageEvent = "message" // ErrorIOEEvent event ErrorIOEvent = "errorIO" // ErrorMAVLinkEvent event ErrorMAVLinkEvent = "errorMAVLink" ) type Driver struct { gobot.Eventer name string connection gobot.Connection interval time.Duration } type MavlinkInterface interface{} // NewDriver creates a new mavlink driver. // // It add the following events: // // "packet" - triggered when a new packet is read // "message" - triggered when a new valid message is processed func NewDriver(a BaseAdaptor, v ...time.Duration) *Driver { m := &Driver{ name: "Mavlink", connection: a, Eventer: gobot.NewEventer(), interval: 10 * time.Millisecond, } if len(v) > 0 { m.interval = v[0] } m.AddEvent(PacketEvent) m.AddEvent(MessageEvent) m.AddEvent(ErrorIOEvent) m.AddEvent(ErrorMAVLinkEvent) return m } func (m *Driver) Connection() gobot.Connection { return m.connection } func (m *Driver) Name() string { return m.name } func (m *Driver) SetName(n string) { m.name = n } // adaptor returns driver associated adaptor func (m *Driver) adaptor() BaseAdaptor { //nolint:forcetypeassert // ok here return m.Connection().(BaseAdaptor) } // Start begins process to read mavlink packets every m.Interval // and process them func (m *Driver) Start() error { go func() { for { packet, err := m.adaptor().ReadMAVLinkPacket() if err != nil { m.Publish(ErrorIOEvent, err) continue } m.Publish(PacketEvent, packet) message, err := packet.MAVLinkMessage() if err != nil { m.Publish(ErrorMAVLinkEvent, err) continue } m.Publish(MessageEvent, message) time.Sleep(m.interval) } }() return nil } // Halt returns true if device is halted successfully func (m *Driver) Halt() error { return nil } // SendPacket sends a packet to mavlink device func (m *Driver) SendPacket(packet *common.MAVLinkPacket) error { _, err := m.adaptor().Write(packet.Pack()) return err } ================================================ FILE: platforms/mavlink/mavlink_driver_test.go ================================================ //nolint:forcetypeassert,nilnil // ok here package mavlink import ( "io" "strings" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" common "gobot.io/x/gobot/v2/platforms/mavlink/common" ) var _ gobot.Driver = (*Driver)(nil) func initTestMavlinkDriver() *Driver { m := NewAdaptor("/dev/null") m.connect = func(port string) (io.ReadWriteCloser, error) { return nil, nil } m.sp = nullReadWriteCloser{} return NewDriver(m) } func TestMavlinkDriver(t *testing.T) { m := NewAdaptor("/dev/null") m.sp = nullReadWriteCloser{} m.connect = func(port string) (io.ReadWriteCloser, error) { return nil, nil } d := NewDriver(m) assert.NotNil(t, d.Connection()) assert.Equal(t, 10*time.Millisecond, d.interval) d = NewDriver(m, 100*time.Millisecond) assert.Equal(t, 100*time.Millisecond, d.interval) } func TestMavlinkDriverName(t *testing.T) { d := initTestMavlinkDriver() assert.True(t, strings.HasPrefix(d.Name(), "Mavlink")) d.SetName("NewName") assert.Equal(t, "NewName", d.Name()) } func TestMavlinkDriverStart(t *testing.T) { d := initTestMavlinkDriver() err := make(chan error) packet := make(chan *common.MAVLinkPacket) message := make(chan common.MAVLinkMessage) _ = d.On(PacketEvent, func(data interface{}) { packet <- data.(*common.MAVLinkPacket) }) _ = d.On(MessageEvent, func(data interface{}) { message <- data.(common.MAVLinkMessage) }) _ = d.On(ErrorIOEvent, func(data interface{}) { err <- data.(error) }) _ = d.On(ErrorMAVLinkEvent, func(data interface{}) { err <- data.(error) }) require.NoError(t, d.Start()) select { case p := <-packet: require.NoError(t, d.SendPacket(p)) case <-time.After(100 * time.Millisecond): require.Fail(t, "packet was not emitted") } select { case <-message: case <-time.After(100 * time.Millisecond): require.Fail(t, "message was not emitted") } select { case <-err: case <-time.After(100 * time.Millisecond): require.Fail(t, "error was not emitted") } } func TestMavlinkDriverHalt(t *testing.T) { d := initTestMavlinkDriver() require.NoError(t, d.Halt()) } ================================================ FILE: platforms/mavlink/mavlink_udp_adaptor.go ================================================ package mavlink import ( "net" common "gobot.io/x/gobot/v2/platforms/mavlink/common" ) type UDPConnection interface { Close() error ReadFromUDP(b []byte) (int, *net.UDPAddr, error) WriteTo(b []byte, a net.Addr) (int, error) } type UDPAdaptor struct { name string port string sock UDPConnection } var _ BaseAdaptor = (*UDPAdaptor)(nil) // NewAdaptor creates a new Mavlink-over-UDP adaptor with specified // port. func NewUDPAdaptor(port string) *UDPAdaptor { return &UDPAdaptor{ name: "Mavlink", port: port, } } func (m *UDPAdaptor) Name() string { return m.name } func (m *UDPAdaptor) SetName(n string) { m.name = n } func (m *UDPAdaptor) Port() string { return m.port } // Connect returns true if connection to device is successful func (m *UDPAdaptor) Connect() error { m.close() addr, err := net.ResolveUDPAddr("udp", m.Port()) if err != nil { return err } m.sock, err = net.ListenUDP("udp", addr) if err != nil { return err } return nil } func (m *UDPAdaptor) close() error { sock := m.sock m.sock = nil if sock != nil { return sock.Close() } else { return nil } } // Finalize returns true if connection to devices is closed successfully func (m *UDPAdaptor) Finalize() error { return m.close() } func (m *UDPAdaptor) ReadMAVLinkPacket() (*common.MAVLinkPacket, error) { buf := make([]byte, 4096) for { got, _, err := m.sock.ReadFromUDP(buf) if err != nil { return nil, err } if got < 2 { continue } sof := buf[0] length := buf[1] if sof != common.MAVLINK_10_STX { continue } if length > 250 { continue } m := &common.MAVLinkPacket{} m.Decode(buf) return m, nil } } func (m *UDPAdaptor) Write(b []byte) (int, error) { addr, err := net.ResolveUDPAddr("udp", m.Port()) if err != nil { return 0, err } return m.sock.WriteTo(b, addr) } ================================================ FILE: platforms/mavlink/mavlink_udp_adaptor_test.go ================================================ package mavlink import ( "bytes" "errors" "net" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" mavlink "gobot.io/x/gobot/v2/platforms/mavlink/common" ) var _ gobot.Adaptor = (*UDPAdaptor)(nil) type MockUDPConnection struct { TestClose func() error TestReadFromUDP func([]byte) (int, *net.UDPAddr, error) TestWriteTo func([]byte, net.Addr) (int, error) } func (m *MockUDPConnection) Close() error { return m.TestClose() } func (m *MockUDPConnection) ReadFromUDP(b []byte) (int, *net.UDPAddr, error) { return m.TestReadFromUDP(b) } func (m *MockUDPConnection) WriteTo(b []byte, a net.Addr) (int, error) { return m.TestWriteTo(b, a) } func NewMockUDPConnection() *MockUDPConnection { return &MockUDPConnection{ TestClose: func() error { return nil }, TestReadFromUDP: func([]byte) (int, *net.UDPAddr, error) { return 0, nil, nil }, TestWriteTo: func([]byte, net.Addr) (int, error) { return 0, nil }, } } func initTestMavlinkUDPAdaptor() *UDPAdaptor { m := NewUDPAdaptor(":14550") return m } func TestMavlinkUDPAdaptor(t *testing.T) { a := initTestMavlinkUDPAdaptor() assert.Equal(t, ":14550", a.Port()) } func TestMavlinkUDPAdaptorName(t *testing.T) { a := initTestMavlinkUDPAdaptor() assert.True(t, strings.HasPrefix(a.Name(), "Mavlink")) a.SetName("NewName") assert.Equal(t, "NewName", a.Name()) } func TestMavlinkUDPAdaptorConnectAndFinalize(t *testing.T) { a := initTestMavlinkUDPAdaptor() require.NoError(t, a.Connect()) require.NoError(t, a.Finalize()) } func TestMavlinkUDPAdaptorWrite(t *testing.T) { a := initTestMavlinkUDPAdaptor() _ = a.Connect() defer func() { _ = a.Finalize() }() m := NewMockUDPConnection() m.TestWriteTo = func([]byte, net.Addr) (int, error) { return 3, nil } a.sock = m i, err := a.Write([]byte{0x01, 0x02, 0x03}) assert.Equal(t, 3, i) require.NoError(t, err) } func TestMavlinkReadMAVLinkReadDefaultPacket(t *testing.T) { a := initTestMavlinkUDPAdaptor() _ = a.Connect() defer func() { _ = a.Finalize() }() m := NewMockUDPConnection() m.TestReadFromUDP = func(b []byte) (int, *net.UDPAddr, error) { buf := new(bytes.Buffer) buf.Write([]byte{mavlink.MAVLINK_10_STX, 0x02, 0x03}) copy(b, buf.Bytes()) return buf.Len(), nil, nil } a.sock = m p, _ := a.ReadMAVLinkPacket() assert.Equal(t, uint8(254), p.Protocol) } func TestMavlinkReadMAVLinkPacketReadError(t *testing.T) { a := initTestMavlinkUDPAdaptor() _ = a.Connect() defer func() { _ = a.Finalize() }() m := NewMockUDPConnection() i := 0 m.TestReadFromUDP = func(b []byte) (int, *net.UDPAddr, error) { switch i { case 0: i = 1 return 1, nil, nil case 1: i = 2 buf := new(bytes.Buffer) buf.Write([]byte{0x01, 0x02, 0x03}) copy(b, buf.Bytes()) return buf.Len(), nil, nil case 2: i = 3 buf := new(bytes.Buffer) buf.Write([]byte{mavlink.MAVLINK_10_STX, 255}) copy(b, buf.Bytes()) return buf.Len(), nil, nil } return 0, nil, errors.New("read error") } a.sock = m _, err := a.ReadMAVLinkPacket() require.ErrorContains(t, err, "read error") } ================================================ FILE: platforms/megapi/README.md ================================================ # MegaPi The [MegaPi](http://learn.makeblock.com/en/megapi/) is a motor controller by MakeBlock that is compatible with the Raspberry Pi. The code is based on a python implementation that can be found [here](https://github.com/Makeblock-official/PythonForMegaPi). ## How to Install Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) ## How to Use ```go package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/serial/megapi" "gobot.io/x/gobot/v2/platforms/serialport" ) func main() { // use "/dev/ttyUSB0" if connecting with USB cable // use "/dev/ttyAMA0" on devices older than Raspberry Pi 3 Model B adaptor := serialport.NewAdaptor("/dev/ttyS0", serialport.WithName("MegaPi")) motor := megapi.NewMotorDriver(adaptor, 1) work := func() { speed := int16(0) fadeAmount := int16(30) gobot.Every(100*time.Millisecond, func() { motor.Speed(speed) speed = speed + fadeAmount if speed == 0 || speed == 300 { fadeAmount = -fadeAmount } }) } robot := gobot.NewRobot("megaPiBot", []gobot.Connection{adaptor}, []gobot.Device{motor}, work, ) if err := robot.Start(); err != nil { panic(err) } } ``` ================================================ FILE: platforms/megapi/doc.go ================================================ /* Package megapi provides the Gobot adaptor for MegaPi. For more information refer to the README: https://github.com/hybridgroup/gobot/blob/release/platforms/megapi/README.md */ package megapi // import "gobot.io/x/gobot/v2/platforms/megapi" ================================================ FILE: platforms/microbit/LICENSE ================================================ Copyright (c) 2014-2018 The Hybrid Group Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: platforms/microbit/README.md ================================================ # Microbit The [Microbit](http://microbit.org/) is a tiny computer with built-in Bluetooth LE aka Bluetooth 4.0. ## How to Install Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) You must install the Microbit firmware from [@sandeepmistry] located at [https://github.com/sandeepmistry/node-bbc-microbit](https://github.com/sandeepmistry/node-bbc-microbit) to use the Microbit with Gobot. This firmware is based on the micro:bit template, but with a few changes. If you have the [Gort](https://gort.io) command line tool installed, you can install the firmware using the following commands: ```sh gort microbit download gort microbit install /media/mysystem/MICROBIT ``` Substitute the proper location to your Microbit for `/media/mysystem/MICROBIT` in the previous command. Once the firmware is installed, make sure your rotate your Microbit in a circle to calibrate the magnetometer before your try to connect to it using Gobot, or it will not respond. You can also follow the firmware installation instructions at [https://github.com/sandeepmistry/node-bbc-microbit#flashing-microbit-firmware](https://github.com/sandeepmistry/node-bbc-microbit#flashing-microbit-firmware). The source code for the firmware is located at [https://github.com/sandeepmistry/node-bbc-microbit-firmware](https://github.com/sandeepmistry/node-bbc-microbit-firmware) however you do not need this source code to install the firmware using the installation instructions. ## How to Use The Gobot package for the Microbit includes several [different drivers](https://github.com/hybridgroup/gobot/blob/release/drivers/ble/README.md). The platform itself is represented by the generic Bluetooth LE [Client adaptor](https://github.com/hybridgroup/gobot/blob/release/platforms/bleclient/ble_client_adaptor.go), see examples below. The following example uses the LEDDriver: ```go package main import ( "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/bleclient" "gobot.io/x/gobot/v2/drivers/ble/microbit" ) func main() { bleAdaptor := bleclient.NewAdaptor(os.Args[1]) ubit := microbit.NewLEDDriver(bleAdaptor) work := func() { if err := ubit.Blank(); err != nil { fmt.Println(err) } gobot.After(1*time.Second, func() { ubit.WriteText("Hello") }) gobot.After(7*time.Second, func() { ubit.Smile() }) } robot := gobot.NewRobot("blinkBot", []gobot.Connection{bleAdaptor}, []gobot.Device{ubit}, work, ) if err := robot.Start(); err != nil { panic(err) } } ``` ### Using Microbit with GPIO and AIO Drivers The IOPinDriver is a special kind of Driver. It supports the DigitalReader, DigitalWriter, and AnalogReader interfaces. This means you can use it with any gpio or aio Driver. In this example, we are using the normal `gpio.ButtonDriver` and `gpio.LedDriver`: ```go package main import ( "os" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/bleclient" "gobot.io/x/gobot/v2/drivers/ble/microbit" ) func main() { bleAdaptor := bleclient.NewAdaptor(os.Args[1]) ubit := microbit.NewIOPinDriver(bleAdaptor) button := gpio.NewButtonDriver(ubit, "0") led := gpio.NewLedDriver(ubit, "1") work := func() { _ = button.On(gpio.ButtonPush, func(data interface{}) { if err := led.On(); err != nil { fmt.Println(err) } }) _ = button.On(gpio.ButtonRelease, func(data interface{}) { if err := led.Off(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("buttonBot", []gobot.Connection{bleAdaptor}, []gobot.Device{ubit, button, led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ``` ## How to Connect The Microbit is a Bluetooth LE device. You need to know the BLE ID of the Microbit that you want to connect to. ### OSX If you connect by name, then you do not need to worry about the Bluetooth LE ID. However, if you want to connect by ID, OS X uses its own Bluetooth ID system which is different from the IDs used on Linux. The code calls thru the XPC interfaces provided by OSX, so as a result does not need to run under sudo. For example: `go run examples/microbit_led.go "BBC micro:bit"` OSX uses its own Bluetooth ID system which is different from the IDs used on Linux. The code calls thru the XPC interfaces provided by OSX, so as a result does not need to run under sudo. ### Ubuntu On Linux the BLE code will need to run as a root user account. The easiest way to accomplish this is probably to use `go build` to build your program, and then to run the requesting executable using `sudo`. For example: ```sh go build examples/microbit_led.go sudo ./microbit_led "BBC micro:bit" ``` ### Windows Hopefully coming soon... ================================================ FILE: platforms/microbit/doc.go ================================================ /* Package microbit contains the Gobot drivers for the Microbit. For more information refer to the microbit README: https://github.com/hybridgroup/gobot/blob/release/drivers/ble/microbit/README.md */ package microbit // import "gobot.io/x/gobot/v2/drivers/ble/microbit" ================================================ FILE: platforms/mqtt/LICENSE ================================================ Copyright (c) 2013-2018 The Hybrid Group Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: platforms/mqtt/README.md ================================================ # MQTT MQTT is an Internet of Things connectivity protocol featuring a lightweight publish/subscribe messaging transport. It is useful for its small code footprint and minimal network bandwidth usage. This repository contains the Gobot adaptor/driver to connect to MQTT servers. It uses the Paho MQTT Golang client package () created and maintained by the Eclipse Foundation () thank you! For more info about the MQTT machine to machine messaging standard, go to . ## How to Install Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) ## How to Use Before running the example, make sure you have an MQTT message broker running somewhere you can connect to ```go package main import ( "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/mqtt" "fmt" "time" ) func main() { mqttAdaptor := mqtt.NewAdaptor("tcp://0.0.0.0:1883", "pinger") work := func() { _ = mqttAdaptor.On("hello", func(msg mqtt.Message) { fmt.Println(msg) }) _ = mqttAdaptor.On("hola", func(msg mqtt.Message) { fmt.Println(msg) }) data := []byte("o") gobot.Every(1*time.Second, func() { mqttAdaptor.Publish("hello", data) }) gobot.Every(5*time.Second, func() { mqttAdaptor.Publish("hola", data) }) } robot := gobot.NewRobot("mqttBot", []gobot.Connection{mqttAdaptor}, work, ) if err := robot.Start(); err != nil { panic(err) } } ``` ## Supported Features * Publish messages * Respond to incoming message events ## License Copyright (c) 2013-2018 The Hybrid Group. Licensed under the Apache 2.0 license. ================================================ FILE: platforms/mqtt/doc.go ================================================ /* Package mqtt provides Gobot adaptor for the mqtt message service. Installing: Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) For further information refer to mqtt README: https://github.com/hybridgroup/gobot/blob/release/platforms/mqtt/README.md */ package mqtt // import "gobot.io/x/gobot/v2/platforms/mqtt" ================================================ FILE: platforms/mqtt/mqtt_adaptor.go ================================================ package mqtt import ( "crypto/tls" "crypto/x509" "fmt" "os" paho "github.com/eclipse/paho.mqtt.golang" "gobot.io/x/gobot/v2" ) // ErrNilClient is returned when a client action can't be taken because the struct has no client var ErrNilClient = fmt.Errorf("no MQTT client available") // Message is a message received from the broker. type Message paho.Message // Adaptor is the Gobot Adaptor for MQTT type Adaptor struct { name string Host string clientID string username string password string useSSL bool serverCert string clientCert string clientKey string autoReconnect bool cleanSession bool client paho.Client qos int } // NewAdaptor creates a new mqtt adaptor with specified host and client id func NewAdaptor(host string, clientID string) *Adaptor { return &Adaptor{ name: gobot.DefaultName("MQTT"), Host: host, autoReconnect: false, cleanSession: true, useSSL: false, clientID: clientID, } } // NewAdaptorWithAuth creates a new mqtt adaptor with specified host, client id, username, and password. func NewAdaptorWithAuth(host, clientID, username, password string) *Adaptor { return &Adaptor{ name: "MQTT", Host: host, autoReconnect: false, cleanSession: true, useSSL: false, clientID: clientID, username: username, password: password, } } // Name returns the MQTT adaptors name func (a *Adaptor) Name() string { return a.name } // SetName sets the MQTT adaptors name func (a *Adaptor) SetName(n string) { a.name = n } // Port returns the Host name func (a *Adaptor) Port() string { return a.Host } // AutoReconnect returns the MQTT AutoReconnect setting func (a *Adaptor) AutoReconnect() bool { return a.autoReconnect } // SetAutoReconnect sets the MQTT AutoReconnect setting func (a *Adaptor) SetAutoReconnect(val bool) { a.autoReconnect = val } // CleanSession returns the MQTT CleanSession setting func (a *Adaptor) CleanSession() bool { return a.cleanSession } // SetCleanSession sets the MQTT CleanSession setting. Should be false if reconnect is enabled. // Otherwise all subscriptions will be lost func (a *Adaptor) SetCleanSession(val bool) { a.cleanSession = val } // UseSSL returns the MQTT server SSL preference func (a *Adaptor) UseSSL() bool { return a.useSSL } // SetUseSSL sets the MQTT server SSL preference func (a *Adaptor) SetUseSSL(val bool) { a.useSSL = val } // ServerCert returns the MQTT server SSL cert file func (a *Adaptor) ServerCert() string { return a.serverCert } // SetQoS sets the QoS value passed into the MTT client on Publish/Subscribe events func (a *Adaptor) SetQoS(qos int) { a.qos = qos } // SetServerCert sets the MQTT server SSL cert file func (a *Adaptor) SetServerCert(val string) { a.serverCert = val } // ClientCert returns the MQTT client SSL cert file func (a *Adaptor) ClientCert() string { return a.clientCert } // SetClientCert sets the MQTT client SSL cert file func (a *Adaptor) SetClientCert(val string) { a.clientCert = val } // ClientKey returns the MQTT client SSL key file func (a *Adaptor) ClientKey() string { return a.clientKey } // SetClientKey sets the MQTT client SSL key file func (a *Adaptor) SetClientKey(val string) { a.clientKey = val } // Connect returns true if connection to mqtt is established func (a *Adaptor) Connect() error { a.client = paho.NewClient(a.createClientOptions()) if token := a.client.Connect(); token.Wait() && token.Error() != nil { return token.Error() } return nil } // Disconnect returns true if connection to mqtt is closed func (a *Adaptor) Disconnect() error { if a.client != nil { a.client.Disconnect(500) } return nil } // Finalize returns true if connection to mqtt is finalized successfully func (a *Adaptor) Finalize() error { return a.Disconnect() } // Publish a message under a specific topic func (a *Adaptor) Publish(topic string, message []byte) bool { _, err := a.PublishWithQOS(topic, a.qos, message) return err == nil } // PublishAndRetain publishes a message under a specific topic with retain flag func (a *Adaptor) PublishAndRetain(topic string, message []byte) bool { if a.client == nil { return false } a.client.Publish(topic, byte(a.qos), true, message) return true } // PublishWithQOS allows per-publish QOS values to be set and returns a paho.Token func (a *Adaptor) PublishWithQOS(topic string, qos int, message []byte) (paho.Token, error) { if a.client == nil { return nil, ErrNilClient } token := a.client.Publish(topic, byte(qos), false, message) return token, nil } // OnWithQOS allows per-subscribe QOS values to be set and returns a paho.Token func (a *Adaptor) OnWithQOS(event string, qos int, f func(msg Message)) (paho.Token, error) { if a.client == nil { return nil, ErrNilClient } token := a.client.Subscribe(event, byte(qos), func(client paho.Client, msg paho.Message) { f(msg) }) return token, nil } // On subscribes to a topic, and then calls the message handler function when data is received func (a *Adaptor) On(event string, f func(msg Message)) bool { _, err := a.OnWithQOS(event, a.qos, f) return err == nil } func (a *Adaptor) createClientOptions() *paho.ClientOptions { opts := paho.NewClientOptions() opts.AddBroker(a.Host) opts.SetClientID(a.clientID) if a.username != "" && a.password != "" { opts.SetPassword(a.password) opts.SetUsername(a.username) } opts.AutoReconnect = a.autoReconnect opts.CleanSession = a.cleanSession if a.UseSSL() { opts.SetTLSConfig(a.newTLSConfig()) } return opts } // newTLSConfig sets the TLS config in the case that we are using // an MQTT broker with TLS func (a *Adaptor) newTLSConfig() *tls.Config { // Import server certificate var certpool *x509.CertPool if len(a.ServerCert()) > 0 { certpool = x509.NewCertPool() pemCerts, err := os.ReadFile(a.ServerCert()) if err == nil { certpool.AppendCertsFromPEM(pemCerts) } } // Import client certificate/key pair var certs []tls.Certificate if len(a.ClientCert()) > 0 && len(a.ClientKey()) > 0 { cert, err := tls.LoadX509KeyPair(a.ClientCert(), a.ClientKey()) if err != nil { // TODO: proper error handling panic(err) } certs = append(certs, cert) } // Create tls.Config with desired tls properties return &tls.Config{ // RootCAs = certs used to verify server cert. RootCAs: certpool, // ClientAuth = whether to request cert from server. // Since the server is set up for SSL, this happens // anyways. ClientAuth: tls.NoClientCert, // ClientCAs = certs used to validate client cert. ClientCAs: nil, // InsecureSkipVerify = verify that cert contents // match server. IP matches what is in cert etc. InsecureSkipVerify: false, // Certificates = list of certs client sends to server. Certificates: certs, // MinVersion contains the minimum TLS version that is acceptable. // TLS 1.2 is currently used as the minimum when acting as a client. MinVersion: tls.VersionTLS12, } } ================================================ FILE: platforms/mqtt/mqtt_adaptor_test.go ================================================ package mqtt import ( "fmt" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) var _ gobot.Adaptor = (*Adaptor)(nil) func initTestMqttAdaptor() *Adaptor { return NewAdaptor("tcp://localhost:1883", "client") } func TestMqttAdaptorName(t *testing.T) { a := initTestMqttAdaptor() assert.True(t, strings.HasPrefix(a.Name(), "MQTT")) a.SetName("NewName") assert.Equal(t, "NewName", a.Name()) } func TestMqttAdaptorPort(t *testing.T) { a := initTestMqttAdaptor() assert.Equal(t, "tcp://localhost:1883", a.Port()) } func TestMqttAdaptorAutoReconnect(t *testing.T) { a := initTestMqttAdaptor() assert.False(t, a.AutoReconnect()) a.SetAutoReconnect(true) assert.True(t, a.AutoReconnect()) } func TestMqttAdaptorCleanSession(t *testing.T) { a := initTestMqttAdaptor() assert.True(t, a.CleanSession()) a.SetCleanSession(false) assert.False(t, a.CleanSession()) } func TestMqttAdaptorUseSSL(t *testing.T) { a := initTestMqttAdaptor() assert.False(t, a.UseSSL()) a.SetUseSSL(true) assert.True(t, a.UseSSL()) } func TestMqttAdaptorUseServerCert(t *testing.T) { a := initTestMqttAdaptor() assert.Empty(t, a.ServerCert()) a.SetServerCert("/path/to/server.cert") assert.Equal(t, "/path/to/server.cert", a.ServerCert()) } func TestMqttAdaptorUseClientCert(t *testing.T) { a := initTestMqttAdaptor() assert.Empty(t, a.ClientCert()) a.SetClientCert("/path/to/client.cert") assert.Equal(t, "/path/to/client.cert", a.ClientCert()) } func TestMqttAdaptorUseClientKey(t *testing.T) { a := initTestMqttAdaptor() assert.Empty(t, a.ClientKey()) a.SetClientKey("/path/to/client.key") assert.Equal(t, "/path/to/client.key", a.ClientKey()) } func TestMqttAdaptorConnectError(t *testing.T) { a := NewAdaptor("tcp://localhost:1884", "client") err := a.Connect() require.ErrorContains(t, err, "connection refused") } func TestMqttAdaptorConnectSSLError(t *testing.T) { a := NewAdaptor("tcp://localhost:1884", "client") a.SetUseSSL(true) err := a.Connect() require.ErrorContains(t, err, "connection refused") } func TestMqttAdaptorConnectWithAuthError(t *testing.T) { a := NewAdaptorWithAuth("xyz://localhost:1883", "client", "user", "pass") require.ErrorContains(t, a.Connect(), "network Error : unknown protocol") } func TestMqttAdaptorFinalize(t *testing.T) { a := initTestMqttAdaptor() require.NoError(t, a.Finalize()) } func TestMqttAdaptorCannotPublishUnlessConnected(t *testing.T) { a := initTestMqttAdaptor() data := []byte("o") assert.False(t, a.Publish("test", data)) } func TestMqttAdaptorPublishWhenConnected(t *testing.T) { a := initTestMqttAdaptor() _ = a.Connect() data := []byte("o") assert.True(t, a.Publish("test", data)) } func TestMqttAdaptorCannotOnUnlessConnected(t *testing.T) { a := initTestMqttAdaptor() assert.False(t, a.On("hola", func(msg Message) { fmt.Println("hola") })) } func TestMqttAdaptorOnWhenConnected(t *testing.T) { a := initTestMqttAdaptor() _ = a.Connect() assert.True(t, a.On("hola", func(msg Message) { fmt.Println("hola") })) } func TestMqttAdaptorQoS(t *testing.T) { a := initTestMqttAdaptor() a.SetQoS(1) assert.Equal(t, 1, a.qos) } ================================================ FILE: platforms/mqtt/mqtt_driver.go ================================================ package mqtt import "gobot.io/x/gobot/v2" const ( // Data event when data is available for Driver Data = "data" // Error event when error occurs in Driver Error = "error" ) // Driver for mqtt type Driver struct { gobot.Eventer gobot.Commander name string topic string connection gobot.Connection } // NewDriver returns a new Gobot MQTT Driver func NewDriver(a *Adaptor, topic string) *Driver { m := &Driver{ name: gobot.DefaultName("MQTT"), topic: topic, connection: a, Eventer: gobot.NewEventer(), Commander: gobot.NewCommander(), } m.AddEvent(Data) m.AddEvent(Error) return m } // Name returns name for the Driver func (m *Driver) Name() string { return m.name } // Name sets name for the Driver func (m *Driver) SetName(name string) { m.name = name } // Connection returns Connections used by the Driver func (m *Driver) Connection() gobot.Connection { return m.connection } func (m *Driver) adaptor() *Adaptor { //nolint:forcetypeassert // ok here return m.Connection().(*Adaptor) } // Start starts the Driver func (m *Driver) Start() error { return nil } // Halt halts the Driver func (m *Driver) Halt() error { return nil } // Topic returns the current topic for the Driver func (m *Driver) Topic() string { return m.topic } // SetTopic sets the current topic for the Driver func (m *Driver) SetTopic(topic string) { m.topic = topic } // Publish a message to the current device topic func (m *Driver) Publish(data interface{}) bool { //nolint:forcetypeassert // ok here message := data.([]byte) return m.adaptor().Publish(m.topic, message) } // On subscribes to data updates for the current device topic, // and then calls the message handler function when data is received func (m *Driver) On(n string, f func(msg interface{})) error { // TODO: also be able to subscribe to Error updates f1 := func(msg Message) { f(msg) } m.adaptor().On(m.topic, f1) return nil } ================================================ FILE: platforms/mqtt/mqtt_driver_test.go ================================================ package mqtt import ( "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) var _ gobot.Driver = (*Driver)(nil) func TestMqttDriver(t *testing.T) { d := NewDriver(initTestMqttAdaptor(), "/test/topic") assert.True(t, strings.HasPrefix(d.Name(), "MQTT")) assert.True(t, strings.HasPrefix(d.Connection().Name(), "MQTT")) require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestMqttDriverName(t *testing.T) { d := NewDriver(initTestMqttAdaptor(), "/test/topic") assert.True(t, strings.HasPrefix(d.Name(), "MQTT")) d.SetName("NewName") assert.Equal(t, "NewName", d.Name()) } func TestMqttDriverTopic(t *testing.T) { d := NewDriver(initTestMqttAdaptor(), "/test/topic") assert.Equal(t, "/test/topic", d.Topic()) d.SetTopic("/test/newtopic") assert.Equal(t, "/test/newtopic", d.Topic()) } func TestMqttDriverPublish(t *testing.T) { a := initTestMqttAdaptor() d := NewDriver(a, "/test/topic") _ = a.Connect() _ = d.Start() defer func() { _ = d.Halt() }() assert.True(t, d.Publish([]byte{0x01, 0x02, 0x03})) } func TestMqttDriverPublishError(t *testing.T) { a := initTestMqttAdaptor() d := NewDriver(a, "/test/topic") _ = d.Start() defer func() { _ = d.Halt() }() assert.False(t, d.Publish([]byte{0x01, 0x02, 0x03})) } ================================================ FILE: platforms/nats/README.md ================================================ # NATS NATS is a lightweight messaging protocol perfect for your IoT/Robotics projects. It operates over TCP, offers a great number of features but an incredibly simple Pub Sub style model of communicating broadcast messages. NATS is blazingly fast as it is written in Go. This repository contains the Gobot adaptor/drivers to connect to NATS servers. It uses the NATS Go Client available at . The NATS project is a project part of the [CNCF](https://www.cncf.io/). Find more information on setting up a NATS server and its capability at . The NATS messaging protocol () is really easy to work with and can be practiced by setting up a NATS server using Go or Docker. For information on setting up a server using the source code, visit . For information on the Docker image up on Docker Hub, see . Getting the server set up is very easy. The server itself is Golang, can be built for different architectures and installs in a small footprint. This is an excellent way to get communications going between your IoT and Robotics projects. ## How to Install Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) ## How to Use Before running the example, make sure you have an NATS server running somewhere you can connect to (for demo purposes you could also use the public endpoint `demo.nats.io:4222`). ```go package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/nats" ) func main() { natsAdaptor := nats.NewAdaptor("nats://localhost:4222", 1234) work := func() { natsAdaptor.On("hello", func(msg nats.Message) { fmt.Printf("[Received on %q] %s\n", msg.Subject, string(msg.Data)) }) natsAdaptor.On("hola", func(msg nats.Message) { fmt.Printf("[Received on %q] %s\n", msg.Subject, string(msg.Data)) }) data := []byte("Hello Gobot!") gobot.Every(1*time.Second, func() { natsAdaptor.Publish("hello", data) }) gobot.Every(5*time.Second, func() { natsAdaptor.Publish("hola", data) }) } robot := gobot.NewRobot("natsBot", []gobot.Connection{natsAdaptor}, work, ) if err := robot.Start(); err != nil { panic(err) } } ``` To run with TLS enabled, set the URL scheme prefix to `tls://`. Make sure the NATS server has TLS enabled and use the NATS option parameters to pass in the TLS settings to the adaptor. Refer to the [github.com/nats-io/go-nats](https://github.com/nats-io/go-nats) README for more TLS option parameters. ```go package main import ( "fmt" "time" natsio "github.com/nats-io/go-nats" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/nats" ) func main() { natsAdaptor := nats.NewAdaptor("tls://localhost:4222", 1234, natsio.RootCAs("certs/ca.pem")) work := func() { natsAdaptor.On("hello", func(msg nats.Message) { fmt.Printf("[Received on %q] %s\n", msg.Subject, string(msg.Data)) }) natsAdaptor.On("hola", func(msg nats.Message) { fmt.Printf("[Received on %q] %s\n", msg.Subject, string(msg.Data)) }) data := []byte("Hello Gobot!") gobot.Every(1*time.Second, func() { natsAdaptor.Publish("hello", data) }) gobot.Every(5*time.Second, func() { natsAdaptor.Publish("hola", data) }) } robot := gobot.NewRobot("natsBot", []gobot.Connection{natsAdaptor}, work, ) if err := robot.Start(); err != nil { panic(err) } } ``` ### Supported Features * Publish messages * Respond to incoming message events * Support for Username/password authentication * Support for NATS adaptor options to support TLS ### Upcoming Features * Encoded messages (JSON) * Exposing more NATS Features (tls) * Simplified tests ## License Copyright (c) 2013-2018 The Hybrid Group. Licensed under the Apache 2.0 license. ================================================ FILE: platforms/nats/doc.go ================================================ /* Package nats provides Gobot adaptor for the nats message service. Installing: Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) For further information refer to nats README: https://github.com/hybridgroup/gobot/blob/release/platforms/nats/README.md */ package nats // import "gobot.io/x/gobot/v2/platforms/nats" ================================================ FILE: platforms/nats/nats_adaptor.go ================================================ package nats import ( "log" "net/url" "strings" "github.com/nats-io/nats.go" "gobot.io/x/gobot/v2" ) // Adaptor is a configuration struct for interacting with a NATS server. // Name is a logical name for the adaptor/nats server connection. // Host is in the form "localhost:4222" which is the hostname/ip and port of the nats server. // ClientID is a unique identifier integer that specifies the identity of the client. type Adaptor struct { name string Host string clientID int username string password string client *nats.Conn connect func() (*nats.Conn, error) } // Message is a message received from the server. type Message *nats.Msg // NewAdaptor populates a new NATS Adaptor. func NewAdaptor(host string, clientID int, options ...nats.Option) *Adaptor { hosts, err := processHostString(host) return &Adaptor{ name: gobot.DefaultName("NATS"), Host: hosts, clientID: clientID, connect: func() (*nats.Conn, error) { if err != nil { return nil, err } return nats.Connect(hosts, options...) }, } } // NewAdaptorWithAuth populates a NATS Adaptor including username and password. func NewAdaptorWithAuth(host string, clientID int, username string, password string, options ...nats.Option) *Adaptor { hosts, err := processHostString(host) return &Adaptor{ Host: hosts, clientID: clientID, username: username, password: password, connect: func() (*nats.Conn, error) { if err != nil { return nil, err } return nats.Connect(hosts, append(options, nats.UserInfo(username, password))...) }, } } func processHostString(host string) (string, error) { urls := strings.Split(host, ",") for i, s := range urls { s = strings.TrimSpace(s) if !strings.HasPrefix(s, "tls://") && !strings.HasPrefix(s, "nats://") { s = "nats://" + s } u, err := url.Parse(s) if err != nil { return "", err } urls[i] = u.String() } return strings.Join(urls, ","), nil } // Name returns the logical client name. func (a *Adaptor) Name() string { return a.name } // SetName sets the logical client name. func (a *Adaptor) SetName(n string) { a.name = n } // Connect makes a connection to the Nats server. func (a *Adaptor) Connect() error { var err error a.client, err = a.connect() return err } // Disconnect from the nats server. func (a *Adaptor) Disconnect() error { if a.client != nil { a.client.Close() } return nil } // Finalize is simply a helper method for the disconnect. func (a *Adaptor) Finalize() error { return a.Disconnect() } // Publish sends a message with the particular topic to the nats server. func (a *Adaptor) Publish(topic string, message []byte) bool { if a.client == nil { return false } if err := a.client.Publish(topic, message); err != nil { log.Println(err) return false } return true } // On is an event-handler style subscriber to a particular topic (named event). // Supply a handler function to use the bytes returned by the server. func (a *Adaptor) On(event string, f func(msg Message)) bool { if a.client == nil { return false } if _, err := a.client.Subscribe(event, func(msg *nats.Msg) { f(msg) }); err != nil { log.Println(err) return false } return true } ================================================ FILE: platforms/nats/nats_adaptor_test.go ================================================ package nats import ( "fmt" "log" "strings" "testing" "github.com/nats-io/nats.go" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) var _ gobot.Adaptor = (*Adaptor)(nil) func connStub(options ...nats.Option) func() (*nats.Conn, error) { return func() (*nats.Conn, error) { opts := nats.GetDefaultOptions() for _, opt := range options { if err := opt(&opts); err != nil { return nil, err } } c := &nats.Conn{Opts: opts} return c, nil } } func initTestNatsAdaptor() *Adaptor { a := NewAdaptor("localhost:4222", 19999) a.connect = func() (*nats.Conn, error) { c := &nats.Conn{} return c, nil } return a } func initTestNatsAdaptorWithAuth() *Adaptor { a := NewAdaptorWithAuth("localhost:4222", 29999, "user", "pass") a.connect = func() (*nats.Conn, error) { c := &nats.Conn{} return c, nil } return a } func initTestNatsAdaptorTLS(options ...nats.Option) *Adaptor { a := NewAdaptor("tls://localhost:4242", 39999, options...) a.connect = connStub(options...) return a } func TestNatsAdaptorName(t *testing.T) { a := initTestNatsAdaptor() assert.True(t, strings.HasPrefix(a.Name(), "NATS")) a.SetName("NewName") assert.Equal(t, "NewName", a.Name()) } func TestNatsAdaptorReturnsHost(t *testing.T) { a := initTestNatsAdaptor() assert.Equal(t, "nats://localhost:4222", a.Host) } func TestNatsAdaptorWithAuth(t *testing.T) { a := initTestNatsAdaptorWithAuth() assert.Equal(t, "user", a.username) assert.Equal(t, "pass", a.password) } func TestNatsAdapterSetsRootCAs(t *testing.T) { a := initTestNatsAdaptorTLS(nats.RootCAs("test_certs/catest.pem")) assert.Equal(t, "tls://localhost:4242", a.Host) _ = a.Connect() o := a.client.Opts casPool, err := o.RootCAsCB() require.NoError(t, err) assert.NotNil(t, casPool) assert.True(t, o.Secure) } func TestNatsAdapterSetsClientCerts(t *testing.T) { a := initTestNatsAdaptorTLS(nats.ClientCert("test_certs/client-cert.pem", "test_certs/client-key.pem")) assert.Equal(t, "tls://localhost:4242", a.Host) _ = a.Connect() cert, err := a.client.Opts.TLSCertCB() require.NoError(t, err) assert.NotNil(t, cert) assert.NotNil(t, cert.Leaf) assert.True(t, a.client.Opts.Secure) } func TestNatsAdapterSetsClientCertsWithUserInfo(t *testing.T) { a := initTestNatsAdaptorTLS(nats.ClientCert("test_certs/client-cert.pem", "test_certs/client-key.pem"), nats.UserInfo("test", "testwd")) assert.Equal(t, "tls://localhost:4242", a.Host) _ = a.Connect() cert, err := a.client.Opts.TLSCertCB() require.NoError(t, err) assert.NotNil(t, cert) assert.NotNil(t, cert.Leaf) assert.True(t, a.client.Opts.Secure) assert.Equal(t, "test", a.client.Opts.User) assert.Equal(t, "testwd", a.client.Opts.Password) } // TODO: implement this test without requiring actual server connection func TestNatsAdaptorPublishWhenConnected(t *testing.T) { t.Skip("TODO: implement this test without requiring actual server connection") a := initTestNatsAdaptor() _ = a.Connect() data := []byte("o") assert.True(t, a.Publish("test", data)) } // TODO: implement this test without requiring actual server connection func TestNatsAdaptorOnWhenConnected(t *testing.T) { t.Skip("TODO: implement this test without requiring actual server connection") a := initTestNatsAdaptor() _ = a.Connect() assert.True(t, a.On("hola", func(msg Message) { fmt.Println("hola") })) } // TODO: implement this test without requiring actual server connection func TestNatsAdaptorPublishWhenConnectedWithAuth(t *testing.T) { t.Skip("TODO: implement this test without requiring actual server connection") a := NewAdaptorWithAuth("localhost:4222", 49999, "test", "testwd") _ = a.Connect() data := []byte("o") assert.True(t, a.Publish("test", data)) } // TODO: implement this test without requiring actual server connection func TestNatsAdaptorOnWhenConnectedWithAuth(t *testing.T) { t.Skip("TODO: implement this test without requiring actual server connection") log.Println("###not skipped###") a := NewAdaptorWithAuth("localhost:4222", 59999, "test", "testwd") _ = a.Connect() assert.True(t, a.On("hola", func(msg Message) { fmt.Println("hola") })) } func TestNatsAdaptorFailedConnect(t *testing.T) { a := NewAdaptor("localhost:9999", 69999) err := a.Connect() if err != nil && strings.Contains(err.Error(), "cannot assign requested address") { t.Skip("FLAKY: Can not test, because IP or port is in use.") } require.ErrorContains(t, err, "nats: no servers available for connection") } func TestNatsAdaptorFinalize(t *testing.T) { a := NewAdaptor("localhost:9999", 79999) require.NoError(t, a.Finalize()) } func TestNatsAdaptorCannotPublishUnlessConnected(t *testing.T) { a := NewAdaptor("localhost:9999", 89999) data := []byte("o") assert.False(t, a.Publish("test", data)) } func TestNatsAdaptorCannotOnUnlessConnected(t *testing.T) { a := NewAdaptor("localhost:9999", 99999) assert.False(t, a.On("hola", func(msg Message) { fmt.Println("hola") })) } ================================================ FILE: platforms/nats/nats_driver.go ================================================ package nats import "gobot.io/x/gobot/v2" const ( // Data event when data is available for Driver Data = "data" // Error event when error occurs in Driver Error = "error" ) // Driver for NATS type Driver struct { gobot.Eventer gobot.Commander name string topic string connection gobot.Connection } // NewDriver returns a new Gobot NATS Driver func NewDriver(a *Adaptor, topic string) *Driver { m := &Driver{ name: gobot.DefaultName("NATS"), topic: topic, connection: a, Eventer: gobot.NewEventer(), Commander: gobot.NewCommander(), } return m } // Name returns name for the Driver func (m *Driver) Name() string { return m.name } // SetName sets name for the Driver func (m *Driver) SetName(name string) { m.name = name } // Connection returns Connections used by the Driver func (m *Driver) Connection() gobot.Connection { return m.connection } func (m *Driver) adaptor() *Adaptor { //nolint:forcetypeassert // ok here return m.Connection().(*Adaptor) } // Start starts the Driver func (m *Driver) Start() error { return nil } // Halt halts the Driver func (m *Driver) Halt() error { return nil } // Topic returns the current topic for the Driver func (m *Driver) Topic() string { return m.topic } // SetTopic sets the current topic for the Driver func (m *Driver) SetTopic(topic string) { m.topic = topic } // Publish a message to the current device topic func (m *Driver) Publish(data interface{}) bool { //nolint:forcetypeassert // ok here message := data.([]byte) return m.adaptor().Publish(m.topic, message) } // On subscribes to data updates for the current device topic, // and then calls the message handler function when data is received func (m *Driver) On(n string, f func(msg Message)) error { // TODO: also be able to subscribe to Error updates m.adaptor().On(m.topic, f) return nil } ================================================ FILE: platforms/nats/nats_driver_test.go ================================================ package nats import ( "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) var _ gobot.Driver = (*Driver)(nil) func TestNatsDriver(t *testing.T) { d := NewDriver(initTestNatsAdaptor(), "/test/topic") assert.True(t, strings.HasPrefix(d.Name(), "NATS")) assert.True(t, strings.HasPrefix(d.Connection().Name(), "NATS")) assert.NotNil(t, d.adaptor()) require.NoError(t, d.Start()) require.NoError(t, d.Halt()) } func TestNatsDriverName(t *testing.T) { d := NewDriver(initTestNatsAdaptor(), "/test/topic") assert.True(t, strings.HasPrefix(d.Name(), "NATS")) d.SetName("NewName") assert.Equal(t, "NewName", d.Name()) } func TestNatsDriverTopic(t *testing.T) { d := NewDriver(initTestNatsAdaptor(), "/test/topic") d.SetTopic("interestingtopic") assert.Equal(t, "interestingtopic", d.Topic()) } ================================================ FILE: platforms/nats/test_certs/catest-key.pem ================================================ -----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: AES-256-CBC,A22F189537986661D31D1E3E2E4883C9 4M+2g/t6q7FfWY7zA8J4JsIRDy3H0y5X6tKtJMIeqlW6CZV0HFNJiiA35/rL3sP7 c96cSY8olwy3mMjk88NrLmAVLfLRzfnu5PEx3mpgqGbRuzElLsYUikU3bjmfpyJA UHjZav5rrG5un5+ZJ6SDlCMo90WWyGOcTyDHdQ5zkLYMO6aRp5guhYMUBRR8MpJF AC88XiSjD64bYEMHIDB0jB8q6WonKM3nb9HorKShVq5rR1Yfps4NLbN8rq98Cv4M cpbI3Q1cXhum+VOHT0vBB9/oFc0+o3IFNdnjg5ygKU7aHjpBl88QJNFjkT4pdWEE OqrMFxsOb53BkOgkjqRadYYYFYh2MTAeP05Eg4c7SKPTq3d+S2Ti5OLcE4rNlCsE d+thb4xdsAamOJG3XrifVG8/VOiNNCG+jPASUWZ8ZXpshOnb3UXmA6tzR33y0E/R HWki9bpKZbznuTN4J3UrmvkJy2pX+RTwz2KApVrS934aFf4urNgSrNH3sb0Kpidi N3WD5SyEudGJcuRqn+wmbm5yPSafNPyHp8Gevh9+5XWlec9hkYeiSjh4aUwXFql3 T3izp5f+bdupQ3W+G3Yd4+uv30KQJ9ZnIb/LHGn9FtzPG1svuD0vi6RAQuEySGwv Y6fac1qDgfPI62QKlpL1X/BFubSK6P9p+OgX6oHM1FBU4U0GRH8curnsn6xkZ48b Nr0yCrMaU48wLQXp/eyxJDx+rleeDrzDje+PW81//ujq44uLygPnnxTfkmIilu9X RSEEUZ4W4AXgaxndqZS0Elp7QneZLduIEYzQqlsXHfPqUKN3xyGyjgBu42eE4c1l k0yFYzebQBJ2nmT9vMLvwiU0BV5gwKLCb/T1Boql0VZCJhoenLP5Yzi/kw9GTCYX n/Ba1oPvb62vpESIzZqc6yU2RJnXqFi//dvmTi+MWjWK6L4Vf//LDihWDvvW1aU0 1bjBWfwhPy1jv6SSjSjsAfXrBKGY1gJxaqcFBcotxyUUeV1069mM/ShEnNCex+cF nmKhnNbhJ2V9jf0c9Y59voDKf/xuYTsdTzu5svDSv8ox4oCQayrauGEfaypWCIgh hNoHy5+ottQJsKgmGb+VuED1o3/D/U7N4+Ee+6hJbJnbaV58r5SWjIR5pGlGy7VN hemNCJA4SBKwtTs2hUkzvYL3UpcQoSHMIXf7KW2v3EVgj/1HZOZwH5dYA2/pV+Pp JQy+zq/ImbVW54WPji2PaQs/j+fz0v2Hc0JxxEmtBQHWhHhrXzvnFrOMbdZfmPNz 5MThA9U22mDn332WrGopFL6ZLCLEqUqQaVEAc3kiZskbfztDa+TS8SCZP9MYOcMY 85GHK3rDuhUjarhWfUkfUVHt/jAWKVMzs8FVQZxtoUsSlJ+AOXa4JM233RA2h5v+ TLASqIrfMxjAIOrbmKd4CX5xofNWqgYTcdbRpuuOoVZ3Lo7JQas7IO0MnIW44pyu ub3qdbUJ/PomvcCO/ZVuIzwxtbWiciuk943ZEYmjCdVQSadhOEXRegbSxAIVRhF1 CnJnYfs9Bsuler9Hs6H9NI4T97S5N0J8vK317ehNUUL5MFLVjiw2NmteABqvjUnv n7Gb7Epi1yYWCcURc/UI0V+wSf912I1xAfI6P/dkDNQgBz/grA6dBKUWZGfjCDGO FlzfrPbJDxHAj/X5u4Df0YY+uQJQ9Kk9ONtvgCcg5+w9ahokqmB+LY1yHe4eO6m9 ZMxL3L1A5aQ/QDN2areMoMCFMzEF2qIP+seMhQ6tPR7Rfi5WEMg+5JuNtsABXz3t BopJzC33aZLfkQ1alWNGhCEmtCsOO3P6fRGNHvLEcw8eJBX3V2R/Ar3re5nY/h+G xP/C0DR/TYyqM+9StCoLIXR1twN3AvWJU0hsKFejJEvzoL4qMrGDn4csznfc8bAB JIXVikNzaXDHc7hdKaqwe9G9e+TQrIUl4tRyaEKAu64TNVA11E2X5cF8dl9XUpcM 59Zb3RUiw3/oqbG5BKvie7Udmxsil1EnFAEFrPT6TTFB+rswj9iPobX41tLZ6ZV8 yRYrZ/DcGHCvjib1fA4BgeldIVin+92sQbgBlFVnPVWsPsmanzpQHQnb2NXaTtX3 N9DMsnclaED7RMC7J5PgUGLyCqa9bRddsT5O+1xBykoU7J6OhXu4pe3rlNy4yJLd PFBB/JwzlDb9CxO4zN3ZrFUvwB9W/N0hAA+o9jTnTEtxyM7gitFkrGXHJIACfZmM WmoEYhEsqn0To78SGfe5jqp56DKPM7onhNWXUu+ZkRi4xFQXJqvwKjZpXV2oQOcS 8JULyft9AmY7sChoNINlALdGRCXmKqoLg16suN7r6WpJx2peQg7fPsPxcb9/9hEM cmrISL7CoZOX01PyQyxL2KEEYjjef5Licz0ywk8DmUv1ABqtP7Uxha8dSuSq6mtc DVcO+YXS8DDsH5UvrGSsMO2Q+P9Juu8Nx+u2LfEF8ANds0L1mKa+3S8JQU8y28g9 34wHQiSA88m7t841J9pJ7+Nlymac3qRRTIyvu7SIz7dTBjPuAdDf/GPfG42YF9D9 sp0NXLzR1Sp2+4ZWrxZoezt8Sljnhl9olSqtrMrV/Dtco/04RXnepCBmE+JIA5sx s+CxWaDjzc2+CN1BOO9Bi9fGsXSmbcGnQ3+UyJWfIPDENUhAdI7ccLCim6R5MDIL Z7bpXR1zw6eIGdFcSsG0dXspPGARQdsFI6r+OroK7MaUkbHE7qjX93LMqd0a/h87 QNUQZleBNAllrFeKvcCwuzVamJyv5gbgdbibpy7Ue5URUxlyy4RCUHnZXLJ7kOE4 Xu8bCzK6nZJ+AQBadtFDT45RWjtMoexkvjZszVgtZLz0TGWnK0SOf/t8MeJ+FKu8 aob7iYLX1xAt9ztnpcR7unDaBiYmePghc9b8SrVfcQdjUe0TxGsW2kQmu6QYvvQ1 pRGmvxRPk2KUUG2rCNlZDfNscEGiIE6Ff4wLQr9N01zXpWx1w3uURcIlZzFvXKOi UtnHbqI49qnJTz/iVGREd0PqHTu+yVKal4OVpGNLMSV9K+ERVI40gllC5tiHX0A+ dRlXxI+s7vJ9rwtyq32XYZtvKiuqCdsMQyOJ2fNaQ4bz06OxvtV301LXxXv1Kya/ -----END RSA PRIVATE KEY----- ================================================ FILE: platforms/nats/test_certs/catest.pem ================================================ -----BEGIN CERTIFICATE----- MIIGpDCCBIygAwIBAgIJAIBmBEvgiah+MA0GCSqGSIb3DQEBCwUAMIGSMQswCQYD VQQGEwJVUzEPMA0GA1UECBMGSGF3YWlpMREwDwYDVQQHEwhIb25vbHVsdTERMA8G A1UEChMIR29ib3QuaW8xFDASBgNVBAsTC09wZW4gU291cmNlMRIwEAYDVQQDEwls b2NhbGhvc3QxIjAgBgkqhkiG9w0BCQEWE25vd2hlcmVAbm93aGVyZS5jb20wHhcN MTcwMjEzMDEyNzA4WhcNMjIwMjEyMDEyNzA4WjCBkjELMAkGA1UEBhMCVVMxDzAN BgNVBAgTBkhhd2FpaTERMA8GA1UEBxMISG9ub2x1bHUxETAPBgNVBAoTCEdvYm90 LmlvMRQwEgYDVQQLEwtPcGVuIFNvdXJjZTESMBAGA1UEAxMJbG9jYWxob3N0MSIw IAYJKoZIhvcNAQkBFhNub3doZXJlQG5vd2hlcmUuY29tMIICIjANBgkqhkiG9w0B AQEFAAOCAg8AMIICCgKCAgEAv8dYH8TRoSwD0yWHr8A7w+vkK6HmImh/VuC9ZpQm ilIpzKgU2Y9hG3+C1OmqyxVSWHhVRFOHv7TUzR5Q7C2PM7GwYe+QHrheZ8ZByRp0 HLcqo/FVpKg7k/cNwGQYWkQ8W4Qms/hI0F0F3r7gHrlLNJ4MTvZAxpfsfo0Qiuc6 Zdf9ugbpSTMoKtkHqpeOu2xo4ScOot1UqQy7xSzAIK3W6FIVLuXbDW16fViYkwUB pWGjwBqotR4tZg4mp4ehaXhtapHyAk8H6gEQcgPkqw8PDVqi336gbiOMlHvMI2m0 iPwidX96Nd7sHuDERrOsi3LEGGl9uzCqEePAj6k5iuYa4c+0Os7t/w0s2ttCz4Xn ryoKxQsaq313WnT84SsQQu5S8ZFJf2B5A+jC8phZx79KHf0QlLlB+xFYxQj1byjX xiUdCw1fA9ocC+Q/rgL59MbHyEApYU04/aKxhnak/bSBgmqekTQyMvwez9VVQ5qY TFiirEMqc2qZym8nbO38YKyvGGkrY5oOzBNEW4WrUuhoJGvt+Up3/ritEZxMaLLi Icih5zgitzVqTkDMAU6yiVazHwhhWcWx4Owo16Q/jiwgXflFEiKT37w2ysh2SWUq qlSWZV2ltI3UAUQlIEzkjTQS8Duj5ObpeCOr4L4IIKwWfZOpaldwqE3CmGpq3McW 5V8CAwEAAaOB+jCB9zAdBgNVHQ4EFgQUBc1Osxlm7cX8oI/WHdsj2peh9vswgccG A1UdIwSBvzCBvIAUBc1Osxlm7cX8oI/WHdsj2peh9vuhgZikgZUwgZIxCzAJBgNV BAYTAlVTMQ8wDQYDVQQIEwZIYXdhaWkxETAPBgNVBAcTCEhvbm9sdWx1MREwDwYD VQQKEwhHb2JvdC5pbzEUMBIGA1UECxMLT3BlbiBTb3VyY2UxEjAQBgNVBAMTCWxv Y2FsaG9zdDEiMCAGCSqGSIb3DQEJARYTbm93aGVyZUBub3doZXJlLmNvbYIJAIBm BEvgiah+MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIBACEaRC/DZfmB 5X06tKVhudPu4PnYKRIW5t+u2nzEKumqVaQ32oUBdkwLzJ0D4XNp/HJSfhuwJQl6 EYzcYH76At8BZ89lWTH37EDWvdZom3NzKz2TzHpU9oaLEi0gnFdTv1z3wUW/G6w5 pzxqiL3qIivYGGo/JRIEwD93F0uLVjUT+Cqh0zft4yJVbupxfJh8m8sVcy7HzVkb JwqAnAL0lLsOH/BjkVzkdKosTUFxLgb/xYBy1OtsskkE1Mql6INJKHYRNPxuauP4 IJT1hPb7sXl0prV+ufIYXdYZUpILw945Z/FBvazNCjZ9lR6l94mh5NQtGL4/wLZR zGpv1+hqvXaHCL7ayY3r43nmfRyqqhsuOEl5iyxE03j2EWmjxK5Z9Vo+5lliUEIl KzADXdZ19mwYDfo12KTZp/DHioRUHjdUG0944jfC8EoX87yF95JTCvRYT8397qn4 OxeTrSG4rrOtYhQs7/xeDjwrl5JNcXEPIwkWyye6NB5XJvAeEiOAL1+IU1iV6Oyy e4ZHMcpSo22m4EFha8zlYD7CaJHo6JBcSqaLMWFaRY1rWakl12/0fJ68R7OioJ/0 3Y3j24hdtuAAccLMzH3YI7uM/mzJhmBAgUXc5Kt6I81vgds7yBio7zaOeC+2+cOq 5uUwm9dfOMZxnJI+HnXDFVyGgGlANQbb -----END CERTIFICATE----- ================================================ FILE: platforms/nats/test_certs/client-cert.pem ================================================ -----BEGIN CERTIFICATE----- MIIFPjCCAyagAwIBAgIJAMSwPHLUBjPUMA0GCSqGSIb3DQEBCwUAMIGSMQswCQYD VQQGEwJVUzEPMA0GA1UECBMGSGF3YWlpMREwDwYDVQQHEwhIb25vbHVsdTERMA8G A1UEChMIR29ib3QuaW8xFDASBgNVBAsTC09wZW4gU291cmNlMRIwEAYDVQQDEwls b2NhbGhvc3QxIjAgBgkqhkiG9w0BCQEWE25vd2hlcmVAbm93aGVyZS5jb20wHhcN MTcwMjEzMDEzNTI5WhcNMjIwMjEyMDEzNTI5WjARMQ8wDQYDVQQDEwZjbGllbnQw ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/9f5QeY89ILj2LX4j2t3R V8LO7YUMcarLENtpu37lpni43Bfn38PZUX5Mgmt7EufcZ6nTxmdhCUBQWz9bCCwl f7Ukxs8vkpDdxXCSCSzafZsxVtaV21yPT9ACr2uYahTR5q4ChblfMd7u0hpbmcTZ LfXzErds92Dept9k1W8tgSzzvv9qK5Wld5ZeYsiSanUC23Jl2CIy9T0H3AnRko+p Lli/szQX9A11Dbjd/SKQam+ca618sZ9kRQQRNQHVLtKhnlZDITZHjExQqlDTcWGQ vRODJIuxJt2L4Qx0tl2poQ2GT2Zxtt7/uY5Lmbga2OOoxBfbp8ar4n/APt19/r+5 Qape/vgGypTh9CjzMBE8cIDXVik4eVR2mRsCuYyZY8fNO07g2zPZ+Zc9VpYZ5c3L bh6cCV3e5lMcLfZtBgj4Y60GZJIkUcgfZpIG/plZ96TG4CZdV1NzI1dHRP91UFvG bExjn1O3hTXSe174+APGGodHIApbY45m5Jdz+XYNUovaghqour2vvIn9kgglr+OU 8o84xYc6bINanEowRl5uYIL/cidYT83DucM0N8uyV4FNm+/tS7ZW4vCm8WEd5mck 2p7ZC/wrHwZB96tRT5dbNArbtlXN17RfyeGzprTz7VB1yxzzVN9OU0rxGgAc36bC Dxf9jS+nzpqT3X2P9EJYLQIDAQABoxcwFTATBgNVHSUEDDAKBggrBgEFBQcDAjAN BgkqhkiG9w0BAQsFAAOCAgEAlBXFfjb2Od8ijz7K8qkSImDarzEnTav+inm1wukE fe30Ld89iMQnAajLzchYElzDZOuTXQrPmsmCg5DbsSOi4yVaZ3aBa37lZ5Q8W9ck vA9gH9jsSMnhrhceAnbjOtueHlcRW8QXQ2KPcTQGi80dApN5hMjAUiSaaE6c13bN lvIpBS87bhk5UKIH+avuug0l+JK25Onwqkz0hgWDGQceLx0+RE6OLQtN8gtjomWb bql/M6DnqQGZwPLcPj9RqVUexl+Nq8Q3vnEcy9w5AG0YK47QgwxtzsLk/eeql9jU 5a7J5Z23+0u2uqbnrHvTBfl/MG1x+C0AnNgPgdCQbzv0U+qrE8l7IZW7mDF0nNwe BThvkR8PCtdXl0SkWcfEbyeNjIQ0pKxNvt4MOMoI3AJWK1g465oDnf8OMOU55Swy iPhj9gg7JCrb8haYLkH4JAg6Ufdv9JGgdWhoNz52YV1cKv2gDf4NpIYvM8Wm9psY RSSAor11sxvqazRVqjOKYsTV/WlvVpM5G/UlySoCJiyw6H3S79hJiJSHdN6KEp5Z I+WEUYZEWJ+TL9RU8jaS6XJW+Fy159fWTzTG6XDLU/HRTypUFWnvvcuhy1zlIDSR ehuCRVj0mVI91A3lEatKgjng7uK2jfcQRV5cMYspVn2Rdvf3NkZ0Hoxt+JDDYlJf NDc= -----END CERTIFICATE----- ================================================ FILE: platforms/nats/test_certs/client-key.pem ================================================ -----BEGIN RSA PRIVATE KEY----- MIIJKAIBAAKCAgEAv/X+UHmPPSC49i1+I9rd0VfCzu2FDHGqyxDbabt+5aZ4uNwX 59/D2VF+TIJrexLn3Gep08ZnYQlAUFs/WwgsJX+1JMbPL5KQ3cVwkgks2n2bMVbW ldtcj0/QAq9rmGoU0eauAoW5XzHe7tIaW5nE2S318xK3bPdg3qbfZNVvLYEs877/ aiuVpXeWXmLIkmp1AttyZdgiMvU9B9wJ0ZKPqS5Yv7M0F/QNdQ243f0ikGpvnGut fLGfZEUEETUB1S7SoZ5WQyE2R4xMUKpQ03FhkL0TgySLsSbdi+EMdLZdqaENhk9m cbbe/7mOS5m4GtjjqMQX26fGq+J/wD7dff6/uUGqXv74BsqU4fQo8zARPHCA11Yp OHlUdpkbArmMmWPHzTtO4Nsz2fmXPVaWGeXNy24enAld3uZTHC32bQYI+GOtBmSS JFHIH2aSBv6ZWfekxuAmXVdTcyNXR0T/dVBbxmxMY59Tt4U10nte+PgDxhqHRyAK W2OOZuSXc/l2DVKL2oIaqLq9r7yJ/ZIIJa/jlPKPOMWHOmyDWpxKMEZebmCC/3In WE/Nw7nDNDfLsleBTZvv7Uu2VuLwpvFhHeZnJNqe2Qv8Kx8GQferUU+XWzQK27ZV zde0X8nhs6a08+1Qdcsc81TfTlNK8RoAHN+mwg8X/Y0vp86ak919j/RCWC0CAwEA AQKCAgAw+IGDaC95ibKF4v8uCHTUJg5lmcR6czj+CvPeml16GqjriAJ1PemJtDeD LzZaNG2AFdYGV7Qh1ilZFp4oDAKvIlBE7I8IdNyOJwNbzglqR+bihGPD4S1Qxiyr srLBNDbRgYbcz96FgYR86o6c1bKZMRdwhlLS8pz80Bdncuek9TJRkGU6YZoQl1x+ AbdnWs81BmS9xJCc7WE/cwvyMfCCWXd8mCvu/Gy+cty5jQ1XSD/m6LVefTXLb6vk 89/e0c4cOveIsp1VTV5eqcRq3J7mPMYQi68zZ1XXjHcQA0ILtzFrFTBuTBfBp0W8 1Z9ZAgG6GSR4/ek6ClNK6P66WNXx7MXmv4HwdceEQxNSDrZWnpzkgLJyh65SNQSR U6Tza5YYhyOng3y1r4nriCn4Ar1a5DTMTo72Aq+OAr9qRINIYW9yCXjiO1kvvNO7 dS6VsyMW5mvxgefnEHLGEWFSLCUjAOabiIF4xSnPr/t3xXrBGuVvhkIO9Pqp87fA GUjTXEIbRuGRPJqLMpmpCK50BgYPupZmKCrnpHdsyE0yLNzK06Ol7qb3AHn7io40 5ANm00BexDGHE8jtJCTyKeHg9m3o86a544zbmkj92dMtO3MqgRPhVrT0remsLtXe xE3nVv8ikFScwQRWvPYEPNDWIdeVN/s0nzCiOESQ6xGBSwVeYQKCAQEA4Z3mOLIA TDonpeRohTtqxq39LY5hgNfbcR4i5PYeEKya6u6zhOgp89ealGn2lZNYLMyrKjxZ xrScMD+1nbUBHKvnAMi2tKbkOp13D17qXFdCnOvMHP1lxH6h3UVYN8O61C7I5Wdt Gix66Ol/8dWdc57CnfqCtrkwCTiBtJQ3e2MncaAZdUjF/6YM+dfpgaPDX0mmElvg 4Lc4pKHa8aezqw8YXqKVPHWc10kfCAxvyabasnVyQz+UjUUNE/NOtHW+8l52/f50 jizreD3CJcre56YxPy3Mvtw32i92tkYGbvmsO0l3STca3S4+2NshO4ZkJDtT3KYb R2LiJQP8EDVjKQKCAQEA2c/QMwYJj210H0Q7v8qLWg5WVEpfQpVaE0oeIaIWUai1 Iqq0naFmrK9ncFZ88ENOYB36zbeZR4dWcfh7HDwQzoCSYjITCkwiQk20McXx1rtJ iJgb4S8Ri5cWfyX2XXZTf5eGzcB6pBRuITWkIMThYV5aCZgWrCo6JKSaZLeA17vS 0kynGBNVTUiypwyAZz0saTU9OFYOwclD+rhjYuiPH90CnieAnXVGX4Co+UsfHMGo mjBWDMwQHj1lfEoatXGVaVnqP/0Fkrkmb7uabFqFBcDiGZiOaausZFd1sqOysn/c U71L2WrN0PYjSiWQzKlUwJRKG0XVVn+QxmMQSsiRZQKCAQBzW43MLU8zqoR9MOU0 QiYdQfbypRs7iqL8GoGS+jhzJB3tw3DsotxYfkPeYLOg1P6/oUJfTQ5GKDC4Bssw wMy5wTdS0k2A3thRFBQ9OrWv0zoPDA2IQRQYvPq8LWmm0aAkP2ueyBwjxtxtXH57 w1JHPMSbi+vry5JBFLBVCXe40gDn+wkpS7VZOqjl0jzleTs67GhKeMnpfCUtIEjX SHz4GLbIJG8Tw7sW5J9GOT2rKHInzx9GPSsSdFz0d3IlmRKx0BUdV053J4aaK1Gq iykf3nzNpfhLGkRAfgY/ulwtv+ENS0n/mHpW3v9pV9mNGvD3CZKefhvyix+/92KZ UwLJAoIBAAYaGE8VoDbwbgxiMPpShkzjke+SldCbtoZL0URH8jAfddOezKiN2P6F e3ReN+nTOOLgdCJHPngOhpFy0KAd3qqqV2+Az5++Okd5Pc8XKItHe+vjtwQ7+VXb ybmOKrS7l+M/L3ucJNNr7xnnEs4INfgwWH1kUV5JYI+ePOUNbwKcNG/HzfaStBUS ME8VvpMl15Sq9Sga4Rb0uH7Ro5clxLyzyFr96FCA9JPAWvuA60I2+q43JHH/VYRD XBB7Uvw6TmFBL5rTT9CodzcyHkVi088xdCQbbgHv2UiGWrnCdEMj6dw+tV1F7LYp 7xsoqkHRjJpIjTruXeeqczfblp1BuTECggEBAMOB0Kb7IBOXLYJcUof3WzwjbhP3 Iu5aZMkWZUKg1FZG5fJGDZiK9Ha5E0+aSsC8LS17mPVmC2dS4NMVFmkuhkAwXPgi tzbDdaHFiv9ypyoEXgmavWDYg7gppEZcg2PkpcpIOK8rxEhQU1XvQr0RQvyWu1Ju 7/dg/Zazb27jYAtO5uAKV8StB0KoqPlkv6v6KOBNM29rSUtcapgtIRBgQLC1tObR mKRHaaXKF+WzYtmQ5UF0mRccjuH2TIrpGp5Rw8Hyi6Nec7sxSYVQIY2g248SZz17 VJMHxZ7cCMjrpAtvjlay829aYfvVh5ea/NiM1y8tKjxdBvqU9/uxAt123Gc= -----END RSA PRIVATE KEY----- ================================================ FILE: platforms/nats/test_certs/server-cert.pem ================================================ -----BEGIN CERTIFICATE----- MIIFSDCCAzCgAwIBAgIJAMSwPHLUBjPTMA0GCSqGSIb3DQEBCwUAMIGSMQswCQYD VQQGEwJVUzEPMA0GA1UECBMGSGF3YWlpMREwDwYDVQQHEwhIb25vbHVsdTERMA8G A1UEChMIR29ib3QuaW8xFDASBgNVBAsTC09wZW4gU291cmNlMRIwEAYDVQQDEwls b2NhbGhvc3QxIjAgBgkqhkiG9w0BCQEWE25vd2hlcmVAbm93aGVyZS5jb20wHhcN MTcwMjEzMDEzMjEzWhcNMjIwMjEyMDEzMjEzWjAUMRIwEAYDVQQDEwlsb2NhbGhv c3QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCiiEt8zo67qXXRbpb3 1U9CJ4Fb8gMidHxa3SN/0p4+5hyCmRxezaYn45TGsjRJ1su/6IUk2X7pagoVDLOl 0jmjhvn1ALHSPSVsW1l56hK+J7O4/9NPU/1m/q1ofoF1/DyO16L/xIC0WghLKvkC f38eUXiB93yOLZun50g69sLS66UmLLa8xDxtb4lA1cHMkuUxXWyDjv8SKP8eGUDc rvurzNJsGphw3ixVz6tvtbc+/PiHQKtQZTvyTKQemn89fpl4v+FBrrKBAXAHMzLc OZexmprQLzyNAeX+mWhVDrfBHUt/yn9Swbg++mQEB5956HfMaAbEbrUdDnYa/UGE SiU09P+9vCTg8SndMDfzb/Jmdc26HuVsl5vPrhMeNnS61jZDwlA90RYTUuk447sx ZP8MzKtgauPOIgKm2quEBTvMrG3aLUHnOxJe/ylUBV9zz4WvmZk4Wk9F4/BsWMOM Hs0xfctBfbrCvcKIg/j0Q/epskkZO+u0BcjH0YdCi3nHBp9Z5E0s/0XK8buP5tfo 3Gm1WBfXOuH3EIufqI4Gq5BRWLQWJ9mlio+ZrqHT6W3h4LJYp9KSoSGRYkrQiMeG Hlu/JYoaFeY/WFTXuMwx+b25yrhu/nKbzaEIgQBu5B1XMhuZpwt75hOe0zff2OAv dOY44exFlmCfnlI7bkAm0lozIQIDAQABox4wHDAaBgNVHREEEzARgglsb2NhbGhv c3SHBH8AAAEwDQYJKoZIhvcNAQELBQADggIBAFo4AM9rJsbBQOIo9WUrAIc5czZM wZVOd/eWHZVqg4k3A+4p/EtVlIG23JyTbIa5OnMyHoqEIV/yDTdy8KFlZSFRdMAh OCTCh7SpCS/CFBG+dZdYltEvLnxFASh5Bb83MNbbQXMPpBKyTtFNaWef5A0wzSZn R2OdPqckcm+3nhzEJTTGEotsguVxK5NAmZuXrFbncCGnXlnqGGu8RvEADfunv01+ rFe1S62mdKW7CJxQzZmhL8na19AbGYXmnYz7bt5hbNZknzeIgemxwIbJUrzogLjM EccAlaA/8yOfrff/IMhiMUnnvA9SHRgmOZcZ0Ecq0i2MkbQviX7x0cGIwBhIZCMT K2VDi4y3AuEEUhcvwUlY1O8GKZ5Oqs/KG4tunpZZ0sZpfX4tTv5pc/zaoV7a8vEv GFjeqUH6xiqgv+vm6ZzJZLVfvkH8NBdV0O/3VvDLKkapfRMic19W64whgWw5vIx1 jzQ4q/DPe+Cxa2Bz/Vx5DG8B0jedPURvOK8TKrbgEwIdIBxtE2IsJz8DPCytRbXS xaaNFSLBz8HV3cnvGPhl9JrnF7rKWFQlhLIFAJuqrTokgyqS0u51I5NYXGLVueSJ 9wnkn3raomFcmwLDervMCx8i187m9xK/PBd6XLJF1oslYweHuW2CX5Tle0w67zAK rSx8jFD3GheS9WcT -----END CERTIFICATE----- ================================================ FILE: platforms/nats/test_certs/server-key.pem ================================================ -----BEGIN RSA PRIVATE KEY----- MIIJKAIBAAKCAgEAoohLfM6Ou6l10W6W99VPQieBW/IDInR8Wt0jf9KePuYcgpkc Xs2mJ+OUxrI0SdbLv+iFJNl+6WoKFQyzpdI5o4b59QCx0j0lbFtZeeoSviezuP/T T1P9Zv6taH6Bdfw8jtei/8SAtFoISyr5An9/HlF4gfd8ji2bp+dIOvbC0uulJiy2 vMQ8bW+JQNXBzJLlMV1sg47/Eij/HhlA3K77q8zSbBqYcN4sVc+rb7W3Pvz4h0Cr UGU78kykHpp/PX6ZeL/hQa6ygQFwBzMy3DmXsZqa0C88jQHl/ploVQ63wR1Lf8p/ UsG4PvpkBAefeeh3zGgGxG61HQ52Gv1BhEolNPT/vbwk4PEp3TA382/yZnXNuh7l bJebz64THjZ0utY2Q8JQPdEWE1LpOOO7MWT/DMyrYGrjziICptqrhAU7zKxt2i1B 5zsSXv8pVAVfc8+Fr5mZOFpPRePwbFjDjB7NMX3LQX26wr3CiIP49EP3qbJJGTvr tAXIx9GHQot5xwafWeRNLP9FyvG7j+bX6NxptVgX1zrh9xCLn6iOBquQUVi0FifZ pYqPma6h0+lt4eCyWKfSkqEhkWJK0IjHhh5bvyWKGhXmP1hU17jMMfm9ucq4bv5y m82hCIEAbuQdVzIbmacLe+YTntM339jgL3TmOOHsRZZgn55SO25AJtJaMyECAwEA AQKCAgADtcjDWJO5hOzDkxqvHZdpky1IxAV+S9pq2JFu4YfrN6V+9a/IGjmov3Et 9/NpnBWak9w2MyDKgzknsdqH9nyKVxJtnU5x1iN8jblFJyq2XIGlv3E7ZldqenXK 5NhfsRpQyGtYG0w00blOvfRhMjfcoU926AdX14KuGoFzlx5rYiWq8WpadMBMXzdq 23ZJDTFeJxvLBQCdkYIBVeI9J2FnUo2bGiBQs0Gf09W9/w/nyC6EJ93BQA5WQZmd eTleVf163CZwMWSxvS6pe2m1zTrBOx49klZ3gYuWfDn9dxCKv/hxOlYdtX5XMbAG x4XEaqIRcG53HW/U8feQNifAtVCUE5LL8A/Xc1WbTPQCdGGUUlX/P7feriY709GV iLBWmz7iOx08QxMRcmfPEb+OZnssEo9rRw1YXn5Mv7F93XbFrilRFRBv5t4KyLCz Gi4jbfvjGzz8ElguNGYWMxZjiyNYNKjOFCGt616M5CV6aShSzdLR/tD4+mgNfJnm RSFm0pwi8PQNg2OQbp9lhZ5FzHPQBQwUi0r6RodSHhQT5L4zPwvGZpPsLOIERGMe rPRtI2VU0sliSqBuzE7d9qDJJoAiQkUxsQVtQVJuNVrNrxtCkOKdDQcrJlL4G5tz f/JcUjiwSMkrAXGtLX8yDXh5GFJFVa8MuLiKSKHLz0OucWxYgQKCAQEA0V6q8rvj k78rrNR4/mcjXQLJopAhu8wYs6bm3M8eKM4nnirKfh81UK80FQmqTd8urCoFkyMA lAu8NBjGY28Wo6xKP4nFGU/ezgD55WeqK6IOwb4a6t3Kk5rrbbOBkpFRgSoViF+z Djt4sARYsXVUfM35t+trsNsLEw1U2Um2GDxhjo+41Z6Sc0oNht27c3d5WLQPnN4q AZ3Tmu0IQaQGHjaaalml3RCY311SVJTSDM91wpf8WREcnUDyDuRDesEeQZk+VWpd hfMtelYNj57VwSyMOrL8zxtz5esbHNrcjQBL+96Yx1iwazg9a3bez9apjxj1zXWk qaA5iW4sWZ9jdQKCAQEAxrsq8HbDUvfurfH0N1s6NoN7JN53AU1SsPDGtF0tLSbU nLVM8IMZTqzC1GeTvz2MYEADfUsrW4o2SciMhv7TTr70JDf3z/j6P57N/uZmXjAa 1Ro00qbHMXtj9/eiPmRfTToHhSPzcSiOrpZlC+F724jYDGRA6Jo/XsCf1HfyIIha B+FPS7GEyGXZIblAHAHlmsCZLdcKZ6PC6lgZpytE2tQqkUuBl+bZYdqR/xkLwExC tECQHodQXWUzyCJFf8ppuDobB9JsTaTTWasDO2nmEN+/O38/mCt+8hbZW3ngiN6j qY7OI2eousIbd+5aF3q94HMSOEYwJUfV56Uxufa3fQKCAQBdhjdApLN8/SlqU6MU qUe/tY4SguW+uOXT4ltACXkEa0qBOcYoXpJ3TzwppZ6gmHCF0WOaHUmV2EQi1WpR Yn8vb7fe+BDGRMpXJVJ7qjn2sbZ7zwrBHX/vPYWrBEN+EFHjK8RgnbcjRWec4OQp qSqrcWr6QDxjzQT+ZrcfNPEVlGtTvlmneuUagNrYAtZINvdKq2xJ+2eyPykWDIni oH1nI6cImLEhtddD97DePXgy5r1IxpGfy6gHispV4ptOC1QTo3uXtiK+wijve98k 56O+XcLqOaf6b93ut33t/soEZjyK7x059yEfVAkDpx7SoqYtWM38EHAUoZDyFffT tQI9AoIBADJJ2qvO4c50/uj1eR8o7qosy1ShFuw1bN9pjl7F1VC/qr2dA0M5aYYH IaYuL60NHiCdEkT6aJZZezNglG70vPQITi98GjF+h5Th0q7WDsF22tNiNku3+GAF IV72QxAWxib8sDp4xnm0EacMV7WR8Y20Kze3htVVcwO/KrLRR2wEFQQ5d59n5Hnx i+iEwDxWHovygNCgwflH72LtuFAdGudlGQB7YufVetzQOnGbHOYkZhzG2bFf/G4l 1dynD38u8WG1EnIARXfAZdsi80ZtndJXTET6BlWzbARG0+naBX+dFz0o7fD3ojLg O6M1pYabgMDzXYDwAe7tJqvfmZ29WOECggEBAL3yoPQ5ghhhFA4tuEX6VvsOhVdH i5OptgHnV8ZrjSABT2F05Bv1sIgRsNzMre7sa3MwyNfXWwZb1HWG+/wn9K0Tucbs c5SFqIcyK0pGTbwGOX+kMvkqTfkQTHMM1FOo2eV8tqWUyxVw+iaLFxh8gyGR0whH zRLKk38yfr9txKoTJqsYvLowPUnugfvQ5piaf/e5ZMsA1yTlqjD9ejkDHOzHAg28 vSZ5lFOf2Kfp6osydKUWbK58e3cqwyZjI6c0yhuItwsV9xSNsvoBmk0D8aG0Yl6G N+ifWFh/fDvM3UXHbovLwU4Umv+xCJS03w33XN54xTBpVodLycWuF0J83o0= -----END RSA PRIVATE KEY----- ================================================ FILE: platforms/neurosky/LICENSE ================================================ Copyright (c) 2013-2018 The Hybrid Group Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: platforms/neurosky/README.md ================================================ # Neurosky NeuroSky delivers fully integrated, single chip EEG biosensors. NeuroSky enables its partners and developers to bring their brainwave application ideas to market with the shortest amount of time, and lowest end consumer price. This package contains the Gobot adaptor and driver for the [Neurosky MindWave Mobile EEG](http://store.neurosky.com/products/mindwave-mobile). ## How to Install Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) ## How To Connect ### OSX In order to allow Gobot running on your Mac to access the MindWave, go to "Bluetooth > Open Bluetooth Preferences > Sharing Setup" and make sure that "Bluetooth Sharing" is checked. Now you must pair with the MindWave. Open System Preferences > Bluetooth. Now with the Bluetooth devices windows open, hold the On/Pair button on the MindWave towards the On/Pair text until you see "MindWave" pop up as available devices. Pair with that device. Once paired your MindWave will be accessable through the serial device similarly named as `/dev/tty.MindWaveMobile-DevA` ### Ubuntu Connecting to the MindWave from Ubuntu or any other Linux-based OS can be done entirely from the command line using [Gort](https://gobot.io/x/gort) CLI commands. Here are the steps. Find the address of the MindWave, by using: ```sh gort scan bluetooth ``` Pair to MindWave using this command (substituting the actual address of your MindWave): ```sh gort bluetooth pair
``` Connect to the MindWave using this command (substituting the actual address of your MindWave): ```sh gort bluetooth connect
``` ### Windows You should be able to pair your MindWave using your normal system tray applet for Bluetooth, and then connect to the COM port that is bound to the device, such as `COM3`. ## How to Use Please refer to the provided example `examples/serialport_neurosky.go`. ================================================ FILE: platforms/opencv/LICENSE ================================================ Copyright (c) 2014-2018 The Hybrid Group Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: platforms/opencv/README.md ================================================ # OpenCV OpenCV (Open Source Computer Vision Library) is an open source computer vision and machine learning software library. OpenCV was built to provide a common infrastructure for computer vision applications and to accelerate the use of machine perception in the commercial products. Being a BSD-licensed product, OpenCV makes it easy for businesses to utilize and modify the code. For more info about OpenCV click [here](http://opencv.org/) ## How to Install This package requires OpenCV 3.4+ be installed on your system, along with GoCV, which is the Go programming language wrapper used by Gobot. The best way is to follow the installation instructions on the GoCV website at [https://gocv.io](https://gocv.io). The instructions should automatically install OpenCV 4+ ### macOS To install on macOS follow the instructions here: ### Ubuntu To install on Ubuntu follow the instructions here: ### Windows Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) To install on Windows follow the instructions here: ## How to Use Here is an example using the camera: ```go package main import ( "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/opencv" "gocv.io/x/gocv" ) func main() { window := opencv.NewWindowDriver() camera := opencv.NewCameraDriver(0) work := func() { camera.On(opencv.Frame, func(data interface{}) { img := data.(gocv.Mat) window.ShowImage(img) window.WaitKey(1) }) } robot := gobot.NewRobot("cameraBot", []gobot.Device{window, camera}, work, ) if err := robot.Start(); err != nil { panic(err) } } ``` Build your application with build tag "gocv". ================================================ FILE: platforms/opencv/camera_driver.go ================================================ //go:build gocv // +build gocv package opencv import ( "errors" "gobot.io/x/gobot/v2" "gocv.io/x/gocv" ) type capture interface { Read(img *gocv.Mat) bool } const ( // Frame event Frame = "frame" ) // CameraDriver is the Gobot Driver for the OpenCV camera type CameraDriver struct { gobot.Eventer name string camera capture Source interface{} start func(*CameraDriver) error } // NewCameraDriver creates a new driver with specified source. // It also creates a start function to either set camera as a File or Camera capture. func NewCameraDriver(source interface{}) *CameraDriver { c := &CameraDriver{ name: "Camera", Eventer: gobot.NewEventer(), Source: source, start: func(c *CameraDriver) error { switch v := c.Source.(type) { case string: c.camera, _ = gocv.VideoCaptureFile(v) case int: c.camera, _ = gocv.VideoCaptureDevice(v) default: return errors.New("unknown camera source") } return nil }, } c.AddEvent(Frame) return c } // Name returns the Driver name func (c *CameraDriver) Name() string { return c.name } // SetName sets the Driver name func (c *CameraDriver) SetName(n string) { c.name = n } // Connection returns the Driver's connection func (c *CameraDriver) Connection() gobot.Connection { return nil } // Start initializes camera by grabbing frames func (c *CameraDriver) Start() error { if err := c.start(c); err != nil { return err } img := gocv.NewMat() go func() { for { if ok := c.camera.Read(&img); ok { c.Publish(Frame, img) } } }() return nil } // Halt stops camera driver func (c *CameraDriver) Halt() error { return nil } ================================================ FILE: platforms/opencv/camera_driver_test.go ================================================ //go:build gocv // +build gocv package opencv import ( "strings" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) var _ gobot.Driver = (*CameraDriver)(nil) func initTestCameraDriver() *CameraDriver { d := NewCameraDriver("") d.start = func(c *CameraDriver) error { d.camera = &testCapture{} return nil } return d } func TestCameraDriver(t *testing.T) { d := initTestCameraDriver() assert.Equal(t, "Camera", d.Name()) assert.Equal(t, (gobot.Connection)(nil), d.Connection()) } func TestCameraDriverName(t *testing.T) { d := initTestCameraDriver() assert.True(t, strings.HasPrefix(d.Name(), "Camera")) d.SetName("NewName") assert.Equal(t, "NewName", d.Name()) } func TestCameraDriverStart(t *testing.T) { sem := make(chan bool) d := initTestCameraDriver() require.NoError(t, d.Start()) d.On(d.Event("frame"), func(data interface{}) { sem <- true }) select { case <-sem: case <-time.After(100 * time.Millisecond): require.Fail(t, "Event \"frame\" was not published") } d = NewCameraDriver("") require.NoError(t, d.Start()) d = NewCameraDriver(true) assert.NotNil(t, d.Start()) } func TestCameraDriverHalt(t *testing.T) { d := initTestCameraDriver() require.NoError(t, d.Halt()) } ================================================ FILE: platforms/opencv/doc.go ================================================ /* Package opencv contains the Gobot drivers for opencv. Installing: # This package requires `opencv` to be installed on your system Then you can install the package with: Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) Example: package main import ( cv "gobot.io/x/go-opencv/opencv" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/opencv" ) func main() { window := opencv.NewWindowDriver() camera := opencv.NewCameraDriver(0) work := func() { camera.On(camera.Event("frame"), func(data interface{}) { window.ShowImage(data.(*cv.IplImage)) }) } robot := gobot.NewRobot("cameraBot", []gobot.Device{window, camera}, work, ) if err := robot.Start(); err != nil { panic(err) } } For further information refer to opencv README: https://github.com/hybridgroup/gobot/blob/release/platforms/opencv/README.md */ package opencv // import "gobot.io/x/gobot/v2/platforms/opencv" ================================================ FILE: platforms/opencv/haarcascade_frontalface_alt.xml ================================================ 20 20 <_> <_> <_> <_>3 7 14 4 -1. <_>3 9 14 2 2. 0 4.0141958743333817e-003 0.0337941907346249 0.8378106951713562 <_> <_> <_>1 2 18 4 -1. <_>7 2 6 4 3. 0 0.0151513395830989 0.1514132022857666 0.7488812208175659 <_> <_> <_>1 7 15 9 -1. <_>1 10 15 3 3. 0 4.2109931819140911e-003 0.0900492817163467 0.6374819874763489 0.8226894140243530 -1 -1 <_> <_> <_> <_>5 6 2 6 -1. <_>5 9 2 3 2. 0 1.6227109590545297e-003 0.0693085864186287 0.7110946178436279 <_> <_> <_>7 5 6 3 -1. <_>9 5 2 3 3. 0 2.2906649392098188e-003 0.1795803010463715 0.6668692231178284 <_> <_> <_>4 0 12 9 -1. <_>4 3 12 3 3. 0 5.0025708042085171e-003 0.1693672984838486 0.6554006934165955 <_> <_> <_>6 9 10 8 -1. <_>6 13 10 4 2. 0 7.9659894108772278e-003 0.5866332054138184 0.0914145186543465 <_> <_> <_>3 6 14 8 -1. <_>3 10 14 4 2. 0 -3.5227010957896709e-003 0.1413166970014572 0.6031895875930786 <_> <_> <_>14 1 6 10 -1. <_>14 1 3 10 2. 0 0.0366676896810532 0.3675672113895416 0.7920318245887756 <_> <_> <_>7 8 5 12 -1. <_>7 12 5 4 3. 0 9.3361474573612213e-003 0.6161385774612427 0.2088509947061539 <_> <_> <_>1 1 18 3 -1. <_>7 1 6 3 3. 0 8.6961314082145691e-003 0.2836230993270874 0.6360273957252502 <_> <_> <_>1 8 17 2 -1. <_>1 9 17 1 2. 0 1.1488880263641477e-003 0.2223580926656723 0.5800700783729553 <_> <_> <_>16 6 4 2 -1. <_>16 7 4 1 2. 0 -2.1484689787030220e-003 0.2406464070081711 0.5787054896354675 <_> <_> <_>5 17 2 2 -1. <_>5 18 2 1 2. 0 2.1219060290604830e-003 0.5559654831886292 0.1362237036228180 <_> <_> <_>14 2 6 12 -1. <_>14 2 3 12 2. 0 -0.0939491465687752 0.8502737283706665 0.4717740118503571 <_> <_> <_>4 0 4 12 -1. <_>4 0 2 6 2. <_>6 6 2 6 2. 0 1.3777789426967502e-003 0.5993673801422119 0.2834529876708984 <_> <_> <_>2 11 18 8 -1. <_>8 11 6 8 3. 0 0.0730631574988365 0.4341886043548584 0.7060034275054932 <_> <_> <_>5 7 10 2 -1. <_>5 8 10 1 2. 0 3.6767389974556863e-004 0.3027887940406799 0.6051574945449829 <_> <_> <_>15 11 5 3 -1. <_>15 12 5 1 3. 0 -6.0479710809886456e-003 0.1798433959484100 0.5675256848335266 6.9566087722778320 0 -1 <_> <_> <_> <_>5 3 10 9 -1. <_>5 6 10 3 3. 0 -0.0165106896311045 0.6644225120544434 0.1424857974052429 <_> <_> <_>9 4 2 14 -1. <_>9 11 2 7 2. 0 2.7052499353885651e-003 0.6325352191925049 0.1288477033376694 <_> <_> <_>3 5 4 12 -1. <_>3 9 4 4 3. 0 2.8069869149476290e-003 0.1240288019180298 0.6193193197250366 <_> <_> <_>4 5 12 5 -1. <_>8 5 4 5 3. 0 -1.5402400167658925e-003 0.1432143002748489 0.5670015811920166 <_> <_> <_>5 6 10 8 -1. <_>5 10 10 4 2. 0 -5.6386279175058007e-004 0.1657433062791824 0.5905207991600037 <_> <_> <_>8 0 6 9 -1. <_>8 3 6 3 3. 0 1.9253729842603207e-003 0.2695507109165192 0.5738824009895325 <_> <_> <_>9 12 1 8 -1. <_>9 16 1 4 2. 0 -5.0214841030538082e-003 0.1893538981676102 0.5782774090766907 <_> <_> <_>0 7 20 6 -1. <_>0 9 20 2 3. 0 2.6365420781075954e-003 0.2309329062700272 0.5695425868034363 <_> <_> <_>7 0 6 17 -1. <_>9 0 2 17 3. 0 -1.5127769438549876e-003 0.2759602069854736 0.5956642031669617 <_> <_> <_>9 0 6 4 -1. <_>11 0 2 4 3. 0 -0.0101574398577213 0.1732538044452667 0.5522047281265259 <_> <_> <_>5 1 6 4 -1. <_>7 1 2 4 3. 0 -0.0119536602869630 0.1339409947395325 0.5559014081954956 <_> <_> <_>12 1 6 16 -1. <_>14 1 2 16 3. 0 4.8859491944313049e-003 0.3628703951835632 0.6188849210739136 <_> <_> <_>0 5 18 8 -1. <_>0 5 9 4 2. <_>9 9 9 4 2. 0 -0.0801329165697098 0.0912110507488251 0.5475944876670837 <_> <_> <_>8 15 10 4 -1. <_>13 15 5 2 2. <_>8 17 5 2 2. 0 1.0643280111253262e-003 0.3715142905712128 0.5711399912834168 <_> <_> <_>3 1 4 8 -1. <_>3 1 2 4 2. <_>5 5 2 4 2. 0 -1.3419450260698795e-003 0.5953313708305359 0.3318097889423370 <_> <_> <_>3 6 14 10 -1. <_>10 6 7 5 2. <_>3 11 7 5 2. 0 -0.0546011403203011 0.1844065934419632 0.5602846145629883 <_> <_> <_>2 1 6 16 -1. <_>4 1 2 16 3. 0 2.9071690514683723e-003 0.3594244122505188 0.6131715178489685 <_> <_> <_>0 18 20 2 -1. <_>0 19 20 1 2. 0 7.4718717951327562e-004 0.5994353294372559 0.3459562957286835 <_> <_> <_>8 13 4 3 -1. <_>8 14 4 1 3. 0 4.3013808317482471e-003 0.4172652065753937 0.6990845203399658 <_> <_> <_>9 14 2 3 -1. <_>9 15 2 1 3. 0 4.5017572119832039e-003 0.4509715139865875 0.7801457047462463 <_> <_> <_>0 12 9 6 -1. <_>0 14 9 2 3. 0 0.0241385009139776 0.5438212752342224 0.1319826990365982 9.4985427856445313 1 -1 <_> <_> <_> <_>5 7 3 4 -1. <_>5 9 3 2 2. 0 1.9212230108678341e-003 0.1415266990661621 0.6199870705604553 <_> <_> <_>9 3 2 16 -1. <_>9 11 2 8 2. 0 -1.2748669541906565e-004 0.6191074252128601 0.1884928941726685 <_> <_> <_>3 6 13 8 -1. <_>3 10 13 4 2. 0 5.1409931620582938e-004 0.1487396955490112 0.5857927799224854 <_> <_> <_>12 3 8 2 -1. <_>12 3 4 2 2. 0 4.1878609918057919e-003 0.2746909856796265 0.6359239816665649 <_> <_> <_>8 8 4 12 -1. <_>8 12 4 4 3. 0 5.1015717908740044e-003 0.5870851278305054 0.2175628989934921 <_> <_> <_>11 3 8 6 -1. <_>15 3 4 3 2. <_>11 6 4 3 2. 0 -2.1448440384119749e-003 0.5880944728851318 0.2979590892791748 <_> <_> <_>7 1 6 19 -1. <_>9 1 2 19 3. 0 -2.8977119363844395e-003 0.2373327016830444 0.5876647233963013 <_> <_> <_>9 0 6 4 -1. <_>11 0 2 4 3. 0 -0.0216106791049242 0.1220654994249344 0.5194202065467835 <_> <_> <_>3 1 9 3 -1. <_>6 1 3 3 3. 0 -4.6299318782985210e-003 0.2631230950355530 0.5817409157752991 <_> <_> <_>8 15 10 4 -1. <_>13 15 5 2 2. <_>8 17 5 2 2. 0 5.9393711853772402e-004 0.3638620078563690 0.5698544979095459 <_> <_> <_>0 3 6 10 -1. <_>3 3 3 10 2. 0 0.0538786612451077 0.4303531050682068 0.7559366226196289 <_> <_> <_>3 4 15 15 -1. <_>3 9 15 5 3. 0 1.8887349870055914e-003 0.2122603058815002 0.5613427162170410 <_> <_> <_>6 5 8 6 -1. <_>6 7 8 2 3. 0 -2.3635339457541704e-003 0.5631849169731140 0.2642767131328583 <_> <_> <_>4 4 12 10 -1. <_>10 4 6 5 2. <_>4 9 6 5 2. 0 0.0240177996456623 0.5797107815742493 0.2751705944538117 <_> <_> <_>6 4 4 4 -1. <_>8 4 2 4 2. 0 2.0543030404951423e-004 0.2705242037773132 0.5752568840980530 <_> <_> <_>15 11 1 2 -1. <_>15 12 1 1 2. 0 8.4790197433903813e-004 0.5435624718666077 0.2334876954555512 <_> <_> <_>3 11 2 2 -1. <_>3 12 2 1 2. 0 1.4091329649090767e-003 0.5319424867630005 0.2063155025243759 <_> <_> <_>16 11 1 3 -1. <_>16 12 1 1 3. 0 1.4642629539594054e-003 0.5418980717658997 0.3068861067295075 <_> <_> <_>3 15 6 4 -1. <_>3 15 3 2 2. <_>6 17 3 2 2. 0 1.6352549428120255e-003 0.3695372939109802 0.6112868189811707 <_> <_> <_>6 7 8 2 -1. <_>6 8 8 1 2. 0 8.3172752056270838e-004 0.3565036952495575 0.6025236248970032 <_> <_> <_>3 11 1 3 -1. <_>3 12 1 1 3. 0 -2.0998890977352858e-003 0.1913982033729553 0.5362827181816101 <_> <_> <_>6 0 12 2 -1. <_>6 1 12 1 2. 0 -7.4213981861248612e-004 0.3835555016994476 0.5529310107231140 <_> <_> <_>9 14 2 3 -1. <_>9 15 2 1 3. 0 3.2655049581080675e-003 0.4312896132469177 0.7101895809173584 <_> <_> <_>7 15 6 2 -1. <_>7 16 6 1 2. 0 8.9134991867467761e-004 0.3984830975532532 0.6391963958740234 <_> <_> <_>0 5 4 6 -1. <_>0 7 4 2 3. 0 -0.0152841797098517 0.2366732954978943 0.5433713793754578 <_> <_> <_>4 12 12 2 -1. <_>8 12 4 2 3. 0 4.8381411470472813e-003 0.5817500948905945 0.3239189088344574 <_> <_> <_>6 3 1 9 -1. <_>6 6 1 3 3. 0 -9.1093179071322083e-004 0.5540593862533569 0.2911868989467621 <_> <_> <_>10 17 3 2 -1. <_>11 17 1 2 3. 0 -6.1275060288608074e-003 0.1775255054235458 0.5196629166603088 <_> <_> <_>9 9 2 2 -1. <_>9 10 2 1 2. 0 -4.4576259097084403e-004 0.3024170100688934 0.5533593893051148 <_> <_> <_>7 6 6 4 -1. <_>9 6 2 4 3. 0 0.0226465407758951 0.4414930939674377 0.6975377202033997 <_> <_> <_>7 17 3 2 -1. <_>8 17 1 2 3. 0 -1.8804960418492556e-003 0.2791394889354706 0.5497952103614807 <_> <_> <_>10 17 3 3 -1. <_>11 17 1 3 3. 0 7.0889107882976532e-003 0.5263199210166931 0.2385547012090683 <_> <_> <_>8 12 3 2 -1. <_>8 13 3 1 2. 0 1.7318050377070904e-003 0.4319379031658173 0.6983600854873657 <_> <_> <_>9 3 6 2 -1. <_>11 3 2 2 3. 0 -6.8482700735330582e-003 0.3082042932510376 0.5390920042991638 <_> <_> <_>3 11 14 4 -1. <_>3 13 14 2 2. 0 -1.5062530110299122e-005 0.5521922111511231 0.3120366036891937 <_> <_> <_>1 10 18 4 -1. <_>10 10 9 2 2. <_>1 12 9 2 2. 0 0.0294755697250366 0.5401322841644287 0.1770603060722351 <_> <_> <_>0 10 3 3 -1. <_>0 11 3 1 3. 0 8.1387329846620560e-003 0.5178617835044861 0.1211019009351730 <_> <_> <_>9 1 6 6 -1. <_>11 1 2 6 3. 0 0.0209429506212473 0.5290294289588928 0.3311221897602081 <_> <_> <_>8 7 3 6 -1. <_>9 7 1 6 3. 0 -9.5665529370307922e-003 0.7471994161605835 0.4451968967914581 18.4129695892333980 2 -1 <_> <_> <_> <_>1 0 18 9 -1. <_>1 3 18 3 3. 0 -2.8206960996612906e-004 0.2064086049795151 0.6076732277870178 <_> <_> <_>12 10 2 6 -1. <_>12 13 2 3 2. 0 1.6790600493550301e-003 0.5851997137069702 0.1255383938550949 <_> <_> <_>0 5 19 8 -1. <_>0 9 19 4 2. 0 6.9827912375330925e-004 0.0940184295177460 0.5728961229324341 <_> <_> <_>7 0 6 9 -1. <_>9 0 2 9 3. 0 7.8959012171253562e-004 0.1781987994909287 0.5694308876991272 <_> <_> <_>5 3 6 1 -1. <_>7 3 2 1 3. 0 -2.8560499195009470e-003 0.1638399064540863 0.5788664817810059 <_> <_> <_>11 3 6 1 -1. <_>13 3 2 1 3. 0 -3.8122469559311867e-003 0.2085440009832382 0.5508564710617065 <_> <_> <_>5 10 4 6 -1. <_>5 13 4 3 2. 0 1.5896620461717248e-003 0.5702760815620422 0.1857215017080307 <_> <_> <_>11 3 6 1 -1. <_>13 3 2 1 3. 0 0.0100783398374915 0.5116943120956421 0.2189770042896271 <_> <_> <_>4 4 12 6 -1. <_>4 6 12 2 3. 0 -0.0635263025760651 0.7131379842758179 0.4043813049793243 <_> <_> <_>15 12 2 6 -1. <_>15 14 2 2 3. 0 -9.1031491756439209e-003 0.2567181885242462 0.5463973283767700 <_> <_> <_>9 3 2 2 -1. <_>10 3 1 2 2. 0 -2.4035000242292881e-003 0.1700665950775147 0.5590974092483521 <_> <_> <_>9 3 3 1 -1. <_>10 3 1 1 3. 0 1.5226360410451889e-003 0.5410556793212891 0.2619054019451141 <_> <_> <_>1 1 4 14 -1. <_>3 1 2 14 2. 0 0.0179974399507046 0.3732436895370483 0.6535220742225647 <_> <_> <_>9 0 4 4 -1. <_>11 0 2 2 2. <_>9 2 2 2 2. 0 -6.4538191072642803e-003 0.2626481950283051 0.5537446141242981 <_> <_> <_>7 5 1 14 -1. <_>7 12 1 7 2. 0 -0.0118807600811124 0.2003753930330277 0.5544745922088623 <_> <_> <_>19 0 1 4 -1. <_>19 2 1 2 2. 0 1.2713660253211856e-003 0.5591902732849121 0.3031975924968720 <_> <_> <_>5 5 6 4 -1. <_>8 5 3 4 2. 0 1.1376109905540943e-003 0.2730407118797302 0.5646508932113648 <_> <_> <_>9 18 3 2 -1. <_>10 18 1 2 3. 0 -4.2651998810470104e-003 0.1405909061431885 0.5461820960044861 <_> <_> <_>8 18 3 2 -1. <_>9 18 1 2 3. 0 -2.9602861031889915e-003 0.1795035004615784 0.5459290146827698 <_> <_> <_>4 5 12 6 -1. <_>4 7 12 2 3. 0 -8.8448226451873779e-003 0.5736783146858215 0.2809219956398010 <_> <_> <_>3 12 2 6 -1. <_>3 14 2 2 3. 0 -6.6430689767003059e-003 0.2370675951242447 0.5503826141357422 <_> <_> <_>10 8 2 12 -1. <_>10 12 2 4 3. 0 3.9997808635234833e-003 0.5608199834823608 0.3304282128810883 <_> <_> <_>7 18 3 2 -1. <_>8 18 1 2 3. 0 -4.1221720166504383e-003 0.1640105992555618 0.5378993153572083 <_> <_> <_>9 0 6 2 -1. <_>11 0 2 2 3. 0 0.0156249096617103 0.5227649211883545 0.2288603931665421 <_> <_> <_>5 11 9 3 -1. <_>5 12 9 1 3. 0 -0.0103564197197557 0.7016193866729736 0.4252927899360657 <_> <_> <_>9 0 6 2 -1. <_>11 0 2 2 3. 0 -8.7960809469223022e-003 0.2767347097396851 0.5355830192565918 <_> <_> <_>1 1 18 5 -1. <_>7 1 6 5 3. 0 0.1622693985700607 0.4342240095138550 0.7442579269409180 <_> <_> <_>8 0 4 4 -1. <_>10 0 2 2 2. <_>8 2 2 2 2. 0 4.5542530715465546e-003 0.5726485848426819 0.2582125067710877 <_> <_> <_>3 12 1 3 -1. <_>3 13 1 1 3. 0 -2.1309209987521172e-003 0.2106848061084747 0.5361018776893616 <_> <_> <_>8 14 5 3 -1. <_>8 15 5 1 3. 0 -0.0132084200158715 0.7593790888786316 0.4552468061447144 <_> <_> <_>5 4 10 12 -1. <_>5 4 5 6 2. <_>10 10 5 6 2. 0 -0.0659966766834259 0.1252475976943970 0.5344039797782898 <_> <_> <_>9 6 9 12 -1. <_>9 10 9 4 3. 0 7.9142656177282333e-003 0.3315384089946747 0.5601043105125427 <_> <_> <_>2 2 12 14 -1. <_>2 2 6 7 2. <_>8 9 6 7 2. 0 0.0208942797034979 0.5506049990653992 0.2768838107585907 15.3241395950317380 3 -1 <_> <_> <_> <_>4 7 12 2 -1. <_>8 7 4 2 3. 0 1.1961159761995077e-003 0.1762690991163254 0.6156241297721863 <_> <_> <_>7 4 6 4 -1. <_>7 6 6 2 2. 0 -1.8679830245673656e-003 0.6118106842041016 0.1832399964332581 <_> <_> <_>4 5 11 8 -1. <_>4 9 11 4 2. 0 -1.9579799845814705e-004 0.0990442633628845 0.5723816156387329 <_> <_> <_>3 10 16 4 -1. <_>3 12 16 2 2. 0 -8.0255657667294145e-004 0.5579879879951477 0.2377282977104187 <_> <_> <_>0 0 16 2 -1. <_>0 1 16 1 2. 0 -2.4510810617357492e-003 0.2231457978487015 0.5858935117721558 <_> <_> <_>7 5 6 2 -1. <_>9 5 2 2 3. 0 5.0361850298941135e-004 0.2653993964195252 0.5794103741645813 <_> <_> <_>3 2 6 10 -1. <_>3 2 3 5 2. <_>6 7 3 5 2. 0 4.0293349884450436e-003 0.5803827047348023 0.2484865039587021 <_> <_> <_>10 5 8 15 -1. <_>10 10 8 5 3. 0 -0.0144517095759511 0.1830351948738098 0.5484204888343811 <_> <_> <_>3 14 8 6 -1. <_>3 14 4 3 2. <_>7 17 4 3 2. 0 2.0380979403853416e-003 0.3363558948040009 0.6051092743873596 <_> <_> <_>14 2 2 2 -1. <_>14 3 2 1 2. 0 -1.6155190533027053e-003 0.2286642044782639 0.5441246032714844 <_> <_> <_>1 10 7 6 -1. <_>1 13 7 3 2. 0 3.3458340913057327e-003 0.5625913143157959 0.2392338067293167 <_> <_> <_>15 4 4 3 -1. <_>15 4 2 3 2. 0 1.6379579901695251e-003 0.3906993865966797 0.5964621901512146 <_> <_> <_>2 9 14 6 -1. <_>2 9 7 3 2. <_>9 12 7 3 2. 0 0.0302512105554342 0.5248482227325440 0.1575746983289719 <_> <_> <_>5 7 10 4 -1. <_>5 9 10 2 2. 0 0.0372519902884960 0.4194310903549194 0.6748418807983398 <_> <_> <_>6 9 8 8 -1. <_>6 9 4 4 2. <_>10 13 4 4 2. 0 -0.0251097902655602 0.1882549971342087 0.5473451018333435 <_> <_> <_>14 1 3 2 -1. <_>14 2 3 1 2. 0 -5.3099058568477631e-003 0.1339973062276840 0.5227110981941223 <_> <_> <_>1 4 4 2 -1. <_>3 4 2 2 2. 0 1.2086479691788554e-003 0.3762088119983673 0.6109635829925537 <_> <_> <_>11 10 2 8 -1. <_>11 14 2 4 2. 0 -0.0219076797366142 0.2663142979145050 0.5404006838798523 <_> <_> <_>0 0 5 3 -1. <_>0 1 5 1 3. 0 5.4116579703986645e-003 0.5363578796386719 0.2232273072004318 <_> <_> <_>2 5 18 8 -1. <_>11 5 9 4 2. <_>2 9 9 4 2. 0 0.0699463263154030 0.5358232855796814 0.2453698068857193 <_> <_> <_>6 6 1 6 -1. <_>6 9 1 3 2. 0 3.4520021290518343e-004 0.2409671992063522 0.5376930236816406 <_> <_> <_>19 1 1 3 -1. <_>19 2 1 1 3. 0 1.2627709656953812e-003 0.5425856709480286 0.3155693113803864 <_> <_> <_>7 6 6 6 -1. <_>9 6 2 6 3. 0 0.0227195098996162 0.4158405959606171 0.6597865223884583 <_> <_> <_>19 1 1 3 -1. <_>19 2 1 1 3. 0 -1.8111000536009669e-003 0.2811253070831299 0.5505244731903076 <_> <_> <_>3 13 2 3 -1. <_>3 14 2 1 3. 0 3.3469670452177525e-003 0.5260028243064880 0.1891465038061142 <_> <_> <_>8 4 8 12 -1. <_>12 4 4 6 2. <_>8 10 4 6 2. 0 4.0791751234792173e-004 0.5673509240150452 0.3344210088253021 <_> <_> <_>5 2 6 3 -1. <_>7 2 2 3 3. 0 0.0127347996458411 0.5343592166900635 0.2395612001419067 <_> <_> <_>6 1 9 10 -1. <_>6 6 9 5 2. 0 -7.3119727894663811e-003 0.6010890007019043 0.4022207856178284 <_> <_> <_>0 4 6 12 -1. <_>2 4 2 12 3. 0 -0.0569487512111664 0.8199151158332825 0.4543190896511078 <_> <_> <_>15 13 2 3 -1. <_>15 14 2 1 3. 0 -5.0116591155529022e-003 0.2200281023979187 0.5357710719108582 <_> <_> <_>7 14 5 3 -1. <_>7 15 5 1 3. 0 6.0334368608891964e-003 0.4413081109523773 0.7181751132011414 <_> <_> <_>15 13 3 3 -1. <_>15 14 3 1 3. 0 3.9437441155314445e-003 0.5478860735893250 0.2791733145713806 <_> <_> <_>6 14 8 3 -1. <_>6 15 8 1 3. 0 -3.6591119132936001e-003 0.6357867717742920 0.3989723920822144 <_> <_> <_>15 13 3 3 -1. <_>15 14 3 1 3. 0 -3.8456181064248085e-003 0.3493686020374298 0.5300664901733398 <_> <_> <_>2 13 3 3 -1. <_>2 14 3 1 3. 0 -7.1926261298358440e-003 0.1119614988565445 0.5229672789573669 <_> <_> <_>4 7 12 12 -1. <_>10 7 6 6 2. <_>4 13 6 6 2. 0 -0.0527989417314529 0.2387102991342545 0.5453451275825501 <_> <_> <_>9 7 2 6 -1. <_>10 7 1 6 2. 0 -7.9537667334079742e-003 0.7586917877197266 0.4439376890659332 <_> <_> <_>8 9 5 2 -1. <_>8 10 5 1 2. 0 -2.7344180271029472e-003 0.2565476894378662 0.5489321947097778 <_> <_> <_>8 6 3 4 -1. <_>9 6 1 4 3. 0 -1.8507939530536532e-003 0.6734347939491272 0.4252474904060364 <_> <_> <_>9 6 2 8 -1. <_>9 10 2 4 2. 0 0.0159189198166132 0.5488352775573731 0.2292661964893341 <_> <_> <_>7 7 3 6 -1. <_>8 7 1 6 3. 0 -1.2687679845839739e-003 0.6104331016540527 0.4022389948368073 <_> <_> <_>11 3 3 3 -1. <_>12 3 1 3 3. 0 6.2883910723030567e-003 0.5310853123664856 0.1536193042993546 <_> <_> <_>5 4 6 1 -1. <_>7 4 2 1 3. 0 -6.2259892001748085e-003 0.1729111969470978 0.5241606235504150 <_> <_> <_>5 6 10 3 -1. <_>5 7 10 1 3. 0 -0.0121325999498367 0.6597759723663330 0.4325182139873505 21.0106391906738280 4 -1 <_> <_> <_> <_>7 3 6 9 -1. <_>7 6 6 3 3. 0 -3.9184908382594585e-003 0.6103435158729553 0.1469330936670303 <_> <_> <_>6 7 9 1 -1. <_>9 7 3 1 3. 0 1.5971299726516008e-003 0.2632363140583038 0.5896466970443726 <_> <_> <_>2 8 16 8 -1. <_>2 12 16 4 2. 0 0.0177801102399826 0.5872874259948731 0.1760361939668655 <_> <_> <_>14 6 2 6 -1. <_>14 9 2 3 2. 0 6.5334769897162914e-004 0.1567801982164383 0.5596066117286682 <_> <_> <_>1 5 6 15 -1. <_>1 10 6 5 3. 0 -2.8353091329336166e-004 0.1913153976202011 0.5732036232948303 <_> <_> <_>10 0 6 9 -1. <_>10 3 6 3 3. 0 1.6104689566418529e-003 0.2914913892745972 0.5623080730438232 <_> <_> <_>6 6 7 14 -1. <_>6 13 7 7 2. 0 -0.0977506190538406 0.1943476945161820 0.5648233294487000 <_> <_> <_>13 7 3 6 -1. <_>13 9 3 2 3. 0 5.5182358482852578e-004 0.3134616911411285 0.5504639744758606 <_> <_> <_>1 8 15 4 -1. <_>6 8 5 4 3. 0 -0.0128582203760743 0.2536481916904450 0.5760142803192139 <_> <_> <_>11 2 3 10 -1. <_>11 7 3 5 2. 0 4.1530239395797253e-003 0.5767722129821777 0.3659774065017700 <_> <_> <_>3 7 4 6 -1. <_>3 9 4 2 3. 0 1.7092459602281451e-003 0.2843191027641296 0.5918939113616943 <_> <_> <_>13 3 6 10 -1. <_>15 3 2 10 3. 0 7.5217359699308872e-003 0.4052427113056183 0.6183109283447266 <_> <_> <_>5 7 8 10 -1. <_>5 7 4 5 2. <_>9 12 4 5 2. 0 2.2479810286313295e-003 0.5783755183219910 0.3135401010513306 <_> <_> <_>4 4 12 12 -1. <_>10 4 6 6 2. <_>4 10 6 6 2. 0 0.0520062111318111 0.5541312098503113 0.1916636973619461 <_> <_> <_>1 4 6 9 -1. <_>3 4 2 9 3. 0 0.0120855299755931 0.4032655954360962 0.6644591093063355 <_> <_> <_>11 3 2 5 -1. <_>11 3 1 5 2. 0 1.4687820112158079e-005 0.3535977900028229 0.5709382891654968 <_> <_> <_>7 3 2 5 -1. <_>8 3 1 5 2. 0 7.1395188570022583e-006 0.3037444949150085 0.5610269904136658 <_> <_> <_>10 14 2 3 -1. <_>10 15 2 1 3. 0 -4.6001640148460865e-003 0.7181087136268616 0.4580326080322266 <_> <_> <_>5 12 6 2 -1. <_>8 12 3 2 2. 0 2.0058949012309313e-003 0.5621951818466187 0.2953684031963348 <_> <_> <_>9 14 2 3 -1. <_>9 15 2 1 3. 0 4.5050270855426788e-003 0.4615387916564941 0.7619017958641052 <_> <_> <_>4 11 12 6 -1. <_>4 14 12 3 2. 0 0.0117468303069472 0.5343837141990662 0.1772529035806656 <_> <_> <_>11 11 5 9 -1. <_>11 14 5 3 3. 0 -0.0583163388073444 0.1686245948076248 0.5340772271156311 <_> <_> <_>6 15 3 2 -1. <_>6 16 3 1 2. 0 2.3629379575140774e-004 0.3792056143283844 0.6026803851127625 <_> <_> <_>11 0 3 5 -1. <_>12 0 1 5 3. 0 -7.8156180679798126e-003 0.1512867063283920 0.5324323773384094 <_> <_> <_>5 5 6 7 -1. <_>8 5 3 7 2. 0 -0.0108761601150036 0.2081822007894516 0.5319945216178894 <_> <_> <_>13 0 1 9 -1. <_>13 3 1 3 3. 0 -2.7745519764721394e-003 0.4098246991634369 0.5210328102111816 <_> <_> <_>3 2 4 8 -1. <_>3 2 2 4 2. <_>5 6 2 4 2. 0 -7.8276381827890873e-004 0.5693274140357971 0.3478842079639435 <_> <_> <_>13 12 4 6 -1. <_>13 14 4 2 3. 0 0.0138704096898437 0.5326750874519348 0.2257698029279709 <_> <_> <_>3 12 4 6 -1. <_>3 14 4 2 3. 0 -0.0236749108880758 0.1551305055618286 0.5200707912445068 <_> <_> <_>13 11 3 4 -1. <_>13 13 3 2 2. 0 -1.4879409718560055e-005 0.5500566959381104 0.3820176124572754 <_> <_> <_>4 4 4 3 -1. <_>4 5 4 1 3. 0 3.6190641112625599e-003 0.4238683879375458 0.6639748215675354 <_> <_> <_>7 5 11 8 -1. <_>7 9 11 4 2. 0 -0.0198171101510525 0.2150038033723831 0.5382357835769653 <_> <_> <_>7 8 3 4 -1. <_>8 8 1 4 3. 0 -3.8154039066284895e-003 0.6675711274147034 0.4215297102928162 <_> <_> <_>9 1 6 1 -1. <_>11 1 2 1 3. 0 -4.9775829538702965e-003 0.2267289012670517 0.5386328101158142 <_> <_> <_>5 5 3 3 -1. <_>5 6 3 1 3. 0 2.2441020701080561e-003 0.4308691024780273 0.6855735778808594 <_> <_> <_>0 9 20 6 -1. <_>10 9 10 3 2. <_>0 12 10 3 2. 0 0.0122824599966407 0.5836614966392517 0.3467479050159454 <_> <_> <_>8 6 3 5 -1. <_>9 6 1 5 3. 0 -2.8548699337989092e-003 0.7016944885253906 0.4311453998088837 <_> <_> <_>11 0 1 3 -1. <_>11 1 1 1 3. 0 -3.7875669077038765e-003 0.2895345091819763 0.5224946141242981 <_> <_> <_>4 2 4 2 -1. <_>4 3 4 1 2. 0 -1.2201230274513364e-003 0.2975570857524872 0.5481644868850708 <_> <_> <_>12 6 4 3 -1. <_>12 7 4 1 3. 0 0.0101605998352170 0.4888817965984345 0.8182697892189026 <_> <_> <_>5 0 6 4 -1. <_>7 0 2 4 3. 0 -0.0161745697259903 0.1481492966413498 0.5239992737770081 <_> <_> <_>9 7 3 8 -1. <_>10 7 1 8 3. 0 0.0192924607545137 0.4786309897899628 0.7378190755844116 <_> <_> <_>9 7 2 2 -1. <_>10 7 1 2 2. 0 -3.2479539513587952e-003 0.7374222874641419 0.4470643997192383 <_> <_> <_>6 7 14 4 -1. <_>13 7 7 2 2. <_>6 9 7 2 2. 0 -9.3803480267524719e-003 0.3489154875278473 0.5537996292114258 <_> <_> <_>0 5 3 6 -1. <_>0 7 3 2 3. 0 -0.0126061299815774 0.2379686981439591 0.5315443277359009 <_> <_> <_>13 11 3 4 -1. <_>13 13 3 2 2. 0 -0.0256219301372766 0.1964688003063202 0.5138769745826721 <_> <_> <_>4 11 3 4 -1. <_>4 13 3 2 2. 0 -7.5741496402770281e-005 0.5590522885322571 0.3365853130817413 <_> <_> <_>5 9 12 8 -1. <_>11 9 6 4 2. <_>5 13 6 4 2. 0 -0.0892108827829361 0.0634046569466591 0.5162634849548340 <_> <_> <_>9 12 1 3 -1. <_>9 13 1 1 3. 0 -2.7670480776578188e-003 0.7323467731475830 0.4490706026554108 <_> <_> <_>10 15 2 4 -1. <_>10 17 2 2 2. 0 2.7152578695677221e-004 0.4114834964275360 0.5985518097877502 23.9187908172607420 5 -1 <_> <_> <_> <_>7 7 6 1 -1. <_>9 7 2 1 3. 0 1.4786219689995050e-003 0.2663545012474060 0.6643316745758057 <_> <_> <_>12 3 6 6 -1. <_>15 3 3 3 2. <_>12 6 3 3 2. 0 -1.8741659587249160e-003 0.6143848896026611 0.2518512904644013 <_> <_> <_>0 4 10 6 -1. <_>0 6 10 2 3. 0 -1.7151009524241090e-003 0.5766341090202332 0.2397463023662567 <_> <_> <_>8 3 8 14 -1. <_>12 3 4 7 2. <_>8 10 4 7 2. 0 -1.8939269939437509e-003 0.5682045817375183 0.2529144883155823 <_> <_> <_>4 4 7 15 -1. <_>4 9 7 5 3. 0 -5.3006052039563656e-003 0.1640675961971283 0.5556079745292664 <_> <_> <_>12 2 6 8 -1. <_>15 2 3 4 2. <_>12 6 3 4 2. 0 -0.0466625317931175 0.6123154163360596 0.4762830138206482 <_> <_> <_>2 2 6 8 -1. <_>2 2 3 4 2. <_>5 6 3 4 2. 0 -7.9431332414969802e-004 0.5707858800888062 0.2839404046535492 <_> <_> <_>2 13 18 7 -1. <_>8 13 6 7 3. 0 0.0148916700854898 0.4089672863483429 0.6006367206573486 <_> <_> <_>4 3 8 14 -1. <_>4 3 4 7 2. <_>8 10 4 7 2. 0 -1.2046529445797205e-003 0.5712450742721558 0.2705289125442505 <_> <_> <_>18 1 2 6 -1. <_>18 3 2 2 3. 0 6.0619381256401539e-003 0.5262504220008850 0.3262225985527039 <_> <_> <_>9 11 2 3 -1. <_>9 12 2 1 3. 0 -2.5286648888140917e-003 0.6853830814361572 0.4199256896972656 <_> <_> <_>18 1 2 6 -1. <_>18 3 2 2 3. 0 -5.9010218828916550e-003 0.3266282081604004 0.5434812903404236 <_> <_> <_>0 1 2 6 -1. <_>0 3 2 2 3. 0 5.6702760048210621e-003 0.5468410849571228 0.2319003939628601 <_> <_> <_>1 5 18 6 -1. <_>1 7 18 2 3. 0 -3.0304100364446640e-003 0.5570667982101440 0.2708238065242767 <_> <_> <_>0 2 6 7 -1. <_>3 2 3 7 2. 0 2.9803649522364140e-003 0.3700568974018097 0.5890625715255737 <_> <_> <_>7 3 6 14 -1. <_>7 10 6 7 2. 0 -0.0758405104279518 0.2140070050954819 0.5419948101043701 <_> <_> <_>3 7 13 10 -1. <_>3 12 13 5 2. 0 0.0192625392228365 0.5526772141456604 0.2726590037345886 <_> <_> <_>11 15 2 2 -1. <_>11 16 2 1 2. 0 1.8888259364757687e-004 0.3958011865615845 0.6017209887504578 <_> <_> <_>2 11 16 4 -1. <_>2 11 8 2 2. <_>10 13 8 2 2. 0 0.0293695498257875 0.5241373777389526 0.1435758024454117 <_> <_> <_>13 7 6 4 -1. <_>16 7 3 2 2. <_>13 9 3 2 2. 0 1.0417619487270713e-003 0.3385409116744995 0.5929983258247376 <_> <_> <_>6 10 3 9 -1. <_>6 13 3 3 3. 0 2.6125640142709017e-003 0.5485377907752991 0.3021597862243652 <_> <_> <_>14 6 1 6 -1. <_>14 9 1 3 2. 0 9.6977467183023691e-004 0.3375276029109955 0.5532032847404480 <_> <_> <_>5 10 4 1 -1. <_>7 10 2 1 2. 0 5.9512659208849072e-004 0.5631743073463440 0.3359399139881134 <_> <_> <_>3 8 15 5 -1. <_>8 8 5 5 3. 0 -0.1015655994415283 0.0637350380420685 0.5230425000190735 <_> <_> <_>1 6 5 4 -1. <_>1 8 5 2 2. 0 0.0361566990613937 0.5136963129043579 0.1029528975486755 <_> <_> <_>3 1 17 6 -1. <_>3 3 17 2 3. 0 3.4624140243977308e-003 0.3879320025444031 0.5558289289474487 <_> <_> <_>6 7 8 2 -1. <_>10 7 4 2 2. 0 0.0195549800992012 0.5250086784362793 0.1875859946012497 <_> <_> <_>9 7 3 2 -1. <_>10 7 1 2 3. 0 -2.3121440317481756e-003 0.6672028899192810 0.4679641127586365 <_> <_> <_>8 7 3 2 -1. <_>9 7 1 2 3. 0 -1.8605289515107870e-003 0.7163379192352295 0.4334670901298523 <_> <_> <_>8 9 4 2 -1. <_>8 10 4 1 2. 0 -9.4026362057775259e-004 0.3021360933780670 0.5650203227996826 <_> <_> <_>8 8 4 3 -1. <_>8 9 4 1 3. 0 -5.2418331615626812e-003 0.1820009052753449 0.5250256061553955 <_> <_> <_>9 5 6 4 -1. <_>9 5 3 4 2. 0 1.1729019752237946e-004 0.3389188051223755 0.5445973277091980 <_> <_> <_>8 13 4 3 -1. <_>8 14 4 1 3. 0 1.1878840159624815e-003 0.4085349142551422 0.6253563165664673 <_> <_> <_>4 7 12 6 -1. <_>10 7 6 3 2. <_>4 10 6 3 2. 0 -0.0108813596889377 0.3378399014472961 0.5700082778930664 <_> <_> <_>8 14 4 3 -1. <_>8 15 4 1 3. 0 1.7354859737679362e-003 0.4204635918140411 0.6523038744926453 <_> <_> <_>9 7 3 3 -1. <_>9 8 3 1 3. 0 -6.5119052305817604e-003 0.2595216035842896 0.5428143739700317 <_> <_> <_>7 4 3 8 -1. <_>8 4 1 8 3. 0 -1.2136430013924837e-003 0.6165143847465515 0.3977893888950348 <_> <_> <_>10 0 3 6 -1. <_>11 0 1 6 3. 0 -0.0103542404249310 0.1628028005361557 0.5219504833221436 <_> <_> <_>6 3 4 8 -1. <_>8 3 2 8 2. 0 5.5858830455690622e-004 0.3199650943279266 0.5503574013710022 <_> <_> <_>14 3 6 13 -1. <_>14 3 3 13 2. 0 0.0152996499091387 0.4103994071483612 0.6122388243675232 <_> <_> <_>8 13 3 6 -1. <_>8 16 3 3 2. 0 -0.0215882100164890 0.1034912988543510 0.5197384953498840 <_> <_> <_>14 3 6 13 -1. <_>14 3 3 13 2. 0 -0.1283462941646576 0.8493865132331848 0.4893102943897247 <_> <_> <_>0 7 10 4 -1. <_>0 7 5 2 2. <_>5 9 5 2 2. 0 -2.2927189711481333e-003 0.3130157887935638 0.5471575260162354 <_> <_> <_>14 3 6 13 -1. <_>14 3 3 13 2. 0 0.0799151062965393 0.4856320917606354 0.6073989272117615 <_> <_> <_>0 3 6 13 -1. <_>3 3 3 13 2. 0 -0.0794410929083824 0.8394674062728882 0.4624533057212830 <_> <_> <_>9 1 4 1 -1. <_>9 1 2 1 2. 0 -5.2800010889768600e-003 0.1881695985794067 0.5306698083877564 <_> <_> <_>8 0 2 1 -1. <_>9 0 1 1 2. 0 1.0463109938427806e-003 0.5271229147911072 0.2583065927028656 <_> <_> <_>10 16 4 4 -1. <_>12 16 2 2 2. <_>10 18 2 2 2. 0 2.6317298761568964e-004 0.4235304892063141 0.5735440850257874 <_> <_> <_>9 6 2 3 -1. <_>10 6 1 3 2. 0 -3.6173160187900066e-003 0.6934396028518677 0.4495444893836975 <_> <_> <_>4 5 12 2 -1. <_>8 5 4 2 3. 0 0.0114218797534704 0.5900921225547791 0.4138193130493164 <_> <_> <_>8 7 3 5 -1. <_>9 7 1 5 3. 0 -1.9963278900831938e-003 0.6466382741928101 0.4327239990234375 24.5278797149658200 6 -1 <_> <_> <_> <_>6 4 8 6 -1. <_>6 6 8 2 3. 0 -9.9691245704889297e-003 0.6142324209213257 0.2482212036848068 <_> <_> <_>9 5 2 12 -1. <_>9 11 2 6 2. 0 7.3073059320449829e-004 0.5704951882362366 0.2321965992450714 <_> <_> <_>4 6 6 8 -1. <_>4 10 6 4 2. 0 6.4045301405712962e-004 0.2112251967191696 0.5814933180809021 <_> <_> <_>12 2 8 5 -1. <_>12 2 4 5 2. 0 4.5424019917845726e-003 0.2950482070446014 0.5866311788558960 <_> <_> <_>0 8 18 3 -1. <_>0 9 18 1 3. 0 9.2477443104144186e-005 0.2990990877151489 0.5791326761245728 <_> <_> <_>8 12 4 8 -1. <_>8 16 4 4 2. 0 -8.6603146046400070e-003 0.2813029885292053 0.5635542273521423 <_> <_> <_>0 2 8 5 -1. <_>4 2 4 5 2. 0 8.0515816807746887e-003 0.3535369038581848 0.6054757237434387 <_> <_> <_>13 11 3 4 -1. <_>13 13 3 2 2. 0 4.3835240649059415e-004 0.5596532225608826 0.2731510996818543 <_> <_> <_>5 11 6 1 -1. <_>7 11 2 1 3. 0 -9.8168973636347800e-005 0.5978031754493713 0.3638561069965363 <_> <_> <_>11 3 3 1 -1. <_>12 3 1 1 3. 0 -1.1298790341243148e-003 0.2755252122879028 0.5432729125022888 <_> <_> <_>7 13 5 3 -1. <_>7 14 5 1 3. 0 6.4356150105595589e-003 0.4305641949176788 0.7069833278656006 <_> <_> <_>11 11 7 6 -1. <_>11 14 7 3 2. 0 -0.0568293295800686 0.2495242953300476 0.5294997096061707 <_> <_> <_>2 11 7 6 -1. <_>2 14 7 3 2. 0 4.0668169967830181e-003 0.5478553175926209 0.2497723996639252 <_> <_> <_>12 14 2 6 -1. <_>12 16 2 2 3. 0 4.8164798499783501e-005 0.3938601016998291 0.5706356167793274 <_> <_> <_>8 14 3 3 -1. <_>8 15 3 1 3. 0 6.1795017682015896e-003 0.4407606124877930 0.7394766807556152 <_> <_> <_>11 0 3 5 -1. <_>12 0 1 5 3. 0 6.4985752105712891e-003 0.5445243120193481 0.2479152977466583 <_> <_> <_>6 1 4 9 -1. <_>8 1 2 9 2. 0 -1.0211090557277203e-003 0.2544766962528229 0.5338971018791199 <_> <_> <_>10 3 6 1 -1. <_>12 3 2 1 3. 0 -5.4247528314590454e-003 0.2718858122825623 0.5324069261550903 <_> <_> <_>8 8 3 4 -1. <_>8 10 3 2 2. 0 -1.0559899965301156e-003 0.3178288042545319 0.5534508824348450 <_> <_> <_>8 12 4 2 -1. <_>8 13 4 1 2. 0 6.6465808777138591e-004 0.4284219145774841 0.6558194160461426 <_> <_> <_>5 18 4 2 -1. <_>5 19 4 1 2. 0 -2.7524109464138746e-004 0.5902860760688782 0.3810262978076935 <_> <_> <_>2 1 18 6 -1. <_>2 3 18 2 3. 0 4.2293202131986618e-003 0.3816489875316620 0.5709385871887207 <_> <_> <_>6 0 3 2 -1. <_>7 0 1 2 3. 0 -3.2868210691958666e-003 0.1747743934392929 0.5259544253349304 <_> <_> <_>13 8 6 2 -1. <_>16 8 3 1 2. <_>13 9 3 1 2. 0 1.5611879643984139e-004 0.3601722121238709 0.5725612044334412 <_> <_> <_>6 10 3 6 -1. <_>6 13 3 3 2. 0 -7.3621381488919724e-006 0.5401858091354370 0.3044497072696686 <_> <_> <_>0 13 20 4 -1. <_>10 13 10 2 2. <_>0 15 10 2 2. 0 -0.0147672500461340 0.3220770061016083 0.5573434829711914 <_> <_> <_>7 7 6 5 -1. <_>9 7 2 5 3. 0 0.0244895908981562 0.4301528036594391 0.6518812775611877 <_> <_> <_>11 0 2 2 -1. <_>11 1 2 1 2. 0 -3.7652091123163700e-004 0.3564583063125610 0.5598236918449402 <_> <_> <_>1 8 6 2 -1. <_>1 8 3 1 2. <_>4 9 3 1 2. 0 7.3657688517414499e-006 0.3490782976150513 0.5561897754669190 <_> <_> <_>0 2 20 2 -1. <_>10 2 10 1 2. <_>0 3 10 1 2. 0 -0.0150999398902059 0.1776272058486939 0.5335299968719482 <_> <_> <_>7 14 5 3 -1. <_>7 15 5 1 3. 0 -3.8316650316119194e-003 0.6149687767028809 0.4221394062042236 <_> <_> <_>7 13 6 6 -1. <_>10 13 3 3 2. <_>7 16 3 3 2. 0 0.0169254001230001 0.5413014888763428 0.2166585028171539 <_> <_> <_>9 12 2 3 -1. <_>9 13 2 1 3. 0 -3.0477850232273340e-003 0.6449490785598755 0.4354617893695831 <_> <_> <_>16 11 1 6 -1. <_>16 13 1 2 3. 0 3.2140589319169521e-003 0.5400155186653137 0.3523217141628265 <_> <_> <_>3 11 1 6 -1. <_>3 13 1 2 3. 0 -4.0023201145231724e-003 0.2774524092674255 0.5338417291641235 <_> <_> <_>4 4 14 12 -1. <_>11 4 7 6 2. <_>4 10 7 6 2. 0 7.4182129465043545e-003 0.5676739215850830 0.3702817857265472 <_> <_> <_>5 4 3 3 -1. <_>5 5 3 1 3. 0 -8.8764587417244911e-003 0.7749221920967102 0.4583688974380493 <_> <_> <_>12 3 3 3 -1. <_>13 3 1 3 3. 0 2.7311739977449179e-003 0.5338721871376038 0.3996661007404327 <_> <_> <_>6 6 8 3 -1. <_>6 7 8 1 3. 0 -2.5082379579544067e-003 0.5611963272094727 0.3777498900890350 <_> <_> <_>12 3 3 3 -1. <_>13 3 1 3 3. 0 -8.0541074275970459e-003 0.2915228903293610 0.5179182887077332 <_> <_> <_>3 1 4 10 -1. <_>3 1 2 5 2. <_>5 6 2 5 2. 0 -9.7938813269138336e-004 0.5536432862281799 0.3700192868709564 <_> <_> <_>5 7 10 2 -1. <_>5 7 5 2 2. 0 -5.8745909482240677e-003 0.3754391074180603 0.5679376125335693 <_> <_> <_>8 7 3 3 -1. <_>9 7 1 3 3. 0 -4.4936719350516796e-003 0.7019699215888977 0.4480949938297272 <_> <_> <_>15 12 2 3 -1. <_>15 13 2 1 3. 0 -5.4389229044318199e-003 0.2310364991426468 0.5313386917114258 <_> <_> <_>7 8 3 4 -1. <_>8 8 1 4 3. 0 -7.5094640487805009e-004 0.5864868760108948 0.4129343032836914 <_> <_> <_>13 4 1 12 -1. <_>13 10 1 6 2. 0 1.4528800420521293e-005 0.3732407093048096 0.5619621276855469 <_> <_> <_>4 5 12 12 -1. <_>4 5 6 6 2. <_>10 11 6 6 2. 0 0.0407580696046352 0.5312091112136841 0.2720521986484528 <_> <_> <_>7 14 7 3 -1. <_>7 15 7 1 3. 0 6.6505931317806244e-003 0.4710015952587128 0.6693493723869324 <_> <_> <_>3 12 2 3 -1. <_>3 13 2 1 3. 0 4.5759351924061775e-003 0.5167819261550903 0.1637275964021683 <_> <_> <_>3 2 14 2 -1. <_>10 2 7 1 2. <_>3 3 7 1 2. 0 6.5269311890006065e-003 0.5397608876228333 0.2938531935214996 <_> <_> <_>0 1 3 10 -1. <_>1 1 1 10 3. 0 -0.0136603796854615 0.7086488008499146 0.4532200098037720 <_> <_> <_>9 0 6 5 -1. <_>11 0 2 5 3. 0 0.0273588690906763 0.5206481218338013 0.3589231967926025 <_> <_> <_>5 7 6 2 -1. <_>8 7 3 2 2. 0 6.2197551596909761e-004 0.3507075905799866 0.5441123247146606 <_> <_> <_>7 1 6 10 -1. <_>7 6 6 5 2. 0 -3.3077080734074116e-003 0.5859522819519043 0.4024891853332520 <_> <_> <_>1 1 18 3 -1. <_>7 1 6 3 3. 0 -0.0106311095878482 0.6743267178535461 0.4422602951526642 <_> <_> <_>16 3 3 6 -1. <_>16 5 3 2 3. 0 0.0194416493177414 0.5282716155052185 0.1797904968261719 27.1533508300781250 7 -1 <_> <_> <_> <_>6 3 7 6 -1. <_>6 6 7 3 2. 0 -5.5052167735993862e-003 0.5914731025695801 0.2626559138298035 <_> <_> <_>4 7 12 2 -1. <_>8 7 4 2 3. 0 1.9562279339879751e-003 0.2312581986188889 0.5741627216339111 <_> <_> <_>0 4 17 10 -1. <_>0 9 17 5 2. 0 -8.8924784213304520e-003 0.1656530052423477 0.5626654028892517 <_> <_> <_>3 4 15 16 -1. <_>3 12 15 8 2. 0 0.0836383774876595 0.5423449873924255 0.1957294940948486 <_> <_> <_>7 15 6 4 -1. <_>7 17 6 2 2. 0 1.2282270472496748e-003 0.3417904078960419 0.5992503762245178 <_> <_> <_>15 2 4 9 -1. <_>15 2 2 9 2. 0 5.7629169896245003e-003 0.3719581961631775 0.6079903841018677 <_> <_> <_>2 3 3 2 -1. <_>2 4 3 1 2. 0 -1.6417410224676132e-003 0.2577486038208008 0.5576915740966797 <_> <_> <_>13 6 7 9 -1. <_>13 9 7 3 3. 0 3.4113149158656597e-003 0.2950749099254608 0.5514171719551086 <_> <_> <_>8 11 4 3 -1. <_>8 12 4 1 3. 0 -0.0110693201422691 0.7569358944892883 0.4477078914642334 <_> <_> <_>0 2 20 6 -1. <_>10 2 10 3 2. <_>0 5 10 3 2. 0 0.0348659716546535 0.5583708882331848 0.2669621109962463 <_> <_> <_>3 2 6 10 -1. <_>3 2 3 5 2. <_>6 7 3 5 2. 0 6.5701099811121821e-004 0.5627313256263733 0.2988890111446381 <_> <_> <_>13 10 3 4 -1. <_>13 12 3 2 2. 0 -0.0243391301482916 0.2771185040473938 0.5108863115310669 <_> <_> <_>4 10 3 4 -1. <_>4 12 3 2 2. 0 5.9435202274471521e-004 0.5580651760101318 0.3120341897010803 <_> <_> <_>7 5 6 3 -1. <_>9 5 2 3 3. 0 2.2971509024500847e-003 0.3330250084400177 0.5679075717926025 <_> <_> <_>7 6 6 8 -1. <_>7 10 6 4 2. 0 -3.7801829166710377e-003 0.2990534901618958 0.5344808101654053 <_> <_> <_>0 11 20 6 -1. <_>0 14 20 3 2. 0 -0.1342066973447800 0.1463858932256699 0.5392568111419678 <_> <_> <_>4 13 4 6 -1. <_>4 13 2 3 2. <_>6 16 2 3 2. 0 7.5224548345431685e-004 0.3746953904628754 0.5692734718322754 <_> <_> <_>6 0 8 12 -1. <_>10 0 4 6 2. <_>6 6 4 6 2. 0 -0.0405455417931080 0.2754747867584229 0.5484297871589661 <_> <_> <_>2 0 15 2 -1. <_>2 1 15 1 2. 0 1.2572970008477569e-003 0.3744584023952484 0.5756075978279114 <_> <_> <_>9 12 2 3 -1. <_>9 13 2 1 3. 0 -7.4249948374927044e-003 0.7513859272003174 0.4728231132030487 <_> <_> <_>3 12 1 2 -1. <_>3 13 1 1 2. 0 5.0908129196614027e-004 0.5404896736145020 0.2932321131229401 <_> <_> <_>9 11 2 3 -1. <_>9 12 2 1 3. 0 -1.2808450264856219e-003 0.6169779896736145 0.4273349046707153 <_> <_> <_>7 3 3 1 -1. <_>8 3 1 1 3. 0 -1.8348860321566463e-003 0.2048496007919312 0.5206472277641296 <_> <_> <_>17 7 3 6 -1. <_>17 9 3 2 3. 0 0.0274848695844412 0.5252984762191773 0.1675522029399872 <_> <_> <_>7 2 3 2 -1. <_>8 2 1 2 3. 0 2.2372419480234385e-003 0.5267782807350159 0.2777658104896545 <_> <_> <_>11 4 5 3 -1. <_>11 5 5 1 3. 0 -8.8635291904211044e-003 0.6954557895660400 0.4812048971652985 <_> <_> <_>4 4 5 3 -1. <_>4 5 5 1 3. 0 4.1753971017897129e-003 0.4291887879371643 0.6349195837974548 <_> <_> <_>19 3 1 2 -1. <_>19 4 1 1 2. 0 -1.7098189564421773e-003 0.2930536866188049 0.5361248850822449 <_> <_> <_>5 5 4 3 -1. <_>5 6 4 1 3. 0 6.5328548662364483e-003 0.4495325088500977 0.7409694194793701 <_> <_> <_>17 7 3 6 -1. <_>17 9 3 2 3. 0 -9.5372907817363739e-003 0.3149119913578033 0.5416501760482788 <_> <_> <_>0 7 3 6 -1. <_>0 9 3 2 3. 0 0.0253109894692898 0.5121892094612122 0.1311707943677902 <_> <_> <_>14 2 6 9 -1. <_>14 5 6 3 3. 0 0.0364609695971012 0.5175911784172058 0.2591339945793152 <_> <_> <_>0 4 5 6 -1. <_>0 6 5 2 3. 0 0.0208543296903372 0.5137140154838562 0.1582316011190414 <_> <_> <_>10 5 6 2 -1. <_>12 5 2 2 3. 0 -8.7207747856155038e-004 0.5574309825897217 0.4398978948593140 <_> <_> <_>4 5 6 2 -1. <_>6 5 2 2 3. 0 -1.5227000403683633e-005 0.5548940896987915 0.3708069920539856 <_> <_> <_>8 1 4 6 -1. <_>8 3 4 2 3. 0 -8.4316509310156107e-004 0.3387419879436493 0.5554211139678955 <_> <_> <_>0 2 3 6 -1. <_>0 4 3 2 3. 0 3.6037859972566366e-003 0.5358061790466309 0.3411171138286591 <_> <_> <_>6 6 8 3 -1. <_>6 7 8 1 3. 0 -6.8057891912758350e-003 0.6125202775001526 0.4345862865447998 <_> <_> <_>0 1 5 9 -1. <_>0 4 5 3 3. 0 -0.0470216609537601 0.2358165979385376 0.5193738937377930 <_> <_> <_>16 0 4 15 -1. <_>16 0 2 15 2. 0 -0.0369541086256504 0.7323111295700073 0.4760943949222565 <_> <_> <_>1 10 3 2 -1. <_>1 11 3 1 2. 0 1.0439479956403375e-003 0.5419455170631409 0.3411330878734589 <_> <_> <_>14 4 1 10 -1. <_>14 9 1 5 2. 0 -2.1050689974799752e-004 0.2821694016456604 0.5554947257041931 <_> <_> <_>0 1 4 12 -1. <_>2 1 2 12 2. 0 -0.0808315873146057 0.9129930138587952 0.4697434902191162 <_> <_> <_>11 11 4 2 -1. <_>11 11 2 2 2. 0 -3.6579059087671340e-004 0.6022670269012451 0.3978292942047119 <_> <_> <_>5 11 4 2 -1. <_>7 11 2 2 2. 0 -1.2545920617412776e-004 0.5613213181495667 0.3845539987087250 <_> <_> <_>3 8 15 5 -1. <_>8 8 5 5 3. 0 -0.0687864869832993 0.2261611968278885 0.5300496816635132 <_> <_> <_>0 0 6 10 -1. <_>3 0 3 10 2. 0 0.0124157899990678 0.4075691998004913 0.5828812122344971 <_> <_> <_>11 4 3 2 -1. <_>12 4 1 2 3. 0 -4.7174817882478237e-003 0.2827253937721252 0.5267757773399353 <_> <_> <_>8 12 3 8 -1. <_>8 16 3 4 2. 0 0.0381368584930897 0.5074741244316101 0.1023615971207619 <_> <_> <_>8 14 5 3 -1. <_>8 15 5 1 3. 0 -2.8168049175292253e-003 0.6169006824493408 0.4359692931175232 <_> <_> <_>7 14 4 3 -1. <_>7 15 4 1 3. 0 8.1303603947162628e-003 0.4524433016777039 0.7606095075607300 <_> <_> <_>11 4 3 2 -1. <_>12 4 1 2 3. 0 6.0056019574403763e-003 0.5240408778190613 0.1859712004661560 <_> <_> <_>3 15 14 4 -1. <_>3 15 7 2 2. <_>10 17 7 2 2. 0 0.0191393196582794 0.5209379196166992 0.2332071959972382 <_> <_> <_>2 2 16 4 -1. <_>10 2 8 2 2. <_>2 4 8 2 2. 0 0.0164457596838474 0.5450702905654907 0.3264234960079193 <_> <_> <_>0 8 6 12 -1. <_>3 8 3 12 2. 0 -0.0373568907380104 0.6999046802520752 0.4533241987228394 <_> <_> <_>5 7 10 2 -1. <_>5 7 5 2 2. 0 -0.0197279006242752 0.2653664946556091 0.5412809848785400 <_> <_> <_>9 7 2 5 -1. <_>10 7 1 5 2. 0 6.6972579807043076e-003 0.4480566084384918 0.7138652205467224 <_> <_> <_>13 7 6 4 -1. <_>16 7 3 2 2. <_>13 9 3 2 2. 0 7.4457528535276651e-004 0.4231350123882294 0.5471320152282715 <_> <_> <_>0 13 8 2 -1. <_>0 14 8 1 2. 0 1.1790640419349074e-003 0.5341702103614807 0.3130455017089844 <_> <_> <_>13 7 6 4 -1. <_>16 7 3 2 2. <_>13 9 3 2 2. 0 0.0349806100130081 0.5118659734725952 0.3430530130863190 <_> <_> <_>1 7 6 4 -1. <_>1 7 3 2 2. <_>4 9 3 2 2. 0 5.6859792675822973e-004 0.3532187044620514 0.5468639731407166 <_> <_> <_>12 6 1 12 -1. <_>12 12 1 6 2. 0 -0.0113406497985125 0.2842353880405426 0.5348700881004334 <_> <_> <_>9 5 2 6 -1. <_>10 5 1 6 2. 0 -6.6228108480572701e-003 0.6883640289306641 0.4492664933204651 <_> <_> <_>14 12 2 3 -1. <_>14 13 2 1 3. 0 -8.0160330981016159e-003 0.1709893941879273 0.5224308967590332 <_> <_> <_>4 12 2 3 -1. <_>4 13 2 1 3. 0 1.4206819469109178e-003 0.5290846228599548 0.2993383109569550 <_> <_> <_>8 12 4 3 -1. <_>8 13 4 1 3. 0 -2.7801711112260818e-003 0.6498854160308838 0.4460499882698059 <_> <_> <_>5 2 2 4 -1. <_>5 2 1 2 2. <_>6 4 1 2 2. 0 -1.4747589593753219e-003 0.3260438144207001 0.5388113260269165 <_> <_> <_>5 5 11 3 -1. <_>5 6 11 1 3. 0 -0.0238303393125534 0.7528941035270691 0.4801219999790192 <_> <_> <_>7 6 4 12 -1. <_>7 12 4 6 2. 0 6.9369790144264698e-003 0.5335165858268738 0.3261427879333496 <_> <_> <_>12 13 8 5 -1. <_>12 13 4 5 2. 0 8.2806255668401718e-003 0.4580394029617310 0.5737829804420471 <_> <_> <_>7 6 1 12 -1. <_>7 12 1 6 2. 0 -0.0104395002126694 0.2592320144176483 0.5233827829360962 34.5541114807128910 8 -1 <_> <_> <_> <_>1 2 6 3 -1. <_>4 2 3 3 2. 0 7.2006587870419025e-003 0.3258886039257050 0.6849808096885681 <_> <_> <_>9 5 6 10 -1. <_>12 5 3 5 2. <_>9 10 3 5 2. 0 -2.8593589086085558e-003 0.5838881134986877 0.2537829875946045 <_> <_> <_>5 5 8 12 -1. <_>5 5 4 6 2. <_>9 11 4 6 2. 0 6.8580528022721410e-004 0.5708081722259522 0.2812424004077911 <_> <_> <_>0 7 20 6 -1. <_>0 9 20 2 3. 0 7.9580191522836685e-003 0.2501051127910614 0.5544260740280151 <_> <_> <_>4 2 2 2 -1. <_>4 3 2 1 2. 0 -1.2124150525778532e-003 0.2385368049144745 0.5433350205421448 <_> <_> <_>4 18 12 2 -1. <_>8 18 4 2 3. 0 7.9426132142543793e-003 0.3955070972442627 0.6220757961273193 <_> <_> <_>7 4 4 16 -1. <_>7 12 4 8 2. 0 2.4630590341985226e-003 0.5639708042144775 0.2992357909679413 <_> <_> <_>7 6 7 8 -1. <_>7 10 7 4 2. 0 -6.0396599583327770e-003 0.2186512947082520 0.5411676764488220 <_> <_> <_>6 3 3 1 -1. <_>7 3 1 1 3. 0 -1.2988339876756072e-003 0.2350706011056900 0.5364584922790527 <_> <_> <_>11 15 2 4 -1. <_>11 17 2 2 2. 0 2.2299369447864592e-004 0.3804112970829010 0.5729606151580811 <_> <_> <_>3 5 4 8 -1. <_>3 9 4 4 2. 0 1.4654280385002494e-003 0.2510167956352234 0.5258268713951111 <_> <_> <_>7 1 6 12 -1. <_>7 7 6 6 2. 0 -8.1210042117163539e-004 0.5992823839187622 0.3851158916950226 <_> <_> <_>4 6 6 2 -1. <_>6 6 2 2 3. 0 -1.3836020370945334e-003 0.5681396126747131 0.3636586964130402 <_> <_> <_>16 4 4 6 -1. <_>16 6 4 2 3. 0 -0.0279364492744207 0.1491317003965378 0.5377560257911682 <_> <_> <_>3 3 5 2 -1. <_>3 4 5 1 2. 0 -4.6919551095925272e-004 0.3692429959774017 0.5572484731674194 <_> <_> <_>9 11 2 3 -1. <_>9 12 2 1 3. 0 -4.9829659983515739e-003 0.6758509278297424 0.4532504081726074 <_> <_> <_>2 16 4 2 -1. <_>2 17 4 1 2. 0 1.8815309740602970e-003 0.5368022918701172 0.2932539880275726 <_> <_> <_>7 13 6 6 -1. <_>10 13 3 3 2. <_>7 16 3 3 2. 0 -0.0190675500780344 0.1649377048015595 0.5330067276954651 <_> <_> <_>7 0 3 4 -1. <_>8 0 1 4 3. 0 -4.6906559728085995e-003 0.1963925957679749 0.5119361877441406 <_> <_> <_>8 15 4 3 -1. <_>8 16 4 1 3. 0 5.9777139686048031e-003 0.4671171903610230 0.7008398175239563 <_> <_> <_>0 4 4 6 -1. <_>0 6 4 2 3. 0 -0.0333031304180622 0.1155416965484619 0.5104162096977234 <_> <_> <_>5 6 12 3 -1. <_>9 6 4 3 3. 0 0.0907441079616547 0.5149660110473633 0.1306173056364059 <_> <_> <_>7 6 6 14 -1. <_>9 6 2 14 3. 0 9.3555898638442159e-004 0.3605481088161469 0.5439859032630920 <_> <_> <_>9 7 3 3 -1. <_>10 7 1 3 3. 0 0.0149016501381993 0.4886212050914764 0.7687569856643677 <_> <_> <_>6 12 2 4 -1. <_>6 14 2 2 2. 0 6.1594118596985936e-004 0.5356813073158264 0.3240939080715179 <_> <_> <_>10 12 7 6 -1. <_>10 14 7 2 3. 0 -0.0506709888577461 0.1848621964454651 0.5230404138565064 <_> <_> <_>1 0 15 2 -1. <_>1 1 15 1 2. 0 6.8665749859064817e-004 0.3840579986572266 0.5517945885658264 <_> <_> <_>14 0 6 6 -1. <_>14 0 3 6 2. 0 8.3712432533502579e-003 0.4288564026355743 0.6131753921508789 <_> <_> <_>5 3 3 1 -1. <_>6 3 1 1 3. 0 -1.2953069526702166e-003 0.2913674116134644 0.5280737876892090 <_> <_> <_>14 0 6 6 -1. <_>14 0 3 6 2. 0 -0.0419416800141335 0.7554799914360046 0.4856030941009522 <_> <_> <_>0 3 20 10 -1. <_>0 8 20 5 2. 0 -0.0235293805599213 0.2838279902935028 0.5256081223487854 <_> <_> <_>14 0 6 6 -1. <_>14 0 3 6 2. 0 0.0408574491739273 0.4870935082435608 0.6277297139167786 <_> <_> <_>0 0 6 6 -1. <_>3 0 3 6 2. 0 -0.0254068691283464 0.7099707722663879 0.4575029015541077 <_> <_> <_>19 15 1 2 -1. <_>19 16 1 1 2. 0 -4.1415440500713885e-004 0.4030886888504028 0.5469412207603455 <_> <_> <_>0 2 4 8 -1. <_>2 2 2 8 2. 0 0.0218241196125746 0.4502024054527283 0.6768701076507568 <_> <_> <_>2 1 18 4 -1. <_>11 1 9 2 2. <_>2 3 9 2 2. 0 0.0141140399500728 0.5442860722541809 0.3791700005531311 <_> <_> <_>8 12 1 2 -1. <_>8 13 1 1 2. 0 6.7214590671937913e-005 0.4200463891029358 0.5873476266860962 <_> <_> <_>5 2 10 6 -1. <_>10 2 5 3 2. <_>5 5 5 3 2. 0 -7.9417638480663300e-003 0.3792561888694763 0.5585265755653381 <_> <_> <_>9 7 2 4 -1. <_>10 7 1 4 2. 0 -7.2144409641623497e-003 0.7253103852272034 0.4603548943996429 <_> <_> <_>9 7 3 3 -1. <_>10 7 1 3 3. 0 2.5817339774221182e-003 0.4693301916122437 0.5900238752365112 <_> <_> <_>4 5 12 8 -1. <_>8 5 4 8 3. 0 0.1340931951999664 0.5149213075637817 0.1808844953775406 <_> <_> <_>15 15 4 3 -1. <_>15 16 4 1 3. 0 2.2962710354477167e-003 0.5399743914604187 0.3717867136001587 <_> <_> <_>8 18 3 1 -1. <_>9 18 1 1 3. 0 -2.1575849968940020e-003 0.2408495992422104 0.5148863792419434 <_> <_> <_>9 13 4 3 -1. <_>9 14 4 1 3. 0 -4.9196188338100910e-003 0.6573588252067566 0.4738740026950836 <_> <_> <_>7 13 4 3 -1. <_>7 14 4 1 3. 0 1.6267469618469477e-003 0.4192821979522705 0.6303114295005798 <_> <_> <_>19 15 1 2 -1. <_>19 16 1 1 2. 0 3.3413388882763684e-004 0.5540298223495483 0.3702101111412048 <_> <_> <_>0 15 8 4 -1. <_>0 17 8 2 2. 0 -0.0266980808228254 0.1710917949676514 0.5101410746574402 <_> <_> <_>9 3 6 4 -1. <_>11 3 2 4 3. 0 -0.0305618792772293 0.1904218047857285 0.5168793797492981 <_> <_> <_>8 14 4 3 -1. <_>8 15 4 1 3. 0 2.8511548880487680e-003 0.4447506964206696 0.6313853859901428 <_> <_> <_>3 14 14 6 -1. <_>3 16 14 2 3. 0 -0.0362114794552326 0.2490727007389069 0.5377349257469177 <_> <_> <_>6 3 6 6 -1. <_>6 6 6 3 2. 0 -2.4115189444273710e-003 0.5381243228912354 0.3664236962795258 <_> <_> <_>5 11 10 6 -1. <_>5 14 10 3 2. 0 -7.7253201743587852e-004 0.5530232191085815 0.3541550040245056 <_> <_> <_>3 10 3 4 -1. <_>4 10 1 4 3. 0 2.9481729143299162e-004 0.4132699072360992 0.5667243003845215 <_> <_> <_>13 9 2 2 -1. <_>13 9 1 2 2. 0 -6.2334560789167881e-003 0.0987872332334518 0.5198668837547302 <_> <_> <_>5 3 6 4 -1. <_>7 3 2 4 3. 0 -0.0262747295200825 0.0911274924874306 0.5028107166290283 <_> <_> <_>9 7 3 3 -1. <_>10 7 1 3 3. 0 5.3212260827422142e-003 0.4726648926734924 0.6222720742225647 <_> <_> <_>2 12 2 3 -1. <_>2 13 2 1 3. 0 -4.1129058226943016e-003 0.2157457023859024 0.5137804746627808 <_> <_> <_>9 8 3 12 -1. <_>9 12 3 4 3. 0 3.2457809429615736e-003 0.5410770773887634 0.3721776902675629 <_> <_> <_>3 14 4 6 -1. <_>3 14 2 3 2. <_>5 17 2 3 2. 0 -0.0163597092032433 0.7787874937057495 0.4685291945934296 <_> <_> <_>16 15 2 2 -1. <_>16 16 2 1 2. 0 3.2166109303943813e-004 0.5478987097740173 0.4240373969078064 <_> <_> <_>2 15 2 2 -1. <_>2 16 2 1 2. 0 6.4452440710738301e-004 0.5330560803413391 0.3501324951648712 <_> <_> <_>8 12 4 3 -1. <_>8 13 4 1 3. 0 -7.8909732401371002e-003 0.6923521161079407 0.4726569056510925 <_> <_> <_>0 7 20 1 -1. <_>10 7 10 1 2. 0 0.0483362115919590 0.5055900216102600 0.0757492035627365 <_> <_> <_>7 6 8 3 -1. <_>7 6 4 3 2. 0 -7.5178127735853195e-004 0.3783741891384125 0.5538573861122131 <_> <_> <_>5 7 8 2 -1. <_>9 7 4 2 2. 0 -2.4953910615295172e-003 0.3081651031970978 0.5359612107276917 <_> <_> <_>9 7 3 5 -1. <_>10 7 1 5 3. 0 -2.2385010961443186e-003 0.6633958816528320 0.4649342894554138 <_> <_> <_>8 7 3 5 -1. <_>9 7 1 5 3. 0 -1.7988430336117744e-003 0.6596844792366028 0.4347187876701355 <_> <_> <_>11 1 3 5 -1. <_>12 1 1 5 3. 0 8.7860915809869766e-003 0.5231832861900330 0.2315579950809479 <_> <_> <_>6 2 3 6 -1. <_>7 2 1 6 3. 0 3.6715380847454071e-003 0.5204250216484070 0.2977376878261566 <_> <_> <_>14 14 6 5 -1. <_>14 14 3 5 2. 0 -0.0353364497423172 0.7238878011703491 0.4861505031585693 <_> <_> <_>9 8 2 2 -1. <_>9 9 2 1 2. 0 -6.9189240457490087e-004 0.3105022013187408 0.5229824781417847 <_> <_> <_>10 7 1 3 -1. <_>10 8 1 1 3. 0 -3.3946109469980001e-003 0.3138968050479889 0.5210173726081848 <_> <_> <_>6 6 2 2 -1. <_>6 6 1 1 2. <_>7 7 1 1 2. 0 9.8569283727556467e-004 0.4536580145359039 0.6585097908973694 <_> <_> <_>2 11 18 4 -1. <_>11 11 9 2 2. <_>2 13 9 2 2. 0 -0.0501631014049053 0.1804454028606415 0.5198916792869568 <_> <_> <_>6 6 2 2 -1. <_>6 6 1 1 2. <_>7 7 1 1 2. 0 -2.2367259953171015e-003 0.7255702018737793 0.4651359021663666 <_> <_> <_>0 15 20 2 -1. <_>0 16 20 1 2. 0 7.4326287722215056e-004 0.4412921071052551 0.5898545980453491 <_> <_> <_>4 14 2 3 -1. <_>4 15 2 1 3. 0 -9.3485182151198387e-004 0.3500052988529205 0.5366017818450928 <_> <_> <_>8 14 4 3 -1. <_>8 15 4 1 3. 0 0.0174979399889708 0.4912194907665253 0.8315284848213196 <_> <_> <_>8 7 2 3 -1. <_>8 8 2 1 3. 0 -1.5200000489130616e-003 0.3570275902748108 0.5370560288429260 <_> <_> <_>9 10 2 3 -1. <_>9 11 2 1 3. 0 7.8003940870985389e-004 0.4353772103786469 0.5967335104942322 39.1072883605957030 9 -1 <_> <_> <_> <_>5 4 10 4 -1. <_>5 6 10 2 2. 0 -9.9945552647113800e-003 0.6162583231925964 0.3054533004760742 <_> <_> <_>9 7 6 4 -1. <_>12 7 3 2 2. <_>9 9 3 2 2. 0 -1.1085229925811291e-003 0.5818294882774353 0.3155578076839447 <_> <_> <_>4 7 3 6 -1. <_>4 9 3 2 3. 0 1.0364380432292819e-003 0.2552052140235901 0.5692911744117737 <_> <_> <_>11 15 4 4 -1. <_>13 15 2 2 2. <_>11 17 2 2 2. 0 6.8211311008781195e-004 0.3685089945793152 0.5934931039810181 <_> <_> <_>7 8 4 2 -1. <_>7 9 4 1 2. 0 -6.8057340104132891e-004 0.2332392036914825 0.5474792122840881 <_> <_> <_>13 1 4 3 -1. <_>13 1 2 3 2. 0 2.6068789884448051e-004 0.3257457017898560 0.5667545795440674 <_> <_> <_>5 15 4 4 -1. <_>5 15 2 2 2. <_>7 17 2 2 2. 0 5.1607372006401420e-004 0.3744716942310333 0.5845472812652588 <_> <_> <_>9 5 4 7 -1. <_>9 5 2 7 2. 0 8.5007521556690335e-004 0.3420371115207672 0.5522807240486145 <_> <_> <_>5 6 8 3 -1. <_>9 6 4 3 2. 0 -1.8607829697430134e-003 0.2804419994354248 0.5375424027442932 <_> <_> <_>9 9 2 2 -1. <_>9 10 2 1 2. 0 -1.5033970121294260e-003 0.2579050958156586 0.5498952269554138 <_> <_> <_>7 15 5 3 -1. <_>7 16 5 1 3. 0 2.3478909861296415e-003 0.4175156056880951 0.6313710808753967 <_> <_> <_>11 10 4 3 -1. <_>11 10 2 3 2. 0 -2.8880240279249847e-004 0.5865169763565064 0.4052666127681732 <_> <_> <_>6 9 8 10 -1. <_>6 14 8 5 2. 0 8.9405477046966553e-003 0.5211141109466553 0.2318654060363770 <_> <_> <_>10 11 6 2 -1. <_>10 11 3 2 2. 0 -0.0193277392536402 0.2753432989120483 0.5241525769233704 <_> <_> <_>4 11 6 2 -1. <_>7 11 3 2 2. 0 -2.0202060113660991e-004 0.5722978711128235 0.3677195906639099 <_> <_> <_>11 3 8 1 -1. <_>11 3 4 1 2. 0 2.1179069299250841e-003 0.4466108083724976 0.5542430877685547 <_> <_> <_>6 3 3 2 -1. <_>7 3 1 2 3. 0 -1.7743760254234076e-003 0.2813253104686737 0.5300959944725037 <_> <_> <_>14 5 6 5 -1. <_>14 5 3 5 2. 0 4.2234458960592747e-003 0.4399709999561310 0.5795428156852722 <_> <_> <_>7 5 2 12 -1. <_>7 11 2 6 2. 0 -0.0143752200528979 0.2981117963790894 0.5292059183120728 <_> <_> <_>8 11 4 3 -1. <_>8 12 4 1 3. 0 -0.0153491804376245 0.7705215215682983 0.4748171865940094 <_> <_> <_>4 1 2 3 -1. <_>5 1 1 3 2. 0 1.5152279956964776e-005 0.3718844056129456 0.5576897263526917 <_> <_> <_>18 3 2 6 -1. <_>18 5 2 2 3. 0 -9.1293919831514359e-003 0.3615196049213409 0.5286766886711121 <_> <_> <_>0 3 2 6 -1. <_>0 5 2 2 3. 0 2.2512159775942564e-003 0.5364704728126526 0.3486298024654388 <_> <_> <_>9 12 2 3 -1. <_>9 13 2 1 3. 0 -4.9696918576955795e-003 0.6927651762962341 0.4676836133003235 <_> <_> <_>7 13 4 3 -1. <_>7 14 4 1 3. 0 -0.0128290103748441 0.7712153792381287 0.4660735130310059 <_> <_> <_>18 0 2 6 -1. <_>18 2 2 2 3. 0 -9.3660065904259682e-003 0.3374983966350555 0.5351287722587585 <_> <_> <_>0 0 2 6 -1. <_>0 2 2 2 3. 0 3.2452319283038378e-003 0.5325189828872681 0.3289610147476196 <_> <_> <_>8 14 6 3 -1. <_>8 15 6 1 3. 0 -0.0117235602810979 0.6837652921676636 0.4754300117492676 <_> <_> <_>7 4 2 4 -1. <_>8 4 1 4 2. 0 2.9257940695970319e-005 0.3572087883949280 0.5360502004623413 <_> <_> <_>8 5 4 6 -1. <_>8 7 4 2 3. 0 -2.2244219508138485e-005 0.5541427135467529 0.3552064001560211 <_> <_> <_>6 4 2 2 -1. <_>7 4 1 2 2. 0 5.0881509669125080e-003 0.5070844292640686 0.1256462037563324 <_> <_> <_>3 14 14 4 -1. <_>10 14 7 2 2. <_>3 16 7 2 2. 0 0.0274296794086695 0.5269560217857361 0.1625818014144898 <_> <_> <_>6 15 6 2 -1. <_>6 15 3 1 2. <_>9 16 3 1 2. 0 -6.4142867922782898e-003 0.7145588994026184 0.4584197103977203 <_> <_> <_>14 15 6 2 -1. <_>14 16 6 1 2. 0 3.3479959238320589e-003 0.5398612022399902 0.3494696915149689 <_> <_> <_>2 12 12 8 -1. <_>2 16 12 4 2. 0 -0.0826354920864105 0.2439192980527878 0.5160226225852966 <_> <_> <_>7 7 7 2 -1. <_>7 8 7 1 2. 0 1.0261740535497665e-003 0.3886891901493073 0.5767908096313477 <_> <_> <_>0 2 18 2 -1. <_>0 3 18 1 2. 0 -1.6307090409100056e-003 0.3389458060264587 0.5347700715065002 <_> <_> <_>9 6 2 5 -1. <_>9 6 1 5 2. 0 2.4546680506318808e-003 0.4601413905620575 0.6387246847152710 <_> <_> <_>7 5 3 8 -1. <_>8 5 1 8 3. 0 -9.9476519972085953e-004 0.5769879221916199 0.4120396077632904 <_> <_> <_>9 6 3 4 -1. <_>10 6 1 4 3. 0 0.0154091902077198 0.4878709018230438 0.7089822292327881 <_> <_> <_>4 13 3 2 -1. <_>4 14 3 1 2. 0 1.1784400558099151e-003 0.5263553261756897 0.2895244956016541 <_> <_> <_>9 4 6 3 -1. <_>11 4 2 3 3. 0 -0.0277019198983908 0.1498828977346420 0.5219606757164002 <_> <_> <_>5 4 6 3 -1. <_>7 4 2 3 3. 0 -0.0295053999871016 0.0248933192342520 0.4999816119670868 <_> <_> <_>14 11 5 2 -1. <_>14 12 5 1 2. 0 4.5159430010244250e-004 0.5464622974395752 0.4029662907123566 <_> <_> <_>1 2 6 9 -1. <_>3 2 2 9 3. 0 7.1772639639675617e-003 0.4271056950092316 0.5866296887397766 <_> <_> <_>14 6 6 13 -1. <_>14 6 3 13 2. 0 -0.0741820484399796 0.6874179244041443 0.4919027984142304 <_> <_> <_>3 6 14 8 -1. <_>3 6 7 4 2. <_>10 10 7 4 2. 0 -0.0172541607171297 0.3370676040649414 0.5348739027976990 <_> <_> <_>16 0 4 11 -1. <_>16 0 2 11 2. 0 0.0148515598848462 0.4626792967319489 0.6129904985427856 <_> <_> <_>3 4 12 12 -1. <_>3 4 6 6 2. <_>9 10 6 6 2. 0 0.0100020002573729 0.5346122980117798 0.3423453867435455 <_> <_> <_>11 4 5 3 -1. <_>11 5 5 1 3. 0 2.0138120744377375e-003 0.4643830060958862 0.5824304223060608 <_> <_> <_>4 11 4 2 -1. <_>4 12 4 1 2. 0 1.5135470312088728e-003 0.5196396112442017 0.2856149971485138 <_> <_> <_>10 7 2 2 -1. <_>10 7 1 2 2. 0 3.1381431035697460e-003 0.4838162958621979 0.5958529710769653 <_> <_> <_>8 7 2 2 -1. <_>9 7 1 2 2. 0 -5.1450440660119057e-003 0.8920302987098694 0.4741412103176117 <_> <_> <_>9 17 3 2 -1. <_>10 17 1 2 3. 0 -4.4736708514392376e-003 0.2033942937850952 0.5337278842926025 <_> <_> <_>5 6 3 3 -1. <_>5 7 3 1 3. 0 1.9628470763564110e-003 0.4571633934974670 0.6725863218307495 <_> <_> <_>10 0 3 3 -1. <_>11 0 1 3 3. 0 5.4260450415313244e-003 0.5271108150482178 0.2845670878887177 <_> <_> <_>5 6 6 2 -1. <_>5 6 3 1 2. <_>8 7 3 1 2. 0 4.9611460417509079e-004 0.4138312935829163 0.5718597769737244 <_> <_> <_>12 16 4 3 -1. <_>12 17 4 1 3. 0 9.3728788197040558e-003 0.5225151181221008 0.2804847061634064 <_> <_> <_>3 12 3 2 -1. <_>3 13 3 1 2. 0 6.0500897234305739e-004 0.5236768722534180 0.3314523994922638 <_> <_> <_>9 12 3 2 -1. <_>9 13 3 1 2. 0 5.6792551185935736e-004 0.4531059861183167 0.6276971101760864 <_> <_> <_>1 11 16 4 -1. <_>1 11 8 2 2. <_>9 13 8 2 2. 0 0.0246443394571543 0.5130851864814758 0.2017143964767456 <_> <_> <_>12 4 3 3 -1. <_>12 5 3 1 3. 0 -0.0102904504165053 0.7786595225334168 0.4876641035079956 <_> <_> <_>4 4 5 3 -1. <_>4 5 5 1 3. 0 2.0629419013857841e-003 0.4288598895072937 0.5881264209747315 <_> <_> <_>12 16 4 3 -1. <_>12 17 4 1 3. 0 -5.0519481301307678e-003 0.3523977994918823 0.5286008715629578 <_> <_> <_>5 4 3 3 -1. <_>5 5 3 1 3. 0 -5.7692620903253555e-003 0.6841086149215698 0.4588094055652618 <_> <_> <_>9 0 2 2 -1. <_>9 1 2 1 2. 0 -4.5789941214025021e-004 0.3565520048141480 0.5485978126525879 <_> <_> <_>8 9 4 2 -1. <_>8 10 4 1 2. 0 -7.5918837683275342e-004 0.3368793129920960 0.5254197120666504 <_> <_> <_>8 8 4 3 -1. <_>8 9 4 1 3. 0 -1.7737259622663260e-003 0.3422161042690277 0.5454015135765076 <_> <_> <_>0 13 6 3 -1. <_>2 13 2 3 3. 0 -8.5610467940568924e-003 0.6533612012863159 0.4485856890678406 <_> <_> <_>16 14 3 2 -1. <_>16 15 3 1 2. 0 1.7277270089834929e-003 0.5307580232620239 0.3925352990627289 <_> <_> <_>1 18 18 2 -1. <_>7 18 6 2 3. 0 -0.0281996093690395 0.6857458949089050 0.4588584005832672 <_> <_> <_>16 14 3 2 -1. <_>16 15 3 1 2. 0 -1.7781109781935811e-003 0.4037851095199585 0.5369856953620911 <_> <_> <_>1 14 3 2 -1. <_>1 15 3 1 2. 0 3.3177141449414194e-004 0.5399798750877380 0.3705750107765198 <_> <_> <_>7 14 6 3 -1. <_>7 15 6 1 3. 0 2.6385399978607893e-003 0.4665437042713165 0.6452730894088745 <_> <_> <_>5 14 8 3 -1. <_>5 15 8 1 3. 0 -2.1183069329708815e-003 0.5914781093597412 0.4064677059650421 <_> <_> <_>10 6 4 14 -1. <_>10 6 2 14 2. 0 -0.0147732896730304 0.3642038106918335 0.5294762849807739 <_> <_> <_>6 6 4 14 -1. <_>8 6 2 14 2. 0 -0.0168154407292604 0.2664231956005096 0.5144972801208496 <_> <_> <_>13 5 2 3 -1. <_>13 6 2 1 3. 0 -6.3370140269398689e-003 0.6779531240463257 0.4852097928524017 <_> <_> <_>7 16 6 1 -1. <_>9 16 2 1 3. 0 -4.4560048991115764e-005 0.5613964796066284 0.4153054058551788 <_> <_> <_>9 12 3 3 -1. <_>9 13 3 1 3. 0 -1.0240620467811823e-003 0.5964478254318237 0.4566304087638855 <_> <_> <_>7 0 3 3 -1. <_>8 0 1 3 3. 0 -2.3161689750850201e-003 0.2976115047931671 0.5188159942626953 <_> <_> <_>4 0 16 18 -1. <_>4 9 16 9 2. 0 0.5321757197380066 0.5187839269638062 0.2202631980180740 <_> <_> <_>1 1 16 14 -1. <_>1 8 16 7 2. 0 -0.1664305031299591 0.1866022944450378 0.5060343146324158 <_> <_> <_>3 9 15 4 -1. <_>8 9 5 4 3. 0 0.1125352978706360 0.5212125182151794 0.1185022965073586 <_> <_> <_>6 12 7 3 -1. <_>6 13 7 1 3. 0 9.3046864494681358e-003 0.4589937031269074 0.6826149225234985 <_> <_> <_>14 15 2 3 -1. <_>14 16 2 1 3. 0 -4.6255099587142467e-003 0.3079940974712372 0.5225008726119995 <_> <_> <_>2 3 16 14 -1. <_>2 3 8 7 2. <_>10 10 8 7 2. 0 -0.1111646965146065 0.2101044058799744 0.5080801844596863 <_> <_> <_>16 2 4 18 -1. <_>18 2 2 9 2. <_>16 11 2 9 2. 0 -0.0108884396031499 0.5765355229377747 0.4790464043617249 <_> <_> <_>4 15 2 3 -1. <_>4 16 2 1 3. 0 5.8564301580190659e-003 0.5065100193023682 0.1563598960638046 <_> <_> <_>16 2 4 18 -1. <_>18 2 2 9 2. <_>16 11 2 9 2. 0 0.0548543892800808 0.4966914951801300 0.7230510711669922 <_> <_> <_>1 1 8 3 -1. <_>1 2 8 1 3. 0 -0.0111973397433758 0.2194979041814804 0.5098798274993897 <_> <_> <_>8 11 4 3 -1. <_>8 12 4 1 3. 0 4.4069071300327778e-003 0.4778401851654053 0.6770902872085571 <_> <_> <_>5 11 5 9 -1. <_>5 14 5 3 3. 0 -0.0636652931571007 0.1936362981796265 0.5081024169921875 <_> <_> <_>16 0 4 11 -1. <_>16 0 2 11 2. 0 -9.8081491887569427e-003 0.5999063253402710 0.4810341000556946 <_> <_> <_>7 0 6 1 -1. <_>9 0 2 1 3. 0 -2.1717099007219076e-003 0.3338333964347839 0.5235472917556763 <_> <_> <_>16 3 3 7 -1. <_>17 3 1 7 3. 0 -0.0133155202493072 0.6617069840431213 0.4919213056564331 <_> <_> <_>1 3 3 7 -1. <_>2 3 1 7 3. 0 2.5442079640924931e-003 0.4488744139671326 0.6082184910774231 <_> <_> <_>7 8 6 12 -1. <_>7 12 6 4 3. 0 0.0120378397405148 0.5409392118453980 0.3292432129383087 <_> <_> <_>0 0 4 11 -1. <_>2 0 2 11 2. 0 -0.0207010507583618 0.6819120049476624 0.4594995975494385 <_> <_> <_>14 0 6 20 -1. <_>14 0 3 20 2. 0 0.0276082791388035 0.4630792140960693 0.5767282843589783 <_> <_> <_>0 3 1 2 -1. <_>0 4 1 1 2. 0 1.2370620388537645e-003 0.5165379047393799 0.2635016143321991 <_> <_> <_>5 5 10 8 -1. <_>10 5 5 4 2. <_>5 9 5 4 2. 0 -0.0376693382859230 0.2536393105983734 0.5278980135917664 <_> <_> <_>4 7 12 4 -1. <_>4 7 6 2 2. <_>10 9 6 2 2. 0 -1.8057259730994701e-003 0.3985156118869782 0.5517500042915344 50.6104812622070310 10 -1 <_> <_> <_> <_>2 1 6 4 -1. <_>5 1 3 4 2. 0 4.4299028813838959e-003 0.2891018092632294 0.6335226297378540 <_> <_> <_>9 7 6 4 -1. <_>12 7 3 2 2. <_>9 9 3 2 2. 0 -2.3813319858163595e-003 0.6211789250373840 0.3477487862110138 <_> <_> <_>5 6 2 6 -1. <_>5 9 2 3 2. 0 2.2915711160749197e-003 0.2254412025213242 0.5582118034362793 <_> <_> <_>9 16 6 4 -1. <_>12 16 3 2 2. <_>9 18 3 2 2. 0 9.9457940086722374e-004 0.3711710870265961 0.5930070877075195 <_> <_> <_>9 4 2 12 -1. <_>9 10 2 6 2. 0 7.7164667891338468e-004 0.5651720166206360 0.3347995877265930 <_> <_> <_>7 1 6 18 -1. <_>9 1 2 18 3. 0 -1.1386410333216190e-003 0.3069126009941101 0.5508630871772766 <_> <_> <_>4 12 12 2 -1. <_>8 12 4 2 3. 0 -1.6403039626311511e-004 0.5762827992439270 0.3699047863483429 <_> <_> <_>8 8 6 2 -1. <_>8 9 6 1 2. 0 2.9793529392918572e-005 0.2644244134426117 0.5437911152839661 <_> <_> <_>8 0 3 6 -1. <_>9 0 1 6 3. 0 8.5774902254343033e-003 0.5051138997077942 0.1795724928379059 <_> <_> <_>11 18 3 2 -1. <_>11 19 3 1 2. 0 -2.6032689493149519e-004 0.5826969146728516 0.4446826875209808 <_> <_> <_>1 1 17 4 -1. <_>1 3 17 2 2. 0 -6.1404630541801453e-003 0.3113852143287659 0.5346971750259399 <_> <_> <_>11 8 4 12 -1. <_>11 8 2 12 2. 0 -0.0230869501829147 0.3277946114540100 0.5331197977066040 <_> <_> <_>8 14 4 3 -1. <_>8 15 4 1 3. 0 -0.0142436502501369 0.7381709814071655 0.4588063061237335 <_> <_> <_>12 3 2 17 -1. <_>12 3 1 17 2. 0 0.0194871295243502 0.5256630778312683 0.2274471968412399 <_> <_> <_>4 7 6 1 -1. <_>6 7 2 1 3. 0 -9.6681108698248863e-004 0.5511230826377869 0.3815006911754608 <_> <_> <_>18 3 2 3 -1. <_>18 4 2 1 3. 0 3.1474709976464510e-003 0.5425636768341065 0.2543726861476898 <_> <_> <_>8 4 3 4 -1. <_>8 6 3 2 2. 0 -1.8026070029009134e-004 0.5380191802978516 0.3406304121017456 <_> <_> <_>4 5 12 10 -1. <_>4 10 12 5 2. 0 -6.0266260989010334e-003 0.3035801947116852 0.5420572161674500 <_> <_> <_>5 18 4 2 -1. <_>7 18 2 2 2. 0 4.4462960795499384e-004 0.3990997076034546 0.5660110116004944 <_> <_> <_>17 2 3 6 -1. <_>17 4 3 2 3. 0 2.2609760053455830e-003 0.5562806725502014 0.3940688073635101 <_> <_> <_>7 7 6 6 -1. <_>9 7 2 6 3. 0 0.0511330589652061 0.4609653949737549 0.7118561863899231 <_> <_> <_>17 2 3 6 -1. <_>17 4 3 2 3. 0 -0.0177863091230392 0.2316166013479233 0.5322144031524658 <_> <_> <_>8 0 3 4 -1. <_>9 0 1 4 3. 0 -4.9679628573358059e-003 0.2330771982669830 0.5122029185295105 <_> <_> <_>9 14 2 3 -1. <_>9 15 2 1 3. 0 2.0667689386755228e-003 0.4657444059848785 0.6455488204956055 <_> <_> <_>0 12 6 3 -1. <_>0 13 6 1 3. 0 7.4413768015801907e-003 0.5154392123222351 0.2361633926630020 <_> <_> <_>8 14 4 3 -1. <_>8 15 4 1 3. 0 -3.6277279723435640e-003 0.6219773292541504 0.4476661086082459 <_> <_> <_>3 12 2 3 -1. <_>3 13 2 1 3. 0 -5.3530759178102016e-003 0.1837355047464371 0.5102208256721497 <_> <_> <_>5 6 12 7 -1. <_>9 6 4 7 3. 0 0.1453091949224472 0.5145987272262573 0.1535930931568146 <_> <_> <_>0 2 3 6 -1. <_>0 4 3 2 3. 0 2.4394490756094456e-003 0.5343660116195679 0.3624661862850189 <_> <_> <_>14 6 1 3 -1. <_>14 7 1 1 3. 0 -3.1283390708267689e-003 0.6215007901191711 0.4845592081546783 <_> <_> <_>2 0 3 14 -1. <_>3 0 1 14 3. 0 1.7940260004252195e-003 0.4299261868000031 0.5824198126792908 <_> <_> <_>12 14 5 6 -1. <_>12 16 5 2 3. 0 0.0362538211047649 0.5260334014892578 0.1439467966556549 <_> <_> <_>4 14 5 6 -1. <_>4 16 5 2 3. 0 -5.1746722310781479e-003 0.3506538867950440 0.5287045240402222 <_> <_> <_>11 10 2 2 -1. <_>12 10 1 1 2. <_>11 11 1 1 2. 0 6.5383297624066472e-004 0.4809640944004059 0.6122040152549744 <_> <_> <_>5 0 3 14 -1. <_>6 0 1 14 3. 0 -0.0264802295714617 0.1139362007379532 0.5045586228370667 <_> <_> <_>10 15 2 3 -1. <_>10 16 2 1 3. 0 -3.0440660193562508e-003 0.6352095007896423 0.4794734120368958 <_> <_> <_>0 2 2 3 -1. <_>0 3 2 1 3. 0 3.6993520334362984e-003 0.5131118297576904 0.2498510926961899 <_> <_> <_>5 11 12 6 -1. <_>5 14 12 3 2. 0 -3.6762931267730892e-004 0.5421394705772400 0.3709532022476196 <_> <_> <_>6 11 3 9 -1. <_>6 14 3 3 3. 0 -0.0413822606205940 0.1894959956407547 0.5081691741943359 <_> <_> <_>11 10 2 2 -1. <_>12 10 1 1 2. <_>11 11 1 1 2. 0 -1.0532729793339968e-003 0.6454367041587830 0.4783608913421631 <_> <_> <_>5 6 1 3 -1. <_>5 7 1 1 3. 0 -2.1648600231856108e-003 0.6215031147003174 0.4499826133251190 <_> <_> <_>4 9 13 3 -1. <_>4 10 13 1 3. 0 -5.6747748749330640e-004 0.3712610900402069 0.5419334769248962 <_> <_> <_>1 7 15 6 -1. <_>6 7 5 6 3. 0 0.1737584024667740 0.5023643970489502 0.1215742006897926 <_> <_> <_>4 5 12 6 -1. <_>8 5 4 6 3. 0 -2.9049699660390615e-003 0.3240267932415009 0.5381883978843689 <_> <_> <_>8 10 4 3 -1. <_>8 11 4 1 3. 0 1.2299539521336555e-003 0.4165507853031158 0.5703486204147339 <_> <_> <_>15 14 1 3 -1. <_>15 15 1 1 3. 0 -5.4329237900674343e-004 0.3854042887687683 0.5547549128532410 <_> <_> <_>1 11 5 3 -1. <_>1 12 5 1 3. 0 -8.3297258242964745e-003 0.2204494029283524 0.5097082853317261 <_> <_> <_>7 1 7 12 -1. <_>7 7 7 6 2. 0 -1.0417630255687982e-004 0.5607066154479981 0.4303036034107208 <_> <_> <_>0 1 6 10 -1. <_>0 1 3 5 2. <_>3 6 3 5 2. 0 0.0312047004699707 0.4621657133102417 0.6982004046440125 <_> <_> <_>16 1 4 3 -1. <_>16 2 4 1 3. 0 7.8943502157926559e-003 0.5269594192504883 0.2269068062305450 <_> <_> <_>5 5 2 3 -1. <_>5 6 2 1 3. 0 -4.3645310215651989e-003 0.6359223127365112 0.4537956118583679 <_> <_> <_>12 2 3 5 -1. <_>13 2 1 5 3. 0 7.6793059706687927e-003 0.5274767875671387 0.2740483880043030 <_> <_> <_>0 3 4 6 -1. <_>0 5 4 2 3. 0 -0.0254311393946409 0.2038519978523254 0.5071732997894287 <_> <_> <_>8 12 4 2 -1. <_>8 13 4 1 2. 0 8.2000601105391979e-004 0.4587455093860626 0.6119868159294128 <_> <_> <_>8 18 3 1 -1. <_>9 18 1 1 3. 0 2.9284600168466568e-003 0.5071274042129517 0.2028204947710037 <_> <_> <_>11 10 2 2 -1. <_>12 10 1 1 2. <_>11 11 1 1 2. 0 4.5256470912136137e-005 0.4812104105949402 0.5430821776390076 <_> <_> <_>7 10 2 2 -1. <_>7 10 1 1 2. <_>8 11 1 1 2. 0 1.3158309739083052e-003 0.4625813961029053 0.6779323220252991 <_> <_> <_>11 11 4 4 -1. <_>11 13 4 2 2. 0 1.5870389761403203e-003 0.5386291742324829 0.3431465029716492 <_> <_> <_>8 12 3 8 -1. <_>9 12 1 8 3. 0 -0.0215396601706743 0.0259425006806850 0.5003222823143005 <_> <_> <_>13 0 6 3 -1. <_>13 1 6 1 3. 0 0.0143344802781940 0.5202844738960266 0.1590632945299149 <_> <_> <_>8 8 3 4 -1. <_>9 8 1 4 3. 0 -8.3881383761763573e-003 0.7282481193542481 0.4648044109344482 <_> <_> <_>5 7 10 10 -1. <_>10 7 5 5 2. <_>5 12 5 5 2. 0 9.1906841844320297e-003 0.5562356710433960 0.3923191130161285 <_> <_> <_>3 18 8 2 -1. <_>3 18 4 1 2. <_>7 19 4 1 2. 0 -5.8453059755265713e-003 0.6803392767906189 0.4629127979278565 <_> <_> <_>10 2 6 8 -1. <_>12 2 2 8 3. 0 -0.0547077991068363 0.2561671137809753 0.5206125974655151 <_> <_> <_>4 2 6 8 -1. <_>6 2 2 8 3. 0 9.1142775490880013e-003 0.5189620256423950 0.3053877055644989 <_> <_> <_>11 0 3 7 -1. <_>12 0 1 7 3. 0 -0.0155750000849366 0.1295074969530106 0.5169094800949097 <_> <_> <_>7 11 2 1 -1. <_>8 11 1 1 2. 0 -1.2050600344082341e-004 0.5735098123550415 0.4230825006961823 <_> <_> <_>15 14 1 3 -1. <_>15 15 1 1 3. 0 1.2273970060050488e-003 0.5289878249168396 0.4079791903495789 <_> <_> <_>7 15 2 2 -1. <_>7 15 1 1 2. <_>8 16 1 1 2. 0 -1.2186600361019373e-003 0.6575639843940735 0.4574409127235413 <_> <_> <_>15 14 1 3 -1. <_>15 15 1 1 3. 0 -3.3256649039685726e-003 0.3628047108650208 0.5195019841194153 <_> <_> <_>6 0 3 7 -1. <_>7 0 1 7 3. 0 -0.0132883097976446 0.1284265965223312 0.5043488740921021 <_> <_> <_>18 1 2 7 -1. <_>18 1 1 7 2. 0 -3.3839771058410406e-003 0.6292240023612976 0.4757505953311920 <_> <_> <_>2 0 8 20 -1. <_>2 10 8 10 2. 0 -0.2195422053337097 0.1487731933593750 0.5065013766288757 <_> <_> <_>3 0 15 6 -1. <_>3 2 15 2 3. 0 4.9111708067357540e-003 0.4256102144718170 0.5665838718414307 <_> <_> <_>4 3 12 2 -1. <_>4 4 12 1 2. 0 -1.8744950648397207e-004 0.4004144072532654 0.5586857199668884 <_> <_> <_>16 0 4 5 -1. <_>16 0 2 5 2. 0 -5.2178641781210899e-003 0.6009116172790527 0.4812706112861633 <_> <_> <_>7 0 3 4 -1. <_>8 0 1 4 3. 0 -1.1111519997939467e-003 0.3514933884143829 0.5287089943885803 <_> <_> <_>16 0 4 5 -1. <_>16 0 2 5 2. 0 4.4036400504410267e-003 0.4642275869846344 0.5924085974693298 <_> <_> <_>1 7 6 13 -1. <_>3 7 2 13 3. 0 0.1229949966073036 0.5025529265403748 0.0691524818539619 <_> <_> <_>16 0 4 5 -1. <_>16 0 2 5 2. 0 -0.0123135102912784 0.5884591937065125 0.4934012889862061 <_> <_> <_>0 0 4 5 -1. <_>2 0 2 5 2. 0 4.1471039876341820e-003 0.4372239112854004 0.5893477797508240 <_> <_> <_>14 12 3 6 -1. <_>14 14 3 2 3. 0 -3.5502649843692780e-003 0.4327551126480103 0.5396270155906677 <_> <_> <_>3 12 3 6 -1. <_>3 14 3 2 3. 0 -0.0192242693156004 0.1913134008646011 0.5068330764770508 <_> <_> <_>16 1 4 3 -1. <_>16 2 4 1 3. 0 1.4395059552043676e-003 0.5308178067207336 0.4243533015251160 <_> <_> <_>8 7 2 10 -1. <_>8 7 1 5 2. <_>9 12 1 5 2. 0 -6.7751999013125896e-003 0.6365395784378052 0.4540086090564728 <_> <_> <_>11 11 4 4 -1. <_>11 13 4 2 2. 0 7.0119630545377731e-003 0.5189834237098694 0.3026199936866760 <_> <_> <_>0 1 4 3 -1. <_>0 2 4 1 3. 0 5.4014651104807854e-003 0.5105062127113342 0.2557682991027832 <_> <_> <_>13 4 1 3 -1. <_>13 5 1 1 3. 0 9.0274988906458020e-004 0.4696914851665497 0.5861827731132507 <_> <_> <_>7 15 3 5 -1. <_>8 15 1 5 3. 0 0.0114744501188397 0.5053645968437195 0.1527177989482880 <_> <_> <_>9 7 3 5 -1. <_>10 7 1 5 3. 0 -6.7023430019617081e-003 0.6508980989456177 0.4890604019165039 <_> <_> <_>8 7 3 5 -1. <_>9 7 1 5 3. 0 -2.0462959073483944e-003 0.6241816878318787 0.4514600038528442 <_> <_> <_>10 6 4 14 -1. <_>10 6 2 14 2. 0 -9.9951568990945816e-003 0.3432781100273132 0.5400953888893127 <_> <_> <_>0 5 5 6 -1. <_>0 7 5 2 3. 0 -0.0357007086277008 0.1878059059381485 0.5074077844619751 <_> <_> <_>9 5 6 4 -1. <_>9 5 3 4 2. 0 4.5584561303257942e-004 0.3805277049541473 0.5402569770812988 <_> <_> <_>0 0 18 10 -1. <_>6 0 6 10 3. 0 -0.0542606003582478 0.6843714714050293 0.4595097005367279 <_> <_> <_>10 6 4 14 -1. <_>10 6 2 14 2. 0 6.0600461438298225e-003 0.5502905249595642 0.4500527977943420 <_> <_> <_>6 6 4 14 -1. <_>8 6 2 14 2. 0 -6.4791832119226456e-003 0.3368858098983765 0.5310757160186768 <_> <_> <_>13 4 1 3 -1. <_>13 5 1 1 3. 0 -1.4939469983801246e-003 0.6487640142440796 0.4756175875663757 <_> <_> <_>5 1 2 3 -1. <_>6 1 1 3 2. 0 1.4610530342906713e-005 0.4034579098224640 0.5451064109802246 <_> <_> <_>18 1 2 18 -1. <_>19 1 1 9 2. <_>18 10 1 9 2. 0 -7.2321938350796700e-003 0.6386873722076416 0.4824739992618561 <_> <_> <_>2 1 4 3 -1. <_>2 2 4 1 3. 0 -4.0645818226039410e-003 0.2986421883106232 0.5157335996627808 <_> <_> <_>18 1 2 18 -1. <_>19 1 1 9 2. <_>18 10 1 9 2. 0 0.0304630808532238 0.5022199749946594 0.7159956097602844 <_> <_> <_>1 14 4 6 -1. <_>1 14 2 3 2. <_>3 17 2 3 2. 0 -8.0544911324977875e-003 0.6492452025413513 0.4619275033473969 <_> <_> <_>10 11 7 6 -1. <_>10 13 7 2 3. 0 0.0395051389932632 0.5150570869445801 0.2450613975524902 <_> <_> <_>0 10 6 10 -1. <_>0 10 3 5 2. <_>3 15 3 5 2. 0 8.4530208259820938e-003 0.4573669135570526 0.6394037008285523 <_> <_> <_>11 0 3 4 -1. <_>12 0 1 4 3. 0 -1.1688120430335402e-003 0.3865512013435364 0.5483661293983460 <_> <_> <_>5 10 5 6 -1. <_>5 13 5 3 2. 0 2.8070670086890459e-003 0.5128579139709473 0.2701480090618134 <_> <_> <_>14 6 1 8 -1. <_>14 10 1 4 2. 0 4.7365209320560098e-004 0.4051581919193268 0.5387461185455322 <_> <_> <_>1 7 18 6 -1. <_>1 7 9 3 2. <_>10 10 9 3 2. 0 0.0117410803213716 0.5295950174331665 0.3719413876533508 <_> <_> <_>9 7 2 2 -1. <_>9 7 1 2 2. 0 3.1833238899707794e-003 0.4789406955242157 0.6895126104354858 <_> <_> <_>5 9 4 5 -1. <_>7 9 2 5 2. 0 7.0241501089185476e-004 0.5384489297866821 0.3918080925941467 54.6200714111328130 11 -1 <_> <_> <_> <_>7 6 6 3 -1. <_>9 6 2 3 3. 0 0.0170599296689034 0.3948527872562408 0.7142534852027893 <_> <_> <_>1 0 18 4 -1. <_>7 0 6 4 3. 0 0.0218408405780792 0.3370316028594971 0.6090016961097717 <_> <_> <_>7 15 2 4 -1. <_>7 17 2 2 2. 0 2.4520049919374287e-004 0.3500576019287109 0.5987902283668518 <_> <_> <_>1 0 19 9 -1. <_>1 3 19 3 3. 0 8.3272606134414673e-003 0.3267528116703033 0.5697240829467773 <_> <_> <_>3 7 3 6 -1. <_>3 9 3 2 3. 0 5.7148298947140574e-004 0.3044599890708923 0.5531656742095947 <_> <_> <_>13 7 4 4 -1. <_>15 7 2 2 2. <_>13 9 2 2 2. 0 6.7373987985774875e-004 0.3650012016296387 0.5672631263732910 <_> <_> <_>3 7 4 4 -1. <_>3 7 2 2 2. <_>5 9 2 2 2. 0 3.4681590477703139e-005 0.3313541114330292 0.5388727188110352 <_> <_> <_>9 6 10 8 -1. <_>9 10 10 4 2. 0 -5.8563398197293282e-003 0.2697942852973938 0.5498778820037842 <_> <_> <_>3 8 14 12 -1. <_>3 14 14 6 2. 0 8.5102273151278496e-003 0.5269358158111572 0.2762879133224487 <_> <_> <_>6 5 10 12 -1. <_>11 5 5 6 2. <_>6 11 5 6 2. 0 -0.0698172077536583 0.2909603118896484 0.5259246826171875 <_> <_> <_>9 11 2 3 -1. <_>9 12 2 1 3. 0 -8.6113670840859413e-004 0.5892577171325684 0.4073697924613953 <_> <_> <_>9 5 6 5 -1. <_>9 5 3 5 2. 0 9.7149249631911516e-004 0.3523564040660858 0.5415862202644348 <_> <_> <_>9 4 2 4 -1. <_>9 6 2 2 2. 0 -1.4727490452060010e-005 0.5423017740249634 0.3503156006336212 <_> <_> <_>9 5 6 5 -1. <_>9 5 3 5 2. 0 0.0484202913939953 0.5193945765495300 0.3411195874214172 <_> <_> <_>5 5 6 5 -1. <_>8 5 3 5 2. 0 1.3257140526548028e-003 0.3157769143581390 0.5335376262664795 <_> <_> <_>11 2 6 1 -1. <_>13 2 2 1 3. 0 1.4922149603080470e-005 0.4451299905776978 0.5536553859710693 <_> <_> <_>3 2 6 1 -1. <_>5 2 2 1 3. 0 -2.7173398993909359e-003 0.3031741976737976 0.5248088836669922 <_> <_> <_>13 5 2 3 -1. <_>13 6 2 1 3. 0 2.9219500720500946e-003 0.4781453013420105 0.6606041789054871 <_> <_> <_>0 10 1 4 -1. <_>0 12 1 2 2. 0 -1.9804988987743855e-003 0.3186308145523071 0.5287625193595886 <_> <_> <_>13 5 2 3 -1. <_>13 6 2 1 3. 0 -4.0012109093368053e-003 0.6413596868515015 0.4749928116798401 <_> <_> <_>8 18 3 2 -1. <_>9 18 1 2 3. 0 -4.3491991236805916e-003 0.1507498025894165 0.5098996758460999 <_> <_> <_>6 15 9 2 -1. <_>6 16 9 1 2. 0 1.3490889687091112e-003 0.4316158890724182 0.5881167054176331 <_> <_> <_>8 14 4 3 -1. <_>8 15 4 1 3. 0 0.0185970701277256 0.4735553860664368 0.9089794158935547 <_> <_> <_>18 4 2 4 -1. <_>18 6 2 2 2. 0 -1.8562379991635680e-003 0.3553189039230347 0.5577837228775024 <_> <_> <_>5 5 2 3 -1. <_>5 6 2 1 3. 0 2.2940430790185928e-003 0.4500094950199127 0.6580877900123596 <_> <_> <_>15 16 3 2 -1. <_>15 17 3 1 2. 0 2.9982850537635386e-004 0.5629242062568665 0.3975878953933716 <_> <_> <_>0 0 3 9 -1. <_>0 3 3 3 3. 0 3.5455459728837013e-003 0.5381547212600708 0.3605485856533051 <_> <_> <_>9 7 3 3 -1. <_>9 8 3 1 3. 0 9.6104722470045090e-003 0.5255997180938721 0.1796745955944061 <_> <_> <_>8 7 3 3 -1. <_>8 8 3 1 3. 0 -6.2783220782876015e-003 0.2272856980562210 0.5114030241966248 <_> <_> <_>9 5 2 6 -1. <_>9 5 1 6 2. 0 3.4598479978740215e-003 0.4626308083534241 0.6608219146728516 <_> <_> <_>8 6 3 4 -1. <_>9 6 1 4 3. 0 -1.3112019514665008e-003 0.6317539811134338 0.4436857998371124 <_> <_> <_>7 6 8 12 -1. <_>11 6 4 6 2. <_>7 12 4 6 2. 0 2.6876179035753012e-003 0.5421109795570374 0.4054022133350372 <_> <_> <_>5 6 8 12 -1. <_>5 6 4 6 2. <_>9 12 4 6 2. 0 3.9118169806897640e-003 0.5358477830886841 0.3273454904556274 <_> <_> <_>12 4 3 3 -1. <_>12 5 3 1 3. 0 -0.0142064504325390 0.7793576717376709 0.4975781142711639 <_> <_> <_>2 16 3 2 -1. <_>2 17 3 1 2. 0 7.1705528534948826e-004 0.5297319889068604 0.3560903966426849 <_> <_> <_>12 4 3 3 -1. <_>12 5 3 1 3. 0 1.6635019565001130e-003 0.4678094089031220 0.5816481709480286 <_> <_> <_>2 12 6 6 -1. <_>2 14 6 2 3. 0 3.3686188980937004e-003 0.5276734232902527 0.3446420133113861 <_> <_> <_>7 13 6 3 -1. <_>7 14 6 1 3. 0 0.0127995302900672 0.4834679961204529 0.7472159266471863 <_> <_> <_>6 14 6 3 -1. <_>6 15 6 1 3. 0 3.3901201095432043e-003 0.4511859118938446 0.6401721239089966 <_> <_> <_>14 15 5 3 -1. <_>14 16 5 1 3. 0 4.7070779837667942e-003 0.5335658788681030 0.3555220961570740 <_> <_> <_>5 4 3 3 -1. <_>5 5 3 1 3. 0 1.4819339849054813e-003 0.4250707030296326 0.5772724151611328 <_> <_> <_>14 15 5 3 -1. <_>14 16 5 1 3. 0 -6.9995759986341000e-003 0.3003320097923279 0.5292900204658508 <_> <_> <_>5 3 6 2 -1. <_>7 3 2 2 3. 0 0.0159390103071928 0.5067319273948669 0.1675581932067871 <_> <_> <_>8 15 4 3 -1. <_>8 16 4 1 3. 0 7.6377349905669689e-003 0.4795069992542267 0.7085601091384888 <_> <_> <_>1 15 5 3 -1. <_>1 16 5 1 3. 0 6.7334040068089962e-003 0.5133113265037537 0.2162470072507858 <_> <_> <_>8 13 4 6 -1. <_>10 13 2 3 2. <_>8 16 2 3 2. 0 -0.0128588099032640 0.1938841938972473 0.5251371860504150 <_> <_> <_>7 8 3 3 -1. <_>8 8 1 3 3. 0 -6.2270800117403269e-004 0.5686538219451904 0.4197868108749390 <_> <_> <_>12 0 5 4 -1. <_>12 2 5 2 2. 0 -5.2651681471616030e-004 0.4224168956279755 0.5429695844650269 <_> <_> <_>0 2 20 2 -1. <_>0 2 10 1 2. <_>10 3 10 1 2. 0 0.0110750999301672 0.5113775134086609 0.2514517903327942 <_> <_> <_>1 0 18 4 -1. <_>7 0 6 4 3. 0 -0.0367282517254353 0.7194662094116211 0.4849618971347809 <_> <_> <_>4 3 6 1 -1. <_>6 3 2 1 3. 0 -2.8207109426148236e-004 0.3840261995792389 0.5394446253776550 <_> <_> <_>4 18 13 2 -1. <_>4 19 13 1 2. 0 -2.7489690110087395e-003 0.5937088727951050 0.4569182097911835 <_> <_> <_>2 10 3 6 -1. <_>2 12 3 2 3. 0 0.0100475195795298 0.5138576030731201 0.2802298069000244 <_> <_> <_>14 12 6 8 -1. <_>17 12 3 4 2. <_>14 16 3 4 2. 0 -8.1497840583324432e-003 0.6090037226676941 0.4636121094226837 <_> <_> <_>4 13 10 6 -1. <_>4 13 5 3 2. <_>9 16 5 3 2. 0 -6.8833888508379459e-003 0.3458611071109772 0.5254660248756409 <_> <_> <_>14 12 1 2 -1. <_>14 13 1 1 2. 0 -1.4039360394235700e-005 0.5693104267120361 0.4082083106040955 <_> <_> <_>8 13 4 3 -1. <_>8 14 4 1 3. 0 1.5498419525101781e-003 0.4350537061691284 0.5806517004966736 <_> <_> <_>14 12 2 2 -1. <_>14 13 2 1 2. 0 -6.7841499112546444e-003 0.1468873023986816 0.5182775259017944 <_> <_> <_>4 12 2 2 -1. <_>4 13 2 1 2. 0 2.1705629478674382e-004 0.5293524265289307 0.3456174135208130 <_> <_> <_>8 12 9 2 -1. <_>8 13 9 1 2. 0 3.1198898795992136e-004 0.4652450978755951 0.5942413806915283 <_> <_> <_>9 14 2 3 -1. <_>9 15 2 1 3. 0 5.4507530294358730e-003 0.4653508961200714 0.7024846076965332 <_> <_> <_>11 10 3 6 -1. <_>11 13 3 3 2. 0 -2.5818689027801156e-004 0.5497295260429382 0.3768967092037201 <_> <_> <_>5 6 9 12 -1. <_>5 12 9 6 2. 0 -0.0174425393342972 0.3919087946414948 0.5457497835159302 <_> <_> <_>11 10 3 6 -1. <_>11 13 3 3 2. 0 -0.0453435294330120 0.1631357073783875 0.5154908895492554 <_> <_> <_>6 10 3 6 -1. <_>6 13 3 3 2. 0 1.9190689781680703e-003 0.5145897865295410 0.2791895866394043 <_> <_> <_>5 4 11 3 -1. <_>5 5 11 1 3. 0 -6.0177869163453579e-003 0.6517636179924011 0.4756332933902741 <_> <_> <_>7 1 5 10 -1. <_>7 6 5 5 2. 0 -4.0720738470554352e-003 0.5514652729034424 0.4092685878276825 <_> <_> <_>2 8 18 2 -1. <_>2 9 18 1 2. 0 3.9855059003457427e-004 0.3165240883827210 0.5285550951957703 <_> <_> <_>7 17 5 3 -1. <_>7 18 5 1 3. 0 -6.5418570302426815e-003 0.6853377819061279 0.4652808904647827 <_> <_> <_>5 9 12 1 -1. <_>9 9 4 1 3. 0 3.4845089539885521e-003 0.5484588146209717 0.4502759873867035 <_> <_> <_>0 14 6 6 -1. <_>0 14 3 3 2. <_>3 17 3 3 2. 0 -0.0136967804282904 0.6395779848098755 0.4572555124759674 <_> <_> <_>5 9 12 1 -1. <_>9 9 4 1 3. 0 -0.0173471402376890 0.2751072943210602 0.5181614756584168 <_> <_> <_>3 9 12 1 -1. <_>7 9 4 1 3. 0 -4.0885428898036480e-003 0.3325636088848114 0.5194984078407288 <_> <_> <_>14 10 6 7 -1. <_>14 10 3 7 2. 0 -9.4687901437282562e-003 0.5942280888557434 0.4851819872856140 <_> <_> <_>1 0 16 2 -1. <_>1 1 16 1 2. 0 1.7084840219467878e-003 0.4167110919952393 0.5519806146621704 <_> <_> <_>10 9 10 9 -1. <_>10 12 10 3 3. 0 9.4809094443917274e-003 0.5433894991874695 0.4208514988422394 <_> <_> <_>0 1 10 2 -1. <_>5 1 5 2 2. 0 -4.7389650717377663e-003 0.6407189965248108 0.4560655057430267 <_> <_> <_>17 3 2 3 -1. <_>17 4 2 1 3. 0 6.5761050209403038e-003 0.5214555263519287 0.2258227020502091 <_> <_> <_>1 3 2 3 -1. <_>1 4 2 1 3. 0 -2.1690549328923225e-003 0.3151527941226959 0.5156704783439636 <_> <_> <_>9 7 3 6 -1. <_>10 7 1 6 3. 0 0.0146601703017950 0.4870837032794952 0.6689941287040710 <_> <_> <_>6 5 4 3 -1. <_>8 5 2 3 2. 0 1.7231999663636088e-004 0.3569748997688294 0.5251078009605408 <_> <_> <_>7 5 6 6 -1. <_>9 5 2 6 3. 0 -0.0218037609010935 0.8825920820236206 0.4966329932212830 <_> <_> <_>3 4 12 12 -1. <_>3 4 6 6 2. <_>9 10 6 6 2. 0 -0.0947361066937447 0.1446162015199661 0.5061113834381104 <_> <_> <_>9 2 6 15 -1. <_>11 2 2 15 3. 0 5.5825551971793175e-003 0.5396478772163391 0.4238066077232361 <_> <_> <_>2 2 6 17 -1. <_>4 2 2 17 3. 0 1.9517090404406190e-003 0.4170410931110382 0.5497786998748779 <_> <_> <_>14 10 6 7 -1. <_>14 10 3 7 2. 0 0.0121499001979828 0.4698367118835449 0.5664274096488953 <_> <_> <_>0 10 6 7 -1. <_>3 10 3 7 2. 0 -7.5169620104134083e-003 0.6267772912979126 0.4463135898113251 <_> <_> <_>9 2 6 15 -1. <_>11 2 2 15 3. 0 -0.0716679096221924 0.3097011148929596 0.5221003293991089 <_> <_> <_>5 2 6 15 -1. <_>7 2 2 15 3. 0 -0.0882924199104309 0.0811238884925842 0.5006365180015564 <_> <_> <_>17 9 3 6 -1. <_>17 11 3 2 3. 0 0.0310630798339844 0.5155503749847412 0.1282255947589874 <_> <_> <_>6 7 6 6 -1. <_>8 7 2 6 3. 0 0.0466218404471874 0.4699777960777283 0.7363960742950440 <_> <_> <_>1 10 18 6 -1. <_>10 10 9 3 2. <_>1 13 9 3 2. 0 -0.0121894897893071 0.3920530080795288 0.5518996715545654 <_> <_> <_>0 9 10 9 -1. <_>0 12 10 3 3. 0 0.0130161102861166 0.5260658264160156 0.3685136139392853 <_> <_> <_>8 15 4 3 -1. <_>8 16 4 1 3. 0 -3.4952899441123009e-003 0.6339294910430908 0.4716280996799469 <_> <_> <_>5 12 3 4 -1. <_>5 14 3 2 2. 0 -4.4015039748046547e-005 0.5333027243614197 0.3776184916496277 <_> <_> <_>3 3 16 12 -1. <_>3 9 16 6 2. 0 -0.1096649020910263 0.1765342056751251 0.5198346972465515 <_> <_> <_>1 1 12 12 -1. <_>1 1 6 6 2. <_>7 7 6 6 2. 0 -9.0279558207839727e-004 0.5324159860610962 0.3838908076286316 <_> <_> <_>10 4 2 4 -1. <_>11 4 1 2 2. <_>10 6 1 2 2. 0 7.1126641705632210e-004 0.4647929966449738 0.5755224227905273 <_> <_> <_>0 9 10 2 -1. <_>0 9 5 1 2. <_>5 10 5 1 2. 0 -3.1250279862433672e-003 0.3236708939075470 0.5166770815849304 <_> <_> <_>9 11 3 3 -1. <_>9 12 3 1 3. 0 2.4144679773598909e-003 0.4787439107894898 0.6459717750549316 <_> <_> <_>3 12 9 2 -1. <_>3 13 9 1 2. 0 4.4391240226104856e-004 0.4409308135509491 0.6010255813598633 <_> <_> <_>9 9 2 2 -1. <_>9 10 2 1 2. 0 -2.2611189342569560e-004 0.4038113951683044 0.5493255853652954 50.1697311401367190 12 -1 <_> <_> <_> <_>3 4 13 6 -1. <_>3 6 13 2 3. 0 -0.0469012893736362 0.6600171923637390 0.3743801116943359 <_> <_> <_>9 7 6 4 -1. <_>12 7 3 2 2. <_>9 9 3 2 2. 0 -1.4568349579349160e-003 0.5783991217613220 0.3437797129154205 <_> <_> <_>1 0 6 8 -1. <_>4 0 3 8 2. 0 5.5598369799554348e-003 0.3622266948223114 0.5908216238021851 <_> <_> <_>9 5 2 12 -1. <_>9 11 2 6 2. 0 7.3170487303286791e-004 0.5500419139862061 0.2873558104038239 <_> <_> <_>4 4 3 10 -1. <_>4 9 3 5 2. 0 1.3318009441718459e-003 0.2673169970512390 0.5431019067764282 <_> <_> <_>6 17 8 3 -1. <_>6 18 8 1 3. 0 2.4347059661522508e-004 0.3855027854442596 0.5741388797760010 <_> <_> <_>0 5 10 6 -1. <_>0 7 10 2 3. 0 -3.0512469820678234e-003 0.5503209829330444 0.3462845087051392 <_> <_> <_>13 2 3 2 -1. <_>13 3 3 1 2. 0 -6.8657199153676629e-004 0.3291221857070923 0.5429509282112122 <_> <_> <_>7 5 4 5 -1. <_>9 5 2 5 2. 0 1.4668200165033340e-003 0.3588382005691528 0.5351811051368713 <_> <_> <_>12 14 3 6 -1. <_>12 16 3 2 3. 0 3.2021870720200241e-004 0.4296841919422150 0.5700234174728394 <_> <_> <_>1 11 8 2 -1. <_>1 12 8 1 2. 0 7.4122188379988074e-004 0.5282164812088013 0.3366870880126953 <_> <_> <_>7 13 6 3 -1. <_>7 14 6 1 3. 0 3.8330298848450184e-003 0.4559567868709564 0.6257336139678955 <_> <_> <_>0 5 3 6 -1. <_>0 7 3 2 3. 0 -0.0154564399272203 0.2350116968154907 0.5129452943801880 <_> <_> <_>13 2 3 2 -1. <_>13 3 3 1 2. 0 2.6796779129654169e-003 0.5329415202140808 0.4155062139034271 <_> <_> <_>4 14 4 6 -1. <_>4 14 2 3 2. <_>6 17 2 3 2. 0 2.8296569362282753e-003 0.4273087978363037 0.5804538130760193 <_> <_> <_>13 2 3 2 -1. <_>13 3 3 1 2. 0 -3.9444249123334885e-003 0.2912611961364746 0.5202686190605164 <_> <_> <_>8 2 4 12 -1. <_>8 6 4 4 3. 0 2.7179559692740440e-003 0.5307688117027283 0.3585677146911621 <_> <_> <_>14 0 6 8 -1. <_>17 0 3 4 2. <_>14 4 3 4 2. 0 5.9077627956867218e-003 0.4703775048255920 0.5941585898399353 <_> <_> <_>7 17 3 2 -1. <_>8 17 1 2 3. 0 -4.2240349575877190e-003 0.2141567021608353 0.5088796019554138 <_> <_> <_>8 12 4 2 -1. <_>8 13 4 1 2. 0 4.0725888684391975e-003 0.4766413867473602 0.6841061115264893 <_> <_> <_>6 0 8 12 -1. <_>6 0 4 6 2. <_>10 6 4 6 2. 0 0.0101495301350951 0.5360798835754395 0.3748497068881989 <_> <_> <_>14 0 2 10 -1. <_>15 0 1 5 2. <_>14 5 1 5 2. 0 -1.8864999583456665e-004 0.5720130205154419 0.3853805065155029 <_> <_> <_>5 3 8 6 -1. <_>5 3 4 3 2. <_>9 6 4 3 2. 0 -4.8864358104765415e-003 0.3693122863769531 0.5340958833694458 <_> <_> <_>14 0 6 10 -1. <_>17 0 3 5 2. <_>14 5 3 5 2. 0 0.0261584799736738 0.4962374866008759 0.6059989929199219 <_> <_> <_>9 14 1 2 -1. <_>9 15 1 1 2. 0 4.8560759751126170e-004 0.4438945949077606 0.6012468934059143 <_> <_> <_>15 10 4 3 -1. <_>15 11 4 1 3. 0 0.0112687097862363 0.5244250297546387 0.1840388029813767 <_> <_> <_>8 14 2 3 -1. <_>8 15 2 1 3. 0 -2.8114619199186563e-003 0.6060283780097961 0.4409897029399872 <_> <_> <_>3 13 14 4 -1. <_>10 13 7 2 2. <_>3 15 7 2 2. 0 -5.6112729944288731e-003 0.3891170918941498 0.5589237213134766 <_> <_> <_>1 10 4 3 -1. <_>1 11 4 1 3. 0 8.5680093616247177e-003 0.5069345831871033 0.2062619030475617 <_> <_> <_>9 11 6 1 -1. <_>11 11 2 1 3. 0 -3.8172779022715986e-004 0.5882201790809631 0.4192610979080200 <_> <_> <_>5 11 6 1 -1. <_>7 11 2 1 3. 0 -1.7680290329735726e-004 0.5533605813980103 0.4003368914127350 <_> <_> <_>3 5 16 15 -1. <_>3 10 16 5 3. 0 6.5112537704408169e-003 0.3310146927833557 0.5444191098213196 <_> <_> <_>6 12 4 2 -1. <_>8 12 2 2 2. 0 -6.5948683186434209e-005 0.5433831810951233 0.3944905996322632 <_> <_> <_>4 4 12 10 -1. <_>10 4 6 5 2. <_>4 9 6 5 2. 0 6.9939051754772663e-003 0.5600358247756958 0.4192714095115662 <_> <_> <_>8 6 3 4 -1. <_>9 6 1 4 3. 0 -4.6744439750909805e-003 0.6685466766357422 0.4604960978031158 <_> <_> <_>8 12 4 8 -1. <_>10 12 2 4 2. <_>8 16 2 4 2. 0 0.0115898502990603 0.5357121229171753 0.2926830053329468 <_> <_> <_>8 14 4 3 -1. <_>8 15 4 1 3. 0 0.0130078401416540 0.4679817855358124 0.7307463288307190 <_> <_> <_>12 2 3 2 -1. <_>13 2 1 2 3. 0 -1.1008579749614000e-003 0.3937501013278961 0.5415065288543701 <_> <_> <_>8 15 3 2 -1. <_>8 16 3 1 2. 0 6.0472649056464434e-004 0.4242376089096069 0.5604041218757629 <_> <_> <_>6 0 9 14 -1. <_>9 0 3 14 3. 0 -0.0144948400557041 0.3631210029125214 0.5293182730674744 <_> <_> <_>9 6 2 3 -1. <_>10 6 1 3 2. 0 -5.3056948818266392e-003 0.6860452294349670 0.4621821045875549 <_> <_> <_>10 8 2 3 -1. <_>10 9 2 1 3. 0 -8.1829127157106996e-004 0.3944096863269806 0.5420439243316650 <_> <_> <_>0 9 4 6 -1. <_>0 11 4 2 3. 0 -0.0190775208175182 0.1962621957063675 0.5037891864776611 <_> <_> <_>6 0 8 2 -1. <_>6 1 8 1 2. 0 3.5549470339901745e-004 0.4086259007453919 0.5613973140716553 <_> <_> <_>6 14 7 3 -1. <_>6 15 7 1 3. 0 1.9679730758070946e-003 0.4489121139049530 0.5926123261451721 <_> <_> <_>8 10 8 9 -1. <_>8 13 8 3 3. 0 6.9189141504466534e-003 0.5335925817489624 0.3728385865688324 <_> <_> <_>5 2 3 2 -1. <_>6 2 1 2 3. 0 2.9872779268771410e-003 0.5111321210861206 0.2975643873214722 <_> <_> <_>14 1 6 8 -1. <_>17 1 3 4 2. <_>14 5 3 4 2. 0 -6.2264618463814259e-003 0.5541489720344544 0.4824537932872772 <_> <_> <_>0 1 6 8 -1. <_>0 1 3 4 2. <_>3 5 3 4 2. 0 0.0133533002808690 0.4586423933506012 0.6414797902107239 <_> <_> <_>1 2 18 6 -1. <_>10 2 9 3 2. <_>1 5 9 3 2. 0 0.0335052385926247 0.5392425060272217 0.3429994881153107 <_> <_> <_>9 3 2 1 -1. <_>10 3 1 1 2. 0 -2.5294460356235504e-003 0.1703713983297348 0.5013315081596375 <_> <_> <_>13 2 4 6 -1. <_>15 2 2 3 2. <_>13 5 2 3 2. 0 -1.2801629491150379e-003 0.5305461883544922 0.4697405099868774 <_> <_> <_>5 4 3 3 -1. <_>5 5 3 1 3. 0 7.0687388069927692e-003 0.4615545868873596 0.6436504721641541 <_> <_> <_>13 5 1 3 -1. <_>13 6 1 1 3. 0 9.6880499040707946e-004 0.4833599030971527 0.6043894290924072 <_> <_> <_>2 16 5 3 -1. <_>2 17 5 1 3. 0 3.9647659286856651e-003 0.5187637209892273 0.3231816887855530 <_> <_> <_>13 2 4 6 -1. <_>15 2 2 3 2. <_>13 5 2 3 2. 0 -0.0220577307045460 0.4079256951808929 0.5200980901718140 <_> <_> <_>3 2 4 6 -1. <_>3 2 2 3 2. <_>5 5 2 3 2. 0 -6.6906312713399529e-004 0.5331609249114990 0.3815600872039795 <_> <_> <_>13 5 1 2 -1. <_>13 6 1 1 2. 0 -6.7009328631684184e-004 0.5655422210693359 0.4688901901245117 <_> <_> <_>5 5 2 2 -1. <_>5 6 2 1 2. 0 7.4284552829340100e-004 0.4534381031990051 0.6287400126457214 <_> <_> <_>13 9 2 2 -1. <_>13 9 1 2 2. 0 2.2227810695767403e-003 0.5350633263587952 0.3303655982017517 <_> <_> <_>5 9 2 2 -1. <_>6 9 1 2 2. 0 -5.4130521602928638e-003 0.1113687008619309 0.5005434751510620 <_> <_> <_>13 17 3 2 -1. <_>13 18 3 1 2. 0 -1.4520040167553816e-005 0.5628737807273865 0.4325133860111237 <_> <_> <_>6 16 4 4 -1. <_>6 16 2 2 2. <_>8 18 2 2 2. 0 2.3369169502984732e-004 0.4165835082530975 0.5447791218757629 <_> <_> <_>9 16 2 3 -1. <_>9 17 2 1 3. 0 4.2894547805190086e-003 0.4860391020774841 0.6778649091720581 <_> <_> <_>0 13 9 6 -1. <_>0 15 9 2 3. 0 5.9103150852024555e-003 0.5262305140495300 0.3612113893032074 <_> <_> <_>9 14 2 6 -1. <_>9 17 2 3 2. 0 0.0129005396738648 0.5319377183914185 0.3250288069248200 <_> <_> <_>9 15 2 3 -1. <_>9 16 2 1 3. 0 4.6982979401946068e-003 0.4618245065212250 0.6665925979614258 <_> <_> <_>1 10 18 6 -1. <_>1 12 18 2 3. 0 0.0104398597031832 0.5505670905113220 0.3883604109287262 <_> <_> <_>8 11 4 2 -1. <_>8 12 4 1 2. 0 3.0443191062659025e-003 0.4697853028774262 0.7301844954490662 <_> <_> <_>7 9 6 2 -1. <_>7 10 6 1 2. 0 -6.1593751888722181e-004 0.3830839097499847 0.5464984178543091 <_> <_> <_>8 8 2 3 -1. <_>8 9 2 1 3. 0 -3.4247159492224455e-003 0.2566300034523010 0.5089530944824219 <_> <_> <_>17 5 3 4 -1. <_>18 5 1 4 3. 0 -9.3538565561175346e-003 0.6469966173171997 0.4940795898437500 <_> <_> <_>1 19 18 1 -1. <_>7 19 6 1 3. 0 0.0523389987647533 0.4745982885360718 0.7878770828247070 <_> <_> <_>9 0 3 2 -1. <_>10 0 1 2 3. 0 3.5765620414167643e-003 0.5306664705276489 0.2748498022556305 <_> <_> <_>1 8 1 6 -1. <_>1 10 1 2 3. 0 7.1555317845195532e-004 0.5413125753402710 0.4041908979415894 <_> <_> <_>12 17 8 3 -1. <_>12 17 4 3 2. 0 -0.0105166798457503 0.6158512234687805 0.4815283119678497 <_> <_> <_>0 5 3 4 -1. <_>1 5 1 4 3. 0 7.7347927726805210e-003 0.4695805907249451 0.7028980851173401 <_> <_> <_>9 7 2 3 -1. <_>9 8 2 1 3. 0 -4.3226778507232666e-003 0.2849566042423248 0.5304684042930603 <_> <_> <_>7 11 2 2 -1. <_>7 11 1 1 2. <_>8 12 1 1 2. 0 -2.5534399319440126e-003 0.7056984901428223 0.4688892066478729 <_> <_> <_>11 3 2 5 -1. <_>11 3 1 5 2. 0 1.0268510231981054e-004 0.3902932107448578 0.5573464035987854 <_> <_> <_>7 3 2 5 -1. <_>8 3 1 5 2. 0 7.1395188570022583e-006 0.3684231936931610 0.5263987779617310 <_> <_> <_>15 13 2 3 -1. <_>15 14 2 1 3. 0 -1.6711989883333445e-003 0.3849175870418549 0.5387271046638489 <_> <_> <_>5 6 2 3 -1. <_>5 7 2 1 3. 0 4.9260449595749378e-003 0.4729771912097931 0.7447251081466675 <_> <_> <_>4 19 15 1 -1. <_>9 19 5 1 3. 0 4.3908702209591866e-003 0.4809181094169617 0.5591921806335449 <_> <_> <_>1 19 15 1 -1. <_>6 19 5 1 3. 0 -0.0177936293184757 0.6903678178787231 0.4676927030086517 <_> <_> <_>15 13 2 3 -1. <_>15 14 2 1 3. 0 2.0469669252634048e-003 0.5370690226554871 0.3308162093162537 <_> <_> <_>5 0 4 15 -1. <_>7 0 2 15 2. 0 0.0298914890736341 0.5139865279197693 0.3309059143066406 <_> <_> <_>9 6 2 5 -1. <_>9 6 1 5 2. 0 1.5494900289922953e-003 0.4660237133502960 0.6078342795372009 <_> <_> <_>9 5 2 7 -1. <_>10 5 1 7 2. 0 1.4956969534978271e-003 0.4404835999011993 0.5863919854164124 <_> <_> <_>16 11 3 3 -1. <_>16 12 3 1 3. 0 9.5885928021743894e-004 0.5435971021652222 0.4208523035049439 <_> <_> <_>1 11 3 3 -1. <_>1 12 3 1 3. 0 4.9643701640889049e-004 0.5370578169822693 0.4000622034072876 <_> <_> <_>6 6 8 3 -1. <_>6 7 8 1 3. 0 -2.7280810754746199e-003 0.5659412741661072 0.4259642958641052 <_> <_> <_>0 15 6 2 -1. <_>0 16 6 1 2. 0 2.3026480339467525e-003 0.5161657929420471 0.3350869119167328 <_> <_> <_>1 0 18 6 -1. <_>7 0 6 6 3. 0 0.2515163123607636 0.4869661927223206 0.7147309780120850 <_> <_> <_>6 0 3 4 -1. <_>7 0 1 4 3. 0 -4.6328022144734859e-003 0.2727448940277100 0.5083789825439453 <_> <_> <_>14 10 4 10 -1. <_>16 10 2 5 2. <_>14 15 2 5 2. 0 -0.0404344908893108 0.6851438879966736 0.5021767020225525 <_> <_> <_>3 2 3 2 -1. <_>4 2 1 2 3. 0 1.4972220014897175e-005 0.4284465014934540 0.5522555112838745 <_> <_> <_>11 2 2 2 -1. <_>11 3 2 1 2. 0 -2.4050309730228037e-004 0.4226118922233582 0.5390074849128723 <_> <_> <_>2 10 4 10 -1. <_>2 10 2 5 2. <_>4 15 2 5 2. 0 0.0236578397452831 0.4744631946086884 0.7504366040229797 <_> <_> <_>0 13 20 6 -1. <_>10 13 10 3 2. <_>0 16 10 3 2. 0 -8.1449104472994804e-003 0.4245058894157410 0.5538362860679627 <_> <_> <_>0 5 2 15 -1. <_>1 5 1 15 2. 0 -3.6992130335420370e-003 0.5952357053756714 0.4529713094234467 <_> <_> <_>1 7 18 4 -1. <_>10 7 9 2 2. <_>1 9 9 2 2. 0 -6.7718601785600185e-003 0.4137794077396393 0.5473399758338928 <_> <_> <_>0 0 2 17 -1. <_>1 0 1 17 2. 0 4.2669530957937241e-003 0.4484114944934845 0.5797994136810303 <_> <_> <_>2 6 16 6 -1. <_>10 6 8 3 2. <_>2 9 8 3 2. 0 1.7791989957913756e-003 0.5624858736991882 0.4432444870471954 <_> <_> <_>8 14 1 3 -1. <_>8 15 1 1 3. 0 1.6774770338088274e-003 0.4637751877307892 0.6364241838455200 <_> <_> <_>8 15 4 2 -1. <_>8 16 4 1 2. 0 1.1732629500329494e-003 0.4544503092765808 0.5914415717124939 <_> <_> <_>5 2 8 2 -1. <_>5 2 4 1 2. <_>9 3 4 1 2. 0 8.6998171173036098e-004 0.5334752798080444 0.3885917961597443 <_> <_> <_>6 11 8 6 -1. <_>6 14 8 3 2. 0 7.6378340600058436e-004 0.5398585200309753 0.3744941949844360 <_> <_> <_>9 13 2 2 -1. <_>9 14 2 1 2. 0 1.5684569370932877e-004 0.4317873120307922 0.5614616274833679 <_> <_> <_>18 4 2 6 -1. <_>18 6 2 2 3. 0 -0.0215113703161478 0.1785925030708313 0.5185542702674866 <_> <_> <_>9 12 2 2 -1. <_>9 13 2 1 2. 0 1.3081369979772717e-004 0.4342499077320099 0.5682849884033203 <_> <_> <_>18 4 2 6 -1. <_>18 6 2 2 3. 0 0.0219920407980680 0.5161716938018799 0.2379394024610519 <_> <_> <_>9 13 1 3 -1. <_>9 14 1 1 3. 0 -8.0136500764638186e-004 0.5986763238906860 0.4466426968574524 <_> <_> <_>18 4 2 6 -1. <_>18 6 2 2 3. 0 -8.2736099138855934e-003 0.4108217954635620 0.5251057147979736 <_> <_> <_>0 4 2 6 -1. <_>0 6 2 2 3. 0 3.6831789184361696e-003 0.5173814296722412 0.3397518098354340 <_> <_> <_>9 12 3 3 -1. <_>9 13 3 1 3. 0 -7.9525681212544441e-003 0.6888983249664307 0.4845924079418182 <_> <_> <_>3 13 2 3 -1. <_>3 14 2 1 3. 0 1.5382299898192286e-003 0.5178567171096802 0.3454113900661469 <_> <_> <_>13 13 4 3 -1. <_>13 14 4 1 3. 0 -0.0140435304492712 0.1678421050310135 0.5188667774200440 <_> <_> <_>5 4 3 3 -1. <_>5 5 3 1 3. 0 1.4315890148282051e-003 0.4368256926536560 0.5655773878097534 <_> <_> <_>5 2 10 6 -1. <_>5 4 10 2 3. 0 -0.0340142287313938 0.7802296280860901 0.4959217011928558 <_> <_> <_>3 13 4 3 -1. <_>3 14 4 1 3. 0 -0.0120272999629378 0.1585101038217545 0.5032231807708740 <_> <_> <_>3 7 15 5 -1. <_>8 7 5 5 3. 0 0.1331661939620972 0.5163304805755615 0.2755128145217896 <_> <_> <_>3 7 12 2 -1. <_>7 7 4 2 3. 0 -1.5221949433907866e-003 0.3728317916393280 0.5214552283287048 <_> <_> <_>10 3 3 9 -1. <_>11 3 1 9 3. 0 -9.3929271679371595e-004 0.5838379263877869 0.4511165022850037 <_> <_> <_>8 6 4 6 -1. <_>10 6 2 6 2. 0 0.0277197398245335 0.4728286862373352 0.7331544756889343 <_> <_> <_>9 7 4 3 -1. <_>9 8 4 1 3. 0 3.1030150130391121e-003 0.5302202105522156 0.4101563096046448 <_> <_> <_>0 9 4 9 -1. <_>2 9 2 9 2. 0 0.0778612196445465 0.4998334050178528 0.1272961944341660 <_> <_> <_>9 13 3 5 -1. <_>10 13 1 5 3. 0 -0.0158549398183823 0.0508333593606949 0.5165656208992004 <_> <_> <_>7 7 6 3 -1. <_>9 7 2 3 3. 0 -4.9725300632417202e-003 0.6798133850097656 0.4684231877326965 <_> <_> <_>9 7 3 5 -1. <_>10 7 1 5 3. 0 -9.7676506265997887e-004 0.6010771989822388 0.4788931906223297 <_> <_> <_>5 7 8 2 -1. <_>9 7 4 2 2. 0 -2.4647710379213095e-003 0.3393397927284241 0.5220503807067871 <_> <_> <_>5 9 12 2 -1. <_>9 9 4 2 3. 0 -6.7937700077891350e-003 0.4365136921405792 0.5239663124084473 <_> <_> <_>5 6 10 3 -1. <_>10 6 5 3 2. 0 0.0326080210506916 0.5052723884582520 0.2425214946269989 <_> <_> <_>10 12 3 1 -1. <_>11 12 1 1 3. 0 -5.8514421107247472e-004 0.5733973979949951 0.4758574068546295 <_> <_> <_>0 1 11 15 -1. <_>0 6 11 5 3. 0 -0.0296326000243425 0.3892289102077484 0.5263597965240479 66.6691207885742190 13 -1 <_> <_> <_> <_>1 0 18 6 -1. <_>7 0 6 6 3. 0 0.0465508513152599 0.3276950120925903 0.6240522861480713 <_> <_> <_>7 7 6 1 -1. <_>9 7 2 1 3. 0 7.9537127166986465e-003 0.4256485104560852 0.6942939162254334 <_> <_> <_>5 16 6 4 -1. <_>5 16 3 2 2. <_>8 18 3 2 2. 0 6.8221561377868056e-004 0.3711487054824829 0.5900732874870300 <_> <_> <_>6 5 9 8 -1. <_>6 9 9 4 2. 0 -1.9348249770700932e-004 0.2041133940219879 0.5300545096397400 <_> <_> <_>5 10 2 6 -1. <_>5 13 2 3 2. 0 -2.6710508973337710e-004 0.5416126251220703 0.3103179037570953 <_> <_> <_>7 6 8 10 -1. <_>11 6 4 5 2. <_>7 11 4 5 2. 0 2.7818060480058193e-003 0.5277832746505737 0.3467069864273071 <_> <_> <_>5 6 8 10 -1. <_>5 6 4 5 2. <_>9 11 4 5 2. 0 -4.6779078547842801e-004 0.5308231115341187 0.3294492065906525 <_> <_> <_>9 5 2 2 -1. <_>9 6 2 1 2. 0 -3.0335160772665404e-005 0.5773872733116150 0.3852097094058991 <_> <_> <_>5 12 8 2 -1. <_>5 13 8 1 2. 0 7.8038009814918041e-004 0.4317438900470734 0.6150057911872864 <_> <_> <_>10 2 8 2 -1. <_>10 3 8 1 2. 0 -4.2553851380944252e-003 0.2933903932571411 0.5324292778968811 <_> <_> <_>4 0 2 10 -1. <_>4 0 1 5 2. <_>5 5 1 5 2. 0 -2.4735610350035131e-004 0.5468844771385193 0.3843030035495758 <_> <_> <_>9 10 2 2 -1. <_>9 11 2 1 2. 0 -1.4724259381182492e-004 0.4281542897224426 0.5755587220191956 <_> <_> <_>2 8 15 3 -1. <_>2 9 15 1 3. 0 1.1864770203828812e-003 0.3747301101684570 0.5471466183662415 <_> <_> <_>8 13 4 3 -1. <_>8 14 4 1 3. 0 2.3936580400913954e-003 0.4537783861160278 0.6111528873443604 <_> <_> <_>7 2 3 2 -1. <_>8 2 1 2 3. 0 -1.5390539774671197e-003 0.2971341907978058 0.5189538002014160 <_> <_> <_>7 13 6 3 -1. <_>7 14 6 1 3. 0 -7.1968790143728256e-003 0.6699066758155823 0.4726476967334747 <_> <_> <_>9 9 2 2 -1. <_>9 10 2 1 2. 0 -4.1499789222143590e-004 0.3384954035282135 0.5260317921638489 <_> <_> <_>17 2 3 6 -1. <_>17 4 3 2 3. 0 4.4359830208122730e-003 0.5399122238159180 0.3920140862464905 <_> <_> <_>1 5 3 4 -1. <_>2 5 1 4 3. 0 2.6606200262904167e-003 0.4482578039169312 0.6119617819786072 <_> <_> <_>14 8 4 6 -1. <_>14 10 4 2 3. 0 -1.5287200221791863e-003 0.3711237907409668 0.5340266227722168 <_> <_> <_>1 4 3 8 -1. <_>2 4 1 8 3. 0 -4.7397250309586525e-003 0.6031088232994080 0.4455145001411438 <_> <_> <_>8 13 4 6 -1. <_>8 16 4 3 2. 0 -0.0148291299119592 0.2838754057884216 0.5341861844062805 <_> <_> <_>3 14 2 2 -1. <_>3 15 2 1 2. 0 9.2275557108223438e-004 0.5209547281265259 0.3361653983592987 <_> <_> <_>14 8 4 6 -1. <_>14 10 4 2 3. 0 0.0835298076272011 0.5119969844818115 0.0811644494533539 <_> <_> <_>2 8 4 6 -1. <_>2 10 4 2 3. 0 -7.5633148662745953e-004 0.3317120075225830 0.5189831256866455 <_> <_> <_>10 14 1 6 -1. <_>10 17 1 3 2. 0 9.8403859883546829e-003 0.5247598290443420 0.2334959059953690 <_> <_> <_>7 5 3 6 -1. <_>8 5 1 6 3. 0 -1.5953830443322659e-003 0.5750094056129456 0.4295622110366821 <_> <_> <_>11 2 2 6 -1. <_>12 2 1 3 2. <_>11 5 1 3 2. 0 3.4766020689858124e-005 0.4342445135116577 0.5564029216766357 <_> <_> <_>6 6 6 5 -1. <_>8 6 2 5 3. 0 0.0298629105091095 0.4579147100448608 0.6579188108444214 <_> <_> <_>17 1 3 6 -1. <_>17 3 3 2 3. 0 0.0113255903124809 0.5274311900138855 0.3673888146877289 <_> <_> <_>8 7 3 5 -1. <_>9 7 1 5 3. 0 -8.7828645482659340e-003 0.7100368738174439 0.4642167091369629 <_> <_> <_>9 18 3 2 -1. <_>10 18 1 2 3. 0 4.3639959767460823e-003 0.5279216170310974 0.2705877125263214 <_> <_> <_>8 18 3 2 -1. <_>9 18 1 2 3. 0 4.1804728098213673e-003 0.5072525143623352 0.2449083030223846 <_> <_> <_>12 3 5 2 -1. <_>12 4 5 1 2. 0 -4.5668511302210391e-004 0.4283105134963989 0.5548691153526306 <_> <_> <_>7 1 5 12 -1. <_>7 7 5 6 2. 0 -3.7140368949621916e-003 0.5519387722015381 0.4103653132915497 <_> <_> <_>1 0 18 4 -1. <_>7 0 6 4 3. 0 -0.0253042895346880 0.6867002248764038 0.4869889020919800 <_> <_> <_>4 2 2 2 -1. <_>4 3 2 1 2. 0 -3.4454080741852522e-004 0.3728874027729034 0.5287693142890930 <_> <_> <_>11 14 4 2 -1. <_>13 14 2 1 2. <_>11 15 2 1 2. 0 -8.3935231668874621e-004 0.6060152053833008 0.4616062045097351 <_> <_> <_>0 2 3 6 -1. <_>0 4 3 2 3. 0 0.0172800496220589 0.5049635767936707 0.1819823980331421 <_> <_> <_>9 7 2 3 -1. <_>9 8 2 1 3. 0 -6.3595077954232693e-003 0.1631239950656891 0.5232778787612915 <_> <_> <_>5 5 1 3 -1. <_>5 6 1 1 3. 0 1.0298109846189618e-003 0.4463278055191040 0.6176549196243286 <_> <_> <_>10 10 6 1 -1. <_>10 10 3 1 2. 0 1.0117109632119536e-003 0.5473384857177734 0.4300698935985565 <_> <_> <_>4 10 6 1 -1. <_>7 10 3 1 2. 0 -0.0103088002651930 0.1166985034942627 0.5000867247581482 <_> <_> <_>9 17 3 3 -1. <_>9 18 3 1 3. 0 5.4682018235325813e-003 0.4769287109375000 0.6719213724136353 <_> <_> <_>4 14 1 3 -1. <_>4 15 1 1 3. 0 -9.1696460731327534e-004 0.3471089899539948 0.5178164839744568 <_> <_> <_>12 5 3 3 -1. <_>12 6 3 1 3. 0 2.3922820109874010e-003 0.4785236120223999 0.6216310858726502 <_> <_> <_>4 5 12 3 -1. <_>4 6 12 1 3. 0 -7.5573818758130074e-003 0.5814796090126038 0.4410085082054138 <_> <_> <_>9 8 2 3 -1. <_>9 9 2 1 3. 0 -7.7024032361805439e-004 0.3878000080585480 0.5465722084045410 <_> <_> <_>4 9 3 3 -1. <_>5 9 1 3 3. 0 -8.7125990539789200e-003 0.1660051047801971 0.4995836019515991 <_> <_> <_>6 0 9 17 -1. <_>9 0 3 17 3. 0 -0.0103063201531768 0.4093391001224518 0.5274233818054199 <_> <_> <_>9 12 1 3 -1. <_>9 13 1 1 3. 0 -2.0940979011356831e-003 0.6206194758415222 0.4572280049324036 <_> <_> <_>9 5 2 15 -1. <_>9 10 2 5 3. 0 6.8099051713943481e-003 0.5567759275436401 0.4155600070953369 <_> <_> <_>8 14 2 3 -1. <_>8 15 2 1 3. 0 -1.0746059706434608e-003 0.5638927817344666 0.4353024959564209 <_> <_> <_>10 14 1 3 -1. <_>10 15 1 1 3. 0 2.1550289820879698e-003 0.4826265871524811 0.6749758124351502 <_> <_> <_>7 1 6 5 -1. <_>9 1 2 5 3. 0 0.0317423194646835 0.5048379898071289 0.1883248984813690 <_> <_> <_>0 0 20 2 -1. <_>0 0 10 2 2. 0 -0.0783827230334282 0.2369548976421356 0.5260158181190491 <_> <_> <_>2 13 5 3 -1. <_>2 14 5 1 3. 0 5.7415119372308254e-003 0.5048828721046448 0.2776469886302948 <_> <_> <_>9 11 2 3 -1. <_>9 12 2 1 3. 0 -2.9014600440859795e-003 0.6238604784011841 0.4693317115306854 <_> <_> <_>2 5 9 15 -1. <_>2 10 9 5 3. 0 -2.6427931152284145e-003 0.3314141929149628 0.5169777274131775 <_> <_> <_>5 0 12 10 -1. <_>11 0 6 5 2. <_>5 5 6 5 2. 0 -0.1094966009259224 0.2380045056343079 0.5183441042900085 <_> <_> <_>5 1 2 3 -1. <_>6 1 1 3 2. 0 7.4075913289561868e-005 0.4069635868072510 0.5362150073051453 <_> <_> <_>10 7 6 1 -1. <_>12 7 2 1 3. 0 -5.0593802006915212e-004 0.5506706237792969 0.4374594092369080 <_> <_> <_>3 1 2 10 -1. <_>3 1 1 5 2. <_>4 6 1 5 2. 0 -8.2131777890026569e-004 0.5525709986686707 0.4209375977516174 <_> <_> <_>13 7 2 1 -1. <_>13 7 1 1 2. 0 -6.0276539443293586e-005 0.5455474853515625 0.4748266041278839 <_> <_> <_>4 13 4 6 -1. <_>4 15 4 2 3. 0 6.8065142259001732e-003 0.5157995820045471 0.3424577116966248 <_> <_> <_>13 7 2 1 -1. <_>13 7 1 1 2. 0 1.7202789895236492e-003 0.5013207793235779 0.6331263780593872 <_> <_> <_>5 7 2 1 -1. <_>6 7 1 1 2. 0 -1.3016929733566940e-004 0.5539718270301819 0.4226869940757752 <_> <_> <_>2 12 18 4 -1. <_>11 12 9 2 2. <_>2 14 9 2 2. 0 -4.8016388900578022e-003 0.4425095021724701 0.5430780053138733 <_> <_> <_>5 7 2 2 -1. <_>5 7 1 1 2. <_>6 8 1 1 2. 0 -2.5399310979992151e-003 0.7145782113075256 0.4697605073451996 <_> <_> <_>16 3 4 2 -1. <_>16 4 4 1 2. 0 -1.4278929447755218e-003 0.4070445001125336 0.5399605035781860 <_> <_> <_>0 2 2 18 -1. <_>0 2 1 9 2. <_>1 11 1 9 2. 0 -0.0251425504684448 0.7884690761566162 0.4747352004051209 <_> <_> <_>1 2 18 4 -1. <_>10 2 9 2 2. <_>1 4 9 2 2. 0 -3.8899609353393316e-003 0.4296191930770874 0.5577110052108765 <_> <_> <_>9 14 1 3 -1. <_>9 15 1 1 3. 0 4.3947459198534489e-003 0.4693162143230438 0.7023944258689880 <_> <_> <_>2 12 18 4 -1. <_>11 12 9 2 2. <_>2 14 9 2 2. 0 0.0246784202754498 0.5242322087287903 0.3812510073184967 <_> <_> <_>0 12 18 4 -1. <_>0 12 9 2 2. <_>9 14 9 2 2. 0 0.0380476787686348 0.5011739730834961 0.1687828004360199 <_> <_> <_>11 4 5 3 -1. <_>11 5 5 1 3. 0 7.9424865543842316e-003 0.4828582108020783 0.6369568109512329 <_> <_> <_>6 4 7 3 -1. <_>6 5 7 1 3. 0 -1.5110049862414598e-003 0.5906485915184021 0.4487667977809906 <_> <_> <_>13 17 3 3 -1. <_>13 18 3 1 3. 0 6.4201741479337215e-003 0.5241097807884216 0.2990570068359375 <_> <_> <_>8 1 3 4 -1. <_>9 1 1 4 3. 0 -2.9802159406244755e-003 0.3041465878486633 0.5078489780426025 <_> <_> <_>11 4 2 4 -1. <_>11 4 1 4 2. 0 -7.4580078944563866e-004 0.4128139019012451 0.5256826281547546 <_> <_> <_>0 17 9 3 -1. <_>3 17 3 3 3. 0 -0.0104709500446916 0.5808395147323608 0.4494296014308929 <_> <_> <_>11 0 2 8 -1. <_>12 0 1 4 2. <_>11 4 1 4 2. 0 9.3369204550981522e-003 0.5246552824974060 0.2658948898315430 <_> <_> <_>0 8 6 12 -1. <_>0 8 3 6 2. <_>3 14 3 6 2. 0 0.0279369000345469 0.4674955010414124 0.7087256908416748 <_> <_> <_>10 7 4 12 -1. <_>10 13 4 6 2. 0 7.4277678504586220e-003 0.5409486889839172 0.3758518099784851 <_> <_> <_>5 3 8 14 -1. <_>5 10 8 7 2. 0 -0.0235845092684031 0.3758639991283417 0.5238550901412964 <_> <_> <_>14 10 6 1 -1. <_>14 10 3 1 2. 0 1.1452640173956752e-003 0.4329578876495361 0.5804247260093689 <_> <_> <_>0 4 10 4 -1. <_>0 6 10 2 2. 0 -4.3468660442158580e-004 0.5280618071556091 0.3873069882392883 <_> <_> <_>10 0 5 8 -1. <_>10 4 5 4 2. 0 0.0106485402211547 0.4902113080024719 0.5681251883506775 <_> <_> <_>8 1 4 8 -1. <_>8 1 2 4 2. <_>10 5 2 4 2. 0 -3.9418050437234342e-004 0.5570880174636841 0.4318251013755798 <_> <_> <_>9 11 6 1 -1. <_>11 11 2 1 3. 0 -1.3270479394122958e-004 0.5658439993858337 0.4343554973602295 <_> <_> <_>8 9 3 4 -1. <_>9 9 1 4 3. 0 -2.0125510636717081e-003 0.6056739091873169 0.4537523984909058 <_> <_> <_>18 4 2 6 -1. <_>18 6 2 2 3. 0 2.4854319635778666e-003 0.5390477180480957 0.4138010144233704 <_> <_> <_>8 8 3 4 -1. <_>9 8 1 4 3. 0 1.8237880431115627e-003 0.4354828894138336 0.5717188715934753 <_> <_> <_>7 1 13 3 -1. <_>7 2 13 1 3. 0 -0.0166566595435143 0.3010913133621216 0.5216122865676880 <_> <_> <_>7 13 6 1 -1. <_>9 13 2 1 3. 0 8.0349558265879750e-004 0.5300151109695435 0.3818396925926209 <_> <_> <_>12 11 3 6 -1. <_>12 13 3 2 3. 0 3.4170378930866718e-003 0.5328028798103333 0.4241400063037872 <_> <_> <_>5 11 6 1 -1. <_>7 11 2 1 3. 0 -3.6222729249857366e-004 0.5491728186607361 0.4186977148056030 <_> <_> <_>1 4 18 10 -1. <_>10 4 9 5 2. <_>1 9 9 5 2. 0 -0.1163002029061317 0.1440722048282623 0.5226451158523560 <_> <_> <_>8 6 4 9 -1. <_>8 9 4 3 3. 0 -0.0146950101479888 0.7747725248336792 0.4715717136859894 <_> <_> <_>8 6 4 3 -1. <_>8 7 4 1 3. 0 2.1972130052745342e-003 0.5355433821678162 0.3315644860267639 <_> <_> <_>8 7 3 3 -1. <_>9 7 1 3 3. 0 -4.6965209185145795e-004 0.5767235159873962 0.4458136856555939 <_> <_> <_>14 15 4 3 -1. <_>14 16 4 1 3. 0 6.5144998952746391e-003 0.5215674042701721 0.3647888898849487 <_> <_> <_>5 10 3 10 -1. <_>6 10 1 10 3. 0 0.0213000606745481 0.4994204938411713 0.1567950993776321 <_> <_> <_>8 15 4 3 -1. <_>8 16 4 1 3. 0 3.1881409231573343e-003 0.4742200076580048 0.6287270188331604 <_> <_> <_>0 8 1 6 -1. <_>0 10 1 2 3. 0 9.0019777417182922e-004 0.5347954034805298 0.3943752050399780 <_> <_> <_>10 15 1 3 -1. <_>10 16 1 1 3. 0 -5.1772277802228928e-003 0.6727191805839539 0.5013138055801392 <_> <_> <_>2 15 4 3 -1. <_>2 16 4 1 3. 0 -4.3764649890363216e-003 0.3106675148010254 0.5128793120384216 <_> <_> <_>18 3 2 8 -1. <_>19 3 1 4 2. <_>18 7 1 4 2. 0 2.6299960445612669e-003 0.4886310100555420 0.5755215883255005 <_> <_> <_>0 3 2 8 -1. <_>0 3 1 4 2. <_>1 7 1 4 2. 0 -2.0458688959479332e-003 0.6025794148445129 0.4558076858520508 <_> <_> <_>3 7 14 10 -1. <_>10 7 7 5 2. <_>3 12 7 5 2. 0 0.0694827064871788 0.5240747928619385 0.2185259014368057 <_> <_> <_>0 7 19 3 -1. <_>0 8 19 1 3. 0 0.0240489393472672 0.5011867284774780 0.2090622037649155 <_> <_> <_>12 6 3 3 -1. <_>12 7 3 1 3. 0 3.1095340382307768e-003 0.4866712093353272 0.7108548283576965 <_> <_> <_>0 6 1 3 -1. <_>0 7 1 1 3. 0 -1.2503260513767600e-003 0.3407891094684601 0.5156195163726807 <_> <_> <_>12 6 3 3 -1. <_>12 7 3 1 3. 0 -1.0281190043315291e-003 0.5575572252273560 0.4439432024955750 <_> <_> <_>5 6 3 3 -1. <_>5 7 3 1 3. 0 -8.8893622159957886e-003 0.6402000784873962 0.4620442092418671 <_> <_> <_>8 2 4 2 -1. <_>8 3 4 1 2. 0 -6.1094801640138030e-004 0.3766441941261292 0.5448899865150452 <_> <_> <_>6 3 4 12 -1. <_>8 3 2 12 2. 0 -5.7686357758939266e-003 0.3318648934364319 0.5133677124977112 <_> <_> <_>13 6 2 3 -1. <_>13 7 2 1 3. 0 1.8506490159779787e-003 0.4903570115566254 0.6406934857368469 <_> <_> <_>0 10 20 4 -1. <_>0 12 20 2 2. 0 -0.0997994691133499 0.1536051034927368 0.5015562176704407 <_> <_> <_>2 0 17 14 -1. <_>2 7 17 7 2. 0 -0.3512834906578064 0.0588231310248375 0.5174378752708435 <_> <_> <_>0 0 6 10 -1. <_>0 0 3 5 2. <_>3 5 3 5 2. 0 -0.0452445708215237 0.6961488723754883 0.4677872955799103 <_> <_> <_>14 6 6 4 -1. <_>14 6 3 4 2. 0 0.0714815780520439 0.5167986154556274 0.1038092970848084 <_> <_> <_>0 6 6 4 -1. <_>3 6 3 4 2. 0 2.1895780228078365e-003 0.4273078143596649 0.5532060861587524 <_> <_> <_>13 2 7 2 -1. <_>13 3 7 1 2. 0 -5.9242651332169771e-004 0.4638943970203400 0.5276389122009277 <_> <_> <_>0 2 7 2 -1. <_>0 3 7 1 2. 0 1.6788389766588807e-003 0.5301648974418640 0.3932034969329834 <_> <_> <_>6 11 14 2 -1. <_>13 11 7 1 2. <_>6 12 7 1 2. 0 -2.2163488902151585e-003 0.5630694031715393 0.4757033884525299 <_> <_> <_>8 5 2 2 -1. <_>8 5 1 1 2. <_>9 6 1 1 2. 0 1.1568699846975505e-004 0.4307535886764526 0.5535702705383301 <_> <_> <_>13 9 2 3 -1. <_>13 9 1 3 2. 0 -7.2017288766801357e-003 0.1444882005453110 0.5193064212799072 <_> <_> <_>1 1 3 12 -1. <_>2 1 1 12 3. 0 8.9081272017210722e-004 0.4384432137012482 0.5593621134757996 <_> <_> <_>17 4 1 3 -1. <_>17 5 1 1 3. 0 1.9605009583756328e-004 0.5340415835380554 0.4705956876277924 <_> <_> <_>2 4 1 3 -1. <_>2 5 1 1 3. 0 5.2022142335772514e-004 0.5213856101036072 0.3810079097747803 <_> <_> <_>14 5 1 3 -1. <_>14 6 1 1 3. 0 9.4588572392240167e-004 0.4769414961338043 0.6130738854408264 <_> <_> <_>7 16 2 3 -1. <_>7 17 2 1 3. 0 9.1698471806012094e-005 0.4245009124279022 0.5429363250732422 <_> <_> <_>8 13 4 6 -1. <_>10 13 2 3 2. <_>8 16 2 3 2. 0 2.1833200007677078e-003 0.5457730889320374 0.4191075861454010 <_> <_> <_>5 5 1 3 -1. <_>5 6 1 1 3. 0 -8.6039671441540122e-004 0.5764588713645935 0.4471659958362579 <_> <_> <_>16 0 4 20 -1. <_>16 0 2 20 2. 0 -0.0132362395524979 0.6372823119163513 0.4695009887218475 <_> <_> <_>5 1 2 6 -1. <_>5 1 1 3 2. <_>6 4 1 3 2. 0 4.3376701069064438e-004 0.5317873954772949 0.3945829868316650 67.6989212036132810 14 -1 <_> <_> <_> <_>5 4 10 4 -1. <_>5 6 10 2 2. 0 -0.0248471498489380 0.6555516719818115 0.3873311877250671 <_> <_> <_>15 2 4 12 -1. <_>15 2 2 12 2. 0 6.1348611488938332e-003 0.3748072087764740 0.5973997712135315 <_> <_> <_>7 6 4 12 -1. <_>7 12 4 6 2. 0 6.4498498104512691e-003 0.5425491929054260 0.2548811137676239 <_> <_> <_>14 5 1 8 -1. <_>14 9 1 4 2. 0 6.3491211039945483e-004 0.2462442070245743 0.5387253761291504 <_> <_> <_>1 4 14 10 -1. <_>1 4 7 5 2. <_>8 9 7 5 2. 0 1.4023890253156424e-003 0.5594322085380554 0.3528657853603363 <_> <_> <_>11 6 6 14 -1. <_>14 6 3 7 2. <_>11 13 3 7 2. 0 3.0044000595808029e-004 0.3958503901958466 0.5765938162803650 <_> <_> <_>3 6 6 14 -1. <_>3 6 3 7 2. <_>6 13 3 7 2. 0 1.0042409849120304e-004 0.3698996901512146 0.5534998178482056 <_> <_> <_>4 9 15 2 -1. <_>9 9 5 2 3. 0 -5.0841490738093853e-003 0.3711090981960297 0.5547800064086914 <_> <_> <_>7 14 6 3 -1. <_>7 15 6 1 3. 0 -0.0195372607558966 0.7492755055427551 0.4579297006130219 <_> <_> <_>6 3 14 4 -1. <_>13 3 7 2 2. <_>6 5 7 2 2. 0 -7.4532740654831287e-006 0.5649787187576294 0.3904069960117340 <_> <_> <_>1 9 15 2 -1. <_>6 9 5 2 3. 0 -3.6079459823668003e-003 0.3381088078022003 0.5267801284790039 <_> <_> <_>6 11 8 9 -1. <_>6 14 8 3 3. 0 2.0697501022368670e-003 0.5519291162490845 0.3714388906955719 <_> <_> <_>7 4 3 8 -1. <_>8 4 1 8 3. 0 -4.6463840408250690e-004 0.5608214735984802 0.4113566875457764 <_> <_> <_>14 6 2 6 -1. <_>14 9 2 3 2. 0 7.5490452582016587e-004 0.3559206128120422 0.5329356193542481 <_> <_> <_>5 7 6 4 -1. <_>5 7 3 2 2. <_>8 9 3 2 2. 0 -9.8322238773107529e-004 0.5414795875549316 0.3763205111026764 <_> <_> <_>1 1 18 19 -1. <_>7 1 6 19 3. 0 -0.0199406407773495 0.6347903013229370 0.4705299139022827 <_> <_> <_>1 2 6 5 -1. <_>4 2 3 5 2. 0 3.7680300883948803e-003 0.3913489878177643 0.5563716292381287 <_> <_> <_>12 17 6 2 -1. <_>12 18 6 1 2. 0 -9.4528505578637123e-003 0.2554892897605896 0.5215116739273071 <_> <_> <_>2 17 6 2 -1. <_>2 18 6 1 2. 0 2.9560849070549011e-003 0.5174679160118103 0.3063920140266419 <_> <_> <_>17 3 3 6 -1. <_>17 5 3 2 3. 0 9.1078737750649452e-003 0.5388448238372803 0.2885963022708893 <_> <_> <_>8 17 3 3 -1. <_>8 18 3 1 3. 0 1.8219229532405734e-003 0.4336043000221252 0.5852196812629700 <_> <_> <_>10 13 2 6 -1. <_>10 16 2 3 2. 0 0.0146887395530939 0.5287361741065979 0.2870005965232849 <_> <_> <_>7 13 6 3 -1. <_>7 14 6 1 3. 0 -0.0143879903480411 0.7019448876380920 0.4647370874881744 <_> <_> <_>17 3 3 6 -1. <_>17 5 3 2 3. 0 -0.0189866498112679 0.2986552119255066 0.5247011780738831 <_> <_> <_>8 13 2 3 -1. <_>8 14 2 1 3. 0 1.1527639580890536e-003 0.4323473870754242 0.5931661725044251 <_> <_> <_>9 3 6 2 -1. <_>11 3 2 2 3. 0 0.0109336702153087 0.5286864042282105 0.3130319118499756 <_> <_> <_>0 3 3 6 -1. <_>0 5 3 2 3. 0 -0.0149327302351594 0.2658419013023377 0.5084077119827271 <_> <_> <_>8 5 4 6 -1. <_>8 7 4 2 3. 0 -2.9970539617352188e-004 0.5463526844978333 0.3740724027156830 <_> <_> <_>5 5 3 2 -1. <_>5 6 3 1 2. 0 4.1677621193230152e-003 0.4703496992588043 0.7435721755027771 <_> <_> <_>10 1 3 4 -1. <_>11 1 1 4 3. 0 -6.3905320130288601e-003 0.2069258987903595 0.5280538201332092 <_> <_> <_>1 2 5 9 -1. <_>1 5 5 3 3. 0 4.5029609464108944e-003 0.5182648897171021 0.3483543097972870 <_> <_> <_>13 6 2 3 -1. <_>13 7 2 1 3. 0 -9.2040365561842918e-003 0.6803777217864990 0.4932360053062439 <_> <_> <_>0 6 14 3 -1. <_>7 6 7 3 2. 0 0.0813272595405579 0.5058398842811585 0.2253051996231079 <_> <_> <_>2 11 18 8 -1. <_>2 15 18 4 2. 0 -0.1507928073406220 0.2963424921035767 0.5264679789543152 <_> <_> <_>5 6 2 3 -1. <_>5 7 2 1 3. 0 3.3179009333252907e-003 0.4655495882034302 0.7072932124137878 <_> <_> <_>10 6 4 2 -1. <_>12 6 2 1 2. <_>10 7 2 1 2. 0 7.7402801252901554e-004 0.4780347943305969 0.5668237805366516 <_> <_> <_>6 6 4 2 -1. <_>6 6 2 1 2. <_>8 7 2 1 2. 0 6.8199541419744492e-004 0.4286996126174927 0.5722156763076782 <_> <_> <_>10 1 3 4 -1. <_>11 1 1 4 3. 0 5.3671570494771004e-003 0.5299307107925415 0.3114621937274933 <_> <_> <_>7 1 2 7 -1. <_>8 1 1 7 2. 0 9.7018666565418243e-005 0.3674638867378235 0.5269461870193481 <_> <_> <_>4 2 15 14 -1. <_>4 9 15 7 2. 0 -0.1253408938646317 0.2351492047309876 0.5245791077613831 <_> <_> <_>8 7 3 2 -1. <_>9 7 1 2 3. 0 -5.2516269497573376e-003 0.7115936875343323 0.4693767130374908 <_> <_> <_>2 3 18 4 -1. <_>11 3 9 2 2. <_>2 5 9 2 2. 0 -7.8342109918594360e-003 0.4462651014328003 0.5409085750579834 <_> <_> <_>9 7 2 2 -1. <_>10 7 1 2 2. 0 -1.1310069821774960e-003 0.5945618748664856 0.4417662024497986 <_> <_> <_>13 9 2 3 -1. <_>13 9 1 3 2. 0 1.7601120052859187e-003 0.5353249907493591 0.3973453044891357 <_> <_> <_>5 2 6 2 -1. <_>7 2 2 2 3. 0 -8.1581249833106995e-004 0.3760268092155457 0.5264726877212524 <_> <_> <_>9 5 2 7 -1. <_>9 5 1 7 2. 0 -3.8687589112669230e-003 0.6309912800788879 0.4749819934368134 <_> <_> <_>5 9 2 3 -1. <_>6 9 1 3 2. 0 1.5207129763439298e-003 0.5230181813240051 0.3361223936080933 <_> <_> <_>6 0 14 18 -1. <_>6 9 14 9 2. 0 0.5458673834800720 0.5167139768600464 0.1172635033726692 <_> <_> <_>2 16 6 3 -1. <_>2 17 6 1 3. 0 0.0156501904129982 0.4979439079761505 0.1393294930458069 <_> <_> <_>9 7 3 6 -1. <_>10 7 1 6 3. 0 -0.0117318602278829 0.7129650712013245 0.4921196103096008 <_> <_> <_>7 8 4 3 -1. <_>7 9 4 1 3. 0 -6.1765122227370739e-003 0.2288102954626083 0.5049701929092407 <_> <_> <_>7 12 6 3 -1. <_>7 13 6 1 3. 0 2.2457661107182503e-003 0.4632433950901032 0.6048725843429565 <_> <_> <_>9 12 2 3 -1. <_>9 13 2 1 3. 0 -5.1915869116783142e-003 0.6467421054840088 0.4602192938327789 <_> <_> <_>7 12 6 2 -1. <_>9 12 2 2 3. 0 -0.0238278806209564 0.1482000946998596 0.5226079225540161 <_> <_> <_>5 11 4 6 -1. <_>5 14 4 3 2. 0 1.0284580057486892e-003 0.5135489106178284 0.3375957012176514 <_> <_> <_>11 12 7 2 -1. <_>11 13 7 1 2. 0 -0.0100788502022624 0.2740561068058014 0.5303567051887512 <_> <_> <_>6 10 8 6 -1. <_>6 10 4 3 2. <_>10 13 4 3 2. 0 2.6168930344283581e-003 0.5332670807838440 0.3972454071044922 <_> <_> <_>11 10 3 4 -1. <_>11 12 3 2 2. 0 5.4385367548093200e-004 0.5365604162216187 0.4063411951065064 <_> <_> <_>9 16 2 3 -1. <_>9 17 2 1 3. 0 5.3510512225329876e-003 0.4653759002685547 0.6889045834541321 <_> <_> <_>13 3 1 9 -1. <_>13 6 1 3 3. 0 -1.5274790348485112e-003 0.5449501276016235 0.3624723851680756 <_> <_> <_>1 13 14 6 -1. <_>1 15 14 2 3. 0 -0.0806244164705276 0.1656087040901184 0.5000287294387817 <_> <_> <_>13 6 1 6 -1. <_>13 9 1 3 2. 0 0.0221920292824507 0.5132731199264526 0.2002808004617691 <_> <_> <_>0 4 3 8 -1. <_>1 4 1 8 3. 0 7.3100631125271320e-003 0.4617947936058044 0.6366536021232605 <_> <_> <_>18 0 2 18 -1. <_>18 0 1 18 2. 0 -6.4063072204589844e-003 0.5916250944137573 0.4867860972881317 <_> <_> <_>2 3 6 2 -1. <_>2 4 6 1 2. 0 -7.6415040530264378e-004 0.3888409137725830 0.5315797924995422 <_> <_> <_>9 0 8 6 -1. <_>9 2 8 2 3. 0 7.6734489994123578e-004 0.4159064888954163 0.5605279803276062 <_> <_> <_>6 6 1 6 -1. <_>6 9 1 3 2. 0 6.1474501853808761e-004 0.3089022040367127 0.5120148062705994 <_> <_> <_>14 8 6 3 -1. <_>14 9 6 1 3. 0 -5.0105270929634571e-003 0.3972199857234955 0.5207306146621704 <_> <_> <_>0 0 2 18 -1. <_>1 0 1 18 2. 0 -8.6909132078289986e-003 0.6257408261299133 0.4608575999736786 <_> <_> <_>1 18 18 2 -1. <_>10 18 9 1 2. <_>1 19 9 1 2. 0 -0.0163914598524570 0.2085209935903549 0.5242266058921814 <_> <_> <_>3 15 2 2 -1. <_>3 16 2 1 2. 0 4.0973909199237823e-004 0.5222427248954773 0.3780320882797241 <_> <_> <_>8 14 5 3 -1. <_>8 15 5 1 3. 0 -2.5242289993911982e-003 0.5803927183151245 0.4611890017986298 <_> <_> <_>8 14 2 3 -1. <_>8 15 2 1 3. 0 5.0945312250405550e-004 0.4401271939277649 0.5846015810966492 <_> <_> <_>12 3 3 3 -1. <_>13 3 1 3 3. 0 1.9656419754028320e-003 0.5322325229644775 0.4184590876102448 <_> <_> <_>7 5 6 2 -1. <_>9 5 2 2 3. 0 5.6298897834494710e-004 0.3741844892501831 0.5234565734863281 <_> <_> <_>15 5 5 2 -1. <_>15 6 5 1 2. 0 -6.7946797935292125e-004 0.4631041884422302 0.5356478095054627 <_> <_> <_>0 5 5 2 -1. <_>0 6 5 1 2. 0 7.2856349870562553e-003 0.5044670104980469 0.2377564013004303 <_> <_> <_>17 14 1 6 -1. <_>17 17 1 3 2. 0 -0.0174594894051552 0.7289121150970459 0.5050435066223145 <_> <_> <_>2 9 9 3 -1. <_>5 9 3 3 3. 0 -0.0254217498004436 0.6667134761810303 0.4678100049495697 <_> <_> <_>12 3 3 3 -1. <_>13 3 1 3 3. 0 -1.5647639520466328e-003 0.4391759037971497 0.5323626995086670 <_> <_> <_>0 0 4 18 -1. <_>2 0 2 18 2. 0 0.0114443600177765 0.4346440136432648 0.5680012106895447 <_> <_> <_>17 6 1 3 -1. <_>17 7 1 1 3. 0 -6.7352550104260445e-004 0.4477140903472900 0.5296812057495117 <_> <_> <_>2 14 1 6 -1. <_>2 17 1 3 2. 0 9.3194209039211273e-003 0.4740200042724609 0.7462607026100159 <_> <_> <_>19 8 1 2 -1. <_>19 9 1 1 2. 0 1.3328490604180843e-004 0.5365061759948731 0.4752134978771210 <_> <_> <_>5 3 3 3 -1. <_>6 3 1 3 3. 0 -7.8815799206495285e-003 0.1752219051122665 0.5015255212783814 <_> <_> <_>9 16 2 3 -1. <_>9 17 2 1 3. 0 -5.7985680177807808e-003 0.7271236777305603 0.4896200895309448 <_> <_> <_>2 6 1 3 -1. <_>2 7 1 1 3. 0 -3.8922499516047537e-004 0.4003908932209015 0.5344941020011902 <_> <_> <_>12 4 8 2 -1. <_>16 4 4 1 2. <_>12 5 4 1 2. 0 -1.9288610201328993e-003 0.5605612993240356 0.4803955852985382 <_> <_> <_>0 4 8 2 -1. <_>0 4 4 1 2. <_>4 5 4 1 2. 0 8.4214154630899429e-003 0.4753246903419495 0.7623608708381653 <_> <_> <_>2 16 18 4 -1. <_>2 18 18 2 2. 0 8.1655876711010933e-003 0.5393261909484863 0.4191643893718720 <_> <_> <_>7 15 2 4 -1. <_>7 17 2 2 2. 0 4.8280550981871784e-004 0.4240800142288208 0.5399821996688843 <_> <_> <_>4 0 14 3 -1. <_>4 1 14 1 3. 0 -2.7186630759388208e-003 0.4244599938392639 0.5424923896789551 <_> <_> <_>0 0 4 20 -1. <_>2 0 2 20 2. 0 -0.0125072300434113 0.5895841717720032 0.4550411105155945 <_> <_> <_>12 4 4 8 -1. <_>14 4 2 4 2. <_>12 8 2 4 2. 0 -0.0242865197360516 0.2647134959697723 0.5189179778099060 <_> <_> <_>6 7 2 2 -1. <_>6 7 1 1 2. <_>7 8 1 1 2. 0 -2.9676330741494894e-003 0.7347682714462280 0.4749749898910523 <_> <_> <_>10 6 2 3 -1. <_>10 7 2 1 3. 0 -0.0125289997085929 0.2756049931049347 0.5177599787712097 <_> <_> <_>8 7 3 2 -1. <_>8 8 3 1 2. 0 -1.0104000102728605e-003 0.3510560989379883 0.5144724249839783 <_> <_> <_>8 2 6 12 -1. <_>8 8 6 6 2. 0 -2.1348530426621437e-003 0.5637925863265991 0.4667319953441620 <_> <_> <_>4 0 11 12 -1. <_>4 4 11 4 3. 0 0.0195642597973347 0.4614573121070862 0.6137639880180359 <_> <_> <_>14 9 6 11 -1. <_>16 9 2 11 3. 0 -0.0971463471651077 0.2998378872871399 0.5193555951118469 <_> <_> <_>0 14 4 3 -1. <_>0 15 4 1 3. 0 4.5014568604528904e-003 0.5077884793281555 0.3045755922794342 <_> <_> <_>9 10 2 3 -1. <_>9 11 2 1 3. 0 6.3706971704959869e-003 0.4861018955707550 0.6887500882148743 <_> <_> <_>5 11 3 2 -1. <_>5 12 3 1 2. 0 -9.0721528977155685e-003 0.1673395931720734 0.5017563104629517 <_> <_> <_>9 15 3 3 -1. <_>10 15 1 3 3. 0 -5.3537208586931229e-003 0.2692756950855255 0.5242633223533630 <_> <_> <_>8 8 3 4 -1. <_>9 8 1 4 3. 0 -0.0109328404068947 0.7183864116668701 0.4736028909683228 <_> <_> <_>9 15 3 3 -1. <_>10 15 1 3 3. 0 8.2356072962284088e-003 0.5223966836929321 0.2389862984418869 <_> <_> <_>7 7 3 2 -1. <_>8 7 1 2 3. 0 -1.0038160253316164e-003 0.5719355940818787 0.4433943033218384 <_> <_> <_>2 10 16 4 -1. <_>10 10 8 2 2. <_>2 12 8 2 2. 0 4.0859128348529339e-003 0.5472841858863831 0.4148836135864258 <_> <_> <_>2 3 4 17 -1. <_>4 3 2 17 2. 0 0.1548541933298111 0.4973812103271484 0.0610615983605385 <_> <_> <_>15 13 2 7 -1. <_>15 13 1 7 2. 0 2.0897459762636572e-004 0.4709174036979675 0.5423889160156250 <_> <_> <_>2 2 6 1 -1. <_>5 2 3 1 2. 0 3.3316991175524890e-004 0.4089626967906952 0.5300992131233215 <_> <_> <_>5 2 12 4 -1. <_>9 2 4 4 3. 0 -0.0108134001493454 0.6104369759559631 0.4957334101200104 <_> <_> <_>6 0 8 12 -1. <_>6 0 4 6 2. <_>10 6 4 6 2. 0 0.0456560105085373 0.5069689154624939 0.2866660058498383 <_> <_> <_>13 7 2 2 -1. <_>14 7 1 1 2. <_>13 8 1 1 2. 0 1.2569549726322293e-003 0.4846917092800140 0.6318171024322510 <_> <_> <_>0 12 20 6 -1. <_>0 14 20 2 3. 0 -0.1201507002115250 0.0605261400341988 0.4980959892272949 <_> <_> <_>14 7 2 3 -1. <_>14 7 1 3 2. 0 -1.0533799650147557e-004 0.5363109707832336 0.4708042144775391 <_> <_> <_>0 8 9 12 -1. <_>3 8 3 12 3. 0 -0.2070319056510925 0.0596603304147720 0.4979098141193390 <_> <_> <_>3 0 16 2 -1. <_>3 0 8 2 2. 0 1.2909180077258497e-004 0.4712977111339569 0.5377997756004334 <_> <_> <_>6 15 3 3 -1. <_>6 16 3 1 3. 0 3.8818528992123902e-004 0.4363538026809692 0.5534191131591797 <_> <_> <_>8 15 6 3 -1. <_>8 16 6 1 3. 0 -2.9243610333651304e-003 0.5811185836791992 0.4825215935707092 <_> <_> <_>0 10 1 6 -1. <_>0 12 1 2 3. 0 8.3882332546636462e-004 0.5311700105667114 0.4038138985633850 <_> <_> <_>10 9 4 3 -1. <_>10 10 4 1 3. 0 -1.9061550265178084e-003 0.3770701885223389 0.5260015130043030 <_> <_> <_>9 15 2 3 -1. <_>9 16 2 1 3. 0 8.9514348655939102e-003 0.4766167998313904 0.7682183980941773 <_> <_> <_>5 7 10 1 -1. <_>5 7 5 1 2. 0 0.0130834598094225 0.5264462828636169 0.3062222003936768 <_> <_> <_>4 0 12 19 -1. <_>10 0 6 19 2. 0 -0.2115933001041412 0.6737198233604431 0.4695810079574585 <_> <_> <_>0 6 20 6 -1. <_>10 6 10 3 2. <_>0 9 10 3 2. 0 3.1493250280618668e-003 0.5644835233688355 0.4386953115463257 <_> <_> <_>3 6 2 2 -1. <_>3 6 1 1 2. <_>4 7 1 1 2. 0 3.9754100725986063e-004 0.4526061117649078 0.5895630121231079 <_> <_> <_>15 6 2 2 -1. <_>16 6 1 1 2. <_>15 7 1 1 2. 0 -1.3814480043947697e-003 0.6070582270622253 0.4942413866519928 <_> <_> <_>3 6 2 2 -1. <_>3 6 1 1 2. <_>4 7 1 1 2. 0 -5.8122188784182072e-004 0.5998213291168213 0.4508252143859863 <_> <_> <_>14 4 1 12 -1. <_>14 10 1 6 2. 0 -2.3905329871922731e-003 0.4205588996410370 0.5223848223686218 <_> <_> <_>2 5 16 10 -1. <_>2 5 8 5 2. <_>10 10 8 5 2. 0 0.0272689294070005 0.5206447243690491 0.3563301861286163 <_> <_> <_>9 17 3 2 -1. <_>10 17 1 2 3. 0 -3.7658358924090862e-003 0.3144704103469849 0.5218814015388489 <_> <_> <_>1 4 2 2 -1. <_>1 5 2 1 2. 0 -1.4903489500284195e-003 0.3380196094512940 0.5124437212944031 <_> <_> <_>5 0 15 5 -1. <_>10 0 5 5 3. 0 -0.0174282304942608 0.5829960703849793 0.4919725954532623 <_> <_> <_>0 0 15 5 -1. <_>5 0 5 5 3. 0 -0.0152780301868916 0.6163144707679749 0.4617887139320374 <_> <_> <_>11 2 2 17 -1. <_>11 2 1 17 2. 0 0.0319956094026566 0.5166357159614563 0.1712764054536820 <_> <_> <_>7 2 2 17 -1. <_>8 2 1 17 2. 0 -3.8256710395216942e-003 0.3408012092113495 0.5131387710571289 <_> <_> <_>15 11 2 9 -1. <_>15 11 1 9 2. 0 -8.5186436772346497e-003 0.6105518937110901 0.4997941851615906 <_> <_> <_>3 11 2 9 -1. <_>4 11 1 9 2. 0 9.0641621500253677e-004 0.4327270984649658 0.5582311153411865 <_> <_> <_>5 16 14 4 -1. <_>5 16 7 4 2. 0 0.0103448498994112 0.4855653047561646 0.5452420115470886 69.2298736572265630 15 -1 <_> <_> <_> <_>1 4 18 1 -1. <_>7 4 6 1 3. 0 7.8981826081871986e-003 0.3332524895668030 0.5946462154388428 <_> <_> <_>13 7 6 4 -1. <_>16 7 3 2 2. <_>13 9 3 2 2. 0 1.6170160379260778e-003 0.3490641117095947 0.5577868819236755 <_> <_> <_>9 8 2 12 -1. <_>9 12 2 4 3. 0 -5.5449741194024682e-004 0.5542566180229187 0.3291530013084412 <_> <_> <_>12 1 6 6 -1. <_>12 3 6 2 3. 0 1.5428980113938451e-003 0.3612579107284546 0.5545979142189026 <_> <_> <_>5 2 6 6 -1. <_>5 2 3 3 2. <_>8 5 3 3 2. 0 -1.0329450014978647e-003 0.3530139029026032 0.5576140284538269 <_> <_> <_>9 16 6 4 -1. <_>12 16 3 2 2. <_>9 18 3 2 2. 0 7.7698158565908670e-004 0.3916778862476349 0.5645321011543274 <_> <_> <_>1 2 18 3 -1. <_>7 2 6 3 3. 0 0.1432030051946640 0.4667482078075409 0.7023633122444153 <_> <_> <_>7 4 9 10 -1. <_>7 9 9 5 2. 0 -7.3866490274667740e-003 0.3073684871196747 0.5289257764816284 <_> <_> <_>5 9 4 4 -1. <_>7 9 2 4 2. 0 -6.2936742324382067e-004 0.5622118115425110 0.4037049114704132 <_> <_> <_>11 10 3 6 -1. <_>11 13 3 3 2. 0 7.8893528552725911e-004 0.5267661213874817 0.3557874858379364 <_> <_> <_>7 11 5 3 -1. <_>7 12 5 1 3. 0 -0.0122280502691865 0.6668320894241333 0.4625549912452698 <_> <_> <_>7 11 6 6 -1. <_>10 11 3 3 2. <_>7 14 3 3 2. 0 3.5420239437371492e-003 0.5521438121795654 0.3869673013687134 <_> <_> <_>0 0 10 9 -1. <_>0 3 10 3 3. 0 -1.0585320414975286e-003 0.3628678023815155 0.5320926904678345 <_> <_> <_>13 14 1 6 -1. <_>13 16 1 2 3. 0 1.4935660146875307e-005 0.4632444977760315 0.5363323092460632 <_> <_> <_>0 2 3 6 -1. <_>0 4 3 2 3. 0 5.2537708543241024e-003 0.5132231712341309 0.3265708982944489 <_> <_> <_>8 14 4 3 -1. <_>8 15 4 1 3. 0 -8.2338023930788040e-003 0.6693689823150635 0.4774140119552612 <_> <_> <_>6 14 1 6 -1. <_>6 16 1 2 3. 0 2.1866810129722580e-005 0.4053862094879150 0.5457931160926819 <_> <_> <_>9 15 2 3 -1. <_>9 16 2 1 3. 0 -3.8150229956954718e-003 0.6454995870590210 0.4793178141117096 <_> <_> <_>6 4 3 3 -1. <_>7 4 1 3 3. 0 1.1105879675596952e-003 0.5270407199859619 0.3529678881168366 <_> <_> <_>9 0 11 3 -1. <_>9 1 11 1 3. 0 -5.7707689702510834e-003 0.3803547024726868 0.5352957844734192 <_> <_> <_>0 6 20 3 -1. <_>0 7 20 1 3. 0 -3.0158339068293571e-003 0.5339403152465820 0.3887133002281189 <_> <_> <_>10 1 1 2 -1. <_>10 2 1 1 2. 0 -8.5453689098358154e-004 0.3564616143703461 0.5273603796958923 <_> <_> <_>9 6 2 6 -1. <_>10 6 1 6 2. 0 0.0110505102202296 0.4671907126903534 0.6849737763404846 <_> <_> <_>5 8 12 1 -1. <_>9 8 4 1 3. 0 0.0426058396697044 0.5151473283767700 0.0702200904488564 <_> <_> <_>3 8 12 1 -1. <_>7 8 4 1 3. 0 -3.0781750101596117e-003 0.3041661083698273 0.5152602195739746 <_> <_> <_>9 7 3 5 -1. <_>10 7 1 5 3. 0 -5.4815728217363358e-003 0.6430295705795288 0.4897229969501495 <_> <_> <_>3 9 6 2 -1. <_>6 9 3 2 2. 0 3.1881860923022032e-003 0.5307493209838867 0.3826209902763367 <_> <_> <_>12 9 3 3 -1. <_>12 10 3 1 3. 0 3.5947180003859103e-004 0.4650047123432159 0.5421904921531677 <_> <_> <_>7 0 6 1 -1. <_>9 0 2 1 3. 0 -4.0705031715333462e-003 0.2849679887294769 0.5079116225242615 <_> <_> <_>12 9 3 3 -1. <_>12 10 3 1 3. 0 -0.0145941702648997 0.2971645891666412 0.5128461718559265 <_> <_> <_>7 10 2 1 -1. <_>8 10 1 1 2. 0 -1.1947689927183092e-004 0.5631098151206970 0.4343082010746002 <_> <_> <_>6 4 9 13 -1. <_>9 4 3 13 3. 0 -6.9344649091362953e-004 0.4403578042984009 0.5359959006309509 <_> <_> <_>6 8 4 2 -1. <_>6 9 4 1 2. 0 1.4834799912932795e-005 0.3421008884906769 0.5164697766304016 <_> <_> <_>16 2 4 6 -1. <_>16 2 2 6 2. 0 9.0296985581517220e-003 0.4639343023300171 0.6114075183868408 <_> <_> <_>0 17 6 3 -1. <_>0 18 6 1 3. 0 -8.0640818923711777e-003 0.2820158898830414 0.5075494050979614 <_> <_> <_>10 10 3 10 -1. <_>10 15 3 5 2. 0 0.0260621197521687 0.5208905935287476 0.2688778042793274 <_> <_> <_>8 7 3 5 -1. <_>9 7 1 5 3. 0 0.0173146594315767 0.4663713872432709 0.6738539934158325 <_> <_> <_>10 4 4 3 -1. <_>10 4 2 3 2. 0 0.0226666405797005 0.5209349989891052 0.2212723940610886 <_> <_> <_>8 4 3 8 -1. <_>9 4 1 8 3. 0 -2.1965929772704840e-003 0.6063101291656494 0.4538190066814423 <_> <_> <_>6 6 9 13 -1. <_>9 6 3 13 3. 0 -9.5282476395368576e-003 0.4635204970836639 0.5247430801391602 <_> <_> <_>6 0 8 12 -1. <_>6 0 4 6 2. <_>10 6 4 6 2. 0 8.0943619832396507e-003 0.5289440155029297 0.3913882076740265 <_> <_> <_>14 2 6 8 -1. <_>16 2 2 8 3. 0 -0.0728773325681686 0.7752001881599426 0.4990234971046448 <_> <_> <_>6 0 3 6 -1. <_>7 0 1 6 3. 0 -6.9009521976113319e-003 0.2428039014339447 0.5048090219497681 <_> <_> <_>14 2 6 8 -1. <_>16 2 2 8 3. 0 -0.0113082397729158 0.5734364986419678 0.4842376112937927 <_> <_> <_>0 5 6 6 -1. <_>0 8 6 3 2. 0 0.0596132017672062 0.5029836297035217 0.2524977028369904 <_> <_> <_>9 12 6 2 -1. <_>12 12 3 1 2. <_>9 13 3 1 2. 0 -2.8624620754271746e-003 0.6073045134544373 0.4898459911346436 <_> <_> <_>8 17 3 2 -1. <_>9 17 1 2 3. 0 4.4781449250876904e-003 0.5015289187431335 0.2220316976308823 <_> <_> <_>11 6 2 2 -1. <_>12 6 1 1 2. <_>11 7 1 1 2. 0 -1.7513240454718471e-003 0.6614428758621216 0.4933868944644928 <_> <_> <_>1 9 18 2 -1. <_>7 9 6 2 3. 0 0.0401634201407433 0.5180878043174744 0.3741044998168945 <_> <_> <_>11 6 2 2 -1. <_>12 6 1 1 2. <_>11 7 1 1 2. 0 3.4768949262797832e-004 0.4720416963100433 0.5818032026290894 <_> <_> <_>3 4 12 8 -1. <_>7 4 4 8 3. 0 2.6551650371402502e-003 0.3805010914802551 0.5221335887908936 <_> <_> <_>13 11 5 3 -1. <_>13 12 5 1 3. 0 -8.7706279009580612e-003 0.2944166064262390 0.5231295228004456 <_> <_> <_>9 10 2 3 -1. <_>9 11 2 1 3. 0 -5.5122091434895992e-003 0.7346177101135254 0.4722816944122315 <_> <_> <_>14 7 2 3 -1. <_>14 7 1 3 2. 0 6.8672042107209563e-004 0.5452876091003418 0.4242413043975830 <_> <_> <_>5 4 1 3 -1. <_>5 5 1 1 3. 0 5.6019669864326715e-004 0.4398862123489380 0.5601285099983215 <_> <_> <_>13 4 2 3 -1. <_>13 5 2 1 3. 0 2.4143769405782223e-003 0.4741686880588532 0.6136621832847595 <_> <_> <_>5 4 2 3 -1. <_>5 5 2 1 3. 0 -1.5680900542065501e-003 0.6044552922248840 0.4516409933567047 <_> <_> <_>9 8 2 3 -1. <_>9 9 2 1 3. 0 -3.6827491130679846e-003 0.2452459037303925 0.5294982194900513 <_> <_> <_>8 9 2 2 -1. <_>8 10 2 1 2. 0 -2.9409190756268799e-004 0.3732838034629822 0.5251451134681702 <_> <_> <_>15 14 1 4 -1. <_>15 16 1 2 2. 0 4.2847759323194623e-004 0.5498809814453125 0.4065535068511963 <_> <_> <_>3 12 2 2 -1. <_>3 13 2 1 2. 0 -4.8817070201039314e-003 0.2139908969402313 0.4999957084655762 <_> <_> <_>12 15 2 2 -1. <_>13 15 1 1 2. <_>12 16 1 1 2. 0 2.7272020815871656e-004 0.4650287032127380 0.5813428759574890 <_> <_> <_>9 13 2 2 -1. <_>9 14 2 1 2. 0 2.0947199664078653e-004 0.4387486875057221 0.5572792887687683 <_> <_> <_>4 11 14 9 -1. <_>4 14 14 3 3. 0 0.0485011897981167 0.5244972705841065 0.3212889134883881 <_> <_> <_>7 13 4 3 -1. <_>7 14 4 1 3. 0 -4.5166411437094212e-003 0.6056813001632690 0.4545882046222687 <_> <_> <_>15 14 1 4 -1. <_>15 16 1 2 2. 0 -0.0122916800901294 0.2040929049253464 0.5152214169502258 <_> <_> <_>4 14 1 4 -1. <_>4 16 1 2 2. 0 4.8549679922871292e-004 0.5237604975700378 0.3739503026008606 <_> <_> <_>14 0 6 13 -1. <_>16 0 2 13 3. 0 0.0305560491979122 0.4960533976554871 0.5938246250152588 <_> <_> <_>4 1 2 12 -1. <_>4 1 1 6 2. <_>5 7 1 6 2. 0 -1.5105320198927075e-004 0.5351303815841675 0.4145204126834869 <_> <_> <_>11 14 6 6 -1. <_>14 14 3 3 2. <_>11 17 3 3 2. 0 2.4937440175563097e-003 0.4693366885185242 0.5514941215515137 <_> <_> <_>3 14 6 6 -1. <_>3 14 3 3 2. <_>6 17 3 3 2. 0 -0.0123821301385760 0.6791396737098694 0.4681667983531952 <_> <_> <_>14 17 3 2 -1. <_>14 18 3 1 2. 0 -5.1333461888134480e-003 0.3608739078044891 0.5229160189628601 <_> <_> <_>3 17 3 2 -1. <_>3 18 3 1 2. 0 5.1919277757406235e-004 0.5300073027610779 0.3633613884449005 <_> <_> <_>14 0 6 13 -1. <_>16 0 2 13 3. 0 0.1506042033433914 0.5157316923141480 0.2211782038211823 <_> <_> <_>0 0 6 13 -1. <_>2 0 2 13 3. 0 7.7144149690866470e-003 0.4410496950149536 0.5776609182357788 <_> <_> <_>10 10 7 6 -1. <_>10 12 7 2 3. 0 9.4443522393703461e-003 0.5401855111122131 0.3756650090217590 <_> <_> <_>6 15 2 2 -1. <_>6 15 1 1 2. <_>7 16 1 1 2. 0 2.5006249779835343e-004 0.4368270933628082 0.5607374906539917 <_> <_> <_>6 11 8 6 -1. <_>10 11 4 3 2. <_>6 14 4 3 2. 0 -3.3077150583267212e-003 0.4244799017906189 0.5518230795860291 <_> <_> <_>7 6 2 2 -1. <_>7 6 1 1 2. <_>8 7 1 1 2. 0 7.4048910755664110e-004 0.4496962130069733 0.5900576710700989 <_> <_> <_>2 2 16 6 -1. <_>10 2 8 3 2. <_>2 5 8 3 2. 0 0.0440920516848564 0.5293493270874023 0.3156355023384094 <_> <_> <_>5 4 3 3 -1. <_>5 5 3 1 3. 0 3.3639909233897924e-003 0.4483296871185303 0.5848662257194519 <_> <_> <_>11 7 3 10 -1. <_>11 12 3 5 2. 0 -3.9760079234838486e-003 0.4559507071971893 0.5483639240264893 <_> <_> <_>6 7 3 10 -1. <_>6 12 3 5 2. 0 2.7716930489987135e-003 0.5341786146163940 0.3792484104633331 <_> <_> <_>10 7 3 2 -1. <_>11 7 1 2 3. 0 -2.4123019829858094e-004 0.5667188763618469 0.4576973021030426 <_> <_> <_>8 12 4 2 -1. <_>8 13 4 1 2. 0 4.9425667384639382e-004 0.4421244859695435 0.5628787279129028 <_> <_> <_>10 1 1 3 -1. <_>10 2 1 1 3. 0 -3.8876468897797167e-004 0.4288370907306671 0.5391063094139099 <_> <_> <_>1 2 4 18 -1. <_>1 2 2 9 2. <_>3 11 2 9 2. 0 -0.0500488989055157 0.6899513006210327 0.4703742861747742 <_> <_> <_>12 4 4 12 -1. <_>12 10 4 6 2. 0 -0.0366354808211327 0.2217779010534287 0.5191826224327087 <_> <_> <_>0 0 1 6 -1. <_>0 2 1 2 3. 0 2.4273579474538565e-003 0.5136224031448364 0.3497397899627686 <_> <_> <_>9 11 2 3 -1. <_>9 12 2 1 3. 0 1.9558030180633068e-003 0.4826192855834961 0.6408380866050720 <_> <_> <_>8 7 4 3 -1. <_>8 8 4 1 3. 0 -1.7494610510766506e-003 0.3922835886478424 0.5272685289382935 <_> <_> <_>10 7 3 2 -1. <_>11 7 1 2 3. 0 0.0139550799503922 0.5078201889991760 0.8416504859924316 <_> <_> <_>7 7 3 2 -1. <_>8 7 1 2 3. 0 -2.1896739781368524e-004 0.5520489811897278 0.4314234852790833 <_> <_> <_>9 4 6 1 -1. <_>11 4 2 1 3. 0 -1.5131309628486633e-003 0.3934605121612549 0.5382571220397949 <_> <_> <_>8 7 2 3 -1. <_>9 7 1 3 2. 0 -4.3622800149023533e-003 0.7370628714561462 0.4736475944519043 <_> <_> <_>12 7 8 6 -1. <_>16 7 4 3 2. <_>12 10 4 3 2. 0 0.0651605874300003 0.5159279704093933 0.3281595110893250 <_> <_> <_>0 7 8 6 -1. <_>0 7 4 3 2. <_>4 10 4 3 2. 0 -2.3567399475723505e-003 0.3672826886177063 0.5172886252403259 <_> <_> <_>18 2 2 10 -1. <_>19 2 1 5 2. <_>18 7 1 5 2. 0 0.0151466596871614 0.5031493902206421 0.6687604188919067 <_> <_> <_>0 2 6 4 -1. <_>3 2 3 4 2. 0 -0.0228509604930878 0.6767519712448120 0.4709596931934357 <_> <_> <_>9 4 6 1 -1. <_>11 4 2 1 3. 0 4.8867650330066681e-003 0.5257998108863831 0.4059878885746002 <_> <_> <_>7 15 2 2 -1. <_>7 15 1 1 2. <_>8 16 1 1 2. 0 1.7619599821045995e-003 0.4696272909641266 0.6688278913497925 <_> <_> <_>11 13 1 6 -1. <_>11 16 1 3 2. 0 -1.2942519970238209e-003 0.4320712983608246 0.5344281792640686 <_> <_> <_>8 13 1 6 -1. <_>8 16 1 3 2. 0 0.0109299495816231 0.4997706115245819 0.1637486070394516 <_> <_> <_>14 3 2 1 -1. <_>14 3 1 1 2. 0 2.9958489903947338e-005 0.4282417893409729 0.5633224248886108 <_> <_> <_>8 15 2 3 -1. <_>8 16 2 1 3. 0 -6.5884361974895000e-003 0.6772121191024780 0.4700526893138886 <_> <_> <_>12 15 7 4 -1. <_>12 17 7 2 2. 0 3.2527779694646597e-003 0.5313397049903870 0.4536148905754089 <_> <_> <_>4 14 12 3 -1. <_>4 15 12 1 3. 0 -4.0435739792883396e-003 0.5660061836242676 0.4413388967514038 <_> <_> <_>10 3 3 2 -1. <_>11 3 1 2 3. 0 -1.2523540062829852e-003 0.3731913864612579 0.5356451869010925 <_> <_> <_>4 12 2 2 -1. <_>4 13 2 1 2. 0 1.9246719602961093e-004 0.5189986228942871 0.3738811016082764 <_> <_> <_>10 11 4 6 -1. <_>10 14 4 3 2. 0 -0.0385896712541580 0.2956373989582062 0.5188810825347900 <_> <_> <_>7 13 2 2 -1. <_>7 13 1 1 2. <_>8 14 1 1 2. 0 1.5489870565943420e-004 0.4347135126590729 0.5509533286094666 <_> <_> <_>4 11 14 4 -1. <_>11 11 7 2 2. <_>4 13 7 2 2. 0 -0.0337638482451439 0.3230330049991608 0.5195475816726685 <_> <_> <_>1 18 18 2 -1. <_>7 18 6 2 3. 0 -8.2657067105174065e-003 0.5975489020347595 0.4552114009857178 <_> <_> <_>11 18 2 2 -1. <_>12 18 1 1 2. <_>11 19 1 1 2. 0 1.4481440302915871e-005 0.4745678007602692 0.5497426986694336 <_> <_> <_>7 18 2 2 -1. <_>7 18 1 1 2. <_>8 19 1 1 2. 0 1.4951299817766994e-005 0.4324473142623901 0.5480644106864929 <_> <_> <_>12 18 8 2 -1. <_>12 19 8 1 2. 0 -0.0187417995184660 0.1580052971839905 0.5178533196449280 <_> <_> <_>7 14 6 2 -1. <_>7 15 6 1 2. 0 1.7572239739820361e-003 0.4517636895179749 0.5773764252662659 <_> <_> <_>8 12 4 8 -1. <_>10 12 2 4 2. <_>8 16 2 4 2. 0 -3.1391119118779898e-003 0.4149647951126099 0.5460842251777649 <_> <_> <_>4 9 3 3 -1. <_>4 10 3 1 3. 0 6.6656779381446540e-005 0.4039090871810913 0.5293084979057312 <_> <_> <_>7 10 6 2 -1. <_>9 10 2 2 3. 0 6.7743421532213688e-003 0.4767651855945587 0.6121956110000610 <_> <_> <_>5 0 4 15 -1. <_>7 0 2 15 2. 0 -7.3868161998689175e-003 0.3586258888244629 0.5187280774116516 <_> <_> <_>8 6 12 14 -1. <_>12 6 4 14 3. 0 0.0140409301966429 0.4712139964103699 0.5576155781745911 <_> <_> <_>5 16 3 3 -1. <_>5 17 3 1 3. 0 -5.5258329957723618e-003 0.2661027014255524 0.5039281249046326 <_> <_> <_>8 1 12 19 -1. <_>12 1 4 19 3. 0 0.3868423998355866 0.5144339799880981 0.2525899112224579 <_> <_> <_>3 0 3 2 -1. <_>3 1 3 1 2. 0 1.1459240340627730e-004 0.4284994900226593 0.5423371195793152 <_> <_> <_>10 12 4 5 -1. <_>10 12 2 5 2. 0 -0.0184675697237253 0.3885835111141205 0.5213062167167664 <_> <_> <_>6 12 4 5 -1. <_>8 12 2 5 2. 0 -4.5907011372037232e-004 0.5412563085556030 0.4235909879207611 <_> <_> <_>11 11 2 2 -1. <_>12 11 1 1 2. <_>11 12 1 1 2. 0 1.2527540093287826e-003 0.4899305105209351 0.6624091267585754 <_> <_> <_>0 2 3 6 -1. <_>0 4 3 2 3. 0 1.4910609461367130e-003 0.5286778211593628 0.4040051996707916 <_> <_> <_>11 11 2 2 -1. <_>12 11 1 1 2. <_>11 12 1 1 2. 0 -7.5435562757775187e-004 0.6032990217208862 0.4795120060443878 <_> <_> <_>7 6 4 10 -1. <_>7 11 4 5 2. 0 -6.9478838704526424e-003 0.4084401130676270 0.5373504161834717 <_> <_> <_>11 11 2 2 -1. <_>12 11 1 1 2. <_>11 12 1 1 2. 0 2.8092920547351241e-004 0.4846062958240509 0.5759382247924805 <_> <_> <_>2 13 5 2 -1. <_>2 14 5 1 2. 0 9.6073717577382922e-004 0.5164741277694702 0.3554979860782623 <_> <_> <_>11 11 2 2 -1. <_>12 11 1 1 2. <_>11 12 1 1 2. 0 -2.6883929967880249e-004 0.5677582025527954 0.4731765985488892 <_> <_> <_>7 11 2 2 -1. <_>7 11 1 1 2. <_>8 12 1 1 2. 0 2.1599370520561934e-003 0.4731487035751343 0.7070567011833191 <_> <_> <_>14 13 3 3 -1. <_>14 14 3 1 3. 0 5.6235301308333874e-003 0.5240243077278137 0.2781791985034943 <_> <_> <_>3 13 3 3 -1. <_>3 14 3 1 3. 0 -5.0243991427123547e-003 0.2837013900279999 0.5062304139137268 <_> <_> <_>9 14 2 3 -1. <_>9 15 2 1 3. 0 -9.7611639648675919e-003 0.7400717735290527 0.4934569001197815 <_> <_> <_>8 7 3 3 -1. <_>8 8 3 1 3. 0 4.1515100747346878e-003 0.5119131207466126 0.3407008051872253 <_> <_> <_>13 5 3 3 -1. <_>13 6 3 1 3. 0 6.2465080991387367e-003 0.4923788011074066 0.6579058766365051 <_> <_> <_>0 9 5 3 -1. <_>0 10 5 1 3. 0 -7.0597478188574314e-003 0.2434711009263992 0.5032842159271240 <_> <_> <_>13 5 3 3 -1. <_>13 6 3 1 3. 0 -2.0587709732353687e-003 0.5900310873985291 0.4695087075233460 <_> <_> <_>9 12 2 8 -1. <_>9 12 1 4 2. <_>10 16 1 4 2. 0 -2.4146060459315777e-003 0.3647317886352539 0.5189201831817627 <_> <_> <_>11 7 2 2 -1. <_>12 7 1 1 2. <_>11 8 1 1 2. 0 -1.4817609917372465e-003 0.6034948229789734 0.4940128028392792 <_> <_> <_>0 16 6 4 -1. <_>3 16 3 4 2. 0 -6.3016400672495365e-003 0.5818989872932434 0.4560427963733673 <_> <_> <_>10 6 2 3 -1. <_>10 7 2 1 3. 0 3.4763428848236799e-003 0.5217475891113281 0.3483993113040924 <_> <_> <_>9 5 2 6 -1. <_>9 7 2 2 3. 0 -0.0222508702427149 0.2360700070858002 0.5032082796096802 <_> <_> <_>12 15 8 4 -1. <_>12 15 4 4 2. 0 -0.0306125506758690 0.6499186754226685 0.4914919137954712 <_> <_> <_>0 14 8 6 -1. <_>4 14 4 6 2. 0 0.0130574796348810 0.4413323104381561 0.5683764219284058 <_> <_> <_>9 0 3 2 -1. <_>10 0 1 2 3. 0 -6.0095742810517550e-004 0.4359731078147888 0.5333483219146729 <_> <_> <_>4 15 4 2 -1. <_>6 15 2 2 2. 0 -4.1514250915497541e-004 0.5504062771797180 0.4326060116291046 <_> <_> <_>12 7 3 13 -1. <_>13 7 1 13 3. 0 -0.0137762902304530 0.4064112901687622 0.5201548933982849 <_> <_> <_>5 7 3 13 -1. <_>6 7 1 13 3. 0 -0.0322965085506439 0.0473519712686539 0.4977194964885712 <_> <_> <_>9 6 3 9 -1. <_>9 9 3 3 3. 0 0.0535569787025452 0.4881733059883118 0.6666939258575440 <_> <_> <_>4 4 7 12 -1. <_>4 10 7 6 2. 0 8.1889545544981956e-003 0.5400037169456482 0.4240820109844208 <_> <_> <_>12 12 2 2 -1. <_>13 12 1 1 2. <_>12 13 1 1 2. 0 2.1055320394225419e-004 0.4802047908306122 0.5563852787017822 <_> <_> <_>6 12 2 2 -1. <_>6 12 1 1 2. <_>7 13 1 1 2. 0 -2.4382730480283499e-003 0.7387793064117432 0.4773685038089752 <_> <_> <_>8 9 4 2 -1. <_>10 9 2 1 2. <_>8 10 2 1 2. 0 3.2835570164024830e-003 0.5288546085357666 0.3171291947364807 <_> <_> <_>3 6 2 2 -1. <_>3 6 1 1 2. <_>4 7 1 1 2. 0 2.3729570675641298e-003 0.4750812947750092 0.7060170769691467 <_> <_> <_>16 6 3 2 -1. <_>16 7 3 1 2. 0 -1.4541699783876538e-003 0.3811730146408081 0.5330739021301270 79.2490768432617190 16 -1 <_> <_> <_> <_>0 7 19 4 -1. <_>0 9 19 2 2. 0 0.0557552389800549 0.4019156992435455 0.6806036829948425 <_> <_> <_>10 2 10 1 -1. <_>10 2 5 1 2. 0 2.4730248842388391e-003 0.3351148962974548 0.5965719819068909 <_> <_> <_>9 4 2 12 -1. <_>9 10 2 6 2. 0 -3.5031698644161224e-004 0.5557708144187927 0.3482286930084229 <_> <_> <_>12 18 4 1 -1. <_>12 18 2 1 2. 0 5.4167630150914192e-004 0.4260858893394470 0.5693380832672119 <_> <_> <_>1 7 6 4 -1. <_>1 7 3 2 2. <_>4 9 3 2 2. 0 7.7193678589537740e-004 0.3494240045547485 0.5433688759803772 <_> <_> <_>12 0 6 13 -1. <_>14 0 2 13 3. 0 -1.5999219613149762e-003 0.4028499126434326 0.5484359264373779 <_> <_> <_>2 0 6 13 -1. <_>4 0 2 13 3. 0 -1.1832080053864047e-004 0.3806901872158051 0.5425465106964111 <_> <_> <_>10 5 8 8 -1. <_>10 9 8 4 2. 0 3.2909031142480671e-004 0.2620100080966950 0.5429521799087524 <_> <_> <_>8 3 2 5 -1. <_>9 3 1 5 2. 0 2.9518108931370080e-004 0.3799768984317780 0.5399264097213745 <_> <_> <_>8 4 9 1 -1. <_>11 4 3 1 3. 0 9.0466710389591753e-005 0.4433645009994507 0.5440226197242737 <_> <_> <_>3 4 9 1 -1. <_>6 4 3 1 3. 0 1.5007190086180344e-005 0.3719654977321625 0.5409119725227356 <_> <_> <_>1 0 18 10 -1. <_>7 0 6 10 3. 0 0.1393561065196991 0.5525395870208740 0.4479042887687683 <_> <_> <_>7 17 5 3 -1. <_>7 18 5 1 3. 0 1.6461990308016539e-003 0.4264501035213471 0.5772169828414917 <_> <_> <_>7 11 6 1 -1. <_>9 11 2 1 3. 0 4.9984431825578213e-004 0.4359526038169861 0.5685871243476868 <_> <_> <_>2 2 3 2 -1. <_>2 3 3 1 2. 0 -1.0971280280500650e-003 0.3390136957168579 0.5205408930778503 <_> <_> <_>8 12 4 2 -1. <_>8 13 4 1 2. 0 6.6919892560690641e-004 0.4557456076145172 0.5980659723281860 <_> <_> <_>6 10 3 6 -1. <_>6 13 3 3 2. 0 8.6471042595803738e-004 0.5134841203689575 0.2944033145904541 <_> <_> <_>11 4 2 4 -1. <_>11 4 1 4 2. 0 -2.7182599296793342e-004 0.3906578123569489 0.5377181172370911 <_> <_> <_>7 4 2 4 -1. <_>8 4 1 4 2. 0 3.0249499104684219e-005 0.3679609894752502 0.5225688815116882 <_> <_> <_>9 6 2 4 -1. <_>9 6 1 4 2. 0 -8.5225896909832954e-003 0.7293102145195007 0.4892365038394928 <_> <_> <_>6 13 8 3 -1. <_>6 14 8 1 3. 0 1.6705560265108943e-003 0.4345324933528900 0.5696138143539429 <_> <_> <_>9 15 3 4 -1. <_>10 15 1 4 3. 0 -7.1433838456869125e-003 0.2591280043125153 0.5225623846054077 <_> <_> <_>9 2 2 17 -1. <_>10 2 1 17 2. 0 -0.0163193698972464 0.6922279000282288 0.4651575982570648 <_> <_> <_>7 0 6 1 -1. <_>9 0 2 1 3. 0 4.8034260980784893e-003 0.5352262854576111 0.3286302983760834 <_> <_> <_>8 15 3 4 -1. <_>9 15 1 4 3. 0 -7.5421929359436035e-003 0.2040544003248215 0.5034546256065369 <_> <_> <_>7 13 7 3 -1. <_>7 14 7 1 3. 0 -0.0143631100654602 0.6804888844490051 0.4889059066772461 <_> <_> <_>8 16 3 3 -1. <_>9 16 1 3 3. 0 8.9063588529825211e-004 0.5310695767402649 0.3895480930805206 <_> <_> <_>6 2 8 10 -1. <_>6 7 8 5 2. 0 -4.4060191139578819e-003 0.5741562843322754 0.4372426867485046 <_> <_> <_>2 5 8 8 -1. <_>2 9 8 4 2. 0 -1.8862540309783071e-004 0.2831785976886749 0.5098205208778381 <_> <_> <_>14 16 2 2 -1. <_>14 17 2 1 2. 0 -3.7979281041771173e-003 0.3372507989406586 0.5246580243110657 <_> <_> <_>4 16 2 2 -1. <_>4 17 2 1 2. 0 1.4627049677073956e-004 0.5306674242019653 0.3911710083484650 <_> <_> <_>10 11 4 6 -1. <_>10 14 4 3 2. 0 -4.9164638767251745e-005 0.5462496280670166 0.3942720890045166 <_> <_> <_>6 11 4 6 -1. <_>6 14 4 3 2. 0 -0.0335825011134148 0.2157824039459229 0.5048211812973023 <_> <_> <_>10 14 1 3 -1. <_>10 15 1 1 3. 0 -3.5339309833943844e-003 0.6465312242507935 0.4872696995735169 <_> <_> <_>8 14 4 3 -1. <_>8 15 4 1 3. 0 5.0144111737608910e-003 0.4617668092250824 0.6248074769973755 <_> <_> <_>10 0 4 6 -1. <_>12 0 2 3 2. <_>10 3 2 3 2. 0 0.0188173707574606 0.5220689177513123 0.2000052034854889 <_> <_> <_>0 3 20 2 -1. <_>0 4 20 1 2. 0 -1.3434339780360460e-003 0.4014537930488586 0.5301619768142700 <_> <_> <_>12 0 8 2 -1. <_>16 0 4 1 2. <_>12 1 4 1 2. 0 1.7557960236445069e-003 0.4794039130210877 0.5653169751167297 <_> <_> <_>2 12 10 8 -1. <_>2 16 10 4 2. 0 -0.0956374630331993 0.2034195065498352 0.5006706714630127 <_> <_> <_>17 7 2 10 -1. <_>18 7 1 5 2. <_>17 12 1 5 2. 0 -0.0222412291914225 0.7672473192214966 0.5046340227127075 <_> <_> <_>1 7 2 10 -1. <_>1 7 1 5 2. <_>2 12 1 5 2. 0 -0.0155758196488023 0.7490342259407044 0.4755851030349731 <_> <_> <_>15 10 3 6 -1. <_>15 12 3 2 3. 0 5.3599118255078793e-003 0.5365303754806519 0.4004670977592468 <_> <_> <_>4 4 6 2 -1. <_>6 4 2 2 3. 0 -0.0217634998261929 0.0740154981613159 0.4964174926280975 <_> <_> <_>0 5 20 6 -1. <_>0 7 20 2 3. 0 -0.1656159013509750 0.2859103083610535 0.5218086242675781 <_> <_> <_>0 0 8 2 -1. <_>0 0 4 1 2. <_>4 1 4 1 2. 0 1.6461320046801120e-004 0.4191615879535675 0.5380793213844299 <_> <_> <_>1 0 18 4 -1. <_>7 0 6 4 3. 0 -8.9077502489089966e-003 0.6273192763328552 0.4877404868602753 <_> <_> <_>1 13 6 2 -1. <_>1 14 6 1 2. 0 8.6346449097618461e-004 0.5159940719604492 0.3671025931835175 <_> <_> <_>10 8 3 4 -1. <_>11 8 1 4 3. 0 -1.3751760125160217e-003 0.5884376764297485 0.4579083919525147 <_> <_> <_>6 1 6 1 -1. <_>8 1 2 1 3. 0 -1.4081239933148026e-003 0.3560509979724884 0.5139945149421692 <_> <_> <_>8 14 4 3 -1. <_>8 15 4 1 3. 0 -3.9342888630926609e-003 0.5994288921356201 0.4664272069931030 <_> <_> <_>1 6 18 2 -1. <_>10 6 9 2 2. 0 -0.0319669283926487 0.3345462083816528 0.5144183039665222 <_> <_> <_>15 11 1 2 -1. <_>15 12 1 1 2. 0 -1.5089280168467667e-005 0.5582656264305115 0.4414057135581970 <_> <_> <_>6 5 1 2 -1. <_>6 6 1 1 2. 0 5.1994470413774252e-004 0.4623680114746094 0.6168993711471558 <_> <_> <_>13 4 1 3 -1. <_>13 5 1 1 3. 0 -3.4220460802316666e-003 0.6557074785232544 0.4974805116653442 <_> <_> <_>2 15 1 2 -1. <_>2 16 1 1 2. 0 1.7723299970384687e-004 0.5269501805305481 0.3901908099651337 <_> <_> <_>12 4 4 3 -1. <_>12 5 4 1 3. 0 1.5716759953647852e-003 0.4633373022079468 0.5790457725524902 <_> <_> <_>0 0 7 3 -1. <_>0 1 7 1 3. 0 -8.9041329920291901e-003 0.2689608037471771 0.5053591132164002 <_> <_> <_>9 12 6 2 -1. <_>9 12 3 2 2. 0 4.0677518700249493e-004 0.5456603169441223 0.4329898953437805 <_> <_> <_>5 4 2 3 -1. <_>5 5 2 1 3. 0 6.7604780197143555e-003 0.4648993909358978 0.6689761877059937 <_> <_> <_>18 4 2 3 -1. <_>18 5 2 1 3. 0 2.9100088868290186e-003 0.5309703946113586 0.3377839922904968 <_> <_> <_>3 0 8 6 -1. <_>3 2 8 2 3. 0 1.3885459629818797e-003 0.4074738919734955 0.5349133014678955 <_> <_> <_>0 2 20 6 -1. <_>10 2 10 3 2. <_>0 5 10 3 2. 0 -0.0767642632126808 0.1992176026105881 0.5228242278099060 <_> <_> <_>4 7 2 4 -1. <_>5 7 1 4 2. 0 -2.2688310127705336e-004 0.5438501834869385 0.4253072142601013 <_> <_> <_>3 10 15 2 -1. <_>8 10 5 2 3. 0 -6.3094152137637138e-003 0.4259178936481476 0.5378909707069397 <_> <_> <_>3 0 12 11 -1. <_>9 0 6 11 2. 0 -0.1100727990269661 0.6904156804084778 0.4721749126911163 <_> <_> <_>13 0 2 6 -1. <_>13 0 1 6 2. 0 2.8619659133255482e-004 0.4524914920330048 0.5548306107521057 <_> <_> <_>0 19 2 1 -1. <_>1 19 1 1 2. 0 2.9425329557852820e-005 0.5370373725891113 0.4236463904380798 <_> <_> <_>16 10 4 10 -1. <_>18 10 2 5 2. <_>16 15 2 5 2. 0 -0.0248865708708763 0.6423557996749878 0.4969303905963898 <_> <_> <_>4 8 10 3 -1. <_>4 9 10 1 3. 0 0.0331488512456417 0.4988475143909454 0.1613811999559403 <_> <_> <_>14 12 3 3 -1. <_>14 13 3 1 3. 0 7.8491691965609789e-004 0.5416026115417481 0.4223009049892426 <_> <_> <_>0 10 4 10 -1. <_>0 10 2 5 2. <_>2 15 2 5 2. 0 4.7087189741432667e-003 0.4576328992843628 0.6027557849884033 <_> <_> <_>18 3 2 6 -1. <_>18 5 2 2 3. 0 2.4144479539245367e-003 0.5308973193168640 0.4422498941421509 <_> <_> <_>6 6 1 3 -1. <_>6 7 1 1 3. 0 1.9523180089890957e-003 0.4705634117126465 0.6663324832916260 <_> <_> <_>7 7 7 2 -1. <_>7 8 7 1 2. 0 1.3031980488449335e-003 0.4406126141548157 0.5526962280273438 <_> <_> <_>0 3 2 6 -1. <_>0 5 2 2 3. 0 4.4735497795045376e-003 0.5129023790359497 0.3301498889923096 <_> <_> <_>11 1 3 1 -1. <_>12 1 1 1 3. 0 -2.6652868837118149e-003 0.3135471045970917 0.5175036191940308 <_> <_> <_>5 0 2 6 -1. <_>6 0 1 6 2. 0 1.3666770246345550e-004 0.4119370877742767 0.5306876897811890 <_> <_> <_>1 1 18 14 -1. <_>7 1 6 14 3. 0 -0.0171264503151178 0.6177806258201599 0.4836578965187073 <_> <_> <_>4 6 8 3 -1. <_>8 6 4 3 2. 0 -2.6601430727168918e-004 0.3654330968856812 0.5169736742973328 <_> <_> <_>9 12 6 2 -1. <_>9 12 3 2 2. 0 -0.0229323804378510 0.3490915000438690 0.5163992047309876 <_> <_> <_>5 12 6 2 -1. <_>8 12 3 2 2. 0 2.3316550068557262e-003 0.5166299939155579 0.3709389865398407 <_> <_> <_>10 7 3 5 -1. <_>11 7 1 5 3. 0 0.0169256608933210 0.5014736056327820 0.8053988218307495 <_> <_> <_>7 7 3 5 -1. <_>8 7 1 5 3. 0 -8.9858826249837875e-003 0.6470788717269898 0.4657020866870880 <_> <_> <_>13 0 3 10 -1. <_>14 0 1 10 3. 0 -0.0118746999651194 0.3246378898620606 0.5258755087852478 <_> <_> <_>4 11 3 2 -1. <_>4 12 3 1 2. 0 1.9350569345988333e-004 0.5191941857337952 0.3839643895626068 <_> <_> <_>17 3 3 6 -1. <_>18 3 1 6 3. 0 5.8713490143418312e-003 0.4918133914470673 0.6187043190002441 <_> <_> <_>1 8 18 10 -1. <_>1 13 18 5 2. 0 -0.2483879029750824 0.1836802959442139 0.4988150000572205 <_> <_> <_>13 0 3 10 -1. <_>14 0 1 10 3. 0 0.0122560001909733 0.5227053761482239 0.3632029891014099 <_> <_> <_>9 14 2 3 -1. <_>9 15 2 1 3. 0 8.3990179700776935e-004 0.4490250051021576 0.5774148106575012 <_> <_> <_>16 3 3 7 -1. <_>17 3 1 7 3. 0 2.5407369248569012e-003 0.4804787039756775 0.5858299136161804 <_> <_> <_>4 0 3 10 -1. <_>5 0 1 10 3. 0 -0.0148224299773574 0.2521049976348877 0.5023537278175354 <_> <_> <_>16 3 3 7 -1. <_>17 3 1 7 3. 0 -5.7973959483206272e-003 0.5996695756912231 0.4853715002536774 <_> <_> <_>0 9 1 2 -1. <_>0 10 1 1 2. 0 7.2662148158997297e-004 0.5153716802597046 0.3671779930591583 <_> <_> <_>18 1 2 10 -1. <_>18 1 1 10 2. 0 -0.0172325801104307 0.6621719002723694 0.4994656145572662 <_> <_> <_>0 1 2 10 -1. <_>1 1 1 10 2. 0 7.8624086454510689e-003 0.4633395075798035 0.6256101727485657 <_> <_> <_>10 16 3 4 -1. <_>11 16 1 4 3. 0 -4.7343620099127293e-003 0.3615573048591614 0.5281885266304016 <_> <_> <_>2 8 3 3 -1. <_>3 8 1 3 3. 0 8.3048478700220585e-004 0.4442889094352722 0.5550957918167114 <_> <_> <_>11 0 2 6 -1. <_>12 0 1 3 2. <_>11 3 1 3 2. 0 7.6602199114859104e-003 0.5162935256958008 0.2613354921340942 <_> <_> <_>7 0 2 6 -1. <_>7 0 1 3 2. <_>8 3 1 3 2. 0 -4.1048377752304077e-003 0.2789632081985474 0.5019031763076782 <_> <_> <_>16 3 3 7 -1. <_>17 3 1 7 3. 0 4.8512578941881657e-003 0.4968984127044678 0.5661668181419373 <_> <_> <_>1 3 3 7 -1. <_>2 3 1 7 3. 0 9.9896453320980072e-004 0.4445607960224152 0.5551813244819641 <_> <_> <_>14 1 6 16 -1. <_>16 1 2 16 3. 0 -0.2702363133430481 0.0293882098048925 0.5151314139366150 <_> <_> <_>0 1 6 16 -1. <_>2 1 2 16 3. 0 -0.0130906803533435 0.5699399709701538 0.4447459876537323 <_> <_> <_>2 0 16 8 -1. <_>10 0 8 4 2. <_>2 4 8 4 2. 0 -9.4342790544033051e-003 0.4305466115474701 0.5487895011901856 <_> <_> <_>6 8 5 3 -1. <_>6 9 5 1 3. 0 -1.5482039889320731e-003 0.3680317103862763 0.5128080844879150 <_> <_> <_>9 7 3 3 -1. <_>10 7 1 3 3. 0 5.3746132180094719e-003 0.4838916957378388 0.6101555824279785 <_> <_> <_>8 8 4 3 -1. <_>8 9 4 1 3. 0 1.5786769799888134e-003 0.5325223207473755 0.4118548035621643 <_> <_> <_>9 6 2 4 -1. <_>9 6 1 4 2. 0 3.6856050137430429e-003 0.4810948073863983 0.6252303123474121 <_> <_> <_>0 7 15 1 -1. <_>5 7 5 1 3. 0 9.3887019902467728e-003 0.5200229883193970 0.3629410862922669 <_> <_> <_>8 2 7 9 -1. <_>8 5 7 3 3. 0 0.0127926301211119 0.4961709976196289 0.6738016009330750 <_> <_> <_>1 7 16 4 -1. <_>1 7 8 2 2. <_>9 9 8 2 2. 0 -3.3661040943115950e-003 0.4060279130935669 0.5283598899841309 <_> <_> <_>6 12 8 2 -1. <_>6 13 8 1 2. 0 3.9771420415490866e-004 0.4674113988876343 0.5900775194168091 <_> <_> <_>8 11 3 3 -1. <_>8 12 3 1 3. 0 1.4868030557408929e-003 0.4519116878509522 0.6082053780555725 <_> <_> <_>4 5 14 10 -1. <_>11 5 7 5 2. <_>4 10 7 5 2. 0 -0.0886867493391037 0.2807899117469788 0.5180991888046265 <_> <_> <_>4 12 3 2 -1. <_>4 13 3 1 2. 0 -7.4296112870797515e-005 0.5295584201812744 0.4087625145912170 <_> <_> <_>9 11 6 1 -1. <_>11 11 2 1 3. 0 -1.4932939848222304e-005 0.5461400151252747 0.4538542926311493 <_> <_> <_>4 9 7 6 -1. <_>4 11 7 2 3. 0 5.9162238612771034e-003 0.5329161286354065 0.4192134141921997 <_> <_> <_>7 10 6 3 -1. <_>7 11 6 1 3. 0 1.1141640134155750e-003 0.4512017965316773 0.5706217288970947 <_> <_> <_>9 11 2 2 -1. <_>9 12 2 1 2. 0 8.9249362645205110e-005 0.4577805995941162 0.5897638201713562 <_> <_> <_>0 5 20 6 -1. <_>0 7 20 2 3. 0 2.5319510605186224e-003 0.5299603939056397 0.3357639014720917 <_> <_> <_>6 4 6 1 -1. <_>8 4 2 1 3. 0 0.0124262003228068 0.4959059059619904 0.1346601992845535 <_> <_> <_>9 11 6 1 -1. <_>11 11 2 1 3. 0 0.0283357501029968 0.5117079019546509 6.1043637106195092e-004 <_> <_> <_>5 11 6 1 -1. <_>7 11 2 1 3. 0 6.6165882162749767e-003 0.4736349880695343 0.7011628150939941 <_> <_> <_>10 16 3 4 -1. <_>11 16 1 4 3. 0 8.0468766391277313e-003 0.5216417908668518 0.3282819986343384 <_> <_> <_>8 7 3 3 -1. <_>9 7 1 3 3. 0 -1.1193980462849140e-003 0.5809860825538635 0.4563739001750946 <_> <_> <_>2 12 16 8 -1. <_>2 16 16 4 2. 0 0.0132775902748108 0.5398362278938294 0.4103901088237763 <_> <_> <_>0 15 15 2 -1. <_>0 16 15 1 2. 0 4.8794739996083081e-004 0.4249286055564880 0.5410590767860413 <_> <_> <_>15 4 5 6 -1. <_>15 6 5 2 3. 0 0.0112431701272726 0.5269963741302490 0.3438215851783752 <_> <_> <_>9 5 2 4 -1. <_>10 5 1 4 2. 0 -8.9896668214350939e-004 0.5633075833320618 0.4456613063812256 <_> <_> <_>8 10 9 6 -1. <_>8 12 9 2 3. 0 6.6677159629762173e-003 0.5312889218330383 0.4362679123878479 <_> <_> <_>2 19 15 1 -1. <_>7 19 5 1 3. 0 0.0289472993463278 0.4701794981956482 0.6575797796249390 <_> <_> <_>10 16 3 4 -1. <_>11 16 1 4 3. 0 -0.0234000496566296 0. 0.5137398838996887 <_> <_> <_>0 15 20 4 -1. <_>0 17 20 2 2. 0 -0.0891170501708984 0.0237452797591686 0.4942430853843689 <_> <_> <_>10 16 3 4 -1. <_>11 16 1 4 3. 0 -0.0140546001493931 0.3127323091030121 0.5117511153221130 <_> <_> <_>7 16 3 4 -1. <_>8 16 1 4 3. 0 8.1239398568868637e-003 0.5009049177169800 0.2520025968551636 <_> <_> <_>9 16 3 3 -1. <_>9 17 3 1 3. 0 -4.9964650534093380e-003 0.6387143731117249 0.4927811920642853 <_> <_> <_>8 11 4 6 -1. <_>8 14 4 3 2. 0 3.1253970228135586e-003 0.5136849880218506 0.3680452108383179 <_> <_> <_>9 6 2 12 -1. <_>9 10 2 4 3. 0 6.7669642157852650e-003 0.5509843826293945 0.4363631904125214 <_> <_> <_>8 17 4 3 -1. <_>8 18 4 1 3. 0 -2.3711440153419971e-003 0.6162335276603699 0.4586946964263916 <_> <_> <_>9 18 8 2 -1. <_>13 18 4 1 2. <_>9 19 4 1 2. 0 -5.3522791713476181e-003 0.6185457706451416 0.4920490980148315 <_> <_> <_>1 18 8 2 -1. <_>1 19 8 1 2. 0 -0.0159688591957092 0.1382617950439453 0.4983252882957459 <_> <_> <_>13 5 6 15 -1. <_>15 5 2 15 3. 0 4.7676060348749161e-003 0.4688057899475098 0.5490046143531799 <_> <_> <_>9 8 2 2 -1. <_>9 9 2 1 2. 0 -2.4714691098779440e-003 0.2368514984846115 0.5003952980041504 <_> <_> <_>9 5 2 3 -1. <_>9 5 1 3 2. 0 -7.1033788844943047e-004 0.5856394171714783 0.4721533060073853 <_> <_> <_>1 5 6 15 -1. <_>3 5 2 15 3. 0 -0.1411755979061127 0.0869000628590584 0.4961591064929962 <_> <_> <_>4 1 14 8 -1. <_>11 1 7 4 2. <_>4 5 7 4 2. 0 0.1065180972218514 0.5138837099075317 0.1741005033254623 <_> <_> <_>2 4 4 16 -1. <_>2 4 2 8 2. <_>4 12 2 8 2. 0 -0.0527447499334812 0.7353636026382446 0.4772881865501404 <_> <_> <_>12 4 3 12 -1. <_>12 10 3 6 2. 0 -4.7431760467588902e-003 0.3884406089782715 0.5292701721191406 <_> <_> <_>4 5 10 12 -1. <_>4 5 5 6 2. <_>9 11 5 6 2. 0 9.9676765967160463e-004 0.5223492980003357 0.4003424048423767 <_> <_> <_>9 14 2 3 -1. <_>9 15 2 1 3. 0 8.0284131690859795e-003 0.4959106147289276 0.7212964296340942 <_> <_> <_>5 4 2 3 -1. <_>5 5 2 1 3. 0 8.6025858763605356e-004 0.4444884061813355 0.5538476109504700 <_> <_> <_>12 2 4 10 -1. <_>14 2 2 5 2. <_>12 7 2 5 2. 0 9.3191501218825579e-004 0.5398371219635010 0.4163244068622589 <_> <_> <_>6 4 7 3 -1. <_>6 5 7 1 3. 0 -2.5082060601562262e-003 0.5854265093803406 0.4562500119209290 <_> <_> <_>2 0 18 2 -1. <_>11 0 9 1 2. <_>2 1 9 1 2. 0 -2.1378761157393456e-003 0.4608069062232971 0.5280259251594544 <_> <_> <_>0 0 18 2 -1. <_>0 0 9 1 2. <_>9 1 9 1 2. 0 -2.1546049974858761e-003 0.3791126906871796 0.5255997180938721 <_> <_> <_>13 13 4 6 -1. <_>15 13 2 3 2. <_>13 16 2 3 2. 0 -7.6214009895920753e-003 0.5998609066009522 0.4952073991298676 <_> <_> <_>3 13 4 6 -1. <_>3 13 2 3 2. <_>5 16 2 3 2. 0 2.2055360022932291e-003 0.4484206140041351 0.5588530898094177 <_> <_> <_>10 12 2 6 -1. <_>10 15 2 3 2. 0 1.2586950324475765e-003 0.5450747013092041 0.4423840939998627 <_> <_> <_>5 9 10 10 -1. <_>5 9 5 5 2. <_>10 14 5 5 2. 0 -5.0926720723509789e-003 0.4118275046348572 0.5263035893440247 <_> <_> <_>11 4 4 2 -1. <_>13 4 2 1 2. <_>11 5 2 1 2. 0 -2.5095739401876926e-003 0.5787907838821411 0.4998494982719421 <_> <_> <_>7 12 6 8 -1. <_>10 12 3 8 2. 0 -0.0773275569081306 0.8397865891456604 0.4811120033264160 <_> <_> <_>12 2 4 10 -1. <_>14 2 2 5 2. <_>12 7 2 5 2. 0 -0.0414858199656010 0.2408611029386520 0.5176993012428284 <_> <_> <_>8 11 2 1 -1. <_>9 11 1 1 2. 0 1.0355669655837119e-004 0.4355360865592957 0.5417054295539856 <_> <_> <_>10 5 1 12 -1. <_>10 9 1 4 3. 0 1.3255809899419546e-003 0.5453971028327942 0.4894095063209534 <_> <_> <_>0 11 6 9 -1. <_>3 11 3 9 2. 0 -8.0598732456564903e-003 0.5771024227142334 0.4577918946743012 <_> <_> <_>12 2 4 10 -1. <_>14 2 2 5 2. <_>12 7 2 5 2. 0 0.0190586205571890 0.5169867873191834 0.3400475084781647 <_> <_> <_>4 2 4 10 -1. <_>4 2 2 5 2. <_>6 7 2 5 2. 0 -0.0350578911602497 0.2203243970870972 0.5000503063201904 <_> <_> <_>11 4 4 2 -1. <_>13 4 2 1 2. <_>11 5 2 1 2. 0 5.7296059094369411e-003 0.5043408274650574 0.6597570776939392 <_> <_> <_>0 14 6 3 -1. <_>0 15 6 1 3. 0 -0.0116483299061656 0.2186284959316254 0.4996652901172638 <_> <_> <_>11 4 4 2 -1. <_>13 4 2 1 2. <_>11 5 2 1 2. 0 1.4544479781761765e-003 0.5007681846618652 0.5503727793693543 <_> <_> <_>6 1 3 2 -1. <_>7 1 1 2 3. 0 -2.5030909455381334e-004 0.4129841029644013 0.5241670012474060 <_> <_> <_>11 4 4 2 -1. <_>13 4 2 1 2. <_>11 5 2 1 2. 0 -8.2907272735610604e-004 0.5412868261337280 0.4974496066570282 <_> <_> <_>5 4 4 2 -1. <_>5 4 2 1 2. <_>7 5 2 1 2. 0 1.0862209601327777e-003 0.4605529904365540 0.5879228711128235 <_> <_> <_>13 0 2 12 -1. <_>14 0 1 6 2. <_>13 6 1 6 2. 0 2.0000500080641359e-004 0.5278854966163635 0.4705209136009216 <_> <_> <_>6 0 3 10 -1. <_>7 0 1 10 3. 0 2.9212920926511288e-003 0.5129609704017639 0.3755536973476410 <_> <_> <_>3 0 17 8 -1. <_>3 4 17 4 2. 0 0.0253874007612467 0.4822691977024078 0.5790768265724182 <_> <_> <_>0 4 20 4 -1. <_>0 6 20 2 2. 0 -3.1968469265848398e-003 0.5248395204544067 0.3962840139865875 87.6960296630859380 17 -1 <_> <_> <_> <_>0 3 8 2 -1. <_>4 3 4 2 2. 0 5.8031738735735416e-003 0.3498983979225159 0.5961983203887940 <_> <_> <_>8 11 4 3 -1. <_>8 12 4 1 3. 0 -9.0003069490194321e-003 0.6816636919975281 0.4478552043437958 <_> <_> <_>5 7 6 4 -1. <_>5 7 3 2 2. <_>8 9 3 2 2. 0 -1.1549659539014101e-003 0.5585706233978272 0.3578251004219055 <_> <_> <_>8 3 4 9 -1. <_>8 6 4 3 3. 0 -1.1069850297644734e-003 0.5365036129951477 0.3050428032875061 <_> <_> <_>8 15 1 4 -1. <_>8 17 1 2 2. 0 1.0308309720130637e-004 0.3639095127582550 0.5344635844230652 <_> <_> <_>4 5 12 7 -1. <_>8 5 4 7 3. 0 -5.0984839908778667e-003 0.2859157025814056 0.5504264831542969 <_> <_> <_>4 2 4 10 -1. <_>4 2 2 5 2. <_>6 7 2 5 2. 0 8.2572200335562229e-004 0.5236523747444153 0.3476041853427887 <_> <_> <_>3 0 17 2 -1. <_>3 1 17 1 2. 0 9.9783325567841530e-003 0.4750322103500366 0.6219646930694580 <_> <_> <_>2 2 16 15 -1. <_>2 7 16 5 3. 0 -0.0374025292694569 0.3343375921249390 0.5278062820434570 <_> <_> <_>15 2 5 2 -1. <_>15 3 5 1 2. 0 4.8548257909715176e-003 0.5192180871963501 0.3700444102287293 <_> <_> <_>9 3 2 2 -1. <_>10 3 1 2 2. 0 -1.8664470408111811e-003 0.2929843962192535 0.5091944932937622 <_> <_> <_>4 5 16 15 -1. <_>4 10 16 5 3. 0 0.0168888904154301 0.3686845898628235 0.5431225895881653 <_> <_> <_>7 13 5 6 -1. <_>7 16 5 3 2. 0 -5.8372621424496174e-003 0.3632183969020844 0.5221335887908936 <_> <_> <_>10 7 3 2 -1. <_>11 7 1 2 3. 0 -1.4713739510625601e-003 0.5870683789253235 0.4700650870800018 <_> <_> <_>8 3 3 1 -1. <_>9 3 1 1 3. 0 -1.1522950371727347e-003 0.3195894956588745 0.5140954256057739 <_> <_> <_>9 16 3 3 -1. <_>9 17 3 1 3. 0 -4.2560300789773464e-003 0.6301859021186829 0.4814921021461487 <_> <_> <_>0 2 5 2 -1. <_>0 3 5 1 2. 0 -6.7378291860222816e-003 0.1977048069238663 0.5025808215141296 <_> <_> <_>12 5 4 3 -1. <_>12 6 4 1 3. 0 0.0113826701417565 0.4954132139682770 0.6867045760154724 <_> <_> <_>1 7 12 1 -1. <_>5 7 4 1 3. 0 5.1794708706438541e-003 0.5164427757263184 0.3350647985935211 <_> <_> <_>7 5 6 14 -1. <_>7 12 6 7 2. 0 -0.1174378991127014 0.2315246015787125 0.5234413743019104 <_> <_> <_>0 0 8 10 -1. <_>0 0 4 5 2. <_>4 5 4 5 2. 0 0.0287034492939711 0.4664297103881836 0.6722521185874939 <_> <_> <_>9 1 3 2 -1. <_>10 1 1 2 3. 0 4.8231030814349651e-003 0.5220875144004822 0.2723532915115356 <_> <_> <_>8 1 3 2 -1. <_>9 1 1 2 3. 0 2.6798530016094446e-003 0.5079277157783508 0.2906948924064636 <_> <_> <_>12 4 3 3 -1. <_>12 5 3 1 3. 0 8.0504082143306732e-003 0.4885950982570648 0.6395021080970764 <_> <_> <_>7 4 6 16 -1. <_>7 12 6 8 2. 0 4.8054959625005722e-003 0.5197256803512573 0.3656663894653320 <_> <_> <_>12 4 3 3 -1. <_>12 5 3 1 3. 0 -2.2420159075409174e-003 0.6153467893600464 0.4763701856136322 <_> <_> <_>2 3 2 6 -1. <_>2 5 2 2 3. 0 -0.0137577103450894 0.2637344896793366 0.5030903220176697 <_> <_> <_>14 2 6 9 -1. <_>14 5 6 3 3. 0 -0.1033829972147942 0.2287521958351135 0.5182461142539978 <_> <_> <_>5 4 3 3 -1. <_>5 5 3 1 3. 0 -9.4432085752487183e-003 0.6953303813934326 0.4694949090480804 <_> <_> <_>9 17 3 2 -1. <_>10 17 1 2 3. 0 8.0271181650459766e-004 0.5450655221939087 0.4268783926963806 <_> <_> <_>5 5 2 3 -1. <_>5 6 2 1 3. 0 -4.1945669800043106e-003 0.6091387867927551 0.4571642875671387 <_> <_> <_>13 11 3 6 -1. <_>13 13 3 2 3. 0 0.0109422104433179 0.5241063237190247 0.3284547030925751 <_> <_> <_>3 14 2 6 -1. <_>3 17 2 3 2. 0 -5.7841069065034389e-004 0.5387929081916809 0.4179368913173676 <_> <_> <_>14 3 6 2 -1. <_>14 4 6 1 2. 0 -2.0888620056211948e-003 0.4292691051959992 0.5301715731620789 <_> <_> <_>0 8 16 2 -1. <_>0 9 16 1 2. 0 3.2383969519287348e-003 0.3792347908020020 0.5220744013786316 <_> <_> <_>14 3 6 2 -1. <_>14 4 6 1 2. 0 4.9075027927756310e-003 0.5237283110618591 0.4126757979393005 <_> <_> <_>0 0 5 6 -1. <_>0 2 5 2 3. 0 -0.0322779417037964 0.1947655975818634 0.4994502067565918 <_> <_> <_>12 5 4 3 -1. <_>12 6 4 1 3. 0 -8.9711230248212814e-003 0.6011285185813904 0.4929032027721405 <_> <_> <_>4 11 3 6 -1. <_>4 13 3 2 3. 0 0.0153210898861289 0.5009753704071045 0.2039822041988373 <_> <_> <_>12 5 4 3 -1. <_>12 6 4 1 3. 0 2.0855569746345282e-003 0.4862189888954163 0.5721694827079773 <_> <_> <_>9 5 1 3 -1. <_>9 6 1 1 3. 0 5.0615021027624607e-003 0.5000218749046326 0.1801805943250656 <_> <_> <_>12 5 4 3 -1. <_>12 6 4 1 3. 0 -3.7174751050770283e-003 0.5530117154121399 0.4897592961788178 <_> <_> <_>6 6 8 12 -1. <_>6 12 8 6 2. 0 -0.0121705001220107 0.4178605973720551 0.5383723974227905 <_> <_> <_>12 5 4 3 -1. <_>12 6 4 1 3. 0 4.6248398721218109e-003 0.4997169971466065 0.5761327147483826 <_> <_> <_>5 12 9 2 -1. <_>8 12 3 2 3. 0 -2.1040429419372231e-004 0.5331807136535645 0.4097681045532227 <_> <_> <_>12 5 4 3 -1. <_>12 6 4 1 3. 0 -0.0146417804062366 0.5755925178527832 0.5051776170730591 <_> <_> <_>4 5 4 3 -1. <_>4 6 4 1 3. 0 3.3199489116668701e-003 0.4576976895332336 0.6031805872917175 <_> <_> <_>6 6 9 2 -1. <_>9 6 3 2 3. 0 3.7236879579722881e-003 0.4380396902561188 0.5415883064270020 <_> <_> <_>4 11 1 3 -1. <_>4 12 1 1 3. 0 8.2951161311939359e-004 0.5163031816482544 0.3702219128608704 <_> <_> <_>14 12 6 6 -1. <_>14 12 3 6 2. 0 -0.0114084901288152 0.6072946786880493 0.4862565100193024 <_> <_> <_>7 0 3 7 -1. <_>8 0 1 7 3. 0 -4.5320121571421623e-003 0.3292475938796997 0.5088962912559509 <_> <_> <_>9 8 3 3 -1. <_>10 8 1 3 3. 0 5.1276017911732197e-003 0.4829767942428589 0.6122708916664124 <_> <_> <_>8 8 3 3 -1. <_>9 8 1 3 3. 0 9.8583158105611801e-003 0.4660679996013641 0.6556177139282227 <_> <_> <_>5 10 11 3 -1. <_>5 11 11 1 3. 0 0.0369859188795090 0.5204849243164063 0.1690472066402435 <_> <_> <_>5 7 10 1 -1. <_>10 7 5 1 2. 0 4.6491161920130253e-003 0.5167322158813477 0.3725225031375885 <_> <_> <_>9 7 3 2 -1. <_>10 7 1 2 3. 0 -4.2664702050387859e-003 0.6406493186950684 0.4987342953681946 <_> <_> <_>8 7 3 2 -1. <_>9 7 1 2 3. 0 -4.7956590424291790e-004 0.5897293090820313 0.4464873969554901 <_> <_> <_>11 9 4 2 -1. <_>11 9 2 2 2. 0 3.6827160511165857e-003 0.5441560745239258 0.3472662866115570 <_> <_> <_>5 9 4 2 -1. <_>7 9 2 2 2. 0 -0.0100598800927401 0.2143162935972214 0.5004829764366150 <_> <_> <_>14 10 2 4 -1. <_>14 12 2 2 2. 0 -3.0361840617842972e-004 0.5386424064636231 0.4590323865413666 <_> <_> <_>7 7 3 2 -1. <_>8 7 1 2 3. 0 -1.4545479789376259e-003 0.5751184225082398 0.4497095048427582 <_> <_> <_>14 17 6 3 -1. <_>14 18 6 1 3. 0 1.6515209572389722e-003 0.5421937704086304 0.4238520860671997 <_> <_> <_>4 5 12 12 -1. <_>4 5 6 6 2. <_>10 11 6 6 2. 0 -7.8468639403581619e-003 0.4077920913696289 0.5258157253265381 <_> <_> <_>6 9 8 8 -1. <_>10 9 4 4 2. <_>6 13 4 4 2. 0 -5.1259850151836872e-003 0.4229275882244110 0.5479453206062317 <_> <_> <_>0 4 15 4 -1. <_>5 4 5 4 3. 0 -0.0368909612298012 0.6596375703811646 0.4674678146839142 <_> <_> <_>13 2 4 1 -1. <_>13 2 2 1 2. 0 2.4035639944486320e-004 0.4251135885715485 0.5573202967643738 <_> <_> <_>4 12 2 2 -1. <_>4 13 2 1 2. 0 -1.5150169929256663e-005 0.5259246826171875 0.4074114859104157 <_> <_> <_>8 13 4 3 -1. <_>8 14 4 1 3. 0 2.2108471021056175e-003 0.4671722948551178 0.5886352062225342 <_> <_> <_>9 13 2 3 -1. <_>9 14 2 1 3. 0 -1.1568620102480054e-003 0.5711066126823425 0.4487161934375763 <_> <_> <_>13 11 2 3 -1. <_>13 12 2 1 3. 0 4.9996292218565941e-003 0.5264198184013367 0.2898327112197876 <_> <_> <_>7 12 4 4 -1. <_>7 12 2 2 2. <_>9 14 2 2 2. 0 -1.4656189596280456e-003 0.3891738057136536 0.5197871923446655 <_> <_> <_>10 11 2 2 -1. <_>11 11 1 1 2. <_>10 12 1 1 2. 0 -1.1975039960816503e-003 0.5795872807502747 0.4927955865859985 <_> <_> <_>8 17 3 2 -1. <_>9 17 1 2 3. 0 -4.4954330660402775e-003 0.2377603054046631 0.5012555122375488 <_> <_> <_>10 11 2 2 -1. <_>11 11 1 1 2. <_>10 12 1 1 2. 0 1.4997160178609192e-004 0.4876626133918762 0.5617607831954956 <_> <_> <_>0 17 6 3 -1. <_>0 18 6 1 3. 0 2.6391509454697371e-003 0.5168088078498840 0.3765509128570557 <_> <_> <_>10 11 2 2 -1. <_>11 11 1 1 2. <_>10 12 1 1 2. 0 -2.9368131072260439e-004 0.5446649193763733 0.4874630868434906 <_> <_> <_>8 11 2 2 -1. <_>8 11 1 1 2. <_>9 12 1 1 2. 0 1.4211760135367513e-003 0.4687897861003876 0.6691331863403320 <_> <_> <_>12 5 8 4 -1. <_>12 5 4 4 2. 0 0.0794276371598244 0.5193443894386292 0.2732945978641510 <_> <_> <_>0 5 8 4 -1. <_>4 5 4 4 2. 0 0.0799375027418137 0.4971731007099152 0.1782083958387375 <_> <_> <_>13 2 4 1 -1. <_>13 2 2 1 2. 0 0.0110892597585917 0.5165994763374329 0.3209475874900818 <_> <_> <_>3 2 4 1 -1. <_>5 2 2 1 2. 0 1.6560709627810866e-004 0.4058471918106079 0.5307276248931885 <_> <_> <_>10 0 4 2 -1. <_>12 0 2 1 2. <_>10 1 2 1 2. 0 -5.3354292176663876e-003 0.3445056974887848 0.5158129930496216 <_> <_> <_>7 12 3 1 -1. <_>8 12 1 1 3. 0 1.1287260567769408e-003 0.4594863057136536 0.6075533032417297 <_> <_> <_>8 11 4 8 -1. <_>10 11 2 4 2. <_>8 15 2 4 2. 0 -0.0219692196696997 0.1680400967597961 0.5228595733642578 <_> <_> <_>9 9 2 2 -1. <_>9 10 2 1 2. 0 -2.1775320055894554e-004 0.3861596882343292 0.5215672850608826 <_> <_> <_>3 18 15 2 -1. <_>3 19 15 1 2. 0 2.0200149447191507e-004 0.5517979264259338 0.4363039135932922 <_> <_> <_>2 6 2 12 -1. <_>2 6 1 6 2. <_>3 12 1 6 2. 0 -0.0217331498861313 0.7999460101127625 0.4789851009845734 <_> <_> <_>9 8 2 3 -1. <_>9 9 2 1 3. 0 -8.4399932529777288e-004 0.4085975885391235 0.5374773144721985 <_> <_> <_>7 10 3 2 -1. <_>8 10 1 2 3. 0 -4.3895249837078154e-004 0.5470405220985413 0.4366143047809601 <_> <_> <_>11 11 3 1 -1. <_>12 11 1 1 3. 0 1.5092400135472417e-003 0.4988996982574463 0.5842149257659912 <_> <_> <_>6 11 3 1 -1. <_>7 11 1 1 3. 0 -3.5547839943319559e-003 0.6753690242767334 0.4721005856990814 <_> <_> <_>9 2 4 2 -1. <_>11 2 2 1 2. <_>9 3 2 1 2. 0 4.8191400128416717e-004 0.5415853857994080 0.4357109069824219 <_> <_> <_>4 12 2 3 -1. <_>4 13 2 1 3. 0 -6.0264398343861103e-003 0.2258509993553162 0.4991880953311920 <_> <_> <_>2 1 18 3 -1. <_>8 1 6 3 3. 0 -0.0116681400686502 0.6256554722785950 0.4927498996257782 <_> <_> <_>5 1 4 14 -1. <_>7 1 2 14 2. 0 -2.8718370012938976e-003 0.3947784900665283 0.5245801806449890 <_> <_> <_>8 16 12 3 -1. <_>8 16 6 3 2. 0 0.0170511696487665 0.4752511084079742 0.5794224143028259 <_> <_> <_>1 17 18 3 -1. <_>7 17 6 3 3. 0 -0.0133520802482963 0.6041104793548584 0.4544535875320435 <_> <_> <_>9 14 2 6 -1. <_>9 17 2 3 2. 0 -3.9301801007241011e-004 0.4258275926113129 0.5544905066490173 <_> <_> <_>9 12 1 8 -1. <_>9 16 1 4 2. 0 3.0483349692076445e-003 0.5233420133590698 0.3780272901058197 <_> <_> <_>9 14 2 3 -1. <_>9 15 2 1 3. 0 -4.3579288758337498e-003 0.6371889114379883 0.4838674068450928 <_> <_> <_>9 6 2 12 -1. <_>9 10 2 4 3. 0 5.6661018170416355e-003 0.5374705791473389 0.4163666069507599 <_> <_> <_>12 9 3 3 -1. <_>12 10 3 1 3. 0 6.0677339206449687e-005 0.4638795852661133 0.5311625003814697 <_> <_> <_>0 1 4 8 -1. <_>2 1 2 8 2. 0 0.0367381609976292 0.4688656032085419 0.6466524004936218 <_> <_> <_>9 1 6 2 -1. <_>12 1 3 1 2. <_>9 2 3 1 2. 0 8.6528137326240540e-003 0.5204318761825562 0.2188657969236374 <_> <_> <_>1 3 12 14 -1. <_>1 10 12 7 2. 0 -0.1537135988473892 0.1630371958017349 0.4958840012550354 <_> <_> <_>8 12 4 2 -1. <_>10 12 2 1 2. <_>8 13 2 1 2. 0 -4.1560421232134104e-004 0.5774459242820740 0.4696458876132965 <_> <_> <_>1 9 10 2 -1. <_>1 9 5 1 2. <_>6 10 5 1 2. 0 -1.2640169588848948e-003 0.3977175951004028 0.5217198133468628 <_> <_> <_>8 15 4 3 -1. <_>8 16 4 1 3. 0 -3.5473341122269630e-003 0.6046528220176697 0.4808315038681030 <_> <_> <_>6 8 8 3 -1. <_>6 9 8 1 3. 0 3.0019069527043030e-005 0.3996723890304565 0.5228201150894165 <_> <_> <_>9 15 5 3 -1. <_>9 16 5 1 3. 0 1.3113019522279501e-003 0.4712158143520355 0.5765997767448425 <_> <_> <_>8 7 4 3 -1. <_>8 8 4 1 3. 0 -1.3374709524214268e-003 0.4109584987163544 0.5253170132637024 <_> <_> <_>7 7 6 2 -1. <_>7 8 6 1 2. 0 0.0208767093718052 0.5202993750572205 0.1757981926202774 <_> <_> <_>5 7 8 2 -1. <_>5 7 4 1 2. <_>9 8 4 1 2. 0 -7.5497948564589024e-003 0.6566609740257263 0.4694975018501282 <_> <_> <_>12 9 3 3 -1. <_>12 10 3 1 3. 0 0.0241885501891375 0.5128673911094666 0.3370220959186554 <_> <_> <_>4 7 4 2 -1. <_>4 8 4 1 2. 0 -2.9358828905969858e-003 0.6580786705017090 0.4694541096687317 <_> <_> <_>14 2 6 9 -1. <_>14 5 6 3 3. 0 0.0575579293072224 0.5146445035934448 0.2775259912014008 <_> <_> <_>4 9 3 3 -1. <_>5 9 1 3 3. 0 -1.1343370424583554e-003 0.3836601972579956 0.5192667245864868 <_> <_> <_>12 9 3 3 -1. <_>12 10 3 1 3. 0 0.0168169997632504 0.5085592865943909 0.6177260875701904 <_> <_> <_>0 2 6 9 -1. <_>0 5 6 3 3. 0 5.0535178743302822e-003 0.5138763189315796 0.3684791922569275 <_> <_> <_>17 3 3 6 -1. <_>18 3 1 6 3. 0 -4.5874710194766521e-003 0.5989655256271362 0.4835202097892761 <_> <_> <_>0 3 3 6 -1. <_>1 3 1 6 3. 0 1.6882460331544280e-003 0.4509486854076386 0.5723056793212891 <_> <_> <_>17 14 1 2 -1. <_>17 15 1 1 2. 0 -1.6554000321775675e-003 0.3496770858764648 0.5243319272994995 <_> <_> <_>4 9 4 3 -1. <_>6 9 2 3 2. 0 -0.0193738006055355 0.1120536997914314 0.4968712925910950 <_> <_> <_>12 9 3 3 -1. <_>12 10 3 1 3. 0 0.0103744501248002 0.5148196816444397 0.4395213127136231 <_> <_> <_>5 9 3 3 -1. <_>5 10 3 1 3. 0 1.4973050565458834e-004 0.4084999859333038 0.5269886851310730 <_> <_> <_>9 5 6 8 -1. <_>12 5 3 4 2. <_>9 9 3 4 2. 0 -0.0429819300770760 0.6394104957580566 0.5018504261970520 <_> <_> <_>5 5 6 8 -1. <_>5 5 3 4 2. <_>8 9 3 4 2. 0 8.3065936341881752e-003 0.4707553982734680 0.6698353290557861 <_> <_> <_>16 1 4 6 -1. <_>16 4 4 3 2. 0 -4.1285790503025055e-003 0.4541369080543518 0.5323647260665894 <_> <_> <_>1 0 6 20 -1. <_>3 0 2 20 3. 0 1.7399420030415058e-003 0.4333961904048920 0.5439866185188294 <_> <_> <_>12 11 3 2 -1. <_>13 11 1 2 3. 0 1.1739750334527344e-004 0.4579687118530273 0.5543426275253296 <_> <_> <_>5 11 3 2 -1. <_>6 11 1 2 3. 0 1.8585780344437808e-004 0.4324643909931183 0.5426754951477051 <_> <_> <_>9 4 6 1 -1. <_>11 4 2 1 3. 0 5.5587692186236382e-003 0.5257220864295960 0.3550611138343811 <_> <_> <_>0 0 8 3 -1. <_>4 0 4 3 2. 0 -7.9851560294628143e-003 0.6043018102645874 0.4630635976791382 <_> <_> <_>15 0 2 5 -1. <_>15 0 1 5 2. 0 6.0594122624024749e-004 0.4598254859447479 0.5533195137977600 <_> <_> <_>4 1 3 2 -1. <_>5 1 1 2 3. 0 -2.2983040253166109e-004 0.4130752086639404 0.5322461128234863 <_> <_> <_>7 0 6 15 -1. <_>9 0 2 15 3. 0 4.3740210821852088e-004 0.4043039977550507 0.5409289002418518 <_> <_> <_>6 11 3 1 -1. <_>7 11 1 1 3. 0 2.9482020181603730e-004 0.4494963884353638 0.5628852248191834 <_> <_> <_>12 0 3 4 -1. <_>13 0 1 4 3. 0 0.0103126596659422 0.5177510976791382 0.2704316973686218 <_> <_> <_>5 4 6 1 -1. <_>7 4 2 1 3. 0 -7.7241109684109688e-003 0.1988019049167633 0.4980553984642029 <_> <_> <_>12 7 3 2 -1. <_>12 8 3 1 2. 0 -4.6797208487987518e-003 0.6644750237464905 0.5018296241760254 <_> <_> <_>0 1 4 6 -1. <_>0 4 4 3 2. 0 -5.0755459815263748e-003 0.3898304998874664 0.5185269117355347 <_> <_> <_>12 7 3 2 -1. <_>12 8 3 1 2. 0 2.2479740437120199e-003 0.4801808893680573 0.5660336017608643 <_> <_> <_>2 16 3 3 -1. <_>2 17 3 1 3. 0 8.3327008178457618e-004 0.5210919976234436 0.3957188129425049 <_> <_> <_>13 8 6 10 -1. <_>16 8 3 5 2. <_>13 13 3 5 2. 0 -0.0412793308496475 0.6154541969299316 0.5007054209709168 <_> <_> <_>0 9 5 2 -1. <_>0 10 5 1 2. 0 -5.0930189900100231e-004 0.3975942134857178 0.5228403806686401 <_> <_> <_>12 11 2 2 -1. <_>13 11 1 1 2. <_>12 12 1 1 2. 0 1.2568780221045017e-003 0.4979138076305389 0.5939183235168457 <_> <_> <_>3 15 3 3 -1. <_>3 16 3 1 3. 0 8.0048497766256332e-003 0.4984497129917145 0.1633366048336029 <_> <_> <_>12 7 3 2 -1. <_>12 8 3 1 2. 0 -1.1879300000146031e-003 0.5904964804649353 0.4942624866962433 <_> <_> <_>5 7 3 2 -1. <_>5 8 3 1 2. 0 6.1948952497914433e-004 0.4199557900428772 0.5328726172447205 <_> <_> <_>9 5 9 9 -1. <_>9 8 9 3 3. 0 6.6829859279096127e-003 0.5418602824211121 0.4905889034271240 <_> <_> <_>5 0 3 7 -1. <_>6 0 1 7 3. 0 -3.7062340416014194e-003 0.3725939095020294 0.5138000249862671 <_> <_> <_>5 2 12 5 -1. <_>9 2 4 5 3. 0 -0.0397394113242626 0.6478961110115051 0.5050346851348877 <_> <_> <_>6 11 2 2 -1. <_>6 11 1 1 2. <_>7 12 1 1 2. 0 1.4085009461268783e-003 0.4682339131832123 0.6377884149551392 <_> <_> <_>15 15 3 2 -1. <_>15 16 3 1 2. 0 3.9322688826359808e-004 0.5458530187606812 0.4150482118129730 <_> <_> <_>2 15 3 2 -1. <_>2 16 3 1 2. 0 -1.8979819724336267e-003 0.3690159916877747 0.5149704217910767 <_> <_> <_>14 12 6 8 -1. <_>17 12 3 4 2. <_>14 16 3 4 2. 0 -0.0139704402536154 0.6050562858581543 0.4811357855796814 <_> <_> <_>2 8 15 6 -1. <_>7 8 5 6 3. 0 -0.1010081991553307 0.2017080038785934 0.4992361962795258 <_> <_> <_>2 2 18 17 -1. <_>8 2 6 17 3. 0 -0.0173469204455614 0.5713148713111877 0.4899486005306244 <_> <_> <_>5 1 4 1 -1. <_>7 1 2 1 2. 0 1.5619759506080300e-004 0.4215388894081116 0.5392642021179199 <_> <_> <_>5 2 12 5 -1. <_>9 2 4 5 3. 0 0.1343892961740494 0.5136151909828186 0.3767612874507904 <_> <_> <_>3 2 12 5 -1. <_>7 2 4 5 3. 0 -0.0245822407305241 0.7027357816696167 0.4747906923294067 <_> <_> <_>4 9 12 4 -1. <_>10 9 6 2 2. <_>4 11 6 2 2. 0 -3.8553720805794001e-003 0.4317409098148346 0.5427716970443726 <_> <_> <_>5 15 6 2 -1. <_>5 15 3 1 2. <_>8 16 3 1 2. 0 -2.3165249731391668e-003 0.5942698717117310 0.4618647992610931 <_> <_> <_>10 14 2 3 -1. <_>10 15 2 1 3. 0 -4.8518120311200619e-003 0.6191568970680237 0.4884895086288452 <_> <_> <_>0 13 20 2 -1. <_>0 13 10 1 2. <_>10 14 10 1 2. 0 2.4699938949197531e-003 0.5256664752960205 0.4017199873924255 <_> <_> <_>4 9 12 8 -1. <_>10 9 6 4 2. <_>4 13 6 4 2. 0 0.0454969592392445 0.5237867832183838 0.2685773968696594 <_> <_> <_>8 13 3 6 -1. <_>8 16 3 3 2. 0 -0.0203195996582508 0.2130445986986160 0.4979738891124725 <_> <_> <_>10 12 2 2 -1. <_>10 13 2 1 2. 0 2.6994998916052282e-004 0.4814041852951050 0.5543122291564941 <_> <_> <_>9 12 2 2 -1. <_>9 12 1 1 2. <_>10 13 1 1 2. 0 -1.8232699949294329e-003 0.6482579708099365 0.4709989130496979 <_> <_> <_>4 11 14 4 -1. <_>11 11 7 2 2. <_>4 13 7 2 2. 0 -6.3015790656208992e-003 0.4581927955150604 0.5306236147880554 <_> <_> <_>8 5 4 2 -1. <_>8 6 4 1 2. 0 -2.4139499873854220e-004 0.5232086777687073 0.4051763117313385 <_> <_> <_>10 10 6 3 -1. <_>12 10 2 3 3. 0 -1.0330369696021080e-003 0.5556201934814453 0.4789193868637085 <_> <_> <_>2 14 1 2 -1. <_>2 15 1 1 2. 0 1.8041160365100950e-004 0.5229442715644836 0.4011810123920441 <_> <_> <_>13 8 6 12 -1. <_>16 8 3 6 2. <_>13 14 3 6 2. 0 -0.0614078603684902 0.6298682093620300 0.5010703206062317 <_> <_> <_>1 8 6 12 -1. <_>1 8 3 6 2. <_>4 14 3 6 2. 0 -0.0695439130067825 0.7228280901908875 0.4773184061050415 <_> <_> <_>10 0 6 10 -1. <_>12 0 2 10 3. 0 -0.0705426633358002 0.2269513010978699 0.5182529091835022 <_> <_> <_>5 11 8 4 -1. <_>5 11 4 2 2. <_>9 13 4 2 2. 0 2.4423799477517605e-003 0.5237097144126892 0.4098151028156281 <_> <_> <_>10 16 8 4 -1. <_>14 16 4 2 2. <_>10 18 4 2 2. 0 1.5494349645450711e-003 0.4773750901222229 0.5468043088912964 <_> <_> <_>7 7 6 6 -1. <_>9 7 2 6 3. 0 -0.0239142198115587 0.7146975994110107 0.4783824980258942 <_> <_> <_>10 2 4 10 -1. <_>10 2 2 10 2. 0 -0.0124536901712418 0.2635296881198883 0.5241122841835022 <_> <_> <_>6 1 4 9 -1. <_>8 1 2 9 2. 0 -2.0760179904755205e-004 0.3623757064342499 0.5113608837127686 <_> <_> <_>12 19 2 1 -1. <_>12 19 1 1 2. 0 2.9781080229440704e-005 0.4705932140350342 0.5432801842689514 90.2533493041992190 18 -1 <_> <_> <_> <_>1 2 4 9 -1. <_>3 2 2 9 2. 0 0.0117727499455214 0.3860518932342529 0.6421167254447937 <_> <_> <_>7 5 6 4 -1. <_>9 5 2 4 3. 0 0.0270375702530146 0.4385654926300049 0.6754038929939270 <_> <_> <_>9 4 2 4 -1. <_>9 6 2 2 2. 0 -3.6419500247575343e-005 0.5487101078033447 0.3423315882682800 <_> <_> <_>14 5 2 8 -1. <_>14 9 2 4 2. 0 1.9995409529656172e-003 0.3230532109737396 0.5400317907333374 <_> <_> <_>7 6 5 12 -1. <_>7 12 5 6 2. 0 4.5278300531208515e-003 0.5091639757156372 0.2935043871402741 <_> <_> <_>14 6 2 6 -1. <_>14 9 2 3 2. 0 4.7890920541249216e-004 0.4178153872489929 0.5344064235687256 <_> <_> <_>4 6 2 6 -1. <_>4 9 2 3 2. 0 1.1720920447260141e-003 0.2899182140827179 0.5132070779800415 <_> <_> <_>8 15 10 4 -1. <_>13 15 5 2 2. <_>8 17 5 2 2. 0 9.5305702416226268e-004 0.4280124902725220 0.5560845136642456 <_> <_> <_>6 18 2 2 -1. <_>7 18 1 2 2. 0 1.5099150004971307e-005 0.4044871926307678 0.5404760241508484 <_> <_> <_>11 3 6 2 -1. <_>11 4 6 1 2. 0 -6.0817901976406574e-004 0.4271768927574158 0.5503466129302979 <_> <_> <_>2 0 16 6 -1. <_>2 2 16 2 3. 0 3.3224520739167929e-003 0.3962723910808563 0.5369734764099121 <_> <_> <_>11 3 6 2 -1. <_>11 4 6 1 2. 0 -1.1037490330636501e-003 0.4727177917957306 0.5237749814987183 <_> <_> <_>4 11 10 3 -1. <_>4 12 10 1 3. 0 -1.4350269921123981e-003 0.5603008270263672 0.4223509132862091 <_> <_> <_>11 3 6 2 -1. <_>11 4 6 1 2. 0 2.0767399109899998e-003 0.5225917100906372 0.4732725918292999 <_> <_> <_>3 3 6 2 -1. <_>3 4 6 1 2. 0 -1.6412809782195836e-004 0.3999075889587402 0.5432739853858948 <_> <_> <_>16 0 4 7 -1. <_>16 0 2 7 2. 0 8.8302437216043472e-003 0.4678385853767395 0.6027327179908752 <_> <_> <_>0 14 9 6 -1. <_>0 16 9 2 3. 0 -0.0105520701035857 0.3493967056274414 0.5213974714279175 <_> <_> <_>9 16 3 3 -1. <_>9 17 3 1 3. 0 -2.2731600329279900e-003 0.6185818910598755 0.4749062955379486 <_> <_> <_>4 6 6 2 -1. <_>6 6 2 2 3. 0 -8.4786332445219159e-004 0.5285341143608093 0.3843482136726379 <_> <_> <_>15 11 1 3 -1. <_>15 12 1 1 3. 0 1.2081359745934606e-003 0.5360640883445740 0.3447335958480835 <_> <_> <_>5 5 2 3 -1. <_>5 6 2 1 3. 0 2.6512730401009321e-003 0.4558292031288147 0.6193962097167969 <_> <_> <_>10 9 2 2 -1. <_>10 10 2 1 2. 0 -1.1012479662895203e-003 0.3680230081081390 0.5327628254890442 <_> <_> <_>3 1 4 3 -1. <_>5 1 2 3 2. 0 4.9561518244445324e-004 0.3960595130920410 0.5274940729141235 <_> <_> <_>16 0 4 7 -1. <_>16 0 2 7 2. 0 -0.0439017713069916 0.7020444869995117 0.4992839097976685 <_> <_> <_>0 0 20 1 -1. <_>10 0 10 1 2. 0 0.0346903502941132 0.5049164295196533 0.2766602933406830 <_> <_> <_>15 11 1 3 -1. <_>15 12 1 1 3. 0 -2.7442190330475569e-003 0.2672632932662964 0.5274971127510071 <_> <_> <_>0 4 3 4 -1. <_>1 4 1 4 3. 0 3.3316588960587978e-003 0.4579482972621918 0.6001101732254028 <_> <_> <_>16 3 3 6 -1. <_>16 5 3 2 3. 0 -0.0200445707887411 0.3171594142913818 0.5235717892646790 <_> <_> <_>1 3 3 6 -1. <_>1 5 3 2 3. 0 1.3492030557245016e-003 0.5265362858772278 0.4034324884414673 <_> <_> <_>6 2 12 6 -1. <_>12 2 6 3 2. <_>6 5 6 3 2. 0 2.9702018946409225e-003 0.5332456827163696 0.4571984112262726 <_> <_> <_>8 10 4 3 -1. <_>8 11 4 1 3. 0 6.3039981760084629e-003 0.4593310952186585 0.6034635901451111 <_> <_> <_>4 2 14 6 -1. <_>11 2 7 3 2. <_>4 5 7 3 2. 0 -0.0129365902394056 0.4437963962554932 0.5372971296310425 <_> <_> <_>9 11 2 3 -1. <_>9 12 2 1 3. 0 4.0148729458451271e-003 0.4680323898792267 0.6437833905220032 <_> <_> <_>15 13 2 3 -1. <_>15 14 2 1 3. 0 -2.6401679497212172e-003 0.3709631860256195 0.5314332842826843 <_> <_> <_>8 12 4 3 -1. <_>8 13 4 1 3. 0 0.0139184398576617 0.4723555147647858 0.7130808830261231 <_> <_> <_>15 11 1 3 -1. <_>15 12 1 1 3. 0 -4.5087869511917233e-004 0.4492394030094147 0.5370404124259949 <_> <_> <_>7 13 5 2 -1. <_>7 14 5 1 2. 0 2.5384349282830954e-004 0.4406864047050476 0.5514402985572815 <_> <_> <_>7 12 6 3 -1. <_>7 13 6 1 3. 0 2.2710000630468130e-003 0.4682416915893555 0.5967984199523926 <_> <_> <_>5 11 4 4 -1. <_>5 13 4 2 2. 0 2.4120779708027840e-003 0.5079392194747925 0.3018598854541779 <_> <_> <_>11 4 3 3 -1. <_>12 4 1 3 3. 0 -3.6025670851813629e-005 0.5601037144660950 0.4471096992492676 <_> <_> <_>6 4 3 3 -1. <_>7 4 1 3 3. 0 -7.4905529618263245e-003 0.2207535058259964 0.4989944100379944 <_> <_> <_>16 5 3 6 -1. <_>17 5 1 6 3. 0 -0.0175131205469370 0.6531215906143189 0.5017648935317993 <_> <_> <_>3 6 12 7 -1. <_>7 6 4 7 3. 0 0.1428163051605225 0.4967963099479675 0.1482062041759491 <_> <_> <_>16 5 3 6 -1. <_>17 5 1 6 3. 0 5.5345268920063972e-003 0.4898946881294251 0.5954223871231079 <_> <_> <_>3 13 2 3 -1. <_>3 14 2 1 3. 0 -9.6323591424152255e-004 0.3927116990089417 0.5196074247360230 <_> <_> <_>16 5 3 6 -1. <_>17 5 1 6 3. 0 -2.0370010752230883e-003 0.5613325238227844 0.4884858131408691 <_> <_> <_>1 5 3 6 -1. <_>2 5 1 6 3. 0 1.6614829655736685e-003 0.4472880065441132 0.5578880906105042 <_> <_> <_>1 9 18 1 -1. <_>7 9 6 1 3. 0 -3.1188090797513723e-003 0.3840532898902893 0.5397477746009827 <_> <_> <_>0 9 8 7 -1. <_>4 9 4 7 2. 0 -6.4000617712736130e-003 0.5843983888626099 0.4533218145370483 <_> <_> <_>12 11 8 2 -1. <_>12 12 8 1 2. 0 3.1319601112045348e-004 0.5439221858978272 0.4234727919101715 <_> <_> <_>0 11 8 2 -1. <_>0 12 8 1 2. 0 -0.0182220991700888 0.1288464963436127 0.4958404898643494 <_> <_> <_>9 13 2 3 -1. <_>9 14 2 1 3. 0 8.7969247251749039e-003 0.4951297938823700 0.7153480052947998 <_> <_> <_>4 10 12 4 -1. <_>4 10 6 2 2. <_>10 12 6 2 2. 0 -4.2395070195198059e-003 0.3946599960327148 0.5194936990737915 <_> <_> <_>9 3 3 7 -1. <_>10 3 1 7 3. 0 9.7086271271109581e-003 0.4897503852844238 0.6064900159835815 <_> <_> <_>7 2 3 5 -1. <_>8 2 1 5 3. 0 -3.9934171363711357e-003 0.3245440125465393 0.5060828924179077 <_> <_> <_>9 12 4 6 -1. <_>11 12 2 3 2. <_>9 15 2 3 2. 0 -0.0167850591242313 0.1581953018903732 0.5203778743743897 <_> <_> <_>8 7 3 6 -1. <_>9 7 1 6 3. 0 0.0182720907032490 0.4680935144424439 0.6626979112625122 <_> <_> <_>15 4 4 2 -1. <_>15 5 4 1 2. 0 5.6872838176786900e-003 0.5211697816848755 0.3512184917926788 <_> <_> <_>8 7 3 3 -1. <_>9 7 1 3 3. 0 -1.0739039862528443e-003 0.5768386125564575 0.4529845118522644 <_> <_> <_>14 2 6 4 -1. <_>14 4 6 2 2. 0 -3.7093870341777802e-003 0.4507763087749481 0.5313581228256226 <_> <_> <_>7 16 6 1 -1. <_>9 16 2 1 3. 0 -2.1110709349159151e-004 0.5460820198059082 0.4333376884460449 <_> <_> <_>15 13 2 3 -1. <_>15 14 2 1 3. 0 1.0670139454305172e-003 0.5371856093406677 0.4078390896320343 <_> <_> <_>8 7 3 10 -1. <_>9 7 1 10 3. 0 3.5943021066486835e-003 0.4471287131309509 0.5643836259841919 <_> <_> <_>11 10 2 6 -1. <_>11 12 2 2 3. 0 -5.1776031032204628e-003 0.4499393105506897 0.5280330181121826 <_> <_> <_>6 10 4 1 -1. <_>8 10 2 1 2. 0 -2.5414369883947074e-004 0.5516173243522644 0.4407708048820496 <_> <_> <_>10 9 2 2 -1. <_>10 10 2 1 2. 0 6.3522560521960258e-003 0.5194190144538879 0.2465227991342545 <_> <_> <_>8 9 2 2 -1. <_>8 10 2 1 2. 0 -4.4205080484971404e-004 0.3830705881118774 0.5139682292938232 <_> <_> <_>12 7 2 2 -1. <_>13 7 1 1 2. <_>12 8 1 1 2. 0 7.4488727841526270e-004 0.4891090989112854 0.5974786877632141 <_> <_> <_>5 7 2 2 -1. <_>5 7 1 1 2. <_>6 8 1 1 2. 0 -3.5116379149258137e-003 0.7413681745529175 0.4768764972686768 <_> <_> <_>13 0 3 14 -1. <_>14 0 1 14 3. 0 -0.0125409103929996 0.3648819029331207 0.5252826809883118 <_> <_> <_>4 0 3 14 -1. <_>5 0 1 14 3. 0 9.4931852072477341e-003 0.5100492835044861 0.3629586994647980 <_> <_> <_>13 4 3 14 -1. <_>14 4 1 14 3. 0 0.0129611501470208 0.5232442021369934 0.4333561062812805 <_> <_> <_>9 14 2 3 -1. <_>9 15 2 1 3. 0 4.7209449112415314e-003 0.4648149013519287 0.6331052780151367 <_> <_> <_>8 14 4 3 -1. <_>8 15 4 1 3. 0 -2.3119079414755106e-003 0.5930309891700745 0.4531058073043823 <_> <_> <_>4 2 3 16 -1. <_>5 2 1 16 3. 0 -2.8262299019843340e-003 0.3870477974414825 0.5257101058959961 <_> <_> <_>7 2 8 10 -1. <_>7 7 8 5 2. 0 -1.4311339473351836e-003 0.5522503256797791 0.4561854898929596 <_> <_> <_>6 14 7 3 -1. <_>6 15 7 1 3. 0 1.9378310535103083e-003 0.4546220898628235 0.5736966729164124 <_> <_> <_>9 2 10 12 -1. <_>14 2 5 6 2. <_>9 8 5 6 2. 0 2.6343559147790074e-004 0.5345739126205444 0.4571875035762787 <_> <_> <_>6 7 8 2 -1. <_>6 8 8 1 2. 0 7.8257522545754910e-004 0.3967815935611725 0.5220187902450562 <_> <_> <_>8 13 4 6 -1. <_>8 16 4 3 2. 0 -0.0195504408329725 0.2829642891883850 0.5243508219718933 <_> <_> <_>6 6 1 3 -1. <_>6 7 1 1 3. 0 4.3914958951063454e-004 0.4590066969394684 0.5899090170860291 <_> <_> <_>16 2 4 6 -1. <_>16 4 4 2 3. 0 0.0214520003646612 0.5231410861015320 0.2855378985404968 <_> <_> <_>6 6 4 2 -1. <_>6 6 2 1 2. <_>8 7 2 1 2. 0 5.8973580598831177e-004 0.4397256970405579 0.5506421923637390 <_> <_> <_>16 2 4 6 -1. <_>16 4 4 2 3. 0 -0.0261576101183891 0.3135079145431519 0.5189175009727478 <_> <_> <_>0 2 4 6 -1. <_>0 4 4 2 3. 0 -0.0139598604291677 0.3213272988796234 0.5040717720985413 <_> <_> <_>9 6 2 6 -1. <_>9 6 1 6 2. 0 -6.3699018210172653e-003 0.6387544870376587 0.4849506914615631 <_> <_> <_>3 4 6 10 -1. <_>3 9 6 5 2. 0 -8.5613820701837540e-003 0.2759132087230682 0.5032019019126892 <_> <_> <_>9 5 2 6 -1. <_>9 5 1 6 2. 0 9.6622901037335396e-004 0.4685640931129456 0.5834879279136658 <_> <_> <_>3 13 2 3 -1. <_>3 14 2 1 3. 0 7.6550268568098545e-004 0.5175207257270813 0.3896422088146210 <_> <_> <_>13 13 3 2 -1. <_>13 14 3 1 2. 0 -8.1833340227603912e-003 0.2069136947393417 0.5208122134208679 <_> <_> <_>2 16 10 4 -1. <_>2 16 5 2 2. <_>7 18 5 2 2. 0 -9.3976939097046852e-003 0.6134091019630432 0.4641222953796387 <_> <_> <_>5 6 10 6 -1. <_>10 6 5 3 2. <_>5 9 5 3 2. 0 4.8028980381786823e-003 0.5454108119010925 0.4395219981670380 <_> <_> <_>7 14 1 3 -1. <_>7 15 1 1 3. 0 -3.5680569708347321e-003 0.6344485282897949 0.4681093990802765 <_> <_> <_>14 16 6 3 -1. <_>14 17 6 1 3. 0 4.0733120404183865e-003 0.5292683243751526 0.4015620052814484 <_> <_> <_>5 4 3 3 -1. <_>5 5 3 1 3. 0 1.2568129459396005e-003 0.4392988085746765 0.5452824831008911 <_> <_> <_>7 4 10 3 -1. <_>7 5 10 1 3. 0 -2.9065010603517294e-003 0.5898832082748413 0.4863379895687103 <_> <_> <_>0 4 5 4 -1. <_>0 6 5 2 2. 0 -2.4409340694546700e-003 0.4069364964962006 0.5247421860694885 <_> <_> <_>13 11 3 9 -1. <_>13 14 3 3 3. 0 0.0248307008296251 0.5182725787162781 0.3682524859905243 <_> <_> <_>4 11 3 9 -1. <_>4 14 3 3 3. 0 -0.0488540083169937 0.1307577937841415 0.4961281120777130 <_> <_> <_>9 7 2 1 -1. <_>9 7 1 1 2. 0 -1.6110379947349429e-003 0.6421005725860596 0.4872662127017975 <_> <_> <_>5 0 6 17 -1. <_>7 0 2 17 3. 0 -0.0970094799995422 0.0477693490684032 0.4950988888740540 <_> <_> <_>10 3 6 3 -1. <_>10 3 3 3 2. 0 1.1209240183234215e-003 0.4616267085075378 0.5354745984077454 <_> <_> <_>2 2 15 4 -1. <_>7 2 5 4 3. 0 -1.3064090162515640e-003 0.6261854171752930 0.4638805985450745 <_> <_> <_>8 2 8 2 -1. <_>12 2 4 1 2. <_>8 3 4 1 2. 0 4.5771620352752507e-004 0.5384417772293091 0.4646640121936798 <_> <_> <_>8 1 3 6 -1. <_>8 3 3 2 3. 0 -6.3149951165542006e-004 0.3804047107696533 0.5130257010459900 <_> <_> <_>9 17 2 2 -1. <_>9 18 2 1 2. 0 1.4505970466416329e-004 0.4554310142993927 0.5664461851119995 <_> <_> <_>0 0 2 14 -1. <_>1 0 1 14 2. 0 -0.0164745505899191 0.6596958041191101 0.4715859889984131 <_> <_> <_>12 0 7 3 -1. <_>12 1 7 1 3. 0 0.0133695797994733 0.5195466279983521 0.3035964965820313 <_> <_> <_>1 14 1 2 -1. <_>1 15 1 1 2. 0 1.0271780047332868e-004 0.5229176282882690 0.4107066094875336 <_> <_> <_>14 12 2 8 -1. <_>15 12 1 4 2. <_>14 16 1 4 2. 0 -5.5311559699475765e-003 0.6352887749671936 0.4960907101631165 <_> <_> <_>1 0 7 3 -1. <_>1 1 7 1 3. 0 -2.6187049224972725e-003 0.3824546039104462 0.5140984058380127 <_> <_> <_>14 12 2 8 -1. <_>15 12 1 4 2. <_>14 16 1 4 2. 0 5.0834268331527710e-003 0.4950439929962158 0.6220818758010864 <_> <_> <_>6 0 8 12 -1. <_>6 0 4 6 2. <_>10 6 4 6 2. 0 0.0798181593418121 0.4952335953712463 0.1322475969791412 <_> <_> <_>6 1 8 9 -1. <_>6 4 8 3 3. 0 -0.0992265865206718 0.7542728781700134 0.5008416771888733 <_> <_> <_>5 2 2 2 -1. <_>5 3 2 1 2. 0 -6.5174017800018191e-004 0.3699302971363068 0.5130121111869812 <_> <_> <_>13 14 6 6 -1. <_>16 14 3 3 2. <_>13 17 3 3 2. 0 -0.0189968496561050 0.6689178943634033 0.4921202957630158 <_> <_> <_>0 17 20 2 -1. <_>0 17 10 1 2. <_>10 18 10 1 2. 0 0.0173468999564648 0.4983300864696503 0.1859198063611984 <_> <_> <_>10 3 2 6 -1. <_>11 3 1 3 2. <_>10 6 1 3 2. 0 5.5082101607695222e-004 0.4574424028396606 0.5522121787071228 <_> <_> <_>5 12 6 2 -1. <_>8 12 3 2 2. 0 2.0056050270795822e-003 0.5131744742393494 0.3856469988822937 <_> <_> <_>10 7 6 13 -1. <_>10 7 3 13 2. 0 -7.7688191086053848e-003 0.4361700117588043 0.5434309244155884 <_> <_> <_>5 15 10 5 -1. <_>10 15 5 5 2. 0 0.0508782789111137 0.4682720899581909 0.6840639710426331 <_> <_> <_>10 4 4 10 -1. <_>10 4 2 10 2. 0 -2.2901780903339386e-003 0.4329245090484619 0.5306099057197571 <_> <_> <_>5 7 2 1 -1. <_>6 7 1 1 2. 0 -1.5715380141045898e-004 0.5370057225227356 0.4378164112567902 <_> <_> <_>10 3 6 7 -1. <_>10 3 3 7 2. 0 0.1051924005150795 0.5137274265289307 0.0673614665865898 <_> <_> <_>4 3 6 7 -1. <_>7 3 3 7 2. 0 2.7198919560760260e-003 0.4112060964107513 0.5255665183067322 <_> <_> <_>1 7 18 5 -1. <_>7 7 6 5 3. 0 0.0483377799391747 0.5404623746871948 0.4438967108726502 <_> <_> <_>3 17 4 3 -1. <_>5 17 2 3 2. 0 9.5703761326149106e-004 0.4355969130992889 0.5399510860443115 <_> <_> <_>8 14 12 6 -1. <_>14 14 6 3 2. <_>8 17 6 3 2. 0 -0.0253712590783834 0.5995175242424011 0.5031024813652039 <_> <_> <_>0 13 20 4 -1. <_>0 13 10 2 2. <_>10 15 10 2 2. 0 0.0524579510092735 0.4950287938117981 0.1398351043462753 <_> <_> <_>4 5 14 2 -1. <_>11 5 7 1 2. <_>4 6 7 1 2. 0 -0.0123656298965216 0.6397299170494080 0.4964106082916260 <_> <_> <_>1 2 10 12 -1. <_>1 2 5 6 2. <_>6 8 5 6 2. 0 -0.1458971947431564 0.1001669988036156 0.4946322143077850 <_> <_> <_>6 1 14 3 -1. <_>6 2 14 1 3. 0 -0.0159086007624865 0.3312329947948456 0.5208340883255005 <_> <_> <_>8 16 2 3 -1. <_>8 17 2 1 3. 0 3.9486068999394774e-004 0.4406363964080811 0.5426102876663208 <_> <_> <_>9 17 3 2 -1. <_>10 17 1 2 3. 0 -5.2454001270234585e-003 0.2799589931964874 0.5189967155456543 <_> <_> <_>5 15 4 2 -1. <_>5 15 2 1 2. <_>7 16 2 1 2. 0 -5.0421799533069134e-003 0.6987580060958862 0.4752142131328583 <_> <_> <_>10 15 1 3 -1. <_>10 16 1 1 3. 0 2.9812189750373363e-003 0.4983288943767548 0.6307479739189148 <_> <_> <_>8 16 4 4 -1. <_>8 16 2 2 2. <_>10 18 2 2 2. 0 -7.2884308174252510e-003 0.2982333004474640 0.5026869773864746 <_> <_> <_>6 11 8 6 -1. <_>6 14 8 3 2. 0 1.5094350092113018e-003 0.5308442115783691 0.3832970857620239 <_> <_> <_>2 13 5 2 -1. <_>2 14 5 1 2. 0 -9.3340799212455750e-003 0.2037964016199112 0.4969817101955414 <_> <_> <_>13 14 6 6 -1. <_>16 14 3 3 2. <_>13 17 3 3 2. 0 0.0286671407520771 0.5025696754455566 0.6928027272224426 <_> <_> <_>1 9 18 4 -1. <_>7 9 6 4 3. 0 0.1701968014240265 0.4960052967071533 0.1476442962884903 <_> <_> <_>13 14 6 6 -1. <_>16 14 3 3 2. <_>13 17 3 3 2. 0 -3.2614478841423988e-003 0.5603063702583313 0.4826056063175201 <_> <_> <_>0 2 1 6 -1. <_>0 4 1 2 3. 0 5.5769277969375253e-004 0.5205562114715576 0.4129633009433746 <_> <_> <_>5 0 15 20 -1. <_>5 10 15 10 2. 0 0.3625833988189697 0.5221652984619141 0.3768612146377564 <_> <_> <_>1 14 6 6 -1. <_>1 14 3 3 2. <_>4 17 3 3 2. 0 -0.0116151301190257 0.6022682785987854 0.4637489914894104 <_> <_> <_>8 14 4 6 -1. <_>10 14 2 3 2. <_>8 17 2 3 2. 0 -4.0795197710394859e-003 0.4070447087287903 0.5337479114532471 <_> <_> <_>7 11 2 1 -1. <_>8 11 1 1 2. 0 5.7204300537705421e-004 0.4601835012435913 0.5900393128395081 <_> <_> <_>9 17 3 2 -1. <_>10 17 1 2 3. 0 6.7543348995968699e-004 0.5398252010345459 0.4345428943634033 <_> <_> <_>8 17 3 2 -1. <_>9 17 1 2 3. 0 6.3295697327703238e-004 0.5201563239097595 0.4051358997821808 <_> <_> <_>12 14 4 6 -1. <_>14 14 2 3 2. <_>12 17 2 3 2. 0 1.2435320531949401e-003 0.4642387926578522 0.5547441244125366 <_> <_> <_>4 14 4 6 -1. <_>4 14 2 3 2. <_>6 17 2 3 2. 0 -4.7363857738673687e-003 0.6198567152023315 0.4672552049160004 <_> <_> <_>13 14 2 6 -1. <_>14 14 1 3 2. <_>13 17 1 3 2. 0 -6.4658462069928646e-003 0.6837332844734192 0.5019000768661499 <_> <_> <_>5 14 2 6 -1. <_>5 14 1 3 2. <_>6 17 1 3 2. 0 3.5017321351915598e-004 0.4344803094863892 0.5363622903823853 <_> <_> <_>7 0 6 12 -1. <_>7 4 6 4 3. 0 1.5754920605104417e-004 0.4760079085826874 0.5732020735740662 <_> <_> <_>0 7 12 2 -1. <_>4 7 4 2 3. 0 9.9774366244673729e-003 0.5090985894203186 0.3635039925575256 <_> <_> <_>10 3 3 13 -1. <_>11 3 1 13 3. 0 -4.1464529931545258e-004 0.5570064783096314 0.4593802094459534 <_> <_> <_>7 3 3 13 -1. <_>8 3 1 13 3. 0 -3.5888899583369493e-004 0.5356845855712891 0.4339134991168976 <_> <_> <_>10 8 6 3 -1. <_>10 9 6 1 3. 0 4.0463250479660928e-004 0.4439803063869476 0.5436776876449585 <_> <_> <_>3 11 3 2 -1. <_>4 11 1 2 3. 0 -8.2184787606820464e-004 0.4042294919490814 0.5176299214363098 <_> <_> <_>13 12 6 8 -1. <_>16 12 3 4 2. <_>13 16 3 4 2. 0 5.9467419050633907e-003 0.4927651882171631 0.5633779764175415 <_> <_> <_>7 6 6 5 -1. <_>9 6 2 5 3. 0 -0.0217533893883228 0.8006293773651123 0.4800840914249420 <_> <_> <_>17 11 2 7 -1. <_>17 11 1 7 2. 0 -0.0145403798669577 0.3946054875850678 0.5182222723960877 <_> <_> <_>3 13 8 2 -1. <_>7 13 4 2 2. 0 -0.0405107699334621 0.0213249903172255 0.4935792982578278 <_> <_> <_>6 9 8 3 -1. <_>6 10 8 1 3. 0 -5.8458268176764250e-004 0.4012795984745026 0.5314025282859802 <_> <_> <_>4 3 4 3 -1. <_>4 4 4 1 3. 0 5.5151800625026226e-003 0.4642418920993805 0.5896260738372803 <_> <_> <_>11 3 4 3 -1. <_>11 4 4 1 3. 0 -6.0626221820712090e-003 0.6502159237861633 0.5016477704048157 <_> <_> <_>1 4 17 12 -1. <_>1 8 17 4 3. 0 0.0945358425378799 0.5264708995819092 0.4126827120780945 <_> <_> <_>11 3 4 3 -1. <_>11 4 4 1 3. 0 4.7315051779150963e-003 0.4879199862480164 0.5892447829246521 <_> <_> <_>4 8 6 3 -1. <_>4 9 6 1 3. 0 -5.2571471314877272e-004 0.3917280137538910 0.5189412832260132 <_> <_> <_>12 3 5 3 -1. <_>12 4 5 1 3. 0 -2.5464049540460110e-003 0.5837599039077759 0.4985705912113190 <_> <_> <_>1 11 2 7 -1. <_>2 11 1 7 2. 0 -0.0260756891220808 0.1261983960866928 0.4955821931362152 <_> <_> <_>15 12 2 8 -1. <_>16 12 1 4 2. <_>15 16 1 4 2. 0 -5.4779709316790104e-003 0.5722513794898987 0.5010265707969666 <_> <_> <_>4 8 11 3 -1. <_>4 9 11 1 3. 0 5.1337741315364838e-003 0.5273262262344360 0.4226376116275787 <_> <_> <_>9 13 6 2 -1. <_>12 13 3 1 2. <_>9 14 3 1 2. 0 4.7944980906322598e-004 0.4450066983699799 0.5819587111473084 <_> <_> <_>6 13 4 3 -1. <_>6 14 4 1 3. 0 -2.1114079281687737e-003 0.5757653117179871 0.4511714875698090 <_> <_> <_>9 12 3 3 -1. <_>10 12 1 3 3. 0 -0.0131799904629588 0.1884381026029587 0.5160734057426453 <_> <_> <_>5 3 3 3 -1. <_>5 4 3 1 3. 0 -4.7968099825084209e-003 0.6589789986610413 0.4736118912696838 <_> <_> <_>9 4 2 3 -1. <_>9 5 2 1 3. 0 6.7483168095350266e-003 0.5259429812431335 0.3356395065784454 <_> <_> <_>0 2 16 3 -1. <_>0 3 16 1 3. 0 1.4623369788751006e-003 0.5355271100997925 0.4264092147350311 <_> <_> <_>15 12 2 8 -1. <_>16 12 1 4 2. <_>15 16 1 4 2. 0 4.7645159065723419e-003 0.5034406781196594 0.5786827802658081 <_> <_> <_>3 12 2 8 -1. <_>3 12 1 4 2. <_>4 16 1 4 2. 0 6.8066660314798355e-003 0.4756605029106140 0.6677829027175903 <_> <_> <_>14 13 3 6 -1. <_>14 15 3 2 3. 0 3.6608621012419462e-003 0.5369611978530884 0.4311546981334686 <_> <_> <_>3 13 3 6 -1. <_>3 15 3 2 3. 0 0.0214496403932571 0.4968641996383667 0.1888816058635712 <_> <_> <_>6 5 10 2 -1. <_>11 5 5 1 2. <_>6 6 5 1 2. 0 4.1678901761770248e-003 0.4930733144283295 0.5815368890762329 <_> <_> <_>2 14 14 6 -1. <_>2 17 14 3 2. 0 8.6467564105987549e-003 0.5205205082893372 0.4132595062255859 <_> <_> <_>10 14 1 3 -1. <_>10 15 1 1 3. 0 -3.6114078829996288e-004 0.5483555197715759 0.4800927937030792 <_> <_> <_>4 16 2 2 -1. <_>4 16 1 1 2. <_>5 17 1 1 2. 0 1.0808729566633701e-003 0.4689902067184448 0.6041421294212341 <_> <_> <_>10 6 2 3 -1. <_>10 7 2 1 3. 0 5.7719959877431393e-003 0.5171142220497131 0.3053277134895325 <_> <_> <_>0 17 20 2 -1. <_>0 17 10 1 2. <_>10 18 10 1 2. 0 1.5720770461484790e-003 0.5219978094100952 0.4178803861141205 <_> <_> <_>13 6 1 3 -1. <_>13 7 1 1 3. 0 -1.9307859474793077e-003 0.5860369801521301 0.4812920093536377 <_> <_> <_>8 13 3 2 -1. <_>9 13 1 2 3. 0 -7.8926272690296173e-003 0.1749276965856552 0.4971733987331390 <_> <_> <_>12 2 3 3 -1. <_>13 2 1 3 3. 0 -2.2224679123610258e-003 0.4342589080333710 0.5212848186492920 <_> <_> <_>3 18 2 2 -1. <_>3 18 1 1 2. <_>4 19 1 1 2. 0 1.9011989934369922e-003 0.4765186905860901 0.6892055273056030 <_> <_> <_>9 16 3 4 -1. <_>10 16 1 4 3. 0 2.7576119173318148e-003 0.5262191295623779 0.4337486028671265 <_> <_> <_>6 6 1 3 -1. <_>6 7 1 1 3. 0 5.1787449046969414e-003 0.4804069101810455 0.7843729257583618 <_> <_> <_>13 1 5 2 -1. <_>13 2 5 1 2. 0 -9.0273341629654169e-004 0.4120846986770630 0.5353423953056335 <_> <_> <_>7 14 6 2 -1. <_>7 14 3 1 2. <_>10 15 3 1 2. 0 5.1797959022223949e-003 0.4740372896194458 0.6425960063934326 <_> <_> <_>11 3 3 4 -1. <_>12 3 1 4 3. 0 -0.0101140001788735 0.2468792051076889 0.5175017714500427 <_> <_> <_>1 13 12 6 -1. <_>5 13 4 6 3. 0 -0.0186170600354671 0.5756294131278992 0.4628978967666626 <_> <_> <_>14 11 5 2 -1. <_>14 12 5 1 2. 0 5.9225959703326225e-003 0.5169625878334045 0.3214271068572998 <_> <_> <_>2 15 14 4 -1. <_>2 15 7 2 2. <_>9 17 7 2 2. 0 -6.2945079989731312e-003 0.3872014880180359 0.5141636729240418 <_> <_> <_>3 7 14 2 -1. <_>10 7 7 1 2. <_>3 8 7 1 2. 0 6.5353019163012505e-003 0.4853048920631409 0.6310489773750305 <_> <_> <_>1 11 4 2 -1. <_>1 12 4 1 2. 0 1.0878399480134249e-003 0.5117315053939819 0.3723258972167969 <_> <_> <_>14 0 6 14 -1. <_>16 0 2 14 3. 0 -0.0225422400981188 0.5692740082740784 0.4887112975120544 <_> <_> <_>4 11 1 3 -1. <_>4 12 1 1 3. 0 -3.0065660830587149e-003 0.2556012868881226 0.5003992915153503 <_> <_> <_>14 0 6 14 -1. <_>16 0 2 14 3. 0 7.4741272255778313e-003 0.4810872972011566 0.5675926804542542 <_> <_> <_>1 10 3 7 -1. <_>2 10 1 7 3. 0 0.0261623207479715 0.4971194863319397 0.1777237057685852 <_> <_> <_>8 12 9 2 -1. <_>8 13 9 1 2. 0 9.4352738233283162e-004 0.4940010905265808 0.5491250753402710 <_> <_> <_>0 6 20 1 -1. <_>10 6 10 1 2. 0 0.0333632417023182 0.5007612109184265 0.2790724039077759 <_> <_> <_>8 4 4 4 -1. <_>8 4 2 4 2. 0 -0.0151186501607299 0.7059578895568848 0.4973031878471375 <_> <_> <_>0 0 2 2 -1. <_>0 1 2 1 2. 0 9.8648946732282639e-004 0.5128620266914368 0.3776761889457703 104.7491989135742200 19 -1 <_> <_> <_> <_>5 3 10 9 -1. <_>5 6 10 3 3. 0 -0.0951507985591888 0.6470757126808167 0.4017286896705627 <_> <_> <_>15 2 4 10 -1. <_>15 2 2 10 2. 0 6.2702340073883533e-003 0.3999822139739990 0.5746449232101440 <_> <_> <_>8 2 2 7 -1. <_>9 2 1 7 2. 0 3.0018089455552399e-004 0.3558770120143890 0.5538809895515442 <_> <_> <_>7 4 12 1 -1. <_>11 4 4 1 3. 0 1.1757409665733576e-003 0.4256534874439240 0.5382617712020874 <_> <_> <_>3 4 9 1 -1. <_>6 4 3 1 3. 0 4.4235268433112651e-005 0.3682908117771149 0.5589926838874817 <_> <_> <_>15 10 1 4 -1. <_>15 12 1 2 2. 0 -2.9936920327600092e-005 0.5452470183372498 0.4020367860794067 <_> <_> <_>4 10 6 4 -1. <_>7 10 3 4 2. 0 3.0073199886828661e-003 0.5239058136940002 0.3317843973636627 <_> <_> <_>15 9 1 6 -1. <_>15 12 1 3 2. 0 -0.0105138896033168 0.4320689141750336 0.5307983756065369 <_> <_> <_>7 17 6 3 -1. <_>7 18 6 1 3. 0 8.3476826548576355e-003 0.4504637122154236 0.6453298926353455 <_> <_> <_>14 3 2 16 -1. <_>15 3 1 8 2. <_>14 11 1 8 2. 0 -3.1492270063608885e-003 0.4313425123691559 0.5370525121688843 <_> <_> <_>4 9 1 6 -1. <_>4 12 1 3 2. 0 -1.4435649973165710e-005 0.5326603055000305 0.3817971944808960 <_> <_> <_>12 1 5 2 -1. <_>12 2 5 1 2. 0 -4.2855090578086674e-004 0.4305163919925690 0.5382009744644165 <_> <_> <_>6 18 4 2 -1. <_>6 18 2 1 2. <_>8 19 2 1 2. 0 1.5062429883982986e-004 0.4235970973968506 0.5544965267181397 <_> <_> <_>2 4 16 10 -1. <_>10 4 8 5 2. <_>2 9 8 5 2. 0 0.0715598315000534 0.5303059816360474 0.2678802907466888 <_> <_> <_>6 5 1 10 -1. <_>6 10 1 5 2. 0 8.4095180500298738e-004 0.3557108938694000 0.5205433964729309 <_> <_> <_>4 8 15 2 -1. <_>9 8 5 2 3. 0 0.0629865005612373 0.5225362777709961 0.2861376106739044 <_> <_> <_>1 8 15 2 -1. <_>6 8 5 2 3. 0 -3.3798629883676767e-003 0.3624185919761658 0.5201697945594788 <_> <_> <_>9 5 3 6 -1. <_>9 7 3 2 3. 0 -1.1810739670181647e-004 0.5474476814270020 0.3959893882274628 <_> <_> <_>5 7 8 2 -1. <_>9 7 4 2 2. 0 -5.4505601292476058e-004 0.3740422129631043 0.5215715765953064 <_> <_> <_>9 11 2 3 -1. <_>9 12 2 1 3. 0 -1.8454910023137927e-003 0.5893052220344544 0.4584448933601379 <_> <_> <_>1 0 16 3 -1. <_>1 1 16 1 3. 0 -4.3832371011376381e-004 0.4084582030773163 0.5385351181030273 <_> <_> <_>11 2 7 2 -1. <_>11 3 7 1 2. 0 -2.4000830017030239e-003 0.3777455091476440 0.5293580293655396 <_> <_> <_>5 1 10 18 -1. <_>5 7 10 6 3. 0 -0.0987957417964935 0.2963612079620361 0.5070089101791382 <_> <_> <_>17 4 3 2 -1. <_>18 4 1 2 3. 0 3.1798239797353745e-003 0.4877632856369019 0.6726443767547607 <_> <_> <_>8 13 1 3 -1. <_>8 14 1 1 3. 0 3.2406419632025063e-004 0.4366911053657532 0.5561109781265259 <_> <_> <_>3 14 14 6 -1. <_>3 16 14 2 3. 0 -0.0325472503900528 0.3128157854080200 0.5308616161346436 <_> <_> <_>0 2 3 4 -1. <_>1 2 1 4 3. 0 -7.7561130747199059e-003 0.6560224890708923 0.4639872014522553 <_> <_> <_>12 1 5 2 -1. <_>12 2 5 1 2. 0 0.0160272493958473 0.5172680020332336 0.3141897916793823 <_> <_> <_>3 1 5 2 -1. <_>3 2 5 1 2. 0 7.1002350523485802e-006 0.4084446132183075 0.5336294770240784 <_> <_> <_>10 13 2 3 -1. <_>10 14 2 1 3. 0 7.3422808200120926e-003 0.4966922104358673 0.6603465080261231 <_> <_> <_>8 13 2 3 -1. <_>8 14 2 1 3. 0 -1.6970280557870865e-003 0.5908237099647522 0.4500182867050171 <_> <_> <_>14 12 2 3 -1. <_>14 13 2 1 3. 0 2.4118260480463505e-003 0.5315160751342773 0.3599720895290375 <_> <_> <_>7 2 2 3 -1. <_>7 3 2 1 3. 0 -5.5300937965512276e-003 0.2334040999412537 0.4996814131736755 <_> <_> <_>5 6 10 4 -1. <_>10 6 5 2 2. <_>5 8 5 2 2. 0 -2.6478730142116547e-003 0.5880935788154602 0.4684734046459198 <_> <_> <_>9 13 1 6 -1. <_>9 16 1 3 2. 0 0.0112956296652555 0.4983777105808258 0.1884590983390808 <_> <_> <_>10 12 2 2 -1. <_>11 12 1 1 2. <_>10 13 1 1 2. 0 -6.6952878842130303e-004 0.5872138142585754 0.4799019992351532 <_> <_> <_>4 12 2 3 -1. <_>4 13 2 1 3. 0 1.4410680159926414e-003 0.5131189227104187 0.3501011133193970 <_> <_> <_>14 4 6 6 -1. <_>14 6 6 2 3. 0 2.4637870956212282e-003 0.5339372158050537 0.4117639064788818 <_> <_> <_>8 17 2 3 -1. <_>8 18 2 1 3. 0 3.3114518737420440e-004 0.4313383102416992 0.5398246049880981 <_> <_> <_>16 4 4 6 -1. <_>16 6 4 2 3. 0 -0.0335572697222233 0.2675336897373200 0.5179154872894287 <_> <_> <_>0 4 4 6 -1. <_>0 6 4 2 3. 0 0.0185394193977118 0.4973869919776917 0.2317177057266235 <_> <_> <_>14 6 2 3 -1. <_>14 6 1 3 2. 0 -2.9698139405809343e-004 0.5529708266258240 0.4643664062023163 <_> <_> <_>4 9 8 1 -1. <_>8 9 4 1 2. 0 -4.5577259152196348e-004 0.5629584193229675 0.4469191133975983 <_> <_> <_>8 12 4 3 -1. <_>8 13 4 1 3. 0 -0.0101589802652597 0.6706212759017944 0.4925918877124786 <_> <_> <_>5 12 10 6 -1. <_>5 14 10 2 3. 0 -2.2413829356082715e-005 0.5239421725273132 0.3912901878356934 <_> <_> <_>11 12 1 2 -1. <_>11 13 1 1 2. 0 7.2034963523037732e-005 0.4799438118934631 0.5501788854598999 <_> <_> <_>8 15 4 2 -1. <_>8 16 4 1 2. 0 -6.9267209619283676e-003 0.6930009722709656 0.4698084890842438 <_> <_> <_>6 9 8 8 -1. <_>10 9 4 4 2. <_>6 13 4 4 2. 0 -7.6997838914394379e-003 0.4099623858928680 0.5480883121490479 <_> <_> <_>7 12 4 6 -1. <_>7 12 2 3 2. <_>9 15 2 3 2. 0 -7.3130549862980843e-003 0.3283475935459137 0.5057886242866516 <_> <_> <_>10 11 3 1 -1. <_>11 11 1 1 3. 0 1.9650589674711227e-003 0.4978047013282776 0.6398249864578247 <_> <_> <_>9 7 2 10 -1. <_>9 7 1 5 2. <_>10 12 1 5 2. 0 7.1647600270807743e-003 0.4661160111427307 0.6222137212753296 <_> <_> <_>8 0 6 6 -1. <_>10 0 2 6 3. 0 -0.0240786392241716 0.2334644943475723 0.5222162008285523 <_> <_> <_>3 11 2 6 -1. <_>3 13 2 2 3. 0 -0.0210279691964388 0.1183653995394707 0.4938226044178009 <_> <_> <_>16 12 1 2 -1. <_>16 13 1 1 2. 0 3.6017020465806127e-004 0.5325019955635071 0.4116711020469666 <_> <_> <_>1 14 6 6 -1. <_>1 14 3 3 2. <_>4 17 3 3 2. 0 -0.0172197297215462 0.6278762221336365 0.4664269089698792 <_> <_> <_>13 1 3 6 -1. <_>14 1 1 6 3. 0 -7.8672142699360847e-003 0.3403415083885193 0.5249736905097961 <_> <_> <_>8 8 2 2 -1. <_>8 9 2 1 2. 0 -4.4777389848604798e-004 0.3610411882400513 0.5086259245872498 <_> <_> <_>9 9 3 3 -1. <_>10 9 1 3 3. 0 5.5486010387539864e-003 0.4884265959262848 0.6203498244285584 <_> <_> <_>8 7 3 3 -1. <_>8 8 3 1 3. 0 -6.9461148232221603e-003 0.2625930011272430 0.5011097192764282 <_> <_> <_>14 0 2 3 -1. <_>14 0 1 3 2. 0 1.3569870498031378e-004 0.4340794980525971 0.5628312230110169 <_> <_> <_>1 0 18 9 -1. <_>7 0 6 9 3. 0 -0.0458802506327629 0.6507998704910278 0.4696274995803833 <_> <_> <_>11 5 4 15 -1. <_>11 5 2 15 2. 0 -0.0215825606137514 0.3826502859592438 0.5287616848945618 <_> <_> <_>5 5 4 15 -1. <_>7 5 2 15 2. 0 -0.0202095396816731 0.3233368098735809 0.5074477195739746 <_> <_> <_>14 0 2 3 -1. <_>14 0 1 3 2. 0 5.8496710844337940e-003 0.5177603960037231 0.4489670991897583 <_> <_> <_>4 0 2 3 -1. <_>5 0 1 3 2. 0 -5.7476379879517481e-005 0.4020850956439972 0.5246363878250122 <_> <_> <_>11 12 2 2 -1. <_>12 12 1 1 2. <_>11 13 1 1 2. 0 -1.1513100471347570e-003 0.6315072178840637 0.4905154109001160 <_> <_> <_>7 12 2 2 -1. <_>7 12 1 1 2. <_>8 13 1 1 2. 0 1.9862831104546785e-003 0.4702459871768951 0.6497151255607605 <_> <_> <_>12 0 3 4 -1. <_>13 0 1 4 3. 0 -5.2719512023031712e-003 0.3650383949279785 0.5227652788162231 <_> <_> <_>4 11 3 3 -1. <_>4 12 3 1 3. 0 1.2662699446082115e-003 0.5166100859642029 0.3877618014812470 <_> <_> <_>12 7 4 2 -1. <_>12 8 4 1 2. 0 -6.2919440679252148e-003 0.7375894188880920 0.5023847818374634 <_> <_> <_>8 10 3 2 -1. <_>9 10 1 2 3. 0 6.7360111279413104e-004 0.4423226118087769 0.5495585799217224 <_> <_> <_>9 9 3 2 -1. <_>10 9 1 2 3. 0 -1.0523450328037143e-003 0.5976396203041077 0.4859583079814911 <_> <_> <_>8 9 3 2 -1. <_>9 9 1 2 3. 0 -4.4216238893568516e-004 0.5955939292907715 0.4398930966854096 <_> <_> <_>12 0 3 4 -1. <_>13 0 1 4 3. 0 1.1747940443456173e-003 0.5349888205528259 0.4605058133602142 <_> <_> <_>5 0 3 4 -1. <_>6 0 1 4 3. 0 5.2457437850534916e-003 0.5049191117286682 0.2941577136516571 <_> <_> <_>4 14 12 4 -1. <_>10 14 6 2 2. <_>4 16 6 2 2. 0 -0.0245397202670574 0.2550177872180939 0.5218586921691895 <_> <_> <_>8 13 2 3 -1. <_>8 14 2 1 3. 0 7.3793041519820690e-004 0.4424861073493958 0.5490816235542297 <_> <_> <_>10 10 3 8 -1. <_>10 14 3 4 2. 0 1.4233799884095788e-003 0.5319514274597168 0.4081355929374695 <_> <_> <_>8 10 4 8 -1. <_>8 10 2 4 2. <_>10 14 2 4 2. 0 -2.4149110540747643e-003 0.4087659120559692 0.5238950252532959 <_> <_> <_>10 8 3 1 -1. <_>11 8 1 1 3. 0 -1.2165299849584699e-003 0.5674579143524170 0.4908052980899811 <_> <_> <_>9 12 1 6 -1. <_>9 15 1 3 2. 0 -1.2438809499144554e-003 0.4129425883293152 0.5256118178367615 <_> <_> <_>10 8 3 1 -1. <_>11 8 1 1 3. 0 6.1942739412188530e-003 0.5060194134712219 0.7313653230667114 <_> <_> <_>7 8 3 1 -1. <_>8 8 1 1 3. 0 -1.6607169527560472e-003 0.5979632139205933 0.4596369862556458 <_> <_> <_>5 2 15 14 -1. <_>5 9 15 7 2. 0 -0.0273162592202425 0.4174365103244782 0.5308842062950134 <_> <_> <_>2 1 2 10 -1. <_>2 1 1 5 2. <_>3 6 1 5 2. 0 -1.5845570014789701e-003 0.5615804791450501 0.4519486129283905 <_> <_> <_>14 14 2 3 -1. <_>14 15 2 1 3. 0 -1.5514739789068699e-003 0.4076187014579773 0.5360785126686096 <_> <_> <_>2 7 3 3 -1. <_>3 7 1 3 3. 0 3.8446558755822480e-004 0.4347293972969055 0.5430442094802856 <_> <_> <_>17 4 3 3 -1. <_>17 5 3 1 3. 0 -0.0146722598001361 0.1659304946660996 0.5146093964576721 <_> <_> <_>0 4 3 3 -1. <_>0 5 3 1 3. 0 8.1608882173895836e-003 0.4961819052696228 0.1884745955467224 <_> <_> <_>13 5 6 2 -1. <_>16 5 3 1 2. <_>13 6 3 1 2. 0 1.1121659772470593e-003 0.4868263900279999 0.6093816161155701 <_> <_> <_>4 19 12 1 -1. <_>8 19 4 1 3. 0 -7.2603770531713963e-003 0.6284325122833252 0.4690375924110413 <_> <_> <_>12 12 2 4 -1. <_>12 14 2 2 2. 0 -2.4046430189628154e-004 0.5575000047683716 0.4046044051647186 <_> <_> <_>3 15 1 3 -1. <_>3 16 1 1 3. 0 -2.3348190006799996e-004 0.4115762114524841 0.5252848267555237 <_> <_> <_>11 16 6 4 -1. <_>11 16 3 4 2. 0 5.5736480280756950e-003 0.4730072915554047 0.5690100789070129 <_> <_> <_>2 10 3 10 -1. <_>3 10 1 10 3. 0 0.0306237693876028 0.4971886873245239 0.1740095019340515 <_> <_> <_>12 8 2 4 -1. <_>12 8 1 4 2. 0 9.2074798885732889e-004 0.5372117757797241 0.4354872107505798 <_> <_> <_>6 8 2 4 -1. <_>7 8 1 4 2. 0 -4.3550739064812660e-005 0.5366883873939514 0.4347316920757294 <_> <_> <_>10 14 2 3 -1. <_>10 14 1 3 2. 0 -6.6452710889279842e-003 0.3435518145561218 0.5160533189773560 <_> <_> <_>5 1 10 3 -1. <_>10 1 5 3 2. 0 0.0432219989597797 0.4766792058944702 0.7293652892112732 <_> <_> <_>10 7 3 2 -1. <_>11 7 1 2 3. 0 2.2331769578158855e-003 0.5029315948486328 0.5633171200752258 <_> <_> <_>5 6 9 2 -1. <_>8 6 3 2 3. 0 3.1829739455133677e-003 0.4016092121601105 0.5192136764526367 <_> <_> <_>9 8 2 2 -1. <_>9 9 2 1 2. 0 -1.8027749320026487e-004 0.4088315963745117 0.5417919754981995 <_> <_> <_>2 11 16 6 -1. <_>2 11 8 3 2. <_>10 14 8 3 2. 0 -5.2934689447283745e-003 0.4075677096843720 0.5243561863899231 <_> <_> <_>12 7 2 2 -1. <_>13 7 1 1 2. <_>12 8 1 1 2. 0 1.2750959722325206e-003 0.4913282990455627 0.6387010812759399 <_> <_> <_>9 5 2 3 -1. <_>9 6 2 1 3. 0 4.3385322205722332e-003 0.5031672120094299 0.2947346866130829 <_> <_> <_>9 7 3 2 -1. <_>10 7 1 2 3. 0 8.5250744596123695e-003 0.4949789047241211 0.6308869123458862 <_> <_> <_>5 1 8 12 -1. <_>5 7 8 6 2. 0 -9.4266352243721485e-004 0.5328366756439209 0.4285649955272675 <_> <_> <_>13 5 2 2 -1. <_>13 6 2 1 2. 0 1.3609660090878606e-003 0.4991525113582611 0.5941501259803772 <_> <_> <_>5 5 2 2 -1. <_>5 6 2 1 2. 0 4.4782509212382138e-004 0.4573504030704498 0.5854480862617493 <_> <_> <_>12 4 3 3 -1. <_>12 5 3 1 3. 0 1.3360050506889820e-003 0.4604358971118927 0.5849052071571350 <_> <_> <_>4 14 2 3 -1. <_>4 15 2 1 3. 0 -6.0967548051849008e-004 0.3969388902187347 0.5229423046112061 <_> <_> <_>12 4 3 3 -1. <_>12 5 3 1 3. 0 -2.3656780831515789e-003 0.5808320045471191 0.4898357093334198 <_> <_> <_>5 4 3 3 -1. <_>5 5 3 1 3. 0 1.0734340175986290e-003 0.4351210892200470 0.5470039248466492 <_> <_> <_>9 14 2 6 -1. <_>10 14 1 3 2. <_>9 17 1 3 2. 0 2.1923359017819166e-003 0.5355060100555420 0.3842903971672058 <_> <_> <_>8 14 3 2 -1. <_>9 14 1 2 3. 0 5.4968618787825108e-003 0.5018138885498047 0.2827191948890686 <_> <_> <_>9 5 6 6 -1. <_>11 5 2 6 3. 0 -0.0753688216209412 0.1225076019763947 0.5148826837539673 <_> <_> <_>5 5 6 6 -1. <_>7 5 2 6 3. 0 0.0251344703137875 0.4731766879558563 0.7025446295738220 <_> <_> <_>13 13 1 2 -1. <_>13 14 1 1 2. 0 -2.9358599931583740e-005 0.5430532097816467 0.4656086862087250 <_> <_> <_>0 2 10 2 -1. <_>0 3 10 1 2. 0 -5.8355910005047917e-004 0.4031040072441101 0.5190119743347168 <_> <_> <_>13 13 1 2 -1. <_>13 14 1 1 2. 0 -2.6639450807124376e-003 0.4308126866817474 0.5161771178245544 <_> <_> <_>5 7 2 2 -1. <_>5 7 1 1 2. <_>6 8 1 1 2. 0 -1.3804089976474643e-003 0.6219829916954041 0.4695515930652618 <_> <_> <_>13 5 2 7 -1. <_>13 5 1 7 2. 0 1.2313219485804439e-003 0.5379363894462585 0.4425831139087677 <_> <_> <_>6 13 1 2 -1. <_>6 14 1 1 2. 0 -1.4644179827882908e-005 0.5281640291213989 0.4222503006458283 <_> <_> <_>11 0 3 7 -1. <_>12 0 1 7 3. 0 -0.0128188095986843 0.2582092881202698 0.5179932713508606 <_> <_> <_>0 3 2 16 -1. <_>0 3 1 8 2. <_>1 11 1 8 2. 0 0.0228521898388863 0.4778693020343781 0.7609264254570007 <_> <_> <_>11 0 3 7 -1. <_>12 0 1 7 3. 0 8.2305970136076212e-004 0.5340992212295532 0.4671724140644074 <_> <_> <_>6 0 3 7 -1. <_>7 0 1 7 3. 0 0.0127701200544834 0.4965761005878449 0.1472366005182266 <_> <_> <_>11 16 8 4 -1. <_>11 16 4 4 2. 0 -0.0500515103340149 0.6414994001388550 0.5016592144966126 <_> <_> <_>1 16 8 4 -1. <_>5 16 4 4 2. 0 0.0157752707600594 0.4522320032119751 0.5685362219810486 <_> <_> <_>13 5 2 7 -1. <_>13 5 1 7 2. 0 -0.0185016207396984 0.2764748930931091 0.5137959122657776 <_> <_> <_>5 5 2 7 -1. <_>6 5 1 7 2. 0 2.4626250378787518e-003 0.5141941905021668 0.3795408010482788 <_> <_> <_>18 6 2 14 -1. <_>18 13 2 7 2. 0 0.0629161670804024 0.5060648918151856 0.6580433845520020 <_> <_> <_>6 10 3 4 -1. <_>6 12 3 2 2. 0 -2.1648500478477217e-005 0.5195388197898865 0.4019886851310730 <_> <_> <_>14 7 1 2 -1. <_>14 8 1 1 2. 0 2.1180990152060986e-003 0.4962365031242371 0.5954458713531494 <_> <_> <_>0 1 18 6 -1. <_>0 1 9 3 2. <_>9 4 9 3 2. 0 -0.0166348908096552 0.3757933080196381 0.5175446867942810 <_> <_> <_>14 7 1 2 -1. <_>14 8 1 1 2. 0 -2.8899470344185829e-003 0.6624013781547546 0.5057178735733032 <_> <_> <_>0 6 2 14 -1. <_>0 13 2 7 2. 0 0.0767832621932030 0.4795796871185303 0.8047714829444885 <_> <_> <_>17 0 3 12 -1. <_>18 0 1 12 3. 0 3.9170677773654461e-003 0.4937882125377655 0.5719941854476929 <_> <_> <_>0 6 18 3 -1. <_>0 7 18 1 3. 0 -0.0726706013083458 0.0538945607841015 0.4943903982639313 <_> <_> <_>6 0 14 16 -1. <_>6 8 14 8 2. 0 0.5403950214385986 0.5129774212837219 0.1143338978290558 <_> <_> <_>0 0 3 12 -1. <_>1 0 1 12 3. 0 2.9510019812732935e-003 0.4528343975543976 0.5698574185371399 <_> <_> <_>13 0 3 7 -1. <_>14 0 1 7 3. 0 3.4508369863033295e-003 0.5357726812362671 0.4218730926513672 <_> <_> <_>5 7 1 2 -1. <_>5 8 1 1 2. 0 -4.2077939724549651e-004 0.5916172862052918 0.4637925922870636 <_> <_> <_>14 4 6 6 -1. <_>14 6 6 2 3. 0 3.3051050268113613e-003 0.5273385047912598 0.4382042884826660 <_> <_> <_>5 7 7 2 -1. <_>5 8 7 1 2. 0 4.7735060798004270e-004 0.4046528041362763 0.5181884765625000 <_> <_> <_>8 6 6 9 -1. <_>8 9 6 3 3. 0 -0.0259285103529692 0.7452235817909241 0.5089386105537415 <_> <_> <_>5 4 6 1 -1. <_>7 4 2 1 3. 0 -2.9729790985584259e-003 0.3295435905456543 0.5058795213699341 <_> <_> <_>13 0 6 4 -1. <_>16 0 3 2 2. <_>13 2 3 2 2. 0 5.8508329093456268e-003 0.4857144057750702 0.5793024897575378 <_> <_> <_>1 2 18 12 -1. <_>1 6 18 4 3. 0 -0.0459675192832947 0.4312731027603149 0.5380653142929077 <_> <_> <_>3 2 17 12 -1. <_>3 6 17 4 3. 0 0.1558596044778824 0.5196170210838318 0.1684713959693909 <_> <_> <_>5 14 7 3 -1. <_>5 15 7 1 3. 0 0.0151648297905922 0.4735757112503052 0.6735026836395264 <_> <_> <_>10 14 1 3 -1. <_>10 15 1 1 3. 0 -1.0604249546304345e-003 0.5822926759719849 0.4775702953338623 <_> <_> <_>3 14 3 3 -1. <_>3 15 3 1 3. 0 6.6476291976869106e-003 0.4999198913574219 0.2319535017013550 <_> <_> <_>14 4 6 6 -1. <_>14 6 6 2 3. 0 -0.0122311301529408 0.4750893115997315 0.5262982249259949 <_> <_> <_>0 4 6 6 -1. <_>0 6 6 2 3. 0 5.6528882123529911e-003 0.5069767832756043 0.3561818897724152 <_> <_> <_>12 5 4 3 -1. <_>12 6 4 1 3. 0 1.2977829901501536e-003 0.4875693917274475 0.5619062781333923 <_> <_> <_>4 5 4 3 -1. <_>4 6 4 1 3. 0 0.0107815898954868 0.4750770032405853 0.6782308220863342 <_> <_> <_>18 0 2 6 -1. <_>18 2 2 2 3. 0 2.8654779307544231e-003 0.5305461883544922 0.4290736019611359 <_> <_> <_>8 1 4 9 -1. <_>10 1 2 9 2. 0 2.8663428965955973e-003 0.4518479108810425 0.5539351105690002 <_> <_> <_>6 6 8 2 -1. <_>6 6 4 2 2. 0 -5.1983320154249668e-003 0.4149119853973389 0.5434188842773438 <_> <_> <_>6 5 4 2 -1. <_>6 5 2 1 2. <_>8 6 2 1 2. 0 5.3739990107715130e-003 0.4717896878719330 0.6507657170295715 <_> <_> <_>10 5 2 3 -1. <_>10 6 2 1 3. 0 -0.0146415298804641 0.2172164022922516 0.5161777138710022 <_> <_> <_>9 5 1 3 -1. <_>9 6 1 1 3. 0 -1.5042580344015732e-005 0.5337383747100830 0.4298836886882782 <_> <_> <_>9 10 2 2 -1. <_>9 11 2 1 2. 0 -1.1875660129589960e-004 0.4604594111442566 0.5582447052001953 <_> <_> <_>0 8 4 3 -1. <_>0 9 4 1 3. 0 0.0169955305755138 0.4945895075798035 0.0738800764083862 <_> <_> <_>6 0 8 6 -1. <_>6 3 8 3 2. 0 -0.0350959412753582 0.7005509138107300 0.4977591037750244 <_> <_> <_>1 0 6 4 -1. <_>1 0 3 2 2. <_>4 2 3 2 2. 0 2.4217350874096155e-003 0.4466265141963959 0.5477694272994995 <_> <_> <_>13 0 3 7 -1. <_>14 0 1 7 3. 0 -9.6340337768197060e-004 0.4714098870754242 0.5313338041305542 <_> <_> <_>9 16 2 2 -1. <_>9 17 2 1 2. 0 1.6391130338888615e-004 0.4331546127796173 0.5342242121696472 <_> <_> <_>11 4 6 10 -1. <_>11 9 6 5 2. 0 -0.0211414601653814 0.2644700109958649 0.5204498767852783 <_> <_> <_>0 10 19 2 -1. <_>0 11 19 1 2. 0 8.7775202700868249e-004 0.5208349823951721 0.4152742922306061 <_> <_> <_>9 5 8 9 -1. <_>9 8 8 3 3. 0 -0.0279439203441143 0.6344125270843506 0.5018811821937561 <_> <_> <_>4 0 3 7 -1. <_>5 0 1 7 3. 0 6.7297378554940224e-003 0.5050438046455383 0.3500863909721375 <_> <_> <_>8 6 4 12 -1. <_>10 6 2 6 2. <_>8 12 2 6 2. 0 0.0232810396701097 0.4966318011283875 0.6968677043914795 <_> <_> <_>0 2 6 4 -1. <_>0 4 6 2 2. 0 -0.0116449799388647 0.3300260007381439 0.5049629807472229 <_> <_> <_>8 15 4 3 -1. <_>8 16 4 1 3. 0 0.0157643090933561 0.4991598129272461 0.7321153879165649 <_> <_> <_>8 0 3 7 -1. <_>9 0 1 7 3. 0 -1.3611479662358761e-003 0.3911735117435455 0.5160670876502991 <_> <_> <_>9 5 3 4 -1. <_>10 5 1 4 3. 0 -8.1522337859496474e-004 0.5628911256790161 0.4949719011783600 <_> <_> <_>8 5 3 4 -1. <_>9 5 1 4 3. 0 -6.0066272271797061e-004 0.5853595137596130 0.4550595879554749 <_> <_> <_>7 6 6 1 -1. <_>9 6 2 1 3. 0 4.9715518252924085e-004 0.4271470010280609 0.5443599224090576 <_> <_> <_>7 14 4 4 -1. <_>7 14 2 2 2. <_>9 16 2 2 2. 0 2.3475370835512877e-003 0.5143110752105713 0.3887656927108765 <_> <_> <_>13 14 4 6 -1. <_>15 14 2 3 2. <_>13 17 2 3 2. 0 -8.9261569082736969e-003 0.6044502258300781 0.4971720874309540 <_> <_> <_>7 8 1 8 -1. <_>7 12 1 4 2. 0 -0.0139199104160070 0.2583160996437073 0.5000367760658264 <_> <_> <_>16 0 2 8 -1. <_>17 0 1 4 2. <_>16 4 1 4 2. 0 1.0209949687123299e-003 0.4857374131679535 0.5560358166694641 <_> <_> <_>2 0 2 8 -1. <_>2 0 1 4 2. <_>3 4 1 4 2. 0 -2.7441629208624363e-003 0.5936884880065918 0.4645777046680450 <_> <_> <_>6 1 14 3 -1. <_>6 2 14 1 3. 0 -0.0162001308053732 0.3163014948368073 0.5193495154380798 <_> <_> <_>7 9 3 10 -1. <_>7 14 3 5 2. 0 4.3331980705261230e-003 0.5061224102973938 0.3458878993988037 <_> <_> <_>9 14 2 2 -1. <_>9 15 2 1 2. 0 5.8497930876910686e-004 0.4779017865657806 0.5870177745819092 <_> <_> <_>7 7 6 8 -1. <_>7 11 6 4 2. 0 -2.2466450463980436e-003 0.4297851026058197 0.5374773144721985 <_> <_> <_>9 7 3 6 -1. <_>9 10 3 3 2. 0 2.3146099410951138e-003 0.5438671708106995 0.4640969932079315 <_> <_> <_>7 13 3 3 -1. <_>7 14 3 1 3. 0 8.7679121643304825e-003 0.4726893007755280 0.6771789789199829 <_> <_> <_>9 9 2 2 -1. <_>9 10 2 1 2. 0 -2.2448020172305405e-004 0.4229173064231873 0.5428048968315125 <_> <_> <_>0 1 18 2 -1. <_>6 1 6 2 3. 0 -7.4336021207273006e-003 0.6098880767822266 0.4683673977851868 <_> <_> <_>7 1 6 14 -1. <_>7 8 6 7 2. 0 -2.3189240600913763e-003 0.5689436793327332 0.4424242079257965 <_> <_> <_>1 9 18 1 -1. <_>7 9 6 1 3. 0 -2.1042178850620985e-003 0.3762221038341522 0.5187087059020996 <_> <_> <_>9 7 2 2 -1. <_>9 7 1 2 2. 0 4.6034841216169298e-004 0.4699405133724213 0.5771207213401794 <_> <_> <_>9 3 2 9 -1. <_>10 3 1 9 2. 0 1.0547629790380597e-003 0.4465216994285584 0.5601701736450195 <_> <_> <_>18 14 2 3 -1. <_>18 15 2 1 3. 0 8.7148818420246243e-004 0.5449805259704590 0.3914709091186523 <_> <_> <_>7 11 3 1 -1. <_>8 11 1 1 3. 0 3.3364820410497487e-004 0.4564009010791779 0.5645738840103149 <_> <_> <_>10 8 3 4 -1. <_>11 8 1 4 3. 0 -1.4853250468149781e-003 0.5747377872467041 0.4692778885364533 <_> <_> <_>7 14 3 6 -1. <_>8 14 1 6 3. 0 3.0251620337367058e-003 0.5166196823120117 0.3762814104557037 <_> <_> <_>10 8 3 4 -1. <_>11 8 1 4 3. 0 5.0280741415917873e-003 0.5002111792564392 0.6151527166366577 <_> <_> <_>7 8 3 4 -1. <_>8 8 1 4 3. 0 -5.8164511574432254e-004 0.5394598245620728 0.4390751123428345 <_> <_> <_>7 9 6 9 -1. <_>7 12 6 3 3. 0 0.0451415292918682 0.5188326835632324 0.2063035964965820 <_> <_> <_>0 14 2 3 -1. <_>0 15 2 1 3. 0 -1.0795620037242770e-003 0.3904685080051422 0.5137907266616821 <_> <_> <_>11 12 1 2 -1. <_>11 13 1 1 2. 0 1.5995999274309725e-004 0.4895322918891907 0.5427504181861877 <_> <_> <_>4 3 8 3 -1. <_>8 3 4 3 2. 0 -0.0193592701107264 0.6975228786468506 0.4773507118225098 <_> <_> <_>0 4 20 6 -1. <_>0 4 10 6 2. 0 0.2072550952434540 0.5233635902404785 0.3034991919994354 <_> <_> <_>9 14 1 3 -1. <_>9 15 1 1 3. 0 -4.1953290929086506e-004 0.5419396758079529 0.4460186064243317 <_> <_> <_>8 14 4 3 -1. <_>8 15 4 1 3. 0 2.2582069505006075e-003 0.4815764129161835 0.6027408838272095 <_> <_> <_>0 15 14 4 -1. <_>0 17 14 2 2. 0 -6.7811207845807076e-003 0.3980278968811035 0.5183305740356445 <_> <_> <_>1 14 18 6 -1. <_>1 17 18 3 2. 0 0.0111543098464608 0.5431231856346130 0.4188759922981262 <_> <_> <_>0 0 10 6 -1. <_>0 0 5 3 2. <_>5 3 5 3 2. 0 0.0431624315679073 0.4738228023052216 0.6522961258888245 105.7611007690429700 20 -1 ================================================ FILE: platforms/opencv/helpers_test.go ================================================ //go:build gocv // +build gocv package opencv import ( "gocv.io/x/gocv" ) type testCapture struct{} func (c *testCapture) Read(img *gocv.Mat) bool { return true } type testWindow struct{} func (w *testWindow) ShowImage(img gocv.Mat) { return } ================================================ FILE: platforms/opencv/utils.go ================================================ //go:build gocv // +build gocv package opencv import ( "image" "image/color" "gocv.io/x/gocv" ) var classifier *gocv.CascadeClassifier // loadHaarClassifierCascade returns open cv HaarCascade loaded func loadCascadeClassifier(haar string) *gocv.CascadeClassifier { if classifier != nil { return classifier } c := gocv.NewCascadeClassifier() c.Load(haar) classifier = &c return classifier } // DetectObjects loads Haar cascade to detect face objects in image func DetectObjects(haar string, img gocv.Mat) []image.Rectangle { return loadCascadeClassifier(haar).DetectMultiScale(img) } // DrawRectangles uses Rect array values to return image with rectangles drawn. func DrawRectangles(img gocv.Mat, rects []image.Rectangle, r int, g int, b int, thickness int) { for _, rect := range rects { gocv.Rectangle(&img, rect, color.RGBA{uint8(r), uint8(g), uint8(b), 0}, thickness) } return } ================================================ FILE: platforms/opencv/utils_test.go ================================================ //go:build gocv // +build gocv package opencv import ( "path" "runtime" "testing" "github.com/stretchr/testify/assert" "gocv.io/x/gocv" ) func TestUtils(t *testing.T) { _, currentfile, _, _ := runtime.Caller(0) image := gocv.IMRead(path.Join(path.Dir(currentfile), "lena-256x256.jpg"), gocv.IMReadColor) rect := DetectObjects("haarcascade_frontalface_alt.xml", image) assert.NotEqual(t, 0, len(rect)) DrawRectangles(image, rect, 0, 0, 0, 0) } ================================================ FILE: platforms/opencv/window_driver.go ================================================ //go:build gocv // +build gocv package opencv import ( "gobot.io/x/gobot/v2" "gocv.io/x/gocv" ) type window interface { IMShow(gocv.Mat) } // WindowDriver is the Gobot Driver for the OpenCV window type WindowDriver struct { name string window window start func(*WindowDriver) } // NewWindowDriver creates a new window driver. // It adds an start function to initialize window func NewWindowDriver() *WindowDriver { return &WindowDriver{ name: "Window", start: func(w *WindowDriver) { w.window = gocv.NewWindow(w.Name()) }, } } // Name returns the Driver name func (w *WindowDriver) Name() string { return w.name } // SetName sets the Driver name func (w *WindowDriver) SetName(n string) { w.name = n } // Connection returns the Driver's connection func (w *WindowDriver) Connection() gobot.Connection { return nil } // Start starts window thread and driver func (w *WindowDriver) Start() error { w.start(w) return nil } // Halt returns true if camera is halted successfully func (w *WindowDriver) Halt() error { return nil } // ShowImage displays image in window func (w *WindowDriver) ShowImage(img gocv.Mat) { w.window.IMShow(img) } // WaitKey gives window a chance to redraw, and checks for keyboard input func (w *WindowDriver) WaitKey(pause int) int { return gocv.WaitKey(pause) } ================================================ FILE: platforms/opencv/window_driver_test.go ================================================ //go:build gocv // +build gocv package opencv import ( "path" "runtime" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gocv.io/x/gocv" ) var _ gobot.Driver = (*WindowDriver)(nil) func initTestWindowDriver() *WindowDriver { d := NewWindowDriver() return d } func TestWindowDriver(t *testing.T) { d := initTestWindowDriver() assert.Equal(t, "Window", d.Name()) assert.Equal(t, (gobot.Connection)(nil), d.Connection()) } func TestWindowDriverName(t *testing.T) { d := initTestWindowDriver() assert.True(t, strings.HasPrefix(d.Name(), "Window")) d.SetName("NewName") assert.Equal(t, "NewName", d.Name()) } func TestWindowDriverStart(t *testing.T) { d := initTestWindowDriver() require.NoError(t, d.Start()) } func TestWindowDriverHalt(t *testing.T) { d := initTestWindowDriver() require.NoError(t, d.Halt()) } func TestWindowDriverShowImage(t *testing.T) { d := initTestWindowDriver() _, currentfile, _, _ := runtime.Caller(0) image := gocv.IMRead(path.Join(path.Dir(currentfile), "lena-256x256.jpg"), gocv.IMReadColor) d.Start() d.ShowImage(image) } ================================================ FILE: platforms/orangepi/orangepi5pro/LICENSE ================================================ Copyright (c) 2025 The Hybrid Group Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: platforms/orangepi/orangepi5pro/README.md ================================================ # OrangePi 5 Pro The OrangePi 5 Pro is a single board SoC computer based on the Rockchip RK3588S arm64 processor. It has built-in GPIO, I2C, PWM, SPI and MIPI DSI interfaces. For more info about the OrangePi 5 Pro, go to [http://www.orangepi.org/html/hardWare/computerAndMicrocontrollers/details/Orange-Pi-5-Pro.html](http://www.orangepi.org/html/hardWare/computerAndMicrocontrollers/details/Orange-Pi-5-Pro.html). ## How to Install Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) Tested OS: * [armbian](https://www.armbian.com/orange-pi-5-pro/): "Armbian_community_25.5.0-trunk.4_Orangepi5pro_bookworm_vendor_6.1.99_minimal" (1-wire not working) * [Debian server image](http://www.orangepi.org/html/hardWare/computerAndMicrocontrollers/service-and-support/Orange-Pi-5-Pro.html): "Orangepi5pro_1.0.4_debian_bookworm_server_linux6.1.43" ## Configuration steps for the OS ### System access and configuration basics Please follow the instructions of the OS provider. A ssh access is used in this guide. ```sh ssh @192.168.1.xxx ``` ### Enabling hardware drivers Not all drivers are enabled by default. You can have a look at the configuration file, to find out what is enabled at your system: ```sh cat /boot/armbianEnv.txt ``` ```sh sudo apt install armbian-config sudo armbian-config ``` ## How to Use The pin numbering used by your Gobot program should match the way your board is labeled right on the board itself. ```go r := orangepi5pro.NewAdaptor() led := gpio.NewLedDriver(r, "7") ``` ## How to Connect ### Compiling Compile your Gobot program on your workstation like this: ```sh GOARCH=arm64 GOOS=linux go build -o output/ examples/orangepi5pro_blink.go ``` Once you have compiled your code, you can upload your program and execute it on the board from your workstation using the `scp` and `ssh` commands like this: ```sh scp output/orangepi5pro_blink @192.168.1.xxx:~ ssh -t @192.168.1.xxx "./orangepi5pro_blink" ``` ## Troubleshooting ================================================ FILE: platforms/orangepi/orangepi5pro/adaptor.go ================================================ package orangepi5pro import ( "fmt" "sync" multierror "github.com/hashicorp/go-multierror" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/adaptors" "gobot.io/x/gobot/v2/system" ) const ( defaultI2cBusNumber = 4 defaultSpiBusNumber = 0 defaultSpiChipNumber = 0 defaultSpiMode = 0 defaultSpiBitsNumber = 8 defaultSpiMaxSpeed = 500000 ) // Adaptor represents a Gobot Adaptor for the OrangePi 5 Pro type Adaptor struct { *adaptors.AnalogPinsAdaptor *adaptors.DigitalPinsAdaptor *adaptors.PWMPinsAdaptor *adaptors.I2cBusAdaptor *adaptors.SpiBusAdaptor name string sys *system.Accesser // used for unit tests only mutex *sync.Mutex } // NewAdaptor creates a OrangePi 5 Pro Adaptor // // Optional parameters: // // adaptors.WithGpioSysfsAccess(): use legacy sysfs driver instead of default character device driver // adaptors.WithSpiGpioAccess(sclk, ncs, sdo, sdi): use GPIO's instead of /dev/spidev#.# // adaptors.WithGpiosActiveLow(pin's): invert the pin behavior // adaptors.WithGpiosPullUp/Down(pin's): sets the internal pull resistor // adaptors.WithGpiosOpenDrain/Source(pin's): sets the output behavior // adaptors.WithGpioEventOnFallingEdge/RaisingEdge/BothEdges(pin, handler): activate edge detection // // Further optional parameters for: // // AIO, see [adaptors.NewAnalogPinsAdaptor] // GPIO, see [adaptors.NewDigitalPinsAdaptor] // I2C, see [adaptors.NewI2cBusAdaptor] // PWM, see [adaptors.NewPWMPinsAdaptor] // SPI, see [adaptors.NewSpiBusAdaptor] func NewAdaptor(opts ...interface{}) *Adaptor { sys := system.NewAccesser() a := &Adaptor{ name: gobot.DefaultName("Zero"), sys: sys, mutex: &sync.Mutex{}, } var analogPinsOpts []adaptors.AnalogPinsOptionApplier var digitalPinsOpts []adaptors.DigitalPinsOptionApplier var pwmPinsOpts []adaptors.PwmPinsOptionApplier var i2cBusOpts []adaptors.I2CBusOptionApplier var spiBusOpts []adaptors.SpiBusOptionApplier for _, opt := range opts { switch o := opt.(type) { case adaptors.AnalogPinsOptionApplier: analogPinsOpts = append(analogPinsOpts, o) case adaptors.DigitalPinsOptionApplier: digitalPinsOpts = append(digitalPinsOpts, o) case adaptors.PwmPinsOptionApplier: pwmPinsOpts = append(pwmPinsOpts, o) case adaptors.I2CBusOptionApplier: i2cBusOpts = append(i2cBusOpts, o) case adaptors.SpiBusOptionApplier: spiBusOpts = append(spiBusOpts, o) default: panic(fmt.Sprintf("'%s' can not be applied on adaptor '%s'", opt, a.name)) } } analogPinTranslator := adaptors.NewAnalogPinTranslator(sys, analogPinDefinitions) digitalPinTranslator := adaptors.NewDigitalPinTranslator(sys, gpioPinDefinitions) pwmPinTranslator := adaptors.NewPWMPinTranslator(sys, pwmPinDefinitions) // Valid bus numbers are [1,4,5,8] which corresponds to /dev/i2c-1, /dev/i2c-4, /dev/i2c-5, /dev/i2c-8 // needs to be enabled by DT-overlay: i2c1-m4, i2c4-m3, i2c5-m2 or i2c5-m3, i2c8-m2 // We don't support i2c-0, i2c-2, i2c-3, i2c-6, i2c-7 (rk3x-i2c), i2c-9 (ddc), i2c-10 (fde50000.dp) i2cBusNumberValidator := adaptors.NewBusNumberValidator([]int{1, 3, 4}) // Valid bus numbers are [0,4] which corresponds to /dev/spidev0.x, /dev/spidev4.x // x is the chip number <255 spiBusNumberValidator := adaptors.NewBusNumberValidator([]int{0, 4}) a.AnalogPinsAdaptor = adaptors.NewAnalogPinsAdaptor(sys, analogPinTranslator.Translate, analogPinsOpts...) a.DigitalPinsAdaptor = adaptors.NewDigitalPinsAdaptor(sys, digitalPinTranslator.Translate, digitalPinsOpts...) a.PWMPinsAdaptor = adaptors.NewPWMPinsAdaptor(sys, pwmPinTranslator.Translate, pwmPinsOpts...) a.I2cBusAdaptor = adaptors.NewI2cBusAdaptor(sys, i2cBusNumberValidator.Validate, defaultI2cBusNumber, i2cBusOpts...) a.SpiBusAdaptor = adaptors.NewSpiBusAdaptor(sys, spiBusNumberValidator.Validate, defaultSpiBusNumber, defaultSpiChipNumber, defaultSpiMode, defaultSpiBitsNumber, defaultSpiMaxSpeed, a.DigitalPinsAdaptor, spiBusOpts...) return a } // Name returns the name of the Adaptor func (a *Adaptor) Name() string { return a.name } // SetName sets the name of the Adaptor func (a *Adaptor) SetName(n string) { a.name = n } // Connect create new connection to board and pins. func (a *Adaptor) Connect() error { a.mutex.Lock() defer a.mutex.Unlock() if err := a.SpiBusAdaptor.Connect(); err != nil { return err } if err := a.I2cBusAdaptor.Connect(); err != nil { return err } if err := a.AnalogPinsAdaptor.Connect(); err != nil { return err } if err := a.PWMPinsAdaptor.Connect(); err != nil { return err } return a.DigitalPinsAdaptor.Connect() } // Finalize closes connection to board, pins and bus func (a *Adaptor) Finalize() error { a.mutex.Lock() defer a.mutex.Unlock() err := a.DigitalPinsAdaptor.Finalize() if e := a.PWMPinsAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } if e := a.AnalogPinsAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } if e := a.I2cBusAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } if e := a.SpiBusAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } return err } ================================================ FILE: platforms/orangepi/orangepi5pro/adaptor_test.go ================================================ package orangepi5pro import ( "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/adaptors" "gobot.io/x/gobot/v2/system" ) const ( pwmDir = "/sys/devices/platform/febf0030.pwm/pwm/pwmchip2/" //nolint:gosec // false positive pwmExportPath = pwmDir + "export" pwmUnexportPath = pwmDir + "unexport" pwmPwmDir = pwmDir + "pwm0/" pwmEnablePath = pwmPwmDir + "enable" pwmPeriodPath = pwmPwmDir + "period" pwmDutyCyclePath = pwmPwmDir + "duty_cycle" pwmPolarityPath = pwmPwmDir + "polarity" pwmInvertedIdentifier = "inversed" ) var pwmMockPaths = []string{ pwmExportPath, pwmUnexportPath, pwmEnablePath, pwmPeriodPath, pwmDutyCyclePath, pwmPolarityPath, } // make sure that this Adaptor fulfills all the required interfaces var ( _ gobot.Adaptor = (*Adaptor)(nil) _ gobot.DigitalPinnerProvider = (*Adaptor)(nil) _ gobot.PWMPinnerProvider = (*Adaptor)(nil) _ gpio.DigitalReader = (*Adaptor)(nil) _ gpio.DigitalWriter = (*Adaptor)(nil) _ aio.AnalogReader = (*Adaptor)(nil) _ i2c.Connector = (*Adaptor)(nil) ) func preparePwmFs(fs *system.MockFilesystem) { fs.Files[pwmEnablePath].Contents = "0" fs.Files[pwmPeriodPath].Contents = "0" fs.Files[pwmDutyCyclePath].Contents = "0" fs.Files[pwmPolarityPath].Contents = pwmInvertedIdentifier } func initConnectedTestAdaptorWithMockedFilesystem(mockPaths []string) (*Adaptor, *system.MockFilesystem) { a := initConnectedTestAdaptor() fs := a.sys.UseMockFilesystem(mockPaths) return a, fs } func initConnectedTestAdaptor() *Adaptor { a := NewAdaptor() if err := a.Connect(); err != nil { panic(err) } return a } func TestNewAdaptor(t *testing.T) { // arrange & act a := NewAdaptor() // assert assert.IsType(t, &Adaptor{}, a) assert.True(t, strings.HasPrefix(a.Name(), "Zero")) assert.NotNil(t, a.sys) assert.NotNil(t, a.mutex) assert.NotNil(t, a.AnalogPinsAdaptor) assert.NotNil(t, a.DigitalPinsAdaptor) assert.NotNil(t, a.PWMPinsAdaptor) assert.NotNil(t, a.I2cBusAdaptor) assert.NotNil(t, a.SpiBusAdaptor) assert.True(t, a.sys.HasDigitalPinCdevAccess()) // act & assert a.SetName("NewName") assert.Equal(t, "NewName", a.Name()) } func TestNewAdaptorWithOption(t *testing.T) { // arrange & act a := NewAdaptor(adaptors.WithGpiosActiveLow("1"), adaptors.WithGpioSysfsAccess()) // assert require.NoError(t, a.Connect()) assert.True(t, a.sys.HasDigitalPinSysfsAccess()) } func TestDigitalIO(t *testing.T) { // some basic tests, further tests are done in "digitalpinsadaptor.go" // arrange a := initConnectedTestAdaptor() dpa := a.sys.UseMockDigitalPinAccess() require.True(t, a.sys.HasDigitalPinCdevAccess()) // act & assert write err := a.DigitalWrite("7", 1) require.NoError(t, err) assert.Equal(t, []int{1}, dpa.Written("gpiochip1", "15")) // arrange, act & assert read dpa.UseValues("gpiochip0", "14", []int{3}) i, err := a.DigitalRead("10") require.NoError(t, err) assert.Equal(t, 3, i) // act and assert unknown pin require.ErrorContains(t, a.DigitalWrite("99", 1), "'99' is not a valid id for a digital pin") // act and assert finalize require.NoError(t, a.Finalize()) assert.Equal(t, 0, dpa.Exported("gpiochip1", "15")) assert.Equal(t, 0, dpa.Exported("gpiochip0", "14")) } func TestDigitalIOSysfs(t *testing.T) { // some basic tests, further tests are done in "digitalpinsadaptor.go" // arrange a := NewAdaptor(adaptors.WithGpioSysfsAccess()) require.NoError(t, a.Connect()) dpa := a.sys.UseMockDigitalPinAccess() require.True(t, a.sys.HasDigitalPinSysfsAccess()) // act & assert write err := a.DigitalWrite("7", 1) require.NoError(t, err) assert.Equal(t, []int{1}, dpa.Written("", "47")) // arrange, act & assert read dpa.UseValues("", "14", []int{4}) i, err := a.DigitalRead("10") require.NoError(t, err) assert.Equal(t, 4, i) // act and assert unknown pin require.ErrorContains(t, a.DigitalWrite("99", 1), "'99' is not a valid id for a digital pin") // act and assert finalize require.NoError(t, a.Finalize()) assert.Equal(t, 0, dpa.Exported("", "47")) assert.Equal(t, 0, dpa.Exported("", "14")) } func TestAnalogRead(t *testing.T) { mockPaths := []string{ "/sys/class/thermal/thermal_zone0/temp", } a, fs := initConnectedTestAdaptorWithMockedFilesystem(mockPaths) fs.Files["/sys/class/thermal/thermal_zone0/temp"].Contents = "567\n" got, err := a.AnalogRead("soc_thermal") require.NoError(t, err) assert.Equal(t, 567, got) _, err = a.AnalogRead("thermal_zone10") require.ErrorContains(t, err, "'thermal_zone10' is not a valid id for an analog pin") fs.WithReadError = true _, err = a.AnalogRead("soc_thermal") require.ErrorContains(t, err, "read error") fs.WithReadError = false require.NoError(t, a.Finalize()) } func TestFinalizeErrorAfterGPIO(t *testing.T) { // arrange a := initConnectedTestAdaptor() dpa := a.sys.UseMockDigitalPinAccess() require.True(t, a.sys.HasDigitalPinCdevAccess()) require.NoError(t, a.DigitalWrite("7", 1)) dpa.UseUnexportError("gpiochip1", "15") // act err := a.Finalize() // assert require.ErrorContains(t, err, "unexport error") } func TestFinalizeErrorAfterPWM(t *testing.T) { // indirect test for PWM.Finalize() is called for the adaptor // arrange a, fs := initConnectedTestAdaptorWithMockedFilesystem(pwmMockPaths) preparePwmFs(fs) require.NoError(t, a.PwmWrite("33", 1)) fs.WithWriteError = true // act err := a.Finalize() // assert require.ErrorContains(t, err, "write error") } func TestSpiDefaultValues(t *testing.T) { a := NewAdaptor() assert.Equal(t, 0, a.SpiDefaultBusNumber()) assert.Equal(t, 0, a.SpiDefaultChipNumber()) assert.Equal(t, 0, a.SpiDefaultMode()) assert.Equal(t, 8, a.SpiDefaultBitCount()) assert.Equal(t, int64(500000), a.SpiDefaultMaxSpeed()) } func TestI2cDefaultBus(t *testing.T) { a := NewAdaptor() assert.Equal(t, 4, a.DefaultI2cBus()) } func TestI2cFinalizeWithErrors(t *testing.T) { // arrange a := initConnectedTestAdaptor() a.sys.UseMockSyscall() fs := a.sys.UseMockFilesystem([]string{"/dev/i2c-4"}) con, err := a.GetI2cConnection(0xff, 4) require.NoError(t, err) _, err = con.Write([]byte{0xbf}) require.NoError(t, err) fs.WithCloseError = true // act err = a.Finalize() // assert require.ErrorContains(t, err, "close error") } ================================================ FILE: platforms/orangepi/orangepi5pro/doc.go ================================================ /* Package orangepi5pro contains the Gobot adaptor for the OrangePi 5 Pro. For further information refer to the boards README: https://github.com/hybridgroup/gobot/blob/release/platforms/orangepi/orangepi5pro/README.md */ package orangepi5pro // import "gobot.io/x/gobot/v2/platforms/orangepi/orangepi5pro" ================================================ FILE: platforms/orangepi/orangepi5pro/pinmap.go ================================================ package orangepi5pro import "gobot.io/x/gobot/v2/platforms/adaptors" // notes for character device // sysfs: Chip*32 + (A=0, B=8, C=16, D=24) + Nr // tested with cdev on a OrangePi 5 Pro V1.2 board: armbian Linux, OK: works, ?: unknown, NOK: not working // IN: works only as input, PU: if used as input, external pullup resistor needed var gpioPinDefinitions = adaptors.DigitalPinDefinitions{ "8": {Sysfs: 13, Cdev: adaptors.CdevPin{Chip: 0, Line: 13}}, // GPIOO_B5_UART2_TX_MO - OK "10": {Sysfs: 14, Cdev: adaptors.CdevPin{Chip: 0, Line: 14}}, // GPIOO_B6_UART2_RX_MO - OK "18": {Sysfs: 32, Cdev: adaptors.CdevPin{Chip: 1, Line: 0}}, // GPIO1_A0_UART6_RX_M1 - OK "16": {Sysfs: 33, Cdev: adaptors.CdevPin{Chip: 1, Line: 1}}, // GPIO1_A1_UART6_TX_M1 - PU "27": {Sysfs: 34, Cdev: adaptors.CdevPin{Chip: 1, Line: 2}}, // GPIO1_A2_I2C4_SDA_M3_PWM0_M2_SPI4_CLK_M2 - PU "28": {Sysfs: 35, Cdev: adaptors.CdevPin{Chip: 1, Line: 3}}, // GPIO1_A3_I2C4_SCL_M3_PWM1_M2_SPI4_CSO_M2 - OK "29": {Sysfs: 36, Cdev: adaptors.CdevPin{Chip: 1, Line: 4}}, // GPIO1_A4 - OK "31": {Sysfs: 38, Cdev: adaptors.CdevPin{Chip: 1, Line: 6}}, // GPIO1_A6 - OK "12": {Sysfs: 39, Cdev: adaptors.CdevPin{Chip: 1, Line: 7}}, // GPIO1_A7_PWM3_IR_M3 - OK "22": {Sysfs: 40, Cdev: adaptors.CdevPin{Chip: 1, Line: 8}}, // GPIO1_B0 - OK "21": {Sysfs: 41, Cdev: adaptors.CdevPin{Chip: 1, Line: 9}}, // GPIO1_B1_SPI0_MISO_M2 - OK "19": {Sysfs: 42, Cdev: adaptors.CdevPin{Chip: 1, Line: 10}}, // GPIO1_B2_SPI0_MOSI_M2_UART4_RX_M2 - PU "23": {Sysfs: 43, Cdev: adaptors.CdevPin{Chip: 1, Line: 11}}, // GPIO1_B3_SPI0_CLK_M2_UART4_TX_M2 - OK "24": {Sysfs: 44, Cdev: adaptors.CdevPin{Chip: 1, Line: 12}}, // GPIO1_B4_SPI0_CSO_M2_UART7_RX_M2 - OK "26": {Sysfs: 45, Cdev: adaptors.CdevPin{Chip: 1, Line: 13}}, // GPIO1_B5_SPI0_CS1_M2_UART7_TX_M2 - OK "15": {Sysfs: 46, Cdev: adaptors.CdevPin{Chip: 1, Line: 14}}, // GPIO1_B6_I2C5_SCL_M3_UART1_TX_M1 - OK "7": {Sysfs: 47, Cdev: adaptors.CdevPin{Chip: 1, Line: 15}}, // GPIO1_B7_PWM13_M2_I2C5_SDA_M3_UART1_RX_M1 - OK "5": {Sysfs: 58, Cdev: adaptors.CdevPin{Chip: 1, Line: 26}}, // GPIO1_D2_I2C1_SCL_M4_UART4_TX_M0 - OK "3": {Sysfs: 59, Cdev: adaptors.CdevPin{Chip: 1, Line: 27}}, // GPIO1_D3_I2C1_SDA_M4_UART4_RX_M0 - OK "32": {Sysfs: 62, Cdev: adaptors.CdevPin{Chip: 1, Line: 30}}, // GPIO1_D6_PWM14_M2_I2C8_SCL_M2 - OK "33": {Sysfs: 63, Cdev: adaptors.CdevPin{Chip: 1, Line: 31}}, // GPIO1_D7_PWM15_IR_M3_I2C8_SDA_M2 - OK "36": {Sysfs: 131, Cdev: adaptors.CdevPin{Chip: 4, Line: 3}}, // GPIO4_A3_UART0_TX_M2 - PU "38": {Sysfs: 132, Cdev: adaptors.CdevPin{Chip: 4, Line: 4}}, // GPIO4_A4_UART0_RX_M2 - OK "40": {Sysfs: 133, Cdev: adaptors.CdevPin{Chip: 4, Line: 5}}, // GPIO4_A5_UART3_TX_M2 - OK "37": {Sysfs: 134, Cdev: adaptors.CdevPin{Chip: 4, Line: 6}}, // GPIO4_A6_I2C5_SCL_M2_UART3_RX_M2 - OK "35": {Sysfs: 135, Cdev: adaptors.CdevPin{Chip: 4, Line: 7}}, // GPIO4_A7_I2C5_SDA_M2 - OK "11": {Sysfs: 138, Cdev: adaptors.CdevPin{Chip: 4, Line: 10}}, // GPIO4_B2_CAN1_RX_M1_PWM14_R1 - OK "13": {Sysfs: 139, Cdev: adaptors.CdevPin{Chip: 4, Line: 11}}, // GPIO4_B3_CAN1_TX_M1_PWM15_IR_M1 - OK } var pwmPinDefinitions = adaptors.PWMPinDefinitions{ // needs to be enabled by DT-overlay pwm0-m2 (pwm0 = "/pwm@fd8b0000";) "27": {Dir: "/sys/devices/platform/fd8b0000.pwm/pwm/", DirRegexp: "pwmchip[0|1|2|3|4|5|6|7]$", Channel: 0}, // needs to be enabled by DT-overlay pwm1-m2 (pwm0 = "/pwm@fd8b0010";) "28": {Dir: "/sys/devices/platform/fd8b0010.pwm/pwm/", DirRegexp: "pwmchip[0|1|2|3|4|5|6|7]$", Channel: 0}, // needs to be enabled by DT-overlay pwm3-m3 (pwm0 = "/pwm@fd8b0030";) "12": {Dir: "/sys/devices/platform/fd8b0030.pwm/pwm/", DirRegexp: "pwmchip[0|1|2|3|4|5|6|7]$", Channel: 0}, // needs to be enabled by DT-overlay pwm13-m2 (pwm13 = "/pwm@febf0010";) "7": {Dir: "/sys/devices/platform/febf0010.pwm/pwm/", DirRegexp: "pwmchip[0|1|2|3|4|5|6|7]$", Channel: 0}, // needs to be enabled by DT-overlay pwm14-m1 (pwm14 = "/pwm@febf0020";) "11": {Dir: "/sys/devices/platform/febf0020.pwm/pwm/", DirRegexp: "pwmchip[0|1|2|3|4|5|6|7]$", Channel: 0}, // needs to be enabled by DT-overlay pwm14-m2 (pwm14 = "/pwm@febf0020";) "32": {Dir: "/sys/devices/platform/febf0020.pwm/pwm/", DirRegexp: "pwmchip[0|1|2|3|4|5|6|7]$", Channel: 0}, // needs to be enabled by DT-overlay pwm15-m1 (pwm15 = "/pwm@febf0030";) "13": {Dir: "/sys/devices/platform/febf0030.pwm/pwm/", DirRegexp: "pwmchip[0|1|2|3|4|5|6|7]$", Channel: 0}, // needs to be enabled by DT-overlay pwm15-m3 (pwm15 = "/pwm@febf0030";) "33": {Dir: "/sys/devices/platform/febf0030.pwm/pwm/", DirRegexp: "pwmchip[0|1|2|3|4|5|6|7]$", Channel: 0}, } var analogPinDefinitions = adaptors.AnalogPinDefinitions{ // +/-273.200 °C need >=7 characters to read: +/-273200 millidegree Celsius // names equals /sys/class/thermal/thermal_zone*/hwmon*/name "soc_thermal": {Path: "/sys/class/thermal/thermal_zone0/temp", W: false, ReadBufLen: 7}, "bigcore0_thermal": {Path: "/sys/class/thermal/thermal_zone1/temp", W: false, ReadBufLen: 7}, "bigcore1_thermal": {Path: "/sys/class/thermal/thermal_zone2/temp", W: false, ReadBufLen: 7}, "littlecore_thermal": {Path: "/sys/class/thermal/thermal_zone3/temp", W: false, ReadBufLen: 7}, "center_thermal": {Path: "/sys/class/thermal/thermal_zone4/temp", W: false, ReadBufLen: 7}, "gpu_thermal": {Path: "/sys/class/thermal/thermal_zone5/temp", W: false, ReadBufLen: 7}, "npu_thermal": {Path: "/sys/class/thermal/thermal_zone6/temp", W: false, ReadBufLen: 7}, } ================================================ FILE: platforms/parrot/LICENSE ================================================ Copyright (c) 2014-2018 The Hybrid Group Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: platforms/parrot/README.md ================================================ # Parrot This package contains the Gobot adaptors and drivers for the various Parrot (https://www.parrot.com) drones. This package currently supports the following drones: - Parrot ARDrone 2.0 - Parrot Bebop/Bebop 2 - Parrot Minidrone ================================================ FILE: platforms/parrot/ardrone/LICENSE ================================================ Copyright (c) 2014-2018 The Hybrid Group Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: platforms/parrot/ardrone/README.md ================================================ # Ardrone The ARDrone from Parrot is an inexpensive quadcopter that is controlled using WiFi. It includes a built-in front-facing HD video camera, as well as a second lower resolution bottom facing video camera. For more info about the ARDrone platform click [here](http://ardrone2.parrot.com/). ## How to Install Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) ## How to Use ```go package main import ( "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/parrot/ardrone" ) func main() { ardroneAdaptor := ardrone.NewAdaptor("Drone") drone := ardrone.NewDriver(ardroneAdaptor, "Drone") work := func() { drone.On(drone.Event("flying"), func(data interface{}) { gobot.After(3*time.Second, func() { drone.Land() }) }) drone.TakeOff() } robot := gobot.NewRobot("drone", []gobot.Connection{ardroneAdaptor}, []gobot.Device{drone}, work, ) if err := robot.Start(); err != nil { panic(err) } } ``` ## How to Connect The ARDrone is a WiFi device, so there is no additional work to establish a connection to a single drone. However, in order to connect to multiple drones, you need to perform some configuration steps on each drone via SSH. ================================================ FILE: platforms/parrot/ardrone/ardrone_adaptor.go ================================================ package ardrone import ( client "github.com/hybridgroup/go-ardrone/client" "gobot.io/x/gobot/v2" ) // drone defines expected drone behaviour type drone interface { Takeoff() bool Land() Up(n float64) Down(n float64) Left(n float64) Right(n float64) Forward(n float64) Backward(n float64) Clockwise(n float64) Counterclockwise(n float64) Hover() } // Adaptor is gobot.Adaptor representation for the Ardrone type Adaptor struct { name string drone drone config client.Config connect func(*Adaptor) (drone, error) } // NewAdaptor returns a new ardrone.Adaptor and optionally accepts: // // string: The ardrones IP Address func NewAdaptor(v ...string) *Adaptor { a := &Adaptor{ name: gobot.DefaultName("ARDrone"), connect: func(a *Adaptor) (drone, error) { return client.Connect(a.config) }, } a.config = client.DefaultConfig() if len(v) > 0 { a.config.Ip = v[0] } return a } // Name returns the Adaptor Name func (a *Adaptor) Name() string { return a.name } // SetName sets the Adaptor Name func (a *Adaptor) SetName(n string) { a.name = n } // Connect establishes a connection to the ardrone func (a *Adaptor) Connect() error { d, err := a.connect(a) if err != nil { return err } a.drone = d return nil } // Finalize terminates the connection to the ardrone func (a *Adaptor) Finalize() error { return nil } ================================================ FILE: platforms/parrot/ardrone/ardrone_adaptor_test.go ================================================ package ardrone import ( "errors" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) var _ gobot.Adaptor = (*Adaptor)(nil) func initTestArdroneAdaptor() *Adaptor { a := NewAdaptor() a.connect = func(a *Adaptor) (drone, error) { return &testDrone{}, nil } return a } func TestArdroneAdaptor(t *testing.T) { a := NewAdaptor() assert.Equal(t, "192.168.1.1", a.config.Ip) a = NewAdaptor("192.168.100.100") assert.Equal(t, "192.168.100.100", a.config.Ip) } func TestArdroneAdaptorConnect(t *testing.T) { a := initTestArdroneAdaptor() require.NoError(t, a.Connect()) a.connect = func(a *Adaptor) (drone, error) { return nil, errors.New("connection error") } require.ErrorContains(t, a.Connect(), "connection error") } func TestArdroneAdaptorName(t *testing.T) { a := initTestArdroneAdaptor() assert.True(t, strings.HasPrefix(a.Name(), "ARDrone")) a.SetName("NewName") assert.Equal(t, "NewName", a.Name()) } func TestArdroneAdaptorFinalize(t *testing.T) { a := initTestArdroneAdaptor() require.NoError(t, a.Finalize()) } ================================================ FILE: platforms/parrot/ardrone/ardrone_driver.go ================================================ package ardrone import ( "gobot.io/x/gobot/v2" ) const ( // Flying event Flying = "flying" ) // Driver is gobot.Driver representation for the Ardrone type Driver struct { gobot.Eventer name string connection gobot.Connection } // NewDriver creates an Driver for the ARDrone. // // It add the following events: // // 'flying' - Sent when the device has taken off. func NewDriver(connection *Adaptor) *Driver { d := &Driver{ name: gobot.DefaultName("ARDrone"), connection: connection, Eventer: gobot.NewEventer(), } d.AddEvent(Flying) return d } // Name returns the Driver Name func (a *Driver) Name() string { return a.name } // SetName sets the Driver Name func (a *Driver) SetName(n string) { a.name = n } // Connection returns the Driver Connection func (a *Driver) Connection() gobot.Connection { return a.connection } // adaptor returns ardrone adaptor func (a *Driver) adaptor() *Adaptor { //nolint:forcetypeassert // ok here return a.Connection().(*Adaptor) } // Start starts the Driver func (a *Driver) Start() error { return nil } // Halt halts the Driver func (a *Driver) Halt() error { return nil } // TakeOff makes the drone start flying, and publishes `flying` event func (a *Driver) TakeOff() { a.Publish(a.Event("flying"), a.adaptor().drone.Takeoff()) } // Land causes the drone to land func (a *Driver) Land() { a.adaptor().drone.Land() } // Up makes the drone gain altitude. // speed can be a value from `0.0` to `1.0`. func (a *Driver) Up(speed float64) { a.adaptor().drone.Up(speed) } // Down makes the drone reduce altitude. // speed can be a value from `0.0` to `1.0`. func (a *Driver) Down(speed float64) { a.adaptor().drone.Down(speed) } // Left causes the drone to bank to the left, controls the roll, which is // a horizontal movement using the camera as a reference point. // speed can be a value from `0.0` to `1.0`. func (a *Driver) Left(speed float64) { a.adaptor().drone.Left(speed) } // Right causes the drone to bank to the right, controls the roll, which is // a horizontal movement using the camera as a reference point. // speed can be a value from `0.0` to `1.0`. func (a *Driver) Right(speed float64) { a.adaptor().drone.Right(speed) } // Forward causes the drone go forward, controls the pitch. // speed can be a value from `0.0` to `1.0`. func (a *Driver) Forward(speed float64) { a.adaptor().drone.Forward(speed) } // Backward causes the drone go backward, controls the pitch. // speed can be a value from `0.0` to `1.0`. func (a *Driver) Backward(speed float64) { a.adaptor().drone.Backward(speed) } // Clockwise causes the drone to spin in clockwise direction // speed can be a value from `0.0` to `1.0`. func (a *Driver) Clockwise(speed float64) { a.adaptor().drone.Clockwise(speed) } // CounterClockwise the drone to spin in counter clockwise direction // speed can be a value from `0.0` to `1.0`. func (a *Driver) CounterClockwise(speed float64) { a.adaptor().drone.Counterclockwise(speed) } // Hover makes the drone to hover in place. func (a *Driver) Hover() { a.adaptor().drone.Hover() } ================================================ FILE: platforms/parrot/ardrone/ardrone_driver_test.go ================================================ package ardrone import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) var _ gobot.Driver = (*Driver)(nil) func initTestArdroneDriver() *Driver { a := NewAdaptor() a.connect = func(a *Adaptor) (drone, error) { return &testDrone{}, nil } d := NewDriver(a) d.SetName("mydrone") _ = a.Connect() return d } func TestArdroneDriver(t *testing.T) { d := initTestArdroneDriver() assert.Equal(t, "mydrone", d.Name()) } func TestArdroneDriverName(t *testing.T) { d := initTestArdroneDriver() assert.Equal(t, "mydrone", d.Name()) d.SetName("NewName") assert.Equal(t, "NewName", d.Name()) } func TestArdroneDriverStart(t *testing.T) { d := initTestArdroneDriver() require.NoError(t, d.Start()) } func TestArdroneDriverHalt(t *testing.T) { d := initTestArdroneDriver() require.NoError(t, d.Halt()) } func TestArdroneDriverTakeOff(t *testing.T) { d := initTestArdroneDriver() d.TakeOff() } func TestArdroneDriverand(t *testing.T) { d := initTestArdroneDriver() d.Land() } func TestArdroneDriverUp(t *testing.T) { d := initTestArdroneDriver() d.Up(1) } func TestArdroneDriverDown(t *testing.T) { d := initTestArdroneDriver() d.Down(1) } func TestArdroneDriverLeft(t *testing.T) { d := initTestArdroneDriver() d.Left(1) } func TestArdroneDriverRight(t *testing.T) { d := initTestArdroneDriver() d.Right(1) } func TestArdroneDriverForward(t *testing.T) { d := initTestArdroneDriver() d.Forward(1) } func TestArdroneDriverackward(t *testing.T) { d := initTestArdroneDriver() d.Backward(1) } func TestArdroneDriverClockwise(t *testing.T) { d := initTestArdroneDriver() d.Clockwise(1) } func TestArdroneDriverCounterClockwise(t *testing.T) { d := initTestArdroneDriver() d.CounterClockwise(1) } func TestArdroneDriverHover(t *testing.T) { d := initTestArdroneDriver() d.Hover() } ================================================ FILE: platforms/parrot/ardrone/doc.go ================================================ /* Package ardrone provides the Gobot adaptor and driver for the Parrot Ardrone. Installing: Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) Example: package main import ( "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/parrot/ardrone" ) func main() { ardroneAdaptor := ardrone.NewAdaptor() drone := ardrone.NewDriver(ardroneAdaptor) work := func() { drone.TakeOff() drone.On(drone.Event("flying"), func(data interface{}) { gobot.After(3*time.Second, func() { drone.Land() }) }) } robot := gobot.NewRobot("drone", []gobot.Connection{ardroneAdaptor}, []gobot.Device{drone}, work, ) if err := robot.Start(); err != nil { panic(err) } } For more information refer to the ardrone README: https://github.com/hybridgroup/gobot/blob/release/platforms/parrot/ardrone/README.md */ package ardrone // import "gobot.io/x/gobot/v2/platforms/parrot/ardrone" ================================================ FILE: platforms/parrot/ardrone/pitch.go ================================================ package ardrone import "math" // ValidatePitch helps validate pitch values such as those created by // a joystick to values between 0-1.0 that are required as // params to Parrot ARDrone PCMDs func ValidatePitch(data float64, offset float64) float64 { value := math.Abs(data) / offset if value >= 0.1 { if value <= 1.0 { return float64(int(value*100)) / 100 } return 1.0 } return 0.0 } ================================================ FILE: platforms/parrot/ardrone/pitch_test.go ================================================ package ardrone import ( "testing" "github.com/stretchr/testify/assert" ) func TestArdroneValidatePitchWhenEqualOffset(t *testing.T) { assert.InDelta(t, 1.0, ValidatePitch(32767.0, 32767.0), 0.0) } func TestArdroneValidatePitchWhenTiny(t *testing.T) { assert.InDelta(t, 0.0, ValidatePitch(1.1, 32767.0), 0.0) } func TestArdroneValidatePitchWhenCentered(t *testing.T) { assert.InDelta(t, 0.5, ValidatePitch(16383.5, 32767.0), 0.0) } ================================================ FILE: platforms/parrot/ardrone/test_helper.go ================================================ package ardrone type testDrone struct{} func (t testDrone) Takeoff() bool { return true } func (t testDrone) Land() {} func (t testDrone) Up(a float64) {} func (t testDrone) Down(a float64) {} func (t testDrone) Left(a float64) {} func (t testDrone) Right(a float64) {} func (t testDrone) Forward(a float64) {} func (t testDrone) Backward(a float64) {} func (t testDrone) Clockwise(a float64) {} func (t testDrone) Counterclockwise(a float64) {} func (t testDrone) Hover() {} ================================================ FILE: platforms/parrot/bebop/LICENSE ================================================ Copyright (c) 2014-2018 The Hybrid Group Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: platforms/parrot/bebop/README.md ================================================ # Bebop The Parrot Bebop and Parrot Bebop 2 are inexpensive quadcopters that can be controlled using their built-in API commands via a WiFi connection. They include a built-in front-facing HD video camera, as well as a second lower resolution bottom-facing video camera. ## How to Install Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) ## How to Use ```go package main import ( "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/parrot/bebop" ) func main() { bebopAdaptor := bebop.NewAdaptor() drone := bebop.NewDriver(bebopAdaptor) work := func() { drone.HullProtection(true) drone.TakeOff() gobot.On(drone.Event("flying"), func(data interface{}) { gobot.After(3*time.Second, func() { drone.Land() }) }) } robot := gobot.NewRobot("drone", []gobot.Connection{bebopAdaptor}, []gobot.Device{drone}, work, ) if err := robot.Start(); err != nil { panic(err) } } ``` ## How to Connect By default, the Parrot Bebop is a WiFi access point, so there is no additional work to establish a connection to a single drone, you just connect to it. Once connected, if you want to stream drone video you can either: - Use the RTP protocol with an external player such as mplayer or VLC. - Grab the video frames from the drone's data frames, and work with them directly. ================================================ FILE: platforms/parrot/bebop/bebop_adaptor.go ================================================ package bebop import ( "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/parrot/bebop/client" ) // drone defines expected drone behaviour type drone interface { TakeOff() error Land() error Up(n int) error Down(n int) error Left(n int) error Right(n int) error Forward(n int) error Backward(n int) error Clockwise(n int) error CounterClockwise(n int) error Stop() error Connect() error Video() chan []byte StartRecording() error StopRecording() error HullProtection(protect bool) error Outdoor(outdoor bool) error VideoEnable(enable bool) error VideoStreamMode(mode int8) error } // Adaptor is gobot.Adaptor representation for the Bebop type Adaptor struct { name string drone drone connect func(*Adaptor) error } // NewAdaptor returns a new BebopAdaptor func NewAdaptor() *Adaptor { return &Adaptor{ name: gobot.DefaultName("Bebop"), drone: client.New(), connect: func(a *Adaptor) error { return a.drone.Connect() }, } } // Name returns the Bebop adaptors Name func (a *Adaptor) Name() string { return a.name } // SetName sets the Bebop adaptors Name func (a *Adaptor) SetName(n string) { a.name = n } // Connect establishes a connection to the ardrone func (a *Adaptor) Connect() error { return a.connect(a) } // Finalize terminates the connection to the ardrone func (a *Adaptor) Finalize() error { return nil } ================================================ FILE: platforms/parrot/bebop/bebop_adaptor_test.go ================================================ package bebop import ( "errors" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) var _ gobot.Adaptor = (*Adaptor)(nil) func initTestBebopAdaptor() *Adaptor { a := NewAdaptor() a.connect = func(b *Adaptor) error { b.drone = &testDrone{} return nil } return a } func TestBebopAdaptorName(t *testing.T) { a := NewAdaptor() assert.True(t, strings.HasPrefix(a.Name(), "Bebop")) a.SetName("NewName") assert.Equal(t, "NewName", a.Name()) } func TestBebopAdaptorConnect(t *testing.T) { a := initTestBebopAdaptor() require.NoError(t, a.Connect()) a.connect = func(a *Adaptor) error { return errors.New("connection error") } require.ErrorContains(t, a.Connect(), "connection error") } func TestBebopAdaptorFinalize(t *testing.T) { a := initTestBebopAdaptor() _ = a.Connect() require.NoError(t, a.Finalize()) } ================================================ FILE: platforms/parrot/bebop/bebop_driver.go ================================================ package bebop import ( "gobot.io/x/gobot/v2" ) const ( // Flying event Flying = "flying" ) // Driver is gobot.Driver representation for the Bebop type Driver struct { gobot.Eventer name string connection gobot.Connection } // NewDriver creates an Bebop Driver. func NewDriver(connection *Adaptor) *Driver { d := &Driver{ name: gobot.DefaultName("Bebop"), connection: connection, Eventer: gobot.NewEventer(), } d.AddEvent(Flying) return d } // Name returns the Bebop Drivers Name func (a *Driver) Name() string { return a.name } // SetName sets the Bebop Drivers Name func (a *Driver) SetName(n string) { a.name = n } // Connection returns the Bebop Drivers Connection func (a *Driver) Connection() gobot.Connection { return a.connection } // adaptor returns ardrone adaptor func (a *Driver) adaptor() *Adaptor { //nolint:forcetypeassert // ok here return a.Connection().(*Adaptor) } // Start starts the Bebop Driver func (a *Driver) Start() error { return nil } // Halt halts the Bebop Driver func (a *Driver) Halt() error { return nil } // TakeOff makes the drone start flying func (a *Driver) TakeOff() { a.Publish(a.Event("flying"), a.adaptor().drone.TakeOff()) } // Land causes the drone to land func (a *Driver) Land() error { return a.adaptor().drone.Land() } // Up makes the drone gain altitude. // speed can be a value from `0` to `100`. func (a *Driver) Up(speed int) error { return a.adaptor().drone.Up(speed) } // Down makes the drone reduce altitude. // speed can be a value from `0` to `100`. func (a *Driver) Down(speed int) error { return a.adaptor().drone.Down(speed) } // Left causes the drone to bank to the left, controls the roll, which is // a horizontal movement using the camera as a reference point. // speed can be a value from `0` to `100`. func (a *Driver) Left(speed int) error { return a.adaptor().drone.Left(speed) } // Right causes the drone to bank to the right, controls the roll, which is // a horizontal movement using the camera as a reference point. // speed can be a value from `0` to `100`. func (a *Driver) Right(speed int) error { return a.adaptor().drone.Right(speed) } // Forward causes the drone go forward, controls the pitch. // speed can be a value from `0` to `100`. func (a *Driver) Forward(speed int) error { return a.adaptor().drone.Forward(speed) } // Backward causes the drone go forward, controls the pitch. // speed can be a value from `0` to `100`. func (a *Driver) Backward(speed int) error { return a.adaptor().drone.Backward(speed) } // Clockwise causes the drone to spin in clockwise direction // speed can be a value from `0` to `100`. func (a *Driver) Clockwise(speed int) error { return a.adaptor().drone.Clockwise(speed) } // CounterClockwise the drone to spin in counter clockwise direction // speed can be a value from `0` to `100`. func (a *Driver) CounterClockwise(speed int) error { return a.adaptor().drone.CounterClockwise(speed) } // Stop makes the drone to hover in place. func (a *Driver) Stop() error { return a.adaptor().drone.Stop() } // Video returns a channel which raw video frames will be broadcast on func (a *Driver) Video() chan []byte { return a.adaptor().drone.Video() } // StartRecording starts the recording video to the drones interal storage func (a *Driver) StartRecording() error { return a.adaptor().drone.StartRecording() } // StopRecording stops a previously started recording func (a *Driver) StopRecording() error { return a.adaptor().drone.StopRecording() } // HullProtection tells the drone if the hull/prop protectors are attached. This is needed to adjust // flight characteristics of the Bebop. func (a *Driver) HullProtection(protect bool) error { return a.adaptor().drone.HullProtection(protect) } // Outdoor tells the drone if flying Outdoor or not. This is needed to adjust flight characteristics of the Bebop. func (a *Driver) Outdoor(outdoor bool) error { return a.adaptor().drone.Outdoor(outdoor) } // VideoEnable tells the drone to start/stop streaming video func (a *Driver) VideoEnable(enable bool) error { return a.adaptor().drone.VideoEnable(enable) } // VideoStreamMode tells the drone what mode to use for streaming video func (a *Driver) VideoStreamMode(mode int8) error { return a.adaptor().drone.VideoStreamMode(mode) } ================================================ FILE: platforms/parrot/bebop/bebop_driver_test.go ================================================ package bebop import ( "strings" "testing" "github.com/stretchr/testify/assert" "gobot.io/x/gobot/v2" ) var _ gobot.Driver = (*Driver)(nil) func TestBebopDriverName(t *testing.T) { a := initTestBebopAdaptor() d := NewDriver(a) assert.True(t, strings.HasPrefix(d.Name(), "Bebop")) d.SetName("NewName") assert.Equal(t, "NewName", d.Name()) } ================================================ FILE: platforms/parrot/bebop/client/client.go ================================================ package client import ( "bytes" "encoding/binary" "fmt" "net" "time" ) func validatePitch(val int) int { if val > 100 { return 100 } else if val < 0 { return 0 } return val } type tmpFrame struct { arstreamACK ARStreamACK fragments map[int][]byte frame []byte waitForIframe bool frameFlags int } type ARStreamACK struct { FrameNumber int HighPacketsAck uint64 LowPacketsAck uint64 } type ARStreamFrame struct { FrameNumber int FrameFlags int FragmentNumber int FragmentsPerFrame int Frame []byte } func NewARStreamFrame(buf []byte) ARStreamFrame { // // ARSTREAM_NetworkHeaders_DataHeader_t; // // uint16_t frameNumber; // uint8_t frameFlags; // Infos on the current frame // uint8_t fragmentNumber; // Index of the current fragment in current frame // uint8_t fragmentsPerFrame; // Number of fragments in current frame // // * frameFlags structure : // * x x x x x x x x // * | | | | | | | \-> FLUSH FRAME // * | | | | | | \-> UNUSED // * | | | | | \-> UNUSED // * | | | | \-> UNUSED // * | | | \-> UNUSED // * | | \-> UNUSED // * | \-> UNUSED // * \-> UNUSED // * // frame := ARStreamFrame{ FrameFlags: int(buf[2]), FragmentNumber: int(buf[3]), FragmentsPerFrame: int(buf[4]), } var number uint16 if err := binary.Read(bytes.NewReader(buf[0:2]), binary.LittleEndian, &number); err != nil { panic(err) } frame.FrameNumber = int(number) frame.Frame = buf[5:] return frame } type NetworkFrame struct { Type int Seq int Id int Size int Data []byte } func NewNetworkFrame(buf []byte) NetworkFrame { frame := NetworkFrame{ Type: int(buf[0]), Id: int(buf[1]), Seq: int(buf[2]), Data: []byte{}, } var size uint32 if err := binary.Read(bytes.NewReader(buf[3:7]), binary.LittleEndian, &size); err != nil { panic(err) } frame.Size = int(size) frame.Data = buf[7:frame.Size] return frame } type Pcmd struct { Flag int Roll int Pitch int Yaw int Gaz int Psi float32 } type Bebop struct { IP string NavData map[string]string Pcmd Pcmd tmpFrame tmpFrame C2dPort int D2cPort int RTPStreamPort int RTPControlPort int DiscoveryPort int c2dClient *net.UDPConn d2cClient *net.UDPConn discoveryClient *net.TCPConn nwFrameGenerator *nwFrameGenerator video chan []byte writeChan chan []byte } func New() *Bebop { return &Bebop{ IP: "192.168.42.1", NavData: make(map[string]string), C2dPort: 54321, D2cPort: 43210, RTPStreamPort: 55004, RTPControlPort: 55005, DiscoveryPort: 44444, nwFrameGenerator: newNetworkFrameGenerator(), Pcmd: Pcmd{ Flag: 0, Roll: 0, Pitch: 0, Yaw: 0, Gaz: 0, Psi: 0, }, tmpFrame: tmpFrame{}, video: make(chan []byte), writeChan: make(chan []byte), } } func (b *Bebop) write(buf []byte) error { b.writeChan <- buf return nil } func (b *Bebop) Discover() error { addr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%d", b.IP, b.DiscoveryPort)) if err != nil { return err } b.discoveryClient, err = net.DialTCP("tcp", nil, addr) if err != nil { return err } if _, err := fmt.Fprintf(b.discoveryClient, `{ "controller_type": "computer", "controller_name": "go-bebop", "d2c_port": "%d", "arstream2_client_stream_port": "%d", "arstream2_client_control_port": "%d", }`, b.D2cPort, b.RTPStreamPort, b.RTPControlPort); err != nil { return err } data := make([]byte, 10240) _, err = b.discoveryClient.Read(data) if err != nil { return err } return b.discoveryClient.Close() } func (b *Bebop) Connect() error { err := b.Discover() if err != nil { return err } c2daddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", b.IP, b.C2dPort)) if err != nil { return err } b.c2dClient, err = net.DialUDP("udp", nil, c2daddr) if err != nil { return err } d2caddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf(":%d", b.D2cPort)) if err != nil { return err } b.d2cClient, err = net.ListenUDP("udp", d2caddr) if err != nil { return err } go func() { for { _, err := b.c2dClient.Write(<-b.writeChan) if err != nil { fmt.Println(err) } } }() go func() { for { data := make([]byte, 40960) i, _, err := b.d2cClient.ReadFromUDP(data) if err != nil { fmt.Println("d2cClient error:", err) } b.packetReceiver(data[0:i]) } }() // send pcmd values at 40hz go func() { // wait a little bit so that there is enough time to get some ACKs time.Sleep(500 * time.Millisecond) for { if err := b.write(b.generatePcmd().Bytes()); err != nil { fmt.Println("pcmd c2dClient.Write", err) } time.Sleep(25 * time.Millisecond) } }() if err := b.GenerateAllStates(); err != nil { return err } if err := b.FlatTrim(); err != nil { return err } return nil } func (b *Bebop) FlatTrim() error { // // ARCOMMANDS_Generator_GenerateARDrone3PilotingFlatTrim // cmd := &bytes.Buffer{} cmd.WriteByte(ARCOMMANDS_ID_PROJECT_ARDRONE3) cmd.WriteByte(ARCOMMANDS_ID_ARDRONE3_CLASS_PILOTING) tmp := &bytes.Buffer{} if err := binary.Write(tmp, binary.LittleEndian, uint16(ARCOMMANDS_ID_ARDRONE3_PILOTING_CMD_FLATTRIM)); err != nil { return err } cmd.Write(tmp.Bytes()) return b.write(b.nwFrameGenerator.generate(cmd, ARNETWORKAL_FRAME_TYPE_DATA, BD_NET_CD_NONACK_ID).Bytes()) } func (b *Bebop) GenerateAllStates() error { // // ARCOMMANDS_Generator_GenerateCommonCommonAllStates // cmd := &bytes.Buffer{} cmd.WriteByte(ARCOMMANDS_ID_PROJECT_COMMON) cmd.WriteByte(ARCOMMANDS_ID_COMMON_CLASS_COMMON) tmp := &bytes.Buffer{} if err := binary.Write(tmp, binary.LittleEndian, uint16(ARCOMMANDS_ID_COMMON_COMMON_CMD_ALLSTATES)); err != nil { return err } cmd.Write(tmp.Bytes()) return b.write(b.nwFrameGenerator.generate(cmd, ARNETWORKAL_FRAME_TYPE_DATA, BD_NET_CD_NONACK_ID).Bytes()) } func (b *Bebop) TakeOff() error { // // ARCOMMANDS_Generator_GenerateARDrone3PilotingTakeOff // cmd := &bytes.Buffer{} cmd.WriteByte(ARCOMMANDS_ID_PROJECT_ARDRONE3) cmd.WriteByte(ARCOMMANDS_ID_ARDRONE3_CLASS_PILOTING) tmp := &bytes.Buffer{} if err := binary.Write(tmp, binary.LittleEndian, uint16(ARCOMMANDS_ID_ARDRONE3_PILOTING_CMD_TAKEOFF)); err != nil { return err } cmd.Write(tmp.Bytes()) return b.write(b.nwFrameGenerator.generate(cmd, ARNETWORKAL_FRAME_TYPE_DATA, BD_NET_CD_NONACK_ID).Bytes()) } func (b *Bebop) Land() error { // // ARCOMMANDS_Generator_GenerateARDrone3PilotingLanding // cmd := &bytes.Buffer{} cmd.WriteByte(ARCOMMANDS_ID_PROJECT_ARDRONE3) cmd.WriteByte(ARCOMMANDS_ID_ARDRONE3_CLASS_PILOTING) tmp := &bytes.Buffer{} if err := binary.Write(tmp, binary.LittleEndian, uint16(ARCOMMANDS_ID_ARDRONE3_PILOTING_CMD_LANDING)); err != nil { return err } cmd.Write(tmp.Bytes()) return b.write(b.nwFrameGenerator.generate(cmd, ARNETWORKAL_FRAME_TYPE_DATA, BD_NET_CD_NONACK_ID).Bytes()) } func (b *Bebop) Up(val int) error { b.Pcmd.Flag = 1 b.Pcmd.Gaz = validatePitch(val) return nil } func (b *Bebop) Down(val int) error { b.Pcmd.Flag = 1 b.Pcmd.Gaz = validatePitch(val) * -1 return nil } func (b *Bebop) Forward(val int) error { b.Pcmd.Flag = 1 b.Pcmd.Pitch = validatePitch(val) return nil } func (b *Bebop) Backward(val int) error { b.Pcmd.Flag = 1 b.Pcmd.Pitch = validatePitch(val) * -1 return nil } func (b *Bebop) Right(val int) error { b.Pcmd.Flag = 1 b.Pcmd.Roll = validatePitch(val) return nil } func (b *Bebop) Left(val int) error { b.Pcmd.Flag = 1 b.Pcmd.Roll = validatePitch(val) * -1 return nil } func (b *Bebop) Clockwise(val int) error { b.Pcmd.Flag = 1 b.Pcmd.Yaw = validatePitch(val) return nil } func (b *Bebop) CounterClockwise(val int) error { b.Pcmd.Flag = 1 b.Pcmd.Yaw = validatePitch(val) * -1 return nil } func (b *Bebop) Stop() error { b.Pcmd = Pcmd{ Flag: 0, Roll: 0, Pitch: 0, Yaw: 0, Gaz: 0, Psi: 0, } return nil } func (b *Bebop) generatePcmd() *bytes.Buffer { // // ARCOMMANDS_Generator_GenerateARDrone3PilotingPCMD // // uint8 - flag Boolean flag to activate roll/pitch movement // int8 - roll Roll consign for the drone [-100;100] // int8 - pitch Pitch consign for the drone [-100;100] // int8 - yaw Yaw consign for the drone [-100;100] // int8 - gaz Gaz consign for the drone [-100;100] // float - psi [NOT USED] - Magnetic north heading of the // controlling device (deg) [-180;180] // cmd := &bytes.Buffer{} cmd.WriteByte(ARCOMMANDS_ID_PROJECT_ARDRONE3) cmd.WriteByte(ARCOMMANDS_ID_ARDRONE3_CLASS_PILOTING) tmp := &bytes.Buffer{} if err := binary.Write(tmp, binary.LittleEndian, uint16(ARCOMMANDS_ID_ARDRONE3_PILOTING_CMD_PCMD)); err != nil { panic(err) } cmd.Write(tmp.Bytes()) tmp = &bytes.Buffer{} //nolint:gosec // TODO: fix later if err := binary.Write(tmp, binary.LittleEndian, uint8(b.Pcmd.Flag)); err != nil { panic(err) } cmd.Write(tmp.Bytes()) tmp = &bytes.Buffer{} //nolint:gosec // TODO: fix later if err := binary.Write(tmp, binary.LittleEndian, int8(b.Pcmd.Roll)); err != nil { panic(err) } cmd.Write(tmp.Bytes()) tmp = &bytes.Buffer{} //nolint:gosec // TODO: fix later if err := binary.Write(tmp, binary.LittleEndian, int8(b.Pcmd.Pitch)); err != nil { panic(err) } cmd.Write(tmp.Bytes()) tmp = &bytes.Buffer{} //nolint:gosec // TODO: fix later if err := binary.Write(tmp, binary.LittleEndian, int8(b.Pcmd.Yaw)); err != nil { panic(err) } cmd.Write(tmp.Bytes()) tmp = &bytes.Buffer{} //nolint:gosec // TODO: fix later if err := binary.Write(tmp, binary.LittleEndian, int8(b.Pcmd.Gaz)); err != nil { panic(err) } cmd.Write(tmp.Bytes()) tmp = &bytes.Buffer{} if err := binary.Write(tmp, binary.LittleEndian, uint32(b.Pcmd.Psi)); err != nil { panic(err) } cmd.Write(tmp.Bytes()) return b.nwFrameGenerator.generate(cmd, ARNETWORKAL_FRAME_TYPE_DATA, BD_NET_CD_NONACK_ID) } func (b *Bebop) createAck(frame NetworkFrame) *bytes.Buffer { // // ARNETWORK_Receiver_ThreadRun // // // libARNetwork/Sources/ARNETWORK_Manager.h#ARNETWORK_Manager_IDOutputToIDAck // //nolint:gosec // TODO: fix later return b.nwFrameGenerator.generate(bytes.NewBuffer([]byte{uint8(frame.Seq)}), ARNETWORKAL_FRAME_TYPE_ACK, byte(uint16(frame.Id)+(ARNETWORKAL_MANAGER_DEFAULT_ID_MAX/2)), ) } func (b *Bebop) createPong(frame NetworkFrame) *bytes.Buffer { return b.nwFrameGenerator.generate(bytes.NewBuffer(frame.Data), ARNETWORKAL_FRAME_TYPE_DATA, ARNETWORK_MANAGER_INTERNAL_BUFFER_ID_PONG, ) } func (b *Bebop) packetReceiver(buf []byte) { frame := NewNetworkFrame(buf) // // libARNetwork/Sources/ARNETWORK_Receiver.c#ARNETWORK_Receiver_ThreadRun // if frame.Type == int(ARNETWORKAL_FRAME_TYPE_DATA_WITH_ACK) { ack := b.createAck(frame).Bytes() if err := b.write(ack); err != nil { fmt.Println("ARNETWORKAL_FRAME_TYPE_DATA_WITH_ACK", err) } } if frame.Type == int(ARNETWORKAL_FRAME_TYPE_DATA_LOW_LATENCY) && frame.Id == int(BD_NET_DC_VIDEO_DATA_ID) { arstreamFrame := NewARStreamFrame(frame.Data) ack := b.createARStreamACK(arstreamFrame).Bytes() if err := b.write(ack); err != nil { fmt.Println("ARNETWORKAL_FRAME_TYPE_DATA_LOW_LATENCY", err) } } // // libARNetwork/Sources/ARNETWORK_Receiver.c#ARNETWORK_Receiver_ThreadRun // if frame.Id == int(ARNETWORK_MANAGER_INTERNAL_BUFFER_ID_PING) { pong := b.createPong(frame).Bytes() if err := b.write(pong); err != nil { fmt.Println("ARNETWORK_MANAGER_INTERNAL_BUFFER_ID_PING", err) } } } func (b *Bebop) StartRecording() error { buf := b.videoRecord(ARCOMMANDS_ARDRONE3_MEDIARECORD_VIDEO_RECORD_START) return b.write(b.nwFrameGenerator.generate(buf, ARNETWORKAL_FRAME_TYPE_DATA, BD_NET_CD_NONACK_ID).Bytes()) } func (b *Bebop) StopRecording() error { buf := b.videoRecord(ARCOMMANDS_ARDRONE3_MEDIARECORD_VIDEO_RECORD_STOP) return b.write(b.nwFrameGenerator.generate(buf, ARNETWORKAL_FRAME_TYPE_DATA, BD_NET_CD_NONACK_ID).Bytes()) } func (b *Bebop) videoRecord(state byte) *bytes.Buffer { // // ARCOMMANDS_Generator_GenerateARDrone3MediaRecordVideo // cmd := &bytes.Buffer{} cmd.WriteByte(ARCOMMANDS_ID_PROJECT_ARDRONE3) cmd.WriteByte(ARCOMMANDS_ID_ARDRONE3_CLASS_MEDIARECORD) tmp := &bytes.Buffer{} if err := binary.Write(tmp, binary.LittleEndian, uint16(ARCOMMANDS_ID_ARDRONE3_MEDIARECORD_CMD_VIDEO), ); err != nil { panic(err) } cmd.Write(tmp.Bytes()) tmp = &bytes.Buffer{} if err := binary.Write(tmp, binary.LittleEndian, uint32(state)); err != nil { panic(err) } cmd.Write(tmp.Bytes()) cmd.WriteByte(0) return cmd } func (b *Bebop) Video() chan []byte { return b.video } func (b *Bebop) HullProtection(protect bool) error { // // ARCOMMANDS_Generator_GenerateARDrone3SpeedSettingsHullProtection // cmd := &bytes.Buffer{} cmd.WriteByte(ARCOMMANDS_ID_PROJECT_ARDRONE3) cmd.WriteByte(ARCOMMANDS_ID_ARDRONE3_CLASS_SPEEDSETTINGS) tmp := &bytes.Buffer{} if err := binary.Write(tmp, binary.LittleEndian, uint16(ARCOMMANDS_ID_ARDRONE3_SPEEDSETTINGS_CMD_HULLPROTECTION), ); err != nil { return err } cmd.Write(tmp.Bytes()) tmp = &bytes.Buffer{} if err := binary.Write(tmp, binary.LittleEndian, bool2int8(protect)); err != nil { return err } cmd.Write(tmp.Bytes()) return b.write(b.nwFrameGenerator.generate(cmd, ARNETWORKAL_FRAME_TYPE_DATA, BD_NET_CD_NONACK_ID).Bytes()) } func (b *Bebop) Outdoor(outdoor bool) error { // // ARCOMMANDS_Generator_GenerateARDrone3SpeedSettingsOutdoor // cmd := &bytes.Buffer{} cmd.WriteByte(ARCOMMANDS_ID_PROJECT_ARDRONE3) cmd.WriteByte(ARCOMMANDS_ID_ARDRONE3_CLASS_SPEEDSETTINGS) tmp := &bytes.Buffer{} if err := binary.Write(tmp, binary.LittleEndian, uint16(ARCOMMANDS_ID_ARDRONE3_SPEEDSETTINGS_CMD_OUTDOOR), ); err != nil { return err } cmd.Write(tmp.Bytes()) tmp = &bytes.Buffer{} if err := binary.Write(tmp, binary.LittleEndian, bool2int8(outdoor)); err != nil { return err } cmd.Write(tmp.Bytes()) return b.write(b.nwFrameGenerator.generate(cmd, ARNETWORKAL_FRAME_TYPE_DATA, BD_NET_CD_NONACK_ID).Bytes()) } func (b *Bebop) VideoEnable(enable bool) error { cmd := &bytes.Buffer{} cmd.WriteByte(ARCOMMANDS_ID_PROJECT_ARDRONE3) cmd.WriteByte(ARCOMMANDS_ID_ARDRONE3_CLASS_MEDIASTREAMING) tmp := &bytes.Buffer{} if err := binary.Write(tmp, binary.LittleEndian, uint16(ARCOMMANDS_ID_ARDRONE3_MEDIASTREAMING_CMD_VIDEOENABLE), ); err != nil { return err } cmd.Write(tmp.Bytes()) tmp = &bytes.Buffer{} if err := binary.Write(tmp, binary.LittleEndian, bool2int8(enable)); err != nil { return err } cmd.Write(tmp.Bytes()) return b.write(b.nwFrameGenerator.generate(cmd, ARNETWORKAL_FRAME_TYPE_DATA, BD_NET_CD_NONACK_ID).Bytes()) } func (b *Bebop) VideoStreamMode(mode int8) error { cmd := &bytes.Buffer{} cmd.WriteByte(ARCOMMANDS_ID_PROJECT_ARDRONE3) cmd.WriteByte(ARCOMMANDS_ID_ARDRONE3_CLASS_MEDIASTREAMING) tmp := &bytes.Buffer{} if err := binary.Write(tmp, binary.LittleEndian, uint16(ARCOMMANDS_ID_ARDRONE3_MEDIASTREAMING_CMD_VIDEOSTREAMMODE), ); err != nil { return err } cmd.Write(tmp.Bytes()) tmp = &bytes.Buffer{} if err := binary.Write(tmp, binary.LittleEndian, mode); err != nil { return err } cmd.Write(tmp.Bytes()) return b.write(b.nwFrameGenerator.generate(cmd, ARNETWORKAL_FRAME_TYPE_DATA, BD_NET_CD_NONACK_ID).Bytes()) } func bool2int8(b bool) int8 { if b { return 1 } return 0 } func (b *Bebop) createARStreamACK(frame ARStreamFrame) *bytes.Buffer { // // ARSTREAM_NetworkHeaders_AckPacket_t; // // uint16_t frameNumber; // id of the current frame // uint64_t highPacketsAck; // Upper 64 packets bitfield // uint64_t lowPacketsAck; // Lower 64 packets bitfield // // libARStream/Sources/ARSTREAM_NetworkHeaders.c#ARSTREAM_NetworkHeaders_AckPacketSetFlag // // // each bit in the highPacketsAck and lowPacketsAck correspond to the // fragmentsPerFrame which have been received per frameNumber, so time to // flip some bits! // if frame.FrameNumber != b.tmpFrame.arstreamACK.FrameNumber { if len(b.tmpFrame.fragments) > 0 { emit := false // if we missed some frames, wait for the next iframe if frame.FrameNumber != b.tmpFrame.arstreamACK.FrameNumber+1 { b.tmpFrame.waitForIframe = true } // if it's an iframe if b.tmpFrame.frameFlags == 1 { b.tmpFrame.waitForIframe = false emit = true } else if !b.tmpFrame.waitForIframe { emit = true } if emit { skip := false for i := 0; i < len(b.tmpFrame.fragments); i++ { // check if any fragments are missing if len(b.tmpFrame.fragments[i]) == 0 { skip = true break } b.tmpFrame.frame = append(b.tmpFrame.frame, b.tmpFrame.fragments[i]...) } if !skip { select { case b.video <- b.tmpFrame.frame: default: } } } } b.tmpFrame.fragments = make(map[int][]byte) b.tmpFrame.frame = []byte{} b.tmpFrame.arstreamACK.FrameNumber = frame.FrameNumber b.tmpFrame.frameFlags = frame.FrameFlags } b.tmpFrame.fragments[frame.FragmentNumber] = frame.Frame if frame.FragmentNumber < 64 { //nolint:gosec // TODO: fix later b.tmpFrame.arstreamACK.LowPacketsAck |= uint64(1) << uint64(frame.FragmentNumber) } else { //nolint:gosec // TODO: fix later b.tmpFrame.arstreamACK.HighPacketsAck |= uint64(1) << uint64(frame.FragmentNumber-64) } ackPacket := &bytes.Buffer{} tmp := &bytes.Buffer{} //nolint:gosec // TODO: fix later if err := binary.Write(tmp, binary.LittleEndian, uint16(b.tmpFrame.arstreamACK.FrameNumber)); err != nil { panic(err) } ackPacket.Write(tmp.Bytes()) tmp = &bytes.Buffer{} if err := binary.Write(tmp, binary.LittleEndian, b.tmpFrame.arstreamACK.HighPacketsAck); err != nil { panic(err) } ackPacket.Write(tmp.Bytes()) tmp = &bytes.Buffer{} if err := binary.Write(tmp, binary.LittleEndian, b.tmpFrame.arstreamACK.LowPacketsAck); err != nil { panic(err) } ackPacket.Write(tmp.Bytes()) return b.nwFrameGenerator.generate(ackPacket, ARNETWORKAL_FRAME_TYPE_DATA, BD_NET_CD_VIDEO_ACK_ID) } ================================================ FILE: platforms/parrot/bebop/client/constants.go ================================================ package client const ( // libARNetworkAL/Includes/libARNetworkAL/ARNETWORKAL_Manager.h ARNETWORKAL_MANAGER_DEFAULT_ID_MAX uint16 = 256 // ARNETWORKAL_Frame_t identifiers BD_NET_CD_NONACK_ID byte = 10 BD_NET_CD_ACK_ID byte = 11 BD_NET_CD_EMERGENCY_ID byte = 12 BD_NET_CD_VIDEO_ACK_ID byte = 13 BD_NET_DC_VIDEO_DATA_ID byte = 125 BD_NET_DC_EVENT_ID byte = 126 BD_NET_DC_NAVDATA_ID byte = 127 // eARCOMMANDS_ID_PROJECT ARCOMMANDS_ID_PROJECT_COMMON byte = 0 ARCOMMANDS_ID_PROJECT_ARDRONE3 byte = 1 // eARCOMMANDS_ID_ARDRONE3_CLASS ARCOMMANDS_ID_ARDRONE3_CLASS_PILOTING byte = 0 ARCOMMANDS_ID_ARDRONE3_CLASS_ANIMATIONS byte = 5 ARCOMMANDS_ID_ARDRONE3_CLASS_CAMERA byte = 1 ARCOMMANDS_ID_ARDRONE3_CLASS_MEDIARECORD byte = 7 ARCOMMANDS_ID_ARDRONE3_CLASS_MEDIARECORDSTATE byte = 8 ARCOMMANDS_ID_ARDRONE3_CLASS_MEDIARECORDEVENT byte = 3 ARCOMMANDS_ID_ARDRONE3_CLASS_PILOTINGSTATE byte = 4 ARCOMMANDS_ID_ARDRONE3_CLASS_NETWORK byte = 13 ARCOMMANDS_ID_ARDRONE3_CLASS_NETWORKSTATE byte = 14 ARCOMMANDS_ID_ARDRONE3_CLASS_PILOTINGSETTINGS byte = 2 ARCOMMANDS_ID_ARDRONE3_CLASS_PILOTINGSETTINGSSTATE byte = 6 ARCOMMANDS_ID_ARDRONE3_CLASS_SPEEDSETTINGS byte = 11 ARCOMMANDS_ID_ARDRONE3_CLASS_SPEEDSETTINGSSTATE byte = 12 ARCOMMANDS_ID_ARDRONE3_CLASS_NETWORKSETTINGS byte = 9 ARCOMMANDS_ID_ARDRONE3_CLASS_NETWORKSETTINGSSTATE byte = 10 ARCOMMANDS_ID_ARDRONE3_CLASS_SETTINGS byte = 15 ARCOMMANDS_ID_ARDRONE3_CLASS_SETTINGSSTATE byte = 16 ARCOMMANDS_ID_ARDRONE3_CLASS_DIRECTORMODE byte = 17 ARCOMMANDS_ID_ARDRONE3_CLASS_DIRECTORMODESTATE byte = 18 ARCOMMANDS_ID_ARDRONE3_CLASS_PICTURESETTINGS byte = 19 ARCOMMANDS_ID_ARDRONE3_CLASS_PICTURESETTINGSSTATE byte = 20 ARCOMMANDS_ID_ARDRONE3_CLASS_MEDIASTREAMING byte = 21 ARCOMMANDS_ID_ARDRONE3_CLASS_MEDIASTREAMINGSTATE byte = 22 ARCOMMANDS_ID_ARDRONE3_CLASS_GPSSETTINGS byte = 23 ARCOMMANDS_ID_ARDRONE3_CLASS_GPSSETTINGSSTATE byte = 24 ARCOMMANDS_ID_ARDRONE3_CLASS_CAMERASTATE byte = 25 ARCOMMANDS_ID_ARDRONE3_CLASS_ANTIFLICKERING byte = 29 ARCOMMANDS_ID_ARDRONE3_CLASS_ANTIFLICKERINGSTATE byte = 30 // eARCOMMANDS_ID_ARDRONE3_PILOTINGSTATE_CMD ARCOMMANDS_ID_ARDRONE3_PILOTINGSTATE_CMD_FLATTRIMCHANGED byte = 0 ARCOMMANDS_ID_ARDRONE3_PILOTINGSTATE_CMD_FLYINGSTATECHANGED byte = 1 ARCOMMANDS_ID_ARDRONE3_PILOTINGSTATE_CMD_ALERTSTATECHANGED byte = 2 ARCOMMANDS_ID_ARDRONE3_PILOTINGSTATE_CMD_NAVIGATEHOMESTATECHANGED byte = 3 ARCOMMANDS_ID_ARDRONE3_PILOTINGSTATE_CMD_POSITIONCHANGED byte = 4 ARCOMMANDS_ID_ARDRONE3_PILOTINGSTATE_CMD_SPEEDCHANGED byte = 5 ARCOMMANDS_ID_ARDRONE3_PILOTINGSTATE_CMD_ATTITUDECHANGED byte = 6 ARCOMMANDS_ID_ARDRONE3_PILOTINGSTATE_CMD_AUTOTAKEOFFMODECHANGED byte = 7 ARCOMMANDS_ID_ARDRONE3_PILOTINGSTATE_CMD_ALTITUDECHANGED byte = 8 ARCOMMANDS_ID_ARDRONE3_PILOTINGSTATE_CMD_MAX byte = 9 // eARCOMMANDS_ID_ARDRONE3_ANIMATIONS_CMD; ARCOMMANDS_ID_ARDRONE3_ANIMATIONS_CMD_FLIP byte = 0 ARCOMMANDS_ID_ARDRONE3_ANIMATIONS_CMD_MAX byte = 1 // eARCOMMANDS_ARDRONE3_PILOTINGSTATE_FLYINGSTATECHANGED_STATE; ARCOMMANDS_ARDRONE3_PILOTINGSTATE_FLYINGSTATECHANGED_STATE_LANDED byte = 0 ARCOMMANDS_ARDRONE3_PILOTINGSTATE_FLYINGSTATECHANGED_STATE_TAKINGOFF byte = 1 ARCOMMANDS_ARDRONE3_PILOTINGSTATE_FLYINGSTATECHANGED_STATE_HOVERING byte = 2 ARCOMMANDS_ARDRONE3_PILOTINGSTATE_FLYINGSTATECHANGED_STATE_FLYING byte = 3 ARCOMMANDS_ARDRONE3_PILOTINGSTATE_FLYINGSTATECHANGED_STATE_LANDING byte = 4 ARCOMMANDS_ARDRONE3_PILOTINGSTATE_FLYINGSTATECHANGED_STATE_EMERGENCY byte = 5 ARCOMMANDS_ARDRONE3_PILOTINGSTATE_FLYINGSTATECHANGED_STATE_MAX byte = 6 // eARCOMMANDS_ARDRONE3_ANIMATIONS_FLIP_DIRECTION; ARCOMMANDS_ARDRONE3_ANIMATIONS_FLIP_DIRECTION_FRONT byte = 0 ARCOMMANDS_ARDRONE3_ANIMATIONS_FLIP_DIRECTION_BACK byte = 1 ARCOMMANDS_ARDRONE3_ANIMATIONS_FLIP_DIRECTION_RIGHT byte = 2 ARCOMMANDS_ARDRONE3_ANIMATIONS_FLIP_DIRECTION_LEFT byte = 3 ARCOMMANDS_ARDRONE3_ANIMATIONS_FLIP_DIRECTION_MAX byte = 4 // eARCOMMANDS_ID_COMMON_CLASS ARCOMMANDS_ID_COMMON_CLASS_NETWORK byte = 0 ARCOMMANDS_ID_COMMON_CLASS_NETWORKEVENT byte = 1 ARCOMMANDS_ID_COMMON_CLASS_SETTINGS byte = 2 ARCOMMANDS_ID_COMMON_CLASS_SETTINGSSTATE byte = 3 ARCOMMANDS_ID_COMMON_CLASS_COMMON byte = 4 ARCOMMANDS_ID_COMMON_CLASS_COMMONSTATE byte = 5 ARCOMMANDS_ID_COMMON_CLASS_OVERHEAT byte = 6 ARCOMMANDS_ID_COMMON_CLASS_OVERHEATSTATE byte = 7 ARCOMMANDS_ID_COMMON_CLASS_CONTROLLERSTATE byte = 8 ARCOMMANDS_ID_COMMON_CLASS_WIFISETTINGS byte = 9 ARCOMMANDS_ID_COMMON_CLASS_WIFISETTINGSSTATE byte = 10 ARCOMMANDS_ID_COMMON_CLASS_MAVLINK byte = 11 ARCOMMANDS_ID_COMMON_CLASS_MAVLINKSTATE byte = 12 ARCOMMANDS_ID_COMMON_CLASS_CALIBRATION byte = 13 ARCOMMANDS_ID_COMMON_CLASS_CALIBRATIONSTATE byte = 14 ARCOMMANDS_ID_COMMON_CLASS_CAMERASETTINGSSTATE byte = 15 ARCOMMANDS_ID_COMMON_CLASS_GPS byte = 16 ARCOMMANDS_ID_COMMON_CLASS_FLIGHTPLANSTATE byte = 17 ARCOMMANDS_ID_COMMON_CLASS_FLIGHTPLANEVENT byte = 19 ARCOMMANDS_ID_COMMON_CLASS_ARLIBSVERSIONSSTATE byte = 18 // eARCOMMANDS_ID_ARDRONE3_PILOTING_CMD ARCOMMANDS_ID_ARDRONE3_PILOTING_CMD_FLATTRIM byte = 0 ARCOMMANDS_ID_ARDRONE3_PILOTING_CMD_TAKEOFF byte = 1 ARCOMMANDS_ID_ARDRONE3_PILOTING_CMD_PCMD byte = 2 ARCOMMANDS_ID_ARDRONE3_PILOTING_CMD_LANDING byte = 3 ARCOMMANDS_ID_ARDRONE3_PILOTING_CMD_EMERGENCY byte = 4 ARCOMMANDS_ID_ARDRONE3_PILOTING_CMD_NAVIGATEHOME byte = 5 ARCOMMANDS_ID_ARDRONE3_PILOTING_CMD_AUTOTAKEOFFMODE byte = 6 ARCOMMANDS_ID_ARDRONE3_PILOTING_CMD_MAX byte = 7 // eARCOMMANDS_ID_ARDRONE3_MEDIARECORD_CMD ARCOMMANDS_ID_ARDRONE3_MEDIARECORD_CMD_PICTURE byte = 0 ARCOMMANDS_ID_ARDRONE3_MEDIARECORD_CMD_VIDEO byte = 1 ARCOMMANDS_ID_ARDRONE3_MEDIARECORD_CMD_PICTUREV2 byte = 2 ARCOMMANDS_ID_ARDRONE3_MEDIARECORD_CMD_VIDEOV2 byte = 3 ARCOMMANDS_ID_ARDRONE3_MEDIARECORD_CMD_MAX byte = 4 // eARCOMMANDS_ARDRONE3_MEDIARECORD_VIDEO_RECORD ARCOMMANDS_ARDRONE3_MEDIARECORD_VIDEO_RECORD_STOP byte = 0 ARCOMMANDS_ARDRONE3_MEDIARECORD_VIDEO_RECORD_START byte = 1 ARCOMMANDS_ARDRONE3_MEDIARECORD_VIDEO_RECORD_MAX byte = 2 // eARCOMMANDS_ID_COMMON_COMMON_CMD ARCOMMANDS_ID_COMMON_COMMON_CMD_ALLSTATES byte = 0 ARCOMMANDS_ID_COMMON_COMMON_CMD_CURRENTDATE byte = 1 ARCOMMANDS_ID_COMMON_COMMON_CMD_CURRENTTIME byte = 2 ARCOMMANDS_ID_COMMON_COMMON_CMD_REBOOT byte = 3 ARCOMMANDS_ID_COMMON_COMMON_CMD_MAX byte = 4 // eARCOMMANDS_ID_COMMON_COMMONSTATE_CMD; ARCOMMANDS_ID_COMMON_COMMONSTATE_CMD_ALLSTATESCHANGED byte = 0 ARCOMMANDS_ID_COMMON_COMMONSTATE_CMD_BATTERYSTATECHANGED byte = 1 ARCOMMANDS_ID_COMMON_COMMONSTATE_CMD_MASSSTORAGESTATELISTCHANGED byte = 2 ARCOMMANDS_ID_COMMON_COMMONSTATE_CMD_MASSSTORAGEINFOSTATELISTCHANGED byte = 3 ARCOMMANDS_ID_COMMON_COMMONSTATE_CMD_CURRENTDATECHANGED byte = 4 ARCOMMANDS_ID_COMMON_COMMONSTATE_CMD_CURRENTTIMECHANGED byte = 5 ARCOMMANDS_ID_COMMON_COMMONSTATE_CMD_MASSSTORAGEINFOREMAININGLISTCHANGED byte = 6 ARCOMMANDS_ID_COMMON_COMMONSTATE_CMD_WIFISIGNALCHANGED byte = 6 ARCOMMANDS_ID_COMMON_COMMONSTATE_CMD_SENSORSSTATESLISTCHANGED byte = 7 ARCOMMANDS_ID_COMMON_COMMONSTATE_CMD_MAX byte = 8 // eARMEDIA_ENCAPSULER_CODEC CODEC_UNKNNOWN byte = 0 CODEC_VLIB byte = 1 CODEC_P264 byte = 2 CODEC_MPEG4_VISUAL byte = 3 CODEC_MPEG4_AVC byte = 4 CODEC_MOTION_JPEG byte = 5 // eARMEDIA_ENCAPSULER_FRAME_TYPE; ARMEDIA_ENCAPSULER_FRAME_TYPE_UNKNNOWN byte = 0 ARMEDIA_ENCAPSULER_FRAME_TYPE_I_FRAME byte = 1 ARMEDIA_ENCAPSULER_FRAME_TYPE_P_FRAME byte = 2 ARMEDIA_ENCAPSULER_FRAME_TYPE_JPEG byte = 3 ARMEDIA_ENCAPSULER_FRAME_TYPE_MAX byte = 4 // eARNETWORK_MANAGER_INTERNAL_BUFFER_ID ARNETWORK_MANAGER_INTERNAL_BUFFER_ID_PING byte = 0 ARNETWORK_MANAGER_INTERNAL_BUFFER_ID_PONG byte = 1 ARNETWORK_MANAGER_INTERNAL_BUFFER_ID_MAX byte = 3 // eARNETWORKAL_FRAME_TYPE ARNETWORKAL_FRAME_TYPE_UNINITIALIZED byte = 0 ARNETWORKAL_FRAME_TYPE_ACK byte = 1 ARNETWORKAL_FRAME_TYPE_DATA byte = 2 ARNETWORKAL_FRAME_TYPE_DATA_LOW_LATENCY byte = 3 ARNETWORKAL_FRAME_TYPE_DATA_WITH_ACK byte = 4 ARNETWORKAL_FRAME_TYPE_MAX byte = 5 ARCOMMANDS_ID_ARDRONE3_SPEEDSETTINGS_CMD_MAXVERTICALSPEED byte = 0 ARCOMMANDS_ID_ARDRONE3_SPEEDSETTINGS_CMD_MAXROTATIONSPEED byte = 1 ARCOMMANDS_ID_ARDRONE3_SPEEDSETTINGS_CMD_HULLPROTECTION byte = 2 ARCOMMANDS_ID_ARDRONE3_SPEEDSETTINGS_CMD_OUTDOOR byte = 3 ARCOMMANDS_ID_ARDRONE3_MEDIASTREAMING_CMD_VIDEOENABLE byte = 0 ARCOMMANDS_ID_ARDRONE3_MEDIASTREAMING_CMD_VIDEOSTREAMMODE byte = 1 ) ================================================ FILE: platforms/parrot/bebop/client/examples/ff.conf ================================================ Port 8090 BindAddress 0.0.0.0 MaxClients 1000 MaxBandWidth 50000 CustomLog - NoDaemon File /tmp/bebop.ffm FileMaxSize 20M Feed bebop.ffm Format mpjpeg VideoFrameRate 14 VideoSize 640x368 VideoQMin 3 VideoQMax 31 NoAudio Strict -1 ACL allow 192.168.0.0 192.168.255.255 ACL allow localhost ACL allow 127.0.0.1 ================================================ FILE: platforms/parrot/bebop/client/examples/takeoff.go ================================================ //go:build example // +build example // // Do not build by default. package main import ( "fmt" "time" "gobot.io/x/gobot/v2/platforms/parrot/bebop/client" ) func main() { bebop := client.New() if err := bebop.Connect(); err != nil { fmt.Println(err) return } if err := bebop.HullProtection(true); err != nil { fmt.Println(err) return } fmt.Println("takeoff") if err := bebop.TakeOff(); err != nil { fmt.Println(err) fmt.Println("fail") return } time.Sleep(5 * time.Second) fmt.Println("land") if err := bebop.Land(); err != nil { fmt.Println(err) return } time.Sleep(5 * time.Second) fmt.Println("done") } ================================================ FILE: platforms/parrot/bebop/client/examples/video.go ================================================ //go:build example // +build example // // Do not build by default. /* This example will connect to the Bebop and stream its video to a webpage via ffserver. This requires you to have both ffmpeg and ffserver installed on your computer. In order to run this example you will first need to start ffserver with: $ ffserver -f ff.conf then in a separate terminal run this program: $ go run video.go You will then be able to view the video feed by navigation to http://localhost:8090/bebop.mjpeg in a web browser. *NOTE* firefox works best for viewing the video feed. */ package main import ( "fmt" "io" "os/exec" "time" "gobot.io/x/gobot/v2/platforms/parrot/bebop/client" ) func main() { bebop := client.New() if err := bebop.Connect(); err != nil { fmt.Println(err) return } if err := bebop.VideoEnable(true); err != nil { fmt.Println(err) return } if err := bebop.VideoStreamMode(0); err != nil { fmt.Println(err) return } ffmpeg := exec.Command("ffmpeg", "-i", "pipe:0", "http://localhost:8090/bebop.ffm") ffmpegErr, err := ffmpeg.StderrPipe() if err != nil { fmt.Println(err) return } ffmpegIn, err := ffmpeg.StdinPipe() if err != nil { fmt.Println(err) return } if err := ffmpeg.Start(); err != nil { fmt.Println(err) return } go func() { for { buf, err := io.ReadAll(ffmpegErr) if err != nil { fmt.Println(err) } if len(buf) > 0 { fmt.Println(string(buf)) } } }() go func() { for { if _, err := ffmpegIn.Write(<-bebop.Video()); err != nil { fmt.Println(err) } } }() time.Sleep(99 * time.Second) } ================================================ FILE: platforms/parrot/bebop/client/networkframegenerator.go ================================================ package client import ( "bytes" "encoding/binary" "sync" ) type nwFrameGenerator struct { seq map[byte]byte hlen int mutex *sync.Mutex } func newNetworkFrameGenerator() *nwFrameGenerator { nwg := nwFrameGenerator{ seq: make(map[byte]byte), // each frame id has it's own sequence number hlen: 7, // size of ARNETWORKAL_Frame_t header mutex: &sync.Mutex{}, } return &nwg } // generate the "NetworkFrame" as bytes buffer func (nwg *nwFrameGenerator) generate(cmd *bytes.Buffer, frameType byte, id byte) *bytes.Buffer { nwg.mutex.Lock() defer nwg.mutex.Unlock() // func networkFrameGenerator() func(*bytes.Buffer, byte, byte) NetworkFrame { // // ARNETWORKAL_Frame_t // // uint8 type - frame type ARNETWORK_FRAME_TYPE // uint8 id - identifier of the buffer sending the frame // uint8 seq - sequence number of the frame // uint32 size - size of the frame // if _, ok := nwg.seq[id]; !ok { nwg.seq[id] = 0 } nwg.seq[id]++ // automatically rollover to 0 when > 255 is fine ret := &bytes.Buffer{} ret.WriteByte(frameType) ret.WriteByte(id) ret.WriteByte(nwg.seq[id]) size := &bytes.Buffer{} //nolint:gosec // TODO: fix later if err := binary.Write(size, binary.LittleEndian, uint32(cmd.Len()+nwg.hlen)); err != nil { panic(err) } ret.Write(size.Bytes()) ret.Write(cmd.Bytes()) return ret } ================================================ FILE: platforms/parrot/bebop/doc.go ================================================ /* Package bebop provides the Gobot adaptor and driver for the Parrot Bebop. Installing: Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) For more information refer to the bebop README: https://github.com/hybridgroup/gobot/blob/release/platforms/parrot/bebop/README.md */ package bebop // import "gobot.io/x/gobot/v2/platforms/parrot/bebop" ================================================ FILE: platforms/parrot/bebop/pitch.go ================================================ package bebop import "math" // ValidatePitch helps validate pitch values such as those created by // a joystick to values between 0-100 that are required as // params to Parrot Bebop PCMDs func ValidatePitch(data float64, offset float64) int { value := math.Abs(data) / offset if value >= 0.1 { if value <= 1.0 { return int((float64(int(value*100)) / 100) * 100) } return 100 } return 0 } ================================================ FILE: platforms/parrot/bebop/pitch_test.go ================================================ package bebop import ( "testing" "github.com/stretchr/testify/assert" ) func TestBebopValidatePitchWhenEqualOffset(t *testing.T) { assert.Equal(t, 100, ValidatePitch(32767.0, 32767.0)) } func TestBebopValidatePitchWhenTiny(t *testing.T) { assert.Equal(t, 0, ValidatePitch(1.1, 32767.0)) } func TestBebopValidatePitchWhenCentered(t *testing.T) { assert.Equal(t, 50, ValidatePitch(16383.5, 32767.0)) } ================================================ FILE: platforms/parrot/bebop/test_helper.go ================================================ package bebop type testDrone struct{} func (t testDrone) TakeOff() error { return nil } func (t testDrone) Land() error { return nil } func (t testDrone) Up(n int) error { return nil } func (t testDrone) Down(n int) error { return nil } func (t testDrone) Left(n int) error { return nil } func (t testDrone) Right(n int) error { return nil } func (t testDrone) Forward(n int) error { return nil } func (t testDrone) Backward(n int) error { return nil } func (t testDrone) Clockwise(n int) error { return nil } func (t testDrone) CounterClockwise(n int) error { return nil } func (t testDrone) Stop() error { return nil } func (t testDrone) Connect() error { return nil } func (t testDrone) Video() chan []byte { return nil } func (t testDrone) StartRecording() error { return nil } func (t testDrone) StopRecording() error { return nil } func (t testDrone) HullProtection(protect bool) error { return nil } func (t testDrone) Outdoor(outdoor bool) error { return nil } func (t testDrone) VideoEnable(enable bool) error { return nil } func (t testDrone) VideoStreamMode(mode int8) error { return nil } ================================================ FILE: platforms/parrot/minidrone/LICENSE ================================================ Copyright (c) 2014-2018 The Hybrid Group Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: platforms/parrot/minidrone/README.md ================================================ # Parrot Minidrone The Parrot Minidrones are very inexpensive drones that are controlled using Bluetooth LE aka Bluetooth 4.0. Models that are known to work with this package include: - Parrot Rolling Spider - Parrot Airborne Cargo Mars - Parrot Airborne Cargo Travis - Parrot Mambo Models that should work now, but have not been tested by us: - Parrot Airborne Night Swat - Parrot Airborne Night Maclane - Parrot Airborne Night Blaze - Parrot HYDROFOIL Orak - Parrot HYDROFOIL NewZ Models that will require additional work for compatibility: - Parrot Swing ## How to Install Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) ## How to Use ```go package main import ( "fmt" "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/bleclient" "gobot.io/x/gobot/v2/drivers/ble/parrot" ) func main() { bleAdaptor := bleclient.NewAdaptor(os.Args[1]) drone := parrot.NewMinidroneDriver(bleAdaptor) work := func() { drone.On(minidrone.Battery, func(data interface{}) { fmt.Printf("battery: %d\n", data) }) drone.On(minidrone.FlightStatus, func(data interface{}) { fmt.Printf("flight status: %d\n", data) }) drone.On(minidrone.Takeoff, func(data interface{}) { fmt.Println("taking off...") }) drone.On(minidrone.Hovering, func(data interface{}) { fmt.Println("hovering!") gobot.After(5*time.Second, func() { drone.Land() }) }) drone.On(minidrone.Landing, func(data interface{}) { fmt.Println("landing...") }) drone.On(minidrone.Landed, func(data interface{}) { fmt.Println("landed.") }) time.Sleep(1000 * time.Millisecond) drone.TakeOff() } robot := gobot.NewRobot("minidrone", []gobot.Connection{bleAdaptor}, []gobot.Device{drone}, work, ) if err := robot.Start(); err != nil { panic(err) } } ``` ## How to Connect The Parrot Minidrones are Bluetooth LE devices. You need to know the BLE ID or name of the Minidrone you want to connect to. The Gobot BLE client adaptor also lets you connect by friendly name, aka "RS_1234". ### OSX To run any of the Gobot BLE code you must use the `GODEBUG=cgocheck=0` flag in order to get around some of the issues in the CGo-based implementation. If you connect by name, then you do not need to worry about the Bluetooth LE ID. However, if you want to connect by ID, OS X uses its own Bluetooth ID system which is different from the IDs used on Linux. The code calls thru the XPC interfaces provided by OSX, so as a result does not need to run under sudo. For example: `GODEBUG=cgocheck=0 go run examples/minidrone.go RS_1234` ### Ubuntu On Linux the BLE code will need to run as a root user account. The easiest way to accomplish this is probably to use `go build` to build your program, and then to run the requesting executable using `sudo`. For example: ```sh go build examples/minidrone.go sudo ./minidrone RS_1234 ``` ### Windows Hopefully coming soon... ================================================ FILE: platforms/parrot/minidrone/doc.go ================================================ /* Package minidrone contains the Gobot driver for the Parrot Minidrone. For more information refer to the minidrone README: https://github.com/hybridgroup/gobot/blob/release/platforms/parrot/minidrone/README.md */ package minidrone // import "gobot.io/x/gobot/v2/drivers/ble/parrot" ================================================ FILE: platforms/parrot/parrot.go ================================================ /* Package parrot contains Gobot adaptors and drivers for the Parrot drones This package currently supports the following Parrot drones: - Parrot Minidrone - Intel Joule developer kit For further information refer to Parrot README: https://gobot.io/x/gobot/v2/blob/release/platforms/parrot/README.md */ package parrot ================================================ FILE: platforms/particle/LICENSE ================================================ Copyright (c) 2013-2018 The Hybrid Group Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: platforms/particle/README.md ================================================ # Particle The Particle Photon and Particle Electron are connected microcontrollers from Particle (), the company formerly known as Spark Devices. The Photon uses a Wi-Fi connection to the Particle cloud, and the Electron uses a 3G wireless connection. Once the Photon or Electron connects to the network, it automatically connects with a central server (the "Particle Cloud") and stays connected so it can be controlled from external systems, such as a Gobot program. To run Gobot programs please make sure you are running default Tinker firmware on the Photon or Electron. For more info about the Particle platform go to ## How to Install Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) ## How to Use ```go package main import ( "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/particle" ) func main() { core := particle.NewAdaptor("device_id", "access_token") led := gpio.NewLedDriver(core, "D7") work := func() { gobot.Every(1*time.Second, func() { if err := led.Toggle(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("spark", []gobot.Connection{core}, []gobot.Device{led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ``` ================================================ FILE: platforms/particle/adaptor.go ================================================ package particle import ( "encoding/json" "errors" "fmt" "io" "net/http" "net/url" "strconv" "github.com/donovanhide/eventsource" "gobot.io/x/gobot/v2" ) // Adaptor is the Gobot Adaptor for Particle type Adaptor struct { gobot.Eventer name string DeviceID string AccessToken string APIServer string servoPins map[string]bool } // Event is an event emitted by the Particle cloud type Event struct { Name string Data string Error error } var eventSource = func(url string) (chan eventsource.Event, chan error, error) { stream, err := eventsource.Subscribe(url, "") if err != nil { return nil, nil, err } return stream.Events, stream.Errors, nil } // NewAdaptor creates new Photon adaptor with deviceId and accessToken // using api.particle.io server as default func NewAdaptor(deviceID string, accessToken string) *Adaptor { return &Adaptor{ name: gobot.DefaultName("Particle"), DeviceID: deviceID, AccessToken: accessToken, servoPins: make(map[string]bool), APIServer: "https://api.particle.io", Eventer: gobot.NewEventer(), } } // Name returns the Adaptor name func (s *Adaptor) Name() string { return s.name } // SetName sets the Adaptor name func (s *Adaptor) SetName(n string) { s.name = n } // Connect returns true if connection to Particle Photon or Electron is successful func (s *Adaptor) Connect() error { return nil } // Finalize returns true if connection to Particle Photon or Electron is finalized successfully func (s *Adaptor) Finalize() error { return nil } // AnalogRead reads analog ping value using Particle cloud api func (s *Adaptor) AnalogRead(pin string) (int, error) { params := url.Values{ "params": {pin}, "access_token": {s.AccessToken}, } url := fmt.Sprintf("%v/analogread", s.deviceURL()) resp, err := s.request("POST", url, params) if err == nil { //nolint:forcetypeassert // ok here return int(resp["return_value"].(float64)), nil } return 0, err } // PwmWrite writes in pin using analog write api func (s *Adaptor) PwmWrite(pin string, level byte) error { return s.AnalogWrite(pin, level) } // AnalogWrite writes analog pin with specified level using Particle cloud api func (s *Adaptor) AnalogWrite(pin string, level byte) error { params := url.Values{ "params": {fmt.Sprintf("%v,%v", pin, level)}, "access_token": {s.AccessToken}, } url := fmt.Sprintf("%v/analogwrite", s.deviceURL()) _, err := s.request("POST", url, params) return err } // DigitalWrite writes to a digital pin using Particle cloud api func (s *Adaptor) DigitalWrite(pin string, level byte) error { params := url.Values{ "params": {fmt.Sprintf("%v,%v", pin, s.pinLevel(level))}, "access_token": {s.AccessToken}, } url := fmt.Sprintf("%v/digitalwrite", s.deviceURL()) _, err := s.request("POST", url, params) return err } // DigitalRead reads from digital pin using Particle cloud api func (s *Adaptor) DigitalRead(pin string) (int, error) { params := url.Values{ "params": {pin}, "access_token": {s.AccessToken}, } url := fmt.Sprintf("%v/digitalread", s.deviceURL()) resp, err := s.request("POST", url, params) if err != nil { return -1, err } //nolint:forcetypeassert // ok here return int(resp["return_value"].(float64)), nil } // ServoWrite writes the 0-180 degree angle to the specified pin. // To use it requires installing the "tinker-servo" sketch on your // Particle device. not just the default "tinker". func (s *Adaptor) ServoWrite(pin string, angle byte) error { if _, present := s.servoPins[pin]; !present { if err := s.servoPinOpen(pin); err != nil { return err } } params := url.Values{ "params": {fmt.Sprintf("%v,%v", pin, angle)}, "access_token": {s.AccessToken}, } url := fmt.Sprintf("%v/servoSet", s.deviceURL()) _, err := s.request("POST", url, params) return err } // EventStream returns a gobot.Event based on the following params: // // * source - "all"/"devices"/"device" (More info at: http://docs.particle.io/api/#reading-data-from-a-core-events) // * name - Event name to subscribe for, leave blank to subscribe to all events. // // A new event is emitted as a particle.Event struct func (s *Adaptor) EventStream(source string, name string) (*gobot.Event, error) { var url string switch source { case "all": url = fmt.Sprintf("%s/v1/events/%s?access_token=%s", s.APIServer, name, s.AccessToken) case "devices": url = fmt.Sprintf("%s/v1/devices/events/%s?access_token=%s", s.APIServer, name, s.AccessToken) case "device": url = fmt.Sprintf("%s/events/%s?access_token=%s", s.deviceURL(), name, s.AccessToken) default: return nil, errors.New("source param should be: all, devices or device") } events, _, err := eventSource(url) if err != nil { return nil, err } go func() { for { ev := <-events if ev.Event() != "" && ev.Data() != "" { s.Publish(ev.Event(), ev.Data()) } } }() return nil, nil //nolint:nilnil // seems ok here } // Variable returns a core variable value as a string func (s *Adaptor) Variable(name string) (string, error) { url := fmt.Sprintf("%v/%s?access_token=%s", s.deviceURL(), name, s.AccessToken) resp, err := s.request("GET", url, nil) if err != nil { return "", err } var result string switch val := resp["result"].(type) { case bool: result = strconv.FormatBool(val) case float64: result = strconv.FormatFloat(val, 'f', -1, 64) case string: result = val } return result, nil } // Function executes a core function and // returns value from request. // Takes a String as the only argument and returns an Int. // If function is not defined in core, it will time out func (s *Adaptor) Function(name string, args string) (int, error) { params := url.Values{ "args": {args}, "access_token": {s.AccessToken}, } url := fmt.Sprintf("%s/%s", s.deviceURL(), name) resp, err := s.request("POST", url, params) if err != nil { return -1, err } //nolint:forcetypeassert // ok here return int(resp["return_value"].(float64)), nil } // setAPIServer sets Particle cloud api server, this can be used to change from default api.spark.io func (s *Adaptor) setAPIServer(server string) { s.APIServer = server } // deviceURL constructs device url to make requests from Particle cloud api func (s *Adaptor) deviceURL() string { if len(s.APIServer) == 0 { s.setAPIServer("https://api.particle.io") } return fmt.Sprintf("%v/v1/devices/%v", s.APIServer, s.DeviceID) } // pinLevel converts byte level to string expected in api func (s *Adaptor) pinLevel(level byte) string { if level == 1 { return "HIGH" } return "LOW" } // request makes request to Particle cloud server, return err != nil if there is // any issue with the request. // //nolint:bodyclose,noctx // not changed yet func (s *Adaptor) request(method string, url string, params url.Values) (map[string]interface{}, error) { var resp *http.Response var err error switch method { case "POST": resp, err = http.PostForm(url, params) //nolint:gosec // accepted, because local function and no exposed routing case "GET": resp, err = http.Get(url) //nolint:gosec // accepted, because local function and no exposed routing } if err != nil { return nil, err } buf, err := io.ReadAll(resp.Body) if err != nil { return nil, err } var m map[string]interface{} if err := json.Unmarshal(buf, &m); err != nil { return m, err } if resp.Status != "200 OK" { return m, fmt.Errorf("%v: error communicating to the Particle cloud", resp.Status) } if _, ok := m["error"]; ok { //nolint:forcetypeassert // ok here return m, errors.New(m["error"].(string)) } return m, nil } func (s *Adaptor) servoPinOpen(pin string) error { params := url.Values{ "params": {pin}, "access_token": {s.AccessToken}, } url := fmt.Sprintf("%v/servoOpen", s.deviceURL()) _, err := s.request("POST", url, params) if err != nil { return err } s.servoPins[pin] = true return nil } ================================================ FILE: platforms/particle/adaptor_test.go ================================================ package particle import ( "errors" "net/http" "net/http/httptest" "net/url" "strings" "testing" "github.com/donovanhide/eventsource" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) // HELPERS func createTestServer(handler func(w http.ResponseWriter, r *http.Request)) *httptest.Server { return httptest.NewServer(http.HandlerFunc(handler)) } func getDummyResponseForPath(t *testing.T, path string, dummyResponse string) *httptest.Server { t.Helper() dummyData := []byte(dummyResponse) return createTestServer(func(w http.ResponseWriter, r *http.Request) { //nolint:testifylint // TODO: fix later require.Equal(t, "/v1/devices"+path, r.URL.Path) _, _ = w.Write(dummyData) }) } func getDummyResponseForPathWithParams( t *testing.T, path string, params []string, dummyResponse string, ) *httptest.Server { t.Helper() dummyData := []byte(dummyResponse) return createTestServer(func(w http.ResponseWriter, r *http.Request) { //nolint:testifylint // TODO: fix later require.Equal(t, "/v1/devices"+path, r.URL.Path) _ = r.ParseForm() for key, value := range params { if r.Form["params"][key] != value { t.Error("Expected param to be " + r.Form["params"][key] + " but was " + value) } } _, _ = w.Write(dummyData) }) } func initTestAdaptor() *Adaptor { return NewAdaptor("myDevice", "token") } func initTestAdaptorWithServo() *Adaptor { a := NewAdaptor("myDevice", "token") a.servoPins["1"] = true return a } // TESTS func TestAdaptor(t *testing.T) { var a interface{} = initTestAdaptor() _, ok := a.(gobot.Adaptor) if !ok { require.Fail(t, "Adaptor{} should be a gobot.Adaptor") } } func TestNewAdaptor(t *testing.T) { // does it return a pointer to an instance of Adaptor? var a interface{} = initTestAdaptor() core, ok := a.(*Adaptor) if !ok { require.Fail(t, "NewAdaptor() should have returned a *Adaptor") } assert.Equal(t, "https://api.particle.io", core.APIServer) assert.True(t, strings.HasPrefix(core.Name(), "Particle")) core.SetName("sparkie") assert.Equal(t, "sparkie", core.Name()) } func TestAdaptorConnect(t *testing.T) { a := initTestAdaptor() require.NoError(t, a.Connect()) } func TestAdaptorFinalize(t *testing.T) { a := initTestAdaptor() _ = a.Connect() require.NoError(t, a.Finalize()) } func TestAdaptorAnalogRead(t *testing.T) { // When no error response := `{"return_value": 5.2}` params := []string{"A1"} a := initTestAdaptor() testServer := getDummyResponseForPathWithParams(t, "/"+a.DeviceID+"/analogread", params, response) a.setAPIServer(testServer.URL) defer testServer.Close() val, _ := a.AnalogRead("A1") assert.Equal(t, 5, val) } func TestAdaptorAnalogReadError(t *testing.T) { a := initTestAdaptor() // When error testServer := createTestServer(func(w http.ResponseWriter, r *http.Request) { http.NotFound(w, r) }) defer testServer.Close() a.setAPIServer(testServer.URL) val, _ := a.AnalogRead("A1") assert.Equal(t, 0, val) } func TestAdaptorPwmWrite(t *testing.T) { response := `{}` params := []string{"A1,1"} a := initTestAdaptor() testServer := getDummyResponseForPathWithParams(t, "/"+a.DeviceID+"/analogwrite", params, response) defer testServer.Close() a.setAPIServer(testServer.URL) _ = a.PwmWrite("A1", 1) } func TestAdaptorAnalogWrite(t *testing.T) { response := `{}` params := []string{"A1,1"} a := initTestAdaptor() testServer := getDummyResponseForPathWithParams(t, "/"+a.DeviceID+"/analogwrite", params, response) defer testServer.Close() a.setAPIServer(testServer.URL) _ = a.AnalogWrite("A1", 1) } func TestAdaptorDigitalWrite(t *testing.T) { // When HIGH response := `{}` params := []string{"D7,HIGH"} a := initTestAdaptor() testServer := getDummyResponseForPathWithParams(t, "/"+a.DeviceID+"/digitalwrite", params, response) a.setAPIServer(testServer.URL) _ = a.DigitalWrite("D7", 1) testServer.Close() // When LOW params = []string{"D7,LOW"} testServer = getDummyResponseForPathWithParams(t, "/"+a.DeviceID+"/digitalwrite", params, response) defer testServer.Close() a.setAPIServer(testServer.URL) _ = a.DigitalWrite("D7", 0) } func TestAdaptorServoOpen(t *testing.T) { response := `{}` params := []string{"1"} a := initTestAdaptor() testServer := getDummyResponseForPathWithParams(t, "/"+a.DeviceID+"/servoOpen", params, response) defer testServer.Close() a.setAPIServer(testServer.URL) _ = a.servoPinOpen("1") } func TestAdaptorServoWrite(t *testing.T) { response := `{}` params := []string{"1,128"} a := initTestAdaptorWithServo() testServer := getDummyResponseForPathWithParams(t, "/"+a.DeviceID+"/servoSet", params, response) defer testServer.Close() a.setAPIServer(testServer.URL) _ = a.ServoWrite("1", 128) } func TestAdaptorDigitalRead(t *testing.T) { // When HIGH response := `{"return_value": 1}` params := []string{"D7"} a := initTestAdaptor() testServer := getDummyResponseForPathWithParams(t, "/"+a.DeviceID+"/digitalread", params, response) a.setAPIServer(testServer.URL) val, _ := a.DigitalRead("D7") assert.Equal(t, 1, val) testServer.Close() // When LOW response = `{"return_value": 0}` testServer = getDummyResponseForPathWithParams(t, "/"+a.DeviceID+"/digitalread", params, response) a.setAPIServer(testServer.URL) defer testServer.Close() val, _ = a.DigitalRead("D7") assert.Equal(t, 0, val) } func TestAdaptorDigitalReadError(t *testing.T) { a := initTestAdaptor() // When error testServer := createTestServer(func(w http.ResponseWriter, r *http.Request) { http.NotFound(w, r) }) defer testServer.Close() a.setAPIServer(testServer.URL) val, _ := a.DigitalRead("D7") assert.Equal(t, -1, val) } func TestAdaptorFunction(t *testing.T) { response := `{"return_value": 1}` a := initTestAdaptor() testServer := getDummyResponseForPath(t, "/"+a.DeviceID+"/hello", response) a.setAPIServer(testServer.URL) val, _ := a.Function("hello", "100,200") assert.Equal(t, 1, val) testServer.Close() // When not existent response = `{"ok": false, "error": "timeout"}` testServer = getDummyResponseForPath(t, "/"+a.DeviceID+"/hello", response) a.setAPIServer(testServer.URL) _, err := a.Function("hello", "") require.ErrorContains(t, err, "timeout") testServer.Close() } func TestAdaptorVariable(t *testing.T) { // When String response := `{"result": "1"}` a := initTestAdaptor() testServer := getDummyResponseForPath(t, "/"+a.DeviceID+"/variable_name", response) a.setAPIServer(testServer.URL) val, _ := a.Variable("variable_name") assert.Equal(t, "1", val) testServer.Close() // When float response = `{"result": 1.1}` testServer = getDummyResponseForPath(t, "/"+a.DeviceID+"/variable_name", response) a.setAPIServer(testServer.URL) val, _ = a.Variable("variable_name") assert.Equal(t, "1.1", val) testServer.Close() // When int response = `{"result": 1}` testServer = getDummyResponseForPath(t, "/"+a.DeviceID+"/variable_name", response) a.setAPIServer(testServer.URL) val, _ = a.Variable("variable_name") assert.Equal(t, "1", val) testServer.Close() // When bool response = `{"result": true}` testServer = getDummyResponseForPath(t, "/"+a.DeviceID+"/variable_name", response) a.setAPIServer(testServer.URL) val, _ = a.Variable("variable_name") assert.Equal(t, "true", val) testServer.Close() // When not existent response = `{"ok": false, "error": "Variable not found"}` testServer = getDummyResponseForPath(t, "/"+a.DeviceID+"/not_existent", response) a.setAPIServer(testServer.URL) _, err := a.Variable("not_existent") require.ErrorContains(t, err, "Variable not found") testServer.Close() } func TestAdaptorSetAPIServer(t *testing.T) { a := initTestAdaptor() apiServer := "new_api_server" assert.NotEqual(t, apiServer, a.APIServer) a.setAPIServer(apiServer) assert.Equal(t, apiServer, a.APIServer) } func TestAdaptorDeviceURL(t *testing.T) { // When APIServer is set a := initTestAdaptor() a.setAPIServer("http://server") a.DeviceID = "devID" assert.Equal(t, "http://server/v1/devices/devID", a.deviceURL()) // When APIServer is not set a = &Adaptor{name: "particleie", DeviceID: "myDevice", AccessToken: "token"} assert.Equal(t, "https://api.particle.io/v1/devices/myDevice", a.deviceURL()) } func TestAdaptorPinLevel(t *testing.T) { a := initTestAdaptor() assert.Equal(t, "HIGH", a.pinLevel(1)) assert.Equal(t, "LOW", a.pinLevel(0)) assert.Equal(t, "LOW", a.pinLevel(5)) } func TestAdaptorPostToparticle(t *testing.T) { a := initTestAdaptor() // When error on request vals := url.Values{} vals.Add("error", "error") resp, err := a.request("POST", "http://invalid%20host.com", vals) if err == nil { t.Error("request() should return an error when request was unsuccessful but returned", resp) } // When error reading body // Pending // When response.Status is not 200 testServer := createTestServer(func(w http.ResponseWriter, r *http.Request) { http.NotFound(w, r) }) defer testServer.Close() resp, err = a.request("POST", testServer.URL+"/existent", vals) if err == nil { t.Error("request() should return an error when status is not 200 but returned", resp) } } func TestAdaptorEventStream(t *testing.T) { a := initTestAdaptor() var url string eventSource = func(u string) (chan eventsource.Event, chan error, error) { url = u return nil, nil, nil } _, _ = a.EventStream("all", "ping") assert.Equal(t, "https://api.particle.io/v1/events/ping?access_token=token", url) _, _ = a.EventStream("devices", "ping") assert.Equal(t, "https://api.particle.io/v1/devices/events/ping?access_token=token", url) _, _ = a.EventStream("device", "ping") assert.Equal(t, "https://api.particle.io/v1/devices/myDevice/events/ping?access_token=token", url) _, err := a.EventStream("nothing", "ping") require.ErrorContains(t, err, "source param should be: all, devices or device") eventSource = func(u string) (chan eventsource.Event, chan error, error) { return nil, nil, errors.New("error connecting sse") } _, err = a.EventStream("devices", "") require.ErrorContains(t, err, "error connecting sse") eventChan := make(chan eventsource.Event) errorChan := make(chan error) eventSource = func(u string) (chan eventsource.Event, chan error, error) { return eventChan, errorChan, nil } _, err = a.EventStream("devices", "") require.NoError(t, err) } ================================================ FILE: platforms/particle/doc.go ================================================ /* Package particle provides the Gobot adaptor for the Particle Photon and Electron. Installing: Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) Example: package main import ( "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/particle" ) func main() { core := paticle.NewAdaptor("device_id", "access_token") led := gpio.NewLedDriver(core, "D7") work := func() { gobot.Every(1*time.Second, func() { if err := led.Toggle(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("particle", []gobot.Connection{core}, []gobot.Device{led}, work, ) if err := robot.Start(); err != nil { panic(err) } } For further information refer to Particle readme: https://github.com/hybridgroup/gobot/blob/release/platforms/particle/README.md */ package particle // import "gobot.io/x/gobot/v2/platforms/particle" ================================================ FILE: platforms/pebble/README.md ================================================ # Pebble This repository contains the Gobot adaptor for [Pebble smart watch](http://getpebble.com/). It uses the Pebble 2.0 SDK, and requires the 2.0 iOS or Android app, and that the ["watchbot" app](https://gobot.io/x/watchbot) has been installed on the Pebble watch. ## How to Install Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) * Install Pebble 2.0 iOS or Android app. (If you haven't already) * Follow README to install and configure "watchbot" on your watch: ## How to Use Before running the example, make sure configuration settings match with your program. In the example, api host is your computer IP, robot name is 'pebble' and robot api port is 8080 ```go package main import ( "fmt" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/api" "gobot.io/x/gobot/v2/platforms/pebble" ) func main() { manager := gobot.NewManager() api.NewAPI(manager).Start() pebbleAdaptor := pebble.NewAdaptor() watch := pebble.NewDriver(pebbleAdaptor) work := func() { watch.SendNotification("Hello Pebble!") watch.On(watch.Event("button"), func(data interface{}) { fmt.Println("Button pushed: " + data.(string)) }) watch.On(watch.Event("tap"), func(data interface{}) { fmt.Println("Tap event detected") }) } robot := gobot.NewRobot("pebble", []gobot.Connection{pebbleAdaptor}, []gobot.Device{watch}, work, ) manager.AddRobot(robot) if err := manager.Start(); err != nil { panic(err) } } ``` ## Supported Features * We support event detection of 3 main pebble buttons. * Accelerometer events * Pushing data to pebble watch ## Documentation We're busy adding documentation to our web site at please check there as we continue to work on Gobot Thank you! ## Contributing * All patches must be provided under the Apache 2.0 License * Please use the -s option in git to "sign off" that the commit is your work and you are providing it under the Apache 2.0 License * Submit a Github Pull Request to the appropriate branch and ideally discuss the changes with us in IRC. * We will look at the patch, test it out, and give you feedback. * Avoid doing minor whitespace changes, renamings, etc. along with merged content. These will be done by the maintainers from time to time but they can complicate merges and should be done seperately. * Take care to maintain the existing coding style. * Add unit tests for any new or changed functionality * All pull requests should be "fast forward" * If there are commits after yours use “git rebase -i ” * If you have local changes you may need to use “git stash” * For git help see [progit](http://git-scm.com/book) which is an awesome (and free) book on git ## License Copyright (c) 2013-2018 The Hybrid Group. Licensed under the Apache 2.0 license. ================================================ FILE: platforms/pebble/doc.go ================================================ /* Package pebble contains the Gobot adaptor and driver for Pebble smart watch. Installing: It requires the 2.x iOS or Android app, and "watchbot" app (https://gobot.io/x/watchbot) installed on Pebble watch. Then install running: Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) Example: Before running the example, make sure configuration settings match with your program. In the example, api host is your computer IP, robot name is 'pebble' and robot api port is 8080 package main import ( "fmt" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/api" "gobot.io/x/gobot/v2/platforms/pebble" ) func main() { manager := gobot.NewManager() api.NewAPI(manager).Start() pebbleAdaptor := pebble.NewAdaptor() watch := pebble.NewDriver(pebbleAdaptor) work := func() { watch.SendNotification("Hello Pebble!") watch.On(watch.Event("button"), func(data interface{}) { fmt.Println("Button pushed: " + data.(string)) }) watch.On(watch.Event("tap"), func(data interface{}) { fmt.Println("Tap event detected") }) } robot := gobot.NewRobot("pebble", []gobot.Connection{pebbleAdaptor}, []gobot.Device{watch}, work, ) manager.AddRobot(robot) if err := manager.Start(); err != nil { panic(err) } } For more information refer to the pebble README: https://github.com/hybridgroup/gobot/blob/release/platforms/pebble/README.md */ package pebble // import "gobot.io/x/gobot/v2/platforms/pebble" ================================================ FILE: platforms/pebble/pebble_adaptor.go ================================================ package pebble type Adaptor struct { name string } // NewAdaptor creates a new pebble adaptor func NewAdaptor() *Adaptor { return &Adaptor{ name: "Pebble", } } func (a *Adaptor) Name() string { return a.name } func (a *Adaptor) SetName(n string) { a.name = n } // Connect returns true if connection to pebble is established successfully func (a *Adaptor) Connect() error { return nil } // Finalize returns true if connection to pebble is finalized successfully func (a *Adaptor) Finalize() error { return nil } ================================================ FILE: platforms/pebble/pebble_adaptor_test.go ================================================ package pebble import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) var _ gobot.Adaptor = (*Adaptor)(nil) func initTestAdaptor() *Adaptor { return NewAdaptor() } func TestAdaptor(t *testing.T) { a := initTestAdaptor() assert.Equal(t, "Pebble", a.Name()) } func TestAdaptorConnect(t *testing.T) { a := initTestAdaptor() require.NoError(t, a.Connect()) } func TestAdaptorFinalize(t *testing.T) { a := initTestAdaptor() require.NoError(t, a.Finalize()) } ================================================ FILE: platforms/pebble/pebble_driver.go ================================================ package pebble import ( "gobot.io/x/gobot/v2" ) type Driver struct { gobot.Commander gobot.Eventer name string connection gobot.Connection Messages []string } // NewDriver creates a new pebble driver // Adds following events: // // button - Sent when a pebble button is pressed // accel - Pebble watch acceleromenter data // tab - When a pebble watch tap event is detected // // And the following API commands: // // "publish_event" // "send_notification" // "pending_message" func NewDriver(adaptor *Adaptor) *Driver { p := &Driver{ name: "Pebble", connection: adaptor, Messages: []string{}, Eventer: gobot.NewEventer(), Commander: gobot.NewCommander(), } p.AddEvent("button") p.AddEvent("accel") p.AddEvent("tap") //nolint:forcetypeassert // ok here p.AddCommand("publish_event", func(params map[string]interface{}) interface{} { p.PublishEvent(params["name"].(string), params["data"].(string)) return nil }) //nolint:forcetypeassert // ok here p.AddCommand("send_notification", func(params map[string]interface{}) interface{} { p.SendNotification(params["message"].(string)) return nil }) p.AddCommand("pending_message", func(_ map[string]interface{}) interface{} { return p.PendingMessage() }) return p } func (d *Driver) Name() string { return d.name } func (d *Driver) SetName(n string) { d.name = n } func (d *Driver) Connection() gobot.Connection { return d.connection } // Start returns true if driver is initialized correctly func (d *Driver) Start() error { return nil } // Halt returns true if driver is halted successfully func (d *Driver) Halt() error { return nil } // PublishEvent publishes event with specified name and data in gobot func (d *Driver) PublishEvent(name string, data string) { d.Publish(d.Event(name), data) } // SendNotification appends message to list of notifications to be sent to watch func (d *Driver) SendNotification(message string) string { d.Messages = append(d.Messages, message) return message } // PendingMessages returns messages to be sent as notifications to pebble // (Not intended to be used directly) func (d *Driver) PendingMessage() string { if len(d.Messages) < 1 { return "" } m := d.Messages[0] d.Messages = d.Messages[1:] return m } ================================================ FILE: platforms/pebble/pebble_driver_test.go ================================================ package pebble import ( "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) var _ gobot.Driver = (*Driver)(nil) func initTestDriver() *Driver { return NewDriver(NewAdaptor()) } func TestDriverStart(t *testing.T) { d := initTestDriver() require.NoError(t, d.Start()) } func TestDriverHalt(t *testing.T) { d := initTestDriver() require.NoError(t, d.Halt()) } func TestDriver(t *testing.T) { d := initTestDriver() assert.Equal(t, "Pebble", d.Name()) assert.Equal(t, "Pebble", d.Connection().Name()) sem := make(chan bool) d.SendNotification("Hello") d.SendNotification("World") assert.Equal(t, "Hello", d.Messages[0]) assert.Equal(t, "Hello", d.PendingMessage()) assert.Equal(t, "World", d.PendingMessage()) assert.Empty(t, d.PendingMessage()) _ = d.On(d.Event("button"), func(data interface{}) { sem <- true }) d.PublishEvent("button", "") select { case <-sem: case <-time.After(100 * time.Millisecond): require.Fail(t, "Button Event was not published") } _ = d.On(d.Event("accel"), func(data interface{}) { sem <- true }) d.Command("publish_event")(map[string]interface{}{"name": "accel", "data": "100"}) select { case <-sem: case <-time.After(100 * time.Millisecond): require.Fail(t, "Accel Event was not published") } d.Command("send_notification")(map[string]interface{}{"message": "Hey buddy!"}) assert.Equal(t, "Hey buddy!", d.Messages[0]) message := d.Command("pending_message")(map[string]interface{}{}) assert.Equal(t, "Hey buddy!", message) } ================================================ FILE: platforms/pine64/rock64/LICENSE ================================================ Copyright (c) 2025 The Hybrid Group Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: platforms/pine64/rock64/README.md ================================================ # Pine ROCK64 The Pine ROCK64 is a single board SoC computer based on the Rockchip RK3328 arm64 processor. It has built-in GPIO and I2C interfaces. SPI is most likely not usable (not tested), because in use by the SPI FLASH 128M memory chip. For more info about the Pine ROCK64, go to [https://pine64.org/documentation/ROCK64/](https://pine64.org/documentation/ROCK64/). ## How to Install Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) Tested OS: * [armbian](https://www.armbian.com/rock64/) with Debian ## Configuration steps for the OS ### System access and configuration basics Please follow the instructions of the OS provider. A ssh access is used in this guide. ```sh ssh @192.168.1.xxx ``` ### Enabling hardware drivers Not all drivers are enabled by default. You can have a look at the configuration file, to find out what is enabled at your system: ```sh cat /boot/armbianEnv.txt ``` ```sh sudo apt install armbian-config sudo armbian-config ``` ## How to Use The pin numbering used by your Gobot program should match the way your board is labeled right on the board itself. ```go r := rock64.NewAdaptor() led := gpio.NewLedDriver(r, "7") ``` ## How to Connect ### Compiling Compile your Gobot program on your workstation like this: ```sh GOARCH=arm64 GOOS=linux go build -o output/ examples/rock64_blink.go ``` Once you have compiled your code, you can upload your program and execute it on the board from your workstation using the `scp` and `ssh` commands like this: ```sh scp rock64_blink @192.168.1.xxx:~ ssh -t @192.168.1.xxx "./rock64_blink" ``` ## Troubleshooting ### I2C-0 overlay With the armbian-config sometimes the overlays can not properly applied (different open Bugs). To ensure your overlay is applied have a look into your /boot/boot.cmd and search for the name of the used shell variable(s). This name needs to be used in your /boot/armbianEnv.txt. ```sh cat /boot/boot.cmd | grep overlay_file for overlay_file in ${overlays}; do if load ${devtype} ${devnum}:${distro_bootpart} ${load_addr} ${prefix}dtb/rockchip/overlay/${overlay_prefix}-${overlay_file}.dtbo; then echo "Applying kernel provided DT overlay ${overlay_prefix}-${overlay_file}.dtbo" for overlay_file in ${user_overlays}; do if load ${devtype} ${devnum}:${distro_bootpart} ${load_addr} ${prefix}overlay-user/${overlay_file}.dtbo; then echo "Applying user provided DT overlay ${overlay_file}.dtbo" ``` In the example above the variable is named `overlays`. So your /boot/armbianEnv.txt must contain this variable. ```sh cat /boot/armbianEnv.txt | grep overlay overlay_prefix=rockchip overlays=rk3328-i2c0 ``` In some buggy versions the variable is named "fdt_overlays", just rename the variable in your "armbianEnv.txt" to match the boot script. As you can see in the boot script, the real file name is a concatenate of different variables `${overlay_prefix}-${overlay_file}.dtbo`. This file must exist in the folder `${prefix}dtb/rockchip/overlay` (prefix="/boot/"). So for the i2c-0 overlay: ```sh ls -la /boot/dtb/rockchip/overlay/ | grep i2c0 -rw-r--r-- 1 root root 218 Nov 25 19:15 rockchip-rk3328-i2c0.dtbo -rw-r--r-- 1 root root 223 Nov 25 19:15 rockchip-rk3568-hk-i2c0.dtbo ``` ...means the entry in the armbianEnv.txt sould be set to "overlays=rk3328-i2c0". The variable can contain a space separated list. ### PWM There are 3 PWMs on the chip (pwm0, pwm1, pwm2). Unfortunately all pins are shared with the PMIC, so i2c-1 (pwm0, pwm1) can not be deactivated, because it is mandatory for the i2c communication to PMIC address 0x18. Simply an activation of pwm0 or pwm1 with an overlay leads to the Kernel can not be loaded anymore. ================================================ FILE: platforms/pine64/rock64/adaptor.go ================================================ package rock64 import ( "fmt" "sync" multierror "github.com/hashicorp/go-multierror" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/adaptors" "gobot.io/x/gobot/v2/system" ) const ( defaultI2cBusNumber = 1 defaultSpiBusNumber = 0 defaultSpiChipNumber = 0 defaultSpiMode = 0 defaultSpiBitsNumber = 8 defaultSpiMaxSpeed = 500000 ) // Adaptor represents a Gobot Adaptor for the PINE64 ROCK64 type Adaptor struct { *adaptors.AnalogPinsAdaptor *adaptors.DigitalPinsAdaptor *adaptors.I2cBusAdaptor *adaptors.SpiBusAdaptor name string sys *system.Accesser // used for unit tests only mutex *sync.Mutex } // NewAdaptor creates a ROCK64 Adaptor // // Optional parameters: // // adaptors.WithGpioSysfsAccess(): use legacy sysfs driver instead of default character device driver // adaptors.WithSpiGpioAccess(sclk, ncs, sdo, sdi): use GPIO's instead of /dev/spidev#.# // adaptors.WithGpiosActiveLow(pin's): invert the pin behavior // adaptors.WithGpiosPullUp/Down(pin's): sets the internal pull resistor // adaptors.WithGpiosOpenDrain/Source(pin's): sets the output behavior // adaptors.WithGpioDebounce(pin, period): sets the input debouncer // adaptors.WithGpioEventOnFallingEdge/RaisingEdge/BothEdges(pin, handler): activate edge detection // // Further optional parameters for: // // AIO, see [adaptors.NewAnalogPinsAdaptor] // GPIO, see [adaptors.NewDigitalPinsAdaptor] // I2C, see [adaptors.NewI2cBusAdaptor] // SPI, see [adaptors.NewSpiBusAdaptor] func NewAdaptor(opts ...interface{}) *Adaptor { sys := system.NewAccesser() a := &Adaptor{ name: gobot.DefaultName("ROCK64"), sys: sys, mutex: &sync.Mutex{}, } var analogPinsOpts []adaptors.AnalogPinsOptionApplier var digitalPinsOpts []adaptors.DigitalPinsOptionApplier var i2cBusOpts []adaptors.I2CBusOptionApplier var spiBusOpts []adaptors.SpiBusOptionApplier for _, opt := range opts { switch o := opt.(type) { case adaptors.AnalogPinsOptionApplier: analogPinsOpts = append(analogPinsOpts, o) case adaptors.DigitalPinsOptionApplier: digitalPinsOpts = append(digitalPinsOpts, o) case adaptors.I2CBusOptionApplier: i2cBusOpts = append(i2cBusOpts, o) case adaptors.SpiBusOptionApplier: spiBusOpts = append(spiBusOpts, o) default: panic(fmt.Sprintf("'%s' can not be applied on adaptor '%s'", opt, a.name)) } } analogPinTranslator := adaptors.NewAnalogPinTranslator(sys, analogPinDefinitions) digitalPinTranslator := adaptors.NewDigitalPinTranslator(sys, gpioPinDefinitions) // Valid bus numbers are [0,1] which corresponds to /dev/i2c-0, /dev/i2c-1. // We don't support "/dev/i2c-4 DesignWare HDMI". i2cBusNumberValidator := adaptors.NewBusNumberValidator([]int{0, 1}) // Valid bus number is 0 which corresponds to /dev/spidev0.x // x is the chip number <255 spiBusNumberValidator := adaptors.NewBusNumberValidator([]int{0}) a.AnalogPinsAdaptor = adaptors.NewAnalogPinsAdaptor(sys, analogPinTranslator.Translate, analogPinsOpts...) a.DigitalPinsAdaptor = adaptors.NewDigitalPinsAdaptor(sys, digitalPinTranslator.Translate, digitalPinsOpts...) a.I2cBusAdaptor = adaptors.NewI2cBusAdaptor(sys, i2cBusNumberValidator.Validate, defaultI2cBusNumber, i2cBusOpts...) a.SpiBusAdaptor = adaptors.NewSpiBusAdaptor(sys, spiBusNumberValidator.Validate, defaultSpiBusNumber, defaultSpiChipNumber, defaultSpiMode, defaultSpiBitsNumber, defaultSpiMaxSpeed, a.DigitalPinsAdaptor, spiBusOpts...) return a } // Name returns the name of the Adaptor func (a *Adaptor) Name() string { return a.name } // SetName sets the name of the Adaptor func (a *Adaptor) SetName(n string) { a.name = n } // Connect create new connection to board and pins. func (a *Adaptor) Connect() error { a.mutex.Lock() defer a.mutex.Unlock() if err := a.SpiBusAdaptor.Connect(); err != nil { return err } if err := a.I2cBusAdaptor.Connect(); err != nil { return err } if err := a.AnalogPinsAdaptor.Connect(); err != nil { return err } return a.DigitalPinsAdaptor.Connect() } // Finalize closes connection to board, pins and bus func (a *Adaptor) Finalize() error { a.mutex.Lock() defer a.mutex.Unlock() err := a.DigitalPinsAdaptor.Finalize() if e := a.AnalogPinsAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } if e := a.I2cBusAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } if e := a.SpiBusAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } return err } ================================================ FILE: platforms/pine64/rock64/adaptor_test.go ================================================ package rock64 import ( "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/adaptors" "gobot.io/x/gobot/v2/system" ) // make sure that this Adaptor fulfills all the required interfaces var ( _ gobot.Adaptor = (*Adaptor)(nil) _ gobot.DigitalPinnerProvider = (*Adaptor)(nil) _ gpio.DigitalReader = (*Adaptor)(nil) _ gpio.DigitalWriter = (*Adaptor)(nil) _ aio.AnalogReader = (*Adaptor)(nil) _ i2c.Connector = (*Adaptor)(nil) ) func initConnectedTestAdaptorWithMockedFilesystem(mockPaths []string) (*Adaptor, *system.MockFilesystem) { a := initConnectedTestAdaptor() fs := a.sys.UseMockFilesystem(mockPaths) return a, fs } func initConnectedTestAdaptor() *Adaptor { a := NewAdaptor() if err := a.Connect(); err != nil { panic(err) } return a } func TestNewAdaptor(t *testing.T) { // arrange & act a := NewAdaptor() // assert assert.IsType(t, &Adaptor{}, a) assert.True(t, strings.HasPrefix(a.Name(), "ROCK64")) assert.NotNil(t, a.sys) assert.NotNil(t, a.mutex) assert.NotNil(t, a.AnalogPinsAdaptor) assert.NotNil(t, a.DigitalPinsAdaptor) assert.NotNil(t, a.I2cBusAdaptor) assert.NotNil(t, a.SpiBusAdaptor) assert.True(t, a.sys.HasDigitalPinCdevAccess()) // act & assert a.SetName("NewName") assert.Equal(t, "NewName", a.Name()) } func TestNewAdaptorWithOption(t *testing.T) { // arrange & act a := NewAdaptor(adaptors.WithGpiosActiveLow("1"), adaptors.WithGpioSysfsAccess()) // assert require.NoError(t, a.Connect()) assert.True(t, a.sys.HasDigitalPinSysfsAccess()) } func TestDigitalIO(t *testing.T) { // some basic tests, further tests are done in "digitalpinsadaptor.go" // arrange a := initConnectedTestAdaptor() dpa := a.sys.UseMockDigitalPinAccess() require.True(t, a.sys.HasDigitalPinCdevAccess()) // act & assert write err := a.DigitalWrite("7", 1) require.NoError(t, err) assert.Equal(t, []int{1}, dpa.Written("gpiochip1", "28")) // arrange, act & assert read dpa.UseValues("gpiochip2", "1", []int{3}) i, err := a.DigitalRead("10") require.NoError(t, err) assert.Equal(t, 3, i) // act and assert unknown pin require.ErrorContains(t, a.DigitalWrite("99", 1), "'99' is not a valid id for a digital pin") // act and assert finalize require.NoError(t, a.Finalize()) assert.Equal(t, 0, dpa.Exported("gpiochip1", "28")) assert.Equal(t, 0, dpa.Exported("gpiochip2", "1")) } func TestDigitalIOSysfs(t *testing.T) { // some basic tests, further tests are done in "digitalpinsadaptor.go" // arrange a := NewAdaptor(adaptors.WithGpioSysfsAccess()) require.NoError(t, a.Connect()) dpa := a.sys.UseMockDigitalPinAccess() require.True(t, a.sys.HasDigitalPinSysfsAccess()) // act & assert write err := a.DigitalWrite("7", 1) require.NoError(t, err) assert.Equal(t, []int{1}, dpa.Written("", "60")) // arrange, act & assert read dpa.UseValues("", "65", []int{4}) i, err := a.DigitalRead("10") require.NoError(t, err) assert.Equal(t, 4, i) // act and assert unknown pin require.ErrorContains(t, a.DigitalWrite("99", 1), "'99' is not a valid id for a digital pin") // act and assert finalize require.NoError(t, a.Finalize()) assert.Equal(t, 0, dpa.Exported("", "60")) assert.Equal(t, 0, dpa.Exported("", "65")) } func TestAnalogRead(t *testing.T) { mockPaths := []string{ "/sys/class/thermal/thermal_zone0/temp", } a, fs := initConnectedTestAdaptorWithMockedFilesystem(mockPaths) fs.Files["/sys/class/thermal/thermal_zone0/temp"].Contents = "567\n" got, err := a.AnalogRead("thermal_zone0") require.NoError(t, err) assert.Equal(t, 567, got) _, err = a.AnalogRead("thermal_zone10") require.ErrorContains(t, err, "'thermal_zone10' is not a valid id for an analog pin") fs.WithReadError = true _, err = a.AnalogRead("thermal_zone0") require.ErrorContains(t, err, "read error") fs.WithReadError = false require.NoError(t, a.Finalize()) } func TestFinalizeErrorAfterGPIO(t *testing.T) { // arrange a := initConnectedTestAdaptor() dpa := a.sys.UseMockDigitalPinAccess() require.True(t, a.sys.HasDigitalPinCdevAccess()) require.NoError(t, a.DigitalWrite("7", 1)) dpa.UseUnexportError("gpiochip1", "28") // act err := a.Finalize() // assert require.ErrorContains(t, err, "unexport error") } func TestSpiDefaultValues(t *testing.T) { a := NewAdaptor() assert.Equal(t, 0, a.SpiDefaultBusNumber()) assert.Equal(t, 0, a.SpiDefaultChipNumber()) assert.Equal(t, 0, a.SpiDefaultMode()) assert.Equal(t, 8, a.SpiDefaultBitCount()) assert.Equal(t, int64(500000), a.SpiDefaultMaxSpeed()) } func TestI2cDefaultBus(t *testing.T) { a := NewAdaptor() assert.Equal(t, 1, a.DefaultI2cBus()) } func TestI2cFinalizeWithErrors(t *testing.T) { // arrange a := initConnectedTestAdaptor() a.sys.UseMockSyscall() fs := a.sys.UseMockFilesystem([]string{"/dev/i2c-1"}) con, err := a.GetI2cConnection(0xff, 1) require.NoError(t, err) _, err = con.Write([]byte{0xbf}) require.NoError(t, err) fs.WithCloseError = true // act err = a.Finalize() // assert require.ErrorContains(t, err, "close error") } ================================================ FILE: platforms/pine64/rock64/doc.go ================================================ /* Package rock64 contains the Gobot adaptor for the PINE64 ROCK64. For further information refer to the boards README: https://github.com/hybridgroup/gobot/blob/release/platforms/pine64/rock64/README.md */ package rock64 // import "gobot.io/x/gobot/v2/platforms/pin64/rock64" ================================================ FILE: platforms/pine64/rock64/pinmap.go ================================================ package rock64 import "gobot.io/x/gobot/v2/platforms/adaptors" // notes for character device // sysfs: Chip*32 + (A=0, B=8, C=16) + Nr // tested with cdev on a ROCK64 V2.0 board: armbian Linux, OK: works, ?: unknown, NOK: not working // IN: works only as input, PU: if used as input, external pullup resistor needed // PM: pins are shared with the PMIC i2c communication (address 0x13), GPIO seems to work but problems can occur // // pin suffix: // "P5": those pins are located on the second pin header "P5+BUS" // "SD": those pins should be used with caution and only if eMMC is used and no SD card is inserted // "M2": those pins are used by the SPI FLASH 128M memory chip, but not blocked and maybe work, if unsure don't use it // "SDA/SCL": see PM above, should only used for i2c-1 var gpioPinDefinitions = adaptors.DigitalPinDefinitions{ "13": {Sysfs: 0, Cdev: adaptors.CdevPin{Chip: 0, Line: 0}}, // GPIO0_A0 - OK "P5_13": {Sysfs: 27, Cdev: adaptors.CdevPin{Chip: 0, Line: 27}}, // GPIO0_D3_SPDIF_TX_M0 - OK "33_SD": {Sysfs: 32, Cdev: adaptors.CdevPin{Chip: 1, Line: 0}}, // GPIO1_A0_SDMMC0_D0 - ? "35_SD": {Sysfs: 33, Cdev: adaptors.CdevPin{Chip: 1, Line: 1}}, // GPIO1_A1_SDMMC0_D1 - ? "37_SD": {Sysfs: 34, Cdev: adaptors.CdevPin{Chip: 1, Line: 2}}, // GPIO1_A2_SDMMC0_D2_JTAG_TCK - ? "40_SD": {Sysfs: 35, Cdev: adaptors.CdevPin{Chip: 1, Line: 3}}, // GPIO1_A3_SDMMC0_D3_JTAG_TMS - ? "38_SD": {Sysfs: 36, Cdev: adaptors.CdevPin{Chip: 1, Line: 4}}, // GPIO1_A4_SDMMC0_CMD - ? "36_SD": {Sysfs: 37, Cdev: adaptors.CdevPin{Chip: 1, Line: 5}}, // GPIO1_A5_SDMMC0_DET - ? "32_SD": {Sysfs: 38, Cdev: adaptors.CdevPin{Chip: 1, Line: 6}}, // GPIO1_A6_SDMMC0_CLK - ? "7": {Sysfs: 60, Cdev: adaptors.CdevPin{Chip: 1, Line: 28}}, // GPIO1_D4_CLK32KOUT_M1 - OK (PU) "8": {Sysfs: 64, Cdev: adaptors.CdevPin{Chip: 2, Line: 0}}, // GPIO2_A0_UART2_TX_M1 - OK (PU) "10": {Sysfs: 65, Cdev: adaptors.CdevPin{Chip: 2, Line: 1}}, // GPIO2_A1_UART2_RX_M1 - OK "12": {Sysfs: 67, Cdev: adaptors.CdevPin{Chip: 2, Line: 3}}, // GPIO2_A3 - IN "27_SDA": {Sysfs: 68, Cdev: adaptors.CdevPin{Chip: 2, Line: 4}}, // GPIO2_A4_I2C1_SDA - PM "28_SCL": {Sysfs: 69, Cdev: adaptors.CdevPin{Chip: 2, Line: 5}}, // GPIO2_A5_I2C1_SCL - PM "26": {Sysfs: 76, Cdev: adaptors.CdevPin{Chip: 2, Line: 12}}, // GPIO2_B4_SPI_CSN1_M0 - OK "P5_10": {Sysfs: 79, Cdev: adaptors.CdevPin{Chip: 2, Line: 15}}, // GPIO2_B7_I2S1_MCLK - OK (PU) "P5_9": {Sysfs: 80, Cdev: adaptors.CdevPin{Chip: 2, Line: 16}}, // GPIO2_C0_I2S1_LRCKRX - OK "P5_3": {Sysfs: 81, Cdev: adaptors.CdevPin{Chip: 2, Line: 17}}, // GPIO2_C1_I2S1_LRCKTX - OK "P5_4": {Sysfs: 82, Cdev: adaptors.CdevPin{Chip: 2, Line: 18}}, // GPIO2_C2_I2S1_SCLK - OK (PU) "P5_6": {Sysfs: 83, Cdev: adaptors.CdevPin{Chip: 2, Line: 19}}, // GPIO2_C3_I2S1_SDI - OK "P5_12": {Sysfs: 84, Cdev: adaptors.CdevPin{Chip: 2, Line: 20}}, // GPIO2_C4_I2S1_SDIO1 - OK "P5_11": {Sysfs: 85, Cdev: adaptors.CdevPin{Chip: 2, Line: 21}}, // GPIO2_C5_I2S1_SDIO2 - OK "P5_14": {Sysfs: 86, Cdev: adaptors.CdevPin{Chip: 2, Line: 22}}, // GPIO2_C6_I2S1_SDIO3 - OK "P5_5": {Sysfs: 87, Cdev: adaptors.CdevPin{Chip: 2, Line: 23}}, // GPIO2_C7_I2S1_SDO - OK "5": {Sysfs: 88, Cdev: adaptors.CdevPin{Chip: 2, Line: 24}}, // GPIO2_D0_I2C0_SCL_EthernetLink (P5_22) - OK "P5_22": {Sysfs: 88, Cdev: adaptors.CdevPin{Chip: 2, Line: 24}}, // GPIO2_D0_I2C0_SCL_EthernetLink (P5_22) - OK "3": {Sysfs: 89, Cdev: adaptors.CdevPin{Chip: 2, Line: 25}}, // GPIO2_D1_I2C0_SDA_EthernetSpeed (P5_21) - OK "P5_21": {Sysfs: 89, Cdev: adaptors.CdevPin{Chip: 2, Line: 25}}, // GPIO2_D1_I2C0_SDA_EthernetSpeed (P5_21) - OK "23_M2": {Sysfs: 96, Cdev: adaptors.CdevPin{Chip: 3, Line: 0}}, // GPIO3_A0_SPI_CLK_M2 - NOK "19_M2": {Sysfs: 97, Cdev: adaptors.CdevPin{Chip: 3, Line: 1}}, // GPIO3_A1_SPI_TXD_M2 - OK "21_M2": {Sysfs: 98, Cdev: adaptors.CdevPin{Chip: 3, Line: 2}}, // GPIO3_A2_SPI_RXD_M2 - OK "15": {Sysfs: 100, Cdev: adaptors.CdevPin{Chip: 3, Line: 4}}, // GPIO3_A4 - OK "16": {Sysfs: 101, Cdev: adaptors.CdevPin{Chip: 3, Line: 5}}, // GPIO3_A5 - OK "18": {Sysfs: 102, Cdev: adaptors.CdevPin{Chip: 3, Line: 6}}, // GPIO3_A6 - OK "22": {Sysfs: 103, Cdev: adaptors.CdevPin{Chip: 3, Line: 7}}, // GPIO3_A7 - OK "24_M2": {Sysfs: 104, Cdev: adaptors.CdevPin{Chip: 3, Line: 8}}, // GPIO3_B0_SPI_CSN0_M2 - NOK } var analogPinDefinitions = adaptors.AnalogPinDefinitions{ // +/-273.200 °C need >=7 characters to read: +/-273200 millidegree Celsius "thermal_zone0": {Path: "/sys/class/thermal/thermal_zone0/temp", W: false, ReadBufLen: 7}, } ================================================ FILE: platforms/radxa/rockpi/LICENSE ================================================ Copyright (c) 2014-2018 The Hybrid Group Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: platforms/radxa/rockpi/README.md ================================================ # Radxa Rock Pi The [Radxa Rock Pi board series](https://wiki.radxa.com/Rock4/getting_started) are clones of the popular Raspberry Pi Single Board Computers (SBCs) with GPIO/PWM/I2C functionalities built-in. The Gobot adaptor is currently compatible with: - Rock Pi 4 - Rock Pi 4C+ With the possibility to expand its compatibility into past and future models. Check out the output of `cat /proc/device-tree/model` to see which model you have if you're not sure. The 4C+ model has a Rockchip 3399_T SoC, while the regular 4 has the 3399. Both are similar, but have slightly different GPIO pin configurations. ## How to Install Make sure you've installed an official Linux image from Radxa with working drivers. See the [ROCK 4 Installation Wiki](https://wiki.radxa.com/Rock4/install) for your SBC setup. > Some versions or Armbian ISOs do not detect the newer SoC chips. As for your Gobot development, treat this as a regular Go package. It can be cross-compiled and copied over, or simply compiled on the SBC itself (tested and working with go 1.15.15 on linux/arm64, RockPi4C+). ## How to Use The pin numbering used by your Gobot program should match the way your board is labeled right on the board itself. That is, follow the **colored Pin# numbers** in the middle in the [GPIO mapping Wiki](https://wiki.radxa.com/Rock4/hardware/gpio). These have been translated for you into their corresponding underlying GPIO numbers. ```go package main import ( "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/radxa/rockpi" ) func main() { r := rockpi.NewAdaptor() led := gpio.NewLedDriver(r, "7") work := func() { gobot.Every(1*time.Second, func() { if err := led.Toggle(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("blinkBot", []gobot.Connection{r}, []gobot.Device{led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ``` If you want to use I2C, RockPi4 offers three I2C buses: I2C2 (pins 27, 28), I2C6 (pins 29, 31) and I2C7 (pins 3, 5) of which I2C7 is the default. Changing this is a matter of passing the right bus number using `i2c.WithBus`: ```go a := rockpi.NewAdaptor() adc2 := i2c.NewADS1115Driver(a, i2c.WithBus(6)) ``` There are mapped to `/dev/i2c-[bus]`, just like the Gobot raspi implementation. ### What's currently supported? - General digital pin GPIO access works, but not through the new character device driver. - The I2C buses 2, 6, 7 work - SPI buses 1, 2 work PWM interaction is currently not yet supported. Please see the [official Radxa Rock Pi documentation](https://wiki.radxa.com/Rockpi4/dev/libmraa) on how `librmaa` can be utilized in combination with this module, and how these work. ### Compiling Compile your Gobot program on your workstation like this: ```bash $ GOARCH=arm64 GOOS=linux go build examples/rockpi_blink.go ``` Rock Pi 4s are ARM64 machines. ================================================ FILE: platforms/radxa/rockpi/adaptor.go ================================================ package rockpi import ( "errors" "fmt" "sync" multierror "github.com/hashicorp/go-multierror" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/adaptors" "gobot.io/x/gobot/v2/system" ) const ( procDeviceTreeModel = "/proc/device-tree/model" defaultI2cBusNumber = 7 defaultSpiBusNumber = 1 defaultSpiChipNumber = 0 defaultSpiMode = 0 defaultSpiBitsNumber = 8 defaultSpiMaxSpeed = 500000 ) // Adaptor is the Gobot Adaptor for Radxa's Rock Pi. type Adaptor struct { *adaptors.DigitalPinsAdaptor *adaptors.I2cBusAdaptor *adaptors.SpiBusAdaptor name string mutex sync.Mutex sys *system.Accesser revision string } // NewAdaptor creates a RockPi Adaptor // Do not forget to enable the required overlays in /boot/hw_initfc.conf! // See https://wiki.radxa.com/Rockpi4/dev/libmraa // // Optional parameters: // // adaptors.WithGpioCdevAccess(): use character device driver instead of the default sysfs (NOT work on RockPi4C+!) // adaptors.WithSpiGpioAccess(sclk, ncs, sdo, sdi): use GPIO's instead of /dev/spidev#.# // adaptors.WithGpiosActiveLow(pin's): invert the pin behavior // // Further optional parameters for: // // GPIO, see [adaptors.NewDigitalPinsAdaptor] // I2C, see [adaptors.NewI2cBusAdaptor] // SPI, see [adaptors.NewSpiBusAdaptor] func NewAdaptor(opts ...interface{}) *Adaptor { sys := system.NewAccesser(system.WithDigitalPinSysfsAccess()) a := &Adaptor{ name: gobot.DefaultName("RockPi"), sys: sys, } var digitalPinsOpts []adaptors.DigitalPinsOptionApplier var i2cBusOpts []adaptors.I2CBusOptionApplier var spiBusOpts []adaptors.SpiBusOptionApplier for _, opt := range opts { switch o := opt.(type) { case adaptors.DigitalPinsOptionApplier: digitalPinsOpts = append(digitalPinsOpts, o) case adaptors.I2CBusOptionApplier: i2cBusOpts = append(i2cBusOpts, o) case adaptors.SpiBusOptionApplier: spiBusOpts = append(spiBusOpts, o) default: panic(fmt.Sprintf("'%s' can not be applied on adaptor '%s'", opt, a.name)) } } // The RockPi4 has 3 I2C buses: 2, 6, 7. See https://wiki.radxa.com/Rock4/hardware/gpio // This could change in the future with other revisions! i2cBusNumberValidator := adaptors.NewBusNumberValidator([]int{2, 6, 7}) // The RockPi4 has 2 SPI buses: 1, 2. See https://wiki.radxa.com/Rock4/hardware/gpio // This could change in the future with other revisions! spiBusNumberValidator := adaptors.NewBusNumberValidator([]int{1, 2}) a.DigitalPinsAdaptor = adaptors.NewDigitalPinsAdaptor(sys, a.getPinTranslatorFunction(), digitalPinsOpts...) a.I2cBusAdaptor = adaptors.NewI2cBusAdaptor(sys, i2cBusNumberValidator.Validate, defaultI2cBusNumber, i2cBusOpts...) a.SpiBusAdaptor = adaptors.NewSpiBusAdaptor(sys, spiBusNumberValidator.Validate, defaultSpiBusNumber, defaultSpiChipNumber, defaultSpiMode, defaultSpiBitsNumber, defaultSpiMaxSpeed, a.DigitalPinsAdaptor, spiBusOpts...) return a } // Name returns the adaptors name func (a *Adaptor) Name() string { a.mutex.Lock() defer a.mutex.Unlock() return a.name } // SetName sets the adaptors name func (a *Adaptor) SetName(n string) { a.mutex.Lock() defer a.mutex.Unlock() a.name = n } // Connect create new connection to board and pins. func (a *Adaptor) Connect() error { a.mutex.Lock() defer a.mutex.Unlock() if err := a.SpiBusAdaptor.Connect(); err != nil { return err } if err := a.I2cBusAdaptor.Connect(); err != nil { return err } return a.DigitalPinsAdaptor.Connect() } // Finalize closes connection to board and pins func (a *Adaptor) Finalize() error { a.mutex.Lock() defer a.mutex.Unlock() err := a.DigitalPinsAdaptor.Finalize() if e := a.I2cBusAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } if e := a.SpiBusAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } return err } func (a *Adaptor) getPinTranslatorFunction() func(string) (string, int, error) { return func(pin string) (string, int, error) { var line int if val, ok := pins[pin][a.readRevision()]; ok { line = val } else if val, ok := pins[pin]["*"]; ok { line = val } else { return "", 0, errors.New("not a valid pin") } return "", line, nil } } func (a *Adaptor) readRevision() string { if a.revision == "" { content, err := a.sys.ReadFile(procDeviceTreeModel) if err != nil { return a.revision } model := string(content) switch model { case "Radxa ROCK 4": a.revision = "4" case "Radxa ROCK 4C+": a.revision = "4C+" default: a.revision = "4" } } return a.revision } ================================================ FILE: platforms/radxa/rockpi/adaptor_test.go ================================================ package rockpi import ( "fmt" "strings" "testing" "github.com/stretchr/testify/assert" "gobot.io/x/gobot/v2/system" ) func initConnectedTestAdaptorWithMockedFilesystem(mockPaths []string) (*Adaptor, *system.MockFilesystem) { a := NewAdaptor() fs := a.sys.UseMockFilesystem(mockPaths) _ = a.Connect() return a, fs } func TestNewAdaptor(t *testing.T) { // arrange & act a := NewAdaptor() // assert assert.IsType(t, &Adaptor{}, a) assert.True(t, strings.HasPrefix(a.Name(), "RockPi")) assert.NotNil(t, a.sys) assert.NotNil(t, a.DigitalPinsAdaptor) assert.NotNil(t, a.I2cBusAdaptor) assert.NotNil(t, a.SpiBusAdaptor) assert.True(t, a.sys.HasDigitalPinSysfsAccess()) // act & assert a.SetName("NewName") assert.Equal(t, "NewName", a.Name()) } func TestDefaultI2cBus(t *testing.T) { a, _ := initConnectedTestAdaptorWithMockedFilesystem([]string{}) assert.Equal(t, 7, a.DefaultI2cBus()) } func Test_getPinTranslatorFunction(t *testing.T) { cases := map[string]struct { pin string model string expectedLine int expectedErr error }{ "Rock Pi 4 specific pin": { pin: "12", model: "Radxa ROCK 4", expectedLine: 131, expectedErr: nil, }, "Rock Pi 4C+ specific pin": { pin: "12", model: "Radxa ROCK 4C+", expectedLine: 91, expectedErr: nil, }, "Generic pin": { pin: "3", model: "whatever", expectedLine: 71, expectedErr: nil, }, "Not a valid pin": { pin: "666", model: "whatever", expectedLine: 0, expectedErr: fmt.Errorf("not a valid pin"), }, } for name, tc := range cases { t.Run(name, func(t *testing.T) { // arrange a := NewAdaptor() fn := a.getPinTranslatorFunction() fs := a.sys.UseMockFilesystem([]string{procDeviceTreeModel}) fs.Files[procDeviceTreeModel].Contents = tc.model // act chip, line, err := fn(tc.pin) // assert assert.Empty(t, chip) assert.Equal(t, tc.expectedErr, err) assert.Equal(t, tc.expectedLine, line) }) } } ================================================ FILE: platforms/radxa/rockpi/doc.go ================================================ /* Package rockpi contains the Gobot adaptor for Radxa's Rock Pi Single Board Computers. For further information refer to rockpi README: https://github.com/hybridgroup/gobot/blob/release/platforms/radxa/rockpi/README.md */ package rockpi // import "gobot.io/x/gobot/v2/platforms/radxa/rockpi" ================================================ FILE: platforms/radxa/rockpi/pinmap.go ================================================ package rockpi // See https://wiki.radxa.com/Rock4/hardware/gpio. var pins = map[string]map[string]int{ "3": { "*": 71, }, "5": { "*": 72, }, "7": { "*": 75, }, "8": { "*": 148, }, "10": { "*": 147, }, "11": { "*": 146, }, "12": { "4": 131, "4C+": 91, }, "13": { "4": 150, "4C+": 33, }, "15": { "*": 149, }, "16": { "*": 154, }, "18": { "*": 156, }, "19": { "*": 40, }, "21": { "*": 39, }, "22": { "*": 157, }, "23": { "*": 41, }, "24": { "*": 42, }, "27": { "*": 64, }, "28": { "*": 65, }, "29": { "*": 74, }, "31": { "*": 73, }, "32": { "*": 112, }, "33": { "*": 76, }, "35": { "*": 133, }, "36": { "4": 132, "4C+": 92, }, "37": { "*": 158, }, "38": { "4": 134, "4C+": 36, }, "40": { "4": 135, "4C+": 52, }, } ================================================ FILE: platforms/radxa/zero/LICENSE ================================================ Copyright (c) 2025 The Hybrid Group Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: platforms/radxa/zero/README.md ================================================ # Radxa Zero The Radxa Zero is a single board SoC computer based on the Amlogic S905Y2 arm64 processor. It has built-in GPIO, I2C, PWM, SPI, 1-Wire and ADC interfaces. For more info about the Radxa Zero, go to [https://docs.radxa.com/en/zero/zero](https://docs.radxa.com/en/zero/zero). ## How to Install Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) Tested OS: * [dietPi](https://dietpi.com/downloads/images/DietPi_RadxaZero-ARMv8-Bookworm.img.xz) a minimal image with Debian Bookworm ## Configuration steps for the OS ### WLAN access There is no LAN network interface on the board, but WLAN is sufficient for our needs. After copy over the image to your SD card you can modify the file dietpi.txt before plug in the card to [make it work on first boot](https://dietpi.com/docs/usage/#how-to-do-an-automatic-base-installation-at-first-boot-dietpi-automation). ```txt adjust dietpi.txt to your needs AUTO_SETUP_NET_WIFI_ENABLED=1 AUTO_SETUP_NET_WIFI_COUNTRY_CODE=DE ``` Afterwards the WiFi login data needs to be provided (unencrypted file, will be removed after first boot): ```txt adjust dietpi-wifi.txt aWIFI_SSID[0]="" aWIFI_KEY[0]="" ``` First login needs to be done with "root" or "dietpi", and you will start with a configuration procedure. ```sh ssh root@DietPi ``` ### System access and configuration basics Please follow the instructions of the OS provider. A ssh access for (WLAN with dietpi user) is used in this guide. ```sh ssh dietpi@DietPi ``` ### Enabling hardware drivers in general Not all drivers are enabled by default. You can have a look at the configuration file, to find out what is enabled at your system: ```sh cat /boot/dietpiEnv.txt ``` Missing interfaces needs to be enabled by DT-overlays (drop "meson" prefix and file extension). ```sh list available overlays ls /boot/dtb/amlogic/overlay/ ``` Please read [this GPIO page](https://wiki.radxa.com/Zero/hardware/gpio.) for meaning of the different part of file name (e.g. "ao" vs. "ee"). The [page about overlays](https://wiki.radxa.com/Device-tree-overlays#Meson_G12A_Available_Overlay_.28Radxa_Zero.29) will help you in addition to choose the right one. ### enable I2C | device |SDA|SCL|DT overlay file name| |----------|---|---|--------------------| |/dev/i2c-1| 16| 13|meson-g12a-radxa-zero-i2c-ee-m1-gpiox-10-gpiox-11.dtbo| |/dev/i2c-1| 24| 23|meson-g12a-radxa-zero-i2c-ee-m1-gpioh-6-gpioh-7.dtbo| |/dev/i2c-3| 3| 5|meson-g12a-radxa-zero-i2c-ee-m3-gpioa-14-gpioa-15.dtbo| |/dev/i2c-4| 7| 11|meson-g12a-radxa-zero-i2c-ao-m0-gpioao-2-gpioao-3.dtbo| ```sh /boot/dietpiEnv.txt example for i2c-1 ... overlays=g12a-radxa-zero-i2c-ee-m1-gpioh-6-gpioh-7 ... ``` >The I2C device "/dev/i2c-3" was already enabled on dietPi after setup. ### enable SPI ```sh /boot/dietpiEnv.txt for SPI ... overlays=g12a-radxa-zero-spi-spidev ... ``` >Most likely the overlay is currently defective - it contains "armbian" and only "disabled" spi devices. ### enable PWM |pin | symbol | DT path | driver |DT overlay file name| |--------|---------|---------------------------|--------------------|--------------------| |32, PWMAO_C|pwm_AO_cd|/soc/bus@ff800000/pwm@2000 |meson-g12a-ao-pwm-cd|on by default| |40, PWMAO_A|pwm_AO_ab|/soc/bus@ff800000/pwm@7000 |meson-g12a-ao-pwm-ab|meson-g12a-radxa-zero-pwmao-a-on-gpioao-11.dtbo| |18, PWM_C |pwm_cd |/soc/bus@ffd00000/pwm@1a000|meson-g12a-ee-pwm |meson-g12a-radxa-zero-pwm-c-on-gpiox-8.dtbo| |21, PWM_F |pwm_ef |/soc/bus@ffd00000/pwm@19000|meson-g12a-ee-pwm |on by default| >PWMAO_B (channel 1 of pwm_AO_ab) and PWM_D (channel 1 of pwm_cd) not wired. PWMAO_D (channel 1 of pwm_AO_cd) in use by >"regulator-vddcpu". PWM_E (channel 0 of pwm_ef) in use by wifi32k. PWMAO_C and PWM_F not really working, see >troubleshooting section. ### enable 1-wire The contained overlays maybe not working, because compatible with gxbb (Amlogic Meson S905). At least for my Zero V1.51 g12a (Amlogic Meson S905X2 and above) it does not work. ```sh /boot/dietpiEnv.txt for 1-wire dtc -I dtb -O dts /boot/dtb/amlogic/overlay/meson-w1AB-gpio.dtbo | grep amlogic ... compatible = "amlogic,meson-gxbb"; ``` So create your own overlay as `/boot/overlay_user/meson-g12a-w1-gpioao-3.dts`... ```sh /dts-v1/; /plugin/; / { compatible = "radxa,zero", "amlogic,g12a"; fragment@0 { target-path = "/"; __overlay__ { w1: onewire { compatible = "w1-gpio"; pinctrl-names = "default"; /* GPIOAO_3=0x03, GPIOC_7=0x30 */ /* GPIO_ACTIVE_HIGH=0, GPIO_ACTIVE_LOW=1 */ /* GPIO_SINGLE_ENDED=2, GPIO_LINE_OPEN_DRAIN=4 */ gpios = <0xffffffff 0x03 0x06>; status = "okay"; phandle = <0x01>; }; }; }; __fixups__ { /* gpio_ao or gpio for GPIOC_7 */ gpio_ao = "/fragment@0/__overlay__/onewire:gpios:0"; }; }; ``` ...compile it ```sh dtc -@ -O dtb -b 0 -o meson-g12a-w1-gpioao-3.dtbo meson-g12a-w1-gpioao-3.dts ``` ... and add it as follows: ```sh /boot/dietpiEnv.txt for 1-wire ... user_overlays= meson-g12a-w1-gpioao-3 ... ``` ## enable SAR ADC The 12-bit ADC is enabled by default. The voltage range is 0..1.8V. Raw values can be read with pin 15 (channel 1) or pin 26 (channel 2). Additionally some internal values can be accessed, e.g. gnd and 1/4 vdd. For debugging purposes more information is provided, e.g. each item provides a label: ```sh cat /sys/bus/platform/drivers/meson-saradc/ff809000.adc/iio:device0/in_voltage9_label gnd cat /sys/bus/platform/drivers/meson-saradc/ff809000.adc/iio:device0/in_voltage10_label 0.25vdd ``` ```sh cat /sys/bus/platform/drivers/meson-saradc/ff809000.adc/iio:device0/calibbias -4 cat /sys/bus/platform/drivers/meson-saradc/ff809000.adc/iio:device0/calibscale 1.002447 cat /sys/bus/platform/drivers/meson-saradc/ff809000.adc/iio:device0/in_voltage_scale 0.439453125 cat /sys/bus/platform/drivers/meson-saradc/ff809000.adc/iio:device0/in_voltage9_raw 0 cat /sys/bus/platform/drivers/meson-saradc/ff809000.adc/iio:device0/in_voltage10_raw 1023 ``` The `in_voltage_scale` (e.g. 0.439453125) is for calculation of "value = (raw + offset) * scale", value in millivolts. The `calibbias` is the offset and `calibscale` the scale which is used for internal calibration, so we get an output of 0..4095 for 0..1.8V input. >The channel 10 is a 1/4 of full range, but if the channel 2 is in saturation state (above 1.8V = 4095), it becomes more >and more wrong. ## How to Use The pin numbering used by your Gobot program should match the way your board is labeled right on the board itself. ```go r := zero.NewAdaptor() led := gpio.NewLedDriver(r, "7") ``` ## How to Connect ### Compiling Compile your Gobot program on your workstation like this: ```sh GOARCH=arm64 GOOS=linux go build -o output/ examples/zero_blink.go ``` Once you have compiled your code, you can upload your program and execute it on the board from your workstation using the `scp` and `ssh` commands like this: ```sh scp zero_blink dietpi@DietPi:~ ssh -t dietpi@DietPi "./zero_blink" ``` ## Troubleshooting ### scp fails "bash: line 1: /usr/lib/sftp-server: No such file or directory" The dietPi has only a limited package set, so sftp-server is missing. ```sh sudo apt install openssh-sftp-server ``` ### GPIO pin3, pin5 and pin7 not working like expected e.g. for pin3: `cdev.Export(): cdev.reconfigure(gpiochip0-63)-c.RequestLine(63, [0 2000000000 2]): invalid argument` The pin does not support `adaptors.WithGpioDebounce(inPinNum, debounceTime)`. `cdev.Export(): cdev.reconfigure(gpiochip1-0)-c.RequestLine(0, [0 2]): invalid argument` The pin 8 is configured for UART. >Some pins have low power or have a strong pullup resistor, so the expected voltage drop is maybe not possible. >Pins 7-27 and 11-28 are bridged. ### PWMAO_C and PWM_F not really working If you run `cat /sys/kernel/debug/pwm` when those PWMs are used you can see, that it is working "internally". Most likely the pin itself is not enabled by DT on PWM usage. Currently there is no fix provided for that. ================================================ FILE: platforms/radxa/zero/adaptor.go ================================================ package zero import ( "fmt" "sync" multierror "github.com/hashicorp/go-multierror" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/adaptors" "gobot.io/x/gobot/v2/system" ) const ( defaultI2cBusNumber = 3 defaultSpiBusNumber = 0 defaultSpiChipNumber = 0 defaultSpiMode = 0 defaultSpiBitsNumber = 8 defaultSpiMaxSpeed = 10000000 ) // Adaptor represents a Gobot Adaptor for the Radxa Zero type Adaptor struct { *adaptors.AnalogPinsAdaptor *adaptors.DigitalPinsAdaptor *adaptors.PWMPinsAdaptor *adaptors.I2cBusAdaptor *adaptors.SpiBusAdaptor *adaptors.OneWireBusAdaptor name string sys *system.Accesser // used for unit tests only mutex *sync.Mutex } // NewAdaptor creates a Zero Adaptor // // Optional parameters: // // adaptors.WithGpioSysfsAccess(): use legacy sysfs driver instead of default character device driver // adaptors.WithSpiGpioAccess(sclk, ncs, sdo, sdi): use GPIO's instead of /dev/spidev#.# // adaptors.WithGpiosActiveLow(pin's): invert the pin behavior // adaptors.WithGpiosPullUp/Down(pin's): sets the internal pull resistor // adaptors.WithGpiosOpenDrain/Source(pin's): sets the output behavior // adaptors.WithGpioEventOnFallingEdge/RaisingEdge/BothEdges(pin, handler): activate edge detection // // Further optional parameters for: // // AIO, see [adaptors.NewAnalogPinsAdaptor] // GPIO, see [adaptors.NewDigitalPinsAdaptor] // I2C, see [adaptors.NewI2cBusAdaptor] // 1-wire, see [adaptors.NewOneWireBusAdaptor] // PWM, see [adaptors.NewPWMPinsAdaptor] // SPI, see [adaptors.NewSpiBusAdaptor] func NewAdaptor(opts ...interface{}) *Adaptor { sys := system.NewAccesser() a := &Adaptor{ name: gobot.DefaultName("Zero"), sys: sys, mutex: &sync.Mutex{}, } var analogPinsOpts []adaptors.AnalogPinsOptionApplier var digitalPinsOpts []adaptors.DigitalPinsOptionApplier var pwmPinsOpts []adaptors.PwmPinsOptionApplier var i2cBusOpts []adaptors.I2CBusOptionApplier var spiBusOpts []adaptors.SpiBusOptionApplier var oneWireBusOpts []adaptors.OneWireBusOptionApplier for _, opt := range opts { switch o := opt.(type) { case adaptors.AnalogPinsOptionApplier: analogPinsOpts = append(analogPinsOpts, o) case adaptors.DigitalPinsOptionApplier: digitalPinsOpts = append(digitalPinsOpts, o) case adaptors.PwmPinsOptionApplier: pwmPinsOpts = append(pwmPinsOpts, o) case adaptors.I2CBusOptionApplier: i2cBusOpts = append(i2cBusOpts, o) case adaptors.SpiBusOptionApplier: spiBusOpts = append(spiBusOpts, o) case adaptors.OneWireBusOptionApplier: oneWireBusOpts = append(oneWireBusOpts, o) default: panic(fmt.Sprintf("'%s' can not be applied on adaptor '%s'", opt, a.name)) } } analogPinTranslator := adaptors.NewAnalogPinTranslator(sys, analogPinDefinitions) digitalPinTranslator := adaptors.NewDigitalPinTranslator(sys, gpioPinDefinitions) pwmPinTranslator := adaptors.NewPWMPinTranslator(sys, pwmPinDefinitions) // Valid bus numbers are [1,3,4] which corresponds to /dev/i2c-1, /dev/i2c-3, /dev/i2c-4 // We don't support /dev/i2c-5 (DesignWare HDMI) i2cBusNumberValidator := adaptors.NewBusNumberValidator([]int{1, 3, 4}) // Valid bus numbers are [0,1] which corresponds to /dev/spidev0.x, /dev/spidev1.x // x is the chip number <255 spiBusNumberValidator := adaptors.NewBusNumberValidator([]int{0, 1}) a.AnalogPinsAdaptor = adaptors.NewAnalogPinsAdaptor(sys, analogPinTranslator.Translate, analogPinsOpts...) a.DigitalPinsAdaptor = adaptors.NewDigitalPinsAdaptor(sys, digitalPinTranslator.Translate, digitalPinsOpts...) a.PWMPinsAdaptor = adaptors.NewPWMPinsAdaptor(sys, pwmPinTranslator.Translate, pwmPinsOpts...) a.I2cBusAdaptor = adaptors.NewI2cBusAdaptor(sys, i2cBusNumberValidator.Validate, defaultI2cBusNumber, i2cBusOpts...) a.SpiBusAdaptor = adaptors.NewSpiBusAdaptor(sys, spiBusNumberValidator.Validate, defaultSpiBusNumber, defaultSpiChipNumber, defaultSpiMode, defaultSpiBitsNumber, defaultSpiMaxSpeed, a.DigitalPinsAdaptor, spiBusOpts...) // pin ?? needs to be activated by DT-overlay w1-gpio a.OneWireBusAdaptor = adaptors.NewOneWireBusAdaptor(sys, oneWireBusOpts...) return a } // Name returns the name of the Adaptor func (a *Adaptor) Name() string { return a.name } // SetName sets the name of the Adaptor func (a *Adaptor) SetName(n string) { a.name = n } // Connect create new connection to board and pins. func (a *Adaptor) Connect() error { a.mutex.Lock() defer a.mutex.Unlock() if err := a.OneWireBusAdaptor.Connect(); err != nil { return err } if err := a.SpiBusAdaptor.Connect(); err != nil { return err } if err := a.I2cBusAdaptor.Connect(); err != nil { return err } if err := a.AnalogPinsAdaptor.Connect(); err != nil { return err } if err := a.PWMPinsAdaptor.Connect(); err != nil { return err } return a.DigitalPinsAdaptor.Connect() } // Finalize closes connection to board, pins and bus func (a *Adaptor) Finalize() error { a.mutex.Lock() defer a.mutex.Unlock() err := a.DigitalPinsAdaptor.Finalize() if e := a.PWMPinsAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } if e := a.AnalogPinsAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } if e := a.I2cBusAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } if e := a.SpiBusAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } if e := a.OneWireBusAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } return err } ================================================ FILE: platforms/radxa/zero/adaptor_test.go ================================================ package zero import ( "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/platforms/adaptors" "gobot.io/x/gobot/v2/system" ) const ( pwmDir = "/sys/devices/platform/soc/ffd00000.bus/ffd1a000.pwm/pwm/pwmchip2/" //nolint:gosec // false positive pwmExportPath = pwmDir + "export" pwmUnexportPath = pwmDir + "unexport" pwmPwmDir = pwmDir + "pwm0/" pwmEnablePath = pwmPwmDir + "enable" pwmPeriodPath = pwmPwmDir + "period" pwmDutyCyclePath = pwmPwmDir + "duty_cycle" pwmPolarityPath = pwmPwmDir + "polarity" pwmInvertedIdentifier = "inversed" ) var pwmMockPaths = []string{ pwmExportPath, pwmUnexportPath, pwmEnablePath, pwmPeriodPath, pwmDutyCyclePath, pwmPolarityPath, } // make sure that this Adaptor fulfills all the required interfaces var ( _ gobot.Adaptor = (*Adaptor)(nil) _ gobot.DigitalPinnerProvider = (*Adaptor)(nil) _ gobot.PWMPinnerProvider = (*Adaptor)(nil) _ gpio.DigitalReader = (*Adaptor)(nil) _ gpio.DigitalWriter = (*Adaptor)(nil) _ aio.AnalogReader = (*Adaptor)(nil) _ i2c.Connector = (*Adaptor)(nil) ) func preparePwmFs(fs *system.MockFilesystem) { fs.Files[pwmEnablePath].Contents = "0" fs.Files[pwmPeriodPath].Contents = "0" fs.Files[pwmDutyCyclePath].Contents = "0" fs.Files[pwmPolarityPath].Contents = pwmInvertedIdentifier } func initConnectedTestAdaptorWithMockedFilesystem(mockPaths []string) (*Adaptor, *system.MockFilesystem) { a := initConnectedTestAdaptor() fs := a.sys.UseMockFilesystem(mockPaths) return a, fs } func initConnectedTestAdaptor() *Adaptor { a := NewAdaptor() if err := a.Connect(); err != nil { panic(err) } return a } func TestNewAdaptor(t *testing.T) { // arrange & act a := NewAdaptor() // assert assert.IsType(t, &Adaptor{}, a) assert.True(t, strings.HasPrefix(a.Name(), "Zero")) assert.NotNil(t, a.sys) assert.NotNil(t, a.mutex) assert.NotNil(t, a.AnalogPinsAdaptor) assert.NotNil(t, a.DigitalPinsAdaptor) assert.NotNil(t, a.PWMPinsAdaptor) assert.NotNil(t, a.I2cBusAdaptor) assert.NotNil(t, a.SpiBusAdaptor) assert.True(t, a.sys.HasDigitalPinCdevAccess()) // act & assert a.SetName("NewName") assert.Equal(t, "NewName", a.Name()) } func TestNewAdaptorWithOption(t *testing.T) { // arrange & act a := NewAdaptor(adaptors.WithGpiosActiveLow("1"), adaptors.WithGpioSysfsAccess()) // assert require.NoError(t, a.Connect()) assert.True(t, a.sys.HasDigitalPinSysfsAccess()) } func TestDigitalIO(t *testing.T) { // some basic tests, further tests are done in "digitalpinsadaptor.go" // arrange a := initConnectedTestAdaptor() dpa := a.sys.UseMockDigitalPinAccess() require.True(t, a.sys.HasDigitalPinCdevAccess()) // act & assert write err := a.DigitalWrite("7", 1) require.NoError(t, err) assert.Equal(t, []int{1}, dpa.Written("gpiochip1", "3")) // arrange, act & assert read dpa.UseValues("gpiochip1", "1", []int{3}) i, err := a.DigitalRead("10") require.NoError(t, err) assert.Equal(t, 3, i) // act and assert unknown pin require.ErrorContains(t, a.DigitalWrite("99", 1), "'99' is not a valid id for a digital pin") // act and assert finalize require.NoError(t, a.Finalize()) assert.Equal(t, 0, dpa.Exported("gpiochip1", "3")) assert.Equal(t, 0, dpa.Exported("gpiochip1", "1")) } func TestDigitalIOSysfs(t *testing.T) { // some basic tests, further tests are done in "digitalpinsadaptor.go" // arrange a := NewAdaptor(adaptors.WithGpioSysfsAccess()) require.NoError(t, a.Connect()) dpa := a.sys.UseMockDigitalPinAccess() require.True(t, a.sys.HasDigitalPinSysfsAccess()) // act & assert write err := a.DigitalWrite("7", 1) require.NoError(t, err) assert.Equal(t, []int{1}, dpa.Written("", "415")) // arrange, act & assert read dpa.UseValues("", "413", []int{4}) i, err := a.DigitalRead("10") require.NoError(t, err) assert.Equal(t, 4, i) // act and assert unknown pin require.ErrorContains(t, a.DigitalWrite("99", 1), "'99' is not a valid id for a digital pin") // act and assert finalize require.NoError(t, a.Finalize()) assert.Equal(t, 0, dpa.Exported("", "415")) assert.Equal(t, 0, dpa.Exported("", "413")) } func TestAnalogRead(t *testing.T) { mockPaths := []string{ "/sys/class/thermal/thermal_zone0/temp", } a, fs := initConnectedTestAdaptorWithMockedFilesystem(mockPaths) fs.Files["/sys/class/thermal/thermal_zone0/temp"].Contents = "567\n" got, err := a.AnalogRead("cpu_thermal") require.NoError(t, err) assert.Equal(t, 567, got) _, err = a.AnalogRead("thermal_zone10") require.ErrorContains(t, err, "'thermal_zone10' is not a valid id for an analog pin") fs.WithReadError = true _, err = a.AnalogRead("cpu_thermal") require.ErrorContains(t, err, "read error") fs.WithReadError = false require.NoError(t, a.Finalize()) } func TestFinalizeErrorAfterGPIO(t *testing.T) { // arrange a := initConnectedTestAdaptor() dpa := a.sys.UseMockDigitalPinAccess() require.True(t, a.sys.HasDigitalPinCdevAccess()) require.NoError(t, a.DigitalWrite("7", 1)) dpa.UseUnexportError("gpiochip1", "3") // act err := a.Finalize() // assert require.ErrorContains(t, err, "unexport error") } func TestFinalizeErrorAfterPWM(t *testing.T) { // indirect test for PWM.Finalize() is called for the adaptor // arrange a, fs := initConnectedTestAdaptorWithMockedFilesystem(pwmMockPaths) preparePwmFs(fs) require.NoError(t, a.PwmWrite("18", 1)) fs.WithWriteError = true // act err := a.Finalize() // assert require.ErrorContains(t, err, "write error") } func TestSpiDefaultValues(t *testing.T) { a := NewAdaptor() assert.Equal(t, 0, a.SpiDefaultBusNumber()) assert.Equal(t, 0, a.SpiDefaultChipNumber()) assert.Equal(t, 0, a.SpiDefaultMode()) assert.Equal(t, 8, a.SpiDefaultBitCount()) assert.Equal(t, int64(10000000), a.SpiDefaultMaxSpeed()) } func TestI2cDefaultBus(t *testing.T) { a := NewAdaptor() assert.Equal(t, 3, a.DefaultI2cBus()) } func TestI2cFinalizeWithErrors(t *testing.T) { // arrange a := initConnectedTestAdaptor() a.sys.UseMockSyscall() fs := a.sys.UseMockFilesystem([]string{"/dev/i2c-4"}) con, err := a.GetI2cConnection(0xff, 4) require.NoError(t, err) _, err = con.Write([]byte{0xbf}) require.NoError(t, err) fs.WithCloseError = true // act err = a.Finalize() // assert require.ErrorContains(t, err, "close error") } ================================================ FILE: platforms/radxa/zero/doc.go ================================================ /* Package zero contains the Gobot adaptor for the Radxa Zero. For further information refer to the boards README: https://github.com/hybridgroup/gobot/blob/release/platforms/radxa/zero/README.md */ package zero // import "gobot.io/x/gobot/v2/platforms/radxa/zero" ================================================ FILE: platforms/radxa/zero/pinmap.go ================================================ package zero import "gobot.io/x/gobot/v2/platforms/adaptors" // tested with cdev on a Zero V1.51 board: dietPi Linux, OK: works, ?: unknown, NOK: not working // IN: works only as input, PU: if used as input, external pullup resistor needed // //nolint:lll // ok here var gpioPinDefinitions = adaptors.DigitalPinDefinitions{ "8": {Sysfs: 412, Cdev: adaptors.CdevPin{Chip: 1, Line: 0}}, // GPIOAO_0_UART_AO_A_TXD - ? "10": {Sysfs: 413, Cdev: adaptors.CdevPin{Chip: 1, Line: 1}}, // GPIOAO_1_UART_AO_A_RXD - OK "11": {Sysfs: 414, Cdev: adaptors.CdevPin{Chip: 1, Line: 2}}, // GPIOAO_2_I2C_AO_M0_SCL_UART_AO_B_TX_I2C_AO_S0_SCL - OK "28": {Sysfs: 414, Cdev: adaptors.CdevPin{Chip: 1, Line: 2}}, // GPIOAO_2_I2C_AO_M0_SCL_UART_AO_B_TX_I2C_AO_S0_SCL - OK "7": {Sysfs: 415, Cdev: adaptors.CdevPin{Chip: 1, Line: 3}}, // GPIOAO_3_I2C_AO_M0_SDA_UART_AO_B_RX_I2C_AO_S0_SDA - OK "27": {Sysfs: 415, Cdev: adaptors.CdevPin{Chip: 1, Line: 3}}, // GPIOAO_3_I2C_AO_M0_SDA_UART_AO_B_RX_I2C_AO_S0_SDA - OK "32": {Sysfs: 416, Cdev: adaptors.CdevPin{Chip: 1, Line: 4}}, // GPIOAO_4_PWMAO_C - OK "35": {Sysfs: 420, Cdev: adaptors.CdevPin{Chip: 1, Line: 8}}, // GPIOAO_8_UART_AO_B_TX - OK "37": {Sysfs: 421, Cdev: adaptors.CdevPin{Chip: 1, Line: 9}}, // GPIOAO_9_UART_AO_B_RX - OK "LED": {Sysfs: 422, Cdev: adaptors.CdevPin{Chip: 1, Line: 10}}, // GPIOAO_10_PWMAO_D - Wired to LED besides USB-C "40": {Sysfs: 423, Cdev: adaptors.CdevPin{Chip: 1, Line: 11}}, // GPIOAO_11_PWMAO_A - OK "19": {Sysfs: 447, Cdev: adaptors.CdevPin{Chip: 0, Line: 20}}, // GPIOH_4_UART_EE_C_RTS_SPI_B_MOSI - OK "21": {Sysfs: 448, Cdev: adaptors.CdevPin{Chip: 0, Line: 21}}, // GPIOH_5_UART_EE_C_CTS_SPI_B_MISO_PWM_F - OK "24": {Sysfs: 449, Cdev: adaptors.CdevPin{Chip: 0, Line: 22}}, // GPIOH_6_UART_EE_C_RX_SPI_B_SS0_I2C_EE_M1_SDA - OK "23": {Sysfs: 450, Cdev: adaptors.CdevPin{Chip: 0, Line: 23}}, // GPIOH_7_UART_EE_C_TX_SPI_B_SCLK_I2C_EE_M1_SCL - OK "36": {Sysfs: 451, Cdev: adaptors.CdevPin{Chip: 0, Line: 24}}, // GPIOH_8 - OK "22": {Sysfs: 475, Cdev: adaptors.CdevPin{Chip: 0, Line: 48}}, // GPIOC_7 - OK "3": {Sysfs: 490, Cdev: adaptors.CdevPin{Chip: 0, Line: 63}}, // GPIOA_14_I2C_EE_M3_SDA - OK (i2c-3) "5": {Sysfs: 491, Cdev: adaptors.CdevPin{Chip: 0, Line: 64}}, // GPIOA_15_I2C_EE_M3_SCL - OK (i2-c3) "18": {Sysfs: 500, Cdev: adaptors.CdevPin{Chip: 0, Line: 73}}, // GPIOX_8_SPI_A_MOSI_PWM_C_TDMA_D1 - OK "12": {Sysfs: 501, Cdev: adaptors.CdevPin{Chip: 0, Line: 74}}, // GPIOX_9_SPI_A_MISO_TDMA_D0 - OK "16": {Sysfs: 502, Cdev: adaptors.CdevPin{Chip: 0, Line: 75}}, // GPIOX_10_SPI_A_SS0_I2C_EE_M1_SDA_TDMA_FS - OK "13": {Sysfs: 503, Cdev: adaptors.CdevPin{Chip: 0, Line: 76}}, // GPIOX_11_SPI_A_SCLK_I2C_EE_M1_SCL_TDMA_SCLK - OK } var pwmPinDefinitions = adaptors.PWMPinDefinitions{ // enabled by default, but pin seems to be not really enabled on pwm usage, channel 1 used by "regulator-vddcpu" "32": {Dir: "/sys/devices/platform/soc/ff800000.bus/ff802000.pwm/pwm/", DirRegexp: "pwmchip[0|1|2|3|4]$", Channel: 0}, "40": {Dir: "/sys/devices/platform/soc/ff800000.bus/ff807000.pwm/pwm/", DirRegexp: "pwmchip[0|1|2|3|4]$", Channel: 0}, "18": {Dir: "/sys/devices/platform/soc/ffd00000.bus/ffd1a000.pwm/pwm/", DirRegexp: "pwmchip[0|1|2|3|4]$", Channel: 0}, // enabled by default, but pin seems to be not really enabled on pwm usage, channel 0 used by "wifi32k" "21": {Dir: "/sys/devices/platform/soc/ffd00000.bus/ffd19000.pwm/pwm/", DirRegexp: "pwmchip[0|1|2|3|4]$", Channel: 1}, } var analogPinDefinitions = adaptors.AnalogPinDefinitions{ // +/-273.200 °C need >=7 characters to read: +/-273200 millidegree Celsius // names equals /sys/class/thermal/thermal_zone*/hwmon*/name "cpu_thermal": {Path: "/sys/class/thermal/thermal_zone0/temp", W: false, ReadBufLen: 7}, "ddr_thermal": {Path: "/sys/class/thermal/thermal_zone1/temp", W: false, ReadBufLen: 7}, // 2 channel 12-bit SAR ADC, 0..4095, so 4 characters to read "15": { Path: "/sys/bus/platform/drivers/meson-saradc/ff809000.adc/iio:device0/in_voltage1_raw", W: false, ReadBufLen: 4, }, "15_mean": { Path: "/sys/bus/platform/drivers/meson-saradc/ff809000.adc/iio:device0/in_voltage1_mean_raw", W: false, ReadBufLen: 4, }, "26": { Path: "/sys/bus/platform/drivers/meson-saradc/ff809000.adc/iio:device0/in_voltage2_raw", W: false, ReadBufLen: 4, }, "26_mean": { Path: "/sys/bus/platform/drivers/meson-saradc/ff809000.adc/iio:device0/in_voltage2_mean_raw", W: false, ReadBufLen: 4, }, } ================================================ FILE: platforms/raspi/LICENSE ================================================ Copyright (c) 2014-2018 The Hybrid Group Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: platforms/raspi/README.md ================================================ # Raspberry Pi The Raspberry Pi is an inexpensive and popular ARM based single board computer with digital & PWM GPIO, and i2c interfaces built in. The Gobot adaptor for the Raspberry Pi should support all of the various Raspberry Pi boards such as the Raspberry Pi 4 Model B, Raspberry Pi 3 Model B, Raspberry Pi 2 Model B, Raspberry Pi 1 Model A+, Raspberry Pi Zero, and Raspberry Pi Zero W. For more info about the Raspberry Pi platform, click [here](http://www.raspberrypi.org/). ## How to Install Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) We recommend updating to the latest Raspian Jessie OS when using the Raspberry Pi, however Gobot should also support older versions of the OS, should your application require this. ## How to Use The pin numbering used by your Gobot program should match the way your board is labeled right on the board itself. ```go package main import ( "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/platforms/raspi" ) func main() { r := raspi.NewAdaptor() led := gpio.NewLedDriver(r, "7") work := func() { gobot.Every(1*time.Second, func() { if err := led.Toggle(); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("blinkBot", []gobot.Connection{r}, []gobot.Device{led}, work, ) if err := robot.Start(); err != nil { panic(err) } } ``` ## Compiling Compile your Gobot program on your workstation like this: ```sh GOARM=6 GOARCH=arm GOOS=linux go build examples/raspi_blink.go ``` Use the following `GOARM` values to compile depending on which model Raspberry Pi you are using: `GOARM=6` (Raspberry Pi A, A+, B, B+, Zero) `GOARM=7` (Raspberry Pi 2, 3) Once you have compiled your code, you can upload your program and execute it on the Raspberry Pi from your workstation using the `scp` and `ssh` commands like this: ```sh scp raspi_blink pi@192.168.1.xxx:/home/pi/ ssh -t pi@192.168.1.xxx "./raspi_blink" ``` ## Enabling PWM output on GPIO pins ### Using Linux Kernel sysfs implementation The PWM needs to be enabled in the device tree. Please read `/boot/overlays/README` of your device. Usually "pwm0" can be activated for all raspi variants with a line `dtoverlay=pwm,pin=18,func=2` added to `/boot/config.txt`. The number relates to "GPIO18", not the header number, which is "12" in this case. Now the pin can be used with gobot by the pwm channel name, e.g. for our example above: ```go ... // create the adaptor with a 50Hz default frequency for usage with servos a := NewAdaptor(adaptors.WithPWMDefaultPeriod(20000000)) // move servo connected with header pin 12 to 90° a.ServoWrite("pwm0", 90) ... ``` > If the activation fails or something strange happen, maybe the audio driver conflicts with the PWM. Please deactivate > the audio device tree overlay in `/boot/config.txt` to avoid conflicts. ### Using pi-blaster For support PWM on all pins, you may use a program called pi-blaster. You can follow the instructions for install in the pi-blaster repo here: For using a PWM for servo, the default 100Hz period needs to be adjusted to 50Hz in the source code of the driver. Please refer to . It is not possible to change the period from gobot side. Now the pin can be used with gobot by the header number, e.g.: ```go ... // create the adaptor with usage of pi-blaster instead of default sysfs, 50Hz default is given for calculate // duty cycle for servos but will not change everything for the pi-blaster driver, see description above a := NewAdaptor(adaptors.WithPWMUsePiBlaster(), adaptors.WithPWMDefaultPeriod(20000000)) // move servo to 90° a.ServoWrite("11", 90) // this will not work like expected, see description a.SetPeriod("11", 20000000) ... ``` ================================================ FILE: platforms/raspi/adaptor.go ================================================ package raspi import ( "fmt" "strconv" "strings" "sync" multierror "github.com/hashicorp/go-multierror" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/adaptors" "gobot.io/x/gobot/v2/system" ) const ( infoFile = "/proc/cpuinfo" defaultSpiBusNumber = 0 defaultSpiChipNumber = 0 defaultSpiMode = 0 defaultSpiBitsNumber = 8 defaultSpiMaxSpeed = 500000 ) // Adaptor is the Gobot Adaptor for the Raspberry Pi type Adaptor struct { *adaptors.AnalogPinsAdaptor *adaptors.DigitalPinsAdaptor *adaptors.PWMPinsAdaptor *adaptors.I2cBusAdaptor *adaptors.SpiBusAdaptor name string mutex sync.Mutex sys *system.Accesser revision string } // NewAdaptor creates a Raspi Adaptor // // Optional parameters: // // adaptors.WithGpioSysfsAccess(): use legacy sysfs driver instead of default character device driver // adaptors.WithSpiGpioAccess(sclk, ncs, sdo, sdi): use GPIO's instead of /dev/spidev#.# // adaptors.WithGpiosActiveLow(pin's): invert the pin behavior // adaptors.WithGpiosPullUp/Down(pin's): sets the internal pull resistor // adaptors.WithGpiosOpenDrain/Source(pin's): sets the output behavior // adaptors.WithGpioDebounce(pin, period): sets the input debouncer // adaptors.WithGpioEventOnFallingEdge/RaisingEdge/BothEdges(pin, handler): activate edge detection // // Further optional parameters for: // // AIO, see [adaptors.NewAnalogPinsAdaptor] // GPIO, see [adaptors.NewDigitalPinsAdaptor] // I2C, see [adaptors.NewI2cBusAdaptor] // PWM, see [adaptors.NewPWMPinsAdaptor] // SPI, see [adaptors.NewSpiBusAdaptor] func NewAdaptor(opts ...interface{}) *Adaptor { sys := system.NewAccesser() a := &Adaptor{ name: gobot.DefaultName("RaspberryPi"), sys: sys, } var analogPinsOpts []adaptors.AnalogPinsOptionApplier var digitalPinsOpts []adaptors.DigitalPinsOptionApplier var pwmPinsOpts []adaptors.PwmPinsOptionApplier var i2cBusOpts []adaptors.I2CBusOptionApplier var spiBusOpts []adaptors.SpiBusOptionApplier for _, opt := range opts { switch o := opt.(type) { case adaptors.AnalogPinsOptionApplier: analogPinsOpts = append(analogPinsOpts, o) case adaptors.DigitalPinsOptionApplier: digitalPinsOpts = append(digitalPinsOpts, o) case adaptors.PwmPinsOptionApplier: pwmPinsOpts = append(pwmPinsOpts, o) case adaptors.I2CBusOptionApplier: i2cBusOpts = append(i2cBusOpts, o) case adaptors.SpiBusOptionApplier: spiBusOpts = append(spiBusOpts, o) default: panic(fmt.Sprintf("'%s' can not be applied on adaptor '%s'", opt, a.name)) } } analogPinTranslator := adaptors.NewAnalogPinTranslator(sys, analogPinDefinitions) // Valid bus numbers are [0,1] which corresponds to /dev/i2c-0 through /dev/i2c-1. i2cBusNumberValidator := adaptors.NewBusNumberValidator([]int{0, 1}) // Valid bus numbers are [0,1] which corresponds to /dev/spidev0.x through /dev/spidev1.x. // x is the chip number <255 spiBusNumberValidator := adaptors.NewBusNumberValidator([]int{0, 1}) a.AnalogPinsAdaptor = adaptors.NewAnalogPinsAdaptor(sys, analogPinTranslator.Translate, analogPinsOpts...) a.DigitalPinsAdaptor = adaptors.NewDigitalPinsAdaptor(sys, a.getPinTranslatorFunction(), digitalPinsOpts...) a.PWMPinsAdaptor = adaptors.NewPWMPinsAdaptor(sys, a.getPinTranslatorFunction(), pwmPinsOpts...) a.I2cBusAdaptor = adaptors.NewI2cBusAdaptor(sys, i2cBusNumberValidator.Validate, 1, i2cBusOpts...) a.SpiBusAdaptor = adaptors.NewSpiBusAdaptor(sys, spiBusNumberValidator.Validate, defaultSpiBusNumber, defaultSpiChipNumber, defaultSpiMode, defaultSpiBitsNumber, defaultSpiMaxSpeed, a.DigitalPinsAdaptor, spiBusOpts...) return a } // Name returns the adaptors name func (a *Adaptor) Name() string { a.mutex.Lock() defer a.mutex.Unlock() return a.name } // SetName sets the adaptors name func (a *Adaptor) SetName(n string) { a.mutex.Lock() defer a.mutex.Unlock() a.name = n } // Connect create new connection to board and pins. func (a *Adaptor) Connect() error { a.mutex.Lock() defer a.mutex.Unlock() if err := a.SpiBusAdaptor.Connect(); err != nil { return err } if err := a.I2cBusAdaptor.Connect(); err != nil { return err } if err := a.AnalogPinsAdaptor.Connect(); err != nil { return err } if err := a.PWMPinsAdaptor.Connect(); err != nil { return err } return a.DigitalPinsAdaptor.Connect() } // Finalize closes connection to board and pins func (a *Adaptor) Finalize() error { a.mutex.Lock() defer a.mutex.Unlock() err := a.DigitalPinsAdaptor.Finalize() if e := a.PWMPinsAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } if e := a.AnalogPinsAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } if e := a.I2cBusAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } if e := a.SpiBusAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } return err } // DefaultI2cBus returns the default i2c bus for this platform. // This overrides the base function due to the revision dependency. func (a *Adaptor) DefaultI2cBus() int { rev := a.readRevision() if rev == "2" || rev == "3" { return 1 } return 0 } // getPinTranslatorFunction returns a function to be able to translate GPIO and PWM pins. // This means for pi-blaster usage, each pin can be used and therefore the pin is given as number, like a GPIO pin. // For sysfs-PWM usage, the pin will be given as "pwm0" or "pwm1", because the real pin number depends on the user // configuration in "/boot/config.txt". For further details, see "/boot/overlays/README". func (a *Adaptor) getPinTranslatorFunction() func(string) (string, int, error) { return func(pin string) (string, int, error) { var line int if val, ok := pins[pin][a.readRevision()]; ok { line = val } else if val, ok := pins[pin]["*"]; ok { line = val } else { return "", 0, fmt.Errorf("'%s' is not a valid pin id for raspi revision %s", pin, a.revision) } // We always use "gpiochip0", because currently all pins are available with this approach. A change of the // translator would be needed to support different chips (e.g. gpiochip1) with different revisions. path := "gpiochip0" if strings.HasPrefix(pin, "pwm") { path = "/sys/class/pwm/pwmchip0" } return path, line, nil } } func (a *Adaptor) readRevision() string { if a.revision == "" { a.revision = "0" content, err := a.sys.ReadFile(infoFile) if err != nil { return a.revision } for _, v := range strings.Split(string(content), "\n") { if strings.Contains(v, "Revision") { s := strings.Split(v, " ") version, _ := strconv.ParseInt("0x"+s[len(s)-1], 0, 64) switch { case version <= 3: a.revision = "1" case version <= 15: a.revision = "2" default: a.revision = "3" } } } } return a.revision } ================================================ FILE: platforms/raspi/adaptor_test.go ================================================ package raspi import ( "fmt" "runtime" "strconv" "strings" "sync" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/aio" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/drivers/spi" "gobot.io/x/gobot/v2/platforms/adaptors" "gobot.io/x/gobot/v2/system" ) const ( pwmDir = "/sys/class/pwm/pwmchip0/" //nolint:gosec // false positive pwmPwmDir = pwmDir + "pwm0/" pwmExportPath = pwmDir + "export" pwmUnexportPath = pwmDir + "unexport" pwmEnablePath = pwmPwmDir + "enable" pwmPeriodPath = pwmPwmDir + "period" pwmDutyCyclePath = pwmPwmDir + "duty_cycle" pwmPolarityPath = pwmPwmDir + "polarity" pwmInvertedIdentifier = "inversed" ) var pwmMockPaths = []string{ pwmExportPath, pwmUnexportPath, pwmEnablePath, pwmPeriodPath, pwmDutyCyclePath, pwmPolarityPath, } // make sure that this Adaptor fulfills all the required interfaces var ( _ gobot.Adaptor = (*Adaptor)(nil) _ gobot.DigitalPinnerProvider = (*Adaptor)(nil) _ gobot.PWMPinnerProvider = (*Adaptor)(nil) _ gpio.DigitalReader = (*Adaptor)(nil) _ gpio.DigitalWriter = (*Adaptor)(nil) _ gpio.PwmWriter = (*Adaptor)(nil) _ gpio.ServoWriter = (*Adaptor)(nil) _ aio.AnalogReader = (*Adaptor)(nil) _ i2c.Connector = (*Adaptor)(nil) _ spi.Connector = (*Adaptor)(nil) ) func preparePwmFs(fs *system.MockFilesystem) { fs.Files[pwmEnablePath].Contents = "0" fs.Files[pwmPeriodPath].Contents = "0" fs.Files[pwmDutyCyclePath].Contents = "0" fs.Files[pwmPolarityPath].Contents = pwmInvertedIdentifier } func initConnectedTestAdaptorWithMockedFilesystem(mockPaths []string) (*Adaptor, *system.MockFilesystem) { a := NewAdaptor() fs := a.sys.UseMockFilesystem(mockPaths) if err := a.Connect(); err != nil { panic(err) } return a, fs } func TestNewAdaptor(t *testing.T) { // arrange & act a := NewAdaptor() // assert assert.IsType(t, &Adaptor{}, a) assert.True(t, strings.HasPrefix(a.Name(), "RaspberryPi")) assert.NotNil(t, a.sys) assert.NotNil(t, a.AnalogPinsAdaptor) assert.NotNil(t, a.DigitalPinsAdaptor) assert.NotNil(t, a.PWMPinsAdaptor) assert.NotNil(t, a.I2cBusAdaptor) assert.NotNil(t, a.SpiBusAdaptor) assert.True(t, a.sys.HasDigitalPinCdevAccess()) // act & assert a.SetName("NewName") assert.Equal(t, "NewName", a.Name()) } func TestNewAdaptorWithOption(t *testing.T) { // arrange & act a := NewAdaptor(adaptors.WithGpiosActiveLow("1"), adaptors.WithGpioSysfsAccess()) // assert require.NoError(t, a.Connect()) assert.True(t, a.sys.HasDigitalPinSysfsAccess()) } func TestGetDefaultBus(t *testing.T) { const contentPattern = "Hardware : BCM2708\n%sSerial : 000000003bc748ea\n" tests := map[string]struct { revisionPart string wantRev string wantBus int }{ "no_revision": { wantRev: "0", wantBus: 0, }, "rev_1": { revisionPart: "Revision : 0002\n", wantRev: "1", wantBus: 0, }, "rev_2": { revisionPart: "Revision : 000D\n", wantRev: "2", wantBus: 1, }, "rev_3": { revisionPart: "Revision : 0010\n", wantRev: "3", wantBus: 1, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange a := NewAdaptor() fs := a.sys.UseMockFilesystem([]string{infoFile}) fs.Files[infoFile].Contents = fmt.Sprintf(contentPattern, tc.revisionPart) assert.Empty(t, a.revision) // act, will read and refresh the revision gotBus := a.DefaultI2cBus() // assert assert.Equal(t, tc.wantRev, a.revision) assert.Equal(t, tc.wantBus, gotBus) }) } } func TestFinalize(t *testing.T) { mockedPaths := []string{ "/sys/class/gpio/export", "/sys/class/gpio/unexport", "/dev/pi-blaster", "/dev/i2c-1", "/dev/i2c-0", "/dev/spidev0.0", "/dev/spidev0.1", } a, _ := initConnectedTestAdaptorWithMockedFilesystem(mockedPaths) _ = a.DigitalWrite("3", 1) _ = a.PwmWrite("7", 255) _, _ = a.GetI2cConnection(0xff, 0) require.NoError(t, a.Finalize()) } func TestAnalog(t *testing.T) { mockPaths := []string{ "/sys/class/thermal/thermal_zone0/temp", } a, fs := initConnectedTestAdaptorWithMockedFilesystem(mockPaths) fs.Files["/sys/class/thermal/thermal_zone0/temp"].Contents = "567\n" got, err := a.AnalogRead("thermal_zone0") require.NoError(t, err) assert.Equal(t, 567, got) _, err = a.AnalogRead("thermal_zone10") require.ErrorContains(t, err, "'thermal_zone10' is not a valid id for an analog pin") fs.WithReadError = true _, err = a.AnalogRead("thermal_zone0") require.ErrorContains(t, err, "read error") fs.WithReadError = false require.NoError(t, a.Finalize()) } func TestPwmWrite(t *testing.T) { // arrange a, fs := initConnectedTestAdaptorWithMockedFilesystem(pwmMockPaths) preparePwmFs(fs) // act err := a.PwmWrite("pwm0", 100) // assert require.NoError(t, err) assert.Equal(t, "0", fs.Files[pwmExportPath].Contents) assert.Equal(t, "1", fs.Files[pwmEnablePath].Contents) assert.Equal(t, "10000000", fs.Files[pwmPeriodPath].Contents) assert.Equal(t, "3921568", fs.Files[pwmDutyCyclePath].Contents) assert.Equal(t, "normal", fs.Files[pwmPolarityPath].Contents) // act & assert invalid pin err = a.PwmWrite("pwm1", 42) require.ErrorContains(t, err, "'pwm1' is not a valid pin id for raspi revision 0") require.NoError(t, a.Finalize()) } func TestServoWrite(t *testing.T) { // arrange: prepare 50Hz for servos const ( pin = "pwm0" fiftyHzNano = 20000000 ) a := NewAdaptor(adaptors.WithPWMDefaultPeriodForPin(pin, fiftyHzNano)) fs := a.sys.UseMockFilesystem(pwmMockPaths) preparePwmFs(fs) require.NoError(t, a.Connect()) // act & assert for 0° (min default value) err := a.ServoWrite(pin, 0) require.NoError(t, err) assert.Equal(t, strconv.Itoa(fiftyHzNano), fs.Files[pwmPeriodPath].Contents) assert.Equal(t, "500000", fs.Files[pwmDutyCyclePath].Contents) // act & assert for 180° (max default value) err = a.ServoWrite(pin, 180) require.NoError(t, err) assert.Equal(t, strconv.Itoa(fiftyHzNano), fs.Files[pwmPeriodPath].Contents) assert.Equal(t, "2500000", fs.Files[pwmDutyCyclePath].Contents) // act & assert invalid pins err = a.ServoWrite("3", 120) require.ErrorContains(t, err, "'3' is not a valid pin id for raspi revision 0") require.NoError(t, a.Finalize()) } func TestPWMWrite_piPlaster(t *testing.T) { // arrange const hundredHzNano = 10000000 mockedPaths := []string{"/dev/pi-blaster"} a := NewAdaptor(adaptors.WithPWMUsePiBlaster()) fs := a.sys.UseMockFilesystem(mockedPaths) require.NoError(t, a.Connect()) // act & assert: Write & Pin & Period require.NoError(t, a.PwmWrite("7", 255)) assert.Equal(t, "4=1", strings.Split(fs.Files["/dev/pi-blaster"].Contents, "\n")[0]) pin, _ := a.PWMPin("7") period, err := pin.Period() require.NoError(t, err) assert.Equal(t, uint32(hundredHzNano), period) // act & assert: nonexistent pin require.ErrorContains(t, a.PwmWrite("notexist", 1), "'notexist' is not a valid pin id for raspi revision 0") // act & assert: SetDutyCycle pin, _ = a.PWMPin("12") require.NoError(t, pin.SetDutyCycle(1.5*1000*1000)) assert.Equal(t, "18=0.15", strings.Split(fs.Files["/dev/pi-blaster"].Contents, "\n")[0]) } func TestPWM_piPlaster(t *testing.T) { // arrange const fiftyHzNano = 20000000 // 20 ms mockedPaths := []string{"/dev/pi-blaster"} a := NewAdaptor(adaptors.WithPWMUsePiBlaster(), adaptors.WithPWMDefaultPeriod(fiftyHzNano)) fs := a.sys.UseMockFilesystem(mockedPaths) require.NoError(t, a.Connect()) // act & assert: Pin & Period pin, _ := a.PWMPin("7") period, err := pin.Period() require.NoError(t, err) assert.Equal(t, uint32(fiftyHzNano), period) // act & assert for 180° (max default value), 2.5 ms => 12.5% require.NoError(t, a.ServoWrite("11", 180)) assert.Equal(t, "17=0.125", strings.Split(fs.Files["/dev/pi-blaster"].Contents, "\n")[0]) // act & assert for 90° (center value), 1.5 ms => 7.5% duty require.NoError(t, a.ServoWrite("11", 90)) assert.Equal(t, "17=0.075", strings.Split(fs.Files["/dev/pi-blaster"].Contents, "\n")[0]) // act & assert for 0° (min default value), 0.5 ms => 2.5% duty require.NoError(t, a.ServoWrite("11", 0)) assert.Equal(t, "17=0.025", strings.Split(fs.Files["/dev/pi-blaster"].Contents, "\n")[0]) // act & assert: nonexistent pin require.ErrorContains(t, a.ServoWrite("notexist", 1), "'notexist' is not a valid pin id for raspi revision 0") } func TestDigitalIO(t *testing.T) { // some basic tests, further tests are done in "digitalpinsadaptor.go" // arrange a := NewAdaptor() if err := a.Connect(); err != nil { panic(err) } dpa := a.sys.UseMockDigitalPinAccess() require.True(t, a.sys.HasDigitalPinCdevAccess()) // act & assert write _ = a.DigitalWrite("7", 1) assert.Equal(t, []int{1}, dpa.Written("gpiochip0", "4")) // arrange, act & assert read a.revision = "2" dpa.UseValues("gpiochip0", "27", []int{2}) i, err := a.DigitalRead("13") require.NoError(t, err) assert.Equal(t, 2, i) // act and assert unknown pin require.ErrorContains(t, a.DigitalWrite("notexist", 1), "'notexist' is not a valid pin id for raspi revision 2") // act and assert finalize require.NoError(t, a.Finalize()) assert.Equal(t, 0, dpa.Exported("gpiochip0", "4")) assert.Equal(t, 0, dpa.Exported("gpiochip0", "27")) } func TestDigitalPinConcurrency(t *testing.T) { oldProcs := runtime.GOMAXPROCS(0) runtime.GOMAXPROCS(8) defer runtime.GOMAXPROCS(oldProcs) for retry := 0; retry < 20; retry++ { a := NewAdaptor() var wg sync.WaitGroup for i := 0; i < 20; i++ { wg.Add(1) pinAsString := strconv.Itoa(i) go func(pin string) { defer wg.Done() _, _ = a.DigitalPin(pin) }(pinAsString) } wg.Wait() } } func TestSpiDefaultValues(t *testing.T) { a := NewAdaptor() assert.Equal(t, 0, a.SpiDefaultBusNumber()) assert.Equal(t, 0, a.SpiDefaultChipNumber()) assert.Equal(t, 0, a.SpiDefaultMode()) assert.Equal(t, int64(500000), a.SpiDefaultMaxSpeed()) } func TestI2cDefaultBus(t *testing.T) { mockedPaths := []string{"/dev/i2c-1"} a, _ := initConnectedTestAdaptorWithMockedFilesystem(mockedPaths) a.sys.UseMockSyscall() a.revision = "0" assert.Equal(t, 0, a.DefaultI2cBus()) a.revision = "2" assert.Equal(t, 1, a.DefaultI2cBus()) } func TestI2cFinalizeWithErrors(t *testing.T) { // arrange a := NewAdaptor() a.sys.UseMockSyscall() fs := a.sys.UseMockFilesystem([]string{"/dev/i2c-1"}) require.NoError(t, a.Connect()) con, err := a.GetI2cConnection(0xff, 1) require.NoError(t, err) _, err = con.Write([]byte{0xbf}) require.NoError(t, err) fs.WithCloseError = true // act err = a.Finalize() // assert require.ErrorContains(t, err, "close error") } func Test_getPinTranslatorFunction(t *testing.T) { tests := map[string]struct { id string revision string wantPath string wantLine int wantErr string }{ "translate_12_rev0": { id: "12", wantPath: "gpiochip0", wantLine: 18, }, "translate_13_rev0": { id: "13", wantErr: "'13' is not a valid pin id for raspi revision 0", }, "translate_13_rev1": { id: "13", revision: "1", wantPath: "gpiochip0", wantLine: 21, }, "translate_29_rev1": { id: "29", revision: "1", wantErr: "'29' is not a valid pin id for raspi revision 1", }, "translate_29_rev3": { id: "29", revision: "3", wantPath: "gpiochip0", wantLine: 5, }, "translate_pwm0_rev0": { id: "pwm0", wantPath: "/sys/class/pwm/pwmchip0", wantLine: 0, }, "translate_pwm1_rev0": { id: "pwm1", wantErr: "'pwm1' is not a valid pin id for raspi revision 0", }, "translate_pwm1_rev3": { id: "pwm1", revision: "3", wantPath: "/sys/class/pwm/pwmchip0", wantLine: 1, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange a := NewAdaptor() a.revision = tc.revision // act f := a.getPinTranslatorFunction() path, line, err := f(tc.id) // assert if tc.wantErr != "" { require.EqualError(t, err, tc.wantErr) } else { require.NoError(t, err) } assert.Equal(t, tc.wantPath, path) assert.Equal(t, tc.wantLine, line) }) } } ================================================ FILE: platforms/raspi/doc.go ================================================ /* Package raspi contains the Gobot adaptor for the Raspberry Pi. For further information refer to raspi README: https://github.com/hybridgroup/gobot/blob/release/platforms/raspi/README.md */ package raspi // import "gobot.io/x/gobot/v2/platforms/raspi" ================================================ FILE: platforms/raspi/pinmap.go ================================================ package raspi import "gobot.io/x/gobot/v2/platforms/adaptors" var pins = map[string]map[string]int{ "3": { "1": 0, "2": 2, "3": 2, }, "5": { "1": 1, "2": 3, "3": 3, }, "7": { "*": 4, }, "8": { "*": 14, }, "10": { "*": 15, }, "11": { "*": 17, }, "12": { "*": 18, }, "13": { "1": 21, "2": 27, "3": 27, }, "15": { "*": 22, }, "16": { "*": 23, }, "18": { "*": 24, }, "19": { "*": 10, }, "21": { "*": 9, }, "22": { "*": 25, }, "23": { "*": 11, }, "24": { "*": 8, }, "26": { "*": 7, }, "29": { "3": 5, }, "31": { "3": 6, }, "32": { "3": 12, }, "33": { "3": 13, }, "35": { "3": 19, }, "36": { "3": 16, }, "37": { "3": 26, }, "38": { "3": 20, }, "40": { "3": 21, }, "pwm0": { // pin 12 (GPIO18) and pin 32 (GPIO12) can be configured for "pwm0" "*": 0, }, "pwm1": { // pin 33 (GPIO13) and pin 35 (GPIO19) can be configured for "pwm1" "3": 1, }, } var analogPinDefinitions = adaptors.AnalogPinDefinitions{ // +/-273.200 °C need >=7 characters to read: +/-273200 millidegree Celsius "thermal_zone0": {Path: "/sys/class/thermal/thermal_zone0/temp", W: false, ReadBufLen: 7}, } ================================================ FILE: platforms/serialport/LICENSE ================================================ Copyright (c) 2013-2018 The Hybrid Group Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: platforms/serialport/README.md ================================================ # Serialport The adaptor "serialport" is a small wrapper to get access to the serial port. ## How to Install Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) ## How to Use See documentation for [Sphero](https://github.com/hybridgroup/gobot/blob/release/platforms/sphero/sphero/README.md) or [Neurosky MindWave](https://github.com/hybridgroup/gobot/blob/release/platforms/neurosky/README.md). ================================================ FILE: platforms/serialport/adaptor.go ================================================ package serialport import ( "fmt" "io" "go.bug.st/serial" "gobot.io/x/gobot/v2" ) // configuration contains all changeable attributes of the driver. type configuration struct { name string baudRate int } // Adaptor represents a Gobot Adaptor for the Serial Communication type Adaptor struct { port string cfg *configuration sp io.ReadWriteCloser connectFunc func(string, int) (io.ReadWriteCloser, error) } // NewAdaptor returns a new adaptor given a port for the serial communication func NewAdaptor(port string, opts ...optionApplier) *Adaptor { cfg := configuration{ name: gobot.DefaultName("Serial"), baudRate: 115200, } a := Adaptor{ cfg: &cfg, port: port, connectFunc: func(port string, baudRate int) (io.ReadWriteCloser, error) { return serial.Open(port, &serial.Mode{BaudRate: baudRate}) }, } for _, o := range opts { o.apply(a.cfg) } return &a } // WithName is used to replace the default name of the driver. func WithName(name string) optionApplier { return nameOption(name) } // WithName is used to replace the default name of the driver. func WithBaudRate(baudRate int) optionApplier { return baudRateOption(baudRate) } // Name returns the adaptors name func (a *Adaptor) Name() string { return a.cfg.name } // SetName sets the adaptors name // Deprecated: Please use option [serialport.WithName] instead. func (a *Adaptor) SetName(n string) { WithName(n).apply(a.cfg) } // Connect initiates a connection to the serial port. func (a *Adaptor) Connect() error { if a.sp != nil { return fmt.Errorf("serial port is already connected, try reconnect or run disconnect first") } sp, err := a.connectFunc(a.port, a.cfg.baudRate) if err != nil { return err } a.sp = sp return nil } // Finalize finalizes the adaptor by disconnect func (a *Adaptor) Finalize() error { return a.Disconnect() } // Disconnect terminates the connection to the port. func (a *Adaptor) Disconnect() error { if a.sp != nil { if err := a.sp.Close(); err != nil { return err } a.sp = nil } return nil } // Reconnect attempts to reconnect to the port. If the port is connected it will first close // that connection and then establish a new connection. func (a *Adaptor) Reconnect() error { if a.sp != nil { if err := a.Disconnect(); err != nil { return err } } return a.Connect() } // Port returns the adaptors port func (a *Adaptor) Port() string { return a.port } // IsConnected returns the connection state func (a *Adaptor) IsConnected() bool { return a.sp != nil } // SerialRead reads from the port to the given reference func (a *Adaptor) SerialRead(pData []byte) (int, error) { return a.sp.Read(pData) } // SerialWrite writes to the port func (a *Adaptor) SerialWrite(data []byte) (int, error) { return a.sp.Write(data) } ================================================ FILE: platforms/serialport/adaptor_options.go ================================================ package serialport // optionApplier needs to be implemented by each configurable option type type optionApplier interface { apply(cfg *configuration) } // nameOption is the type for applying another name to the configuration type nameOption string // baudRateOption is the type for applying another baud rate than the default 115200 type baudRateOption int func (o nameOption) String() string { return "name option for Serial Port adaptors" } func (o baudRateOption) String() string { return "baud rate option for Serial Port adaptors" } func (o nameOption) apply(cfg *configuration) { cfg.name = string(o) } func (o baudRateOption) apply(cfg *configuration) { cfg.baudRate = int(o) } ================================================ FILE: platforms/serialport/adaptor_options_test.go ================================================ package serialport import ( "testing" "github.com/stretchr/testify/assert" ) func TestWithName(t *testing.T) { // This is a general test, that options are applied by using the WithName() option. // All other configuration options can also be tested by With..(val).apply(cfg). // arrange & act const newName = "new name" a := NewAdaptor("port", WithName(newName)) // assert assert.Equal(t, newName, a.cfg.name) } func TestWithBaudRate(t *testing.T) { // arrange newBaudRate := 5432 cfg := &configuration{baudRate: 1234} // act WithBaudRate(newBaudRate).apply(cfg) // assert assert.Equal(t, newBaudRate, cfg.baudRate) } ================================================ FILE: platforms/serialport/adaptor_test.go ================================================ package serialport import ( "errors" "io" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) var _ gobot.Adaptor = (*Adaptor)(nil) func initTestAdaptor() (*Adaptor, *nullReadWriteCloser) { a := NewAdaptor("/dev/null") rwc := newNullReadWriteCloser() a.connectFunc = func(string, int) (io.ReadWriteCloser, error) { return rwc, nil } if err := a.Connect(); err != nil { panic(err) } return a, rwc } func TestNewAdaptor(t *testing.T) { // arrange a := NewAdaptor("/dev/null") assert.Equal(t, "/dev/null", a.Port()) require.NotNil(t, a.cfg) assert.Equal(t, 115200, a.cfg.baudRate) assert.True(t, strings.HasPrefix(a.Name(), "Serial")) } func TestSerialRead(t *testing.T) { tests := map[string]struct { readDataBuffer []byte simReadErr bool wantCount int wantErr string }{ "read_ok": { readDataBuffer: []byte{0, 0}, wantCount: 2, }, "error_read": { readDataBuffer: []byte{}, simReadErr: true, wantErr: "read error", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange a, rwc := initTestAdaptor() rwc.simulateReadErr = tc.simReadErr // act gotCount, err := a.SerialRead(tc.readDataBuffer) // assert if tc.wantErr == "" { require.NoError(t, err) } else { require.EqualError(t, err, tc.wantErr) } assert.Equal(t, tc.wantCount, gotCount) }) } } func TestSerialWrite(t *testing.T) { tests := map[string]struct { writeDataBuffer []byte simWriteErr bool wantCount int wantWritten []byte wantErr string }{ "write_ok": { writeDataBuffer: []byte{1, 3, 6}, wantWritten: []byte{1, 3, 6}, wantCount: 3, }, "error_write": { writeDataBuffer: []byte{}, simWriteErr: true, wantErr: "write error", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange a, rwc := initTestAdaptor() rwc.simulateWriteErr = tc.simWriteErr // act gotCount, err := a.SerialWrite(tc.writeDataBuffer) // assert if tc.wantErr == "" { require.NoError(t, err) assert.Equal(t, tc.wantWritten, rwc.written) } else { require.EqualError(t, err, tc.wantErr) } assert.Equal(t, tc.wantCount, gotCount) }) } } func TestConnect(t *testing.T) { // arrange a, _ := initTestAdaptor() require.True(t, a.IsConnected()) // act & assert require.EqualError(t, a.Connect(), "serial port is already connected, try reconnect or run disconnect first") // re-arrange error a.sp = nil a.connectFunc = func(string, int) (io.ReadWriteCloser, error) { return nil, errors.New("connect error") } // act & assert require.ErrorContains(t, a.Connect(), "connect error") assert.False(t, a.IsConnected()) } func TestReconnect(t *testing.T) { // arrange a, _ := initTestAdaptor() require.NotNil(t, a.sp) // act & assert require.NoError(t, a.Reconnect()) require.NotNil(t, a.sp) // act & assert require.NoError(t, a.Disconnect()) require.Nil(t, a.sp) // act & assert require.NoError(t, a.Reconnect()) require.NotNil(t, a.sp) } func TestFinalize(t *testing.T) { // arrange a, rwc := initTestAdaptor() // act & assert require.NoError(t, a.Finalize()) assert.False(t, a.IsConnected()) // re-arrange error rwc.simulateCloseErr = true require.NoError(t, a.Connect()) // act & assert require.ErrorContains(t, a.Finalize(), "close error") } ================================================ FILE: platforms/serialport/doc.go ================================================ /* Package serialport provides the Gobot adaptor for serial communication with drivers. For further information refer to readme: https://github.com/hybridgroup/gobot/blob/release/platforms/serialport/README.md */ package serialport // import "gobot.io/x/gobot/v2/platforms/serialport" ================================================ FILE: platforms/serialport/helpers_test.go ================================================ package serialport import "fmt" type nullReadWriteCloser struct { written []byte simulateReadErr bool simulateWriteErr bool simulateCloseErr bool } func newNullReadWriteCloser() *nullReadWriteCloser { return &nullReadWriteCloser{} } func (rwc *nullReadWriteCloser) Write(data []byte) (int, error) { if rwc.simulateWriteErr { return 0, fmt.Errorf("write error") } rwc.written = append(rwc.written, data...) return len(data), nil } func (rwc *nullReadWriteCloser) Read(p []byte) (int, error) { if rwc.simulateReadErr { return 0, fmt.Errorf("read error") } return len(p), nil } func (rwc *nullReadWriteCloser) Close() error { if rwc.simulateCloseErr { return fmt.Errorf("close error") } return nil } ================================================ FILE: platforms/sphero/bb8/LICENSE ================================================ Copyright (c) 2014-2018 The Hybrid Group Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: platforms/sphero/bb8/README.md ================================================ # Sphero BB-8 The Sphero BB-8 is a toy robot from Sphero that is controlled using Bluetooth LE. For more information, go to [http://www.sphero.com/bb8](http://www.sphero.com/bb8) ## How to Install Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) ## How to Use ```go package main import ( "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/bleclient" "gobot.io/x/gobot/v2/drivers/ble/sphero/bb8" ) func main() { bleAdaptor := bleclient.NewAdaptor(os.Args[1]) bb8 := bb8.NewBB8Driver(bleAdaptor) work := func() { gobot.Every(1*time.Second, func() { r := uint8(gobot.Rand(255)) g := uint8(gobot.Rand(255)) b := uint8(gobot.Rand(255)) bb8.SetRGB(r, g, b) }) } robot := gobot.NewRobot("bb", []gobot.Connection{bleAdaptor}, []gobot.Device{bb8}, work, ) err := robot.Start() if err != nil { fmt.Println(err) } } ``` ## How to Connect The Sphero BB-8 is a Bluetooth LE device. You need to know the BLE ID of the BB-8 you want to connect to. The Gobot BLE client adaptor also lets you connect by friendly name, aka "BB-1247". ### OSX To run any of the Gobot BLE code you must use the `GODEBUG=cgocheck=0` flag in order to get around some of the issues in the CGo-based implementation. If you connect by name, then you do not need to worry about the Bluetooth LE ID. However, if you want to connect by ID, OS X uses its own Bluetooth ID system which is different from the IDs used on Linux. The code calls thru the XPC interfaces provided by OSX, so as a result does not need to run under sudo. For example: `GODEBUG=cgocheck=0 go run examples/bb8.go BB-1247` ### Ubuntu On Linux the BLE code will need to run as a root user account. The easiest way to accomplish this is probably to use `go build` to build your program, and then to run the requesting executable using `sudo`. For example: ```sh go build examples/bb8.go sudo ./bb8 BB-1247 ``` ### Windows Hopefully coming soon... ================================================ FILE: platforms/sphero/ollie/LICENSE ================================================ Copyright (c) 2014-2018 The Hybrid Group Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: platforms/sphero/ollie/README.md ================================================ # Sphero Ollie The Sphero Ollie is a toy robot from Sphero that is controlled using Bluetooth LE. For more information, go to [http://www.sphero.com/ollie](http://www.sphero.com/ollie) ## How to Install Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) ## How to Use ```go package main import ( "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/bleclient" "gobot.io/x/gobot/v2/drivers/ble/sphero/ollie" ) func main() { bleAdaptor := bleclient.NewAdaptor(os.Args[1]) ollie := ollie.NewOllieDriver(bleAdaptor) work := func() { gobot.Every(1*time.Second, func() { r := uint8(gobot.Rand(255)) g := uint8(gobot.Rand(255)) b := uint8(gobot.Rand(255)) ollie.SetRGB(r, g, b) }) } robot := gobot.NewRobot("ollieBot", []gobot.Connection{bleAdaptor}, []gobot.Device{ollie}, work, ) err := robot.Start() if err != nil { fmt.Println(err) } } ``` ## How to Connect The Sphero Ollie is a Bluetooth LE device. You need to know the BLE ID of the Ollie you want to connect to. The Gobot BLE client adaptor also lets you connect by friendly name, aka "2B-1247". ### OSX To run any of the Gobot BLE code you must use the `GODEBUG=cgocheck=0` flag in order to get around some of the issues in the CGo-based implementation. If you connect by name, then you do not need to worry about the Bluetooth LE ID. However, if you want to connect by ID, OS X uses its own Bluetooth ID system which is different from the IDs used on Linux. The code calls thru the XPC interfaces provided by OSX, so as a result does not need to run under sudo. For example: `GODEBUG=cgocheck=0 go run examples/ollie.go 2B-1247` ### Ubuntu On Linux the BLE code will need to run as a root user account. The easiest way to accomplish this is probably to use `go build` to build your program, and then to run the requesting executable using `sudo`. For example: ```sh go build examples/ollie.go sudo ./minidrone 2B-1247 ``` ### Windows Hopefully coming soon... ================================================ FILE: platforms/sphero/sphero/LICENSE ================================================ Copyright (c) 2013-2018 The Hybrid Group Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: platforms/sphero/sphero/README.md ================================================ # Sphero Sphero is a sophisticated and programmable robot housed in a polycarbonate sphere shell. The Gobot Serial Adaptor & Sphero Driver makes it easy to interact with Sphero using Go. Once you have your Sphero setup and connected to your computer you can start writing code to make Sphero move, change direction, speed and colors, or detect Sphero events and execute some code when they occur. Learn more about the Sphero robot go here: ## How to Install Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) ## How To Connect ### OSX In order to allow Gobot running on your Mac to access the Sphero, go to "Bluetooth > Open Bluetooth Preferences > Sharing Setup" and make sure that "Bluetooth Sharing" is checked. Now you must pair with the Sphero. Open System Preferences > Bluetooth. Now with the Bluetooth devices windows open, smack the Sphero until it starts flashing three colors. You should see "Sphero-XXX" pop up as available devices where "XXX" is the first letter of the three colors the sphero is flashing. Pair with that device. Once paired your Sphero will be accessable through the serial device similarly named as `/dev/tty.Sphero-XXX-RN-SPP` ### Ubuntu Connecting to the Sphero from Ubuntu or any other Linux-based OS can be done entirely from the command line using [Gort](http://gort.io/) CLI commands. Here are the steps. Find the address of the Sphero, by using: ```sh gort scan bluetooth ``` Pair to Sphero using this command (substituting the actual address of your Sphero): ```sh gort bluetooth pair
``` Connect to the Sphero using this command (substituting the actual address of your Sphero): ```sh gort bluetooth connect
``` ### Windows You should be able to pair your Sphero using your normal system tray applet for Bluetooth, and then connect to the COM port that is bound to the device, such as `COM3`. ## How to Use Example of a simple program that makes the Sphero roll. ```go package main import ( "fmt" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/serial" "gobot.io/x/gobot/v2/platforms/serialport" ) func main() { adaptor := serialport.NewAdaptor("/dev/rfcomm0") driver := sphero.NewSpheroDriver(adaptor) work := func() { gobot.Every(3*time.Second, func() { driver.Roll(30, uint16(gobot.Rand(360))) }) } robot := gobot.NewRobot("sphero", []gobot.Connection{adaptor}, []gobot.Device{driver}, work, ) if err := robot.Start(); err != nil { panic(err) } } ``` ================================================ FILE: platforms/sphero/sprkplus/LICENSE ================================================ Copyright (c) 2014-2018 The Hybrid Group Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: platforms/sphero/sprkplus/README.md ================================================ # Sphero SPRK+ The Sphero SPRK+ is a toy robot from Sphero that is controlled using Bluetooth LE. For more information, go to [http://www.sphero.com/sprk-plus](http://www.sphero.com/sprk-plus) ## How to Install Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) ## How to Use ```go package main import ( "os" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/bleclient" "gobot.io/x/gobot/v2/drivers/ble/sphero" ) func main() { bleAdaptor := bleclient.NewAdaptor(os.Args[1]) sprk := sphero.NewSPRKPlusDriver(bleAdaptor) work := func() { gobot.Every(1*time.Second, func() { r := uint8(gobot.Rand(255)) g := uint8(gobot.Rand(255)) b := uint8(gobot.Rand(255)) sprk.SetRGB(r, g, b) }) } robot := gobot.NewRobot("sprk", []gobot.Connection{bleAdaptor}, []gobot.Device{sprk}, work, ) err := robot.Start() if err != nil { fmt.Println(err) } } ``` ## How to Connect The Sphero SPRK+ is a Bluetooth LE device. You need to know the BLE ID of the SPRK+ you want to connect to. The Gobot BLE client adaptor also lets you connect by friendly name, aka "SK-1247". ### OSX To run any of the Gobot BLE code you must use the `GODEBUG=cgocheck=0` flag in order to get around some of the issues in the CGo-based implementation. If you connect by name, then you do not need to worry about the Bluetooth LE ID. However, if you want to connect by ID, OS X uses its own Bluetooth ID system which is different from the IDs used on Linux. The code calls thru the XPC interfaces provided by OSX, so as a result does not need to run under sudo. For example: `GODEBUG=cgocheck=0 go run examples/sprkplus.go SK-1247` ### Ubuntu On Linux the BLE code will need to run as a root user account. The easiest way to accomplish this is probably to use `go build` to build your program, and then to run the requesting executable using `sudo`. For example: ```sh go build examples/sprkplus.go sudo ./sprkplus SK-1247 ``` ### Windows Hopefully coming soon... ================================================ FILE: platforms/upboard/README.md ================================================ # Upboard This package contains the Gobot adaptor for the [UP2]() IoT platforms. This package currently supports the following hardware: - UP2 (Squared) ================================================ FILE: platforms/upboard/up2/LICENSE ================================================ Copyright (c) 2014-2018 The Hybrid Group Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: platforms/upboard/up2/README.md ================================================ # UP2 The UP2 Board aka "Up Squared" is a single board SoC computer based on the Intel Apollo Lake processor. It has built-in GPIO, PWM, SPI, and I2C interfaces. For more info about the UP2 Board, go to [http://www.up-board.org/upsquared/](http://www.up-board.org/upsquared/). ## How to Install ### Update operating system and BIOS on UP2 board We recommend updating to the latest Ubuntu 16.04 and BIOS v3.3 when using the UP2 board. To update your UP2 OS go to: To update your UP2 BIOS, go to: Once your UP2 has been updated, you will need to provide permission to the `upsquared` user to access the GPIO or I2C subsystems on the board. ### Configuring GPIO on UP2 board To access the GPIO subsystem, you will need to create a new group, add your user to the group, and then add a UDEV rule. First, run the following commands on the board itself: ```sh sudo groupadd gpio sudo adduser upsquared gpio ``` Now, add a new UDEV rule to the UP2 board. Add the following text as a new UDEV rule named `/etc/udev/rules.d/99-gpio.rules`: ```sh SUBSYSTEM=="gpio*", PROGRAM="/bin/sh -c '\ chown -R root:gpiouser /sys/class/gpio && chmod -R 770 /sys/class/gpio;\ chown -R root:gpiouser /sys/devices/virtual/gpio && chmod -R 770 /sys/devices/virtual/gpio;\ chown -R root:gpiouser /sys$devpath && chmod -R 770 /sys$devpath\ '" ``` ### Configuring built-in LEDs on UP2 board To use the built-in LEDs you will need to create a new group, add your user to the group, and then add a UDEV rule. First, run the following commands on the board itself: ```sh sudo groupadd leds sudo adduser upsquared leds ``` Now add the following text as a new UDEV rule named `/etc/udev/rules.d/99-leds.rules`: ```sh SUBSYSTEM=="leds*", PROGRAM="/bin/sh -c '\ chown -R root:leds /sys/class/leds && chmod -R 770 /sys/class/leds;\ chown -R root:leds /sys/devices/platform/up-pinctrl/leds && chmod -R 770 /sys/devices/platform/up-pinctrl/leds;\ chown -R root:leds /sys/devices/platform/AANT0F01:00/upboard-led.* && chmod -R 770 /sys/devices/platform/AANT0F01:00/upboard-led.*;\ '" ``` ### Configuring I2C on UP2 board To access the I2C subsystem, run the following command: ```sh sudo usermod -aG i2c upsquared ``` You should reboot your UP2 board after making these changes for them to take effect. **IMPORTANT NOTE REGARDING I2C:** The current UP2 firmware is not able to scan for I2C devices using the `i2cdetect` command line tool. If you run this tool, it will cause the I2C subsystem to malfunction until you reboot your system. That means at this time, do not use `i2cdetect` on the UP2 board. ### Local setup Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md) ## How to Use The pin numbering used by your Gobot program should match the way your board is labeled right on the board itself. ```go r := up2.NewAdaptor() led := gpio.NewLedDriver(r, "13") ``` You can also use the values `up2.LEDRed`, `up2.LEDBlue`, `up2.LEDGreen`, and `up2.LEDYellow` as pin reference to access the 4 built-in LEDs. For example: ```go r := up2.NewAdaptor() led := gpio.NewLedDriver(r, up2.LEDRed) ``` ## How to Connect ### Compiling Compile your Gobot program on your workstation like this: ```sh GOARCH=amd64 GOOS=linux go build examples/up2_blink.go ``` Once you have compiled your code, you can you can upload your program and execute it on the UP2 from your workstation using the `scp` and `ssh` commands like this: ```sh scp up2_blink upsquared@192.168.1.xxx:/home/upsquared/ ssh -t upsquared@192.168.1.xxx "./up2_blink" ``` ================================================ FILE: platforms/upboard/up2/adaptor.go ================================================ package up2 import ( "fmt" "os" "strconv" "sync" multierror "github.com/hashicorp/go-multierror" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/adaptors" "gobot.io/x/gobot/v2/system" ) const ( // LEDRed is the built-in red LED. LEDRed = "red" // LEDBlue is the built-in blue LED. LEDBlue = "blue" // LEDGreen is the built-in green LED. LEDGreen = "green" // LEDYellow is the built-in yellow LED. LEDYellow = "yellow" defaultI2cBusNumber = 5 defaultSpiBusNumber = 0 defaultSpiChipNumber = 0 defaultSpiMode = 0 defaultSpiBitsNumber = 8 defaultSpiMaxSpeed = 500000 ) type sysfsPin struct { pin int pwmPin int } // Adaptor represents a Gobot Adaptor for the Upboard UP2 type Adaptor struct { *adaptors.DigitalPinsAdaptor *adaptors.PWMPinsAdaptor *adaptors.I2cBusAdaptor *adaptors.SpiBusAdaptor name string sys *system.Accesser mutex sync.Mutex pinMap map[string]sysfsPin ledPath string } // NewAdaptor creates a UP2 Adaptor // // Optional parameters: // // adaptors.WithGpioCdevAccess(): use character device driver instead of sysfs // adaptors.WithSpiGpioAccess(sclk, ncs, sdo, sdi): use GPIO's instead of /dev/spidev#.# // // Further optional parameters for: // // GPIO, see [adaptors.NewDigitalPinsAdaptor] // I2C, see [adaptors.NewI2cBusAdaptor] // PWM, see [adaptors.NewPWMPinsAdaptor] // SPI, see [adaptors.NewSpiBusAdaptor] func NewAdaptor(opts ...interface{}) *Adaptor { sys := system.NewAccesser(system.WithDigitalPinSysfsAccess()) a := &Adaptor{ name: gobot.DefaultName("UP2"), sys: sys, ledPath: "/sys/class/leds/upboard:%s:/brightness", pinMap: fixedPins, } var digitalPinsOpts []adaptors.DigitalPinsOptionApplier var pwmPinsOpts []adaptors.PwmPinsOptionApplier var i2cBusOpts []adaptors.I2CBusOptionApplier var spiBusOpts []adaptors.SpiBusOptionApplier for _, opt := range opts { switch o := opt.(type) { case adaptors.DigitalPinsOptionApplier: digitalPinsOpts = append(digitalPinsOpts, o) case adaptors.PwmPinsOptionApplier: pwmPinsOpts = append(pwmPinsOpts, o) case adaptors.I2CBusOptionApplier: i2cBusOpts = append(i2cBusOpts, o) case adaptors.SpiBusOptionApplier: spiBusOpts = append(spiBusOpts, o) default: panic(fmt.Sprintf("'%s' can not be applied on adaptor '%s'", opt, a.name)) } } // Valid bus numbers are [5,6] which corresponds to /dev/i2c-5 through /dev/i2c-6. i2cBusNumberValidator := adaptors.NewBusNumberValidator([]int{5, 6}) // Valid bus numbers are [0,1] which corresponds to /dev/spidev0.x through /dev/spidev1.x. // x is the chip number <255 spiBusNumberValidator := adaptors.NewBusNumberValidator([]int{0, 1}) a.DigitalPinsAdaptor = adaptors.NewDigitalPinsAdaptor(sys, a.translateDigitalPin, digitalPinsOpts...) a.PWMPinsAdaptor = adaptors.NewPWMPinsAdaptor(sys, a.translatePWMPin, pwmPinsOpts...) a.I2cBusAdaptor = adaptors.NewI2cBusAdaptor(sys, i2cBusNumberValidator.Validate, defaultI2cBusNumber, i2cBusOpts...) a.SpiBusAdaptor = adaptors.NewSpiBusAdaptor(sys, spiBusNumberValidator.Validate, defaultSpiBusNumber, defaultSpiChipNumber, defaultSpiMode, defaultSpiBitsNumber, defaultSpiMaxSpeed, a.DigitalPinsAdaptor, spiBusOpts...) return a } // Name returns the name of the Adaptor func (a *Adaptor) Name() string { return a.name } // SetName sets the name of the Adaptor func (a *Adaptor) SetName(n string) { a.name = n } // Connect create new connection to board and pins. func (a *Adaptor) Connect() error { a.mutex.Lock() defer a.mutex.Unlock() if err := a.SpiBusAdaptor.Connect(); err != nil { return err } if err := a.I2cBusAdaptor.Connect(); err != nil { return err } if err := a.PWMPinsAdaptor.Connect(); err != nil { return err } return a.DigitalPinsAdaptor.Connect() } // Finalize closes connection to board and pins func (a *Adaptor) Finalize() error { a.mutex.Lock() defer a.mutex.Unlock() err := a.DigitalPinsAdaptor.Finalize() if e := a.PWMPinsAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } if e := a.I2cBusAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } if e := a.SpiBusAdaptor.Finalize(); e != nil { err = multierror.Append(err, e) } return err } // DigitalWrite writes digital value to the specified pin. func (a *Adaptor) DigitalWrite(id string, val byte) error { a.mutex.Lock() defer a.mutex.Unlock() // is it one of the built-in LEDs? if id == LEDRed || id == LEDBlue || id == LEDGreen || id == LEDYellow { pinPath := fmt.Sprintf(a.ledPath, id) fi, err := a.sys.OpenFile(pinPath, os.O_WRONLY|os.O_APPEND, 0o666) defer fi.Close() //nolint:staticcheck // for historical reasons if err != nil { return err } _, err = fi.WriteString(strconv.Itoa(int(val))) return err } return a.DigitalPinsAdaptor.DigitalWrite(id, val) } func (a *Adaptor) translateDigitalPin(id string) (string, int, error) { if val, ok := a.pinMap[id]; ok { return "", val.pin, nil } return "", -1, fmt.Errorf("'%s' is not a valid id for a digital pin", id) } func (a *Adaptor) translatePWMPin(id string) (string, int, error) { sysPin, ok := a.pinMap[id] if !ok { return "", -1, fmt.Errorf("'%s' is not a valid id for a pin", id) } if sysPin.pwmPin == -1 { return "", -1, fmt.Errorf("'%s' is not a valid id for a PWM pin", id) } return "/sys/class/pwm/pwmchip0", sysPin.pwmPin, nil } ================================================ FILE: platforms/upboard/up2/adaptor_test.go ================================================ package up2 import ( "fmt" "strconv" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/drivers/gpio" "gobot.io/x/gobot/v2/drivers/i2c" "gobot.io/x/gobot/v2/drivers/spi" "gobot.io/x/gobot/v2/platforms/adaptors" "gobot.io/x/gobot/v2/system" ) // make sure that this Adaptor fulfills all the required interfaces var ( _ gobot.Adaptor = (*Adaptor)(nil) _ gobot.DigitalPinnerProvider = (*Adaptor)(nil) _ gobot.PWMPinnerProvider = (*Adaptor)(nil) _ gpio.DigitalReader = (*Adaptor)(nil) _ gpio.DigitalWriter = (*Adaptor)(nil) _ gpio.PwmWriter = (*Adaptor)(nil) _ gpio.ServoWriter = (*Adaptor)(nil) _ i2c.Connector = (*Adaptor)(nil) _ spi.Connector = (*Adaptor)(nil) ) const ( pwmDir = "/sys/class/pwm/pwmchip0/" //nolint:gosec // false positive pwmExportPath = pwmDir + "export" pwmUnexportPath = pwmDir + "unexport" pwmEnablePath = pwmDir + "pwm0/enable" pwmDutyCyclePath = pwmDir + "pwm0/duty_cycle" pwmPeriodPath = pwmDir + "pwm0/period" pwmPolarityPath = pwmDir + "pwm0/polarity" ) var pwmMockPaths = []string{ pwmExportPath, pwmUnexportPath, pwmEnablePath, pwmPeriodPath, pwmDutyCyclePath, pwmPolarityPath, } var gpioMockPaths = []string{ "/sys/class/gpio/export", "/sys/class/gpio/unexport", "/sys/class/gpio/gpio462/value", "/sys/class/gpio/gpio462/direction", "/sys/class/gpio/gpio432/value", "/sys/class/gpio/gpio432/direction", "/sys/class/leds/upboard:green:/brightness", } func initConnectedTestAdaptorWithMockedFilesystem(mockPaths []string) (*Adaptor, *system.MockFilesystem) { a := NewAdaptor() fs := a.sys.UseMockFilesystem(mockPaths) if err := a.Connect(); err != nil { panic(err) } return a, fs } func TestNewAdaptor(t *testing.T) { // arrange & act a := NewAdaptor() // assert assert.IsType(t, &Adaptor{}, a) assert.True(t, strings.HasPrefix(a.Name(), "UP2")) assert.NotNil(t, a.sys) assert.Equal(t, "/sys/class/leds/upboard:%s:/brightness", a.ledPath) assert.NotNil(t, a.DigitalPinsAdaptor) assert.NotNil(t, a.PWMPinsAdaptor) assert.NotNil(t, a.I2cBusAdaptor) assert.NotNil(t, a.SpiBusAdaptor) assert.True(t, a.sys.HasDigitalPinSysfsAccess()) // act & assert a.SetName("NewName") assert.Equal(t, "NewName", a.Name()) } func TestDigitalIO(t *testing.T) { a, fs := initConnectedTestAdaptorWithMockedFilesystem(gpioMockPaths) _ = a.DigitalWrite("7", 1) assert.Equal(t, "1", fs.Files["/sys/class/gpio/gpio462/value"].Contents) fs.Files["/sys/class/gpio/gpio432/value"].Contents = "1" i, _ := a.DigitalRead("13") assert.Equal(t, 1, i) _ = a.DigitalWrite("green", 1) assert.Equal(t, "1", fs.Files["/sys/class/leds/upboard:green:/brightness"].Contents, ) require.ErrorContains(t, a.DigitalWrite("99", 1), "'99' is not a valid id for a digital pin") require.NoError(t, a.Finalize()) } func TestPWMWrite(t *testing.T) { // arrange a, fs := initConnectedTestAdaptorWithMockedFilesystem(pwmMockPaths) fs.Files[pwmDutyCyclePath].Contents = "0" fs.Files[pwmPeriodPath].Contents = "0" // act err := a.PwmWrite("32", 100) // assert require.NoError(t, err) assert.Equal(t, "0", fs.Files[pwmExportPath].Contents) assert.Equal(t, "1", fs.Files[pwmEnablePath].Contents) assert.Equal(t, "3921568", fs.Files[pwmDutyCyclePath].Contents) assert.Equal(t, "10000000", fs.Files[pwmPeriodPath].Contents) // pwmPeriodDefault assert.Equal(t, "normal", fs.Files[pwmPolarityPath].Contents) require.NoError(t, a.Finalize()) } func TestServoWrite(t *testing.T) { // arrange: prepare 50Hz for servos const ( pin = "32" fiftyHzNano = 20000000 ) a := NewAdaptor(adaptors.WithPWMDefaultPeriodForPin(pin, fiftyHzNano)) fs := a.sys.UseMockFilesystem(pwmMockPaths) require.NoError(t, a.Connect()) fs.Files[pwmDutyCyclePath].Contents = "0" fs.Files[pwmPeriodPath].Contents = "0" // act & assert for 0° (min default value) err := a.ServoWrite(pin, 0) require.NoError(t, err) assert.Equal(t, strconv.Itoa(fiftyHzNano), fs.Files[pwmPeriodPath].Contents) assert.Equal(t, "500000", fs.Files[pwmDutyCyclePath].Contents) // act & assert for 180° (max default value) err = a.ServoWrite(pin, 180) require.NoError(t, err) assert.Equal(t, strconv.Itoa(fiftyHzNano), fs.Files[pwmPeriodPath].Contents) assert.Equal(t, "2500000", fs.Files[pwmDutyCyclePath].Contents) require.NoError(t, a.Finalize()) } func TestFinalizeErrorAfterGPIO(t *testing.T) { a, fs := initConnectedTestAdaptorWithMockedFilesystem(gpioMockPaths) require.NoError(t, a.DigitalWrite("7", 1)) fs.WithWriteError = true err := a.Finalize() require.ErrorContains(t, err, "write error") } func TestFinalizeErrorAfterPWM(t *testing.T) { // indirect test for PWM.Finalize() is called for the adaptor // arrange a, fs := initConnectedTestAdaptorWithMockedFilesystem(pwmMockPaths) fs.Files[pwmDutyCyclePath].Contents = "0" fs.Files[pwmPeriodPath].Contents = "0" require.NoError(t, a.PwmWrite("32", 1)) fs.WithWriteError = true // act err := a.Finalize() // assert require.ErrorContains(t, err, "write error") } func TestSpiDefaultValues(t *testing.T) { a := NewAdaptor() assert.Equal(t, 0, a.SpiDefaultBusNumber()) assert.Equal(t, 0, a.SpiDefaultMode()) assert.Equal(t, int64(500000), a.SpiDefaultMaxSpeed()) } func TestI2cDefaultBus(t *testing.T) { a := NewAdaptor() assert.Equal(t, 5, a.DefaultI2cBus()) } func TestI2cFinalizeWithErrors(t *testing.T) { // arrange a := NewAdaptor() a.sys.UseMockSyscall() fs := a.sys.UseMockFilesystem([]string{"/dev/i2c-5"}) require.NoError(t, a.Connect()) con, err := a.GetI2cConnection(0xff, 5) require.NoError(t, err) _, err = con.Write([]byte{0xbf}) require.NoError(t, err) fs.WithCloseError = true // act err = a.Finalize() // assert require.ErrorContains(t, err, "close error") } func Test_translatePWMPin(t *testing.T) { tests := map[string]struct { wantDir string wantChannel int wantErr error }{ "16": { wantDir: "/sys/class/pwm/pwmchip0", wantChannel: 3, }, "32": { wantDir: "/sys/class/pwm/pwmchip0", wantChannel: 0, }, "33": { wantDir: "/sys/class/pwm/pwmchip0", wantChannel: 1, }, "PWM0": { wantDir: "", wantChannel: -1, wantErr: fmt.Errorf("'PWM0' is not a valid id for a pin"), }, "7": { wantDir: "", wantChannel: -1, wantErr: fmt.Errorf("'7' is not a valid id for a PWM pin"), }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange a := NewAdaptor() // act dir, channel, err := a.translatePWMPin(name) // assert assert.Equal(t, tc.wantErr, err) assert.Equal(t, tc.wantDir, dir) assert.Equal(t, tc.wantChannel, channel) }) } } ================================================ FILE: platforms/upboard/up2/doc.go ================================================ /* Package up2 contains the Gobot adaptor for the Upboard UP2. For further information refer to the UP2 README: https://github.com/hybridgroup/gobot/blob/release/platforms/upboard/up2/README.md */ package up2 // import "gobot.io/x/gobot/v2/platforms/upboard/up2" ================================================ FILE: platforms/upboard/up2/pinmap.go ================================================ package up2 var fixedPins = map[string]sysfsPin{ "7": { pin: 462, // GPIO4 pwmPin: -1, }, "13": { pin: 432, // GPIO27 pwmPin: -1, }, "15": { pin: 431, // GPIO22 pwmPin: -1, }, "16": { pin: 471, // PWM3 pwmPin: 3, }, "18": { pin: 405, // GPIO24 pwmPin: -1, }, "22": { pin: 402, // GPIO25 pwmPin: -1, }, "29": { pin: 430, // GPIO5 pwmPin: -1, }, "31": { pin: 404, // GPIO6 pwmPin: -1, }, "32": { pin: 468, // PWM0 pwmPin: 0, }, "33": { pin: 469, // PWM1 pwmPin: 1, }, "37": { pin: 403, // GPIO26 pwmPin: -1, }, } ================================================ FILE: platforms/upboard/upboard.go ================================================ /* Package upboard contains Gobot adaptors for the Upboard SoC boards. This package currently supports the following hardware: - UP2 (Squared) For further information refer to the Upboard README: https://github.com/hybridgroup/gobot/blob/release/platforms/upboard/README.md */ package upboard ================================================ FILE: robot.go ================================================ package gobot import ( "fmt" "log" "os" "os/signal" "sync" "sync/atomic" multierror "github.com/hashicorp/go-multierror" ) // JSONRobot a JSON representation of a Robot. type JSONRobot struct { Name string `json:"name"` Commands []string `json:"commands"` Connections []*JSONConnection `json:"connections"` Devices []*JSONDevice `json:"devices"` } // NewJSONRobot returns a JSONRobot given a Robot. func NewJSONRobot(robot *Robot) *JSONRobot { jsonRobot := &JSONRobot{ Name: robot.Name, Commands: []string{}, Connections: []*JSONConnection{}, Devices: []*JSONDevice{}, } for command := range robot.Commands() { jsonRobot.Commands = append(jsonRobot.Commands, command) } robot.Devices().Each(func(device Device) { jsonDevice := NewJSONDevice(device) jsonRobot.Connections = append(jsonRobot.Connections, NewJSONConnection(robot.Connection(jsonDevice.Connection))) jsonRobot.Devices = append(jsonRobot.Devices, jsonDevice) }) return jsonRobot } // Robot is a named entity that manages a collection of connections and devices. // It contains its own work routine and a collection of // custom commands to control a robot remotely via the Gobot api. type Robot struct { Commander Eventer Name string Work func() connections *Connections devices *Devices trap func(chan os.Signal) AutoRun bool running atomic.Value done chan bool workRegistry *RobotWorkRegistry WorkEveryWaitGroup *sync.WaitGroup WorkAfterWaitGroup *sync.WaitGroup } // Robots is a collection of Robot type Robots []*Robot // Len returns the amount of Robots in the collection. func (r *Robots) Len() int { return len(*r) } // Start calls the Start method of each Robot in the collection. We return on first error. func (r *Robots) Start(args ...interface{}) error { autoRun := true if args[0] != nil { var ok bool if autoRun, ok = args[0].(bool); !ok { // we treat this as false autoRun = false } } for _, robot := range *r { if err := robot.Start(autoRun); err != nil { return err } } return nil } // Stop calls the Stop method of each Robot in the collection. We try to stop all robots and // collect the errors. func (r *Robots) Stop() error { var err error for _, robot := range *r { if e := robot.Stop(); e != nil { err = multierror.Append(err, e) } } return err } // Each enumerates through the Robots and calls specified callback function. func (r *Robots) Each(f func(*Robot)) { for _, robot := range *r { f(robot) } } // NewRobot returns a new Robot. It supports the following optional params: // // name: string with the name of the Robot. A name will be automatically generated if no name is supplied. // []Connection: Connections which are automatically started and stopped with the robot // []Device: Devices which are automatically started and stopped with the robot // func(): The work routine the robot will execute once all devices and connections have been initialized and started func NewRobot(v ...interface{}) *Robot { r := &Robot{ Name: fmt.Sprintf("%X", Rand(int(^uint(0)>>1))), connections: &Connections{}, devices: &Devices{}, done: make(chan bool, 1), trap: func(c chan os.Signal) { signal.Notify(c, os.Interrupt) }, AutoRun: true, Work: nil, Eventer: NewEventer(), Commander: NewCommander(), } for i := range v { switch val := v[i].(type) { case string: r.Name = val case []Connection: log.Println("Initializing connections...") for _, connection := range val { c := r.AddConnection(connection) log.Println("Initializing connection", c.Name(), "...") } case []Device: log.Println("Initializing devices...") for _, device := range val { d := r.AddDevice(device) log.Println("Initializing device", d.Name(), "...") } case func(): r.Work = val } } r.workRegistry = &RobotWorkRegistry{ r: make(map[string]*RobotWork), } r.WorkAfterWaitGroup = &sync.WaitGroup{} r.WorkEveryWaitGroup = &sync.WaitGroup{} r.running.Store(false) log.Println("Robot", r.Name, "initialized.") return r } // Start a Robot's Connections, Devices, and work. We stop initialization of // connections and devices on first error. func (r *Robot) Start(args ...interface{}) error { if len(args) > 0 && args[0] != nil { var ok bool if r.AutoRun, ok = args[0].(bool); !ok { // we treat this as false r.AutoRun = false } } log.Println("Starting Robot", r.Name, "...") if err := r.Connections().Start(); err != nil { log.Println(err) return err } if err := r.Devices().Start(); err != nil { log.Println(err) return err } if r.Work == nil { r.Work = func() {} } log.Println("Starting work...") go func() { r.Work() <-r.done }() r.running.Store(true) if !r.AutoRun { return nil } c := make(chan os.Signal, 1) r.trap(c) // waiting for interrupt coming on the channel <-c // Stop calls the Stop method on itself, if we are "auto-running". return r.Stop() } // Stop stops a Robot's connections and devices. We try to stop all items and // collect all errors. func (r *Robot) Stop() error { var err error log.Println("Stopping Robot", r.Name, "...") if e := r.Devices().Halt(); e != nil { err = multierror.Append(err, e) } if e := r.Connections().Finalize(); e != nil { err = multierror.Append(err, e) } if !r.Running() { // start was not successful, a full channel would block return err } r.done <- true r.running.Store(false) return err } // Running returns if the Robot is currently started or not func (r *Robot) Running() bool { return r.running.Load().(bool) //nolint:forcetypeassert // no error return value, so there is no better way } // Devices returns all devices associated with this Robot. func (r *Robot) Devices() *Devices { return r.devices } // AddDevice adds a new Device to the robots collection of devices. Returns the // added device. func (r *Robot) AddDevice(d Device) Device { *r.devices = append(*r.Devices(), d) return d } // Device returns a device given a name. Returns nil if the Device does not exist. func (r *Robot) Device(name string) Device { if r == nil { return nil } for _, device := range *r.devices { if device.Name() == name { return device } } return nil } // Connections returns all connections associated with this robot. func (r *Robot) Connections() *Connections { return r.connections } // AddConnection adds a new connection to the robots collection of connections. // Returns the added connection. func (r *Robot) AddConnection(c Connection) Connection { *r.connections = append(*r.Connections(), c) return c } // Connection returns a connection given a name. Returns nil if the Connection // does not exist. func (r *Robot) Connection(name string) Connection { if r == nil { return nil } for _, connection := range *r.connections { if connection.Name() == name { return connection } } return nil } ================================================ FILE: robot_test.go ================================================ package gobot import ( "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestRobotConnectionEach(t *testing.T) { r := newTestRobot("Robot1") i := 0 r.Connections().Each(func(conn Connection) { i++ }) assert.Equal(t, i, r.Connections().Len()) } func TestRobotToJSON(t *testing.T) { r := newTestRobot("Robot99") r.AddCommand("test_function", func(params map[string]interface{}) interface{} { return nil }) json := NewJSONRobot(r) assert.Len(t, json.Devices, r.Devices().Len()) assert.Len(t, json.Commands, len(r.Commands())) } func TestRobotDevicesToJSON(t *testing.T) { r := newTestRobot("Robot99") json := NewJSONRobot(r) assert.Len(t, json.Devices, r.Devices().Len()) assert.Equal(t, "Device1", json.Devices[0].Name) assert.Equal(t, "*gobot.testDriver", json.Devices[0].Driver) assert.Equal(t, "Connection1", json.Devices[0].Connection) assert.Len(t, json.Devices[0].Commands, 1) } func TestRobotStart(t *testing.T) { r := newTestRobot("Robot99") require.NoError(t, r.Start()) require.NoError(t, r.Stop()) assert.False(t, r.Running()) } func TestRobotStartAutoRun(t *testing.T) { adaptor1 := newTestAdaptor("Connection1", "/dev/null") driver1 := newTestDriver(adaptor1, "Device1", "0") // work := func() {} r := NewRobot("autorun", []Connection{adaptor1}, []Device{driver1}, // work, ) errChan := make(chan error, 1) go func() { errChan <- r.Start() // if no strange things happen, this runs until os.signal occurs }() time.Sleep(10 * time.Millisecond) assert.True(t, r.Running()) // stop it require.NoError(t, r.Stop()) assert.False(t, r.Running()) select { case err := <-errChan: require.NoError(t, err) case <-time.After(10 * time.Millisecond): // because the Start() will run forever, until os.Signal, this is ok here } } ================================================ FILE: robot_work.go ================================================ package gobot import ( "context" "fmt" "sync" "time" "github.com/gofrs/uuid" ) // RobotWorkRegistry contains all the work units registered on a Robot type RobotWorkRegistry struct { sync.RWMutex r map[string]*RobotWork } const ( EveryWorkKind = "every" AfterWorkKind = "after" ) // RobotWork and the RobotWork registry represent units of executing computation // managed at the Robot level. Unlike the utility functions gobot.After and gobot.Every, // RobotWork units require a context.Context, and can be cancelled externally by calling code. // // Usage: // // someWork := myRobot.Every(context.Background(), time.Second * 2, func(){ // fmt.Println("Here I am doing work") // }) // // someWork.CallCancelFunc() // Cancel next tick and remove from work registry // // goroutines for Every and After are run on their own WaitGroups for synchronization: // // someWork2 := myRobot.Every(context.Background(), time.Second * 2, func(){ // fmt.Println("Here I am doing more work") // }) // // somework2.CallCancelFunc() // // // wait for both Every calls to finish // robot.WorkEveryWaitGroup().Wait() type RobotWork struct { id uuid.UUID kind string tickCount int ctx context.Context //nolint:containedctx // done by intention cancelFunc context.CancelFunc function func() ticker *time.Ticker duration time.Duration } // ID returns the UUID of the RobotWork func (rw *RobotWork) ID() uuid.UUID { return rw.id } // CancelFunc returns the context.CancelFunc used to cancel the work func (rw *RobotWork) CancelFunc() context.CancelFunc { return rw.cancelFunc } // CallCancelFunc calls the context.CancelFunc used to cancel the work func (rw *RobotWork) CallCancelFunc() { rw.cancelFunc() } // Ticker returns the time.Ticker used in an Every so that calling code can sync on the same channel func (rw *RobotWork) Ticker() *time.Ticker { if rw.kind == AfterWorkKind { return nil } return rw.ticker } // TickCount returns the number of times the function successfully ran func (rw *RobotWork) TickCount() int { return rw.tickCount } // Duration returns the timeout until an After fires or the period of an Every func (rw *RobotWork) Duration() time.Duration { return rw.duration } func (rw *RobotWork) String() string { format := `ID: %s Kind: %s TickCount: %d ` return fmt.Sprintf(format, rw.id, rw.kind, rw.tickCount) } // WorkRegistry returns the Robot's WorkRegistry func (r *Robot) WorkRegistry() *RobotWorkRegistry { return r.workRegistry } // Every calls the given function for every tick of the provided duration. func (r *Robot) Every(ctx context.Context, d time.Duration, f func()) *RobotWork { rw := r.workRegistry.registerEvery(ctx, d, f) r.WorkEveryWaitGroup.Add(1) go func() { EVERYWORK: for { select { case <-rw.ctx.Done(): r.workRegistry.delete(rw.id) rw.ticker.Stop() break EVERYWORK case <-rw.ticker.C: f() rw.tickCount++ } } r.WorkEveryWaitGroup.Done() }() return rw } // After calls the given function after the provided duration has elapsed func (r *Robot) After(ctx context.Context, d time.Duration, f func()) *RobotWork { rw := r.workRegistry.registerAfter(ctx, d, f) ch := time.After(d) r.WorkAfterWaitGroup.Add(1) go func() { AFTERWORK: for { select { case <-rw.ctx.Done(): r.workRegistry.delete(rw.id) break AFTERWORK case <-ch: f() } } r.WorkAfterWaitGroup.Done() }() return rw } // Get returns the RobotWork specified by the provided ID. To delete something from the registry, it's // necessary to call its context.CancelFunc, which will perform a goroutine-safe delete on the underlying // map. func (rwr *RobotWorkRegistry) Get(id uuid.UUID) *RobotWork { rwr.Lock() defer rwr.Unlock() return rwr.r[id.String()] } // Delete returns the RobotWork specified by the provided ID func (rwr *RobotWorkRegistry) delete(id uuid.UUID) { rwr.Lock() defer rwr.Unlock() delete(rwr.r, id.String()) } // registerAfter creates a new unit of RobotWork and sets up its context/cancellation func (rwr *RobotWorkRegistry) registerAfter(ctx context.Context, d time.Duration, f func()) *RobotWork { rwr.Lock() defer rwr.Unlock() id, _ := uuid.NewV4() rw := &RobotWork{ id: id, kind: AfterWorkKind, function: f, duration: d, } rw.ctx, rw.cancelFunc = context.WithCancel(ctx) rwr.r[id.String()] = rw return rw } // registerEvery creates a new unit of RobotWork and sets up its context/cancellation func (rwr *RobotWorkRegistry) registerEvery(ctx context.Context, d time.Duration, f func()) *RobotWork { rwr.Lock() defer rwr.Unlock() id, _ := uuid.NewV4() rw := &RobotWork{ id: id, kind: EveryWorkKind, function: f, duration: d, ticker: time.NewTicker(d), } rw.ctx, rw.cancelFunc = context.WithCancel(ctx) rwr.r[id.String()] = rw return rw } ================================================ FILE: robot_work_test.go ================================================ package gobot import ( "context" "testing" "time" "github.com/gofrs/uuid" "github.com/stretchr/testify/assert" ) func TestRobotWork(t *testing.T) { id, _ := uuid.NewV4() rw := &RobotWork{ id: id, kind: EveryWorkKind, function: func() {}, } duration := time.Second * 1 ctx, cancelFunc := context.WithCancel(t.Context()) rw.ctx = ctx rw.cancelFunc = cancelFunc rw.duration = duration t.Run("ID()", func(t *testing.T) { assert.Equal(t, rw.ID(), id) }) t.Run("Ticker()", func(t *testing.T) { t.Skip() }) t.Run("Duration()", func(t *testing.T) { assert.Equal(t, rw.duration, duration) }) } func TestRobotWorkRegistry(t *testing.T) { robot := NewRobot("testbot") rw := robot.Every(t.Context(), time.Millisecond*250, func() { _ = 1 + 1 }) t.Run("Get retrieves", func(t *testing.T) { assert.Equal(t, robot.workRegistry.Get(rw.id), rw) }) t.Run("delete deletes", func(t *testing.T) { robot.workRegistry.delete(rw.id) postDeleteKeys := collectStringKeysFromWorkRegistry(robot.workRegistry) assert.NotContains(t, postDeleteKeys, rw.id.String()) }) } func TestRobotAutomationFunctions(t *testing.T) { t.Run("Every with cancel", func(t *testing.T) { robot := NewRobot("testbot") counter := 0 rw := robot.Every(t.Context(), time.Millisecond*100, func() { counter++ }) time.Sleep(time.Millisecond * 225) rw.CallCancelFunc() robot.WorkEveryWaitGroup.Wait() assert.Equal(t, 2, counter) postDeleteKeys := collectStringKeysFromWorkRegistry(robot.workRegistry) assert.NotContains(t, postDeleteKeys, rw.id.String()) }) t.Run("After with cancel", func(t *testing.T) { robot := NewRobot("testbot") rw := robot.After(t.Context(), time.Millisecond*10, func() { _ = 1 + 1 // perform mindless computation! }) rw.CallCancelFunc() robot.WorkAfterWaitGroup.Wait() postDeleteKeys := collectStringKeysFromWorkRegistry(robot.workRegistry) assert.NotContains(t, postDeleteKeys, rw.id.String()) }) } func collectStringKeysFromWorkRegistry(rwr *RobotWorkRegistry) []string { keys := make([]string, len(rwr.r)) var idx int for key := range rwr.r { keys[idx] = key idx++ } return keys } ================================================ FILE: system/GPIO.md ================================================ # GPIOs This document describes some basics for developers. This is useful to understand programming in gobot's [digital pin driver](./digitalpin_access.go). ## GPIOs with sysfs > Kernel SYSFS ABI is deprecated since Linux 4.8, see . > For GPIO's we still use the Kernel SYSFS ABI. ## GPIOs with character devices This document provides some test possibilities by using the new character device feature since Kernel 4.8. Please check your Kernel version before using this. Install of "gpiod" is mandatory for the tests. ```sh uname -a Linux raspi 5.15.61+ #1579 Fri Aug 26 11:08:59 BST 2022 armv6l GNU/Linux sudo apt install gpiod ``` > For work on character device user space drivers, please refer to our [issue #775](https://github.com/hybridgroup/gobot/issues/775). ## Check available GPIO banks Example for Tinkerboard (RK3288) with TinkerOS: ```sh ls -la /sys/class/gpio/ total 0 drwxr-xr-x 2 root root 0 Nov 12 06:53 . drwxr-xr-x 66 root root 0 Feb 14 2019 .. --w------- 1 root root 4096 Feb 14 2019 export lrwxrwxrwx 1 root root 0 Feb 14 2019 gpiochip0 -> ../../devices/platform/pinctrl/gpio/gpiochip0 lrwxrwxrwx 1 root root 0 Feb 14 2019 gpiochip120 -> ../../devices/platform/pinctrl/gpio/gpiochip120 lrwxrwxrwx 1 root root 0 Feb 14 2019 gpiochip152 -> ../../devices/platform/pinctrl/gpio/gpiochip152 lrwxrwxrwx 1 root root 0 Feb 14 2019 gpiochip184 -> ../../devices/platform/pinctrl/gpio/gpiochip184 lrwxrwxrwx 1 root root 0 Feb 14 2019 gpiochip216 -> ../../devices/platform/pinctrl/gpio/gpiochip216 lrwxrwxrwx 1 root root 0 Feb 14 2019 gpiochip24 -> ../../devices/platform/pinctrl/gpio/gpiochip24 lrwxrwxrwx 1 root root 0 Feb 14 2019 gpiochip248 -> ../../devices/platform/pinctrl/gpio/gpiochip248 lrwxrwxrwx 1 root root 0 Feb 14 2019 gpiochip56 -> ../../devices/platform/pinctrl/gpio/gpiochip56 lrwxrwxrwx 1 root root 0 Feb 14 2019 gpiochip88 -> ../../devices/platform/pinctrl/gpio/gpiochip88 ``` Example for "Raspberry Pi Model B Rev 2" with "Raspbian GNU/Linux 11 (bullseye)" (26 pin header): ```sh ls -la /sys/class/gpio/ total 0 drwxrwxr-x 2 root gpio 0 Nov 13 09:33 . drwxr-xr-x 58 root root 0 Sep 13 02:58 .. --w--w---- 1 root gpio 4096 Nov 13 09:33 export lrwxrwxrwx 1 root gpio 0 Nov 13 09:33 gpiochip0 -> ../../devices/platform/soc/20200000.gpio/gpio/gpiochip0 --w--w---- 1 root gpio 4096 Nov 13 09:33 unexport gpiodetect gpiochip0 [pinctrl-bcm2835] (54 lines) gpioinfo gpiochip0 - 54 lines: gpiochip0 - 54 lines: ... line 2: "SDA1" unused input active-high line 3: "SCL1" unused input active-high line 4: "GPIO_GCLK" unused input active-high ... line 7: "SPI_CE1_N" unused input active-high line 8: "SPI_CE0_N" unused input active-high line 9: "SPI_SDI" unused input active-high line 10: "SPI_SDO" unused input active-high line 11: "SPI_SCLK" unused input active-high ... line 14: "TXD0" unused input active-high line 15: "RXD0" unused input active-high ... line 17: "GPIO17" unused input active-high line 18: "GPIO18" unused input active-high ... line 22: "GPIO22" unused input active-high line 23: "GPIO23" unused input active-high line 24: "GPIO24" unused input active-high line 25: "GPIO25" unused input active-high ... ``` ## General GPIO tests For Tinkerboard and in general for all other boards: * the name on system level differ from the header name (normally pin1..pin40) * the mapping is done in gobot by a file named something like [pinmap.go](../platforms/asus/tinkerboard/pinmap.go) * for the next tests the system level name is needed Connect an oscilloscope or at least a meter to the pin (used header pin26 for example). For the output tests a LED with a sufficient resistor to 3.3.V (e.g. 290 Ohm) can be used to detect the output state. > On Tinkerboard the pin26 relates to gpio251. For raspi it relates to gpio7. ### Creating gpio251 (sysfs Tinkerboard) > Needs to be "root" for this to work. Switch to root user by "su -". ```sh echo "251" > /sys/class/gpio/export ``` investigate result: ```sh # cat /sys/class/gpio/gpio251/active_low 0 # cat /sys/class/gpio/gpio251/direction in # cat /sys/class/gpio/gpio251/edge none # cat /sys/class/gpio/gpio251/value 1 ``` > The value can float to "1", if the input is open. ### Test input behavior of gpio251 (sysfs Tinkerboard) > Be careful with connecting the input to GND or 3.3V directly, instead use an resistor with minimum 300 Ohm. Connect the input header pin26 to GND. ```sh # cat /sys/class/gpio/gpio251/direction in # cat /sys/class/gpio/gpio251/value 0 ``` Connect the input header pin26 to +3.3V with an resistor (e.g. 1kOhm). ```sh # cat /sys/class/gpio/gpio251/value 1 ``` ### Test edge detection behavior of gpio251 (sysfs Tinkerboard) investigate status: ```sh # cat /sys/class/gpio/gpio251/edge none ``` The file exists only if the pin can be configured as an interrupt generating input pin. To activate edge detection, "rising", "falling", or "both" needs to be set. ```sh # cat /sys/class/gpio/gpio251/value 1 ``` If edge detection is activated, a poll will return only when the interrupt was triggered. The new value is written to the beginning of the file. > Not tested yet, not supported by gobot yet. ### Test output behavior of gpio251 (sysfs Tinkerboard) Connect the output header pin26 to +3.3V with an resistor (e.g. 1kOhm leads to ~0.3mA, 300Ohm leads to ~10mA). ```sh # echo "out" > /sys/class/gpio/gpio251/direction # cat /sys/class/gpio/gpio251/direction out # cat /sys/class/gpio/gpio251/value 0 # echo "1" > /sys/class/gpio/gpio251/value # cat /sys/class/gpio/gpio251/value 1 # echo "0" > /sys/class/gpio/gpio251/value # cat /sys/class/gpio/gpio251/value 0 ``` The meter should show "0V" for values of "0" and "3.3V", when the value was set to "1". > For armbian and Tinkerboard the value remains to "1", although it was set to "0". In this case the pin is not usable > as output. ### Test inverse output behavior of gpio251 (sysfs Tinkerboard) ```sh # cat /sys/class/gpio/gpio251/value 0 # cat /sys/class/gpio/gpio251/active_low 0 # echo "1" > /sys/class/gpio/gpio251/active_low # cat /sys/class/gpio/gpio251/value 1 # echo "0" > /sys/class/gpio/gpio251/value # cat /sys/class/gpio/gpio251/value 0 ``` The meter should show "0V" for values of "1" and "3.3V", when the value was set to "0". ### Test input behavior of gpio7 (cdev Raspi) > Use --help to get some information of the command usage and options, e.g. "gpioget --help". Be careful with connecting > the input to GND or 3.3V directly, instead use an resistor with minimum 300Ohm. Prefer to use the pull-up or pull-down > feature, if working. ```sh sudo gpioget 0 7 1 gpioinfo | grep 'line 7' line 7: "SPI_CE1_N" unused input active-high sudo gpioget --bias=pull-down 0 7 0 ``` >The value can float to "1", if the input is open. Most likely the raspi device has an internal pull-up resistor. >Setting the bias is not possible for sysfs usage. This is one of the advantages of the new character device Kernel feature. ### Test output behavior of gpio7 (cdev Raspi) ```sh sudo gpioset 0 7=0 gpioinfo | grep 'line 7' line 7: "SPI_CE1_N" unused output active-high sudo gpioset 0 7=1 gpioinfo | grep 'line 7' line 7: "SPI_CE1_N" unused output active-high ``` The meter should show "0V" for values of "0" and "3.3V", when the value was set to "1". A connected LED with pull-up resistor lights up for setting to "0" (inverse). ### Test inverse output behavior of gpio7 (cdev Raspi) ```sh sudo gpioset -l 0 7=0 sudo gpioset -l 0 7=1 ``` The meter should show "0V" for values of "1" and "3.3V", when the value was set to "0" (inverse logic). A connected LED with pull-up resistor lights up for setting to "1" (inverse reversed). > The gpioinfo seems to do not recognize the "active-low" set. ## Links * * ================================================ FILE: system/I2C.md ================================================ # I2C This document describes some basics for developers. ## Byte order All common libraries (smbus, digispark, firmata, i2cget) read and write I2C data in the order LSByte, MSByte. Often the devices store its bytes in the reverse order and therefor needs to be swapped after reading. ## Linux syscall implementation In general there are different ioctl features for I2C * IOCTL I2C_RDWR, needs "I2C_FUNC_I2C" * IOCTL SMBUS, needs "I2C_FUNC_SMBUS.." * SYSFS I/O * call of "i2c_smbus_* methods" >The possible functions should be checked before by "I2C_FUNCS". ## SMBus ioctl workflow and functions > Some calls are branched by kernels [i2c-dev.c:i2cdev_ioctl()](https://elixir.bootlin.com/linux/latest/source/drivers/i2c/i2c-dev.c#L392) > to the next listed calls. Set the device address `ioctl(file, I2C_TARGET, long addr)`. The call set the address directly to the character device. Query the supported functions `ioctl(file, I2C_FUNCS, unsigned long *funcs)`. The call is converted to in-kernel function [i2c.h:i2c_get_functionality()](https://elixir.bootlin.com/linux/latest/source/include/linux/i2c.h#L902) Execute a function, if supported `ioctl(file, I2C_SMBUS, struct i2c_smbus_ioctl_data *args)`. The call is converted by kernels [i2c-dev.c:i2cdev_ioctl_smbus](https://elixir.bootlin.com/linux/latest/source/drivers/i2c/i2c-dev.c#L311) to [i2c.h:i2c_smbus_xfer()](https://elixir.bootlin.com/linux/latest/source/include/linux/i2c.h#L140). This leads to call of [i2c-core-smbus.c:i2c_smbus_xfer_emulated()](https://elixir.bootlin.com/linux/latest/source/drivers/i2c/i2c-core-smbus.c#L607) if adapter.algo->smbus_xfer() is not implemented (that means there is no implementation for the current platform/adapter). ```C /* This is the structure as used in the I2C_SMBUS ioctl call */ struct i2c_smbus_ioctl_data { __u8 read_write; __u8 command; __u32 size; union i2c_smbus_data __user *data; }; /* * Data for SMBus Messages */ #define I2C_SMBUS_BLOCK_MAX 32 /* As specified in SMBus standard */ union i2c_smbus_data { __u8 byte; __u16 word; __u8 block[I2C_SMBUS_BLOCK_MAX + 2]; /* block[0] is used for length */ /* and one more for user-space compatibility */ }; ``` ```C // default preparation for call of "status = __i2c_transfer(adapter, msg, nmsgs)" msgbuf0[I2C_SMBUS_BLOCK_MAX+3]; msgbuf1[I2C_SMBUS_BLOCK_MAX+2]; msgbuf0[0] = command; struct i2c_msg msg[2] = { { .addr = addr, .flags = flags, .len = 1, .buf = msgbuf0, }, { .addr = addr, .flags = flags | I2C_M_RD, .len = 0, .buf = msgbuf1, }, }; /* note: msg[0].buf == msgbuf0, means msg[0].buf[0] == msgbuf0[0] msg[0].buf[1] == msgbuf0[1] msg[0].buf[2] == msgbuf0[2] */ ``` ### Data flow for I2C_FUNC_SMBUS_WRITE_BYTE ```C i2c_smbus_write_byte(const struct i2c_client *client, u8 value); \\would call: i2c_smbus_xfer(client->adapter, client->addr, client->flags, I2C_SMBUS_WRITE, value, I2C_SMBUS_BYTE, NULL); ``` gobot: d.smbusAccess(I2C_SMBUS_WRITE, val, I2C_SMBUS_BYTE, nil), calls without a platform driver ```C i2c_smbus_xfer_emulated(*adapter, addr, flags, read_write=I2C_SMBUS_WRITE, command=val, size=I2C_SMBUS_BYTE, *data=NULL); ``` ```C // by default preparation (see above) msg[0].len = 1; msg[0].buf[0] = command; // corresponds to "val" nmsg = 1; ``` ### Data flow for I2C_FUNC_SMBUS_WRITE_BYTE_DATA ```C i2c_smbus_write_byte_data(const struct i2c_client *client, u8 command, u8 value); // would call: data.byte = value; i2c_smbus_xfer(client->adapter, client->addr, client->flags, I2C_SMBUS_WRITE, command, I2C_SMBUS_BYTE_DATA, &data); ``` gobot: d.smbusAccess(I2C_SMBUS_WRITE, reg, I2C_SMBUS_BYTE_DATA, unsafe.Pointer(&data)), calls without a platform driver ```C datasize = sizeof(data->byte); copy_from_user(&temp, data, datasize); i2c_smbus_xfer_emulated(*adapter, addr, flags, read_write=I2C_SMBUS_WRITE, command=reg, size=I2C_SMBUS_BYTE_DATA, *data=&temp); // leads to: msg[0].len = 2; msg[0].buf[0] = command; // corresponds to "reg" msg[0].buf[1] = data->byte; nmsg = 1; ``` ### Data flow for I2C_FUNC_SMBUS_WRITE_WORD_DATA ```C i2c_smbus_write_word_data(const struct i2c_client *client, u8 command, u16 value); // would call: data.word = value; i2c_smbus_xfer(client->adapter, client->addr, client->flags, I2C_SMBUS_WRITE, command, I2C_SMBUS_WORD_DATA, &data); ``` gobot: d.smbusAccess(I2C_SMBUS_WRITE, reg, I2C_SMBUS_WORD_DATA, unsafe.Pointer(&data)), calls without a platform driver ```C datasize = sizeof(data->word); copy_from_user(&temp, data, datasize); i2c_smbus_xfer_emulated(*adapter, addr, flags, read_write=I2C_SMBUS_WRITE, command=reg, size=I2C_SMBUS_WORD_DATA, *data=&temp); // leads to: msg[0].len = 3; msg[0].buf[0] = command; msg[0].buf[1] = data->word & 0xff; msg[0].buf[2] = data->word >> 8; nmsg = 1; ``` ### Data flow for I2C_FUNC_SMBUS_WRITE_BLOCK_DATA ```C i2c_smbus_write_block_data(const struct i2c_client *client, u8 command, u8 length, const u8 *values); // would call: data.block[0] = length; // set first data element to length memcpy(&data.block[1], values, length); // ...followed by the real data values i2c_smbus_xfer(client->adapter, client->addr, client->flags, I2C_SMBUS_WRITE, command, I2C_SMBUS_BLOCK_DATA, &data); ``` gobot: do not use this feature, but this would call without a platform driver ```C datasize = sizeof(data->block); // it seems this just blocks 32+2 copy_from_user(&temp, data, datasize); // but possibly this only copy what is there i2c_smbus_xfer_emulated(*adapter, addr, flags, read_write==I2C_SMBUS_WRITE, command=reg, size==I2C_SMBUS_BLOCK_DATA, *data==&temp); // leads to: // this reads the length from given user data, first element, add 2 for command and one more for user space compatibility: msg[0].len = data->block[0] + 2; msg[0].buf[0] = command; // by i2c_smbus_try_get_dmabuf(&msg[0], command) msg[0].buf + 1 = data->block; // copy with size!, by memcpy(msg[0].buf + 1, data->block, msg[0].len - 1); nmsg = 1; ``` > "i2c_smbus_write_block_data" adds the real data size as first value in data. Writing this to the device is intended > for SMBus devices, see "section 6.5.7 Block Write/Read" of [smbus 3.0 specification](http://smbus.org/specs/SMBus_3_0_20141220.pdf). > Implementing this behavior in gobot leads to writing the size as first data element, but this is normally not useful > for i2c devices. When using ioctl calls there is no way to drop the size element by using this call. ### Data flow for I2C_FUNC_SMBUS_WRITE_I2C_BLOCK ```C i2c_smbus_write_i2c_block_data(const struct i2c_client *client, u8 command, u8 length, const u8 *values); // would call: data.block[0] = length; // set first data element to length memcpy(data.block + 1, values, length); // ...followed by the real data values i2c_smbus_xfer(client->adapter, client->addr, client->flags, I2C_SMBUS_WRITE, command, I2C_SMBUS_I2C_BLOCK_DATA, &data); ``` gobot: ```go // set the first element with the data size dataLen := len(data) buf := make([]byte, dataLen+1) buf[0] = byte(dataLen) copy(buf[1:], data) d.smbusAccess(I2C_SMBUS_WRITE, reg, I2C_SMBUS_I2C_BLOCK_DATA, unsafe.Pointer(&buf[0])) ``` ...calls without a platform driver ```C datasize = sizeof(data->block); // it seems this just blocks 32+2 copy_from_user(&temp, data, datasize); // but possibly this only copy what is there i2c_smbus_xfer_emulated(*adapter, addr, flags, read_write==I2C_SMBUS_WRITE, command=reg, size==I2C_SMBUS_I2C_BLOCK_DATA, *data==&temp); // this reads the length from given user data, first element, add 1 for command: msg[0].len = data->block[0] + 1; msg[0].buf[0] = command; // by i2c_smbus_try_get_dmabuf(&msg[0], command) msg[0].buf + 1 = data->block + 1; // copy real data without size, by memcpy(msg[0].buf + 1, data->block + 1, data->block[0]); nmsg=1 ``` ### Data flow for I2C_FUNC_SMBUS_READ_BYTE ```C i2c_smbus_read_byte(const struct i2c_client *client); // would call: i2c_smbus_xfer(client->adapter, client->addr, client->flags, I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &data); return data.byte; ``` gobot: d.smbusAccess(I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, unsafe.Pointer(&data)), calls without a platform driver ```C datasize = sizeof(data->byte); // &temp keeps empty i2c_smbus_xfer_emulated(*adapter, addr, flags, read_write==I2C_SMBUS_READ, command=0, size==I2C_SMBUS_BYTE, *data==&temp); msg[0].len = 1; // per default msg[0].flags = I2C_M_RD | flags; msg[0].buf[0] = 0; // from command nmsgs = 1; ``` afterwards copy content to target structure ```C data->byte = msg[0].buf[0]; // copy read value back to given data pointer and one level above copy_to_user(data, &temp, datasize); // copy one byte back to given data pointer ``` ### Data flow for I2C_FUNC_SMBUS_READ_BYTE_DATA ```C i2c_smbus_read_byte_data(const struct i2c_client *client, u8 command); // would call: i2c_smbus_xfer(client->adapter, client->addr, client->flags, I2C_SMBUS_READ, command, I2C_SMBUS_BYTE_DATA, &data); return data.byte; ``` gobot: d.smbusAccess(I2C_SMBUS_READ, reg, I2C_SMBUS_BYTE_DATA, unsafe.Pointer(&data)), calls without a platform driver ```C datasize = sizeof(data->byte); // &temp keeps empty i2c_smbus_xfer_emulated(*adapter, addr, flags, read_write==I2C_SMBUS_READ, command=reg, size==I2C_SMBUS_BYTE_DATA, *data==&temp); msg[0].len = 1; // per default msg[0].buf[0] = command; msg[1].len = 1; nmsgs = 2; ``` afterwards copy content to target structure ```C data->byte = msg[1].buf[0]; // copy read value back to given data pointer and one level above copy_to_user(data, &temp, datasize); // copy one byte back to given data pointer ``` ### Data flow for I2C_FUNC_SMBUS_READ_WORD_DATA ```C i2c_smbus_read_word_data(const struct i2c_client *client, u8 command); // would call: status = i2c_smbus_xfer(client->adapter, client->addr, client->flags, I2C_SMBUS_READ, command, I2C_SMBUS_WORD_DATA, &data); return data.word; ``` gobot: d.smbusAccess(I2C_SMBUS_READ, reg, I2C_SMBUS_WORD_DATA, unsafe.Pointer(&data)), calls without a platform driver ```C datasize = sizeof(data->word); // &temp keeps empty i2c_smbus_xfer_emulated(*adapter, addr, flags, read_write==I2C_SMBUS_READ, command=reg, size==I2C_SMBUS_BYTE_DATA, *data==&temp); msg[0].len = 1; // per default msg[0].buf[0] = command; msg[1].len = 2; nmsgs = 2; ``` afterwards copy content to target structure ```C data->word = msgbuf1[0] | (msgbuf1[1] << 8); // copy read value back to given data pointer and one level above copy_to_user(data, &temp, datasize); // copy 2 bytes back to given data pointer ``` ### Data flow for I2C_FUNC_SMBUS_READ_BLOCK_DATA ```C i2c_smbus_read_block_data(const struct i2c_client *client, u8 command, u8 *values); // would call: i2c_smbus_xfer(client->adapter, client->addr, client->flags, I2C_SMBUS_READ, command, I2C_SMBUS_BLOCK_DATA, &data); // data.block[0] is the read length (N) memcpy(values, &data.block[1], data.block[0]); // copy starting from data.block[1] to "values", N elements return data.block[0]; // number of read bytes (N) ``` gobot: do not use this feature, but this would call without a platform driver ```C datasize = sizeof(data->block); // &temp keeps empty i2c_smbus_xfer_emulated(*adapter, addr, flags, read_write==I2C_SMBUS_READ, command=reg, size==I2C_SMBUS_BYTE_DATA, *data==&temp); msg[0].len = 1; // per default msg[0].buf[0] = command; msg[1].flags |= I2C_M_RECV_LEN; msg[1].len = 1; // block length will be added by the underlying bus driver msg[1].buf[0] = 0; // by i2c_smbus_try_get_dmabuf(&msg[1], 0); nmsgs = 2; ``` afterwards copy content to target structure ```C memcpy(data->block, msg[1].buf, msg[1].buf[0] + 1); // copy read value back to given data pointer and one level above copy_to_user(data, &temp, datasize); // copy all bytes (according to given size) back to given data pointer ``` ### Data flow for I2C_FUNC_SMBUS_READ_I2C_BLOCK ```C i2c_smbus_read_i2c_block_data(const struct i2c_client *client, u8 command, u8 length, u8 *values); // would call: data.block[0] = length; // set first data element to length i2c_smbus_xfer(client->adapter, client->addr, client->flags, I2C_SMBUS_READ, command, I2C_SMBUS_I2C_BLOCK_DATA, &data); // data.block[0] is the read length (N) memcpy(values, &data.block[1], data.block[0]); // copy starting from data.block[1] to "values", N elements return data.block[0]; // number of read bytes (N) ``` gobot: ```go dataLen := len(data) // set the first element with the data size buf := make([]byte, dataLen+1) buf[0] = byte(dataLen) copy(buf[1:], data) log.Printf("buffer: %v", buf) d.smbusAccess(I2C_SMBUS_READ, reg, I2C_SMBUS_I2C_BLOCK_DATA, unsafe.Pointer(&buf[0])); err != nil { // get data from buffer without first size element copy(data, buf[1:]) ``` ...calls without a platform driver ```C datasize = sizeof(data->block); // &temp keeps empty, datasize includes the "size" byte (means real data + 1) copy_from_user(&temp, data, datasize); // but possibly this only copy what is there i2c_smbus_xfer_emulated(*adapter, addr, flags, read_write==I2C_SMBUS_READ, command=reg, size==I2C_SMBUS_I2C_BLOCK_DATA, *data==&temp); msg[0].len = 1; // per default msg[0].buf[0] = command; msg[1].len = data->block[0]; // this reads the length from given user data, first element: msg[1].buf[0] = 0; // by i2c_smbus_try_get_dmabuf(&msg[1], 0); nmsgs = 2; ``` afterwards copy content to target structure ```C // copy read values back, starting from second value (contains length) memcpy(data->block + 1, msg[1].buf, data->block[0]); // and one level above: copy_to_user(data, &temp, datasize); // copy all bytes (according to given size) back to given data pointer // this means, the caller needs to strip the real data starting from second byte (like "i2c_smbus_read_i2c_block_data") ``` ## Links * * * (good for understanding, but there are some small errors in the provided example) * > Qotation from kernel.org: "If possible, use the provided i2c_smbus_* methods described below instead of issuing direct > ioctls." > We do not do this at the moment, instead we using the "IOCTL SMBUS". Because the syscall needs uintptr in Go, there are some known pitfalls with that. Following documents could be helpful: * * * * * for go vet false positives, see: Basically by convert to an uintptr, which is than just a number to an object existing at the moment of creation without any other reference, the garbage collector will possible destroy the original object. Therefor uintptr should be avoided as long as possible. ================================================ FILE: system/ONEWIRE.md ================================================ # 1-wire bus This document describes some basics for developers. This is useful to understand programming in gobot's [1-wire driver](./onewiredevice_sysfs.go). ## 1-wire with sysfs If the 1-wire bus is enabled on the board, the bus data can be connected to one pin of the used platform. The enabling activates the Kernel drivers for common devices (family drivers), which are than mapped to the sysfs, see . ## Check available 1-wire devices Example for Tinkerboard (RK3288) with armbian and 3 connected temperature sensors DS18B20: ```sh ls -la /sys/bus/w1/devices/ insgesamt 0 drwxr-xr-x 2 root root 0 29. Okt 08:58 . drwxr-xr-x 4 root root 0 29. Okt 08:58 .. lrwxrwxrwx 1 root root 0 31. Okt 07:55 28-072261452f18 -> ../../../devices/w1_bus_master1/28-072261452f18 lrwxrwxrwx 1 root root 0 31. Okt 07:55 28-08225482b0de -> ../../../devices/w1_bus_master1/28-08225482b0de lrwxrwxrwx 1 root root 0 31. Okt 07:55 28-1e40710a6461 -> ../../../devices/w1_bus_master1/28-1e40710a6461 lrwxrwxrwx 1 root root 0 29. Okt 08:58 w1_bus_master1 -> ../../../devices/w1_bus_master1 ``` Within a device folder different files are available for typical access. ```sh ls -la /sys/bus/w1/devices/28-072261452f18/ insgesamt 0 drwxr-xr-x 4 root root 0 29. Okt 08:58 . drwxr-xr-x 6 root root 0 29. Okt 08:58 .. -rw-r--r-- 1 root root 4096 31. Okt 07:57 alarms -rw-r--r-- 1 root root 4096 31. Okt 07:57 conv_time lrwxrwxrwx 1 root root 0 31. Okt 07:57 driver -> ../../../bus/w1/drivers/w1_slave_driver --w------- 1 root root 4096 31. Okt 07:57 eeprom_cmd -r--r--r-- 1 root root 4096 31. Okt 07:57 ext_power -rw-r--r-- 1 root root 4096 31. Okt 07:57 features drwxr-xr-x 3 root root 0 29. Okt 08:58 hwmon -r--r--r-- 1 root root 4096 31. Okt 07:57 id -r--r--r-- 1 root root 4096 31. Okt 07:57 name drwxr-xr-x 2 root root 0 31. Okt 07:13 power -rw-r--r-- 1 root root 4096 31. Okt 11:10 resolution lrwxrwxrwx 1 root root 0 29. Okt 08:58 subsystem -> ../../../bus/w1 -r--r--r-- 1 root root 4096 31. Okt 07:57 temperature -rw-r--r-- 1 root root 4096 29. Okt 08:58 uevent -rw-r--r-- 1 root root 4096 31. Okt 07:57 w1_slave ``` This files depends on the family driver. ## Different access levels and modes Currently gobot supports only direct access to the devices in automatic search mode of the controller device. The implementation is similar to the sysfs access of the analog pin driver. E.g. if the cyclic device search should be avoided, the access to the controller device is needed, see Kernel documentation. If this will be implemented in the future, have in mind that more than one controller devices are possible. The gobot's 1-wire architecture can be changed then similar to SPI or I2C. ## Troubleshooting If something is not working, please check this points: Is the correct gpio used: `cat /sys/kernel/debug/gpio` Does the base path exist: `ls /sys/bus/w1/` Is the Kernel module loaded: `lsmod | grep wire` Is the onewire support activated in the device tree: `dtc -I fs -O dts /sys/firmware/devicetree/base | grep onewire` Is there an according overlay on the system: `locate w1-gpio` Is the overlay loading configured: `cat /boot/armbianEnv.txt` Is the content of the overlay correct: `dtc -I dtb -O dts -o -w1-gpio.dtbo.dts /boot/dtb/overlay/-w1-gpio.dtbo` ================================================ FILE: system/PWM.md ================================================ # PWM's This document describes some basics for developers. ## Check the PWM features Example for Tinkerboard: ```sh # ls -la /sys/class/pwm/ total 0 drwxr-xr-x 2 root root 0 Apr 24 14:11 . drwxr-xr-x 66 root root 0 Apr 24 14:09 .. lrwxrwxrwx 1 root root 0 Apr 24 14:09 pwmchip0 -> ../../devices/platform/ff680000.pwm/pwm/pwmchip0 lrwxrwxrwx 1 root root 0 Apr 24 14:09 pwmchip1 -> ../../devices/platform/ff680010.pwm/pwm/pwmchip1 lrwxrwxrwx 1 root root 0 Apr 24 14:09 pwmchip2 -> ../../devices/platform/ff680030.pwm/pwm/pwmchip2 ``` ```sh # ls -la /sys/class/pwm/pwmchip2/ total 0 drwxr-xr-x 3 root root 0 Apr 24 14:17 . drwxr-xr-x 3 root root 0 Apr 24 14:17 .. lrwxrwxrwx 1 root root 0 Apr 24 14:17 device -> ../../../ff680030.pwm --w------- 1 root root 4096 Apr 24 14:17 export -r--r--r-- 1 root root 4096 Apr 24 14:17 npwm drwxr-xr-x 2 root root 0 Apr 24 14:17 power lrwxrwxrwx 1 root root 0 Apr 24 14:17 subsystem -> ../../../../../class/pwm -rw-r--r-- 1 root root 4096 Apr 24 14:17 uevent --w------- 1 root root 4096 Apr 24 14:17 unexport ``` ## General PWM tests Connect an oscilloscope or at least a meter to the pin (used pin32 for example with Tinkerboard). Switch to root user by "su -". ### Investigate state of PWMs For Tinkerboard: * ff680000 and ff680010 seems to be not usable (unknown, which functionality make use of that, maybe fan?) * if there is no ff680020, ff680030, this can be activated. See section [Change available features](README.md#change-available-features) ### Creating pwm0 on pwmchip2 ```sh echo 0 > /sys/class/pwm/pwmchip2/export ``` investigate result: ```sh # ls /sys/class/pwm/pwmchip2/ device export npwm power pwm0 subsystem uevent unexport # ls /sys/class/pwm/pwmchip2/pwm0/ capture duty_cycle enable period polarity power uevent # cat /sys/class/pwm/pwmchip2/pwm0/period 0 # cat /sys/class/pwm/pwmchip2/pwm0/duty_cycle 0 # cat /sys/class/pwm/pwmchip2/pwm0/enable 0 # cat /sys/class/pwm/pwmchip2/pwm0/polarity inversed ``` ### Initialization of pwm0 ```sh echo 10000000 > /sys/class/pwm/pwmchip2/pwm0/period echo "normal" > /sys/class/pwm/pwmchip2/pwm0/polarity echo 3000000 > /sys/class/pwm/pwmchip2/pwm0/duty_cycle # this means 30% echo 1 > /sys/class/pwm/pwmchip2/pwm0/enable ``` > Before writing the period, all other write actions will cause an error "-bash: echo: write error: Invalid argument". > The "period" is in nanoseconds (or a frequency divider for 1GHz), 1000 will produce a frequency of 1MHz, 1000000 will > cause a frequency of 1kHz. For the example 10000000 we have 100Hz. Now we should measure a value of around 1V with the meter, because the basis value is 3.3V and 30% leads to 1V. Try to inverse the sequence: `echo "inversed" > /sys/class/pwm/pwmchip2/pwm0/polarity` Now we should measure a value of around 2.3V with the meter, which is the difference of 1V to 3.3V. If we have attached an oscilloscope we can play around with the values for period and duty_cycle and see what happen. ## Links * ================================================ FILE: system/README.md ================================================ # system This document describes some basics for developers. > The gobot package name is a little bit misleading, because also contains `/dev/i2c-*` usage with syscall for i2c > interface and the file system mock for unit testing. ## Change available features on TinkerOS (Tinkerboard) Open the file /boot/config.txt and add lines/remove comment sign. Then save the file, close and reboot. ### For PWM on TinkerOS (Tinkerboard) intf:pwm2=on intf:pwm3=on ### For i2c on TinkerOS (Tinkerboard) intf:i2c1=on intf:i2c4=on Device tree overlays can also be provided, e.g. "overlay=i2c-100kbit-tinker-overlay". Create a dts-file "i2c1-100kbit-tinker-overlay.dts" with this content: ```c // Definitions for i2c1 with 100 kbit /dts-v1/; /plugin/; / { compatible = "rockchip,rk3288-evb-rk808-linux", "rockchip,rk3288"; fragment@0 { target = <&i2c1>; __overlay__ { status = "okay"; clock-frequency = <100000>; }; }; }; ``` Compile the tree overlay: ```sh dtc -@ -I dts -O dtb -o i2c1-100kbit-tinker-overlay.dtbo i2c1-100kbit-tinker-overlay.dts ``` Copy the file to "/boot/overlays/i2c-100kbit-tinker-overlay.dtbo" > Package "device-tree-compiler" needs to be installed for "dtc" command. ## Change available features on raspi Start "raspi-config" and go to the menu "interface options". After change something save and reboot the device. ## Change available features on armbian Install the armbian-config utility (howto is shown after each login) and start it. ### For i2c on armbian Open the related menu entry and activate/deactivate the needed features. ### For PWM on armbian Go to the device tree menu - this opens the device tree for editing. Looking for the pwm entries. There are some marked with "disabled". Change the entry to "okay" for your needed pwm. Example for Tinkerboard: ff680020 => pwm2, pin33 ff680030 => pwm3, pin32 ## Next steps for developers * test [gpio](GPIO.md) * test [pwm](PWM.md) * background information for [i2c](I2C.md) in gobot ## Links * ================================================ FILE: system/analogpin_sysfs.go ================================================ package system import "fmt" type analogPinSysFs struct { sysfsPath string r, w bool sfa *sysfsFileAccess } func newAnalogPinSysfs(sfa *sysfsFileAccess, path string, r, w bool) *analogPinSysFs { p := &analogPinSysFs{ sysfsPath: path, sfa: sfa, r: r, w: w, } return p } // Read reads a value from sysf path func (p *analogPinSysFs) Read() (int, error) { if !p.r { return 0, fmt.Errorf("the pin '%s' is not allowed to read", p.sysfsPath) } return p.sfa.readInteger(p.sysfsPath) } // Write writes a value to sysf path func (p *analogPinSysFs) Write(val int) error { if !p.w { return fmt.Errorf("the pin '%s' is not allowed to write (val: %v)", p.sysfsPath, val) } return p.sfa.writeInteger(p.sysfsPath, val) } ================================================ FILE: system/analogpin_sysfs_test.go ================================================ package system import ( "fmt" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func Test_newAnalogPinSysfs(t *testing.T) { // arrange m := &MockFilesystem{} sfa := sysfsFileAccess{fs: m, readBufLen: 2} const path = "/sys/whatever" // act pin := newAnalogPinSysfs(&sfa, path, true, false) // assert assert.Equal(t, path, pin.sysfsPath) assert.Equal(t, &sfa, pin.sfa) assert.True(t, pin.r) assert.False(t, pin.w) } func TestRead(t *testing.T) { const ( sysfsPath = "/sys/testread" value = "32" ) tests := map[string]struct { readable bool simErr bool wantVal int wantErr string }{ "read_ok": { readable: true, wantVal: 32, }, "error_not_readable": { readable: false, wantErr: "the pin '/sys/testread' is not allowed to read", }, "error_on_read": { readable: true, simErr: true, wantErr: "read error", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange fs := newMockFilesystem([]string{sysfsPath}) sfa := sysfsFileAccess{fs: fs, readBufLen: 2} pin := newAnalogPinSysfs(&sfa, sysfsPath, tc.readable, false) fs.Files[sysfsPath].Contents = value if tc.simErr { fs.Files[sysfsPath].simulateReadError = fmt.Errorf("read error") } // act got, err := pin.Read() // assert if tc.wantErr != "" { require.EqualError(t, err, tc.wantErr) } else { require.NoError(t, err) } assert.Equal(t, tc.wantVal, got) }) } } func TestWrite(t *testing.T) { const ( sysfsPath = "/sys/testwrite" oldVal = "old_value" ) tests := map[string]struct { writeable bool simErr bool wantVal string wantErr string }{ "write_ok": { writeable: true, wantVal: "23", }, "error_not_writeable": { writeable: false, wantErr: "the pin '/sys/testwrite' is not allowed to write (val: 23)", wantVal: oldVal, }, "error_on_write": { writeable: true, simErr: true, wantErr: "write error", wantVal: "23", // the mock is implemented in this way }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange fs := newMockFilesystem([]string{sysfsPath}) sfa := sysfsFileAccess{fs: fs, readBufLen: 10} pin := newAnalogPinSysfs(&sfa, sysfsPath, false, tc.writeable) fs.Files[sysfsPath].Contents = oldVal if tc.simErr { fs.Files[sysfsPath].simulateWriteError = fmt.Errorf("write error") } // act err := pin.Write(23) // assert if tc.wantErr != "" { require.EqualError(t, err, tc.wantErr) } else { require.NoError(t, err) } assert.Equal(t, tc.wantVal, fs.Files[sysfsPath].Contents) }) } } ================================================ FILE: system/digitalpin_bench_test.go ================================================ package system import ( "testing" ) func BenchmarkDigitalRead(b *testing.B) { a := NewAccesser() mockPaths := []string{ "/sys/class/gpio/export", "/sys/class/gpio/unexport", "/sys/class/gpio/gpio10/value", "/sys/class/gpio/gpio10/direction", } a.UseMockFilesystem(mockPaths) pin := a.NewDigitalPin("", 10) _ = pin.Write(1) for i := 0; i < b.N; i++ { _, _ = pin.Read() } } ================================================ FILE: system/digitalpin_cdev.go ================================================ package system import ( "errors" "fmt" "log" "strconv" "strings" "time" gpiocdev "github.com/warthog618/go-gpiocdev" "gobot.io/x/gobot/v2" ) const systemCdevDebug = false type cdevLine interface { SetValue(value int) error Value() (int, error) Close() error } type digitalPinCdev struct { *digitalPinConfig chipName string pin int line cdevLine } var digitalPinCdevReconfigure = digitalPinCdevReconfigureLine // to allow unit testing var ( digitalPinCdevUsed = map[bool]string{true: "used", false: "unused"} digitalPinCdevActiveLow = map[bool]string{true: "low", false: "high"} digitalPinCdevDebounced = map[bool]string{true: "debounced", false: "not debounced"} ) var digitalPinCdevDirection = map[gpiocdev.LineDirection]string{ gpiocdev.LineDirectionUnknown: "unknown direction", gpiocdev.LineDirectionInput: "input", gpiocdev.LineDirectionOutput: "output", } var digitalPinCdevDrive = map[gpiocdev.LineDrive]string{ gpiocdev.LineDrivePushPull: "push-pull", gpiocdev.LineDriveOpenDrain: "open-drain", gpiocdev.LineDriveOpenSource: "open-source", } var digitalPinCdevBias = map[gpiocdev.LineBias]string{ gpiocdev.LineBiasUnknown: "unknown", gpiocdev.LineBiasDisabled: "disabled", gpiocdev.LineBiasPullUp: "pull-up", gpiocdev.LineBiasPullDown: "pull-down", } var digitalPinCdevEdgeDetect = map[gpiocdev.LineEdge]string{ gpiocdev.LineEdgeNone: "no", gpiocdev.LineEdgeRising: "rising", gpiocdev.LineEdgeFalling: "falling", gpiocdev.LineEdgeBoth: "both", } var digitalPinCdevEventClock = map[gpiocdev.LineEventClock]string{ gpiocdev.LineEventClockMonotonic: "monotonic", gpiocdev.LineEventClockRealtime: "realtime", } // newDigitalPinCdev returns a digital pin given the pin number, with the label "gobotio" followed by the pin number. // The pin label can be modified optionally. The pin is handled by the character device Kernel ABI. func newDigitalPinCdev(chipName string, pin int, options ...func(gobot.DigitalPinOptioner) bool) *digitalPinCdev { if chipName == "" { chipName = "gpiochip0" } cfg := newDigitalPinConfig("gobotio"+strconv.Itoa(pin), options...) d := &digitalPinCdev{ chipName: chipName, pin: pin, digitalPinConfig: cfg, } return d } // ApplyOptions apply all given options to the pin immediately. Implements interface gobot.DigitalPinOptionApplier. func (d *digitalPinCdev) ApplyOptions(options ...func(gobot.DigitalPinOptioner) bool) error { anyChange := false for _, option := range options { anyChange = option(d) || anyChange } if anyChange { return digitalPinCdevReconfigure(d, false) } return nil } // DirectionBehavior gets the direction behavior when the pin is used the next time. This means its possibly not in // this direction type at the moment. Implements the interface gobot.DigitalPinValuer, but should be rarely used. func (d *digitalPinCdev) DirectionBehavior() string { return d.direction } // Export sets the pin as used by this driver. Implements the interface gobot.DigitalPinner. func (d *digitalPinCdev) Export() error { err := digitalPinCdevReconfigure(d, false) if err != nil { return fmt.Errorf("cdev.Export(): %v", err) } return nil } // Unexport releases the pin as input. Implements the interface gobot.DigitalPinner. func (d *digitalPinCdev) Unexport() error { var errs []string if d.line != nil { if err := digitalPinCdevReconfigure(d, true); err != nil { errs = append(errs, err.Error()) } if err := d.line.Close(); err != nil { err = fmt.Errorf("cdev.Unexport()-line.Close(): %v", err) errs = append(errs, err.Error()) } } if len(errs) == 0 { return nil } return errors.New(strings.Join(errs, ",")) } // Write writes the given value to the character device. Implements the interface gobot.DigitalPinner. func (d *digitalPinCdev) Write(val int) error { if val < 0 { val = 0 } if val > 1 { val = 1 } err := d.line.SetValue(val) if err != nil { return fmt.Errorf("cdev.Write(): %v", err) } return nil } // Read reads the given value from character device. Implements the interface gobot.DigitalPinner. func (d *digitalPinCdev) Read() (int, error) { val, err := d.line.Value() if err != nil { return 0, fmt.Errorf("cdev.Read(): %v", err) } return val, err } // ListLines is used for development purposes. func (d *digitalPinCdev) ListLines() error { c, err := gpiocdev.NewChip(d.chipName, gpiocdev.WithConsumer(d.label)) if err != nil { return err } for i := 0; i < c.Lines(); i++ { li, err := c.LineInfo(i) if err != nil { return err } fmt.Println(digitalPinCdevFmtLine(li)) } return nil } // List is used for development purposes. func (d *digitalPinCdev) List() error { c, err := gpiocdev.NewChip(d.chipName) if err != nil { return err } defer c.Close() l, err := c.RequestLine(d.pin) if err != nil && l != nil { l.Close() l = nil } li, err := l.Info() if err != nil { return err } fmt.Println(digitalPinCdevFmtLine(li)) return nil } func digitalPinCdevReconfigureLine(d *digitalPinCdev, forceInput bool) error { // cleanup old line if d.line != nil { d.line.Close() } d.line = nil // acquire chip, temporary // the given label is applied to all lines, which are requested on the chip gpiodChip, err := gpiocdev.NewChip(d.chipName, gpiocdev.WithConsumer(d.label)) id := fmt.Sprintf("%s-%d", d.chipName, d.pin) if err != nil { return fmt.Errorf("cdev.reconfigure(%s)-lib.NewChip(%s): %v", id, d.chipName, err) } defer gpiodChip.Close() // collect line configuration options var opts []gpiocdev.LineReqOption // configure direction, debounce period (inputs only), edge detection (inputs only) and drive (outputs only) if d.direction == IN || forceInput { if systemCdevDebug { log.Printf("input (%s): debounce %s, edge %d, handler %t, inverse %t, bias %d", id, d.debouncePeriod, d.edge, d.edgeEventHandler != nil, d.activeLow, d.bias) } opts = append(opts, gpiocdev.AsInput) if !forceInput && d.drive != digitalPinDrivePushPull && systemCdevDebug { log.Printf("\n++ drive option (%d) is dropped for input++\n", d.drive) } if d.debouncePeriod != 0 { opts = append(opts, gpiocdev.WithDebounce(d.debouncePeriod)) } // edge detection if d.edgeEventHandler != nil && d.pollInterval <= 0 { // use edge detection provided by gpiocdev wrappedHandler := digitalPinCdevGetWrappedEventHandler(d.edgeEventHandler) switch d.edge { case digitalPinEventOnFallingEdge: opts = append(opts, gpiocdev.WithEventHandler(wrappedHandler), gpiocdev.WithFallingEdge) case digitalPinEventOnRisingEdge: opts = append(opts, gpiocdev.WithEventHandler(wrappedHandler), gpiocdev.WithRisingEdge) case digitalPinEventOnBothEdges: opts = append(opts, gpiocdev.WithEventHandler(wrappedHandler), gpiocdev.WithBothEdges) default: opts = append(opts, gpiocdev.WithoutEdges) } } } else { if systemCdevDebug { log.Printf("output (%s): ini-state %d, drive %d, inverse %t, bias %d", id, d.outInitialState, d.drive, d.activeLow, d.bias) } opts = append(opts, gpiocdev.AsOutput(d.outInitialState)) switch d.drive { case digitalPinDriveOpenDrain: opts = append(opts, gpiocdev.AsOpenDrain) case digitalPinDriveOpenSource: opts = append(opts, gpiocdev.AsOpenSource) default: opts = append(opts, gpiocdev.AsPushPull) } if d.debouncePeriod != 0 && systemCdevDebug { log.Printf("\n++debounce option (%d) is dropped for output++\n", d.drive) } if d.edgeEventHandler != nil || d.edge != digitalPinEventNone && systemCdevDebug { log.Printf("\n++edge detection is dropped for output++\n") } } // configure inverse logic (inputs and outputs) if d.activeLow { opts = append(opts, gpiocdev.AsActiveLow) } // configure bias (inputs and outputs) switch d.bias { case digitalPinBiasPullDown: opts = append(opts, gpiocdev.WithPullDown) case digitalPinBiasPullUp: opts = append(opts, gpiocdev.WithPullUp) default: opts = append(opts, gpiocdev.WithBiasAsIs) } // acquire line with collected options gpiodLine, err := gpiodChip.RequestLine(d.pin, opts...) if err != nil { if gpiodLine != nil { gpiodLine.Close() } d.line = nil return fmt.Errorf("cdev.reconfigure(%s)-c.RequestLine(%d, %v): %v", id, d.pin, opts, err) } d.line = gpiodLine // start discrete polling function and wait for first read is done if (d.direction == IN || forceInput) && d.pollInterval > 0 { if err := startEdgePolling(d.label, d.Read, d.pollInterval, d.edge, d.edgeEventHandler, d.pollQuitChan); err != nil { return err } } return nil } func digitalPinCdevGetWrappedEventHandler( handler func(int, time.Duration, string, uint32, uint32), ) func(gpiocdev.LineEvent) { return func(evt gpiocdev.LineEvent) { detectedEdge := "none" switch evt.Type { case gpiocdev.LineEventRisingEdge: detectedEdge = DigitalPinEventRisingEdge case gpiocdev.LineEventFallingEdge: detectedEdge = DigitalPinEventFallingEdge } handler(evt.Offset, evt.Timestamp, detectedEdge, evt.Seqno, evt.LineSeqno) } } func digitalPinCdevFmtLine(li gpiocdev.LineInfo) string { var consumer string if li.Consumer != "" { consumer = fmt.Sprintf(" by '%s'", li.Consumer) } return fmt.Sprintf("++ Info line %d '%s', %s%s ++\n Config: %s\n", li.Offset, li.Name, digitalPinCdevUsed[li.Used], consumer, digitalPinCdevFmtLineConfig(li.Config)) } func digitalPinCdevFmtLineConfig(cfg gpiocdev.LineConfig) string { t := "active-%s, %s, %s, %s bias, %s edge detect, %s, debounce-period: %v, %s event clock" return fmt.Sprintf(t, digitalPinCdevActiveLow[cfg.ActiveLow], digitalPinCdevDirection[cfg.Direction], digitalPinCdevDrive[cfg.Drive], digitalPinCdevBias[cfg.Bias], digitalPinCdevEdgeDetect[cfg.EdgeDetection], digitalPinCdevDebounced[cfg.Debounced], cfg.DebouncePeriod, digitalPinCdevEventClock[cfg.EventClock]) } ================================================ FILE: system/digitalpin_cdev_test.go ================================================ package system import ( "fmt" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) var ( _ gobot.DigitalPinner = (*digitalPinCdev)(nil) _ gobot.DigitalPinValuer = (*digitalPinCdev)(nil) _ gobot.DigitalPinOptioner = (*digitalPinCdev)(nil) _ gobot.DigitalPinOptionApplier = (*digitalPinCdev)(nil) ) func Test_newDigitalPinCdev(t *testing.T) { // arrange const ( chip = "gpiochip0" pin = 17 label = "gobotio17" ) // act d := newDigitalPinCdev(chip, pin) // assert assert.NotNil(t, d) assert.Equal(t, chip, d.chipName) assert.Equal(t, pin, d.pin) assert.Equal(t, label, d.label) assert.Equal(t, IN, d.direction) assert.Equal(t, 0, d.outInitialState) } func Test_newDigitalPinCdevWithOptions(t *testing.T) { // This is a general test, that options are applied by using "newDigitalPinCdev" with the WithPinLabel() option. // All other configuration options will be tested in tests for "digitalPinConfig". // // arrange const label = "my own label" // act dp := newDigitalPinCdev("", 9, WithPinLabel(label)) // assert assert.Equal(t, label, dp.label) } func TestApplyOptions(t *testing.T) { tests := map[string]struct { changed []bool simErr error wantReconfigured int wantErr error }{ "both_changed": { changed: []bool{true, true}, wantReconfigured: 1, }, "first_changed": { changed: []bool{true, false}, wantReconfigured: 1, }, "second_changed": { changed: []bool{false, true}, wantReconfigured: 1, }, "none_changed": { changed: []bool{false, false}, simErr: fmt.Errorf("error not raised"), wantReconfigured: 0, }, "error_on_change": { changed: []bool{false, true}, simErr: fmt.Errorf("error raised"), wantReconfigured: 1, wantErr: fmt.Errorf("error raised"), }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // currently the gpiocdev.Chip has no interface for RequestLine(), // so we can only test without trigger of real reconfigure // arrange orgReconf := digitalPinCdevReconfigure defer func() { digitalPinCdevReconfigure = orgReconf }() inputForced := true reconfigured := 0 digitalPinCdevReconfigure = func(d *digitalPinCdev, forceInput bool) error { inputForced = forceInput reconfigured++ return tc.simErr } d := &digitalPinCdev{digitalPinConfig: &digitalPinConfig{direction: "in"}} optionFunction1 := func(gobot.DigitalPinOptioner) bool { d.direction = "test" return tc.changed[0] } optionFunction2 := func(gobot.DigitalPinOptioner) bool { d.drive = 15 return tc.changed[1] } // act err := d.ApplyOptions(optionFunction1, optionFunction2) // assert assert.Equal(t, tc.wantErr, err) assert.Equal(t, "test", d.direction) assert.Equal(t, 15, d.drive) assert.Equal(t, tc.wantReconfigured, reconfigured) if reconfigured > 0 { assert.False(t, inputForced) } }) } } func TestExport_cdev(t *testing.T) { tests := map[string]struct { simErr error wantReconfigured int wantErr error }{ "no_err": { wantReconfigured: 1, }, "error": { wantReconfigured: 1, simErr: fmt.Errorf("reconfigure error"), wantErr: fmt.Errorf("cdev.Export(): reconfigure error"), }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // currently the gpiocdev.Chip has no interface for RequestLine(), // so we can only test without trigger of real reconfigure // arrange orgReconf := digitalPinCdevReconfigure defer func() { digitalPinCdevReconfigure = orgReconf }() inputForced := true reconfigured := 0 digitalPinCdevReconfigure = func(d *digitalPinCdev, forceInput bool) error { inputForced = forceInput reconfigured++ return tc.simErr } d := &digitalPinCdev{} // act err := d.Export() // assert assert.Equal(t, tc.wantErr, err) assert.False(t, inputForced) assert.Equal(t, tc.wantReconfigured, reconfigured) }) } } func TestUnexport_cdev(t *testing.T) { tests := map[string]struct { simNoLine bool simReconfErr error simCloseErr error wantReconfigured int wantErr error }{ "no_line_no_err": { simNoLine: true, wantReconfigured: 0, }, "no_line_with_err": { simNoLine: true, simReconfErr: fmt.Errorf("reconfigure error"), wantReconfigured: 0, }, "no_err": { wantReconfigured: 1, }, "error_reconfigure": { wantReconfigured: 1, simReconfErr: fmt.Errorf("reconfigure error"), wantErr: fmt.Errorf("reconfigure error"), }, "error_close": { wantReconfigured: 1, simCloseErr: fmt.Errorf("close error"), wantErr: fmt.Errorf("cdev.Unexport()-line.Close(): close error"), }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // currently the gpiocdev.Chip has no interface for RequestLine(), // so we can only test without trigger of real reconfigure // arrange orgReconf := digitalPinCdevReconfigure defer func() { digitalPinCdevReconfigure = orgReconf }() inputForced := false reconfigured := 0 digitalPinCdevReconfigure = func(d *digitalPinCdev, forceInput bool) error { inputForced = forceInput reconfigured++ return tc.simReconfErr } dp := newDigitalPinCdev("", 4) if !tc.simNoLine { dp.line = &lineMock{simCloseErr: tc.simCloseErr} } // act err := dp.Unexport() // assert assert.Equal(t, tc.wantErr, err) assert.Equal(t, tc.wantReconfigured, reconfigured) if reconfigured > 0 { assert.True(t, inputForced) } }) } } func TestWrite_cdev(t *testing.T) { tests := map[string]struct { val int simErr error want int wantErr []string }{ "write_zero": { val: 0, want: 0, }, "write_one": { val: 1, want: 1, }, "write_minus_one": { val: -1, want: 0, }, "write_two": { val: 2, want: 1, }, "write_with_err": { simErr: fmt.Errorf("a write err"), wantErr: []string{"a write err", "cdev.Write"}, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange dp := newDigitalPinCdev("", 4) lm := &lineMock{lastVal: 10, simSetErr: tc.simErr} dp.line = lm // act err := dp.Write(tc.val) // assert if tc.wantErr != nil { for _, want := range tc.wantErr { require.ErrorContains(t, err, want) } } else { require.NoError(t, err) } assert.Equal(t, tc.want, lm.lastVal) }) } } func TestRead_cdev(t *testing.T) { tests := map[string]struct { simVal int simErr error wantErr []string }{ "read_ok": { simVal: 3, }, "write_with_err": { simErr: fmt.Errorf("a read err"), wantErr: []string{"a read err", "cdev.Read"}, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange dp := newDigitalPinCdev("", 4) lm := &lineMock{lastVal: tc.simVal, simValueErr: tc.simErr} dp.line = lm // act got, err := dp.Read() // assert if tc.wantErr != nil { for _, want := range tc.wantErr { require.ErrorContains(t, err, want) } } else { require.NoError(t, err) } assert.Equal(t, got, tc.simVal) }) } } type lineMock struct { lastVal int simSetErr error simValueErr error simCloseErr error } func (lm *lineMock) SetValue(value int) error { lm.lastVal = value; return lm.simSetErr } func (lm *lineMock) Value() (int, error) { return lm.lastVal, lm.simValueErr } func (lm *lineMock) Close() error { return lm.simCloseErr } ================================================ FILE: system/digitalpin_mock.go ================================================ package system import ( "errors" "strconv" "gobot.io/x/gobot/v2" ) type simulateErrors struct { applyOption bool export bool write bool read bool unexport bool } type mockDigitalPinAccess struct { underlyingDigitalPinAccess digitalPinAccesser values map[string][]int simulateErrors map[string]simulateErrors // key is the pin-key pins map[string]*digitalPinMock } type digitalPinMock struct { chip string pin int appliedOptions int exported int written []int values []int readIdx int simulateErrors simulateErrors } func newMockDigitalPinAccess(underlyingDigitalPinAccess digitalPinAccesser) *mockDigitalPinAccess { dpa := mockDigitalPinAccess{ underlyingDigitalPinAccess: underlyingDigitalPinAccess, values: make(map[string][]int), simulateErrors: make(map[string]simulateErrors), pins: make(map[string]*digitalPinMock), } return &dpa } func (dpa *mockDigitalPinAccess) isType(accesserType digitalPinAccesserType) bool { return dpa.underlyingDigitalPinAccess.isType(accesserType) } func (dpa *mockDigitalPinAccess) isSupported() bool { return true } func (dpa *mockDigitalPinAccess) createPin(chip string, pin int, o ...func(gobot.DigitalPinOptioner) bool, ) gobot.DigitalPinner { dpm := &digitalPinMock{chip: chip, pin: pin, readIdx: -1} key := getDigitalPinMockKey(chip, strconv.Itoa(pin)) if v, ok := dpa.values[key]; ok { dpm.values = v } if v, ok := dpa.simulateErrors[key]; ok { dpm.simulateErrors = v } dpa.pins[key] = dpm return dpm } func (dpa *mockDigitalPinAccess) setFs(fs filesystem) { panic("setFs() for mockDigitalPinAccess not supported") } // DigitalPin implements the gobot.DigitalPinnerProvider. func (dpa *mockDigitalPinAccess) DigitalPin(id string) (gobot.DigitalPinner, error) { pin, err := strconv.Atoi(id) return dpa.createPin("", pin), err } func (dpa *mockDigitalPinAccess) AppliedOptions(chip, pin string) int { return dpa.pins[getDigitalPinMockKey(chip, pin)].appliedOptions } func (dpa *mockDigitalPinAccess) Written(chip, pin string) []int { return dpa.pins[getDigitalPinMockKey(chip, pin)].written } func (dpa *mockDigitalPinAccess) Exported(chip, pin string) int { return dpa.pins[getDigitalPinMockKey(chip, pin)].exported } func (dpa *mockDigitalPinAccess) UseValues(chip, pin string, values []int) { key := getDigitalPinMockKey(chip, pin) if pin, ok := dpa.pins[key]; ok { pin.values = values } // for creation and re-creation dpa.values[key] = values } func (dpa *mockDigitalPinAccess) UseUnexportError(chip, pin string) { key := getDigitalPinMockKey(chip, pin) if pin, ok := dpa.pins[key]; ok { pin.simulateErrors.unexport = true } // for creation and re-creation simErrs, ok := dpa.simulateErrors[key] if !ok { simErrs = simulateErrors{} } simErrs.unexport = true dpa.simulateErrors[getDigitalPinMockKey(chip, pin)] = simErrs } func (dp *digitalPinMock) ApplyOptions(options ...func(gobot.DigitalPinOptioner) bool) error { dp.appliedOptions = dp.appliedOptions + len(options) if dp.simulateErrors.applyOption { return errors.New("applyOption error") } return nil } func (dp *digitalPinMock) DirectionBehavior() string { panic("DirectionBehavior() for digitalPinMock needs do be implemented now") } // Write writes the given value to the character device func (dp *digitalPinMock) Write(b int) error { dp.written = append(dp.written, b) if dp.simulateErrors.write { return errors.New("write error") } return nil } // Read reads the given value from character device func (dp *digitalPinMock) Read() (int, error) { dp.readIdx++ if dp.simulateErrors.read { return -1, errors.New("read error") } return dp.values[dp.readIdx], nil } // Export sets the pin as exported with the configured direction func (dp *digitalPinMock) Export() error { dp.exported++ if dp.simulateErrors.export { return errors.New("export error") } return nil } // Unexport release the pin func (dp *digitalPinMock) Unexport() error { dp.exported-- if dp.simulateErrors.unexport { return errors.New("unexport error") } return nil } func getDigitalPinMockKey(chip, pin string) string { return chip + "_" + pin } ================================================ FILE: system/digitalpin_poll.go ================================================ package system import ( "fmt" "sync" "time" ) func startEdgePolling( pinLabel string, pinReadFunc func() (int, error), pollInterval time.Duration, wantedEdge int, eventHandler func(offset int, t time.Duration, et string, sn uint32, lsn uint32), quitChan chan struct{}, ) error { if eventHandler == nil { return fmt.Errorf("an event handler is mandatory for edge polling") } if quitChan == nil { return fmt.Errorf("the quit channel is mandatory for edge polling") } const allEdges = "all" triggerEventOn := "none" switch wantedEdge { case digitalPinEventOnFallingEdge: triggerEventOn = DigitalPinEventFallingEdge case digitalPinEventOnRisingEdge: triggerEventOn = DigitalPinEventRisingEdge case digitalPinEventOnBothEdges: triggerEventOn = allEdges default: return fmt.Errorf("unsupported edge type %d for edge polling", wantedEdge) } wg := sync.WaitGroup{} wg.Add(1) go func() { var oldState int var readStart time.Time var firstLoopDone bool for { select { case <-quitChan: if !firstLoopDone { wg.Done() } return default: // note: pure reading takes between 30us and 1ms on rasperry Pi1, typically 50us, with sysfs also 500us // can happen, so we use the time stamp before start of reading to reduce random duration offset readStart = time.Now() readValue, err := pinReadFunc() if err != nil { fmt.Printf("edge polling error occurred while reading the pin %s: %v\n", pinLabel, err) readValue = oldState // keep the value } if readValue != oldState { detectedEdge := DigitalPinEventRisingEdge if readValue < oldState { detectedEdge = DigitalPinEventFallingEdge } if firstLoopDone && (triggerEventOn == allEdges || triggerEventOn == detectedEdge) { eventHandler(0, time.Duration(readStart.UnixNano()), detectedEdge, 0, 0) } oldState = readValue } // the real poll interval is increased by the reading time, see also note above // negative or zero duration causes no sleep time.Sleep(pollInterval - time.Since(readStart)) if !firstLoopDone { wg.Done() firstLoopDone = true } } } }() wg.Wait() return nil } ================================================ FILE: system/digitalpin_poll_test.go ================================================ package system import ( "errors" "sync" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func Test_startEdgePolling(t *testing.T) { type readValue struct { value int err string } tests := map[string]struct { eventOnEdge int simulateReadValues []readValue simulateNoEventHandler bool simulateNoQuitChan bool wantEdgeTypes []string wantErr string }{ "edge_falling": { eventOnEdge: digitalPinEventOnFallingEdge, simulateReadValues: []readValue{ {value: 1}, {value: 0}, {value: 1}, {value: 0}, {value: 0}, }, wantEdgeTypes: []string{DigitalPinEventFallingEdge, DigitalPinEventFallingEdge}, }, "no_edge_falling": { eventOnEdge: digitalPinEventOnFallingEdge, simulateReadValues: []readValue{ {value: 0}, {value: 1}, {value: 1}, }, wantEdgeTypes: nil, }, "edge_rising": { eventOnEdge: digitalPinEventOnRisingEdge, simulateReadValues: []readValue{ {value: 0}, {value: 1}, {value: 0}, {value: 1}, {value: 1}, }, wantEdgeTypes: []string{DigitalPinEventRisingEdge, DigitalPinEventRisingEdge}, }, "no_edge_rising": { eventOnEdge: digitalPinEventOnRisingEdge, simulateReadValues: []readValue{ {value: 1}, {value: 0}, {value: 0}, }, wantEdgeTypes: nil, }, "edge_both": { eventOnEdge: digitalPinEventOnBothEdges, simulateReadValues: []readValue{ {value: 0}, {value: 1}, {value: 0}, {value: 1}, {value: 1}, }, wantEdgeTypes: []string{DigitalPinEventRisingEdge, DigitalPinEventFallingEdge, DigitalPinEventRisingEdge}, }, "no_edges_low": { eventOnEdge: digitalPinEventOnBothEdges, simulateReadValues: []readValue{ {value: 0}, {value: 0}, {value: 0}, }, wantEdgeTypes: nil, }, "no_edges_high": { eventOnEdge: digitalPinEventOnBothEdges, simulateReadValues: []readValue{ {value: 1}, {value: 1}, {value: 1}, }, wantEdgeTypes: nil, }, "read_error_keep_state": { eventOnEdge: digitalPinEventOnBothEdges, simulateReadValues: []readValue{ {value: 0}, {value: 1, err: "read error suppress rising and falling edge"}, {value: 0}, {value: 1}, {value: 1}, }, wantEdgeTypes: []string{DigitalPinEventRisingEdge}, }, "error_no_eventhandler": { simulateNoEventHandler: true, wantErr: "event handler is mandatory", }, "error_no_quitchannel": { simulateNoQuitChan: true, wantErr: "quit channel is mandatory", }, "error_unsupported_edgetype_none": { eventOnEdge: digitalPinEventNone, wantErr: "unsupported edge type 0", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange pinLabel := "test_pin" pollInterval := time.Microsecond // zero is possible, just to show usage // arrange event handler var edgeTypes []string var eventHandler func(int, time.Duration, string, uint32, uint32) if !tc.simulateNoEventHandler { eventHandler = func(offset int, t time.Duration, et string, sn uint32, lsn uint32) { edgeTypes = append(edgeTypes, et) } } // arrange quit channel var quitChan chan struct{} if !tc.simulateNoQuitChan { quitChan = make(chan struct{}) } defer func() { if quitChan != nil { close(quitChan) } }() // arrange reads numCallsRead := 0 wg := sync.WaitGroup{} if tc.simulateReadValues != nil { wg.Add(1) } readFunc := func() (int, error) { numCallsRead++ readVal := tc.simulateReadValues[numCallsRead-1] var err error if readVal.err != "" { err = errors.New(readVal.err) } if numCallsRead >= len(tc.simulateReadValues) { close(quitChan) // ensure no further read call quitChan = nil // lets skip defer routine wg.Done() // release assertions } return readVal.value, err } // act err := startEdgePolling(pinLabel, readFunc, pollInterval, tc.eventOnEdge, eventHandler, quitChan) wg.Wait() // assert if tc.wantErr != "" { require.ErrorContains(t, err, tc.wantErr) } else { require.NoError(t, err) } assert.Len(t, tc.simulateReadValues, numCallsRead) assert.Equal(t, tc.wantEdgeTypes, edgeTypes) }) } } ================================================ FILE: system/digitalpin_sysfs.go ================================================ package system import ( "errors" "fmt" "log" "os" "strconv" "time" "gobot.io/x/gobot/v2" ) const ( systemSysfsDebug = false // gpioPath default linux sysfs gpio path gpioPath = "/sys/class/gpio" ) var errNotExported = errors.New("pin has not been exported") // digitalPin represents a digital pin type digitalPinSysfs struct { *digitalPinConfig pin string sfa *sysfsFileAccess dirFile *sysfsFile valFile *sysfsFile activeLowFile *sysfsFile } // newDigitalPinSysfs returns a digital pin using for the given number. The name of the sysfs file will prepend "gpio" // to the pin number, eg. a pin number of 10 will have a name of "gpio10". The pin is handled by the sysfs Kernel ABI. func newDigitalPinSysfs( sfa *sysfsFileAccess, pin string, options ...func(gobot.DigitalPinOptioner) bool, ) *digitalPinSysfs { cfg := newDigitalPinConfig("gpio"+pin, options...) d := &digitalPinSysfs{ pin: pin, digitalPinConfig: cfg, sfa: sfa, } return d } // ApplyOptions apply all given options to the pin immediately. Implements interface gobot.DigitalPinOptionApplier. func (d *digitalPinSysfs) ApplyOptions(options ...func(gobot.DigitalPinOptioner) bool) error { anyChange := false for _, option := range options { anyChange = option(d) || anyChange } if anyChange { return d.reconfigure() } return nil } // DirectionBehavior gets the direction behavior when the pin is used the next time. This means its possibly not in // this direction type at the moment. Implements the interface gobot.DigitalPinValuer, but should be rarely used. func (d *digitalPinSysfs) DirectionBehavior() string { return d.direction } // Export sets the pin as exported with the configured direction func (d *digitalPinSysfs) Export() error { return d.reconfigure() } // Unexport release the pin func (d *digitalPinSysfs) Unexport() error { unexport, err := d.sfa.openWrite(gpioPath + "/unexport") if err != nil { return err } defer unexport.close() if d.dirFile != nil { d.dirFile.close() d.dirFile = nil } if d.valFile != nil { d.valFile.close() d.valFile = nil } if d.activeLowFile != nil { d.activeLowFile.close() d.activeLowFile = nil } err = unexport.write([]byte(d.pin)) if err != nil { // If EINVAL then the pin is reserved in the system and can't be unexported, we suppress the error var pathError *os.PathError if !errors.As(err, &pathError) || !errors.Is(err, Syscall_EINVAL) { return err } } return nil } // Write writes the given value to the character device func (d *digitalPinSysfs) Write(b int) error { if d.valFile == nil { return errNotExported } err := d.valFile.write([]byte(strconv.Itoa(b))) return err } // Read reads a value from character device func (d *digitalPinSysfs) Read() (int, error) { if d.valFile == nil { return 0, errNotExported } buf, err := d.valFile.read() if err != nil { return 0, err } return strconv.Atoi(string(buf[0])) } func (d *digitalPinSysfs) reconfigure() error { exportFile, err := d.sfa.openWrite(gpioPath + "/export") if err != nil { return err } defer exportFile.close() err = exportFile.write([]byte(d.pin)) if err != nil { // If EBUSY then the pin has already been exported, we suppress the error var pathError *os.PathError if !errors.As(err, &pathError) || !errors.Is(err, Syscall_EBUSY) { return err } } if d.dirFile != nil { d.dirFile.close() } attempt := 0 for { attempt++ d.dirFile, err = d.sfa.openReadWrite(fmt.Sprintf("%s/%s/direction", gpioPath, d.label)) if err == nil { break } if attempt > 10 { break } time.Sleep(10 * time.Millisecond) } if d.valFile != nil { d.valFile.close() } if err == nil { d.valFile, err = d.sfa.openReadWrite(fmt.Sprintf("%s/%s/value", gpioPath, d.label)) } // configure direction if err == nil { err = d.writeDirectionWithInitialOutput() } // configure inverse logic if err == nil { if d.activeLow { d.activeLowFile, err = d.sfa.openReadWrite(fmt.Sprintf("%s/%s/active_low", gpioPath, d.label)) if err == nil { err = d.activeLowFile.write([]byte("1")) } } } // configure bias (inputs and outputs, unsupported) if err == nil { if d.bias != digitalPinBiasDefault && systemSysfsDebug { log.Printf("bias options (%d) are not supported by sysfs, please use hardware resistors instead\n", d.bias) } } // configure debounce period (inputs only), edge detection (inputs only) and drive (outputs only) if d.direction == IN { // configure debounce (unsupported) if d.debouncePeriod != 0 && systemSysfsDebug { log.Printf("debounce period option (%d) is not supported by sysfs\n", d.debouncePeriod) } // configure edge detection if err == nil { if d.edge != 0 && d.pollInterval <= 0 { err = fmt.Errorf("edge detect option (%d) is not implemented for sysfs without discrete polling", d.edge) } } // start discrete polling function and wait for first read is done if err == nil { if d.pollInterval > 0 { err = startEdgePolling(d.label, d.Read, d.pollInterval, d.edge, d.edgeEventHandler, d.pollQuitChan) } } } else if d.drive != digitalPinDrivePushPull && systemSysfsDebug { // configure drive (unsupported) log.Printf("drive options (%d) are not supported by sysfs\n", d.drive) } if err != nil { if e := d.Unexport(); e != nil { err = fmt.Errorf("unexport error '%v' after '%v'", e, err) } } return err } func (d *digitalPinSysfs) writeDirectionWithInitialOutput() error { if d.dirFile == nil { return errNotExported } if err := d.dirFile.write([]byte(d.direction)); err != nil || d.direction == IN { return err } if d.valFile == nil { return errNotExported } return d.valFile.write([]byte(strconv.Itoa(d.outInitialState))) } ================================================ FILE: system/digitalpin_sysfs_test.go ================================================ package system import ( "errors" "os" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) var ( _ gobot.DigitalPinner = (*digitalPinSysfs)(nil) _ gobot.DigitalPinValuer = (*digitalPinSysfs)(nil) _ gobot.DigitalPinOptioner = (*digitalPinSysfs)(nil) _ gobot.DigitalPinOptionApplier = (*digitalPinSysfs)(nil) ) func initTestDigitalPinSysfsWithMockedFilesystem(mockPaths []string) (*digitalPinSysfs, *MockFilesystem) { fs := newMockFilesystem(mockPaths) sfa := sysfsFileAccess{fs: fs, readBufLen: 2} pin := newDigitalPinSysfs(&sfa, "10") return pin, fs } func Test_newDigitalPinSysfs(t *testing.T) { // arrange m := &MockFilesystem{} sfa := sysfsFileAccess{fs: m, readBufLen: 2} const pinID = "1" // act pin := newDigitalPinSysfs(&sfa, pinID, WithPinOpenDrain()) // assert assert.Equal(t, pinID, pin.pin) assert.Equal(t, &sfa, pin.sfa) assert.Equal(t, "gpio"+pinID, pin.label) assert.Equal(t, "in", pin.direction) assert.Equal(t, 1, pin.drive) } func TestApplyOptionsSysfs(t *testing.T) { tests := map[string]struct { changed []bool simErr bool wantExport string wantErr string }{ "both_changed": { changed: []bool{true, true}, wantExport: "10", }, "first_changed": { changed: []bool{true, false}, wantExport: "10", }, "second_changed": { changed: []bool{false, true}, wantExport: "10", }, "none_changed": { changed: []bool{false, false}, wantExport: "", }, "error_on_change": { changed: []bool{false, true}, simErr: true, wantExport: "10", wantErr: "gpio10/direction: no such file", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange mockPaths := []string{ "/sys/class/gpio/export", "/sys/class/gpio/gpio10/value", } if !tc.simErr { mockPaths = append(mockPaths, "/sys/class/gpio/gpio10/direction") } pin, fs := initTestDigitalPinSysfsWithMockedFilesystem(mockPaths) optionFunction1 := func(gobot.DigitalPinOptioner) bool { pin.direction = OUT return tc.changed[0] } optionFunction2 := func(gobot.DigitalPinOptioner) bool { pin.drive = 15 return tc.changed[1] } // act err := pin.ApplyOptions(optionFunction1, optionFunction2) // assert if tc.wantErr != "" { require.ErrorContains(t, err, tc.wantErr) } else { require.NoError(t, err) } assert.Equal(t, OUT, pin.direction) assert.Equal(t, 15, pin.drive) // marker for call of reconfigure, correct reconfigure is tested independently assert.Equal(t, tc.wantExport, fs.Files["/sys/class/gpio/export"].Contents) }) } } func TestDirectionBehaviorSysfs(t *testing.T) { // arrange pin := newDigitalPinSysfs(nil, "1") require.Equal(t, "in", pin.direction) pin.direction = "test" // act && assert assert.Equal(t, "test", pin.DirectionBehavior()) } func TestDigitalPinExportSysfs(t *testing.T) { // this tests mainly the function reconfigure() const ( exportPath = "/sys/class/gpio/export" dirPath = "/sys/class/gpio/gpio10/direction" valuePath = "/sys/class/gpio/gpio10/value" inversePath = "/sys/class/gpio/gpio10/active_low" unexportPath = "/sys/class/gpio/unexport" ) allMockPaths := []string{exportPath, dirPath, valuePath, inversePath, unexportPath} tests := map[string]struct { mockPaths []string changeDirection string changeOutInitialState int changeActiveLow bool changeBias int changeDrive int changeDebouncePeriod time.Duration changeEdge int changePollInterval time.Duration simEbusyOnPath string wantWrites int wantExport string wantUnexport string wantDirection string wantValue string wantInverse string wantErr string }{ "ok_without_option": { mockPaths: allMockPaths, wantWrites: 2, wantExport: "10", wantDirection: "in", }, "ok_input_bias_dropped": { mockPaths: allMockPaths, changeBias: 3, wantWrites: 2, wantExport: "10", wantDirection: "in", }, "ok_input_drive_dropped": { mockPaths: allMockPaths, changeDrive: 2, wantWrites: 2, wantExport: "10", wantDirection: "in", }, "ok_input_debounce_dropped": { mockPaths: allMockPaths, changeDebouncePeriod: 2 * time.Second, wantWrites: 2, wantExport: "10", wantDirection: "in", }, "ok_input_inverse": { mockPaths: allMockPaths, changeActiveLow: true, wantWrites: 3, wantExport: "10", wantDirection: "in", wantInverse: "1", }, "ok_output": { mockPaths: allMockPaths, changeDirection: "out", changeOutInitialState: 4, wantWrites: 3, wantExport: "10", wantDirection: "out", wantValue: "4", }, "ok_output_bias_dropped": { mockPaths: allMockPaths, changeDirection: "out", changeBias: 3, wantWrites: 3, wantExport: "10", wantDirection: "out", wantValue: "0", }, "ok_output_drive_dropped": { mockPaths: allMockPaths, changeDirection: "out", changeDrive: 2, wantWrites: 3, wantExport: "10", wantDirection: "out", wantValue: "0", }, "ok_output_debounce_dropped": { mockPaths: allMockPaths, changeDirection: "out", changeDebouncePeriod: 2 * time.Second, wantWrites: 3, wantExport: "10", wantDirection: "out", wantValue: "0", }, "ok_output_inverse": { mockPaths: allMockPaths, changeDirection: "out", changeActiveLow: true, wantWrites: 4, wantExport: "10", wantDirection: "out", wantInverse: "1", wantValue: "0", }, "ok_already_exported": { mockPaths: allMockPaths, wantWrites: 2, wantExport: "10", wantDirection: "in", simEbusyOnPath: exportPath, // just means "already exported" }, "error_no_eventhandler_for_polling": { // this only tests the call of function, all other is tested separately mockPaths: allMockPaths, changePollInterval: 3 * time.Second, wantWrites: 3, wantUnexport: "10", wantDirection: "in", wantErr: "event handler is mandatory", }, "error_no_export_file": { mockPaths: []string{unexportPath}, wantErr: "/export: no such file", }, "error_no_direction_file": { mockPaths: []string{exportPath, unexportPath}, wantWrites: 2, wantUnexport: "10", wantErr: "gpio10/direction: no such file", }, "error_write_direction_file": { mockPaths: allMockPaths, wantWrites: 3, wantUnexport: "10", simEbusyOnPath: dirPath, wantErr: "device or resource busy", }, "error_no_value_file": { mockPaths: []string{exportPath, dirPath, unexportPath}, wantWrites: 2, wantUnexport: "10", wantErr: "gpio10/value: no such file", }, "error_no_inverse_file": { mockPaths: []string{exportPath, dirPath, valuePath, unexportPath}, changeActiveLow: true, wantWrites: 3, wantUnexport: "10", wantErr: "gpio10/active_low: no such file", }, "error_input_edge_without_poll": { mockPaths: allMockPaths, changeEdge: 2, wantWrites: 3, wantUnexport: "10", wantErr: "not implemented for sysfs without discrete polling", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange fs := newMockFilesystem(tc.mockPaths) sfa := sysfsFileAccess{fs: fs, readBufLen: 2} pin := newDigitalPinSysfs(&sfa, "10") if tc.changeDirection != "" { pin.direction = tc.changeDirection } if tc.changeOutInitialState != 0 { pin.outInitialState = tc.changeOutInitialState } if tc.changeActiveLow { pin.activeLow = tc.changeActiveLow } if tc.changeBias != 0 { pin.bias = tc.changeBias } if tc.changeDrive != 0 { pin.drive = tc.changeDrive } if tc.changeDebouncePeriod != 0 { pin.debouncePeriod = tc.changeDebouncePeriod } if tc.changeEdge != 0 { pin.edge = tc.changeEdge } if tc.changePollInterval != 0 { pin.pollInterval = tc.changePollInterval } // arrange write function if tc.simEbusyOnPath != "" { fs.Files[tc.simEbusyOnPath].simulateWriteError = &os.PathError{Err: Syscall_EBUSY} } // act err := pin.Export() // assert if tc.wantErr != "" { require.ErrorContains(t, err, tc.wantErr) } else { require.NoError(t, err) assert.NotNil(t, pin.valFile) assert.NotNil(t, pin.dirFile) assert.Equal(t, tc.wantDirection, fs.Files[dirPath].Contents) assert.Equal(t, tc.wantExport, fs.Files[exportPath].Contents) assert.Equal(t, tc.wantValue, fs.Files[valuePath].Contents) assert.Equal(t, tc.wantInverse, fs.Files[inversePath].Contents) } assert.Equal(t, tc.wantUnexport, fs.Files[unexportPath].Contents) assert.Equal(t, tc.wantWrites, fs.numCallsWrite) }) } } func TestDigitalPinSysfs(t *testing.T) { mockPaths := []string{ "/sys/class/gpio/export", "/sys/class/gpio/unexport", "/sys/class/gpio/gpio10/value", "/sys/class/gpio/gpio10/direction", } pin, fs := initTestDigitalPinSysfsWithMockedFilesystem(mockPaths) assert.Equal(t, "10", pin.pin) assert.Equal(t, "gpio10", pin.label) assert.Nil(t, pin.valFile) err := pin.Unexport() require.NoError(t, err) assert.Equal(t, "10", fs.Files["/sys/class/gpio/unexport"].Contents) require.NoError(t, pin.Export()) err = pin.Write(1) require.NoError(t, err) assert.Equal(t, "1", fs.Files["/sys/class/gpio/gpio10/value"].Contents) err = pin.ApplyOptions(WithPinDirectionInput()) require.NoError(t, err) assert.Equal(t, "in", fs.Files["/sys/class/gpio/gpio10/direction"].Contents) data, _ := pin.Read() assert.Equal(t, 1, data) sfa := sysfsFileAccess{fs: fs, readBufLen: 2} pin2 := newDigitalPinSysfs(&sfa, "30") err = pin2.Write(1) require.ErrorContains(t, err, "pin has not been exported") data, err = pin2.Read() require.ErrorContains(t, err, "pin has not been exported") assert.Equal(t, 0, data) // arrange: unexport general write error, the error is not suppressed fs.Files["/sys/class/gpio/unexport"].simulateWriteError = &os.PathError{Err: errors.New("write error")} // act: unexport err = pin.Unexport() // assert: the error is not suppressed var pathError *os.PathError require.ErrorAs(t, err, &pathError) require.ErrorContains(t, err, "write error") } func TestDigitalPinUnexportErrorSysfs(t *testing.T) { tests := map[string]struct { simulateError error wantErr string }{ "reserved_pin": { // simulation of reserved pin, the internal error is suppressed simulateError: &os.PathError{Err: Syscall_EINVAL}, wantErr: "", }, "error_busy": { simulateError: &os.PathError{Err: Syscall_EBUSY}, wantErr: " : device or resource busy", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange mockPaths := []string{ "/sys/class/gpio/unexport", } pin, fs := initTestDigitalPinSysfsWithMockedFilesystem(mockPaths) fs.Files["/sys/class/gpio/unexport"].simulateWriteError = tc.simulateError // act err := pin.Unexport() // assert if tc.wantErr != "" { require.ErrorContains(t, err, tc.wantErr) } else { require.NoError(t, err) } }) } } ================================================ FILE: system/digitalpinaccess.go ================================================ package system import ( "strconv" "gobot.io/x/gobot/v2" ) // sysfsDitalPinHandler represents the sysfs implementation type sysfsDigitalPinAccess struct { sfa *sysfsFileAccess } // cdevDigitalPinAccess represents the character device implementation type cdevDigitalPinAccess struct { fs filesystem chips []string } func (dpa *sysfsDigitalPinAccess) isType(accesserType digitalPinAccesserType) bool { return accesserType == digitalPinAccesserTypeSysfs } func (dpa *sysfsDigitalPinAccess) isSupported() bool { // currently this is supported by all Kernels return true } func (dpa *sysfsDigitalPinAccess) createPin(chip string, pin int, o ...func(gobot.DigitalPinOptioner) bool, ) gobot.DigitalPinner { return newDigitalPinSysfs(dpa.sfa, strconv.Itoa(pin), o...) } func (dpa *sysfsDigitalPinAccess) setFs(fs filesystem) { dpa.sfa = &sysfsFileAccess{fs: fs, readBufLen: 2} } func (dpa *cdevDigitalPinAccess) isType(accesserType digitalPinAccesserType) bool { return accesserType == digitalPinAccesserTypeCdev } func (dpa *cdevDigitalPinAccess) isSupported() bool { chips, err := dpa.fs.find("/dev", "gpiochip") if err != nil || len(chips) == 0 { return false } dpa.chips = chips return true } func (dpa *cdevDigitalPinAccess) createPin(chip string, pin int, o ...func(gobot.DigitalPinOptioner) bool, ) gobot.DigitalPinner { return newDigitalPinCdev(chip, pin, o...) } func (dpa *cdevDigitalPinAccess) setFs(fs filesystem) { dpa.fs = fs } ================================================ FILE: system/digitalpinaccess_test.go ================================================ //nolint:forcetypeassert // ok here package system import ( "testing" "github.com/stretchr/testify/assert" ) func Test_isSupported_sysfs(t *testing.T) { // arrange dpa := sysfsDigitalPinAccess{} // act got := dpa.isSupported() // assert assert.True(t, got) } func Test_isSupported_cdev(t *testing.T) { tests := map[string]struct { mockPaths []string want bool }{ "supported": { mockPaths: []string{"/sys/class/gpio/", "/dev/gpiochip3"}, want: true, }, "not_supported": { mockPaths: []string{"/sys/class/gpio/"}, want: false, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange fs := newMockFilesystem(tc.mockPaths) dpa := cdevDigitalPinAccess{fs: fs} // act got := dpa.isSupported() // assert assert.Equal(t, tc.want, got) }) } } func Test_createAsSysfs(t *testing.T) { // arrange dpa := sysfsDigitalPinAccess{} // act dp := dpa.createPin("chip", 8) // assert assert.NotNil(t, dp) dps := dp.(*digitalPinSysfs) // chip is dropped assert.Equal(t, "gpio8", dps.label) } func Test_createPin_cdev(t *testing.T) { // arrange const ( pin = 18 label = "gobotio18" chip = "gpiochip1" ) dpa := cdevDigitalPinAccess{} // act dp := dpa.createPin(chip, 18) // assert assert.NotNil(t, dp) dpg := dp.(*digitalPinCdev) assert.Equal(t, label, dpg.label) assert.Equal(t, chip, dpg.chipName) } func Test_createPin_WithOptions_sysfs(t *testing.T) { // This is a general test, that options are applied by using "create" with the WithPinLabel() option. // All other configuration options will be tested in tests for "digitalPinConfig". // // arrange const label = "my sysfs label" dpa := sysfsDigitalPinAccess{} // act dp := dpa.createPin("", 9, WithPinLabel(label)) dps := dp.(*digitalPinSysfs) // assert assert.Equal(t, label, dps.label) } func Test_createPin_WithOptions_cdev(t *testing.T) { // This is a general test, that options are applied by using "create" with the WithPinLabel() option. // All other configuration options will be tested in tests for "digitalPinConfig". // // arrange const label = "my cdev label" dpa := cdevDigitalPinAccess{} // act dp := dpa.createPin("", 19, WithPinLabel(label)) dpg := dp.(*digitalPinCdev) // assert assert.Equal(t, label, dpg.label) // test fallback for empty chip assert.Equal(t, "gpiochip0", dpg.chipName) } ================================================ FILE: system/digitalpinoptions.go ================================================ package system import ( "time" "gobot.io/x/gobot/v2" ) const ( // IN gpio direction IN = "in" // OUT gpio direction OUT = "out" // HIGH gpio level HIGH = 1 // LOW gpio level LOW = 0 ) const ( digitalPinBiasDefault = 0 // GPIO uses the hardware default digitalPinBiasDisable = 1 // GPIO has pull disabled digitalPinBiasPullDown = 2 // GPIO has pull up enabled digitalPinBiasPullUp = 3 // GPIO has pull down enabled // open drain and open source allows the connection of output ports with the same mode (OR logic) // * for open drain/collector pull up the ports with an external resistor/load // * for open source/emitter pull down the ports with an external resistor/load digitalPinDrivePushPull = 0 // the pin will be driven actively high and low (default) digitalPinDriveOpenDrain = 1 // the pin will be driven active to low only digitalPinDriveOpenSource = 2 // the pin will be driven active to high only digitalPinEventNone = 0 // no event will be triggered on any pin change (default) digitalPinEventOnFallingEdge = 1 // an event will be triggered on changes from high to low state digitalPinEventOnRisingEdge = 2 // an event will be triggered on changes from low to high state digitalPinEventOnBothEdges = 3 // an event will be triggered on all changes ) const ( // DigitalPinEventRisingEdge indicates an inactive to active event. DigitalPinEventRisingEdge = "rising edge" // DigitalPinEventFallingEdge indicates an active to inactive event. DigitalPinEventFallingEdge = "falling edge" ) type digitalPinConfig struct { label string direction string outInitialState int activeLow bool bias int drive int debouncePeriod time.Duration edge int edgeEventHandler func(lineOffset int, timestamp time.Duration, detectedEdge string, seqno uint32, lseqno uint32) pollInterval time.Duration pollQuitChan chan struct{} } func newDigitalPinConfig(label string, options ...func(gobot.DigitalPinOptioner) bool) *digitalPinConfig { cfg := &digitalPinConfig{ label: label, direction: IN, } for _, option := range options { option(cfg) } return cfg } // WithPinLabel use a pin label, which will replace the default label "gobotio#". func WithPinLabel(label string) func(gobot.DigitalPinOptioner) bool { return func(d gobot.DigitalPinOptioner) bool { return d.SetLabel(label) } } // WithPinDirectionOutput initializes the pin as output instead of the default "input". func WithPinDirectionOutput(initial int) func(gobot.DigitalPinOptioner) bool { return func(d gobot.DigitalPinOptioner) bool { return d.SetDirectionOutput(initial) } } // WithPinDirectionInput initializes the pin as input. func WithPinDirectionInput() func(gobot.DigitalPinOptioner) bool { return func(d gobot.DigitalPinOptioner) bool { return d.SetDirectionInput() } } // WithPinActiveLow initializes the pin with inverse reaction (applies on input and output). func WithPinActiveLow() func(gobot.DigitalPinOptioner) bool { return func(d gobot.DigitalPinOptioner) bool { return d.SetActiveLow() } } // WithPinPullDown initializes the pin to be pulled down (high impedance to GND, applies on input and output). // This is working since Kernel 5.5. func WithPinPullDown() func(gobot.DigitalPinOptioner) bool { return func(d gobot.DigitalPinOptioner) bool { return d.SetBias(digitalPinBiasPullDown) } } // WithPinPullUp initializes the pin to be pulled up (high impedance to VDD, applies on input and output). // This is working since Kernel 5.5. func WithPinPullUp() func(gobot.DigitalPinOptioner) bool { return func(d gobot.DigitalPinOptioner) bool { return d.SetBias(digitalPinBiasPullUp) } } // WithPinOpenDrain initializes the output pin to be driven with open drain/collector. func WithPinOpenDrain() func(gobot.DigitalPinOptioner) bool { return func(d gobot.DigitalPinOptioner) bool { return d.SetDrive(digitalPinDriveOpenDrain) } } // WithPinOpenSource initializes the output pin to be driven with open source/emitter. func WithPinOpenSource() func(gobot.DigitalPinOptioner) bool { return func(d gobot.DigitalPinOptioner) bool { return d.SetDrive(digitalPinDriveOpenSource) } } // WithPinDebounce initializes the input pin to be debounced. func WithPinDebounce(period time.Duration) func(gobot.DigitalPinOptioner) bool { return func(d gobot.DigitalPinOptioner) bool { return d.SetDebounce(period) } } // WithPinEventOnFallingEdge initializes the input pin for edge detection and call the event handler on falling edges. func WithPinEventOnFallingEdge(handler func(lineOffset int, timestamp time.Duration, detectedEdge string, seqno uint32, lseqno uint32), ) func(gobot.DigitalPinOptioner) bool { return func(d gobot.DigitalPinOptioner) bool { return d.SetEventHandlerForEdge(handler, digitalPinEventOnFallingEdge) } } // WithPinEventOnRisingEdge initializes the input pin for edge detection and call the event handler on rising edges. func WithPinEventOnRisingEdge(handler func(lineOffset int, timestamp time.Duration, detectedEdge string, seqno uint32, lseqno uint32), ) func(gobot.DigitalPinOptioner) bool { return func(d gobot.DigitalPinOptioner) bool { return d.SetEventHandlerForEdge(handler, digitalPinEventOnRisingEdge) } } // WithPinEventOnBothEdges initializes the input pin for edge detection and call the event handler on all edges. func WithPinEventOnBothEdges(handler func(lineOffset int, timestamp time.Duration, detectedEdge string, seqno uint32, lseqno uint32), ) func(gobot.DigitalPinOptioner) bool { return func(d gobot.DigitalPinOptioner) bool { return d.SetEventHandlerForEdge(handler, digitalPinEventOnBothEdges) } } // WithPinPollForEdgeDetection initializes a discrete input pin polling function to use for edge detection. func WithPinPollForEdgeDetection( pollInterval time.Duration, pollQuitChan chan struct{}, ) func(gobot.DigitalPinOptioner) bool { return func(d gobot.DigitalPinOptioner) bool { return d.SetPollForEdgeDetection(pollInterval, pollQuitChan) } } // SetLabel sets the label to use for next reconfigure. The function is intended to use by WithPinLabel(). func (d *digitalPinConfig) SetLabel(label string) bool { if d.label == label { return false } d.label = label return true } // SetDirectionOutput sets the direction to output for next reconfigure. The function is intended to use // by WithPinDirectionOutput(). func (d *digitalPinConfig) SetDirectionOutput(initial int) bool { if d.direction == OUT { // in this case also the initial value will not be written return false } d.direction = OUT d.outInitialState = initial return true } // SetDirectionInput sets the direction to input for next reconfigure. The function is intended to use // by WithPinDirectionInput(). func (d *digitalPinConfig) SetDirectionInput() bool { if d.direction == IN { return false } d.direction = IN return true } // SetActiveLow sets the pin with inverse reaction (applies on input and output) for next reconfigure. The function // is intended to use by WithPinActiveLow(). func (d *digitalPinConfig) SetActiveLow() bool { if d.activeLow { return false } d.activeLow = true return true } // SetBias sets the pin bias (applies on input and output) for next reconfigure. The function // is intended to use by WithPinPullUp() and WithPinPullDown(). func (d *digitalPinConfig) SetBias(bias int) bool { if d.bias == bias { return false } d.bias = bias return true } // SetDrive sets the pin drive mode (applies on output only) for next reconfigure. The function // is intended to use by WithPinOpenDrain(), WithPinOpenSource() and WithPinPushPull(). func (d *digitalPinConfig) SetDrive(drive int) bool { if d.drive == drive { return false } d.drive = drive return true } // SetDebounce sets the input pin with the given debounce period for next reconfigure. The function // is intended to use by WithPinDebounce(). func (d *digitalPinConfig) SetDebounce(period time.Duration) bool { if d.debouncePeriod == period { return false } d.debouncePeriod = period return true } // SetEventHandlerForEdge sets the input pin to edge detection to call the event handler on specified edge. The // function is intended to use by WithPinEventOnFallingEdge(), WithPinEventOnRisingEdge() and WithPinEventOnBothEdges(). func (d *digitalPinConfig) SetEventHandlerForEdge( handler func(int, time.Duration, string, uint32, uint32), edge int, ) bool { if d.edge == edge { return false } d.edge = edge d.edgeEventHandler = handler return true } // SetPollForEdgeDetection use a discrete input polling method to detect edges. A poll interval of zero or smaller // will deactivate this function. Please note: Using this feature is CPU consuming and less accurate than using cdev // event handler (go-gpiocdev package) and should be done only if the former is not implemented or not working for // the adaptor. E.g. sysfs driver in gobot has not implemented edge detection yet. The function is only useful // together with SetEventHandlerForEdge() and its corresponding With*() functions. // The function is intended to use by WithPinPollForEdgeDetection(). // //nolint:nonamedreturns // useful here func (d *digitalPinConfig) SetPollForEdgeDetection( pollInterval time.Duration, pollQuitChan chan struct{}, ) (changed bool) { if d.pollInterval == pollInterval { return false } d.pollInterval = pollInterval d.pollQuitChan = pollQuitChan return true } ================================================ FILE: system/digitalpinoptions_test.go ================================================ package system import ( "testing" "time" "github.com/stretchr/testify/assert" "gobot.io/x/gobot/v2" ) var _ gobot.DigitalPinOptioner = (*digitalPinConfig)(nil) func Test_newDigitalPinConfig(t *testing.T) { // arrange const ( label = "gobotio17" ) // act d := newDigitalPinConfig(label) // assert assert.NotNil(t, d) assert.Equal(t, label, d.label) assert.Equal(t, IN, d.direction) assert.Equal(t, 0, d.outInitialState) } func Test_newDigitalPinConfigWithOption(t *testing.T) { // arrange const label = "gobotio18" // act d := newDigitalPinConfig("not used", WithPinLabel(label)) // assert assert.NotNil(t, d) assert.Equal(t, label, d.label) } func TestWithPinLabel(t *testing.T) { const ( oldLabel = "old label" newLabel = "my optional label" ) tests := map[string]struct { setLabel string want bool }{ "no_change": { setLabel: oldLabel, }, "change": { setLabel: newLabel, want: true, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange dpc := &digitalPinConfig{label: oldLabel} // act got := WithPinLabel(tc.setLabel)(dpc) // assert assert.Equal(t, tc.want, got) assert.Equal(t, tc.setLabel, dpc.label) }) } } func TestWithPinDirectionOutput(t *testing.T) { const ( // values other than 0, 1 are normally not useful, just to test oldVal = 3 newVal = 5 ) tests := map[string]struct { oldDir string want bool wantVal int }{ "no_change": { oldDir: "out", wantVal: oldVal, }, "change": { oldDir: "in", want: true, wantVal: newVal, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange dpc := &digitalPinConfig{direction: tc.oldDir, outInitialState: oldVal} // act got := WithPinDirectionOutput(newVal)(dpc) // assert assert.Equal(t, tc.want, got) assert.Equal(t, "out", dpc.direction) assert.Equal(t, tc.wantVal, dpc.outInitialState) }) } } func TestWithPinDirectionInput(t *testing.T) { tests := map[string]struct { oldDir string want bool }{ "no_change": { oldDir: "in", }, "change": { oldDir: "out", want: true, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange const initValOut = 2 // 2 is normally not useful, just to test that is not touched dpc := &digitalPinConfig{direction: tc.oldDir, outInitialState: initValOut} // act got := WithPinDirectionInput()(dpc) // assert assert.Equal(t, tc.want, got) assert.Equal(t, "in", dpc.direction) assert.Equal(t, initValOut, dpc.outInitialState) }) } } func TestWithPinActiveLow(t *testing.T) { tests := map[string]struct { oldActiveLow bool want bool }{ "no_change": { oldActiveLow: true, }, "change": { oldActiveLow: false, want: true, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange dpc := &digitalPinConfig{activeLow: tc.oldActiveLow} // act got := WithPinActiveLow()(dpc) // assert assert.Equal(t, tc.want, got) assert.True(t, dpc.activeLow) }) } } func TestWithPinPullDown(t *testing.T) { tests := map[string]struct { oldBias int want bool wantVal int }{ "no_change": { oldBias: digitalPinBiasPullDown, }, "change": { oldBias: digitalPinBiasPullUp, want: true, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange dpc := &digitalPinConfig{bias: tc.oldBias} // act got := WithPinPullDown()(dpc) // assert assert.Equal(t, tc.want, got) assert.Equal(t, digitalPinBiasPullDown, dpc.bias) }) } } func TestWithPinPullUp(t *testing.T) { tests := map[string]struct { oldBias int want bool wantVal int }{ "no_change": { oldBias: digitalPinBiasPullUp, }, "change": { oldBias: digitalPinBiasPullDown, want: true, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange dpc := &digitalPinConfig{bias: tc.oldBias} // act got := WithPinPullUp()(dpc) // assert assert.Equal(t, tc.want, got) assert.Equal(t, digitalPinBiasPullUp, dpc.bias) }) } } func TestWithPinOpenDrain(t *testing.T) { tests := map[string]struct { oldDrive int want bool wantVal int }{ "no_change": { oldDrive: digitalPinDriveOpenDrain, }, "change_from_pushpull": { oldDrive: digitalPinDrivePushPull, want: true, }, "change_from_opensource": { oldDrive: digitalPinDriveOpenSource, want: true, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange dpc := &digitalPinConfig{drive: tc.oldDrive} // act got := WithPinOpenDrain()(dpc) // assert assert.Equal(t, tc.want, got) assert.Equal(t, digitalPinDriveOpenDrain, dpc.drive) }) } } func TestWithPinOpenSource(t *testing.T) { tests := map[string]struct { oldDrive int want bool wantVal int }{ "no_change": { oldDrive: digitalPinDriveOpenSource, }, "change_from_pushpull": { oldDrive: digitalPinDrivePushPull, want: true, }, "change_from_opendrain": { oldDrive: digitalPinDriveOpenDrain, want: true, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange dpc := &digitalPinConfig{drive: tc.oldDrive} // act got := WithPinOpenSource()(dpc) // assert assert.Equal(t, tc.want, got) assert.Equal(t, digitalPinDriveOpenSource, dpc.drive) }) } } func TestWithPinDebounce(t *testing.T) { const ( oldVal = time.Duration(10) newVal = time.Duration(14) ) tests := map[string]struct { oldDebouncePeriod time.Duration want bool wantVal time.Duration }{ "no_change": { oldDebouncePeriod: newVal, }, "change": { oldDebouncePeriod: oldVal, want: true, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange dpc := &digitalPinConfig{debouncePeriod: tc.oldDebouncePeriod} // act got := WithPinDebounce(newVal)(dpc) // assert assert.Equal(t, tc.want, got) assert.Equal(t, newVal, dpc.debouncePeriod) }) } } func TestWithPinEventOnFallingEdge(t *testing.T) { const ( oldVal = digitalPinEventNone newVal = digitalPinEventOnFallingEdge ) tests := map[string]struct { oldEdge int want bool wantVal int }{ "no_change": { oldEdge: newVal, want: false, }, "change": { oldEdge: oldVal, want: true, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange dpc := &digitalPinConfig{edge: tc.oldEdge} handler := func(lineOffset int, timestamp time.Duration, detectedEdge string, seqno uint32, lseqno uint32) {} // act got := WithPinEventOnFallingEdge(handler)(dpc) // assert assert.Equal(t, tc.want, got) assert.Equal(t, newVal, dpc.edge) if tc.want { assert.NotNil(t, dpc.edgeEventHandler) } else { assert.Nil(t, dpc.edgeEventHandler) } }) } } func TestWithPinEventOnRisingEdge(t *testing.T) { const ( oldVal = digitalPinEventNone newVal = digitalPinEventOnRisingEdge ) tests := map[string]struct { oldEdge int want bool wantVal int }{ "no_change": { oldEdge: newVal, want: false, }, "change": { oldEdge: oldVal, want: true, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange dpc := &digitalPinConfig{edge: tc.oldEdge} handler := func(lineOffset int, timestamp time.Duration, detectedEdge string, seqno uint32, lseqno uint32) {} // act got := WithPinEventOnRisingEdge(handler)(dpc) // assert assert.Equal(t, tc.want, got) assert.Equal(t, newVal, dpc.edge) if tc.want { assert.NotNil(t, dpc.edgeEventHandler) } else { assert.Nil(t, dpc.edgeEventHandler) } }) } } func TestWithPinEventOnBothEdges(t *testing.T) { const ( oldVal = digitalPinEventNone newVal = digitalPinEventOnBothEdges ) tests := map[string]struct { oldEdge int want bool wantVal int }{ "no_change": { oldEdge: newVal, want: false, }, "change": { oldEdge: oldVal, want: true, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange dpc := &digitalPinConfig{edge: tc.oldEdge} handler := func(lineOffset int, timestamp time.Duration, detectedEdge string, seqno uint32, lseqno uint32) {} // act got := WithPinEventOnBothEdges(handler)(dpc) // assert assert.Equal(t, tc.want, got) assert.Equal(t, newVal, dpc.edge) if tc.want { assert.NotNil(t, dpc.edgeEventHandler) } else { assert.Nil(t, dpc.edgeEventHandler) } }) } } func TestWithPinPollForEdgeDetection(t *testing.T) { const ( oldVal = time.Duration(1) newVal = time.Duration(3) ) tests := map[string]struct { oldPollInterval time.Duration want bool wantVal time.Duration }{ "no_change": { oldPollInterval: newVal, }, "change": { oldPollInterval: oldVal, want: true, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange dpc := &digitalPinConfig{pollInterval: tc.oldPollInterval} stopChan := make(chan struct{}) defer close(stopChan) // act got := WithPinPollForEdgeDetection(newVal, stopChan)(dpc) // assert assert.Equal(t, tc.want, got) assert.Equal(t, newVal, dpc.pollInterval) }) } } ================================================ FILE: system/doc.go ================================================ /* Package system provides generic access to Linux gpio, i2c and filesystem. It is intended to be used while implementing support for a single board Linux computer */ package system // import "gobot.io/x/gobot/v2/system" ================================================ FILE: system/fs.go ================================================ package system import ( "os" "path" "regexp" ) // nativeFilesystem represents the native file system implementation type nativeFilesystem struct{} // openFile calls os.OpenFile(). func (fs *nativeFilesystem) openFile(name string, flag int, perm os.FileMode) (File, error) { return os.OpenFile(name, flag, perm) } // stat calls os.Stat() func (fs *nativeFilesystem) stat(name string) (os.FileInfo, error) { return os.Stat(name) } // find returns all items (files or folders) below the given directory matching the given pattern. func (fs *nativeFilesystem) find(baseDir string, pattern string) ([]string, error) { reg, err := regexp.Compile(pattern) if err != nil { return nil, err } items, err := os.ReadDir(baseDir) if err != nil { return nil, err } var found []string for _, item := range items { if reg.MatchString(item.Name()) { found = append(found, path.Join(baseDir, item.Name())) } } return found, nil } // readFile reads the named file and returns the contents. A successful call returns err == nil, not err == EOF. // Because ReadFile reads the whole file, it does not treat an EOF from Read as an error to be reported. func (fs *nativeFilesystem) readFile(name string) ([]byte, error) { return os.ReadFile(name) } ================================================ FILE: system/fs_mock.go ================================================ package system import ( "fmt" "log" "os" "path" "regexp" "strings" "time" ) var ( _ File = (*MockFile)(nil) _ filesystem = (*MockFilesystem)(nil) ) // MockFilesystem represents a filesystem of mock files. type MockFilesystem struct { Seq int // Increases with each write or read. Files map[string]*MockFile WithReadError bool WithWriteError bool WithCloseError bool numCallsWrite int numCallsRead int } // A MockFile represents a mock file that contains a single string. Any write // overwrites, and any read returns from the start. type MockFile struct { Contents string Seq int // When this file was last written or read. Opened bool Closed bool fd uintptr simulateWriteError error simulateReadError error fs *MockFilesystem } var ( errRead = fmt.Errorf("read error") errWrite = fmt.Errorf("write error") errClose = fmt.Errorf("close error") ) // Write writes string(b) to f.Contents func (f *MockFile) Write(b []byte) (int, error) { if f.fs.WithWriteError { return 0, errWrite } return f.WriteString(string(b)) } // Seek seeks to a specific offset in a file func (f *MockFile) Seek(offset int64, whence int) (int64, error) { return offset, nil } // WriteString writes s to f.Contents func (f *MockFile) WriteString(s string) (int, error) { f.Contents = s f.Seq = f.fs.next() f.fs.numCallsWrite++ return len(s), f.simulateWriteError } // Sync implements the File interface Sync function func (f *MockFile) Sync() error { return nil } // Read copies b bytes from f.Contents func (f *MockFile) Read(b []byte) (int, error) { if f.fs.WithReadError { return 0, errRead } count := len(b) if len(f.Contents) < count { // note: if length of content is smaller than given b than b will not completely overridden, e.g. if content // is empty, than b is not changed at all. This is fine for this MockFile, but in real world, on different // length, an error will be created. count = len(f.Contents) } copy(b, []byte(f.Contents)[:count]) f.Seq = f.fs.next() f.fs.numCallsRead++ return count, f.simulateReadError } // ReadAt calls MockFile.Read func (f *MockFile) ReadAt(b []byte, off int64) (int, error) { return f.Read(b) } // Fd returns a random uintprt based on the time of the MockFile creation func (f *MockFile) Fd() uintptr { return f.fd } // Close implements the File interface Close function func (f *MockFile) Close() error { if f != nil { f.Opened = false f.Closed = true if f.fs != nil && f.fs.WithCloseError { f.Closed = false return errClose } } return nil } // newMockFilesystem returns a new MockFilesystem given a list of file and folder paths func newMockFilesystem(items []string) *MockFilesystem { m := &MockFilesystem{ Files: make(map[string]*MockFile), } for _, item := range items { m.Add(item) } return m } // OpenFile opens file name from fs.Files, if the file does not exist it returns an os.PathError func (fs *MockFilesystem) openFile(name string, _ int, _ os.FileMode) (File, error) { f, ok := fs.Files[name] if ok { f.Opened = true f.Closed = false return f, nil } return (*MockFile)(nil), &os.PathError{Err: fmt.Errorf("%s: no such file", name)} } // Stat returns a generic FileInfo for all files in fs.Files. // If the file does not exist it returns an os.PathError func (fs *MockFilesystem) stat(name string) (os.FileInfo, error) { _, ok := fs.Files[name] if ok { // return file based mock FileInfo, CreateTemp don't like "/" in between tmpFile, err := os.CreateTemp("", strings.ReplaceAll(name, "/", "_")) if err != nil { log.Println("A") return nil, err } defer func() { tmpFile.Close() os.Remove(tmpFile.Name()) }() return os.Stat(tmpFile.Name()) } dirName := name + "/" for path := range fs.Files { if strings.HasPrefix(path, dirName) { // return dir based mock FileInfo, TempDir don't like "/" in between tmpDir, err := os.MkdirTemp("", strings.ReplaceAll(name, "/", "_")) if err != nil { return nil, err } defer os.RemoveAll(tmpDir) return os.Stat(tmpDir) } } return nil, &os.PathError{Err: fmt.Errorf("%s: no such file", name)} } // Find returns all items (files or folders) below the given directory matching the given pattern. func (fs *MockFilesystem) find(baseDir string, pattern string) ([]string, error) { reg, err := regexp.Compile(pattern) if err != nil { return nil, err } var found []string for name := range fs.Files { if !strings.HasPrefix(name, baseDir) { continue } item := strings.TrimPrefix(name[len(baseDir):], "/") firstItem := strings.Split(item, "/")[0] if reg.MatchString(firstItem) { found = append(found, path.Join(baseDir, firstItem)) } } return found, nil } // readFile returns the contents of the given file. If the file does not exist it returns an os.PathError func (fs *MockFilesystem) readFile(name string) ([]byte, error) { if fs.WithReadError { return nil, errRead } f, ok := fs.Files[name] if !ok { return nil, &os.PathError{Err: fmt.Errorf("%s: no such file", name)} } f.fs.numCallsRead++ return []byte(f.Contents), nil } func (fs *MockFilesystem) next() int { fs.Seq++ return fs.Seq } // Add adds a new file to fs.Files given a name, and returns the newly created file func (fs *MockFilesystem) Add(name string) *MockFile { f := &MockFile{ Seq: -1, fd: uintptr(time.Now().UnixNano() & 0xffff), fs: fs, } fs.Files[name] = f return f } ================================================ FILE: system/fs_mock_test.go ================================================ package system import ( "sort" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestMockFilesystemOpen(t *testing.T) { fs := newMockFilesystem([]string{"foo"}) f1 := fs.Files["foo"] assert.False(t, f1.Opened) f2, err := fs.openFile("foo", 0, 0o666) assert.Equal(t, f2, f1) require.NoError(t, err) err = f2.Sync() require.NoError(t, err) _, err = fs.openFile("bar", 0, 0o666) require.ErrorContains(t, err, " : bar: no such file") fs.Add("bar") f4, _ := fs.openFile("bar", 0, 0o666) assert.NotEqual(t, f1.Fd(), f4.Fd()) } func TestMockFilesystemStat(t *testing.T) { fs := newMockFilesystem([]string{"foo", "bar/baz"}) fileStat, err := fs.stat("foo") require.NoError(t, err) assert.False(t, fileStat.IsDir()) dirStat, err := fs.stat("bar") require.NoError(t, err) assert.True(t, dirStat.IsDir()) _, err = fs.stat("plonk") require.ErrorContains(t, err, " : plonk: no such file") } func TestMockFilesystemFind(t *testing.T) { // arrange fs := newMockFilesystem([]string{"/foo", "/bar/foo", "/bar/foo/baz", "/bar/baz/foo", "/bar/foo/bak"}) tests := map[string]struct { baseDir string pattern string want []string }{ "flat": {baseDir: "/", pattern: "foo", want: []string{"/foo"}}, "in directory no slash": {baseDir: "/bar", pattern: "foo", want: []string{"/bar/foo", "/bar/foo", "/bar/foo"}}, "file": {baseDir: "/bar/baz/", pattern: "foo", want: []string{"/bar/baz/foo"}}, "file pattern": {baseDir: "/bar/foo/", pattern: "ba.?", want: []string{"/bar/foo/bak", "/bar/foo/baz"}}, "empty": {baseDir: "/", pattern: "plonk", want: nil}, } for name, tt := range tests { t.Run(name, func(t *testing.T) { // act dirs, err := fs.find(tt.baseDir, tt.pattern) // assert require.NoError(t, err) sort.Strings(dirs) assert.Equal(t, tt.want, dirs) }) } } func TestMockFilesystemWrite(t *testing.T) { fs := newMockFilesystem([]string{"bar"}) f1 := fs.Files["bar"] f2, err := fs.openFile("bar", 0, 0o666) require.NoError(t, err) // Never been read or written. assert.LessOrEqual(t, f1.Seq, 0) _, _ = f2.WriteString("testing") // Was written. assert.Positive(t, f1.Seq) assert.Equal(t, "testing", f1.Contents) } func TestMockFilesystemRead(t *testing.T) { fs := newMockFilesystem([]string{"bar"}) f1 := fs.Files["bar"] f1.Contents = "Yip" f2, err := fs.openFile("bar", 0, 0o666) require.NoError(t, err) // Never been read or written. assert.LessOrEqual(t, f1.Seq, 0) buffer := make([]byte, 20) n, _ := f2.Read(buffer) // Was read. assert.Positive(t, f1.Seq) assert.Equal(t, 3, n) assert.Equal(t, "Yip", string(buffer[:3])) n, _ = f2.ReadAt(buffer, 10) assert.Equal(t, 3, n) } ================================================ FILE: system/fs_test.go ================================================ package system import ( "os" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestFilesystemOpen(t *testing.T) { fs := &nativeFilesystem{} file, err := fs.openFile(os.DevNull, os.O_RDONLY, 0o666) require.NoError(t, err) _ = file } func TestFilesystemStat(t *testing.T) { fs := &nativeFilesystem{} fileInfo, err := fs.stat(os.DevNull) require.NoError(t, err) assert.NotNil(t, fileInfo) } ================================================ FILE: system/i2c_device.go ================================================ package system import ( "fmt" "log" "os" "sync" "unsafe" ) const ( i2cDeviceDebug = false forceSetAddress = false // normally address will be written only when changed, this behavior can be overridden ) const ( // From /usr/include/linux/i2c-dev.h: // ioctl signals I2C_TARGET = 0x0703 I2C_FUNCS = 0x0705 I2C_SMBUS = 0x0720 // Read/write markers I2C_SMBUS_READ = 1 I2C_SMBUS_WRITE = 0 // From /usr/include/linux/i2c.h: // Adapter functionality I2C_FUNC_SMBUS_READ_BYTE = 0x00020000 I2C_FUNC_SMBUS_WRITE_BYTE = 0x00040000 I2C_FUNC_SMBUS_READ_BYTE_DATA = 0x00080000 I2C_FUNC_SMBUS_WRITE_BYTE_DATA = 0x00100000 I2C_FUNC_SMBUS_READ_WORD_DATA = 0x00200000 I2C_FUNC_SMBUS_WRITE_WORD_DATA = 0x00400000 I2C_FUNC_SMBUS_READ_BLOCK_DATA = 0x01000000 I2C_FUNC_SMBUS_WRITE_BLOCK_DATA = 0x02000000 I2C_FUNC_SMBUS_READ_I2C_BLOCK = 0x04000000 // I2C-like block transfer with 1-byte reg. addr. I2C_FUNC_SMBUS_WRITE_I2C_BLOCK = 0x08000000 // I2C-like block transfer with 1-byte reg. addr. // Transaction types I2C_SMBUS_BYTE = 1 I2C_SMBUS_BYTE_DATA = 2 I2C_SMBUS_WORD_DATA = 3 I2C_SMBUS_PROC_CALL = 4 I2C_SMBUS_BLOCK_DATA = 5 I2C_SMBUS_I2C_BLOCK_BROKEN = 6 I2C_SMBUS_BLOCK_PROC_CALL = 7 /* SMBus 2.0 */ I2C_SMBUS_I2C_BLOCK_DATA = 8 /* SMBus 2.0 */ ) type i2cSmbusIoctlData struct { readWrite byte command byte protocol uint32 data unsafe.Pointer } type i2cDevice struct { location string sys systemCaller fs filesystem file File funcs uint64 // adapter functionality mask lastAddress int mutex sync.Mutex } // NewI2cDevice returns a Linux Kernel access by ioctrl to the given i2c bus location (character device). // Important note for "os.ModeExclusive": this is undefined without create the file for character devices, this means // a second open will not return an error e.g. due to a busy resource. If this is not wanted, e.g. to minimize count of // open fd's this needs to be prevented at caller side by implementing a caching mechanism. Furthermore this behavior // can lead to problems with multiple devices on the same bus because the cycle SetAddress()...Read()/Write() etc. can // be interrupted when using multiple instances for the same location. func (a *Accesser) NewI2cDevice(location string) (*i2cDevice, error) { if location == "" { return nil, fmt.Errorf("the given character device location is empty") } d := &i2cDevice{ location: location, sys: a.sys, fs: a.fs, lastAddress: -1, } return d, nil } // Close closes the character device file and resets the lazy variables. func (d *i2cDevice) Close() error { d.mutex.Lock() defer d.mutex.Unlock() d.funcs = 0 d.lastAddress = -1 if d.file != nil { return d.file.Close() } return nil } // ReadByte reads a byte from the current register of an i2c device. func (d *i2cDevice) ReadByte(address int) (byte, error) { d.mutex.Lock() defer d.mutex.Unlock() if err := d.queryFunctionality(I2C_FUNC_SMBUS_READ_BYTE, "read byte"); err != nil { return 0, err } var data uint8 = 0xFC // set value for debugging purposes err := d.smbusAccess(address, I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, unsafe.Pointer(&data)) return data, err } // ReadByteData reads a byte from the given register of an i2c device. func (d *i2cDevice) ReadByteData(address int, reg uint8) (uint8, error) { d.mutex.Lock() defer d.mutex.Unlock() if err := d.queryFunctionality(I2C_FUNC_SMBUS_READ_BYTE_DATA, "read byte data"); err != nil { return 0, err } var data uint8 = 0xFD // set value for debugging purposes err := d.smbusAccess(address, I2C_SMBUS_READ, reg, I2C_SMBUS_BYTE_DATA, unsafe.Pointer(&data)) return data, err } // ReadWordData reads a 16 bit value starting from the given register of an i2c device. func (d *i2cDevice) ReadWordData(address int, reg uint8) (uint16, error) { d.mutex.Lock() defer d.mutex.Unlock() if err := d.queryFunctionality(I2C_FUNC_SMBUS_READ_WORD_DATA, "read word data"); err != nil { return 0, err } var data uint16 = 0xFFFE // set value for debugging purposes err := d.smbusAccess(address, I2C_SMBUS_READ, reg, I2C_SMBUS_WORD_DATA, unsafe.Pointer(&data)) return data, err } // ReadBlockData fills the given buffer with reads starting from the given register of an i2c device. func (d *i2cDevice) ReadBlockData(address int, reg uint8, data []byte) error { d.mutex.Lock() defer d.mutex.Unlock() dataLen := len(data) if dataLen > 32 { return fmt.Errorf("reading blocks larger than 32 bytes (%v) not supported", len(data)) } data[0] = 0xFF // set value for debugging purposes if err := d.queryFunctionality(I2C_FUNC_SMBUS_READ_I2C_BLOCK, "read block data"); err != nil { if i2cDeviceDebug { log.Printf("%s, use fallback\n", err.Error()) } return d.readBlockDataFallback(address, reg, data) } // set the first element with the data size buf := make([]byte, dataLen+1) buf[0] = byte(dataLen) copy(buf[1:], data) if err := d.smbusAccess(address, I2C_SMBUS_READ, reg, I2C_SMBUS_I2C_BLOCK_DATA, unsafe.Pointer(&buf[0])); err != nil { return err } // get data from buffer without first size element copy(data, buf[1:]) return nil } // WriteByte writes the given byte value to the current register of an i2c device. func (d *i2cDevice) WriteByte(address int, val byte) error { d.mutex.Lock() defer d.mutex.Unlock() if err := d.queryFunctionality(I2C_FUNC_SMBUS_WRITE_BYTE, "write byte"); err != nil { return err } return d.smbusAccess(address, I2C_SMBUS_WRITE, val, I2C_SMBUS_BYTE, nil) } // WriteByteData writes the given byte value to the given register of an i2c device. func (d *i2cDevice) WriteByteData(address int, reg uint8, val uint8) error { d.mutex.Lock() defer d.mutex.Unlock() if err := d.queryFunctionality(I2C_FUNC_SMBUS_WRITE_BYTE_DATA, "write byte data"); err != nil { return err } data := val return d.smbusAccess(address, I2C_SMBUS_WRITE, reg, I2C_SMBUS_BYTE_DATA, unsafe.Pointer(&data)) } // WriteWordData writes the given 16 bit value starting from the given register of an i2c device. func (d *i2cDevice) WriteWordData(address int, reg uint8, val uint16) error { d.mutex.Lock() defer d.mutex.Unlock() if err := d.queryFunctionality(I2C_FUNC_SMBUS_WRITE_WORD_DATA, "write word data"); err != nil { return err } data := val return d.smbusAccess(address, I2C_SMBUS_WRITE, reg, I2C_SMBUS_WORD_DATA, unsafe.Pointer(&data)) } // WriteBlockData writes the given buffer starting from the given register of an i2c device. func (d *i2cDevice) WriteBlockData(address int, reg uint8, data []byte) error { d.mutex.Lock() defer d.mutex.Unlock() dataLen := len(data) if dataLen > 32 { return fmt.Errorf("writing blocks larger than 32 bytes (%v) not supported", len(data)) } if err := d.queryFunctionality(I2C_FUNC_SMBUS_WRITE_I2C_BLOCK, "write i2c block"); err != nil { if i2cDeviceDebug { log.Printf("%s, use fallback\n", err.Error()) } return d.writeBlockDataFallback(address, reg, data) } // set the first element with the data size buf := make([]byte, dataLen+1) buf[0] = byte(dataLen) copy(buf[1:], data) return d.smbusAccess(address, I2C_SMBUS_WRITE, reg, I2C_SMBUS_I2C_BLOCK_DATA, unsafe.Pointer(&buf[0])) } // WriteBytes writes the given buffer starting from the current register of an i2c device. func (d *i2cDevice) WriteBytes(address int, data []byte) error { d.mutex.Lock() defer d.mutex.Unlock() return d.writeBytes(address, data) } // Read implements direct I2C read operations. func (d *i2cDevice) Read(address int, b []byte) (int, error) { d.mutex.Lock() defer d.mutex.Unlock() return d.read(address, b) } // Write implements the io.ReadWriteCloser method by direct I2C write operations. func (d *i2cDevice) Write(address int, b []byte) (int, error) { d.mutex.Lock() defer d.mutex.Unlock() return d.write(address, b) } func (d *i2cDevice) readBlockDataFallback(address int, reg uint8, data []byte) error { if err := d.writeBytes(address, []byte{reg}); err != nil { return err } if err := d.readAndCheckCount(address, data); err != nil { return err } return nil } func (d *i2cDevice) writeBlockDataFallback(address int, reg uint8, data []byte) error { buf := make([]byte, len(data)+1) copy(buf[1:], data) buf[0] = reg if err := d.writeBytes(address, buf); err != nil { return err } return nil } func (d *i2cDevice) writeBytes(address int, data []byte) error { n, err := d.write(address, data) if err != nil { return err } if n != len(data) { return fmt.Errorf("write %v bytes to device by sysfs, expected %v", n, len(data)) } return nil } func (d *i2cDevice) write(address int, b []byte) (int, error) { if err := d.setAddress(address); err != nil { return 0, err } if err := d.openFileLazy("Write"); err != nil { return 0, err } return d.file.Write(b) } func (d *i2cDevice) readAndCheckCount(address int, data []byte) error { n, err := d.read(address, data) if err != nil { return err } if n != len(data) { return fmt.Errorf("read %v bytes from device by sysfs, expected %v", n, len(data)) } return nil } func (d *i2cDevice) read(address int, b []byte) (int, error) { if err := d.setAddress(address); err != nil { return 0, err } if err := d.openFileLazy("Read"); err != nil { return 0, err } return d.file.Read(b) } func (d *i2cDevice) queryFunctionality(requested uint64, sender string) error { // lazy initialization if d.funcs == 0 { if err := d.syscallIoctl(I2C_FUNCS, unsafe.Pointer(&d.funcs), 0, "Querying functionality"); err != nil { return err } } if d.funcs&requested == 0 { return fmt.Errorf("SMBus %s not supported", sender) } return nil } func (d *i2cDevice) smbusAccess( address int, readWrite byte, command byte, protocol uint32, dataStart unsafe.Pointer, ) error { if err := d.setAddress(address); err != nil { return err } smbus := i2cSmbusIoctlData{ readWrite: readWrite, command: command, protocol: protocol, data: dataStart, // the reflected value of unsafePointer equals uintptr(dataStart), } sender := fmt.Sprintf("SMBus access r/w: %d, command: %d, protocol: %d, address: %d", readWrite, command, protocol, d.lastAddress) if err := d.syscallIoctl(I2C_SMBUS, unsafe.Pointer(&smbus), 0, sender); err != nil { return err } return nil } // setAddress sets the address of the i2c device to use. func (d *i2cDevice) setAddress(address int) error { if d.lastAddress == address && !forceSetAddress { if i2cDeviceDebug { log.Printf("I2C address %d was already sent - skip", address) } return nil } if err := d.syscallIoctl(I2C_TARGET, nil, address, "Setting address"); err != nil { return err } d.lastAddress = address return nil } func (d *i2cDevice) syscallIoctl(signal uintptr, payload unsafe.Pointer, address int, sender string) error { if err := d.openFileLazy(sender); err != nil { return err } //nolint:gosec // TODO: fix later if _, _, errno := d.sys.syscall(Syscall_SYS_IOCTL, d.file, signal, payload, uint16(address)); errno != 0 { return fmt.Errorf("%s failed with syscall.Errno %v", sender, errno) } return nil } func (d *i2cDevice) openFileLazy(sender string) error { //nolint:unparam // useful for debugging // lazy initialization // note: "os.ModeExclusive" is undefined without create the file. This means for the existing character device, // a second open will not return an error e.g. due to a busy resource, so most likely "os.ModeExclusive" is not really // helpful and we drop it to the default "0" used by normal Open(). if d.file == nil { var err error if d.file, err = d.fs.openFile(d.location, os.O_RDWR, 0); err != nil { return err } } return nil } ================================================ FILE: system/i2c_device_test.go ================================================ //nolint:gosec // ok for test package system import ( "os" "testing" "unsafe" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) const dev = "/dev/i2c-1" func getSyscallFuncImpl( errorMask byte, ) func(trap, a1, a2 uintptr, a3 unsafe.Pointer) (r1, r2 uintptr, err SyscallErrno) { // bit 0: error on function query // bit 1: error on set address // bit 2: error on command //nolint:nonamedreturns // useful here return func(trap, a1, a2 uintptr, a3 unsafe.Pointer) (r1, r2 uintptr, err SyscallErrno) { // function query if (trap == Syscall_SYS_IOCTL) && (a2 == I2C_FUNCS) { if errorMask&0x01 == 0x01 { return 0, 0, 1 } funcPtr := (*uint64)(a3) *funcPtr = I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_READ_BYTE_DATA | I2C_FUNC_SMBUS_READ_WORD_DATA | I2C_FUNC_SMBUS_WRITE_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA | I2C_FUNC_SMBUS_WRITE_WORD_DATA } // set address if (trap == Syscall_SYS_IOCTL) && (a2 == I2C_TARGET) { if errorMask&0x02 == 0x02 { return 0, 0, 1 } } // command if (trap == Syscall_SYS_IOCTL) && (a2 == I2C_SMBUS) { if errorMask&0x04 == 0x04 { return 0, 0, 1 } } // Let all operations succeed return 0, 0, 0 } } func initTestI2cDeviceWithMockedSys() (*i2cDevice, *mockSyscall) { a := NewAccesser() msc := a.UseMockSyscall() a.UseMockFilesystem([]string{dev}) d, err := a.NewI2cDevice(dev) if err != nil { panic(err) } return d, msc } func TestNewI2cDevice(t *testing.T) { tests := map[string]struct { dev string wantErr string }{ "ok": { dev: dev, }, "empty": { dev: "", wantErr: "the given character device location is empty", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange a := NewAccesser() // act d, err := a.NewI2cDevice(tc.dev) // assert if tc.wantErr != "" { require.ErrorContains(t, err, tc.wantErr) assert.Equal(t, (*i2cDevice)(nil), d) } else { var _ gobot.I2cSystemDevicer = d require.NoError(t, err) } }) } } func TestClose(t *testing.T) { // arrange d, _ := initTestI2cDeviceWithMockedSys() // act & assert require.NoError(t, d.Close()) } func TestWriteRead(t *testing.T) { // arrange d, _ := initTestI2cDeviceWithMockedSys() wbuf := []byte{0x01, 0x02, 0x03} rbuf := make([]byte, 4) // act wn, werr := d.Write(1, wbuf) rn, rerr := d.Read(1, rbuf) // assert require.NoError(t, werr) require.NoError(t, rerr) assert.Len(t, wbuf, wn) assert.Len(t, wbuf, rn) // will read only the written values assert.Equal(t, rbuf[:len(wbuf)], wbuf) } func TestReadByte(t *testing.T) { tests := map[string]struct { funcs uint64 syscallImpl func(trap, a1, a2 uintptr, a3 unsafe.Pointer) (r1, r2 uintptr, err SyscallErrno) wantErr string }{ "read_byte_ok": { funcs: I2C_FUNC_SMBUS_READ_BYTE, }, "error_syscall": { funcs: I2C_FUNC_SMBUS_READ_BYTE, syscallImpl: getSyscallFuncImpl(0x04), wantErr: "SMBus access r/w: 1, command: 0, protocol: 1, address: 2 " + "failed with syscall.Errno operation not permitted", }, "error_not_supported": { wantErr: "SMBus read byte not supported", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, msc := initTestI2cDeviceWithMockedSys() msc.Impl = tc.syscallImpl d.funcs = tc.funcs const want = byte(5) msc.dataSlice = []byte{want} // act got, err := d.ReadByte(2) // assert if tc.wantErr != "" { require.ErrorContains(t, err, tc.wantErr) } else { require.NoError(t, err) assert.Equal(t, want, got) assert.Equal(t, d.file, msc.lastFile) assert.Equal(t, uintptr(I2C_SMBUS), msc.lastSignal) assert.Equal(t, byte(I2C_SMBUS_READ), msc.smbus.readWrite) assert.Equal(t, byte(0), msc.smbus.command) // register is set to 0 in that case assert.Equal(t, uint32(I2C_SMBUS_BYTE), msc.smbus.protocol) } }) } } func TestReadByteData(t *testing.T) { tests := map[string]struct { funcs uint64 syscallImpl func(trap, a1, a2 uintptr, a3 unsafe.Pointer) (r1, r2 uintptr, err SyscallErrno) wantErr string }{ "read_byte_data_ok": { funcs: I2C_FUNC_SMBUS_READ_BYTE_DATA, }, "error_syscall": { funcs: I2C_FUNC_SMBUS_READ_BYTE_DATA, syscallImpl: getSyscallFuncImpl(0x04), wantErr: "SMBus access r/w: 1, command: 1, protocol: 2, address: 3 " + "failed with syscall.Errno operation not permitted", }, "error_not_supported": { wantErr: "SMBus read byte data not supported", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, msc := initTestI2cDeviceWithMockedSys() msc.Impl = tc.syscallImpl d.funcs = tc.funcs const ( reg = byte(0x01) want = byte(0x02) ) msc.dataSlice = []byte{want} // act got, err := d.ReadByteData(3, reg) // assert if tc.wantErr != "" { require.ErrorContains(t, err, tc.wantErr) } else { require.NoError(t, err) assert.Equal(t, want, got) assert.Equal(t, d.file, msc.lastFile) assert.Equal(t, uintptr(I2C_SMBUS), msc.lastSignal) assert.Equal(t, byte(I2C_SMBUS_READ), msc.smbus.readWrite) assert.Equal(t, reg, msc.smbus.command) assert.Equal(t, uint32(I2C_SMBUS_BYTE_DATA), msc.smbus.protocol) } }) } } func TestReadWordData(t *testing.T) { tests := map[string]struct { funcs uint64 syscallImpl func(trap, a1, a2 uintptr, a3 unsafe.Pointer) (r1, r2 uintptr, err SyscallErrno) wantErr string }{ "read_word_data_ok": { funcs: I2C_FUNC_SMBUS_READ_WORD_DATA, }, "error_syscall": { funcs: I2C_FUNC_SMBUS_READ_WORD_DATA, syscallImpl: getSyscallFuncImpl(0x04), wantErr: "SMBus access r/w: 1, command: 2, protocol: 3, address: 4 " + "failed with syscall.Errno operation not permitted", }, "error_not_supported": { wantErr: "SMBus read word data not supported", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, msc := initTestI2cDeviceWithMockedSys() msc.Impl = tc.syscallImpl d.funcs = tc.funcs const ( reg = byte(0x02) msbyte = byte(0xD4) lsbyte = byte(0x31) want = uint16(54321) ) // all common drivers read LSByte first msc.dataSlice = []byte{lsbyte, msbyte} // act got, err := d.ReadWordData(4, reg) // assert if tc.wantErr != "" { require.ErrorContains(t, err, tc.wantErr) } else { require.NoError(t, err) assert.Equal(t, want, got) assert.Equal(t, d.file, msc.lastFile) assert.Equal(t, uintptr(I2C_SMBUS), msc.lastSignal) assert.Equal(t, byte(I2C_SMBUS_READ), msc.smbus.readWrite) assert.Equal(t, reg, msc.smbus.command) assert.Equal(t, uint32(I2C_SMBUS_WORD_DATA), msc.smbus.protocol) } }) } } func TestReadBlockData(t *testing.T) { // arrange const ( reg = byte(0x03) wantB0 = byte(11) wantB1 = byte(22) wantB2 = byte(33) wantB3 = byte(44) wantB4 = byte(55) wantB5 = byte(66) wantB6 = byte(77) wantB7 = byte(88) wantB8 = byte(99) wantB9 = byte(111) ) tests := map[string]struct { funcs uint64 syscallImpl func(trap, a1, a2 uintptr, a3 unsafe.Pointer) (r1, r2 uintptr, err SyscallErrno) wantErr string }{ "read_block_data_ok": { funcs: I2C_FUNC_SMBUS_READ_I2C_BLOCK, }, "error_syscall": { funcs: I2C_FUNC_SMBUS_READ_I2C_BLOCK, syscallImpl: getSyscallFuncImpl(0x04), wantErr: "SMBus access r/w: 1, command: 3, protocol: 8, address: 5 " + "failed with syscall.Errno operation not permitted", }, "error_from_used_fallback_if_not_supported": { wantErr: "read 1 bytes from device by sysfs, expected 10", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, msc := initTestI2cDeviceWithMockedSys() msc.Impl = tc.syscallImpl d.funcs = tc.funcs msc.dataSlice = []byte{wantB0, wantB1, wantB2, wantB3, wantB4, wantB5, wantB6, wantB7, wantB8, wantB9} buf := []byte{12, 23, 34, 45, 56, 67, 78, 89, 98, 87} // act err := d.ReadBlockData(5, reg, buf) // assert if tc.wantErr != "" { require.ErrorContains(t, err, tc.wantErr) } else { require.NoError(t, err) assert.Equal(t, msc.dataSlice, buf) assert.Equal(t, d.file, msc.lastFile) assert.Equal(t, uintptr(I2C_SMBUS), msc.lastSignal) assert.Equal(t, uint8(len(buf)+1), msc.sliceSize) assert.Equal(t, byte(I2C_SMBUS_READ), msc.smbus.readWrite) assert.Equal(t, reg, msc.smbus.command) assert.Equal(t, uint32(I2C_SMBUS_I2C_BLOCK_DATA), msc.smbus.protocol) } }) } } func TestWriteByte(t *testing.T) { tests := map[string]struct { funcs uint64 syscallImpl func(trap, a1, a2 uintptr, a3 unsafe.Pointer) (r1, r2 uintptr, err SyscallErrno) wantErr string }{ "write_byte_ok": { funcs: I2C_FUNC_SMBUS_WRITE_BYTE, }, "error_syscall": { funcs: I2C_FUNC_SMBUS_WRITE_BYTE, syscallImpl: getSyscallFuncImpl(0x04), wantErr: "SMBus access r/w: 0, command: 68, protocol: 1, address: 6 " + "failed with syscall.Errno operation not permitted", }, "error_not_supported": { wantErr: "SMBus write byte not supported", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, msc := initTestI2cDeviceWithMockedSys() msc.Impl = tc.syscallImpl d.funcs = tc.funcs const val = byte(0x44) // act err := d.WriteByte(6, val) // assert if tc.wantErr != "" { require.ErrorContains(t, err, tc.wantErr) } else { require.NoError(t, err) assert.Equal(t, d.file, msc.lastFile) assert.Equal(t, uintptr(I2C_SMBUS), msc.lastSignal) assert.Equal(t, byte(I2C_SMBUS_WRITE), msc.smbus.readWrite) assert.Equal(t, val, msc.smbus.command) // in byte write, the register/command is used for the value assert.Equal(t, uint32(I2C_SMBUS_BYTE), msc.smbus.protocol) } }) } } func TestWriteByteData(t *testing.T) { tests := map[string]struct { funcs uint64 syscallImpl func(trap, a1, a2 uintptr, a3 unsafe.Pointer) (r1, r2 uintptr, err SyscallErrno) wantErr string }{ "write_byte_data_ok": { funcs: I2C_FUNC_SMBUS_WRITE_BYTE_DATA, }, "error_syscall": { funcs: I2C_FUNC_SMBUS_WRITE_BYTE_DATA, syscallImpl: getSyscallFuncImpl(0x04), wantErr: "SMBus access r/w: 0, command: 4, protocol: 2, address: 7 " + "failed with syscall.Errno operation not permitted", }, "error_not_supported": { wantErr: "SMBus write byte data not supported", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, msc := initTestI2cDeviceWithMockedSys() msc.Impl = tc.syscallImpl d.funcs = tc.funcs const ( reg = byte(0x04) val = byte(0x55) ) // act err := d.WriteByteData(7, reg, val) // assert if tc.wantErr != "" { require.ErrorContains(t, err, tc.wantErr) } else { require.NoError(t, err) assert.Equal(t, d.file, msc.lastFile) assert.Equal(t, uintptr(I2C_SMBUS), msc.lastSignal) assert.Equal(t, byte(I2C_SMBUS_WRITE), msc.smbus.readWrite) assert.Equal(t, reg, msc.smbus.command) assert.Equal(t, uint32(I2C_SMBUS_BYTE_DATA), msc.smbus.protocol) assert.Len(t, msc.dataSlice, 1) assert.Equal(t, val, msc.dataSlice[0]) } }) } } func TestWriteWordData(t *testing.T) { tests := map[string]struct { funcs uint64 syscallImpl func(trap, a1, a2 uintptr, a3 unsafe.Pointer) (r1, r2 uintptr, err SyscallErrno) wantErr string }{ "write_word_data_ok": { funcs: I2C_FUNC_SMBUS_WRITE_WORD_DATA, }, "error_syscall": { funcs: I2C_FUNC_SMBUS_WRITE_WORD_DATA, syscallImpl: getSyscallFuncImpl(0x04), wantErr: "SMBus access r/w: 0, command: 5, protocol: 3, address: 8 " + "failed with syscall.Errno operation not permitted", }, "error_not_supported": { wantErr: "SMBus write word data not supported", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, msc := initTestI2cDeviceWithMockedSys() msc.Impl = tc.syscallImpl d.funcs = tc.funcs const ( reg = byte(0x05) val = uint16(54321) wantLSByte = byte(0x31) wantMSByte = byte(0xD4) ) // act err := d.WriteWordData(8, reg, val) // assert if tc.wantErr != "" { require.ErrorContains(t, err, tc.wantErr) } else { require.NoError(t, err) assert.Equal(t, d.file, msc.lastFile) assert.Equal(t, uintptr(I2C_SMBUS), msc.lastSignal) assert.Equal(t, byte(I2C_SMBUS_WRITE), msc.smbus.readWrite) assert.Equal(t, reg, msc.smbus.command) assert.Equal(t, uint32(I2C_SMBUS_WORD_DATA), msc.smbus.protocol) assert.Len(t, msc.dataSlice, 2) // all common drivers write LSByte first assert.Equal(t, wantLSByte, msc.dataSlice[0]) assert.Equal(t, wantMSByte, msc.dataSlice[1]) } }) } } func TestWriteBlockData(t *testing.T) { // arrange const ( reg = byte(0x06) b0 = byte(0x09) b1 = byte(0x11) b2 = byte(0x22) b3 = byte(0x33) b4 = byte(0x44) b5 = byte(0x55) b6 = byte(0x66) b7 = byte(0x77) b8 = byte(0x88) b9 = byte(0x99) ) tests := map[string]struct { funcs uint64 syscallImpl func(trap, a1, a2 uintptr, a3 unsafe.Pointer) (r1, r2 uintptr, err SyscallErrno) wantErr string }{ "write_block_data_ok": { funcs: I2C_FUNC_SMBUS_WRITE_I2C_BLOCK, }, "error_syscall": { funcs: I2C_FUNC_SMBUS_WRITE_I2C_BLOCK, syscallImpl: getSyscallFuncImpl(0x04), wantErr: "SMBus access r/w: 0, command: 6, protocol: 8, address: 9 " + "failed with syscall.Errno operation not permitted", }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, msc := initTestI2cDeviceWithMockedSys() msc.Impl = tc.syscallImpl d.funcs = tc.funcs data := []byte{b0, b1, b2, b3, b4, b5, b6, b7, b8, b9} // act err := d.WriteBlockData(9, reg, data) // assert if tc.wantErr != "" { require.ErrorContains(t, err, tc.wantErr) } else { require.NoError(t, err) assert.Equal(t, d.file, msc.lastFile) assert.Equal(t, uintptr(I2C_SMBUS), msc.lastSignal) assert.Equal(t, uint8(len(data)+1), msc.sliceSize) // including size element assert.Equal(t, byte(I2C_SMBUS_WRITE), msc.smbus.readWrite) assert.Equal(t, reg, msc.smbus.command) assert.Equal(t, uint32(I2C_SMBUS_I2C_BLOCK_DATA), msc.smbus.protocol) assert.Equal(t, uint8(len(data)), msc.dataSlice[0]) // data size assert.Equal(t, data, msc.dataSlice[1:]) } }) } } func TestWriteBlockDataTooMuch(t *testing.T) { // arrange d, _ := initTestI2cDeviceWithMockedSys() // act err := d.WriteBlockData(10, 0x01, make([]byte, 33)) // assert require.ErrorContains(t, err, "writing blocks larger than 32 bytes (33) not supported") } func Test_setAddress(t *testing.T) { // arrange d, msc := initTestI2cDeviceWithMockedSys() // act err := d.setAddress(0xff) // assert require.NoError(t, err) assert.Equal(t, uintptr(0xff), msc.devAddress) } func Test_queryFunctionality(t *testing.T) { tests := map[string]struct { requested uint64 dev string syscallImpl func(trap, a1, a2 uintptr, a3 unsafe.Pointer) (r1, r2 uintptr, err SyscallErrno) wantErr string wantFile bool wantFuncs uint64 }{ "ok": { requested: I2C_FUNC_SMBUS_READ_BYTE, dev: dev, syscallImpl: getSyscallFuncImpl(0x00), wantFile: true, wantFuncs: 0x7E0000, }, "dev_null_error": { dev: os.DevNull, syscallImpl: getSyscallFuncImpl(0x00), wantErr: " : /dev/null: no such file", }, "query_funcs_error": { dev: dev, syscallImpl: getSyscallFuncImpl(0x01), wantErr: "Querying functionality failed with syscall.Errno operation not permitted", wantFile: true, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange d, msc := initTestI2cDeviceWithMockedSys() d.location = tc.dev msc.Impl = tc.syscallImpl // act err := d.queryFunctionality(tc.requested, "test"+name) // assert if tc.wantErr != "" { require.ErrorContains(t, err, tc.wantErr) } else { require.NoError(t, err) } if tc.wantFile { assert.NotNil(t, d.file) } else { assert.Equal(t, (*MockFile)(nil), d.file) } assert.Equal(t, tc.wantFuncs, d.funcs) }) } } ================================================ FILE: system/onewiredevice_sysfs.go ================================================ package system import ( "fmt" "path" ) type onewireDeviceSysfs struct { id string sysfsPath string sfa *sysfsFileAccess } func newOneWireDeviceSysfs(sfa *sysfsFileAccess, id string) *onewireDeviceSysfs { p := &onewireDeviceSysfs{ id: id, sysfsPath: path.Join("/sys/bus/w1/devices", id), sfa: sfa, } return p } // ID returns the device id in the form "family code"-"serial number". Implements gobot.OneWireSystemDevicer. func (o *onewireDeviceSysfs) ID() string { return o.id } // ReadData reads from the sysfs path specified by the command. Implements gobot.OneWireSystemDevicer. func (o *onewireDeviceSysfs) ReadData(command string, data []byte) error { p := path.Join(o.sysfsPath, command) buf, err := o.sfa.read(p) if err != nil { return err } copy(data, buf) if len(buf) < len(data) { return fmt.Errorf("count of read bytes (%d) is smaller than expected (%d)", len(buf), len(data)) } return nil } // WriteData writes to the path specified by the command. Implements gobot.OneWireSystemDevicer. func (o *onewireDeviceSysfs) WriteData(command string, data []byte) error { p := path.Join(o.sysfsPath, command) return o.sfa.write(p, data) } // ReadInteger reads an integer value from the device. Implements gobot.OneWireSystemDevicer. func (o *onewireDeviceSysfs) ReadInteger(command string) (int, error) { p := path.Join(o.sysfsPath, command) return o.sfa.readInteger(p) } // WriteInteger writes an integer value to the device. Implements gobot.OneWireSystemDevicer. func (o *onewireDeviceSysfs) WriteInteger(command string, val int) error { p := path.Join(o.sysfsPath, command) return o.sfa.writeInteger(p, val) } // Close the 1-wire connection. Implements gobot.OneWireSystemDevicer. func (o *onewireDeviceSysfs) Close() error { // currently nothing to do here - the file descriptors will be closed immediately after read/write return nil } ================================================ FILE: system/onewiredevice_sysfs_test.go ================================================ package system import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func Test_newOneWireDeviceSysfs(t *testing.T) { // arrange m := &MockFilesystem{} sfa := sysfsFileAccess{fs: m, readBufLen: 2} const id = "0815" // act d := newOneWireDeviceSysfs(&sfa, id) // assert assert.Equal(t, "/sys/bus/w1/devices/"+id, d.sysfsPath) assert.Equal(t, &sfa, d.sfa) assert.Equal(t, id, d.ID()) } func TestOneWireDeviceReadData(t *testing.T) { // arrange const ( id = "0816" command = "getValue" path = "/sys/bus/w1/devices/" + id + "/" + command content = "234" countBytesRead = 3 ) fs := newMockFilesystem([]string{path}) sfa := sysfsFileAccess{fs: fs, readBufLen: countBytesRead} d := newOneWireDeviceSysfs(&sfa, id) fs.Files[path].Contents = content data := []byte{1, 1, 1} // act err := d.ReadData(command, data) // assert require.NoError(t, err) assert.Equal(t, []byte(content), data) } func TestOneWireDeviceWriteData(t *testing.T) { // arrange const ( id = "0817" command = "putValue" path = "/sys/bus/w1/devices/" + id + "/" + command ) fs := newMockFilesystem([]string{path}) sfa := sysfsFileAccess{fs: fs} d := newOneWireDeviceSysfs(&sfa, id) fs.Files[path].Contents = "old content" data := []byte{1, 2, 3} // act err := d.WriteData(command, data) // assert require.NoError(t, err) assert.Equal(t, data, []byte(fs.Files[path].Contents)) } func TestOneWireDeviceReadInteger(t *testing.T) { // arrange const ( id = "0818" command = "getIntegerValue" path = "/sys/bus/w1/devices/" + id + "/" + command content = "23456" countBytesRead = 4 want = 2345 // limited by readBufLen ) fs := newMockFilesystem([]string{path}) sfa := sysfsFileAccess{fs: fs, readBufLen: countBytesRead} d := newOneWireDeviceSysfs(&sfa, id) fs.Files[path].Contents = content // act got, err := d.ReadInteger(command) // assert require.NoError(t, err) assert.Equal(t, want, got) } func TestOneWireDeviceWriteInteger(t *testing.T) { // arrange const ( id = "0818" command = "getIntegerValue" path = "/sys/bus/w1/devices/" + id + "/" + command write = 155 ) fs := newMockFilesystem([]string{path}) sfa := sysfsFileAccess{fs: fs} d := newOneWireDeviceSysfs(&sfa, id) fs.Files[path].Contents = "old content" // act err := d.WriteInteger(command, write) // assert require.NoError(t, err) assert.Equal(t, strconv.Itoa(write), fs.Files[path].Contents) } ================================================ FILE: system/pwmpin_sysfs.go ================================================ package system import ( "bytes" "errors" "fmt" "os" "path" "strconv" "time" ) const pwmDebug = false const ( pwmPinErrorPattern = "%s() failed for id %s with %v" //nolint:gosec // false positive pwmPinSetErrorPattern = "%s(%v) failed for id %s with %v" //nolint:gosec // false positive ) // pwmPinSysFs represents a PWM pin type pwmPinSysFs struct { path string pin string polarityNormalIdentifier string polarityInvertedIdentifier string sfa *sysfsFileAccess } // newPWMPinSysfs returns a new pwmPin, working with sysfs file access. func newPWMPinSysfs(sfa *sysfsFileAccess, path string, pin int, polNormIdent string, polInvIdent string) *pwmPinSysFs { p := &pwmPinSysFs{ path: path, pin: strconv.Itoa(pin), polarityNormalIdentifier: polNormIdent, polarityInvertedIdentifier: polInvIdent, sfa: sfa, } return p } // Export exports the pin for use by the operating system by writing the pin to the "Export" path func (p *pwmPinSysFs) Export() error { if err := p.sfa.write(p.pwmExportPath(), []byte(p.pin)); err != nil { // If EBUSY then the pin has already been exported, we suppress the error var pathError *os.PathError if !errors.As(err, &pathError) || !errors.Is(err, Syscall_EBUSY) { return fmt.Errorf(pwmPinErrorPattern, "Export", p.pin, err) } } // Pause to avoid race condition in case there is any udev rule // that changes file permissions on newly exported PWMPin. This // is a common circumstance when running as a non-root user. time.Sleep(100 * time.Millisecond) return nil } // Unexport releases the pin from the operating system by writing the pin to the "Unexport" path func (p *pwmPinSysFs) Unexport() error { if err := p.sfa.write(p.pwmUnexportPath(), []byte(p.pin)); err != nil { return fmt.Errorf(pwmPinErrorPattern, "Unexport", p.pin, err) } return nil } // Enabled reads and returns the enabled state of the pin func (p *pwmPinSysFs) Enabled() (bool, error) { val, err := p.sfa.readInteger(p.pwmEnablePath()) if err != nil { return false, fmt.Errorf(pwmPinErrorPattern, "Enabled", p.pin, err) } return val > 0, nil } // SetEnabled writes enable(1) or disable(0) status. For most platforms this is only possible if period was // already set to > 0. Regardless of setting to enable or disable, a "write error: Invalid argument" will occur. func (p *pwmPinSysFs) SetEnabled(enable bool) error { enableVal := 0 if enable { enableVal = 1 } if err := p.sfa.writeInteger(p.pwmEnablePath(), enableVal); err != nil { if pwmDebug { p.printState() } return fmt.Errorf(pwmPinSetErrorPattern, "SetEnabled", enable, p.pin, err) } return nil } // Polarity reads and returns false if the polarity is inverted, otherwise true func (p *pwmPinSysFs) Polarity() (bool, error) { buf, err := p.sfa.read(p.pwmPolarityPath()) if err != nil { return true, fmt.Errorf(pwmPinErrorPattern, "Polarity", p.pin, err) } if len(buf) == 0 { return true, nil } ps := string(bytes.TrimRight(buf, "\n")) if ps == p.polarityNormalIdentifier { return true, nil } if ps == p.polarityInvertedIdentifier { return false, nil } return true, fmt.Errorf("unknown value (%s) in Polarity", ps) } // SetPolarity writes the polarity as normal if called with true and as inverted if called with false func (p *pwmPinSysFs) SetPolarity(normal bool) error { enabled, _ := p.Enabled() if enabled { return fmt.Errorf("cannot set PWM polarity when enabled") } value := p.polarityNormalIdentifier if !normal { value = p.polarityInvertedIdentifier } if err := p.sfa.write(p.pwmPolarityPath(), []byte(value)); err != nil { if pwmDebug { p.printState() } return fmt.Errorf(pwmPinSetErrorPattern, "SetPolarity", value, p.pin, err) } return nil } // Period returns the current period in nanoseconds func (p *pwmPinSysFs) Period() (uint32, error) { val, err := p.sfa.readInteger(p.pwmPeriodPath()) if err != nil { return 0, fmt.Errorf(pwmPinErrorPattern, "Period", p.pin, err) } //nolint:gosec // TODO: fix later return uint32(val), nil } // SetPeriod writes the current period in nanoseconds func (p *pwmPinSysFs) SetPeriod(period uint32) error { if err := p.sfa.writeInteger(p.pwmPeriodPath(), int(period)); err != nil { if pwmDebug { p.printState() } return fmt.Errorf(pwmPinSetErrorPattern, "SetPeriod", period, p.pin, err) } return nil } // DutyCycle reads and returns the duty cycle in nanoseconds func (p *pwmPinSysFs) DutyCycle() (uint32, error) { val, err := p.sfa.readInteger(p.pwmDutyCyclePath()) if err != nil { return 0, fmt.Errorf(pwmPinErrorPattern, "DutyCycle", p.pin, err) } //nolint:gosec // TODO: fix later return uint32(val), err } // SetDutyCycle writes the duty cycle in nanoseconds func (p *pwmPinSysFs) SetDutyCycle(duty uint32) error { if err := p.sfa.writeInteger(p.pwmDutyCyclePath(), int(duty)); err != nil { if pwmDebug { p.printState() } return fmt.Errorf(pwmPinSetErrorPattern, "SetDutyCycle", duty, p.pin, err) } return nil } // pwmExportPath returns export path func (p *pwmPinSysFs) pwmExportPath() string { return path.Join(p.path, "export") } // pwmUnexportPath returns unexport path func (p *pwmPinSysFs) pwmUnexportPath() string { return path.Join(p.path, "unexport") } // pwmDutyCyclePath returns duty_cycle path for specified pin func (p *pwmPinSysFs) pwmDutyCyclePath() string { return path.Join(p.path, "pwm"+p.pin, "duty_cycle") } // pwmPeriodPath returns period path for specified pin func (p *pwmPinSysFs) pwmPeriodPath() string { return path.Join(p.path, "pwm"+p.pin, "period") } // pwmEnablePath returns enable path for specified pin func (p *pwmPinSysFs) pwmEnablePath() string { return path.Join(p.path, "pwm"+p.pin, "enable") } // pwmPolarityPath returns polarity path for specified pin func (p *pwmPinSysFs) pwmPolarityPath() string { return path.Join(p.path, "pwm"+p.pin, "polarity") } func (p *pwmPinSysFs) printState() { enabled, _ := p.Enabled() polarity, _ := p.Polarity() period, _ := p.Period() duty, _ := p.DutyCycle() fmt.Println("Print state of all PWM variables...") fmt.Printf("Enable: %v, ", enabled) fmt.Printf("Polarity: %v, ", polarity) fmt.Printf("Period: %v, ", period) fmt.Printf("DutyCycle: %v, ", duty) var powerPercent float64 if enabled { if polarity { powerPercent = float64(duty) / float64(period) * 100 } else { powerPercent = float64(period) / float64(duty) * 100 } } fmt.Printf("Power: %.1f\n", powerPercent) } ================================================ FILE: system/pwmpin_sysfs_test.go ================================================ package system import ( "os" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gobot.io/x/gobot/v2" ) var _ gobot.PWMPinner = (*pwmPinSysFs)(nil) const ( normal = "normal" inverted = "inversed" ) func initTestPWMPinSysFsWithMockedFilesystem(mockPaths []string) (*pwmPinSysFs, *MockFilesystem) { fs := newMockFilesystem(mockPaths) sfa := &sysfsFileAccess{fs: fs, readBufLen: 200} pin := newPWMPinSysfs(sfa, "/sys/class/pwm/pwmchip0", 10, normal, inverted) return pin, fs } func TestPwmPin(t *testing.T) { mockedPaths := []string{ "/sys/class/pwm/pwmchip0/export", "/sys/class/pwm/pwmchip0/unexport", "/sys/class/pwm/pwmchip0/pwm10/enable", "/sys/class/pwm/pwmchip0/pwm10/period", "/sys/class/pwm/pwmchip0/pwm10/duty_cycle", "/sys/class/pwm/pwmchip0/pwm10/polarity", } pin, fs := initTestPWMPinSysFsWithMockedFilesystem(mockedPaths) assert.Equal(t, "10", pin.pin) err := pin.Unexport() require.NoError(t, err) assert.Equal(t, "10", fs.Files["/sys/class/pwm/pwmchip0/unexport"].Contents) err = pin.Export() require.NoError(t, err) assert.Equal(t, "10", fs.Files["/sys/class/pwm/pwmchip0/export"].Contents) require.NoError(t, pin.SetPolarity(false)) assert.Equal(t, inverted, fs.Files["/sys/class/pwm/pwmchip0/pwm10/polarity"].Contents) pol, _ := pin.Polarity() assert.False(t, pol) require.NoError(t, pin.SetPolarity(true)) assert.Equal(t, normal, fs.Files["/sys/class/pwm/pwmchip0/pwm10/polarity"].Contents) pol, _ = pin.Polarity() assert.True(t, pol) assert.NotEqual(t, "1", fs.Files["/sys/class/pwm/pwmchip0/pwm10/enable"].Contents) err = pin.SetEnabled(true) require.NoError(t, err) assert.Equal(t, "1", fs.Files["/sys/class/pwm/pwmchip0/pwm10/enable"].Contents) err = pin.SetPolarity(true) require.ErrorContains(t, err, "cannot set PWM polarity when enabled") fs.Files["/sys/class/pwm/pwmchip0/pwm10/period"].Contents = "6" data, _ := pin.Period() assert.Equal(t, uint32(6), data) require.NoError(t, pin.SetPeriod(100000)) data, _ = pin.Period() assert.Equal(t, uint32(100000), data) assert.NotEqual(t, "1", fs.Files["/sys/class/pwm/pwmchip0/pwm10/duty_cycle"].Contents) err = pin.SetDutyCycle(100) require.NoError(t, err) assert.Equal(t, "100", fs.Files["/sys/class/pwm/pwmchip0/pwm10/duty_cycle"].Contents) data, _ = pin.DutyCycle() assert.Equal(t, uint32(100), data) } func TestPwmPinAlreadyExported(t *testing.T) { // arrange mockedPaths := []string{ "/sys/class/pwm/pwmchip0/export", "/sys/class/pwm/pwmchip0/unexport", "/sys/class/pwm/pwmchip0/pwm10/enable", "/sys/class/pwm/pwmchip0/pwm10/period", "/sys/class/pwm/pwmchip0/pwm10/duty_cycle", } pin, fs := initTestPWMPinSysFsWithMockedFilesystem(mockedPaths) fs.Files["/sys/class/pwm/pwmchip0/export"].simulateWriteError = &os.PathError{Err: Syscall_EBUSY} // act & assert: no error indicates that the pin was already exported require.NoError(t, pin.Export()) } func TestPwmPinExportError(t *testing.T) { // arrange mockedPaths := []string{ "/sys/class/pwm/pwmchip0/export", "/sys/class/pwm/pwmchip0/unexport", "/sys/class/pwm/pwmchip0/pwm10/enable", "/sys/class/pwm/pwmchip0/pwm10/period", "/sys/class/pwm/pwmchip0/pwm10/duty_cycle", } pin, fs := initTestPWMPinSysFsWithMockedFilesystem(mockedPaths) fs.Files["/sys/class/pwm/pwmchip0/export"].simulateWriteError = &os.PathError{Err: Syscall_EFAULT} // act err := pin.Export() // assert require.ErrorContains(t, err, "Export() failed for id 10 with : bad address") } func TestPwmPinUnxportError(t *testing.T) { // arrange mockedPaths := []string{ "/sys/class/pwm/pwmchip0/export", "/sys/class/pwm/pwmchip0/unexport", "/sys/class/pwm/pwmchip0/pwm10/enable", "/sys/class/pwm/pwmchip0/pwm10/period", "/sys/class/pwm/pwmchip0/pwm10/duty_cycle", } pin, fs := initTestPWMPinSysFsWithMockedFilesystem(mockedPaths) fs.Files["/sys/class/pwm/pwmchip0/unexport"].simulateWriteError = &os.PathError{Err: Syscall_EBUSY} // act err := pin.Unexport() // assert require.ErrorContains(t, err, "Unexport() failed for id 10 with : device or resource busy") } func TestPwmPinPeriodError(t *testing.T) { // arrange mockedPaths := []string{ "/sys/class/pwm/pwmchip0/export", "/sys/class/pwm/pwmchip0/unexport", "/sys/class/pwm/pwmchip0/pwm10/enable", "/sys/class/pwm/pwmchip0/pwm10/period", "/sys/class/pwm/pwmchip0/pwm10/duty_cycle", } pin, fs := initTestPWMPinSysFsWithMockedFilesystem(mockedPaths) fs.Files["/sys/class/pwm/pwmchip0/pwm10/period"].simulateReadError = &os.PathError{Err: Syscall_EBUSY} // act _, err := pin.Period() // assert require.ErrorContains(t, err, "Period() failed for id 10 with : device or resource busy") } func TestPwmPinPolarityError(t *testing.T) { // arrange mockedPaths := []string{ "/sys/class/pwm/pwmchip0/export", "/sys/class/pwm/pwmchip0/unexport", "/sys/class/pwm/pwmchip0/pwm10/enable", "/sys/class/pwm/pwmchip0/pwm10/period", "/sys/class/pwm/pwmchip0/pwm10/duty_cycle", "/sys/class/pwm/pwmchip0/pwm10/polarity", } pin, fs := initTestPWMPinSysFsWithMockedFilesystem(mockedPaths) fs.Files["/sys/class/pwm/pwmchip0/pwm10/polarity"].simulateReadError = &os.PathError{Err: Syscall_EBUSY} // act _, err := pin.Polarity() // assert require.ErrorContains(t, err, "Polarity() failed for id 10 with : device or resource busy") } func TestPwmPinDutyCycleError(t *testing.T) { // arrange mockedPaths := []string{ "/sys/class/pwm/pwmchip0/export", "/sys/class/pwm/pwmchip0/unexport", "/sys/class/pwm/pwmchip0/pwm10/enable", "/sys/class/pwm/pwmchip0/pwm10/period", "/sys/class/pwm/pwmchip0/pwm10/duty_cycle", } pin, fs := initTestPWMPinSysFsWithMockedFilesystem(mockedPaths) fs.Files["/sys/class/pwm/pwmchip0/pwm10/duty_cycle"].simulateReadError = &os.PathError{Err: Syscall_EBUSY} // act _, err := pin.DutyCycle() // assert require.ErrorContains(t, err, "DutyCycle() failed for id 10 with : device or resource busy") } ================================================ FILE: system/spi_gpio.go ================================================ package system import ( "fmt" "time" "github.com/hashicorp/go-multierror" "gobot.io/x/gobot/v2" ) type spiGpioConfig struct { pinProvider gobot.DigitalPinnerProvider sclkPinID string ncsPinID string sdoPinID string sdiPinID string debug bool } // spiGpio is the implementation of the SPI interface using GPIO's. type spiGpio struct { cfg spiGpioConfig // time between clock edges (i.e. half the cycle time) tclk time.Duration sclkPin gobot.DigitalPinner ncsPin gobot.DigitalPinner sdoPin gobot.DigitalPinner sdiPin gobot.DigitalPinner } // newSpiGpio creates and returns a new SPI connection based on given GPIO's. func newSpiGpio(cfg spiGpioConfig, maxSpeedHz int64) (*spiGpio, error) { spi := &spiGpio{cfg: cfg} spi.initializeTime(maxSpeedHz) return spi, spi.initializeGpios() } func (s *spiGpio) initializeTime(maxSpeedHz int64) { // maxSpeedHz is given in Hz, tclk is half the cycle time, tclk=1/(2*f), tclk[ns]=1 000 000 000/(2*maxSpeed) // but with gpio's a speed of more than ~15kHz is most likely not possible, so we limit to 10kHz if maxSpeedHz > 10000 { if s.cfg.debug { fmt.Printf("reduce SPI speed for GPIO usage to 10Khz") } maxSpeedHz = 10000 } s.tclk = time.Duration(1000000000/2/maxSpeedHz) * time.Nanosecond if s.cfg.debug { fmt.Println("clk", s.tclk) } } // TxRx uses the SPI device to send/receive data. Implements gobot.SpiSystemDevicer. func (s *spiGpio) TxRx(tx []byte, rx []byte) error { var doRx bool if rx != nil { doRx = true if len(tx) != len(rx) { return fmt.Errorf("length of tx (%d) must be the same as length of rx (%d)", len(tx), len(rx)) } } if err := s.ncsPin.Write(0); err != nil { return err } for idx, b := range tx { val, err := s.transferByte(b) if err != nil { return err } if doRx { rx[idx] = val } } return s.ncsPin.Write(1) } // Close the SPI connection. Implements gobot.SpiSystemDevicer. func (s *spiGpio) Close() error { var err error if s.sclkPin != nil { if e := s.sclkPin.Unexport(); e != nil { err = multierror.Append(err, e) } } if s.sdoPin != nil { if e := s.sdoPin.Unexport(); e != nil { err = multierror.Append(err, e) } } if s.sdiPin != nil { if e := s.sdiPin.Unexport(); e != nil { err = multierror.Append(err, e) } } if s.ncsPin != nil { if e := s.ncsPin.Unexport(); e != nil { err = multierror.Append(err, e) } } return err } func (cfg *spiGpioConfig) String() string { return fmt.Sprintf("sclk: %s, ncs: %s, sdo: %s, sdi: %s", cfg.sclkPinID, cfg.ncsPinID, cfg.sdoPinID, cfg.sdiPinID) } // transferByte simultaneously transmit and receive a byte // polarity and phase are assumed to be both 0 (CPOL=0, CPHA=0), so: // * input data is captured on rising edge of SCLK // * output data is propagated on falling edge of SCLK func (s *spiGpio) transferByte(txByte uint8) (uint8, error) { rxByte := uint8(0) bitMask := uint8(0x80) // start at MSBit for i := 0; i < 8; i++ { if err := s.sdoPin.Write(int(txByte & bitMask)); err != nil { return 0, err } time.Sleep(s.tclk) if err := s.sclkPin.Write(1); err != nil { return 0, err } v, err := s.sdiPin.Read() if err != nil { return 0, err } if v != 0 { rxByte |= bitMask } time.Sleep(s.tclk) if err := s.sclkPin.Write(0); err != nil { return 0, err } bitMask = bitMask >> 1 // next lower bit } return rxByte, nil } func (s *spiGpio) initializeGpios() error { var err error // ncs is an output, negated (currently not implemented at pin level) s.ncsPin, err = s.cfg.pinProvider.DigitalPin(s.cfg.ncsPinID) if err != nil { return err } if err := s.ncsPin.ApplyOptions(WithPinDirectionOutput(1)); err != nil { return err } // sclk is an output, CPOL = 0 s.sclkPin, err = s.cfg.pinProvider.DigitalPin(s.cfg.sclkPinID) if err != nil { return err } if err := s.sclkPin.ApplyOptions(WithPinDirectionOutput(0)); err != nil { return err } // sdi is an input s.sdiPin, err = s.cfg.pinProvider.DigitalPin(s.cfg.sdiPinID) if err != nil { return err } // sdo is an output s.sdoPin, err = s.cfg.pinProvider.DigitalPin(s.cfg.sdoPinID) if err != nil { return err } return s.sdoPin.ApplyOptions(WithPinDirectionOutput(0)) } ================================================ FILE: system/spi_gpio_test.go ================================================ package system import ( "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func Test_newSpiGpio(t *testing.T) { // arrange dpa := newMockDigitalPinAccess(nil) cfg := spiGpioConfig{ pinProvider: dpa, sclkPinID: "1", ncsPinID: "2", sdoPinID: "3", sdiPinID: "4", } // act d, err := newSpiGpio(cfg, 10001) // assert require.NoError(t, err) assert.Equal(t, cfg, d.cfg) assert.Equal(t, 50*time.Microsecond, d.tclk) assert.NotNil(t, d.sclkPin) assert.NotNil(t, d.ncsPin) assert.NotNil(t, d.sdoPin) assert.NotNil(t, d.sdiPin) assert.Equal(t, 1, dpa.AppliedOptions("", cfg.sclkPinID)) assert.Equal(t, 1, dpa.AppliedOptions("", cfg.ncsPinID)) assert.Equal(t, 1, dpa.AppliedOptions("", cfg.sdoPinID)) assert.Equal(t, 0, dpa.AppliedOptions("", cfg.sdiPinID)) // already input, so no option applied } func TestSpiGpioTxRx(t *testing.T) { // arrange dpa := newMockDigitalPinAccess(nil) cfg := spiGpioConfig{ pinProvider: dpa, sclkPinID: "1", ncsPinID: "2", sdoPinID: "3", sdiPinID: "4", } dpa.UseValues("", cfg.sdiPinID, []int{1, 0, 0, 1, 0, 1, 0, 1}) d, err := newSpiGpio(cfg, 10001) require.NoError(t, err) // act rx := []byte{0x87} err = d.TxRx([]byte{0xf1}, rx) // assert require.NoError(t, err) assert.Equal(t, []int{0, 1}, dpa.Written("", cfg.ncsPinID)) assert.Equal(t, []int{1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0}, dpa.Written("", cfg.sclkPinID)) assert.Equal(t, []int{128, 64, 32, 16, 0, 0, 0, 1}, dpa.Written("", cfg.sdoPinID)) // > 0 just means a 1 was send assert.Empty(t, dpa.Written("", cfg.sdiPinID)) assert.Equal(t, []byte{0x95}, rx) } func TestSpiGpioClose(t *testing.T) { // arrange dpa := newMockDigitalPinAccess(nil) cfg := spiGpioConfig{ pinProvider: dpa, sclkPinID: "1", ncsPinID: "2", sdoPinID: "3", sdiPinID: "4", } dpa.UseValues("", cfg.sdiPinID, []int{1, 0, 0, 1, 0, 1, 0, 1}) d, err := newSpiGpio(cfg, 10001) require.NoError(t, err) // act err = d.Close() // assert require.NoError(t, err) assert.Equal(t, -1, dpa.Exported("", cfg.sclkPinID)) assert.Equal(t, -1, dpa.Exported("", cfg.ncsPinID)) assert.Equal(t, -1, dpa.Exported("", cfg.sdoPinID)) assert.Equal(t, -1, dpa.Exported("", cfg.sdiPinID)) } ================================================ FILE: system/spi_mock.go ================================================ package system import ( "fmt" "gobot.io/x/gobot/v2" ) type MockSpiAccess struct { underlyingSpiAccess spiAccesser CreateError bool busNum int chipNum int mode int bits int maxSpeed int64 sysdev *spiMock } func newMockSpiAccess(underlyingSpiAccess spiAccesser) *MockSpiAccess { return &MockSpiAccess{underlyingSpiAccess: underlyingSpiAccess} } func (spi *MockSpiAccess) createDevice( busNum, chipNum, mode, bits int, maxSpeed int64, ) (gobot.SpiSystemDevicer, error) { spi.busNum = busNum spi.chipNum = chipNum spi.mode = mode spi.bits = bits spi.maxSpeed = maxSpeed spi.sysdev = newSpiMock(busNum, chipNum, mode, bits, maxSpeed) var err error if spi.CreateError { err = fmt.Errorf("error while create SPI connection in mock") } return spi.sysdev, err } func (spi *MockSpiAccess) isType(accesserType spiBusAccesserType) bool { return spi.underlyingSpiAccess.isType(accesserType) } func (*MockSpiAccess) isSupported() bool { return true } // SetReadError can be used to simulate a read error. func (spi *MockSpiAccess) SetReadError(val bool) { spi.sysdev.simReadErr = val } // SetWriteError can be used to simulate a write error. func (spi *MockSpiAccess) SetWriteError(val bool) { spi.sysdev.simWriteErr = val } // SetCloseError can be used to simulate a error on Close(). func (spi *MockSpiAccess) SetCloseError(val bool) { spi.sysdev.simCloseErr = val } // SetSimRead is used to set the byte stream for next read. func (spi *MockSpiAccess) SetSimRead(data []byte) { spi.sysdev.simRead = make([]byte, len(data)) copy(spi.sysdev.simRead, data) } // Written returns the byte stream which was last written. func (spi *MockSpiAccess) Written() []byte { return spi.sysdev.written } // Reset resets the last written values. func (spi *MockSpiAccess) Reset() { spi.sysdev.written = []byte{} } // spiMock is the a mock implementation, used in tests type spiMock struct { id string simReadErr bool simWriteErr bool simCloseErr bool written []byte simRead []byte } // newSpiMock creates and returns a new connection to a specific // spi device on a bus/chip using the periph.io interface. func newSpiMock(busNum, chipNum, mode, bits int, maxSpeed int64) *spiMock { return &spiMock{id: fmt.Sprintf("bu:%d, c:%d, m:%d, bi:%d, s:%d", busNum, chipNum, mode, bits, maxSpeed)} } // Close the SPI connection to the device. Implements gobot.SpiSystemDevicer. func (c *spiMock) Close() error { if c.simCloseErr { return fmt.Errorf("error while SPI close in mock") } return nil } // TxRx uses the SPI device TX to send/receive data. gobot.SpiSystemDevicer. func (c *spiMock) TxRx(tx []byte, rx []byte) error { if c.simReadErr { return fmt.Errorf("error while SPI read in mock") } c.written = append(c.written, tx...) // the answer can be one cycle behind, this must be considered in test setup copy(rx, c.simRead) return nil } ================================================ FILE: system/spi_periphio.go ================================================ package system import ( "fmt" "periph.io/x/conn/v3/physic" xspi "periph.io/x/conn/v3/spi" xsysfs "periph.io/x/host/v3/sysfs" ) // spiPeriphIo is the implementation of the SPI interface using the periph.io sysfs implementation for Linux. type spiPeriphIo struct { port xspi.PortCloser dev xspi.Conn } // newSpiPeriphIo creates and returns a new connection to a specific SPI device on a bus/chip // using the periph.io interface. func newSpiPeriphIo(busNum, chipNum, mode, bits int, maxSpeed int64) (*spiPeriphIo, error) { p, err := xsysfs.NewSPI(busNum, chipNum) if err != nil { return nil, err } c, err := p.Connect(physic.Frequency(maxSpeed)*physic.Hertz, xspi.Mode(mode), bits) if err != nil { return nil, err } return &spiPeriphIo{port: p, dev: c}, nil } // TxRx uses the SPI device TX to send/receive data. Implements gobot.SpiSystemDevicer. func (c *spiPeriphIo) TxRx(tx []byte, rx []byte) error { dataLen := len(rx) if err := c.dev.Tx(tx, rx); err != nil { return err } if len(rx) != dataLen { return fmt.Errorf("read length (%d) differ to expected (%d)", len(rx), dataLen) } return nil } // Close the SPI connection. Implements gobot.SpiSystemDevicer. func (c *spiPeriphIo) Close() error { return c.port.Close() } ================================================ FILE: system/spiaccess.go ================================================ package system import ( "gobot.io/x/gobot/v2" ) type periphioSpiAccess struct { fs filesystem } type gpioSpiAccess struct { cfg spiGpioConfig } func (psa *periphioSpiAccess) isType(accesserType spiBusAccesserType) bool { return accesserType == spiBusAccesserTypePeriphio } func (psa *periphioSpiAccess) isSupported() bool { devices, err := psa.fs.find("/dev", "spidev") if err != nil || len(devices) == 0 { return false } return true } func (*periphioSpiAccess) createDevice( busNum, chipNum, mode, bits int, maxSpeed int64, ) (gobot.SpiSystemDevicer, error) { return newSpiPeriphIo(busNum, chipNum, mode, bits, maxSpeed) } func (gsa *gpioSpiAccess) isType(accesserType spiBusAccesserType) bool { return accesserType == spiBusAccesserTypeGPIO } func (gsa *gpioSpiAccess) isSupported() bool { return true } func (gsa *gpioSpiAccess) createDevice( busNum, chipNum, mode, bits int, maxSpeed int64, ) (gobot.SpiSystemDevicer, error) { return newSpiGpio(gsa.cfg, maxSpeed) } ================================================ FILE: system/spiaccess_test.go ================================================ package system import ( "testing" "github.com/stretchr/testify/assert" ) func TestGpioSpi_isType(t *testing.T) { // arrange gsa := gpioSpiAccess{} // act & assert GPIO assert.True(t, gsa.isType(spiBusAccesserTypeGPIO)) // act & assert Periphio assert.False(t, gsa.isType(spiBusAccesserTypePeriphio)) } func TestPeriphioSpi_isType(t *testing.T) { // arrange psa := periphioSpiAccess{} // act & assert Periphio assert.True(t, psa.isType(spiBusAccesserTypePeriphio)) // act & assert GPIO assert.False(t, psa.isType(spiBusAccesserTypeGPIO)) } func TestGpioSpi_isSupported(t *testing.T) { // arrange gsa := gpioSpiAccess{} // act got := gsa.isSupported() // assert assert.True(t, got) } func TestPeriphioSpi_isSupported(t *testing.T) { tests := map[string]struct { mockPaths []string want bool }{ "supported": { mockPaths: []string{"/dev/spidev0.0", "/dev/spidev1.0"}, want: true, }, "not_supported": { mockPaths: []string{"/sys/class/gpio/"}, want: false, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange fs := newMockFilesystem(tc.mockPaths) psa := periphioSpiAccess{fs: fs} // act got := psa.isSupported() // assert assert.Equal(t, tc.want, got) }) } } ================================================ FILE: system/syscall.go ================================================ package system import ( "unsafe" "golang.org/x/sys/unix" ) // SyscallErrno wraps the "unix.Errno" type SyscallErrno unix.Errno // wrapping for used constants of unix package const ( Syscall_SYS_IOCTL = unix.SYS_IOCTL Syscall_EINVAL = unix.EINVAL Syscall_EBUSY = unix.EBUSY Syscall_EFAULT = unix.EFAULT ) // nativeSyscall represents the native Syscall type nativeSyscall struct{} // Syscall calls the native unix.Syscall, implements the SystemCaller interface // Note: It would be possible to transfer the address as an unsafe.Pointer to e.g. a byte, uint16 or integer variable. // The unpack process here would be as follows: // * convert the payload back to the pointer: addrPtr := (*byte)(payload) // * call with the content converted to uintptr: r1, r2, errNo = unix.Syscall(trap, f.Fd(), signal, uintptr(*addrPtr)) // This has the main disadvantage, that if someone change the type of the address at caller side, the compiler will not // detect this problem and this unpack procedure would cause unpredictable results. // So the decision was taken to give the address here as a separate parameter, although it is not used in every call. // Note also, that the size of the address variable at Kernel side is u16, therefore uint16 is used here. // //nolint:nonamedreturns // useful here func (sys *nativeSyscall) syscall( trap uintptr, f File, signal uintptr, payload unsafe.Pointer, address uint16, ) (r1, r2 uintptr, err SyscallErrno) { var errNo unix.Errno if signal == I2C_TARGET { // this is the setup for the address, it just needs to be converted to an uintptr, // the given payload is not used in this case, see the comment on the function r1, r2, errNo = unix.Syscall(trap, f.Fd(), signal, uintptr(address)) } else { r1, r2, errNo = unix.Syscall(trap, f.Fd(), signal, uintptr(payload)) } return r1, r2, SyscallErrno(errNo) } // Error implements the error interface. It wraps the "unix.Errno.Error()". func (e SyscallErrno) Error() string { return unix.Errno(e).Error() } ================================================ FILE: system/syscall_mock.go ================================================ package system import ( "unsafe" ) // mockSyscall represents the mock Syscall used for unit tests type mockSyscall struct { lastTrap uintptr lastFile File lastSignal uintptr devAddress uintptr smbus *i2cSmbusIoctlData sliceSize uint8 dataSlice []byte Impl func(trap, a1, a2 uintptr, a3 unsafe.Pointer) (r1, r2 uintptr, err SyscallErrno) } // Syscall calls the user defined implementation, used for tests, implements the SystemCaller interface // //nolint:nonamedreturns // useful here func (sys *mockSyscall) syscall( trap uintptr, f File, signal uintptr, payload unsafe.Pointer, address uint16, ) (r1, r2 uintptr, err SyscallErrno) { sys.lastTrap = trap // points to the used syscall (e.g. "SYS_IOCTL") sys.lastFile = f // a character device file (e.g. file to path "/dev/i2c-1") sys.lastSignal = signal // points to used function type (e.g. I2C_SMBUS, I2C_RDWR) if signal == I2C_TARGET { // this is the setup for the address, it needs to be converted to an uintptr, // the given payload is not used in this case, see the comment on the function used for production sys.devAddress = uintptr(address) } if signal == I2C_SMBUS { // set the I2C smbus data object reference to payload and fill with some data sys.smbus = (*i2cSmbusIoctlData)(payload) if sys.smbus.data != nil { sys.sliceSize = sys.retrieveSliceSize() if sys.smbus.readWrite == I2C_SMBUS_WRITE { // get the data object payload as byte slice sys.dataSlice = unsafe.Slice((*byte)(sys.smbus.data), sys.sliceSize) } if sys.smbus.readWrite == I2C_SMBUS_READ { // fill data object with data from given slice to simulate reading if sys.dataSlice != nil { slc := unsafe.Slice((*byte)(sys.smbus.data), sys.sliceSize) if sys.smbus.protocol == I2C_SMBUS_BLOCK_DATA || sys.smbus.protocol == I2C_SMBUS_I2C_BLOCK_DATA { copy(slc[1:], sys.dataSlice) } else { copy(slc, sys.dataSlice) } } } } } // call mock implementation if sys.Impl != nil { return sys.Impl(trap, f.Fd(), signal, payload) } return 0, 0, 0 } func (sys *mockSyscall) retrieveSliceSize() uint8 { switch sys.smbus.protocol { case I2C_SMBUS_BYTE: return 1 case I2C_SMBUS_BYTE_DATA: return 1 case I2C_SMBUS_WORD_DATA: return 2 default: // for I2C_SMBUS_BLOCK_DATA, I2C_SMBUS_I2C_BLOCK_DATA return *(*byte)(sys.smbus.data) + 1 // first data element contains data size } } ================================================ FILE: system/sysfsfileaccess.go ================================================ package system import ( "io" "os" "strconv" "strings" ) type sysfsFileAccess struct { fs filesystem readBufLen uint16 } // Linux sysfs / GPIO specific sysfs docs. // // https://www.kernel.org/doc/Documentation/filesystems/sysfs.txt // https://www.kernel.org/doc/Documentation/gpio/sysfs.txt // https://www.kernel.org/doc/Documentation/thermal/sysfs-api.txt // see also PWM.md type sysfsFile struct { sfa sysfsFileAccess file File sysfsPath string } func (sfa sysfsFileAccess) readInteger(path string) (int, error) { sf, err := sfa.openRead(path) defer func() { _ = sf.close() }() if err != nil { return 0, err } return sf.readInteger() } func (sfa sysfsFileAccess) read(path string) ([]byte, error) { sf, err := sfa.openRead(path) defer func() { _ = sf.close() }() if err != nil { return nil, err } return sf.read() } func (sfa sysfsFileAccess) writeInteger(path string, val int) error { sf, err := sfa.openWrite(path) defer func() { _ = sf.close() }() if err != nil { return err } return sf.writeInteger(val) } func (sfa sysfsFileAccess) write(path string, data []byte) error { sf, err := sfa.openWrite(path) defer func() { _ = sf.close() }() if err != nil { return err } return sf.write(data) } func (sfa sysfsFileAccess) openRead(path string) (*sysfsFile, error) { f, err := sfa.fs.openFile(path, os.O_RDONLY, 0o644) if err != nil { return nil, err } return &sysfsFile{sfa: sfa, file: f, sysfsPath: path}, nil } func (sfa sysfsFileAccess) openWrite(path string) (*sysfsFile, error) { f, err := sfa.fs.openFile(path, os.O_WRONLY, 0o644) if err != nil { return nil, err } return &sysfsFile{sfa: sfa, file: f, sysfsPath: path}, nil } func (sfa sysfsFileAccess) openReadWrite(path string) (*sysfsFile, error) { f, err := sfa.fs.openFile(path, os.O_RDWR, 0o644) if err != nil { return nil, err } return &sysfsFile{sfa: sfa, file: f, sysfsPath: path}, nil } func (sf *sysfsFile) close() error { if sf == nil || sf.file == nil { return nil } return sf.file.Close() } func (sf *sysfsFile) readInteger() (int, error) { buf, err := sf.read() if err != nil { return 0, err } if len(buf) == 0 { return 0, nil } return strconv.Atoi(strings.Split(string(buf), "\n")[0]) } func (sf *sysfsFile) read() ([]byte, error) { // sysfs docs say: // > If userspace seeks back to zero or does a pread(2) with an offset of '0' the [..] method will // > be called again, rearmed, to fill the buffer. // > The buffer will always be PAGE_SIZE bytes in length. On i386, this is 4096. // TODO: Examine if seek is needed if full buffer is read from sysfs file. buf := make([]byte, sf.sfa.readBufLen) if _, err := sf.file.Seek(0, io.SeekStart); err != nil { return nil, err } i, err := sf.file.Read(buf) if i == 0 { return []byte{}, err } return buf[:i], err } func (sf *sysfsFile) writeInteger(val int) error { return sf.write([]byte(strconv.Itoa(val))) } func (sf *sysfsFile) write(data []byte) error { // sysfs docs say: // > When writing sysfs files, userspace processes should first read the // > entire file, modify the values it wishes to change, then write the // > entire buffer back. // however, this seems outdated/inaccurate (docs are from back in the Kernel BitKeeper days). // Write() returns already a non-nil error when n != len(b). _, err := sf.file.Write(data) return err } ================================================ FILE: system/system.go ================================================ package system import ( "fmt" "os" "unsafe" "gobot.io/x/gobot/v2" ) type digitalPinAccesserType int const ( digitalPinAccesserTypeCdev digitalPinAccesserType = iota digitalPinAccesserTypeSysfs ) type spiBusAccesserType int const ( spiBusAccesserTypePeriphio spiBusAccesserType = iota spiBusAccesserTypeGPIO ) // A File represents basic IO interactions with the underlying file system type File interface { Write(b []byte) (n int, err error) WriteString(s string) (ret int, err error) Sync() error Read(b []byte) (n int, err error) ReadAt(b []byte, off int64) (n int, err error) Seek(offset int64, whence int) (ret int64, err error) Fd() uintptr Close() error } // filesystem is a unexposed interface to allow the switch between the native file system or a mocked implementation type filesystem interface { openFile(name string, flag int, perm os.FileMode) (file File, err error) stat(name string) (os.FileInfo, error) find(baseDir string, pattern string) (dirs []string, err error) readFile(name string) (content []byte, err error) } // systemCaller represents unexposed Syscall interface to allow the switch between native and mocked implementation // Prevent unsafe call, since go 1.15, see "Pattern 4" in: https://go101.org/article/unsafe.html // For go vet false positives, see: https://github.com/golang/go/issues/41205 type systemCaller interface { syscall( trap uintptr, f File, signal uintptr, payload unsafe.Pointer, address uint16, ) (r1, r2 uintptr, err SyscallErrno) } // digitalPinAccesser represents unexposed interface to allow the switch between different implementations and // a mocked one type digitalPinAccesser interface { isType(accesserType digitalPinAccesserType) bool isSupported() bool createPin(chip string, pin int, o ...func(gobot.DigitalPinOptioner) bool) gobot.DigitalPinner setFs(fs filesystem) } // spiAccesser represents unexposed interface to allow the switch between different implementations and a mocked one type spiAccesser interface { isType(accesserType spiBusAccesserType) bool isSupported() bool createDevice(busNum, chipNum, mode, bits int, maxSpeed int64) (gobot.SpiSystemDevicer, error) } type accesserConfiguration struct { debug bool debugSpi bool debugDigitalPin bool useGpioSysfs *bool spiGpioConfig *spiGpioConfig } // Accesser provides access to system calls, filesystem, implementation for digital pin and SPI type Accesser struct { accesserCfg *accesserConfiguration sys systemCaller fs filesystem digitalPinAccess digitalPinAccesser spiAccess spiAccesser } // NewAccesser returns a accesser to native system call, native file system and the chosen digital pin access. // Digital pin accesser can be empty or "sysfs", otherwise it will be automatically chosen. func NewAccesser(options ...AccesserOptionApplier) *Accesser { a := &Accesser{ accesserCfg: &accesserConfiguration{}, } for _, o := range options { if o == nil { continue } o.apply(a.accesserCfg) } return a } // AddAnalogSupport adds the support to access the analog features of the system, usually by sysfs. func (a *Accesser) AddAnalogSupport() { if a.fs == nil { a.fs = &nativeFilesystem{} // for sysfs access } } // AddPWMSupport adds the support to access the PWM features of the system, usually by sysfs. func (a *Accesser) AddPWMSupport() { if a.fs == nil { a.fs = &nativeFilesystem{} // for sysfs access } } // AddDigitalPinSupport adds the support to access the GPIO features of the system. Usually by character device or // sysfs Kernel API. Related options can be applied here. func (a *Accesser) AddDigitalPinSupport(options ...AccesserOptionApplier) { for _, o := range options { if o == nil { continue } o.apply(a.accesserCfg) } if a.fs == nil { a.fs = &nativeFilesystem{} // for sysfs access or check for /dev/gpiochip* in cdev } if a.accesserCfg.useGpioSysfs == nil || !*a.accesserCfg.useGpioSysfs { dpa := &cdevDigitalPinAccess{fs: a.fs} if dpa.isSupported() || a.accesserCfg.useGpioSysfs == nil { a.digitalPinAccess = dpa if a.accesserCfg.debug || a.accesserCfg.debugDigitalPin { fmt.Printf("use cdev driver for digital pins with this chips: %v\n", dpa.chips) } return } if a.accesserCfg.debug || a.accesserCfg.debugDigitalPin { fmt.Println("cdev driver not supported, fallback to sysfs driver") } } // currently sysfs is supported by all Kernels dpa := &sysfsDigitalPinAccess{sfa: &sysfsFileAccess{fs: a.fs, readBufLen: 2}} a.digitalPinAccess = dpa if a.accesserCfg.debug || a.accesserCfg.debugDigitalPin { fmt.Println("use sysfs driver for digital pins") } } // HasDigitalPinSysfsAccess returns whether the used digital pin accesser is a sysfs one. // If no digital pin accesser is defined, returns false. func (a *Accesser) HasDigitalPinSysfsAccess() bool { return a.digitalPinAccess != nil && a.digitalPinAccess.isType(digitalPinAccesserTypeSysfs) } // HasDigitalPinCdevAccess returns whether the used digital pin accesser is a sysfs one. // If no digital pin accesser is defined, returns false. func (a *Accesser) HasDigitalPinCdevAccess() bool { return a.digitalPinAccess != nil && a.digitalPinAccess.isType(digitalPinAccesserTypeCdev) } // AddI2CSupport adds the support to access the I2C features of the system, usually by syscall with character device. func (a *Accesser) AddI2CSupport() { if a.fs == nil { a.fs = &nativeFilesystem{} // for access to the i2c character device, e.g. /dev/i2c-2 } a.sys = &nativeSyscall{} } // AddSPISupport adds the support to access the SPI features of the system, usually by character device or GPIOs. // Related options can be applied here. func (a *Accesser) AddSPISupport(options ...AccesserOptionApplier) { for _, o := range options { if o == nil { continue } o.apply(a.accesserCfg) } if a.fs == nil { a.fs = &nativeFilesystem{} // to check for "/dev/spidev*" or access by GPIO (see AddDigitalPinSupport()) } if a.accesserCfg.spiGpioConfig != nil { // currently GPIO SPI access is always supported a.accesserCfg.spiGpioConfig.debug = a.accesserCfg.debugSpi a.spiAccess = &gpioSpiAccess{cfg: *a.accesserCfg.spiGpioConfig} if a.accesserCfg.debug || a.accesserCfg.debugSpi { fmt.Printf("use gpio driver for SPI with this config: %s\n", a.accesserCfg.spiGpioConfig.String()) } return } gsa := &periphioSpiAccess{fs: a.fs} if !gsa.isSupported() { if a.accesserCfg.debug || a.accesserCfg.debugSpi { fmt.Println("periphio driver not supported for SPI, please activate SPI or try to use GPIOs") } return } a.spiAccess = gsa if a.accesserCfg.debug || a.accesserCfg.debugSpi { fmt.Println("use periphio driver for SPI") } } // HasSpiPeriphioAccess returns whether the used SPI accesser is periphio based. // If SPI accesser is defined, returns false. func (a *Accesser) HasSpiPeriphioAccess() bool { return a.spiAccess != nil && a.spiAccess.isType(spiBusAccesserTypePeriphio) } // HasSpiGpioAccess returns whether the used SPI accesser is GPIO based. // If SPI accesser is defined, returns false. func (a *Accesser) HasSpiGpioAccess() bool { return a.spiAccess != nil && a.spiAccess.isType(spiBusAccesserTypeGPIO) } // AddOneWireSupport adds the support to access the one wire features of the system, usually by sysfs. func (a *Accesser) AddOneWireSupport() { if a.fs == nil { a.fs = &nativeFilesystem{} // for sysfs access } } // UseMockDigitalPinAccess sets the digital pin handler accesser to the chosen one. Used only for tests. func (a *Accesser) UseMockDigitalPinAccess() *mockDigitalPinAccess { dpa := newMockDigitalPinAccess(a.digitalPinAccess) a.digitalPinAccess = dpa return dpa } // UseMockSyscall sets the Syscall implementation of the accesser to the mocked one. Used only for tests. func (a *Accesser) UseMockSyscall() *mockSyscall { msc := &mockSyscall{} a.sys = msc return msc } // UseMockFilesystem sets the filesystem implementation of the accesser to the mocked one. Used only for tests. func (a *Accesser) UseMockFilesystem(files []string) *MockFilesystem { fs := newMockFilesystem(files) a.fs = fs if a.digitalPinAccess != nil { a.digitalPinAccess.setFs(fs) } return fs } // UseMockSpi sets the SPI implementation of the accesser to the mocked one. Used only for tests. func (a *Accesser) UseMockSpi() *MockSpiAccess { msc := newMockSpiAccess(a.spiAccess) a.spiAccess = msc return msc } // NewDigitalPin returns a new system digital pin, according to the given pin number. func (a *Accesser) NewDigitalPin(chip string, pin int, options ...func(gobot.DigitalPinOptioner) bool, ) gobot.DigitalPinner { return a.digitalPinAccess.createPin(chip, pin, options...) } // NewPWMPin returns a new system PWM pin, according to the given pin number. func (a *Accesser) NewPWMPin(path string, pin int, polNormIdent string, polInvIdent string) gobot.PWMPinner { sfa := &sysfsFileAccess{fs: a.fs, readBufLen: 200} return newPWMPinSysfs(sfa, path, pin, polNormIdent, polInvIdent) } func (a *Accesser) NewAnalogPin(path string, w bool, readBufLen uint16) gobot.AnalogPinner { r := readBufLen > 0 if readBufLen == 0 { readBufLen = 32 // max. count of characters for int value is 20 } return newAnalogPinSysfs(&sysfsFileAccess{fs: a.fs, readBufLen: readBufLen}, path, r, w) } // NewSpiDevice returns a new connection to SPI with the given parameters. func (a *Accesser) NewSpiDevice(busNum, chipNum, mode, bits int, maxSpeed int64) (gobot.SpiSystemDevicer, error) { return a.spiAccess.createDevice(busNum, chipNum, mode, bits, maxSpeed) } // NewOneWireDevice returns a new 1-wire device with the given parameters. // note: this is a basic implementation without using the possibilities of bus controller // it depends on automatic device search, see https://www.kernel.org/doc/Documentation/w1/w1.generic func (a *Accesser) NewOneWireDevice(familyCode byte, serialNumber uint64) (gobot.OneWireSystemDevicer, error) { sfa := &sysfsFileAccess{fs: a.fs, readBufLen: 200} deviceID := fmt.Sprintf("%02x-%012x", familyCode, serialNumber) return newOneWireDeviceSysfs(sfa, deviceID), nil } // OpenFile opens file of given name from native or the mocked file system func (a *Accesser) OpenFile(name string, flag int, perm os.FileMode) (File, error) { return a.fs.openFile(name, flag, perm) } // Stat returns a generic FileInfo, if the file with given name exists. It uses the native or the mocked file system. func (a *Accesser) Stat(name string) (os.FileInfo, error) { return a.fs.stat(name) } // Find finds file from native or the mocked file system func (a *Accesser) Find(baseDir string, pattern string) ([]string, error) { return a.fs.find(baseDir, pattern) } // ReadFile reads the named file and returns the contents. A successful call returns err == nil, not err == EOF. // Because ReadFile reads the whole file, it does not treat an EOF from Read as an error to be reported. func (a *Accesser) ReadFile(name string) ([]byte, error) { return a.fs.readFile(name) } ================================================ FILE: system/system_test.go ================================================ package system import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestNewAccesser(t *testing.T) { // arrange & act a := NewAccesser() // assert assert.NotNil(t, a) assert.NotNil(t, a.accesserCfg) assert.Nil(t, a.sys) assert.Nil(t, a.fs) assert.Nil(t, a.digitalPinAccess) assert.Nil(t, a.spiAccess) } func TestAccesserAddAnalogSupport(t *testing.T) { // arrange a := NewAccesser() // act a.AddAnalogSupport() // assert assert.Nil(t, a.sys) assert.Nil(t, a.digitalPinAccess) assert.Nil(t, a.spiAccess) require.NotNil(t, a.fs) assert.IsType(t, &nativeFilesystem{}, a.fs) } func TestAccesserAddPWMSupport(t *testing.T) { // arrange a := NewAccesser() // act a.AddPWMSupport() // assert assert.Nil(t, a.sys) assert.Nil(t, a.digitalPinAccess) assert.Nil(t, a.spiAccess) require.NotNil(t, a.fs) assert.IsType(t, &nativeFilesystem{}, a.fs) } func TestAccesserAddDigitalPinSupport(t *testing.T) { // arrange a := NewAccesser() // act a.AddDigitalPinSupport() // assert assert.Nil(t, a.sys) assert.Nil(t, a.spiAccess) require.NotNil(t, a.fs) assert.IsType(t, &nativeFilesystem{}, a.fs) require.NotNil(t, a.digitalPinAccess) assert.IsType(t, &cdevDigitalPinAccess{}, a.digitalPinAccess) } func TestAccesserAddI2CSupport(t *testing.T) { // assert a := NewAccesser() // act a.AddI2CSupport() // assert assert.Nil(t, a.digitalPinAccess) assert.Nil(t, a.spiAccess) require.NotNil(t, a.fs) assert.IsType(t, &nativeFilesystem{}, a.fs) require.NotNil(t, a.sys) assert.IsType(t, &nativeSyscall{}, a.sys) } func TestAccesserAddSPISupport(t *testing.T) { // arrange a := NewAccesser() // act a.AddSPISupport() // this writes a message, but we need this test case to assert a.fs // assert assert.Nil(t, a.sys) assert.Nil(t, a.digitalPinAccess) require.NotNil(t, a.fs) assert.IsType(t, &nativeFilesystem{}, a.fs) // arrange for periphio needed a.UseMockFilesystem([]string{"/dev/spidev"}) // act for apply periphio a.AddSPISupport() // assert require.NotNil(t, a.spiAccess) assert.IsType(t, &periphioSpiAccess{}, a.spiAccess) } func TestAccesserAddOneWireSupport(t *testing.T) { // arrange a := NewAccesser() // act a.AddOneWireSupport() // assert assert.Nil(t, a.sys) assert.Nil(t, a.digitalPinAccess) assert.Nil(t, a.spiAccess) require.NotNil(t, a.fs) assert.IsType(t, &nativeFilesystem{}, a.fs) } func TestAccesserNewDigitalPin(t *testing.T) { // arrange const ( chip = "14" line = 13 ) a := NewAccesser() dpa := a.UseMockDigitalPinAccess() // act dp := a.NewDigitalPin(chip, line) // assert assert.Len(t, dpa.pins, 1) assert.IsType(t, &digitalPinMock{}, dp) myPin := dpa.pins["14_13"] assert.Same(t, myPin, dp) assert.Equal(t, chip, myPin.chip) assert.Equal(t, line, myPin.pin) } //nolint:forcetypeassert // ok for this test func TestAccesserNewPWMPin(t *testing.T) { // arrange const ( path = "path" pin = 12 polNormIdent = "norm" polInvIdent = "inv" ) a := NewAccesser() // act pp := a.NewPWMPin(path, pin, polNormIdent, polInvIdent) // assert assert.IsType(t, &pwmPinSysFs{}, pp) assert.Equal(t, path, pp.(*pwmPinSysFs).path) assert.Equal(t, strconv.Itoa(pin), pp.(*pwmPinSysFs).pin) assert.Equal(t, polNormIdent, pp.(*pwmPinSysFs).polarityNormalIdentifier) assert.Equal(t, polInvIdent, pp.(*pwmPinSysFs).polarityInvertedIdentifier) } //nolint:forcetypeassert // ok for this test func TestAccesserNewAnalogPin(t *testing.T) { // arrange const ( path = "path" w = true readBufLen = 123 ) a := NewAccesser() // act ap := a.NewAnalogPin(path, w, readBufLen) // assert assert.IsType(t, &analogPinSysFs{}, ap) assert.Equal(t, path, ap.(*analogPinSysFs).sysfsPath) assert.True(t, ap.(*analogPinSysFs).r) assert.True(t, ap.(*analogPinSysFs).w) assert.IsType(t, &sysfsFileAccess{}, ap.(*analogPinSysFs).sfa) } func TestAccesserNewSpiDevice(t *testing.T) { // arrange const ( busNum = 15 chipNum = 14 mode = 13 bits = 12 maxSpeed = int64(11) ) a := NewAccesser() spi := a.UseMockSpi() // act con, err := a.NewSpiDevice(busNum, chipNum, mode, bits, maxSpeed) // assert require.NoError(t, err) assert.NotNil(t, con) assert.Equal(t, busNum, spi.busNum) assert.Equal(t, chipNum, spi.chipNum) assert.Equal(t, mode, spi.mode) assert.Equal(t, bits, spi.bits) assert.Equal(t, maxSpeed, spi.maxSpeed) } //nolint:forcetypeassert // ok for this test func TestAccesserNewOneWireDevice(t *testing.T) { // arrange const ( familyCode = 255 serialNumber = 12345678987654321 wantID = "ff-2bdc546291f4b1" ) a := NewAccesser() // act con, err := a.NewOneWireDevice(familyCode, serialNumber) // assert require.NoError(t, err) assert.IsType(t, &onewireDeviceSysfs{}, con) assert.Equal(t, wantID, con.(*onewireDeviceSysfs).id) assert.Equal(t, "/sys/bus/w1/devices/"+wantID, con.(*onewireDeviceSysfs).sysfsPath) assert.IsType(t, &sysfsFileAccess{}, con.(*onewireDeviceSysfs).sfa) } ================================================ FILE: system/systemoptions.go ================================================ package system import ( "gobot.io/x/gobot/v2" ) // accesserOptionApplier is the interface for system options. This provides the possibility for change the systems // behavior by the caller/user when creating the system access, e.g. by "NewAccesser().Add..". // The interface needs to be implemented by each configurable option type. type AccesserOptionApplier interface { apply(cfg *accesserConfiguration) } type systemAccesserDebugOption bool type systemDigitalPinDebugOption bool type systemSpiDebugOption bool type systemUseDigitalPinSysfsOption bool type systemUseSpiGpioOption spiGpioConfig // WithSystemAccesserDebug can be used to switch on debug messages. func WithSystemAccesserDebug() systemAccesserDebugOption { return systemAccesserDebugOption(true) } // WithDigitalPinDebug can be used to switch on debug messages for digital pins. func WithDigitalPinDebug() systemDigitalPinDebugOption { return systemDigitalPinDebugOption(true) } // WithSpiDebug can be used to switch on debug messages for SPI. func WithSpiDebug() systemSpiDebugOption { return systemSpiDebugOption(true) } // WithDigitalPinSysfsAccess can be used to change the default character device implementation for digital pins to the // legacy sysfs Kernel ABI. func WithDigitalPinSysfsAccess() systemUseDigitalPinSysfsOption { return systemUseDigitalPinSysfsOption(true) } // WithDigitalPinCdevAccess can be used to change the default sysfs implementation for digital pins in old platforms to // test the character device Kernel ABI. The access is provided by the go-gpiocdev package. func WithDigitalPinCdevAccess() systemUseDigitalPinSysfsOption { return systemUseDigitalPinSysfsOption(false) } // WithSpiGpioAccess can be used to switch the default SPI implementation to GPIO usage. func WithSpiGpioAccess(p gobot.DigitalPinnerProvider, sclkPin, ncsPin, sdoPin, sdiPin string) systemUseSpiGpioOption { o := systemUseSpiGpioOption{ pinProvider: p, sclkPinID: sclkPin, ncsPinID: ncsPin, sdoPinID: sdoPin, sdiPinID: sdiPin, } return o } func (o systemAccesserDebugOption) String() string { return "switch on system accesser debugging option" } func (o systemDigitalPinDebugOption) String() string { return "switch on system digital pin debugging option" } func (o systemSpiDebugOption) String() string { return "switch on system SPI debugging option" } func (o systemUseDigitalPinSysfsOption) String() string { return "system accesser use sysfs vs. cdev for digital pins option" } func (o systemUseSpiGpioOption) String() string { return "system accesser use discrete GPIOs for SPI option" } func (o systemAccesserDebugOption) apply(cfg *accesserConfiguration) { cfg.debug = bool(o) } func (o systemDigitalPinDebugOption) apply(cfg *accesserConfiguration) { cfg.debugDigitalPin = bool(o) } func (o systemSpiDebugOption) apply(cfg *accesserConfiguration) { cfg.debugSpi = bool(o) } func (o systemUseDigitalPinSysfsOption) apply(cfg *accesserConfiguration) { c := bool(o) cfg.useGpioSysfs = &c } func (o systemUseSpiGpioOption) apply(cfg *accesserConfiguration) { c := spiGpioConfig(o) cfg.spiGpioConfig = &c } ================================================ FILE: system/systemoptions_test.go ================================================ //nolint:forcetypeassert // ok here package system import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestWithDigitalPinOptionAccess_HasDigitalPinCdevAccess_HasDigitalPinSysfsAccess(t *testing.T) { // note: default accesser already tested on tests with AddDigitalPinSupport() tests := map[string]struct { initialAccesser digitalPinAccesser option AccesserOptionApplier wantCdev bool }{ "with_cdev": { initialAccesser: &sysfsDigitalPinAccess{}, option: WithDigitalPinCdevAccess(), wantCdev: true, }, "with_sysfs": { initialAccesser: &cdevDigitalPinAccess{}, option: WithDigitalPinSysfsAccess(), wantCdev: false, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange a := NewAccesser() a.digitalPinAccess = tc.initialAccesser a.AddDigitalPinSupport(tc.option) // act gotCdev := a.HasDigitalPinCdevAccess() gotSysfs := a.HasDigitalPinSysfsAccess() // assert if tc.wantCdev { assert.True(t, gotCdev) assert.False(t, gotSysfs) assert.IsType(t, &cdevDigitalPinAccess{}, a.digitalPinAccess) assert.IsType(t, &nativeFilesystem{}, a.digitalPinAccess.(*cdevDigitalPinAccess).fs) } else { assert.False(t, gotCdev) assert.True(t, gotSysfs) assert.IsType(t, &sysfsDigitalPinAccess{}, a.digitalPinAccess) assert.IsType(t, &nativeFilesystem{}, a.digitalPinAccess.(*sysfsDigitalPinAccess).sfa.fs) } }) } } func TestWithSpiOptionAccess_HasSpiPeriphioAccess_HasSpiGpioAccess(t *testing.T) { // note: default accesser already tested on tests with AddSPISupport() tests := map[string]struct { initialAccesser spiAccesser option AccesserOptionApplier wantPeriphio bool }{ "with_periphio": { initialAccesser: &gpioSpiAccess{}, wantPeriphio: true, }, "withr_sysfs": { initialAccesser: &periphioSpiAccess{}, option: WithSpiGpioAccess(nil, "2", "3", "4", "5"), wantPeriphio: false, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { // arrange a := NewAccesser() a.spiAccess = tc.initialAccesser // arrange for periphio needed a.UseMockFilesystem([]string{"/dev/spidev"}) a.AddDigitalPinSupport() a.AddSPISupport(tc.option) // act gotPeriphio := a.HasSpiPeriphioAccess() gotGpio := a.HasSpiGpioAccess() // assert require.NotNil(t, a.spiAccess) if tc.wantPeriphio { assert.True(t, gotPeriphio) assert.False(t, gotGpio) assert.IsType(t, &periphioSpiAccess{}, a.spiAccess) } else { assert.False(t, gotPeriphio) assert.True(t, gotGpio) assert.IsType(t, &gpioSpiAccess{}, a.spiAccess) } }) } } ================================================ FILE: utils.go ================================================ package gobot import ( "crypto/rand" "fmt" "math" "math/big" "time" ) // Every triggers f every t time.Duration until the end of days, or when a Stop() // is called on the Ticker that is returned by the Every function. // It does not wait for the previous execution of f to finish before // it fires the next f. func Every(t time.Duration, f func()) *time.Ticker { ticker := time.NewTicker(t) go func() { for { <-ticker.C f() } }() return ticker } // After triggers f after t duration. func After(t time.Duration, f func()) { time.AfterFunc(t, f) } // Rand returns a positive random int up to maximum func Rand(maximum int) int { i, _ := rand.Int(rand.Reader, big.NewInt(int64(maximum))) return int(i.Int64()) } // FromScale returns a converted input from minimum, maximum to 0.0...1.0. func FromScale(input, minimum, maximum float64) float64 { return (input - math.Min(minimum, maximum)) / (math.Max(minimum, maximum) - math.Min(minimum, maximum)) } // ToScale returns a converted input from 0...1 to minimum...maximum scale. // If input is less than minimum then ToScale returns minimum. // If input is greater than maximum then ToScale returns maximum func ToScale(input, minimum, maximum float64) float64 { i := input*(math.Max(minimum, maximum)-math.Min(minimum, maximum)) + math.Min(minimum, maximum) switch { case i < math.Min(minimum, maximum): return math.Min(minimum, maximum) case i > math.Max(minimum, maximum): return math.Max(minimum, maximum) default: return i } } // Rescale performs a direct linear rescaling of a number from one scale to another. func Rescale(input, fromMin, fromMax, toMin, toMax float64) float64 { return (input-fromMin)*(toMax-toMin)/(fromMax-fromMin) + toMin } // DefaultName returns a sensible random default name // for a robot, adaptor or driver func DefaultName(name string) string { return fmt.Sprintf("%s-%X", name, Rand(int(^uint(0)>>1))) } ================================================ FILE: utils_test.go ================================================ package gobot import ( "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestEvery(t *testing.T) { i := 0 begin := time.Now() sem := make(chan time.Time, 1) Every(2*time.Millisecond, func() { i++ if i == 2 { sem <- time.Now() } }) <-sem if time.Since(begin) < 4*time.Millisecond { t.Error("Test should have taken at least 4 milliseconds") } } func TestEveryWhenStopped(t *testing.T) { sem := make(chan bool) done := Every(100*time.Millisecond, func() { sem <- true }) select { case <-sem: done.Stop() case <-time.After(190 * time.Millisecond): done.Stop() require.Fail(t, "Every was not called") } select { case <-time.After(190 * time.Millisecond): case <-sem: t.Error("Every should have stopped") } } func TestAfter(t *testing.T) { i := 0 sem := make(chan bool) After(100*time.Millisecond, func() { i++ sem <- true }) select { case <-sem: case <-time.After(190 * time.Millisecond): require.Fail(t, "After was not called") } assert.Equal(t, 1, i) } func TestFromScale(t *testing.T) { assert.InDelta(t, 0.5, FromScale(5, 0, 10), 0.0) } func TestToScale(t *testing.T) { assert.InDelta(t, 10.0, ToScale(500, 0, 10), 0.0) assert.InDelta(t, 0.0, ToScale(-1, 0, 10), 0.0) assert.InDelta(t, 5.0, ToScale(0.5, 0, 10), 0.0) } func TestRescale(t *testing.T) { assert.InDelta(t, 5.0, Rescale(500, 0, 1000, 0, 10), 0.0) assert.InDelta(t, 490.0, Rescale(-1.0, -1, 0, 490, 350), 0.0) } func TestRand(t *testing.T) { a := Rand(10000) b := Rand(10000) if a == b { require.NotEqual(t, a, b) } } func TestDefaultName(t *testing.T) { name := DefaultName("tester") assert.Contains(t, name, "tester") }